From 8f455b66da9db238655242d1213c05affac412d9 Mon Sep 17 00:00:00 2001 From: dimitri Date: Sat, 17 Mar 2012 20:33:32 +0000 Subject: Release-1.8.0 --- trunk/CVSROOT/checkoutlist | 13 + trunk/CVSROOT/commitinfo | 15 + trunk/CVSROOT/config | 9 + trunk/CVSROOT/cvswrappers | 23 + trunk/CVSROOT/editinfo | 21 + trunk/CVSROOT/loginfo | 26 + trunk/CVSROOT/modules | 27 + trunk/CVSROOT/notify | 12 + trunk/CVSROOT/rcsinfo | 13 + trunk/CVSROOT/taginfo | 20 + trunk/CVSROOT/verifymsg | 21 + trunk/Doxyfile | 311 + trunk/INSTALL | 7 + trunk/LANGUAGE.HOWTO | 50 + trunk/LICENSE | 340 + trunk/Makefile.in | 135 + trunk/Makefile.win_make.in | 32 + trunk/Makefile.win_nmake.in | 49 + trunk/PLATFORMS | 31 + trunk/README | 29 + trunk/addon/doxmlparser/Doxyfile | 177 + trunk/addon/doxmlparser/Doxyfile.impl | 179 + .../addon/doxmlparser/examples/metrics/Makefile.in | 13 + trunk/addon/doxmlparser/examples/metrics/main.cpp | 254 + .../doxmlparser/examples/metrics/metrics.pro.in | 20 + trunk/addon/doxmlparser/include/doxmlintf.h | 1134 ++ trunk/addon/doxmlparser/src/Makefile.in | 13 + trunk/addon/doxmlparser/src/basehandler.cpp | 3 + trunk/addon/doxmlparser/src/basehandler.h | 325 + trunk/addon/doxmlparser/src/baseiterator.h | 50 + trunk/addon/doxmlparser/src/compoundhandler.cpp | 650 + trunk/addon/doxmlparser/src/compoundhandler.h | 236 + trunk/addon/doxmlparser/src/debug.cpp | 24 + trunk/addon/doxmlparser/src/debug.h | 7 + trunk/addon/doxmlparser/src/dochandler.cpp | 2240 +++ trunk/addon/doxmlparser/src/dochandler.h | 1352 ++ trunk/addon/doxmlparser/src/doxmlintf.h | 1 + trunk/addon/doxmlparser/src/doxmlparser.pro.in | 27 + trunk/addon/doxmlparser/src/graphhandler.cpp | 216 + trunk/addon/doxmlparser/src/graphhandler.h | 154 + trunk/addon/doxmlparser/src/linkedtexthandler.cpp | 133 + trunk/addon/doxmlparser/src/linkedtexthandler.h | 54 + trunk/addon/doxmlparser/src/loamhandler.cpp | 75 + trunk/addon/doxmlparser/src/loamhandler.h | 52 + trunk/addon/doxmlparser/src/mainhandler.cpp | 299 + trunk/addon/doxmlparser/src/mainhandler.h | 82 + trunk/addon/doxmlparser/src/memberhandler.cpp | 600 + trunk/addon/doxmlparser/src/memberhandler.h | 252 + trunk/addon/doxmlparser/src/paramhandler.cpp | 158 + trunk/addon/doxmlparser/src/paramhandler.h | 103 + trunk/addon/doxmlparser/src/sectionhandler.cpp | 168 + trunk/addon/doxmlparser/src/sectionhandler.h | 102 + trunk/addon/doxmlparser/src/stringimpl.h | 30 + trunk/addon/doxmlparser/test/Makefile.in | 13 + trunk/addon/doxmlparser/test/main.cpp | 759 + trunk/addon/doxmlparser/test/xmlparse.pro.in | 20 + trunk/addon/doxyapp/Makefile.in | 17 + trunk/addon/doxyapp/README | 8 + trunk/addon/doxyapp/doxyapp.cpp | 314 + trunk/addon/doxyapp/doxyapp.pro.in | 12 + trunk/addon/doxywizard/Makefile.in | 39 + trunk/addon/doxywizard/README | 3 + trunk/addon/doxywizard/config.h | 18 + trunk/addon/doxywizard/config.l | 555 + trunk/addon/doxywizard/doxywizard.cpp | 639 + trunk/addon/doxywizard/doxywizard.h | 84 + trunk/addon/doxywizard/doxywizard.ico | Bin 0 -> 84071 bytes trunk/addon/doxywizard/doxywizard.pro.in | 28 + trunk/addon/doxywizard/doxywizard.qrc | 11 + trunk/addon/doxywizard/doxywizard.rc | 1 + trunk/addon/doxywizard/expert.cpp | 561 + trunk/addon/doxywizard/expert.h | 65 + trunk/addon/doxywizard/helplabel.h | 33 + trunk/addon/doxywizard/images/add.png | Bin 0 -> 4321 bytes trunk/addon/doxywizard/images/del.png | Bin 0 -> 4231 bytes trunk/addon/doxywizard/images/file.png | Bin 0 -> 4380 bytes trunk/addon/doxywizard/images/folder.png | Bin 0 -> 4308 bytes trunk/addon/doxywizard/images/refresh.png | Bin 0 -> 4458 bytes trunk/addon/doxywizard/images/tunecolor.png | Bin 0 -> 116333 bytes trunk/addon/doxywizard/input.h | 34 + trunk/addon/doxywizard/inputbool.cpp | 110 + trunk/addon/doxywizard/inputbool.h | 70 + trunk/addon/doxywizard/inputint.cpp | 96 + trunk/addon/doxywizard/inputint.h | 70 + trunk/addon/doxywizard/inputstring.cpp | 193 + trunk/addon/doxywizard/inputstring.h | 90 + trunk/addon/doxywizard/inputstrlist.cpp | 254 + trunk/addon/doxywizard/inputstrlist.h | 91 + trunk/addon/doxywizard/version.h | 23 + trunk/addon/doxywizard/wizard.cpp | 1295 ++ trunk/addon/doxywizard/wizard.h | 253 + trunk/configure | 674 + trunk/configure.bin | 0 trunk/doc/Doxyfile | 53 + trunk/doc/Makefile.in | 36 + trunk/doc/Makefile.latex | 25 + trunk/doc/Makefile.win_make.in | 36 + trunk/doc/Makefile.win_nmake.in | 38 + trunk/doc/arch.doc | 242 + trunk/doc/archoverview.eps | 380 + trunk/doc/archoverview.gif | Bin 0 -> 7822 bytes trunk/doc/autolink.doc | 134 + trunk/doc/commands.doc | 2876 ++++ trunk/doc/config.doc | 2657 ++++ trunk/doc/custcmd.doc | 125 + trunk/doc/customize.doc | 379 + trunk/doc/dbusxml.doc | 149 + trunk/doc/diagrams.doc | 148 + trunk/doc/docblocks.doc | 600 + trunk/doc/doxygen.1 | 46 + trunk/doc/doxygen.sty | 482 + trunk/doc/doxygen_logo.eps | 6322 ++++++++ trunk/doc/doxygen_logo.gif | Bin 0 -> 29863 bytes trunk/doc/doxygen_logo_low.gif | Bin 0 -> 3952 bytes trunk/doc/doxygen_manual.css | 1029 ++ trunk/doc/doxygen_manual.tex | 110 + trunk/doc/doxygen_usage.doc | 106 + trunk/doc/doxywizard.1 | 10 + trunk/doc/doxywizard.gif | Bin 0 -> 18928 bytes trunk/doc/doxywizard_expert.png | Bin 0 -> 30056 bytes trunk/doc/doxywizard_main.png | Bin 0 -> 57204 bytes trunk/doc/doxywizard_menu.png | Bin 0 -> 58661 bytes trunk/doc/doxywizard_page1.png | Bin 0 -> 39646 bytes trunk/doc/doxywizard_page2.png | Bin 0 -> 39048 bytes trunk/doc/doxywizard_page3.png | Bin 0 -> 50904 bytes trunk/doc/doxywizard_page4.png | Bin 0 -> 43718 bytes trunk/doc/doxywizard_usage.doc | 138 + trunk/doc/external.doc | 120 + trunk/doc/faq.doc | 299 + trunk/doc/features.doc | 116 + trunk/doc/formulas.doc | 112 + trunk/doc/grouping.doc | 228 + trunk/doc/htmlcmds.doc | 153 + trunk/doc/index.doc | 208 + trunk/doc/index.hhp.txt | 108 + trunk/doc/infoflow.eps | 624 + trunk/doc/infoflow.fig | 229 + trunk/doc/infoflow.png | Bin 0 -> 100602 bytes trunk/doc/install.doc | 643 + trunk/doc/install_prefix | 2 + trunk/doc/language.doc | 747 + trunk/doc/language.tpl | 357 + trunk/doc/lists.doc | 125 + trunk/doc/maintainers.txt | 161 + trunk/doc/markdown.doc | 605 + trunk/doc/output.doc | 64 + trunk/doc/perlmod.doc | 193 + trunk/doc/perlmod_tree.doc | 377 + trunk/doc/preprocessing.doc | 263 + trunk/doc/searching.doc | 158 + trunk/doc/starting.doc | 328 + trunk/doc/translator.py | 2012 +++ trunk/doc/translator_report.txt | 792 + trunk/doc/trouble.doc | 142 + trunk/doc/xmlcmds.doc | 103 + trunk/examples/Makefile.in | 130 + trunk/examples/Makefile.win.in | 122 + trunk/examples/afterdoc.cfg | 10 + trunk/examples/afterdoc.h | 18 + trunk/examples/author.cfg | 10 + trunk/examples/author.cpp | 13 + trunk/examples/autolink.cfg | 10 + trunk/examples/autolink.cpp | 99 + trunk/examples/class.cfg | 10 + trunk/examples/class.h | 11 + trunk/examples/dbusxml.cfg | 12 + trunk/examples/dbusxml.xml | 78 + trunk/examples/define.cfg | 11 + trunk/examples/define.h | 18 + trunk/examples/diagrams.cfg | 14 + trunk/examples/diagrams_a.h | 4 + trunk/examples/diagrams_b.h | 5 + trunk/examples/diagrams_c.h | 6 + trunk/examples/diagrams_d.h | 7 + trunk/examples/diagrams_e.h | 5 + trunk/examples/docstring.cfg | 11 + trunk/examples/docstring.py | 27 + trunk/examples/enum.cfg | 10 + trunk/examples/enum.h | 24 + trunk/examples/example.cfg | 12 + trunk/examples/example.cpp | 19 + trunk/examples/example.tag | 14 + trunk/examples/example_test.cpp | 5 + trunk/examples/file.cfg | 10 + trunk/examples/file.h | 10 + trunk/examples/func.cfg | 10 + trunk/examples/func.h | 21 + trunk/examples/group.cfg | 10 + trunk/examples/group.cpp | 88 + trunk/examples/include.cfg | 11 + trunk/examples/include.cpp | 22 + trunk/examples/jdstyle.cfg | 10 + trunk/examples/jdstyle.cpp | 66 + trunk/examples/manual.c | 87 + trunk/examples/manual.cfg | 16 + trunk/examples/memgrp.cfg | 11 + trunk/examples/memgrp.cpp | 41 + trunk/examples/mux.cfg | 14 + trunk/examples/mux.vhdl | 32 + trunk/examples/overload.cfg | 11 + trunk/examples/overload.cpp | 25 + trunk/examples/page.cfg | 10 + trunk/examples/page.doc | 15 + trunk/examples/par.cfg | 10 + trunk/examples/par.cpp | 20 + trunk/examples/pyexample.cfg | 10 + trunk/examples/pyexample.py | 30 + trunk/examples/qtstyle.cfg | 10 + trunk/examples/qtstyle.cpp | 65 + trunk/examples/relates.cfg | 10 + trunk/examples/relates.cpp | 23 + trunk/examples/restypedef.cfg | 10 + trunk/examples/restypedef.cpp | 25 + trunk/examples/structcmd.cfg | 10 + trunk/examples/structcmd.h | 57 + trunk/examples/tag.cfg | 12 + trunk/examples/tag.cpp | 9 + trunk/examples/tclexample.cfg | 13 + trunk/examples/tclexample.tcl | 82 + trunk/examples/templ.cfg | 10 + trunk/examples/templ.cpp | 35 + trunk/libmd5/Makefile.in | 16 + trunk/libmd5/libmd5.pro.in | 10 + trunk/libmd5/md5.c | 313 + trunk/libmd5/md5.h | 57 + trunk/libmd5/md5_loc.h | 6 + trunk/packages/rpm/doxygen.spec.in | 99 + trunk/qtools/Doxyfile | 283 + trunk/qtools/LICENSE.GPL | 349 + trunk/qtools/LICENSE.QPL | 103 + trunk/qtools/Makefile.in | 30 + trunk/qtools/README | 4 + trunk/qtools/qarray.doc | 486 + trunk/qtools/qarray.h | 110 + trunk/qtools/qasciidict.h | 107 + trunk/qtools/qbuffer.cpp | 465 + trunk/qtools/qbuffer.h | 98 + trunk/qtools/qcache.h | 152 + trunk/qtools/qcollection.cpp | 182 + trunk/qtools/qcollection.h | 74 + trunk/qtools/qconfig.h | 1 + trunk/qtools/qcstring.cpp | 799 + trunk/qtools/qcstring.h | 464 + trunk/qtools/qdatastream.cpp | 951 ++ trunk/qtools/qdatastream.h | 173 + trunk/qtools/qdatetime.cpp | 1434 ++ trunk/qtools/qdatetime.h | 216 + trunk/qtools/qdict.doc | 492 + trunk/qtools/qdict.h | 116 + trunk/qtools/qdir.cpp | 1200 ++ trunk/qtools/qdir.h | 235 + trunk/qtools/qdir_unix.cpp | 288 + trunk/qtools/qdir_win32.cpp | 485 + trunk/qtools/qfeatures.h | 978 ++ trunk/qtools/qfile.cpp | 550 + trunk/qtools/qfile.h | 128 + trunk/qtools/qfile_unix.cpp | 668 + trunk/qtools/qfile_win32.cpp | 678 + trunk/qtools/qfiledefs_p.h | 261 + trunk/qtools/qfileinfo.cpp | 458 + trunk/qtools/qfileinfo.h | 138 + trunk/qtools/qfileinfo_unix.cpp | 425 + trunk/qtools/qfileinfo_win32.cpp | 356 + trunk/qtools/qgarray.cpp | 747 + trunk/qtools/qgarray.h | 120 + trunk/qtools/qgcache.cpp | 878 ++ trunk/qtools/qgcache.h | 130 + trunk/qtools/qgdict.cpp | 1218 ++ trunk/qtools/qgdict.h | 222 + trunk/qtools/qgeneric.h | 43 + trunk/qtools/qglist.cpp | 1223 ++ trunk/qtools/qglist.h | 257 + trunk/qtools/qglobal.cpp | 685 + trunk/qtools/qglobal.h | 644 + trunk/qtools/qgstring.cpp | 258 + trunk/qtools/qgstring.h | 139 + trunk/qtools/qgvector.cpp | 638 + trunk/qtools/qgvector.h | 120 + trunk/qtools/qintdict.doc | 475 + trunk/qtools/qintdict.h | 102 + trunk/qtools/qiodevice.cpp | 638 + trunk/qtools/qiodevice.h | 155 + trunk/qtools/qlist.doc | 1048 ++ trunk/qtools/qlist.h | 139 + trunk/qtools/qmap.cpp | 254 + trunk/qtools/qmap.h | 606 + trunk/qtools/qmodules.h | 11 + trunk/qtools/qmutex.cpp | 95 + trunk/qtools/qmutex.h | 83 + trunk/qtools/qmutex_p.h | 90 + trunk/qtools/qmutex_unix.cpp | 117 + trunk/qtools/qmutex_win32.cpp | 108 + trunk/qtools/qptrdict.doc | 486 + trunk/qtools/qptrdict.h | 103 + trunk/qtools/qqueue.h | 70 + trunk/qtools/qregexp.cpp | 1092 ++ trunk/qtools/qregexp.h | 92 + trunk/qtools/qshared.h | 55 + trunk/qtools/qsortedlist.doc | 94 + trunk/qtools/qsortedlist.h | 59 + trunk/qtools/qstack.doc | 135 + trunk/qtools/qstack.h | 71 + trunk/qtools/qstring.cpp | 15318 +++++++++++++++++++ trunk/qtools/qstring.h | 833 + trunk/qtools/qstringlist.cpp | 307 + trunk/qtools/qstringlist.h | 82 + trunk/qtools/qstrlist.doc | 5 + trunk/qtools/qstrlist.h | 109 + trunk/qtools/qstrvec.h | 90 + trunk/qtools/qtextcodec.cpp | 2071 +++ trunk/qtools/qtextcodec.h | 104 + trunk/qtools/qtextstream.cpp | 2237 +++ trunk/qtools/qtextstream.h | 351 + trunk/qtools/qthread.cpp | 85 + trunk/qtools/qthread.h | 77 + trunk/qtools/qthread_p.h | 85 + trunk/qtools/qthread_unix.cpp | 219 + trunk/qtools/qthread_win32.cpp | 158 + trunk/qtools/qtl.doc | 249 + trunk/qtools/qtl.h | 223 + trunk/qtools/qtools.pro.in | 102 + trunk/qtools/qutfcodec.cpp | 276 + trunk/qtools/qutfcodec.h | 71 + trunk/qtools/qvaluelist.doc | 772 + trunk/qtools/qvaluelist.h | 449 + trunk/qtools/qvaluestack.h | 64 + trunk/qtools/qvector.doc | 344 + trunk/qtools/qvector.h | 85 + trunk/qtools/qwaitcondition.h | 68 + trunk/qtools/qwaitcondition_unix.cpp | 133 + trunk/qtools/qwaitcondition_win32.cpp | 186 + trunk/qtools/qxml.cpp | 6061 ++++++++ trunk/qtools/qxml.h | 671 + trunk/qtools/scstring.cpp | 798 + trunk/qtools/scstring.h | 155 + trunk/src/Makefile.in | 49 + trunk/src/arguments.cpp | 17 + trunk/src/arguments.h | 99 + trunk/src/bib2xhtml.h | 290 + trunk/src/bib2xhtml.pl | 290 + trunk/src/bufstr.h | 118 + trunk/src/cite.cpp | 254 + trunk/src/cite.h | 100 + trunk/src/classdef.cpp | 4022 +++++ trunk/src/classdef.h | 495 + trunk/src/classlist.cpp | 163 + trunk/src/classlist.h | 63 + trunk/src/cmdmapper.cpp | 204 + trunk/src/cmdmapper.h | 222 + trunk/src/code.h | 35 + trunk/src/code.l | 3567 +++++ trunk/src/commentcnv.h | 27 + trunk/src/commentcnv.l | 881 ++ trunk/src/commentscan.h | 84 + trunk/src/commentscan.l | 2906 ++++ trunk/src/compound.xsd | 829 + trunk/src/compound_xsd.h | 829 + trunk/src/config.h | 610 + trunk/src/config.l | 1609 ++ trunk/src/config.xml | 1641 ++ trunk/src/configgen.py | 137 + trunk/src/configoptions.cpp | 2494 +++ trunk/src/configoptions.h | 26 + trunk/src/constexp.h | 33 + trunk/src/constexp.l | 120 + trunk/src/constexp.y | 278 + trunk/src/cppvalue.cpp | 95 + trunk/src/cppvalue.h | 62 + trunk/src/dbusxmlscanner.cpp | 875 ++ trunk/src/dbusxmlscanner.h | 58 + trunk/src/debug.cpp | 118 + trunk/src/debug.h | 51 + trunk/src/declinfo.h | 33 + trunk/src/declinfo.l | 357 + trunk/src/defargs.h | 29 + trunk/src/defargs.l | 482 + trunk/src/defgen.cpp | 631 + trunk/src/defgen.h | 20 + trunk/src/define.cpp | 52 + trunk/src/define.h | 91 + trunk/src/definition.cpp | 1791 +++ trunk/src/definition.h | 386 + trunk/src/diagram.cpp | 1306 ++ trunk/src/diagram.h | 133 + trunk/src/dirdef.cpp | 982 ++ trunk/src/dirdef.h | 182 + trunk/src/docparser.cpp | 6970 +++++++++ trunk/src/docparser.h | 1284 ++ trunk/src/docsets.cpp | 488 + trunk/src/docsets.h | 85 + trunk/src/doctokenizer.h | 155 + trunk/src/doctokenizer.l | 1319 ++ trunk/src/docvisitor.h | 191 + trunk/src/dot.cpp | 4576 ++++++ trunk/src/dot.h | 456 + trunk/src/doxygen.bst | 1388 ++ trunk/src/doxygen.cpp | 10844 +++++++++++++ trunk/src/doxygen.css | 1015 ++ trunk/src/doxygen.h | 177 + trunk/src/doxygen.pro.in | 39 + trunk/src/doxygen_bst.h | 1388 ++ trunk/src/doxygen_css.h | 1015 ++ trunk/src/eclipsehelp.cpp | 205 + trunk/src/eclipsehelp.h | 77 + trunk/src/entry.cpp | 458 + trunk/src/entry.h | 351 + trunk/src/example.h | 45 + trunk/src/filedef.cpp | 1679 ++ trunk/src/filedef.h | 326 + trunk/src/filename.cpp | 144 + trunk/src/filename.h | 69 + trunk/src/filestorage.h | 135 + trunk/src/footer.html | 16 + trunk/src/footer_html.h | 16 + trunk/src/formula.cpp | 329 + trunk/src/formula.h | 59 + trunk/src/fortrancode.h | 35 + trunk/src/fortrancode.l | 1073 ++ trunk/src/fortranscanner.h | 51 + trunk/src/fortranscanner.l | 2252 +++ trunk/src/ftextstream.cpp | 259 + trunk/src/ftextstream.h | 82 + trunk/src/ftvhelp.cpp | 992 ++ trunk/src/ftvhelp.h | 80 + trunk/src/groupdef.cpp | 1475 ++ trunk/src/groupdef.h | 192 + trunk/src/growbuf.h | 38 + trunk/src/header.html | 49 + trunk/src/header_html.h | 49 + trunk/src/htags.cpp | 179 + trunk/src/htags.h | 28 + trunk/src/htmlattrib.h | 77 + trunk/src/htmldocvisitor.cpp | 1855 +++ trunk/src/htmldocvisitor.h | 165 + trunk/src/htmlgen.cpp | 3021 ++++ trunk/src/htmlgen.h | 290 + trunk/src/htmlhelp.cpp | 708 + trunk/src/htmlhelp.h | 104 + trunk/src/image.cpp | 540 + trunk/src/image.h | 69 + trunk/src/increasebuffer.pl | 9 + trunk/src/index.cpp | 3932 +++++ trunk/src/index.h | 271 + trunk/src/index.xsd | 66 + trunk/src/index_xsd.h | 66 + trunk/src/indexlog.cpp | 152 + trunk/src/indexlog.h | 57 + trunk/src/jquery.js | 13 + trunk/src/jquery_fx.js | 47 + trunk/src/jquery_fx_js.h | 47 + trunk/src/jquery_js.h | 13 + trunk/src/jquery_ui.js | 32 + trunk/src/jquery_ui_js.h | 32 + trunk/src/lang_cfg.h | 40 + trunk/src/language.cpp | 422 + trunk/src/language.h | 26 + trunk/src/latexdocvisitor.cpp | 1825 +++ trunk/src/latexdocvisitor.h | 192 + trunk/src/latexgen.cpp | 2623 ++++ trunk/src/latexgen.h | 272 + trunk/src/layout.cpp | 1328 ++ trunk/src/layout.h | 198 + trunk/src/layout_default.h | 188 + trunk/src/layout_default.xml | 188 + trunk/src/libdoxycfg.pro.in | 27 + trunk/src/libdoxycfg.t.in | 52 + trunk/src/libdoxygen.pro.in | 274 + trunk/src/libdoxygen.t.in | 177 + trunk/src/lockingptr.h | 162 + trunk/src/lodepng.cpp | 4158 +++++ trunk/src/lodepng.h | 1575 ++ trunk/src/logos.cpp | 1986 +++ trunk/src/logos.h | 27 + trunk/src/main.cpp | 41 + trunk/src/mandocvisitor.cpp | 1010 ++ trunk/src/mandocvisitor.h | 160 + trunk/src/mangen.cpp | 787 + trunk/src/mangen.h | 262 + trunk/src/markdown.cpp | 2237 +++ trunk/src/markdown.h | 54 + trunk/src/marshal.cpp | 830 + trunk/src/marshal.h | 95 + trunk/src/memberdef.cpp | 4507 ++++++ trunk/src/memberdef.h | 399 + trunk/src/membergroup.cpp | 365 + trunk/src/membergroup.h | 153 + trunk/src/memberlist.cpp | 831 + trunk/src/memberlist.h | 202 + trunk/src/membername.cpp | 83 + trunk/src/membername.h | 98 + trunk/src/message.cpp | 196 + trunk/src/message.h | 31 + trunk/src/msc.cpp | 198 + trunk/src/msc.h | 38 + trunk/src/namespacedef.cpp | 992 ++ trunk/src/namespacedef.h | 168 + trunk/src/navtree.css | 127 + trunk/src/navtree.js | 355 + trunk/src/navtree_css.h | 127 + trunk/src/navtree_js.h | 355 + trunk/src/objcache.cpp | 326 + trunk/src/objcache.h | 127 + trunk/src/outputgen.cpp | 82 + trunk/src/outputgen.h | 494 + trunk/src/outputlist.cpp | 316 + trunk/src/outputlist.h | 518 + trunk/src/pagedef.cpp | 283 + trunk/src/pagedef.h | 86 + trunk/src/parserintf.h | 171 + trunk/src/perlmodgen.cpp | 2930 ++++ trunk/src/perlmodgen.h | 23 + trunk/src/portable.cpp | 410 + trunk/src/portable.h | 47 + trunk/src/portable_c.c | 24 + trunk/src/pre.h | 33 + trunk/src/pre.l | 3051 ++++ trunk/src/printdocvisitor.h | 712 + trunk/src/pycode.h | 41 + trunk/src/pycode.l | 1486 ++ trunk/src/pyscanner.h | 60 + trunk/src/pyscanner.l | 1727 +++ trunk/src/qhp.cpp | 340 + trunk/src/qhp.h | 69 + trunk/src/qhpxmlwriter.cpp | 151 + trunk/src/qhpxmlwriter.h | 63 + trunk/src/qtbc.h | 45 + trunk/src/reflist.cpp | 171 + trunk/src/reflist.h | 94 + trunk/src/resize.js | 81 + trunk/src/resize_js.h | 81 + trunk/src/rtfdocvisitor.cpp | 1750 +++ trunk/src/rtfdocvisitor.h | 166 + trunk/src/rtfgen.cpp | 2931 ++++ trunk/src/rtfgen.h | 284 + trunk/src/rtfstyle.cpp | 518 + trunk/src/rtfstyle.h | 83 + trunk/src/scanner.h | 55 + trunk/src/scanner.l | 6154 ++++++++ trunk/src/search.css | 238 + trunk/src/search.js | 778 + trunk/src/search_css.h | 238 + trunk/src/search_functions.php | 374 + trunk/src/search_functions_php.h | 374 + trunk/src/search_js.h | 778 + trunk/src/search_opensearch.php | 127 + trunk/src/search_opensearch_php.h | 127 + trunk/src/searchindex.cpp | 1084 ++ trunk/src/searchindex.h | 79 + trunk/src/section.h | 68 + trunk/src/sizzle.js | 19 + trunk/src/sizzle_js.h | 19 + trunk/src/sortdict.h | 665 + trunk/src/store.cpp | 481 + trunk/src/store.h | 123 + trunk/src/svgpan.js | 319 + trunk/src/svgpan_js.h | 319 + trunk/src/tagreader.cpp | 1408 ++ trunk/src/tagreader.h | 28 + trunk/src/tclscanner.h | 52 + trunk/src/tclscanner.l | 2683 ++++ trunk/src/textdocvisitor.cpp | 88 + trunk/src/textdocvisitor.h | 139 + trunk/src/translator.cpp | 248 + trunk/src/translator.h | 509 + trunk/src/translator_adapter.h | 202 + trunk/src/translator_am.h | 1853 +++ trunk/src/translator_ar.h | 1615 ++ trunk/src/translator_br.h | 1888 +++ trunk/src/translator_ca.h | 1893 +++ trunk/src/translator_cn.h | 1886 +++ trunk/src/translator_cz.h | 1926 +++ trunk/src/translator_de.h | 1986 +++ trunk/src/translator_dk.h | 1834 +++ trunk/src/translator_en.h | 1891 +++ trunk/src/translator_eo.h | 1880 +++ trunk/src/translator_es.h | 1935 +++ trunk/src/translator_fa.h | 1834 +++ trunk/src/translator_fi.h | 1903 +++ trunk/src/translator_fr.h | 1950 +++ trunk/src/translator_gr.h | 1864 +++ trunk/src/translator_hr.h | 1572 ++ trunk/src/translator_hu.h | 1546 ++ trunk/src/translator_id.h | 1867 +++ trunk/src/translator_it.h | 1853 +++ trunk/src/translator_je.h | 67 + trunk/src/translator_jp.h | 1772 +++ trunk/src/translator_ke.h | 59 + trunk/src/translator_kr.h | 1889 +++ trunk/src/translator_lt.h | 1563 ++ trunk/src/translator_mk.h | 1767 +++ trunk/src/translator_nl.h | 1470 ++ trunk/src/translator_no.h | 1617 ++ trunk/src/translator_pl.h | 1804 +++ trunk/src/translator_pt.h | 1891 +++ trunk/src/translator_ro.h | 1797 +++ trunk/src/translator_ru.h | 1846 +++ trunk/src/translator_sc.h | 1805 +++ trunk/src/translator_si.h | 1251 ++ trunk/src/translator_sk.h | 1854 +++ trunk/src/translator_sr.h | 1838 +++ trunk/src/translator_sv.h | 1662 ++ trunk/src/translator_tr.h | 1872 +++ trunk/src/translator_tw.h | 1864 +++ trunk/src/translator_ua.h | 1589 ++ trunk/src/translator_vi.h | 1787 +++ trunk/src/translator_za.h | 1767 +++ trunk/src/translatordecoder.h | 760 + trunk/src/types.h | 92 + trunk/src/util.cpp | 7361 +++++++++ trunk/src/util.h | 407 + trunk/src/version.h | 23 + trunk/src/vhdlcode.h | 18 + trunk/src/vhdlcode.l | 1606 ++ trunk/src/vhdldocgen.cpp | 2785 ++++ trunk/src/vhdldocgen.h | 285 + trunk/src/vhdlparser.y | 2392 +++ trunk/src/vhdlscanner.h | 131 + trunk/src/vhdlscanner.l | 991 ++ trunk/src/xmldocvisitor.cpp | 1002 ++ trunk/src/xmldocvisitor.h | 163 + trunk/src/xmlgen.cpp | 2015 +++ trunk/src/xmlgen.h | 20 + trunk/tmake/CHANGES | 49 + trunk/tmake/LICENSE | 9 + trunk/tmake/README | 10 + trunk/tmake/bin/progen | 249 + trunk/tmake/bin/tmake | 1262 ++ trunk/tmake/doc/m-linux-gcc.html | 85 + trunk/tmake/doc/m-win32-msvc.html | 89 + trunk/tmake/doc/tmake.html | 727 + trunk/tmake/doc/tmake_ref.html | 463 + trunk/tmake/example/hello.cpp | 102 + trunk/tmake/example/hello.h | 34 + trunk/tmake/example/hello.pro | 3 + trunk/tmake/example/main.cpp | 38 + trunk/tmake/example/wc.t | 6 + trunk/tmake/lib/aix-g++/app.t | 2 + trunk/tmake/lib/aix-g++/lib.t | 2 + trunk/tmake/lib/aix-g++/subdirs.t | 2 + trunk/tmake/lib/aix-g++/tmake.conf | 58 + trunk/tmake/lib/aix-xlc/app.t | 2 + trunk/tmake/lib/aix-xlc/lib.t | 2 + trunk/tmake/lib/aix-xlc/subdirs.t | 2 + trunk/tmake/lib/aix-xlc/tmake.conf | 64 + trunk/tmake/lib/beos-g++/app.t | 2 + trunk/tmake/lib/beos-g++/lib.t | 2 + trunk/tmake/lib/beos-g++/subdirs.t | 2 + trunk/tmake/lib/beos-g++/tmake.conf | 51 + trunk/tmake/lib/bsdi-g++/app.t | 2 + trunk/tmake/lib/bsdi-g++/lib.t | 2 + trunk/tmake/lib/bsdi-g++/subdirs.t | 2 + trunk/tmake/lib/bsdi-g++/tmake.conf | 61 + trunk/tmake/lib/dgux-g++/app.t | 2 + trunk/tmake/lib/dgux-g++/lib.t | 2 + trunk/tmake/lib/dgux-g++/subdirs.t | 2 + trunk/tmake/lib/dgux-g++/tmake.conf | 59 + trunk/tmake/lib/freebsd-g++/app.t | 2 + trunk/tmake/lib/freebsd-g++/lib.t | 2 + trunk/tmake/lib/freebsd-g++/subdirs.t | 2 + trunk/tmake/lib/freebsd-g++/tmake.conf | 60 + trunk/tmake/lib/gnu-g++/app.t | 2 + trunk/tmake/lib/gnu-g++/lib.t | 2 + trunk/tmake/lib/gnu-g++/subdirs.t | 2 + trunk/tmake/lib/gnu-g++/tmake.conf | 58 + trunk/tmake/lib/hpux-acc/app.t | 2 + trunk/tmake/lib/hpux-acc/lib.t | 2 + trunk/tmake/lib/hpux-acc/subdirs.t | 2 + trunk/tmake/lib/hpux-acc/tmake.conf | 60 + trunk/tmake/lib/hpux-cc/app.t | 2 + trunk/tmake/lib/hpux-cc/lib.t | 2 + trunk/tmake/lib/hpux-cc/subdirs.t | 2 + trunk/tmake/lib/hpux-cc/tmake.conf | 59 + trunk/tmake/lib/hpux-g++/app.t | 2 + trunk/tmake/lib/hpux-g++/lib.t | 2 + trunk/tmake/lib/hpux-g++/subdirs.t | 2 + trunk/tmake/lib/hpux-g++/tmake.conf | 60 + trunk/tmake/lib/irix-64/app.t | 2 + trunk/tmake/lib/irix-64/lib.t | 2 + trunk/tmake/lib/irix-64/subdirs.t | 2 + trunk/tmake/lib/irix-64/tmake.conf | 60 + trunk/tmake/lib/irix-dcc/app.t | 2 + trunk/tmake/lib/irix-dcc/lib.t | 2 + trunk/tmake/lib/irix-dcc/subdirs.t | 2 + trunk/tmake/lib/irix-dcc/tmake.conf | 60 + trunk/tmake/lib/irix-g++/app.t | 2 + trunk/tmake/lib/irix-g++/lib.t | 2 + trunk/tmake/lib/irix-g++/subdirs.t | 2 + trunk/tmake/lib/irix-g++/tmake.conf | 60 + trunk/tmake/lib/irix-n32/app.t | 2 + trunk/tmake/lib/irix-n32/lib.t | 2 + trunk/tmake/lib/irix-n32/subdirs.t | 2 + trunk/tmake/lib/irix-n32/tmake.conf | 60 + trunk/tmake/lib/irix-o32/app.t | 2 + trunk/tmake/lib/irix-o32/lib.t | 2 + trunk/tmake/lib/irix-o32/subdirs.t | 2 + trunk/tmake/lib/irix-o32/tmake.conf | 60 + trunk/tmake/lib/linux-64/app.t | 2 + trunk/tmake/lib/linux-64/lib.t | 2 + trunk/tmake/lib/linux-64/subdirs.t | 2 + trunk/tmake/lib/linux-64/tmake.conf | 59 + trunk/tmake/lib/linux-g++/app.t | 2 + trunk/tmake/lib/linux-g++/lib.t | 2 + trunk/tmake/lib/linux-g++/subdirs.t | 2 + trunk/tmake/lib/linux-g++/tmake.conf | 59 + trunk/tmake/lib/m68k-atari-mint-g++/app.t | 2 + trunk/tmake/lib/m68k-atari-mint-g++/lib.t | 2 + trunk/tmake/lib/m68k-atari-mint-g++/subdirs.t | 2 + trunk/tmake/lib/m68k-atari-mint-g++/tmake.conf | 59 + trunk/tmake/lib/macosx-c++/app.t | 2 + trunk/tmake/lib/macosx-c++/lib.t | 2 + trunk/tmake/lib/macosx-c++/subdirs.t | 2 + trunk/tmake/lib/macosx-c++/tmake.conf | 59 + trunk/tmake/lib/macosx-uni-c++/app.t | 2 + trunk/tmake/lib/macosx-uni-c++/lib.t | 2 + trunk/tmake/lib/macosx-uni-c++/subdirs.t | 2 + trunk/tmake/lib/macosx-uni-c++/tmake.conf | 59 + trunk/tmake/lib/netbsd-g++/app.t | 2 + trunk/tmake/lib/netbsd-g++/lib.t | 2 + trunk/tmake/lib/netbsd-g++/subdirs.t | 2 + trunk/tmake/lib/netbsd-g++/tmake.conf | 61 + trunk/tmake/lib/openbsd-g++/app.t | 2 + trunk/tmake/lib/openbsd-g++/lib.t | 2 + trunk/tmake/lib/openbsd-g++/subdirs.t | 2 + trunk/tmake/lib/openbsd-g++/tmake.conf | 61 + trunk/tmake/lib/osf1-cxx/app.t | 2 + trunk/tmake/lib/osf1-cxx/lib.t | 2 + trunk/tmake/lib/osf1-cxx/subdirs.t | 2 + trunk/tmake/lib/osf1-cxx/tmake.conf | 60 + trunk/tmake/lib/osf1-g++/app.t | 2 + trunk/tmake/lib/osf1-g++/lib.t | 2 + trunk/tmake/lib/osf1-g++/subdirs.t | 2 + trunk/tmake/lib/osf1-g++/tmake.conf | 58 + trunk/tmake/lib/qnx-g++/app.t | 2 + trunk/tmake/lib/qnx-g++/lib.t | 2 + trunk/tmake/lib/qnx-g++/subdirs.t | 2 + trunk/tmake/lib/qnx-g++/tmake.conf | 58 + trunk/tmake/lib/sco-g++/app.t | 2 + trunk/tmake/lib/sco-g++/lib.t | 2 + trunk/tmake/lib/sco-g++/subdirs.t | 2 + trunk/tmake/lib/sco-g++/tmake.conf | 58 + trunk/tmake/lib/solaris-cc-64/app.t | 2 + trunk/tmake/lib/solaris-cc-64/lib.t | 2 + trunk/tmake/lib/solaris-cc-64/subdirs.t | 2 + trunk/tmake/lib/solaris-cc-64/tmake.conf | 61 + trunk/tmake/lib/solaris-cc-gcc/app.t | 2 + trunk/tmake/lib/solaris-cc-gcc/lib.t | 2 + trunk/tmake/lib/solaris-cc-gcc/subdirs.t | 2 + trunk/tmake/lib/solaris-cc-gcc/tmake.conf | 62 + trunk/tmake/lib/solaris-cc/app.t | 2 + trunk/tmake/lib/solaris-cc/lib.t | 2 + trunk/tmake/lib/solaris-cc/subdirs.t | 2 + trunk/tmake/lib/solaris-cc/tmake.conf | 61 + trunk/tmake/lib/solaris-g++/app.t | 2 + trunk/tmake/lib/solaris-g++/lib.t | 2 + trunk/tmake/lib/solaris-g++/subdirs.t | 2 + trunk/tmake/lib/solaris-g++/tmake.conf | 59 + trunk/tmake/lib/sunos-g++/app.t | 2 + trunk/tmake/lib/sunos-g++/lib.t | 2 + trunk/tmake/lib/sunos-g++/subdirs.t | 2 + trunk/tmake/lib/sunos-g++/tmake.conf | 58 + trunk/tmake/lib/ultrix-g++/app.t | 2 + trunk/tmake/lib/ultrix-g++/lib.t | 2 + trunk/tmake/lib/ultrix-g++/subdirs.t | 2 + trunk/tmake/lib/ultrix-g++/tmake.conf | 58 + trunk/tmake/lib/unix/app.t | 6 + trunk/tmake/lib/unix/generic.t | 283 + trunk/tmake/lib/unix/lib.t | 6 + trunk/tmake/lib/unix/subdirs.t | 38 + trunk/tmake/lib/unixware-g++/app.t | 2 + trunk/tmake/lib/unixware-g++/lib.t | 2 + trunk/tmake/lib/unixware-g++/subdirs.t | 2 + trunk/tmake/lib/unixware-g++/tmake.conf | 60 + trunk/tmake/lib/unixware7-cc/app.t | 2 + trunk/tmake/lib/unixware7-cc/lib.t | 2 + trunk/tmake/lib/unixware7-cc/subdirs.t | 2 + trunk/tmake/lib/unixware7-cc/tmake.conf | 60 + trunk/tmake/lib/unixware7-g++/app.t | 2 + trunk/tmake/lib/unixware7-g++/lib.t | 2 + trunk/tmake/lib/unixware7-g++/subdirs.t | 2 + trunk/tmake/lib/unixware7-g++/tmake.conf | 60 + trunk/tmake/lib/win32-borland/app.t | 6 + trunk/tmake/lib/win32-borland/generic.t | 237 + trunk/tmake/lib/win32-borland/lib.t | 6 + trunk/tmake/lib/win32-borland/subdirs.t | 3 + trunk/tmake/lib/win32-borland/tmake.conf | 56 + trunk/tmake/lib/win32-g++/app.t | 6 + trunk/tmake/lib/win32-g++/generic.t | 241 + trunk/tmake/lib/win32-g++/lib.t | 6 + trunk/tmake/lib/win32-g++/subdirs.t | 2 + trunk/tmake/lib/win32-g++/tmake.conf | 56 + trunk/tmake/lib/win32-mingw/app.t | 6 + trunk/tmake/lib/win32-mingw/generic.t | 241 + trunk/tmake/lib/win32-mingw/lib.t | 6 + trunk/tmake/lib/win32-mingw/subdirs.t | 2 + trunk/tmake/lib/win32-mingw/tmake.conf | 56 + trunk/tmake/lib/win32-msvc/app.t | 6 + trunk/tmake/lib/win32-msvc/generic.t | 229 + trunk/tmake/lib/win32-msvc/lib.t | 6 + trunk/tmake/lib/win32-msvc/subdirs.t | 2 + trunk/tmake/lib/win32-msvc/tmake.conf | 65 + trunk/tmake/lib/win32-msvc/vcapp.t | 244 + trunk/tmake/lib/win32-msvc/vclib.t | 178 + trunk/tmake/lib/win32-symantec/app.t | 6 + trunk/tmake/lib/win32-symantec/generic.t | 211 + trunk/tmake/lib/win32-symantec/lib.t | 6 + trunk/tmake/lib/win32-symantec/subdirs.t | 2 + trunk/tmake/lib/win32-symantec/tmake.conf | 56 + trunk/tmake/lib/win32-visage/app.t | 6 + trunk/tmake/lib/win32-visage/generic.t | 207 + trunk/tmake/lib/win32-visage/lib.t | 6 + trunk/tmake/lib/win32-visage/subdirs.t | 2 + trunk/tmake/lib/win32-visage/tmake.conf | 56 + trunk/tmake/lib/win32-watcom/app.t | 6 + trunk/tmake/lib/win32-watcom/generic.t | 201 + trunk/tmake/lib/win32-watcom/lib.t | 6 + trunk/tmake/lib/win32-watcom/subdirs.t | 2 + trunk/tmake/lib/win32-watcom/tmake.conf | 54 + trunk/tmake/lib/win32/subdirs.t | 54 + trunk/winbuild/Doxygen.sln | 48 + trunk/winbuild/Doxygen.vcproj | 4263 ++++++ trunk/winbuild/Doxywizard.vcproj | 590 + trunk/winbuild/Lex.rules | 40 + trunk/winbuild/iconv.h | 141 + trunk/winbuild/iconv.lib | Bin 0 -> 958612 bytes trunk/winbuild/iconv.vcproj | 464 + trunk/winbuild/iconv64.lib | Bin 0 -> 1206128 bytes trunk/winbuild/moc.rules | 20 + trunk/winbuild/qtools.vcproj | 1583 ++ trunk/winbuild/runbison.bat | 7 + trunk/winbuild/unistd.h | 7 + trunk/winbuild/version.bat | 24 + 831 files changed, 361893 insertions(+) create mode 100644 trunk/CVSROOT/checkoutlist create mode 100644 trunk/CVSROOT/commitinfo create mode 100644 trunk/CVSROOT/config create mode 100644 trunk/CVSROOT/cvswrappers create mode 100644 trunk/CVSROOT/editinfo create mode 100644 trunk/CVSROOT/loginfo create mode 100644 trunk/CVSROOT/modules create mode 100644 trunk/CVSROOT/notify create mode 100644 trunk/CVSROOT/rcsinfo create mode 100644 trunk/CVSROOT/taginfo create mode 100644 trunk/CVSROOT/verifymsg create mode 100644 trunk/Doxyfile create mode 100644 trunk/INSTALL create mode 100644 trunk/LANGUAGE.HOWTO create mode 100644 trunk/LICENSE create mode 100644 trunk/Makefile.in create mode 100644 trunk/Makefile.win_make.in create mode 100644 trunk/Makefile.win_nmake.in create mode 100644 trunk/PLATFORMS create mode 100644 trunk/README create mode 100644 trunk/addon/doxmlparser/Doxyfile create mode 100644 trunk/addon/doxmlparser/Doxyfile.impl create mode 100644 trunk/addon/doxmlparser/examples/metrics/Makefile.in create mode 100644 trunk/addon/doxmlparser/examples/metrics/main.cpp create mode 100644 trunk/addon/doxmlparser/examples/metrics/metrics.pro.in create mode 100644 trunk/addon/doxmlparser/include/doxmlintf.h create mode 100644 trunk/addon/doxmlparser/src/Makefile.in create mode 100644 trunk/addon/doxmlparser/src/basehandler.cpp create mode 100644 trunk/addon/doxmlparser/src/basehandler.h create mode 100644 trunk/addon/doxmlparser/src/baseiterator.h create mode 100644 trunk/addon/doxmlparser/src/compoundhandler.cpp create mode 100644 trunk/addon/doxmlparser/src/compoundhandler.h create mode 100644 trunk/addon/doxmlparser/src/debug.cpp create mode 100644 trunk/addon/doxmlparser/src/debug.h create mode 100644 trunk/addon/doxmlparser/src/dochandler.cpp create mode 100644 trunk/addon/doxmlparser/src/dochandler.h create mode 120000 trunk/addon/doxmlparser/src/doxmlintf.h create mode 100644 trunk/addon/doxmlparser/src/doxmlparser.pro.in create mode 100644 trunk/addon/doxmlparser/src/graphhandler.cpp create mode 100644 trunk/addon/doxmlparser/src/graphhandler.h create mode 100644 trunk/addon/doxmlparser/src/linkedtexthandler.cpp create mode 100644 trunk/addon/doxmlparser/src/linkedtexthandler.h create mode 100644 trunk/addon/doxmlparser/src/loamhandler.cpp create mode 100644 trunk/addon/doxmlparser/src/loamhandler.h create mode 100644 trunk/addon/doxmlparser/src/mainhandler.cpp create mode 100644 trunk/addon/doxmlparser/src/mainhandler.h create mode 100644 trunk/addon/doxmlparser/src/memberhandler.cpp create mode 100644 trunk/addon/doxmlparser/src/memberhandler.h create mode 100644 trunk/addon/doxmlparser/src/paramhandler.cpp create mode 100644 trunk/addon/doxmlparser/src/paramhandler.h create mode 100644 trunk/addon/doxmlparser/src/sectionhandler.cpp create mode 100644 trunk/addon/doxmlparser/src/sectionhandler.h create mode 100644 trunk/addon/doxmlparser/src/stringimpl.h create mode 100644 trunk/addon/doxmlparser/test/Makefile.in create mode 100644 trunk/addon/doxmlparser/test/main.cpp create mode 100644 trunk/addon/doxmlparser/test/xmlparse.pro.in create mode 100644 trunk/addon/doxyapp/Makefile.in create mode 100644 trunk/addon/doxyapp/README create mode 100644 trunk/addon/doxyapp/doxyapp.cpp create mode 100644 trunk/addon/doxyapp/doxyapp.pro.in create mode 100644 trunk/addon/doxywizard/Makefile.in create mode 100644 trunk/addon/doxywizard/README create mode 100644 trunk/addon/doxywizard/config.h create mode 100644 trunk/addon/doxywizard/config.l create mode 100644 trunk/addon/doxywizard/doxywizard.cpp create mode 100644 trunk/addon/doxywizard/doxywizard.h create mode 100644 trunk/addon/doxywizard/doxywizard.ico create mode 100644 trunk/addon/doxywizard/doxywizard.pro.in create mode 100644 trunk/addon/doxywizard/doxywizard.qrc create mode 100644 trunk/addon/doxywizard/doxywizard.rc create mode 100644 trunk/addon/doxywizard/expert.cpp create mode 100644 trunk/addon/doxywizard/expert.h create mode 100644 trunk/addon/doxywizard/helplabel.h create mode 100644 trunk/addon/doxywizard/images/add.png create mode 100644 trunk/addon/doxywizard/images/del.png create mode 100644 trunk/addon/doxywizard/images/file.png create mode 100644 trunk/addon/doxywizard/images/folder.png create mode 100644 trunk/addon/doxywizard/images/refresh.png create mode 100644 trunk/addon/doxywizard/images/tunecolor.png create mode 100644 trunk/addon/doxywizard/input.h create mode 100644 trunk/addon/doxywizard/inputbool.cpp create mode 100644 trunk/addon/doxywizard/inputbool.h create mode 100644 trunk/addon/doxywizard/inputint.cpp create mode 100644 trunk/addon/doxywizard/inputint.h create mode 100644 trunk/addon/doxywizard/inputstring.cpp create mode 100644 trunk/addon/doxywizard/inputstring.h create mode 100644 trunk/addon/doxywizard/inputstrlist.cpp create mode 100644 trunk/addon/doxywizard/inputstrlist.h create mode 100644 trunk/addon/doxywizard/version.h create mode 100644 trunk/addon/doxywizard/wizard.cpp create mode 100644 trunk/addon/doxywizard/wizard.h create mode 100755 trunk/configure create mode 100755 trunk/configure.bin create mode 100644 trunk/doc/Doxyfile create mode 100644 trunk/doc/Makefile.in create mode 100644 trunk/doc/Makefile.latex create mode 100644 trunk/doc/Makefile.win_make.in create mode 100644 trunk/doc/Makefile.win_nmake.in create mode 100644 trunk/doc/arch.doc create mode 100644 trunk/doc/archoverview.eps create mode 100644 trunk/doc/archoverview.gif create mode 100644 trunk/doc/autolink.doc create mode 100644 trunk/doc/commands.doc create mode 100644 trunk/doc/config.doc create mode 100644 trunk/doc/custcmd.doc create mode 100644 trunk/doc/customize.doc create mode 100644 trunk/doc/dbusxml.doc create mode 100644 trunk/doc/diagrams.doc create mode 100644 trunk/doc/docblocks.doc create mode 100644 trunk/doc/doxygen.1 create mode 100644 trunk/doc/doxygen.sty create mode 100644 trunk/doc/doxygen_logo.eps create mode 100644 trunk/doc/doxygen_logo.gif create mode 100644 trunk/doc/doxygen_logo_low.gif create mode 100644 trunk/doc/doxygen_manual.css create mode 100644 trunk/doc/doxygen_manual.tex create mode 100644 trunk/doc/doxygen_usage.doc create mode 100644 trunk/doc/doxywizard.1 create mode 100644 trunk/doc/doxywizard.gif create mode 100644 trunk/doc/doxywizard_expert.png create mode 100644 trunk/doc/doxywizard_main.png create mode 100644 trunk/doc/doxywizard_menu.png create mode 100644 trunk/doc/doxywizard_page1.png create mode 100644 trunk/doc/doxywizard_page2.png create mode 100644 trunk/doc/doxywizard_page3.png create mode 100644 trunk/doc/doxywizard_page4.png create mode 100644 trunk/doc/doxywizard_usage.doc create mode 100644 trunk/doc/external.doc create mode 100644 trunk/doc/faq.doc create mode 100644 trunk/doc/features.doc create mode 100644 trunk/doc/formulas.doc create mode 100644 trunk/doc/grouping.doc create mode 100644 trunk/doc/htmlcmds.doc create mode 100644 trunk/doc/index.doc create mode 100644 trunk/doc/index.hhp.txt create mode 100644 trunk/doc/infoflow.eps create mode 100644 trunk/doc/infoflow.fig create mode 100644 trunk/doc/infoflow.png create mode 100644 trunk/doc/install.doc create mode 100644 trunk/doc/install_prefix create mode 100644 trunk/doc/language.doc create mode 100644 trunk/doc/language.tpl create mode 100644 trunk/doc/lists.doc create mode 100644 trunk/doc/maintainers.txt create mode 100644 trunk/doc/markdown.doc create mode 100644 trunk/doc/output.doc create mode 100644 trunk/doc/perlmod.doc create mode 100644 trunk/doc/perlmod_tree.doc create mode 100644 trunk/doc/preprocessing.doc create mode 100644 trunk/doc/searching.doc create mode 100644 trunk/doc/starting.doc create mode 100644 trunk/doc/translator.py create mode 100644 trunk/doc/translator_report.txt create mode 100644 trunk/doc/trouble.doc create mode 100644 trunk/doc/xmlcmds.doc create mode 100644 trunk/examples/Makefile.in create mode 100644 trunk/examples/Makefile.win.in create mode 100644 trunk/examples/afterdoc.cfg create mode 100644 trunk/examples/afterdoc.h create mode 100644 trunk/examples/author.cfg create mode 100644 trunk/examples/author.cpp create mode 100644 trunk/examples/autolink.cfg create mode 100644 trunk/examples/autolink.cpp create mode 100644 trunk/examples/class.cfg create mode 100644 trunk/examples/class.h create mode 100644 trunk/examples/dbusxml.cfg create mode 100644 trunk/examples/dbusxml.xml create mode 100644 trunk/examples/define.cfg create mode 100644 trunk/examples/define.h create mode 100644 trunk/examples/diagrams.cfg create mode 100644 trunk/examples/diagrams_a.h create mode 100644 trunk/examples/diagrams_b.h create mode 100644 trunk/examples/diagrams_c.h create mode 100644 trunk/examples/diagrams_d.h create mode 100644 trunk/examples/diagrams_e.h create mode 100644 trunk/examples/docstring.cfg create mode 100644 trunk/examples/docstring.py create mode 100644 trunk/examples/enum.cfg create mode 100644 trunk/examples/enum.h create mode 100644 trunk/examples/example.cfg create mode 100644 trunk/examples/example.cpp create mode 100644 trunk/examples/example.tag create mode 100644 trunk/examples/example_test.cpp create mode 100644 trunk/examples/file.cfg create mode 100644 trunk/examples/file.h create mode 100644 trunk/examples/func.cfg create mode 100644 trunk/examples/func.h create mode 100644 trunk/examples/group.cfg create mode 100644 trunk/examples/group.cpp create mode 100644 trunk/examples/include.cfg create mode 100644 trunk/examples/include.cpp create mode 100644 trunk/examples/jdstyle.cfg create mode 100644 trunk/examples/jdstyle.cpp create mode 100644 trunk/examples/manual.c create mode 100644 trunk/examples/manual.cfg create mode 100644 trunk/examples/memgrp.cfg create mode 100644 trunk/examples/memgrp.cpp create mode 100644 trunk/examples/mux.cfg create mode 100644 trunk/examples/mux.vhdl create mode 100644 trunk/examples/overload.cfg create mode 100644 trunk/examples/overload.cpp create mode 100644 trunk/examples/page.cfg create mode 100644 trunk/examples/page.doc create mode 100644 trunk/examples/par.cfg create mode 100644 trunk/examples/par.cpp create mode 100644 trunk/examples/pyexample.cfg create mode 100644 trunk/examples/pyexample.py create mode 100644 trunk/examples/qtstyle.cfg create mode 100644 trunk/examples/qtstyle.cpp create mode 100644 trunk/examples/relates.cfg create mode 100644 trunk/examples/relates.cpp create mode 100644 trunk/examples/restypedef.cfg create mode 100644 trunk/examples/restypedef.cpp create mode 100644 trunk/examples/structcmd.cfg create mode 100644 trunk/examples/structcmd.h create mode 100644 trunk/examples/tag.cfg create mode 100644 trunk/examples/tag.cpp create mode 100644 trunk/examples/tclexample.cfg create mode 100644 trunk/examples/tclexample.tcl create mode 100644 trunk/examples/templ.cfg create mode 100644 trunk/examples/templ.cpp create mode 100644 trunk/libmd5/Makefile.in create mode 100644 trunk/libmd5/libmd5.pro.in create mode 100644 trunk/libmd5/md5.c create mode 100644 trunk/libmd5/md5.h create mode 100644 trunk/libmd5/md5_loc.h create mode 100644 trunk/packages/rpm/doxygen.spec.in create mode 100644 trunk/qtools/Doxyfile create mode 100644 trunk/qtools/LICENSE.GPL create mode 100644 trunk/qtools/LICENSE.QPL create mode 100644 trunk/qtools/Makefile.in create mode 100644 trunk/qtools/README create mode 100644 trunk/qtools/qarray.doc create mode 100644 trunk/qtools/qarray.h create mode 100644 trunk/qtools/qasciidict.h create mode 100644 trunk/qtools/qbuffer.cpp create mode 100644 trunk/qtools/qbuffer.h create mode 100644 trunk/qtools/qcache.h create mode 100644 trunk/qtools/qcollection.cpp create mode 100644 trunk/qtools/qcollection.h create mode 100644 trunk/qtools/qconfig.h create mode 100644 trunk/qtools/qcstring.cpp create mode 100644 trunk/qtools/qcstring.h create mode 100644 trunk/qtools/qdatastream.cpp create mode 100644 trunk/qtools/qdatastream.h create mode 100644 trunk/qtools/qdatetime.cpp create mode 100644 trunk/qtools/qdatetime.h create mode 100644 trunk/qtools/qdict.doc create mode 100644 trunk/qtools/qdict.h create mode 100644 trunk/qtools/qdir.cpp create mode 100644 trunk/qtools/qdir.h create mode 100644 trunk/qtools/qdir_unix.cpp create mode 100644 trunk/qtools/qdir_win32.cpp create mode 100644 trunk/qtools/qfeatures.h create mode 100644 trunk/qtools/qfile.cpp create mode 100644 trunk/qtools/qfile.h create mode 100644 trunk/qtools/qfile_unix.cpp create mode 100644 trunk/qtools/qfile_win32.cpp create mode 100644 trunk/qtools/qfiledefs_p.h create mode 100644 trunk/qtools/qfileinfo.cpp create mode 100644 trunk/qtools/qfileinfo.h create mode 100644 trunk/qtools/qfileinfo_unix.cpp create mode 100644 trunk/qtools/qfileinfo_win32.cpp create mode 100644 trunk/qtools/qgarray.cpp create mode 100644 trunk/qtools/qgarray.h create mode 100644 trunk/qtools/qgcache.cpp create mode 100644 trunk/qtools/qgcache.h create mode 100644 trunk/qtools/qgdict.cpp create mode 100644 trunk/qtools/qgdict.h create mode 100644 trunk/qtools/qgeneric.h create mode 100644 trunk/qtools/qglist.cpp create mode 100644 trunk/qtools/qglist.h create mode 100644 trunk/qtools/qglobal.cpp create mode 100644 trunk/qtools/qglobal.h create mode 100644 trunk/qtools/qgstring.cpp create mode 100644 trunk/qtools/qgstring.h create mode 100644 trunk/qtools/qgvector.cpp create mode 100644 trunk/qtools/qgvector.h create mode 100644 trunk/qtools/qintdict.doc create mode 100644 trunk/qtools/qintdict.h create mode 100644 trunk/qtools/qiodevice.cpp create mode 100644 trunk/qtools/qiodevice.h create mode 100644 trunk/qtools/qlist.doc create mode 100644 trunk/qtools/qlist.h create mode 100644 trunk/qtools/qmap.cpp create mode 100644 trunk/qtools/qmap.h create mode 100644 trunk/qtools/qmodules.h create mode 100644 trunk/qtools/qmutex.cpp create mode 100644 trunk/qtools/qmutex.h create mode 100644 trunk/qtools/qmutex_p.h create mode 100644 trunk/qtools/qmutex_unix.cpp create mode 100644 trunk/qtools/qmutex_win32.cpp create mode 100644 trunk/qtools/qptrdict.doc create mode 100644 trunk/qtools/qptrdict.h create mode 100644 trunk/qtools/qqueue.h create mode 100644 trunk/qtools/qregexp.cpp create mode 100644 trunk/qtools/qregexp.h create mode 100644 trunk/qtools/qshared.h create mode 100644 trunk/qtools/qsortedlist.doc create mode 100644 trunk/qtools/qsortedlist.h create mode 100644 trunk/qtools/qstack.doc create mode 100644 trunk/qtools/qstack.h create mode 100644 trunk/qtools/qstring.cpp create mode 100644 trunk/qtools/qstring.h create mode 100644 trunk/qtools/qstringlist.cpp create mode 100644 trunk/qtools/qstringlist.h create mode 100644 trunk/qtools/qstrlist.doc create mode 100644 trunk/qtools/qstrlist.h create mode 100644 trunk/qtools/qstrvec.h create mode 100644 trunk/qtools/qtextcodec.cpp create mode 100644 trunk/qtools/qtextcodec.h create mode 100644 trunk/qtools/qtextstream.cpp create mode 100644 trunk/qtools/qtextstream.h create mode 100644 trunk/qtools/qthread.cpp create mode 100644 trunk/qtools/qthread.h create mode 100644 trunk/qtools/qthread_p.h create mode 100644 trunk/qtools/qthread_unix.cpp create mode 100644 trunk/qtools/qthread_win32.cpp create mode 100644 trunk/qtools/qtl.doc create mode 100644 trunk/qtools/qtl.h create mode 100644 trunk/qtools/qtools.pro.in create mode 100644 trunk/qtools/qutfcodec.cpp create mode 100644 trunk/qtools/qutfcodec.h create mode 100644 trunk/qtools/qvaluelist.doc create mode 100644 trunk/qtools/qvaluelist.h create mode 100644 trunk/qtools/qvaluestack.h create mode 100644 trunk/qtools/qvector.doc create mode 100644 trunk/qtools/qvector.h create mode 100644 trunk/qtools/qwaitcondition.h create mode 100644 trunk/qtools/qwaitcondition_unix.cpp create mode 100644 trunk/qtools/qwaitcondition_win32.cpp create mode 100644 trunk/qtools/qxml.cpp create mode 100644 trunk/qtools/qxml.h create mode 100644 trunk/qtools/scstring.cpp create mode 100644 trunk/qtools/scstring.h create mode 100644 trunk/src/Makefile.in create mode 100644 trunk/src/arguments.cpp create mode 100644 trunk/src/arguments.h create mode 100644 trunk/src/bib2xhtml.h create mode 100755 trunk/src/bib2xhtml.pl create mode 100644 trunk/src/bufstr.h create mode 100644 trunk/src/cite.cpp create mode 100644 trunk/src/cite.h create mode 100644 trunk/src/classdef.cpp create mode 100644 trunk/src/classdef.h create mode 100644 trunk/src/classlist.cpp create mode 100644 trunk/src/classlist.h create mode 100644 trunk/src/cmdmapper.cpp create mode 100644 trunk/src/cmdmapper.h create mode 100644 trunk/src/code.h create mode 100644 trunk/src/code.l create mode 100644 trunk/src/commentcnv.h create mode 100644 trunk/src/commentcnv.l create mode 100644 trunk/src/commentscan.h create mode 100644 trunk/src/commentscan.l create mode 100644 trunk/src/compound.xsd create mode 100644 trunk/src/compound_xsd.h create mode 100644 trunk/src/config.h create mode 100644 trunk/src/config.l create mode 100644 trunk/src/config.xml create mode 100755 trunk/src/configgen.py create mode 100644 trunk/src/configoptions.cpp create mode 100644 trunk/src/configoptions.h create mode 100644 trunk/src/constexp.h create mode 100644 trunk/src/constexp.l create mode 100644 trunk/src/constexp.y create mode 100644 trunk/src/cppvalue.cpp create mode 100644 trunk/src/cppvalue.h create mode 100644 trunk/src/dbusxmlscanner.cpp create mode 100644 trunk/src/dbusxmlscanner.h create mode 100644 trunk/src/debug.cpp create mode 100644 trunk/src/debug.h create mode 100644 trunk/src/declinfo.h create mode 100644 trunk/src/declinfo.l create mode 100644 trunk/src/defargs.h create mode 100644 trunk/src/defargs.l create mode 100644 trunk/src/defgen.cpp create mode 100644 trunk/src/defgen.h create mode 100644 trunk/src/define.cpp create mode 100644 trunk/src/define.h create mode 100644 trunk/src/definition.cpp create mode 100644 trunk/src/definition.h create mode 100644 trunk/src/diagram.cpp create mode 100644 trunk/src/diagram.h create mode 100644 trunk/src/dirdef.cpp create mode 100644 trunk/src/dirdef.h create mode 100644 trunk/src/docparser.cpp create mode 100644 trunk/src/docparser.h create mode 100644 trunk/src/docsets.cpp create mode 100644 trunk/src/docsets.h create mode 100644 trunk/src/doctokenizer.h create mode 100644 trunk/src/doctokenizer.l create mode 100644 trunk/src/docvisitor.h create mode 100644 trunk/src/dot.cpp create mode 100644 trunk/src/dot.h create mode 100644 trunk/src/doxygen.bst create mode 100644 trunk/src/doxygen.cpp create mode 100644 trunk/src/doxygen.css create mode 100644 trunk/src/doxygen.h create mode 100644 trunk/src/doxygen.pro.in create mode 100644 trunk/src/doxygen_bst.h create mode 100644 trunk/src/doxygen_css.h create mode 100644 trunk/src/eclipsehelp.cpp create mode 100644 trunk/src/eclipsehelp.h create mode 100644 trunk/src/entry.cpp create mode 100644 trunk/src/entry.h create mode 100644 trunk/src/example.h create mode 100644 trunk/src/filedef.cpp create mode 100644 trunk/src/filedef.h create mode 100644 trunk/src/filename.cpp create mode 100644 trunk/src/filename.h create mode 100644 trunk/src/filestorage.h create mode 100644 trunk/src/footer.html create mode 100644 trunk/src/footer_html.h create mode 100644 trunk/src/formula.cpp create mode 100644 trunk/src/formula.h create mode 100644 trunk/src/fortrancode.h create mode 100644 trunk/src/fortrancode.l create mode 100644 trunk/src/fortranscanner.h create mode 100644 trunk/src/fortranscanner.l create mode 100644 trunk/src/ftextstream.cpp create mode 100644 trunk/src/ftextstream.h create mode 100644 trunk/src/ftvhelp.cpp create mode 100644 trunk/src/ftvhelp.h create mode 100644 trunk/src/groupdef.cpp create mode 100644 trunk/src/groupdef.h create mode 100644 trunk/src/growbuf.h create mode 100644 trunk/src/header.html create mode 100644 trunk/src/header_html.h create mode 100644 trunk/src/htags.cpp create mode 100644 trunk/src/htags.h create mode 100644 trunk/src/htmlattrib.h create mode 100644 trunk/src/htmldocvisitor.cpp create mode 100644 trunk/src/htmldocvisitor.h create mode 100644 trunk/src/htmlgen.cpp create mode 100644 trunk/src/htmlgen.h create mode 100644 trunk/src/htmlhelp.cpp create mode 100644 trunk/src/htmlhelp.h create mode 100644 trunk/src/image.cpp create mode 100644 trunk/src/image.h create mode 100755 trunk/src/increasebuffer.pl create mode 100644 trunk/src/index.cpp create mode 100644 trunk/src/index.h create mode 100644 trunk/src/index.xsd create mode 100644 trunk/src/index_xsd.h create mode 100644 trunk/src/indexlog.cpp create mode 100644 trunk/src/indexlog.h create mode 100644 trunk/src/jquery.js create mode 100644 trunk/src/jquery_fx.js create mode 100644 trunk/src/jquery_fx_js.h create mode 100644 trunk/src/jquery_js.h create mode 100644 trunk/src/jquery_ui.js create mode 100644 trunk/src/jquery_ui_js.h create mode 100644 trunk/src/lang_cfg.h create mode 100644 trunk/src/language.cpp create mode 100644 trunk/src/language.h create mode 100644 trunk/src/latexdocvisitor.cpp create mode 100644 trunk/src/latexdocvisitor.h create mode 100644 trunk/src/latexgen.cpp create mode 100644 trunk/src/latexgen.h create mode 100644 trunk/src/layout.cpp create mode 100644 trunk/src/layout.h create mode 100644 trunk/src/layout_default.h create mode 100644 trunk/src/layout_default.xml create mode 100644 trunk/src/libdoxycfg.pro.in create mode 100644 trunk/src/libdoxycfg.t.in create mode 100644 trunk/src/libdoxygen.pro.in create mode 100644 trunk/src/libdoxygen.t.in create mode 100644 trunk/src/lockingptr.h create mode 100644 trunk/src/lodepng.cpp create mode 100644 trunk/src/lodepng.h create mode 100644 trunk/src/logos.cpp create mode 100644 trunk/src/logos.h create mode 100644 trunk/src/main.cpp create mode 100644 trunk/src/mandocvisitor.cpp create mode 100644 trunk/src/mandocvisitor.h create mode 100644 trunk/src/mangen.cpp create mode 100644 trunk/src/mangen.h create mode 100644 trunk/src/markdown.cpp create mode 100644 trunk/src/markdown.h create mode 100644 trunk/src/marshal.cpp create mode 100644 trunk/src/marshal.h create mode 100644 trunk/src/memberdef.cpp create mode 100644 trunk/src/memberdef.h create mode 100644 trunk/src/membergroup.cpp create mode 100644 trunk/src/membergroup.h create mode 100644 trunk/src/memberlist.cpp create mode 100644 trunk/src/memberlist.h create mode 100644 trunk/src/membername.cpp create mode 100644 trunk/src/membername.h create mode 100644 trunk/src/message.cpp create mode 100644 trunk/src/message.h create mode 100644 trunk/src/msc.cpp create mode 100644 trunk/src/msc.h create mode 100644 trunk/src/namespacedef.cpp create mode 100644 trunk/src/namespacedef.h create mode 100644 trunk/src/navtree.css create mode 100644 trunk/src/navtree.js create mode 100644 trunk/src/navtree_css.h create mode 100644 trunk/src/navtree_js.h create mode 100644 trunk/src/objcache.cpp create mode 100644 trunk/src/objcache.h create mode 100644 trunk/src/outputgen.cpp create mode 100644 trunk/src/outputgen.h create mode 100644 trunk/src/outputlist.cpp create mode 100644 trunk/src/outputlist.h create mode 100644 trunk/src/pagedef.cpp create mode 100644 trunk/src/pagedef.h create mode 100644 trunk/src/parserintf.h create mode 100644 trunk/src/perlmodgen.cpp create mode 100644 trunk/src/perlmodgen.h create mode 100644 trunk/src/portable.cpp create mode 100644 trunk/src/portable.h create mode 100644 trunk/src/portable_c.c create mode 100644 trunk/src/pre.h create mode 100644 trunk/src/pre.l create mode 100644 trunk/src/printdocvisitor.h create mode 100644 trunk/src/pycode.h create mode 100644 trunk/src/pycode.l create mode 100644 trunk/src/pyscanner.h create mode 100644 trunk/src/pyscanner.l create mode 100644 trunk/src/qhp.cpp create mode 100644 trunk/src/qhp.h create mode 100644 trunk/src/qhpxmlwriter.cpp create mode 100644 trunk/src/qhpxmlwriter.h create mode 100644 trunk/src/qtbc.h create mode 100644 trunk/src/reflist.cpp create mode 100644 trunk/src/reflist.h create mode 100644 trunk/src/resize.js create mode 100644 trunk/src/resize_js.h create mode 100644 trunk/src/rtfdocvisitor.cpp create mode 100644 trunk/src/rtfdocvisitor.h create mode 100644 trunk/src/rtfgen.cpp create mode 100644 trunk/src/rtfgen.h create mode 100644 trunk/src/rtfstyle.cpp create mode 100644 trunk/src/rtfstyle.h create mode 100644 trunk/src/scanner.h create mode 100644 trunk/src/scanner.l create mode 100644 trunk/src/search.css create mode 100644 trunk/src/search.js create mode 100644 trunk/src/search_css.h create mode 100644 trunk/src/search_functions.php create mode 100644 trunk/src/search_functions_php.h create mode 100644 trunk/src/search_js.h create mode 100644 trunk/src/search_opensearch.php create mode 100644 trunk/src/search_opensearch_php.h create mode 100644 trunk/src/searchindex.cpp create mode 100644 trunk/src/searchindex.h create mode 100644 trunk/src/section.h create mode 100644 trunk/src/sizzle.js create mode 100644 trunk/src/sizzle_js.h create mode 100644 trunk/src/sortdict.h create mode 100644 trunk/src/store.cpp create mode 100644 trunk/src/store.h create mode 100644 trunk/src/svgpan.js create mode 100644 trunk/src/svgpan_js.h create mode 100644 trunk/src/tagreader.cpp create mode 100644 trunk/src/tagreader.h create mode 100644 trunk/src/tclscanner.h create mode 100644 trunk/src/tclscanner.l create mode 100644 trunk/src/textdocvisitor.cpp create mode 100644 trunk/src/textdocvisitor.h create mode 100644 trunk/src/translator.cpp create mode 100644 trunk/src/translator.h create mode 100644 trunk/src/translator_adapter.h create mode 100644 trunk/src/translator_am.h create mode 100644 trunk/src/translator_ar.h create mode 100644 trunk/src/translator_br.h create mode 100644 trunk/src/translator_ca.h create mode 100644 trunk/src/translator_cn.h create mode 100644 trunk/src/translator_cz.h create mode 100644 trunk/src/translator_de.h create mode 100644 trunk/src/translator_dk.h create mode 100644 trunk/src/translator_en.h create mode 100644 trunk/src/translator_eo.h create mode 100644 trunk/src/translator_es.h create mode 100644 trunk/src/translator_fa.h create mode 100644 trunk/src/translator_fi.h create mode 100644 trunk/src/translator_fr.h create mode 100644 trunk/src/translator_gr.h create mode 100644 trunk/src/translator_hr.h create mode 100644 trunk/src/translator_hu.h create mode 100644 trunk/src/translator_id.h create mode 100644 trunk/src/translator_it.h create mode 100644 trunk/src/translator_je.h create mode 100644 trunk/src/translator_jp.h create mode 100644 trunk/src/translator_ke.h create mode 100644 trunk/src/translator_kr.h create mode 100644 trunk/src/translator_lt.h create mode 100644 trunk/src/translator_mk.h create mode 100644 trunk/src/translator_nl.h create mode 100644 trunk/src/translator_no.h create mode 100644 trunk/src/translator_pl.h create mode 100644 trunk/src/translator_pt.h create mode 100644 trunk/src/translator_ro.h create mode 100644 trunk/src/translator_ru.h create mode 100644 trunk/src/translator_sc.h create mode 100644 trunk/src/translator_si.h create mode 100644 trunk/src/translator_sk.h create mode 100644 trunk/src/translator_sr.h create mode 100644 trunk/src/translator_sv.h create mode 100644 trunk/src/translator_tr.h create mode 100644 trunk/src/translator_tw.h create mode 100644 trunk/src/translator_ua.h create mode 100644 trunk/src/translator_vi.h create mode 100644 trunk/src/translator_za.h create mode 100644 trunk/src/translatordecoder.h create mode 100644 trunk/src/types.h create mode 100644 trunk/src/util.cpp create mode 100644 trunk/src/util.h create mode 100644 trunk/src/version.h create mode 100644 trunk/src/vhdlcode.h create mode 100644 trunk/src/vhdlcode.l create mode 100644 trunk/src/vhdldocgen.cpp create mode 100644 trunk/src/vhdldocgen.h create mode 100644 trunk/src/vhdlparser.y create mode 100644 trunk/src/vhdlscanner.h create mode 100644 trunk/src/vhdlscanner.l create mode 100644 trunk/src/xmldocvisitor.cpp create mode 100644 trunk/src/xmldocvisitor.h create mode 100644 trunk/src/xmlgen.cpp create mode 100644 trunk/src/xmlgen.h create mode 100644 trunk/tmake/CHANGES create mode 100644 trunk/tmake/LICENSE create mode 100644 trunk/tmake/README create mode 100755 trunk/tmake/bin/progen create mode 100755 trunk/tmake/bin/tmake create mode 100644 trunk/tmake/doc/m-linux-gcc.html create mode 100644 trunk/tmake/doc/m-win32-msvc.html create mode 100644 trunk/tmake/doc/tmake.html create mode 100644 trunk/tmake/doc/tmake_ref.html create mode 100644 trunk/tmake/example/hello.cpp create mode 100644 trunk/tmake/example/hello.h create mode 100644 trunk/tmake/example/hello.pro create mode 100644 trunk/tmake/example/main.cpp create mode 100644 trunk/tmake/example/wc.t create mode 100755 trunk/tmake/lib/aix-g++/app.t create mode 100755 trunk/tmake/lib/aix-g++/lib.t create mode 100755 trunk/tmake/lib/aix-g++/subdirs.t create mode 100755 trunk/tmake/lib/aix-g++/tmake.conf create mode 100755 trunk/tmake/lib/aix-xlc/app.t create mode 100755 trunk/tmake/lib/aix-xlc/lib.t create mode 100755 trunk/tmake/lib/aix-xlc/subdirs.t create mode 100755 trunk/tmake/lib/aix-xlc/tmake.conf create mode 100755 trunk/tmake/lib/beos-g++/app.t create mode 100755 trunk/tmake/lib/beos-g++/lib.t create mode 100755 trunk/tmake/lib/beos-g++/subdirs.t create mode 100755 trunk/tmake/lib/beos-g++/tmake.conf create mode 100755 trunk/tmake/lib/bsdi-g++/app.t create mode 100755 trunk/tmake/lib/bsdi-g++/lib.t create mode 100755 trunk/tmake/lib/bsdi-g++/subdirs.t create mode 100755 trunk/tmake/lib/bsdi-g++/tmake.conf create mode 100755 trunk/tmake/lib/dgux-g++/app.t create mode 100755 trunk/tmake/lib/dgux-g++/lib.t create mode 100755 trunk/tmake/lib/dgux-g++/subdirs.t create mode 100755 trunk/tmake/lib/dgux-g++/tmake.conf create mode 100755 trunk/tmake/lib/freebsd-g++/app.t create mode 100755 trunk/tmake/lib/freebsd-g++/lib.t create mode 100755 trunk/tmake/lib/freebsd-g++/subdirs.t create mode 100755 trunk/tmake/lib/freebsd-g++/tmake.conf create mode 100755 trunk/tmake/lib/gnu-g++/app.t create mode 100755 trunk/tmake/lib/gnu-g++/lib.t create mode 100755 trunk/tmake/lib/gnu-g++/subdirs.t create mode 100755 trunk/tmake/lib/gnu-g++/tmake.conf create mode 100755 trunk/tmake/lib/hpux-acc/app.t create mode 100755 trunk/tmake/lib/hpux-acc/lib.t create mode 100755 trunk/tmake/lib/hpux-acc/subdirs.t create mode 100755 trunk/tmake/lib/hpux-acc/tmake.conf create mode 100755 trunk/tmake/lib/hpux-cc/app.t create mode 100755 trunk/tmake/lib/hpux-cc/lib.t create mode 100755 trunk/tmake/lib/hpux-cc/subdirs.t create mode 100755 trunk/tmake/lib/hpux-cc/tmake.conf create mode 100755 trunk/tmake/lib/hpux-g++/app.t create mode 100755 trunk/tmake/lib/hpux-g++/lib.t create mode 100755 trunk/tmake/lib/hpux-g++/subdirs.t create mode 100755 trunk/tmake/lib/hpux-g++/tmake.conf create mode 100755 trunk/tmake/lib/irix-64/app.t create mode 100755 trunk/tmake/lib/irix-64/lib.t create mode 100755 trunk/tmake/lib/irix-64/subdirs.t create mode 100755 trunk/tmake/lib/irix-64/tmake.conf create mode 100755 trunk/tmake/lib/irix-dcc/app.t create mode 100755 trunk/tmake/lib/irix-dcc/lib.t create mode 100755 trunk/tmake/lib/irix-dcc/subdirs.t create mode 100755 trunk/tmake/lib/irix-dcc/tmake.conf create mode 100755 trunk/tmake/lib/irix-g++/app.t create mode 100755 trunk/tmake/lib/irix-g++/lib.t create mode 100755 trunk/tmake/lib/irix-g++/subdirs.t create mode 100755 trunk/tmake/lib/irix-g++/tmake.conf create mode 100755 trunk/tmake/lib/irix-n32/app.t create mode 100755 trunk/tmake/lib/irix-n32/lib.t create mode 100755 trunk/tmake/lib/irix-n32/subdirs.t create mode 100755 trunk/tmake/lib/irix-n32/tmake.conf create mode 100755 trunk/tmake/lib/irix-o32/app.t create mode 100755 trunk/tmake/lib/irix-o32/lib.t create mode 100755 trunk/tmake/lib/irix-o32/subdirs.t create mode 100755 trunk/tmake/lib/irix-o32/tmake.conf create mode 100644 trunk/tmake/lib/linux-64/app.t create mode 100644 trunk/tmake/lib/linux-64/lib.t create mode 100644 trunk/tmake/lib/linux-64/subdirs.t create mode 100644 trunk/tmake/lib/linux-64/tmake.conf create mode 100755 trunk/tmake/lib/linux-g++/app.t create mode 100755 trunk/tmake/lib/linux-g++/lib.t create mode 100755 trunk/tmake/lib/linux-g++/subdirs.t create mode 100755 trunk/tmake/lib/linux-g++/tmake.conf create mode 100755 trunk/tmake/lib/m68k-atari-mint-g++/app.t create mode 100755 trunk/tmake/lib/m68k-atari-mint-g++/lib.t create mode 100755 trunk/tmake/lib/m68k-atari-mint-g++/subdirs.t create mode 100755 trunk/tmake/lib/m68k-atari-mint-g++/tmake.conf create mode 100755 trunk/tmake/lib/macosx-c++/app.t create mode 100755 trunk/tmake/lib/macosx-c++/lib.t create mode 100755 trunk/tmake/lib/macosx-c++/subdirs.t create mode 100755 trunk/tmake/lib/macosx-c++/tmake.conf create mode 100644 trunk/tmake/lib/macosx-uni-c++/app.t create mode 100644 trunk/tmake/lib/macosx-uni-c++/lib.t create mode 100644 trunk/tmake/lib/macosx-uni-c++/subdirs.t create mode 100644 trunk/tmake/lib/macosx-uni-c++/tmake.conf create mode 100755 trunk/tmake/lib/netbsd-g++/app.t create mode 100755 trunk/tmake/lib/netbsd-g++/lib.t create mode 100755 trunk/tmake/lib/netbsd-g++/subdirs.t create mode 100755 trunk/tmake/lib/netbsd-g++/tmake.conf create mode 100755 trunk/tmake/lib/openbsd-g++/app.t create mode 100755 trunk/tmake/lib/openbsd-g++/lib.t create mode 100755 trunk/tmake/lib/openbsd-g++/subdirs.t create mode 100755 trunk/tmake/lib/openbsd-g++/tmake.conf create mode 100755 trunk/tmake/lib/osf1-cxx/app.t create mode 100755 trunk/tmake/lib/osf1-cxx/lib.t create mode 100755 trunk/tmake/lib/osf1-cxx/subdirs.t create mode 100755 trunk/tmake/lib/osf1-cxx/tmake.conf create mode 100755 trunk/tmake/lib/osf1-g++/app.t create mode 100755 trunk/tmake/lib/osf1-g++/lib.t create mode 100755 trunk/tmake/lib/osf1-g++/subdirs.t create mode 100755 trunk/tmake/lib/osf1-g++/tmake.conf create mode 100755 trunk/tmake/lib/qnx-g++/app.t create mode 100755 trunk/tmake/lib/qnx-g++/lib.t create mode 100755 trunk/tmake/lib/qnx-g++/subdirs.t create mode 100755 trunk/tmake/lib/qnx-g++/tmake.conf create mode 100755 trunk/tmake/lib/sco-g++/app.t create mode 100755 trunk/tmake/lib/sco-g++/lib.t create mode 100755 trunk/tmake/lib/sco-g++/subdirs.t create mode 100755 trunk/tmake/lib/sco-g++/tmake.conf create mode 100644 trunk/tmake/lib/solaris-cc-64/app.t create mode 100644 trunk/tmake/lib/solaris-cc-64/lib.t create mode 100644 trunk/tmake/lib/solaris-cc-64/subdirs.t create mode 100644 trunk/tmake/lib/solaris-cc-64/tmake.conf create mode 100755 trunk/tmake/lib/solaris-cc-gcc/app.t create mode 100755 trunk/tmake/lib/solaris-cc-gcc/lib.t create mode 100755 trunk/tmake/lib/solaris-cc-gcc/subdirs.t create mode 100755 trunk/tmake/lib/solaris-cc-gcc/tmake.conf create mode 100755 trunk/tmake/lib/solaris-cc/app.t create mode 100755 trunk/tmake/lib/solaris-cc/lib.t create mode 100755 trunk/tmake/lib/solaris-cc/subdirs.t create mode 100755 trunk/tmake/lib/solaris-cc/tmake.conf create mode 100755 trunk/tmake/lib/solaris-g++/app.t create mode 100755 trunk/tmake/lib/solaris-g++/lib.t create mode 100755 trunk/tmake/lib/solaris-g++/subdirs.t create mode 100755 trunk/tmake/lib/solaris-g++/tmake.conf create mode 100755 trunk/tmake/lib/sunos-g++/app.t create mode 100755 trunk/tmake/lib/sunos-g++/lib.t create mode 100755 trunk/tmake/lib/sunos-g++/subdirs.t create mode 100755 trunk/tmake/lib/sunos-g++/tmake.conf create mode 100755 trunk/tmake/lib/ultrix-g++/app.t create mode 100755 trunk/tmake/lib/ultrix-g++/lib.t create mode 100755 trunk/tmake/lib/ultrix-g++/subdirs.t create mode 100755 trunk/tmake/lib/ultrix-g++/tmake.conf create mode 100755 trunk/tmake/lib/unix/app.t create mode 100755 trunk/tmake/lib/unix/generic.t create mode 100755 trunk/tmake/lib/unix/lib.t create mode 100755 trunk/tmake/lib/unix/subdirs.t create mode 100755 trunk/tmake/lib/unixware-g++/app.t create mode 100755 trunk/tmake/lib/unixware-g++/lib.t create mode 100755 trunk/tmake/lib/unixware-g++/subdirs.t create mode 100755 trunk/tmake/lib/unixware-g++/tmake.conf create mode 100755 trunk/tmake/lib/unixware7-cc/app.t create mode 100755 trunk/tmake/lib/unixware7-cc/lib.t create mode 100755 trunk/tmake/lib/unixware7-cc/subdirs.t create mode 100755 trunk/tmake/lib/unixware7-cc/tmake.conf create mode 100755 trunk/tmake/lib/unixware7-g++/app.t create mode 100755 trunk/tmake/lib/unixware7-g++/lib.t create mode 100755 trunk/tmake/lib/unixware7-g++/subdirs.t create mode 100755 trunk/tmake/lib/unixware7-g++/tmake.conf create mode 100755 trunk/tmake/lib/win32-borland/app.t create mode 100755 trunk/tmake/lib/win32-borland/generic.t create mode 100755 trunk/tmake/lib/win32-borland/lib.t create mode 100755 trunk/tmake/lib/win32-borland/subdirs.t create mode 100755 trunk/tmake/lib/win32-borland/tmake.conf create mode 100755 trunk/tmake/lib/win32-g++/app.t create mode 100755 trunk/tmake/lib/win32-g++/generic.t create mode 100755 trunk/tmake/lib/win32-g++/lib.t create mode 100755 trunk/tmake/lib/win32-g++/subdirs.t create mode 100755 trunk/tmake/lib/win32-g++/tmake.conf create mode 100755 trunk/tmake/lib/win32-mingw/app.t create mode 100755 trunk/tmake/lib/win32-mingw/generic.t create mode 100755 trunk/tmake/lib/win32-mingw/lib.t create mode 100755 trunk/tmake/lib/win32-mingw/subdirs.t create mode 100755 trunk/tmake/lib/win32-mingw/tmake.conf create mode 100755 trunk/tmake/lib/win32-msvc/app.t create mode 100755 trunk/tmake/lib/win32-msvc/generic.t create mode 100755 trunk/tmake/lib/win32-msvc/lib.t create mode 100755 trunk/tmake/lib/win32-msvc/subdirs.t create mode 100755 trunk/tmake/lib/win32-msvc/tmake.conf create mode 100755 trunk/tmake/lib/win32-msvc/vcapp.t create mode 100755 trunk/tmake/lib/win32-msvc/vclib.t create mode 100755 trunk/tmake/lib/win32-symantec/app.t create mode 100755 trunk/tmake/lib/win32-symantec/generic.t create mode 100755 trunk/tmake/lib/win32-symantec/lib.t create mode 100755 trunk/tmake/lib/win32-symantec/subdirs.t create mode 100755 trunk/tmake/lib/win32-symantec/tmake.conf create mode 100755 trunk/tmake/lib/win32-visage/app.t create mode 100755 trunk/tmake/lib/win32-visage/generic.t create mode 100755 trunk/tmake/lib/win32-visage/lib.t create mode 100755 trunk/tmake/lib/win32-visage/subdirs.t create mode 100755 trunk/tmake/lib/win32-visage/tmake.conf create mode 100755 trunk/tmake/lib/win32-watcom/app.t create mode 100755 trunk/tmake/lib/win32-watcom/generic.t create mode 100755 trunk/tmake/lib/win32-watcom/lib.t create mode 100755 trunk/tmake/lib/win32-watcom/subdirs.t create mode 100755 trunk/tmake/lib/win32-watcom/tmake.conf create mode 100755 trunk/tmake/lib/win32/subdirs.t create mode 100644 trunk/winbuild/Doxygen.sln create mode 100644 trunk/winbuild/Doxygen.vcproj create mode 100644 trunk/winbuild/Doxywizard.vcproj create mode 100644 trunk/winbuild/Lex.rules create mode 100644 trunk/winbuild/iconv.h create mode 100644 trunk/winbuild/iconv.lib create mode 100644 trunk/winbuild/iconv.vcproj create mode 100644 trunk/winbuild/iconv64.lib create mode 100644 trunk/winbuild/moc.rules create mode 100644 trunk/winbuild/qtools.vcproj create mode 100644 trunk/winbuild/runbison.bat create mode 100644 trunk/winbuild/unistd.h create mode 100644 trunk/winbuild/version.bat diff --git a/trunk/CVSROOT/checkoutlist b/trunk/CVSROOT/checkoutlist new file mode 100644 index 0000000..b04b350 --- /dev/null +++ b/trunk/CVSROOT/checkoutlist @@ -0,0 +1,13 @@ +# The "checkoutlist" file is used to support additional version controlled +# administrative files in $CVSROOT/CVSROOT, such as template files. +# +# The first entry on a line is a filename which will be checked out from +# the corresponding RCS file in the $CVSROOT/CVSROOT directory. +# The remainder of the line is an error message to use if the file cannot +# be checked out. +# +# File format: +# +# [] +# +# comment lines begin with '#' diff --git a/trunk/CVSROOT/commitinfo b/trunk/CVSROOT/commitinfo new file mode 100644 index 0000000..b19e7b7 --- /dev/null +++ b/trunk/CVSROOT/commitinfo @@ -0,0 +1,15 @@ +# The "commitinfo" file is used to control pre-commit checks. +# The filter on the right is invoked with the repository and a list +# of files to check. A non-zero exit of the filter program will +# cause the commit to be aborted. +# +# The first entry on a line is a regular expression which is tested +# against the directory that the change is being committed to, relative +# to the $CVSROOT. For the first match that is found, then the remainder +# of the line is the name of the filter to run. +# +# If the repository name does not match any of the regular expressions in this +# file, the "DEFAULT" line is used, if it is specified. +# +# If the name "ALL" appears as a regular expression it is always used +# in addition to the first matching regex or "DEFAULT". diff --git a/trunk/CVSROOT/config b/trunk/CVSROOT/config new file mode 100644 index 0000000..8817419 --- /dev/null +++ b/trunk/CVSROOT/config @@ -0,0 +1,9 @@ +# Set this to "no" if pserver shouldn't check system users/passwords +#SystemAuth=no + +# Set `PreservePermissions' to `yes' to save file status information +# in the repository. +#PreservePermissions=no + +TopLevelAdmin=yes +#LockDir=/u/kp3softd/cvslocks/ diff --git a/trunk/CVSROOT/cvswrappers b/trunk/CVSROOT/cvswrappers new file mode 100644 index 0000000..0c725ea --- /dev/null +++ b/trunk/CVSROOT/cvswrappers @@ -0,0 +1,23 @@ +# This file affects handling of files based on their names. +# +# The -t/-f options allow one to treat directories of files +# as a single file, or to transform a file in other ways on +# its way in and out of CVS. +# +# The -m option specifies whether CVS attempts to merge files. +# +# The -k option specifies keyword expansion (e.g. -kb for binary). +# +# Format of wrapper file ($CVSROOT/CVSROOT/cvswrappers or .cvswrappers) +# +# wildcard [option value][option value]... +# +# where option is one of +# -f from cvs filter value: path to filter +# -t to cvs filter value: path to filter +# -m update methodology value: MERGE or COPY +# -k expansion mode value: b, o, kkv, &c +# +# and value is a single-quote delimited value. +# For example: +*.gif -k 'b' -m 'COPY' diff --git a/trunk/CVSROOT/editinfo b/trunk/CVSROOT/editinfo new file mode 100644 index 0000000..d78886c --- /dev/null +++ b/trunk/CVSROOT/editinfo @@ -0,0 +1,21 @@ +# The "editinfo" file is used to allow verification of logging +# information. It works best when a template (as specified in the +# rcsinfo file) is provided for the logging procedure. Given a +# template with locations for, a bug-id number, a list of people who +# reviewed the code before it can be checked in, and an external +# process to catalog the differences that were code reviewed, the +# following test can be applied to the code: +# +# Making sure that the entered bug-id number is correct. +# Validating that the code that was reviewed is indeed the code being +# checked in (using the bug-id number or a seperate review +# number to identify this particular code set.). +# +# If any of the above test failed, then the commit would be aborted. +# +# Actions such as mailing a copy of the report to each reviewer are +# better handled by an entry in the loginfo file. +# +# One thing that should be noted is the the ALL keyword is not +# supported. There can be only one entry that matches a given +# repository. diff --git a/trunk/CVSROOT/loginfo b/trunk/CVSROOT/loginfo new file mode 100644 index 0000000..5a59f0a --- /dev/null +++ b/trunk/CVSROOT/loginfo @@ -0,0 +1,26 @@ +# The "loginfo" file controls where "cvs commit" log information +# is sent. The first entry on a line is a regular expression which must match +# the directory that the change is being made to, relative to the +# $CVSROOT. If a match is found, then the remainder of the line is a filter +# program that should expect log information on its standard input. +# +# If the repository name does not match any of the regular expressions in this +# file, the "DEFAULT" line is used, if it is specified. +# +# If the name ALL appears as a regular expression it is always used +# in addition to the first matching regex or DEFAULT. +# +# You may specify a format string as part of the +# filter. The string is composed of a `%' followed +# by a single format character, or followed by a set of format +# characters surrounded by `{' and `}' as separators. The format +# characters are: +# +# s = file name +# V = old version number (pre-checkin) +# v = new version number (post-checkin) +# +# For example: +#DEFAULT (echo ""; id; echo %s; date; cat) >> $CVSROOT/CVSROOT/commitlog +# or +#DEFAULT (echo ""; id; echo %{sVv}; date; cat) >> $CVSROOT/CVSROOT/commitlog diff --git a/trunk/CVSROOT/modules b/trunk/CVSROOT/modules new file mode 100644 index 0000000..581582c --- /dev/null +++ b/trunk/CVSROOT/modules @@ -0,0 +1,27 @@ +# Three different line formats are valid: +# key -a aliases... +# key [options] directory +# key [options] directory files... +# +# Where "options" are composed of: +# -i prog Run "prog" on "cvs commit" from top-level of module. +# -o prog Run "prog" on "cvs checkout" of module. +# -e prog Run "prog" on "cvs export" of module. +# -t prog Run "prog" on "cvs rtag" of module. +# -u prog Run "prog" on "cvs update" of module. +# -d dir Place module in directory "dir" instead of module name. +# -l Top-level directory only -- do not recurse. +# +# NOTE: If you change any of the "Run" options above, you'll have to +# release and re-checkout any working directories of these modules. +# +# And "directory" is a path to a directory relative to $CVSROOT. +# +# The "-a" option specifies an alias. An alias is interpreted as if +# everything on the right of the "-a" had been typed on the command line. +# +# You can encode a module within a module by using the special '&' +# character to interpose another module into the current module. This +# can be useful for creating a module that consists of many directories +# spread out over the entire source repository. +doxygen -a addon bin doc examples html lib objects packages qtools src tmake wintools libpng libmd5 diff --git a/trunk/CVSROOT/notify b/trunk/CVSROOT/notify new file mode 100644 index 0000000..34f0bc2 --- /dev/null +++ b/trunk/CVSROOT/notify @@ -0,0 +1,12 @@ +# The "notify" file controls where notifications from watches set by +# "cvs watch add" or "cvs edit" are sent. The first entry on a line is +# a regular expression which is tested against the directory that the +# change is being made to, relative to the $CVSROOT. If it matches, +# then the remainder of the line is a filter program that should contain +# one occurrence of %s for the user to notify, and information on its +# standard input. +# +# "ALL" or "DEFAULT" can be used in place of the regular expression. +# +# For example: +#ALL mail %s -s "CVS notification" diff --git a/trunk/CVSROOT/rcsinfo b/trunk/CVSROOT/rcsinfo new file mode 100644 index 0000000..49e59f4 --- /dev/null +++ b/trunk/CVSROOT/rcsinfo @@ -0,0 +1,13 @@ +# The "rcsinfo" file is used to control templates with which the editor +# is invoked on commit and import. +# +# The first entry on a line is a regular expression which is tested +# against the directory that the change is being made to, relative to the +# $CVSROOT. For the first match that is found, then the remainder of the +# line is the name of the file that contains the template. +# +# If the repository name does not match any of the regular expressions in this +# file, the "DEFAULT" line is used, if it is specified. +# +# If the name "ALL" appears as a regular expression it is always used +# in addition to the first matching regex or "DEFAULT". diff --git a/trunk/CVSROOT/taginfo b/trunk/CVSROOT/taginfo new file mode 100644 index 0000000..274a46d --- /dev/null +++ b/trunk/CVSROOT/taginfo @@ -0,0 +1,20 @@ +# The "taginfo" file is used to control pre-tag checks. +# The filter on the right is invoked with the following arguments: +# +# $1 -- tagname +# $2 -- operation "add" for tag, "mov" for tag -F, and "del" for tag -d +# $3 -- repository +# $4-> file revision [file revision ...] +# +# A non-zero exit of the filter program will cause the tag to be aborted. +# +# The first entry on a line is a regular expression which is tested +# against the directory that the change is being committed to, relative +# to the $CVSROOT. For the first match that is found, then the remainder +# of the line is the name of the filter to run. +# +# If the repository name does not match any of the regular expressions in this +# file, the "DEFAULT" line is used, if it is specified. +# +# If the name "ALL" appears as a regular expression it is always used +# in addition to the first matching regex or "DEFAULT". diff --git a/trunk/CVSROOT/verifymsg b/trunk/CVSROOT/verifymsg new file mode 100644 index 0000000..86f747c --- /dev/null +++ b/trunk/CVSROOT/verifymsg @@ -0,0 +1,21 @@ +# The "verifymsg" file is used to allow verification of logging +# information. It works best when a template (as specified in the +# rcsinfo file) is provided for the logging procedure. Given a +# template with locations for, a bug-id number, a list of people who +# reviewed the code before it can be checked in, and an external +# process to catalog the differences that were code reviewed, the +# following test can be applied to the code: +# +# Making sure that the entered bug-id number is correct. +# Validating that the code that was reviewed is indeed the code being +# checked in (using the bug-id number or a seperate review +# number to identify this particular code set.). +# +# If any of the above test failed, then the commit would be aborted. +# +# Actions such as mailing a copy of the report to each reviewer are +# better handled by an entry in the loginfo file. +# +# One thing that should be noted is the the ALL keyword is not +# supported. There can be only one entry that matches a given +# repository. diff --git a/trunk/Doxyfile b/trunk/Doxyfile new file mode 100644 index 0000000..335bc00 --- /dev/null +++ b/trunk/Doxyfile @@ -0,0 +1,311 @@ +# Doxyfile 1.6.3 + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- +DOXYFILE_ENCODING = UTF-8 +PROJECT_NAME = Doxygen +PROJECT_NUMBER = +OUTPUT_DIRECTORY = doxygen_docs +CREATE_SUBDIRS = NO +OUTPUT_LANGUAGE = English +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ABBREVIATE_BRIEF = +ALWAYS_DETAILED_SEC = NO +INLINE_INHERITED_MEMB = NO +FULL_PATH_NAMES = YES +STRIP_FROM_PATH = +STRIP_FROM_INC_PATH = +SHORT_NAMES = NO +JAVADOC_AUTOBRIEF = YES +QT_AUTOBRIEF = NO +MULTILINE_CPP_IS_BRIEF = NO +INHERIT_DOCS = YES +SEPARATE_MEMBER_PAGES = NO +TAB_SIZE = 8 +ALIASES = +OPTIMIZE_OUTPUT_FOR_C = NO +OPTIMIZE_OUTPUT_JAVA = NO +OPTIMIZE_FOR_FORTRAN = NO +OPTIMIZE_OUTPUT_VHDL = NO +EXTENSION_MAPPING = +BUILTIN_STL_SUPPORT = NO +CPP_CLI_SUPPORT = NO +SIP_SUPPORT = NO +IDL_PROPERTY_SUPPORT = YES +DISTRIBUTE_GROUP_DOC = NO +SUBGROUPING = YES +TYPEDEF_HIDES_STRUCT = NO +SYMBOL_CACHE_SIZE = 0 +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- +EXTRACT_ALL = YES +EXTRACT_PRIVATE = YES +EXTRACT_STATIC = YES +EXTRACT_LOCAL_CLASSES = YES +EXTRACT_LOCAL_METHODS = NO +EXTRACT_ANON_NSPACES = NO +HIDE_UNDOC_MEMBERS = NO +HIDE_UNDOC_CLASSES = NO +HIDE_FRIEND_COMPOUNDS = NO +HIDE_IN_BODY_DOCS = NO +INTERNAL_DOCS = NO +CASE_SENSE_NAMES = NO +HIDE_SCOPE_NAMES = NO +SHOW_INCLUDE_FILES = YES +FORCE_LOCAL_INCLUDES = NO +INLINE_INFO = YES +SORT_MEMBER_DOCS = YES +SORT_BRIEF_DOCS = NO +SORT_MEMBERS_CTORS_1ST = NO +SORT_GROUP_NAMES = NO +SORT_BY_SCOPE_NAME = NO +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = YES +GENERATE_BUGLIST = YES +GENERATE_DEPRECATEDLIST= YES +ENABLED_SECTIONS = +MAX_INITIALIZER_LINES = 30 +SHOW_USED_FILES = YES +SHOW_DIRECTORIES = YES +SHOW_FILES = YES +SHOW_NAMESPACES = YES +FILE_VERSION_FILTER = +LAYOUT_FILE = +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- +QUIET = NO +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_IF_DOC_ERROR = YES +WARN_NO_PARAMDOC = NO +WARN_FORMAT = "$file:$line: $text " +WARN_LOGFILE = +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- +INPUT = src +INPUT_ENCODING = UTF-8 +FILE_PATTERNS = *.h \ + *.cpp +RECURSIVE = NO +EXCLUDE = src/code.cpp \ + src/ce_lex.cpp \ + src/ce_parse.cpp \ + src/declinfo.cpp \ + src/defargs.cpp \ + src/doxytag.cpp \ + src/pre.cpp \ + src/scanner.cpp \ + src/tag.cpp \ + src/doctokenizer.cpp \ + src/logos.cpp \ + src/suffixtree.cpp \ + src/suffixtree.h \ + src/searchindex.cpp \ + src/searchindex.h \ + src/commentcnv.cpp \ + src/commentscan.cpp \ + src/pycode.cpp \ + src/config.cpp \ + src/pyscanner.cpp \ + src/fortranscanner.cpp \ + src/fortrancode.cpp \ + src/vhdlscanner.cpp \ + src/vhdlcode.cpp \ + src/doxygen_css.h \ + src/doxygen_js.h \ + src/doxygen_php.h \ + src/compound_xsd.h \ + src/layout_default.h \ + src/bib2xhtml.h \ + src/doxygen_bst.h \ + src/header_html.h \ + src/index_xsd.h \ + src/jquery_js.h \ + src/jquery_fx_js.h \ + src/jquery_ui_js.h \ + src/navtree_css.h \ + src/navtree_hs.h \ + src/search_css.h \ + src/search_functions_php.h \ + src/search_opensearch_php.h \ + src/search_js.h \ + src/sizzle_js.h +EXCLUDE_SYMLINKS = NO +EXCLUDE_PATTERNS = +EXCLUDE_SYMBOLS = +EXAMPLE_PATH = +EXAMPLE_PATTERNS = +EXAMPLE_RECURSIVE = NO +IMAGE_PATH = +INPUT_FILTER = +FILTER_PATTERNS = +FILTER_SOURCE_FILES = NO +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- +SOURCE_BROWSER = YES +INLINE_SOURCES = NO +STRIP_CODE_COMMENTS = YES +REFERENCED_BY_RELATION = YES +REFERENCES_RELATION = YES +REFERENCES_LINK_SOURCE = YES +USE_HTAGS = NO +VERBATIM_HEADERS = YES +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- +ALPHABETICAL_INDEX = YES +COLS_IN_ALPHA_INDEX = 5 +IGNORE_PREFIX = +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- +GENERATE_HTML = YES +HTML_OUTPUT = +HTML_FILE_EXTENSION = .html +HTML_HEADER = +HTML_FOOTER = +HTML_STYLESHEET = +HTML_COLORSTYLE_HUE = 220 +HTML_COLORSTYLE_SAT = 100 +HTML_COLORSTYLE_GAMMA = 80 +HTML_TIMESTAMP = YES +HTML_ALIGN_MEMBERS = YES +HTML_DYNAMIC_SECTIONS = YES +GENERATE_DOCSET = YES +DOCSET_FEEDNAME = "Doxygen docs" +DOCSET_BUNDLE_ID = org.doxygen.Doxygen +DOCSET_PUBLISHER_ID = org.doxygen.Publisher +DOCSET_PUBLISHER_NAME = Publisher +GENERATE_HTMLHELP = NO +CHM_FILE = +HHC_LOCATION = +GENERATE_CHI = NO +CHM_INDEX_ENCODING = +BINARY_TOC = NO +TOC_EXPAND = NO +GENERATE_QHP = NO +QCH_FILE = +QHP_NAMESPACE = org.doxygen.Project +QHP_VIRTUAL_FOLDER = doc +QHP_CUST_FILTER_NAME = +QHP_CUST_FILTER_ATTRS = +QHP_SECT_FILTER_ATTRS = +QHG_LOCATION = +GENERATE_ECLIPSEHELP = NO +ECLIPSE_DOC_ID = org.doxygen.Project +DISABLE_INDEX = YES +ENUM_VALUES_PER_LINE = 4 +GENERATE_TREEVIEW = YES +USE_INLINE_TREES = YES +TREEVIEW_WIDTH = 250 +EXT_LINKS_IN_WINDOW = NO +FORMULA_FONTSIZE = 10 +SEARCHENGINE = YES +SERVER_BASED_SEARCH = NO +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- +GENERATE_LATEX = NO +LATEX_OUTPUT = +LATEX_CMD_NAME = latex +MAKEINDEX_CMD_NAME = makeindex +COMPACT_LATEX = NO +PAPER_TYPE = a4wide +EXTRA_PACKAGES = +LATEX_HEADER = +PDF_HYPERLINKS = YES +USE_PDFLATEX = NO +LATEX_BATCHMODE = NO +LATEX_HIDE_INDICES = NO +LATEX_SOURCE_CODE = NO +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- +GENERATE_RTF = NO +RTF_OUTPUT = +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +RTF_EXTENSIONS_FILE = +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- +GENERATE_MAN = NO +MAN_OUTPUT = +MAN_EXTENSION = .3 +MAN_LINKS = NO +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- +GENERATE_XML = NO +XML_OUTPUT = xml +XML_SCHEMA = +XML_DTD = +XML_PROGRAMLISTING = YES +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- +GENERATE_AUTOGEN_DEF = NO +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- +GENERATE_PERLMOD = NO +PERLMOD_LATEX = NO +PERLMOD_PRETTY = YES +PERLMOD_MAKEVAR_PREFIX = +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = YES +EXPAND_ONLY_PREDEF = YES +SEARCH_INCLUDES = YES +INCLUDE_PATH = +INCLUDE_FILE_PATTERNS = +PREDEFINED = +EXPAND_AS_DEFINED = +SKIP_FUNCTION_MACROS = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- +TAGFILES = qtools_docs/qtools.tag=../../qtools_docs/html +GENERATE_TAGFILE = +ALLEXTERNALS = NO +EXTERNAL_GROUPS = YES +PERL_PATH = /usr/bin/perl +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- +CLASS_DIAGRAMS = NO +MSCGEN_PATH = +HIDE_UNDOC_RELATIONS = YES +HAVE_DOT = YES +DOT_FONTNAME = Helvetica +DOT_FONTSIZE = 10 +DOT_FONTPATH = +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +GROUP_GRAPHS = YES +UML_LOOK = NO +TEMPLATE_RELATIONS = YES +INCLUDE_GRAPH = YES +INCLUDED_BY_GRAPH = YES +CALL_GRAPH = NO +CALLER_GRAPH = NO +GRAPHICAL_HIERARCHY = YES +DIRECTORY_GRAPH = YES +DOT_IMAGE_FORMAT = svg +DOT_PATH = +DOTFILE_DIRS = +DOT_GRAPH_MAX_NODES = 50 +MAX_DOT_GRAPH_DEPTH = 0 +DOT_TRANSPARENT = NO +DOT_MULTI_TARGETS = NO +GENERATE_LEGEND = YES +DOT_CLEANUP = NO diff --git a/trunk/INSTALL b/trunk/INSTALL new file mode 100644 index 0000000..490e762 --- /dev/null +++ b/trunk/INSTALL @@ -0,0 +1,7 @@ +DOXYGEN Version 1.8.0 + +Please read the installation section of the manual +(http://www.doxygen.org/install.html) for instructions. + +-------- +Dimitri van Heesch (17 March 2012) diff --git a/trunk/LANGUAGE.HOWTO b/trunk/LANGUAGE.HOWTO new file mode 100644 index 0000000..e535a05 --- /dev/null +++ b/trunk/LANGUAGE.HOWTO @@ -0,0 +1,50 @@ +This short howto explains how to add support for a new language to Doxygen: + +Just follow these steps: + +1) Tell me which language you want to add support for. If no one else + is already working on support for that language, you will be + assigned as the maintainer for the language. I'll create a + list on Doxygen's homepage, so everyone knows who is doing what. +2) Create a copy of translator_en.h and name it + translator_.h + I'll use xx in the rest of this document. +3) Edit language.cpp: + - Add a #include + - In setTranslator() add + + else if (L_EQUAL("your_language_name")) + { + theTranslator = new TranslatorYourLanguage; + } + + after the if { ... } +4) Edit libdoxygen.pro.in and add translator_xx.h to the HEADERS line. +5) Edit translator_xx.h: + - Change TRANSLATOR_EN_H to TRANSLATOR_XX_H (in both the #include line and + the #define line). + - Change TranslatorEnglish to TranslatorYourLanguage + - In the member idLanguage() change "english" into the name of your + language (use lower case characters only). Depending on the language you + may also wish to change the member functions latexLanguageSupportCommand() + and idLanguageCharset(). + - Edit all the strings that are returned by the members that start + with tr. Try to match punctuation and capitals! + To enter special characters (with accents) you can: + a) 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 + leave the Html and man output for what it is (which is fine, if + idLanguageCharset() is set correctly). + b) Use html codes like ä for an a with an umlaut (i.e. ). + See the HTML specification for the codes. +6) Run configure and make again from the root of the distribution, + in order to regenerate the Makefiles. +7) Now you can use OUTPUT_LANGUAGE = your_language_name + in the config file to generate output in your language. +8) Send translator_xx.h to me so I can add it to doxygen. + Send also your name and e-mail address to be included in the + maintainers.txt list. + +Good luck, and let me know if there are problems. + diff --git a/trunk/LICENSE b/trunk/LICENSE new file mode 100644 index 0000000..219ec28 --- /dev/null +++ b/trunk/LICENSE @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) yyyy + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) yyyy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/trunk/Makefile.in b/trunk/Makefile.in new file mode 100644 index 0000000..62e4ff9 --- /dev/null +++ b/trunk/Makefile.in @@ -0,0 +1,135 @@ +#all: src/version.cpp doxywizard +# cd qtools ; $(MAKE) +# cd src ; $(MAKE) + +DESTDIR = + +clean: FORCE + cd examples ; $(MAKE) clean + cd doc ; $(MAKE) clean + cd qtools ; $(MAKE) clean + cd src ; $(MAKE) clean + cd libmd5 ; $(MAKE) clean + -cd addon/doxywizard ; $(MAKE) clean + cd addon/doxmlparser/src ; $(MAKE) clean + cd addon/doxmlparser/test ; $(MAKE) clean + cd addon/doxmlparser/examples/metrics ; $(MAKE) clean + -rm -f bin/doxy* + -rm -f objects/*.o + +distclean: clean + cd src ; $(MAKE) distclean + cd libmd5 ; $(MAKE) distclean + -cd addon/doxywizard ; $(MAKE) distclean + cd addon/doxmlparser/src ; $(MAKE) distclean + cd addon/doxmlparser/test ; $(MAKE) distclean + cd addon/doxmlparser/examples/metrics ; $(MAKE) distclean + cd addon/doxyapp ; $(MAKE) distclean + -rm -f lib/lib* + -rm -f bin/doxy* + -rm -f html + -rm -f latex + -rm -f objects/*.o + -rm -f src/Makefile.doxygen src/Makefile.libdoxygen + -rm -f src/Makefile.libdoxycfg src/libdoxycfg.t src/libdoxygen.t + -rm -f libmd5/Makefile.libmd5 + -rm -f Makefile qtools/Makefile src/Makefile examples/Makefile doc/Makefile + -rm -f .makeconfig .tmakeconfig + -rm -f src/doxygen.pro src/libdoxygen.pro qtools/qtools.pro src/libdoxycfg.pro libmd5/libmd5.pro + -rm -f src/version.cpp + -rm -r addon/doxywizard/Makefile + -rm -f addon/doxywizard/doxywizard.pro + -rm -f VERSION + -rm -f packages/rpm/doxygen.spec + +DATE=$(shell date "+%B %Y") + +MAN1DIR = man/man1 + +install: doxywizard_install + $(INSTTOOL) -d $(DESTDIR)/$(INSTALL)/bin + $(INSTTOOL) -m 755 bin/doxygen $(DESTDIR)/$(INSTALL)/bin + $(INSTTOOL) -d $(DESTDIR)/$(INSTALL)/$(MAN1DIR) + cat doc/doxygen.1 | sed -e "s/DATE/$(DATE)/g" -e "s/VERSION/$(VERSION)/g" > doxygen.1 + $(INSTTOOL) -m 644 doxygen.1 $(DESTDIR)/$(INSTALL)/$(MAN1DIR)/doxygen.1 + rm doxygen.1 + +install_docs: + $(INSTTOOL) -d $(DESTDIR)/$(DOCDIR) + $(MAKE) -C examples + $(MAKE) -C doc + $(MAKE) -C latex + $(INSTTOOL) -m 644 latex/doxygen_manual.pdf $(DESTDIR)/$(DOCDIR) + cp -r examples $(DESTDIR)/$(DOCDIR) + cp -r html $(DESTDIR)/$(DOCDIR) + +docs: FORCE + cd examples ; $(MAKE) + cd doc ; $(MAKE) + +pdf: docs + cd latex ; $(MAKE) + +DISTFILES = Doxyfile libmd5 addon tmake doc examples bin lib objects \ + qtools src configure configure.bin Makefile.in Makefile.win_nmake.in \ + Makefile.win_make.in INSTALL LANGUAGE.HOWTO LICENSE PLATFORMS \ + VERSION packages winbuild + +archive: clean + tar zcvf dx`date +%y%m%d`.tgz $(DISTFILES) + +DISTDIR = doxygen-`echo $(VERSION) | tr - _` + +dist: clean + rm -rf $(DISTDIR) + mkdir $(DISTDIR) + cp -a $(DISTFILES) README $(DISTDIR) + find $(DISTDIR) \( -name ".svn" \) -print0 | xargs -0 rm -rf + tar zcvf $(DISTDIR).src.tar.gz $(DISTDIR) + rm -rf $(DISTDIR) + +src/version.cpp: Makefile + echo "char versionString[]=\"$(VERSION)\";" > src/version.cpp + +addon/doxywizard/version.cpp: Makefile + echo "char versionString[]=\"$(VERSION)\";" > addon/doxywizard/version.cpp + +DISTDIR = doxygen-`echo $(VERSION) | tr - _` +rpm: dist + gzip -df $(DISTDIR).src.tar.gz + mkdir $(DISTDIR) + mkdir $(DISTDIR)/packages + mkdir $(DISTDIR)/packages/rpm + cp packages/rpm/doxygen.spec $(DISTDIR)/packages/rpm + rm -rf $(DISTDIR) + gzip -9v $(DISTDIR).src.tar + rpmbuild -ta %%WITHDOXYWIZARD%% $(DISTDIR).src.tar.gz + +rpmsrc: dist + gzip -df $(DISTDIR).src.tar.gz + mkdir $(DISTDIR) + mkdir $(DISTDIR)/packages + mkdir $(DISTDIR)/packages/rpm + cp packages/rpm/doxygen.spec $(DISTDIR)/packages/rpm + tar -rvf $(DISTDIR).src.tar $(DISTDIR)/packages/rpm/doxygen.spec + rm -rf $(DISTDIR) + gzip -9v $(DISTDIR).src.tar + rpmbuild -ts %%WITHDOXYWIZARD%% $(DISTDIR).src.tar.gz + +rpmbinary: dist + gzip -df $(DISTDIR).src.tar.gz + mkdir $(DISTDIR) + mkdir $(DISTDIR)/packages + mkdir $(DISTDIR)/packages/rpm + cp packages/rpm/doxygen.spec $(DISTDIR)/packages/rpm + tar -rvf $(DISTDIR).src.tar $(DISTDIR)/packages/rpm/doxygen.spec + rm -rf $(DISTDIR) + gzip -9v $(DISTDIR).src.tar + rpmbuild -tb %%WITHDOXYWIZARD%% $(DISTDIR).src.tar.gz + + +ctags: + ctags -f tags src addon/doxywizard qtools + +FORCE: + diff --git a/trunk/Makefile.win_make.in b/trunk/Makefile.win_make.in new file mode 100644 index 0000000..175dc6f --- /dev/null +++ b/trunk/Makefile.win_make.in @@ -0,0 +1,32 @@ +all: src\version.cpp + set TMAKEPATH=$(TMAKEPATH) & cd qtools & $(MAKE) + set TMAKEPATH=$(TMAKEPATH) & cd libmd5 & $(MAKE) + set TMAKEPATH=$(TMAKEPATH) & cd src & $(MAKE) + +clean: + cd examples & $(MAKE) clean + cd doc & $(MAKE) clean + cd src & $(MAKE) clean + -del bin\doxy*.* + -del objects\*.o + +distclean: clean + -del src\Makefile.libdoxygen \ + src\Makefile.doxygen \ + src\Makefile.libdoxycfg \ + src\libdoxycfg.t src\libdoxygen.t + -del Makefile src\Makefile examples\Makefile doc\Makefile + -del src\libdoxygen.pro src\doxygen.pro src\libdoxycfg.pro + -del src\version.cpp + +docs: + set TMAKEPATH=$(TMAKEPATH) & cd examples & $(MAKE) + set TMAKEPATH=$(TMAKEPATH) & cd doc & $(MAKE) + +ps: docs + cd latex & $(MAKE) + +src\version.cpp: Makefile + echo char versionString[]="""$(VERSION)"""; > src\version.cpp + +FORCE: diff --git a/trunk/Makefile.win_nmake.in b/trunk/Makefile.win_nmake.in new file mode 100644 index 0000000..723d4fd --- /dev/null +++ b/trunk/Makefile.win_nmake.in @@ -0,0 +1,49 @@ +all: src\version.cpp + set TMAKEPATH=$(TMAKEPATH) + cd qtools + $(MAKE) + cd .. + cd libmd5 + $(MAKE) + cd .. + cd src + $(MAKE) + +clean: FORCE + cd examples + $(MAKE) clean + cd .. + cd doc + $(MAKE) clean + cd .. + cd src + $(MAKE) clean + cd .. + -del bin\doxy*.* + -del objects\*.o + +distclean: clean + -del src\Makefile.libdoxygen \ + src\Makefile.doxygen \ + src\Makefile.libdoxycfg \ + src\libdoxycfg.t src\libdoxygen.t + -del Makefile src\Makefile examples\Makefile doc\Makefile + -del src\libdoxygen.pro src\doxygen.pro src\libdoxycfg.pro + -del src\version.cpp + +docs: FORCE + cd examples + $(MAKE) + cd .. + cd doc + $(MAKE) + cd .. + +ps: docs + cd latex + $(MAKE) + +src\version.cpp: Makefile + echo char versionString[]="$(VERSION)"; > src\version.cpp + +FORCE: diff --git a/trunk/PLATFORMS b/trunk/PLATFORMS new file mode 100644 index 0000000..c358a1d --- /dev/null +++ b/trunk/PLATFORMS @@ -0,0 +1,31 @@ +aix-g++ +aix-xlc +beos-g++ +dgux-g++ +freebsd-g++ +gnu-g++ +hpux-acc +hpux-cc +hpux-g++ +irix-64 +irix-dcc +irix-g++ +irix-n32 +linux-g++ +linux-64 +macosx-c++ +macosx-uni-c++ +m68k-atari-mint-g++ +netbsd-g++ +openbsd-g++ +osf1-cxx +osf1-g++ +qnx-g++ +sco-g++ +solaris-cc +solaris-cc-64 +solaris-g++ +sunos-g++ +ultrix-g++ +unixware-g++ +win32-g++ diff --git a/trunk/README b/trunk/README new file mode 100644 index 0000000..432fa63 --- /dev/null +++ b/trunk/README @@ -0,0 +1,29 @@ +DOXYGEN Version 1.8.0 + +Please read INSTALL for compilation instructions. + +The latest version of doxygen can be obtained from: + http://www.doxygen.org/ + +There are three mailing lists: + doxygen-users@lists.sourceforge.net For doxygen users + doxygen-develop@lists.sourceforge.net For doxygen developers + doxygen-announce@lists.sourceforge.net Announcement of new releases only + +please follow the link in + + http://sourceforge.net/projects/doxygen + +to subscribe to the lists or to visit the archives. + +Use the bug tracker to report bugs: + + https://bugzilla.gnome.org/enter_bug.cgi?product=doxygen + +Before reporting a bug, please check that it has not already been reported. +Also, please use the bug tracker for reporting bugs rather than the help +forum. + +Enjoy, + +Dimitri van Heesch (dimitri@stack.nl) (17 March 2012) diff --git a/trunk/addon/doxmlparser/Doxyfile b/trunk/addon/doxmlparser/Doxyfile new file mode 100644 index 0000000..faf4bee --- /dev/null +++ b/trunk/addon/doxmlparser/Doxyfile @@ -0,0 +1,177 @@ +# Doxyfile 1.2.12-20011209 + +#--------------------------------------------------------------------------- +# General configuration options +#--------------------------------------------------------------------------- +PROJECT_NAME = doxmlparser +PROJECT_NUMBER = +OUTPUT_DIRECTORY = doc +OUTPUT_LANGUAGE = English +EXTRACT_ALL = YES +EXTRACT_PRIVATE = YES +EXTRACT_STATIC = YES +EXTRACT_LOCAL_CLASSES = YES +HIDE_UNDOC_MEMBERS = NO +HIDE_UNDOC_CLASSES = NO +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ALWAYS_DETAILED_SEC = NO +INLINE_INHERITED_MEMB = NO +FULL_PATH_NAMES = NO +STRIP_FROM_PATH = +INTERNAL_DOCS = NO +STRIP_CODE_COMMENTS = YES +CASE_SENSE_NAMES = YES +SHORT_NAMES = NO +HIDE_SCOPE_NAMES = NO +VERBATIM_HEADERS = YES +SHOW_INCLUDE_FILES = YES +JAVADOC_AUTOBRIEF = NO +INHERIT_DOCS = YES +INLINE_INFO = YES +SORT_MEMBER_DOCS = YES +DISTRIBUTE_GROUP_DOC = NO +TAB_SIZE = 8 +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = YES +GENERATE_BUGLIST = YES +ALIASES = +ENABLED_SECTIONS = +MAX_INITIALIZER_LINES = 30 +OPTIMIZE_OUTPUT_FOR_C = NO +SHOW_USED_FILES = YES +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- +QUIET = NO +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_FORMAT = +WARN_LOGFILE = +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- +INPUT = include +FILE_PATTERNS = *.h +RECURSIVE = NO +EXCLUDE = +EXCLUDE_PATTERNS = +EXAMPLE_PATH = +EXAMPLE_PATTERNS = +EXAMPLE_RECURSIVE = NO +IMAGE_PATH = +INPUT_FILTER = +FILTER_SOURCE_FILES = NO +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- +SOURCE_BROWSER = YES +INLINE_SOURCES = NO +REFERENCED_BY_RELATION = YES +REFERENCES_RELATION = YES +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- +ALPHABETICAL_INDEX = NO +COLS_IN_ALPHA_INDEX = 5 +IGNORE_PREFIX = +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- +GENERATE_HTML = YES +HTML_OUTPUT = +HTML_HEADER = +HTML_FOOTER = +HTML_STYLESHEET = +HTML_ALIGN_MEMBERS = YES +GENERATE_HTMLHELP = NO +GENERATE_CHI = NO +BINARY_TOC = NO +TOC_EXPAND = NO +DISABLE_INDEX = NO +ENUM_VALUES_PER_LINE = 4 +GENERATE_TREEVIEW = NO +TREEVIEW_WIDTH = 250 +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- +GENERATE_LATEX = NO +LATEX_OUTPUT = +COMPACT_LATEX = NO +PAPER_TYPE = a4wide +EXTRA_PACKAGES = +LATEX_HEADER = +PDF_HYPERLINKS = NO +USE_PDFLATEX = NO +LATEX_BATCHMODE = NO +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- +GENERATE_RTF = NO +RTF_OUTPUT = +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +RTF_EXTENSIONS_FILE = +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- +GENERATE_MAN = NO +MAN_OUTPUT = +MAN_EXTENSION = +MAN_LINKS = NO +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- +GENERATE_XML = YES +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- +GENERATE_AUTOGEN_DEF = NO +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = NO +EXPAND_ONLY_PREDEF = NO +SEARCH_INCLUDES = YES +INCLUDE_PATH = +INCLUDE_FILE_PATTERNS = +PREDEFINED = +EXPAND_AS_DEFINED = +SKIP_FUNCTION_MACROS = YES +#--------------------------------------------------------------------------- +# Configuration::addtions related to external references +#--------------------------------------------------------------------------- +TAGFILES = ../../qtools_docs/qtools.tag=../../../../qtools_docs/html +GENERATE_TAGFILE = +ALLEXTERNALS = NO +PERL_PATH = +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- +CLASS_DIAGRAMS = NO +HAVE_DOT = NO +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +TEMPLATE_RELATIONS = YES +HIDE_UNDOC_RELATIONS = YES +INCLUDE_GRAPH = YES +INCLUDED_BY_GRAPH = YES +GRAPHICAL_HIERARCHY = YES +DOT_PATH = +DOTFILE_DIRS = +MAX_DOT_GRAPH_WIDTH = 1280 +MAX_DOT_GRAPH_HEIGHT = 1024 +GENERATE_LEGEND = YES +DOT_CLEANUP = YES +#--------------------------------------------------------------------------- +# Configuration::addtions related to the search engine +#--------------------------------------------------------------------------- +SEARCHENGINE = NO +CGI_NAME = +CGI_URL = +DOC_URL = +DOC_ABSPATH = +BIN_ABSPATH = +EXT_DOC_PATHS = diff --git a/trunk/addon/doxmlparser/Doxyfile.impl b/trunk/addon/doxmlparser/Doxyfile.impl new file mode 100644 index 0000000..a954db3 --- /dev/null +++ b/trunk/addon/doxmlparser/Doxyfile.impl @@ -0,0 +1,179 @@ +# Doxyfile 1.2.13.1 + +#--------------------------------------------------------------------------- +# General configuration options +#--------------------------------------------------------------------------- +PROJECT_NAME = doxmlparser +PROJECT_NUMBER = +OUTPUT_DIRECTORY = doc_impl +OUTPUT_LANGUAGE = English +EXTRACT_ALL = YES +EXTRACT_PRIVATE = YES +EXTRACT_STATIC = YES +EXTRACT_LOCAL_CLASSES = YES +HIDE_UNDOC_MEMBERS = NO +HIDE_UNDOC_CLASSES = NO +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ALWAYS_DETAILED_SEC = NO +INLINE_INHERITED_MEMB = NO +FULL_PATH_NAMES = NO +STRIP_FROM_PATH = +INTERNAL_DOCS = NO +STRIP_CODE_COMMENTS = YES +CASE_SENSE_NAMES = YES +SHORT_NAMES = NO +HIDE_SCOPE_NAMES = NO +VERBATIM_HEADERS = YES +SHOW_INCLUDE_FILES = YES +JAVADOC_AUTOBRIEF = NO +INHERIT_DOCS = YES +INLINE_INFO = YES +SORT_MEMBER_DOCS = YES +DISTRIBUTE_GROUP_DOC = NO +TAB_SIZE = 8 +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = YES +GENERATE_BUGLIST = YES +ALIASES = +ENABLED_SECTIONS = +MAX_INITIALIZER_LINES = 30 +OPTIMIZE_OUTPUT_FOR_C = NO +SHOW_USED_FILES = YES +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- +QUIET = NO +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_FORMAT = +WARN_LOGFILE = +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- +INPUT = src +FILE_PATTERNS = +RECURSIVE = NO +EXCLUDE = +EXCLUDE_SYMLINKS = NO +EXCLUDE_PATTERNS = +EXAMPLE_PATH = +EXAMPLE_PATTERNS = +EXAMPLE_RECURSIVE = NO +IMAGE_PATH = +INPUT_FILTER = +FILTER_SOURCE_FILES = NO +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- +SOURCE_BROWSER = NO +INLINE_SOURCES = NO +REFERENCED_BY_RELATION = YES +REFERENCES_RELATION = YES +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- +ALPHABETICAL_INDEX = NO +COLS_IN_ALPHA_INDEX = 5 +IGNORE_PREFIX = +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- +GENERATE_HTML = YES +HTML_OUTPUT = +HTML_HEADER = +HTML_FOOTER = +HTML_STYLESHEET = +HTML_ALIGN_MEMBERS = YES +GENERATE_HTMLHELP = NO +GENERATE_CHI = NO +BINARY_TOC = NO +TOC_EXPAND = NO +DISABLE_INDEX = NO +ENUM_VALUES_PER_LINE = 4 +GENERATE_TREEVIEW = NO +TREEVIEW_WIDTH = 250 +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- +GENERATE_LATEX = NO +LATEX_OUTPUT = +COMPACT_LATEX = NO +PAPER_TYPE = a4wide +EXTRA_PACKAGES = +LATEX_HEADER = +PDF_HYPERLINKS = NO +USE_PDFLATEX = NO +LATEX_BATCHMODE = NO +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- +GENERATE_RTF = NO +RTF_OUTPUT = +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +RTF_EXTENSIONS_FILE = +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- +GENERATE_MAN = NO +MAN_OUTPUT = +MAN_EXTENSION = +MAN_LINKS = NO +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- +GENERATE_XML = YES +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- +GENERATE_AUTOGEN_DEF = NO +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = YES +EXPAND_ONLY_PREDEF = YES +SEARCH_INCLUDES = YES +INCLUDE_PATH = +INCLUDE_FILE_PATTERNS = +PREDEFINED = +EXPAND_AS_DEFINED = DEFINE_CLS_IMPL +SKIP_FUNCTION_MACROS = YES +#--------------------------------------------------------------------------- +# Configuration::addtions related to external references +#--------------------------------------------------------------------------- +TAGFILES = ../../qtools_docs/qtools.tag=../../../../qtools_docs/html +GENERATE_TAGFILE = +ALLEXTERNALS = NO +EXTERNAL_GROUPS = YES +PERL_PATH = +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- +CLASS_DIAGRAMS = NO +HAVE_DOT = YES +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +TEMPLATE_RELATIONS = YES +HIDE_UNDOC_RELATIONS = YES +INCLUDE_GRAPH = YES +INCLUDED_BY_GRAPH = YES +GRAPHICAL_HIERARCHY = YES +DOT_PATH = +DOTFILE_DIRS = +MAX_DOT_GRAPH_WIDTH = 1280 +MAX_DOT_GRAPH_HEIGHT = 1024 +GENERATE_LEGEND = YES +DOT_CLEANUP = YES +#--------------------------------------------------------------------------- +# Configuration::addtions related to the search engine +#--------------------------------------------------------------------------- +SEARCHENGINE = NO +CGI_NAME = +CGI_URL = +DOC_URL = +DOC_ABSPATH = +BIN_ABSPATH = +EXT_DOC_PATHS = diff --git a/trunk/addon/doxmlparser/examples/metrics/Makefile.in b/trunk/addon/doxmlparser/examples/metrics/Makefile.in new file mode 100644 index 0000000..83cbc28 --- /dev/null +++ b/trunk/addon/doxmlparser/examples/metrics/Makefile.in @@ -0,0 +1,13 @@ +all clean depend: Makefile.metrics + $(MAKE) -f Makefile.metrics $@ + +distclean: clean + $(RM) -rf Makefile.metrics metrics.pro Makefile obj + +tmake: + $(ENV) $(PERL) $(TMAKE) metrics.pro >Makefile.metrics + +Makefile.metrics: metrics.pro + $(ENV) $(PERL) $(TMAKE) metrics.pro >Makefile.metrics + +install: diff --git a/trunk/addon/doxmlparser/examples/metrics/main.cpp b/trunk/addon/doxmlparser/examples/metrics/main.cpp new file mode 100644 index 0000000..1328abe --- /dev/null +++ b/trunk/addon/doxmlparser/examples/metrics/main.cpp @@ -0,0 +1,254 @@ +/****************************************************************************** + * + * $Id$ + * + * + * Copyright (C) 1997-2006 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. + * + */ + +/*! \mainpage Metrics + * This is a small example that shows how to use doxygen's XML output and + * the doxmlparser library. The example shows some very basic code metrics. + */ + +#include +#include +#include +#include + +bool isDocumented(IDocRoot *brief,IDocRoot *detailed) +{ + bool found=false; + if (brief) + { + IDocIterator *docIt = brief->contents(); + if (docIt->current()) // method has brief description + { + found=true; + } + docIt->release(); + } + if (detailed && !found) + { + IDocIterator *docIt = detailed->contents(); + if (docIt->current()) + { + found=true; + } + docIt->release(); + } + return found; +} + +int main(int argc,char **argv) +{ + if (argc!=2) + { + printf("Usage: %s xml_output_dir\n",argv[0]); + exit(1); + } + + int numClasses=0; + int numDocClasses=0; + int numStructs=0; + int numUnions=0; + int numInterfaces=0; + int numExceptions=0; + int numNamespaces=0; + int numFiles=0; + int numGroups=0; + int numPages=0; + int numPackages=0; + int numPubMethods=0; + int numProMethods=0; + int numPriMethods=0; + int numDocPubMethods=0; + int numDocProMethods=0; + int numDocPriMethods=0; + int numFunctions=0; + int numAttributes=0; + int numVariables=0; + int numDocFunctions=0; + int numDocAttributes=0; + int numDocVariables=0; + int numParams=0; + + IDoxygen *dox = createObjectModel(); + + dox->setDebugLevel(0); + + if (!dox->readXMLDir(argv[1])) + { + printf("Error reading %s/index.xml\n",argv[1]); + exit(1); + } + + ICompoundIterator *cli = dox->compounds(); + ICompound *comp; + for (cli->toFirst();(comp=cli->current());cli->toNext()) + { + printf("Processing %s...\n",comp->name()->latin1()); + bool hasDocs = isDocumented(comp->briefDescription(),comp->detailedDescription()); + switch (comp->kind()) + { + case ICompound::Class: + numClasses++; + if (hasDocs) numDocClasses++; + break; + case ICompound::Struct: numStructs++; break; + case ICompound::Union: numUnions++; break; + case ICompound::Interface: numInterfaces++; break; + case ICompound::Exception: numExceptions++; break; + case ICompound::Namespace: numNamespaces++; break; + case ICompound::File: numFiles++; break; + case ICompound::Group: numGroups++; break; + case ICompound::Page: numPages++; break; + default: break; + } + + ISectionIterator *sli = comp->sections(); + ISection *sec; + for (sli->toFirst();(sec=sli->current());sli->toNext()) + { + IMemberIterator *mli = sec->members(); + IMember *mem; + for (mli->toFirst();(mem=mli->current());mli->toNext()) + { + IParamIterator *pli = mem->parameters(); + IParam *par; + if (comp->kind()==ICompound::Class || + comp->kind()==ICompound::Struct || + comp->kind()==ICompound::Interface + ) + { + if (mem->kind()==IMember::Function || + mem->kind()==IMember::Prototype || + mem->kind()==IMember::Signal || + mem->kind()==IMember::Slot || + mem->kind()==IMember::DCOP + ) // is a "method" + { + if (mem->section()->isPublic()) + { + numPubMethods++; + if (isDocumented(mem->briefDescription(),mem->detailedDescription())) + { + numDocPubMethods++; + } + } + else if (mem->section()->isProtected()) + { + numProMethods++; + if (isDocumented(mem->briefDescription(),mem->detailedDescription())) + { + numDocProMethods++; + } + } + else if (mem->section()->isPrivate()) + { + numPriMethods++; + if (isDocumented(mem->briefDescription(),mem->detailedDescription())) + { + numDocPriMethods++; + } + } + } + else if (mem->kind()==IMember::Variable || + mem->kind()==IMember::Property + ) // is an "attribute" + { + numAttributes++; + if (isDocumented(mem->briefDescription(),mem->detailedDescription())) + { + numDocAttributes++; + } + } + } + else if (comp->kind()==ICompound::File || + comp->kind()==ICompound::Namespace + ) + { + if (mem->kind()==IMember::Function || + mem->kind()==IMember::Prototype || + mem->kind()==IMember::Signal || + mem->kind()==IMember::Slot || + mem->kind()==IMember::DCOP + ) // is a "method" + { + numFunctions++; + if (isDocumented(mem->briefDescription(),mem->detailedDescription())) + { + numDocFunctions++; + } + } + else if (mem->kind()==IMember::Variable || + mem->kind()==IMember::Property + ) // is an "attribute" + { + numVariables++; + if (isDocumented(mem->briefDescription(),mem->detailedDescription())) + { + numDocVariables++; + } + } + } + + for (pli->toFirst();(par=pli->current());pli->toNext()) + { + numParams++; + } + const char *type = mem->typeString()->latin1(); + if (type && strcmp(type, "void")) + { + numParams++; // count non-void return types as well + } + pli->release(); + } + mli->release(); + } + sli->release(); + + comp->release(); + } + cli->release(); + + dox->release(); + + int numMethods = numPubMethods+numProMethods+numPriMethods; + int numDocMethods = numDocPubMethods+numDocProMethods+numDocPriMethods; + + printf("Metrics:\n"); + printf("-----------------------------------\n"); + if (numClasses>0) printf("Classes: %10d (%d documented)\n",numClasses,numDocClasses); + if (numStructs>0) printf("Structs: %10d\n",numStructs); + if (numUnions>0) printf("Unions: %10d\n",numUnions); + if (numInterfaces>0) printf("Interfaces: %10d\n",numInterfaces); + if (numExceptions>0) printf("Exceptions: %10d\n",numExceptions); + if (numNamespaces>0) printf("Namespaces: %10d\n",numNamespaces); + if (numFiles>0) printf("Files: %10d\n",numFiles); + if (numGroups>0) printf("Groups: %10d\n",numGroups); + if (numPages>0) printf("Pages: %10d\n",numPages); + if (numPackages>0) printf("Packages: %10d\n",numPackages); + if (numMethods>0) printf("Methods: %10d (%d documented)\n",numMethods,numDocMethods); + if (numPubMethods>0) printf(" Public: %10d (%d documented)\n",numPubMethods,numDocPubMethods); + if (numProMethods>0) printf(" Protected: %10d (%d documented)\n",numProMethods,numDocProMethods); + if (numPriMethods>0) printf(" Private: %10d (%d documented)\n",numPriMethods,numDocPriMethods); + if (numFunctions>0) printf("Functions: %10d (%d documented)\n",numFunctions,numDocFunctions); + if (numAttributes>0) printf("Attributes: %10d (%d documented)\n",numAttributes,numDocAttributes); + if (numVariables>0) printf("Variables: %10d (%d documented)\n",numVariables,numDocVariables); + if (numParams>0) printf("Params: %10d\n",numParams); + printf("-----------------------------------\n"); + if (numClasses>0) printf("Avg. #methods/compound: %10f\n",(double)numMethods/(double)numClasses); + if (numMethods>0) printf("Avg. #params/method: %10f\n",(double)numParams/(double)numMethods); + printf("-----------------------------------\n"); + + return 0; +} + diff --git a/trunk/addon/doxmlparser/examples/metrics/metrics.pro.in b/trunk/addon/doxmlparser/examples/metrics/metrics.pro.in new file mode 100644 index 0000000..6dd344f --- /dev/null +++ b/trunk/addon/doxmlparser/examples/metrics/metrics.pro.in @@ -0,0 +1,20 @@ +TEMPLATE = app.t +CONFIG = console warn_on $extraopts +HEADERS = +SOURCES = main.cpp +unix:LIBS += -L../../../../lib -L../../lib -ldoxmlparser -lqtools +win32:INCLUDEPATH += . +win32-mingw:LIBS += -L../../../../lib -L../../lib -ldoxmlparser -lqtools +win32-msvc:LIBS += doxmlparser.lib qtools.lib shell32.lib +win32-msvc:TMAKE_LFLAGS += /LIBPATH:..\..\..\..\lib;..\..\lib +win32-borland:LIBS += doxmlparser.lib qtools.lib shell32.lib +win32-borland:TMAKE_LFLAGS += -L..\..\..\..\lib -L..\..\lib +win32:TMAKE_CXXFLAGS += -DQT_NODLL +DESTDIR = +OBJECTS_DIR = obj +TARGET = metrics +DEPENDPATH = ../../include +INCLUDEPATH += ../../../../qtools ../../include +unix:TARGETDEPS = ../../lib/libdoxmlparser.a +win32:TARGETDEPS = ..\..\lib\doxmlparser.lib + diff --git a/trunk/addon/doxmlparser/include/doxmlintf.h b/trunk/addon/doxmlparser/include/doxmlintf.h new file mode 100644 index 0000000..88cb2e3 --- /dev/null +++ b/trunk/addon/doxmlparser/include/doxmlintf.h @@ -0,0 +1,1134 @@ +/****************************************************************************** + * + * $Id$ + * + * + * Copyright (C) 1997-2006 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. + * + */ + +#ifndef _DOXMLINTF_H +#define _DOXMLINTF_H + +/*! \file + * \brief The interface to the object model provided by the XML parser + * library. + * + * To start using this library one calls createObjectModel() and then + * uses the returned IDoxygen interface to read doxygen generated + * XML output and navigate through the information contained in it. + * + * @see createObjectModel() + */ + +class IMember; +class IDocIterator; +class ICompound; +class ISection; +class INode; +class IDocInternal; +class IDocRoot; + +#define VIRTUAL_DESTRUCTOR(x) virtual ~x() {} + +/*! \brief Read only interface to a string. + */ +class IString +{ + public: + VIRTUAL_DESTRUCTOR(IString) + /*! Returns a latin1 character representation of the string. */ + virtual const char *latin1() const = 0; + /*! Returns a utf8 character representation of the string. */ + virtual const char *utf8() const = 0; + /*! Returns a 16-bit unicode character representation of the character at + * position \a index in the string. The first character is at index 0. + */ + virtual unsigned short unicodeCharAt(int index) const = 0; + /*! Returns true if this string is empty or false otherwise */ + virtual bool isEmpty() const = 0; + /*! Returns the number of characters in the string. */ + virtual int length() const = 0; +}; + +/*! \brief Base interface for hyperlinked text + * + * Depending on the result of kind() the interface is extended by + * ILT_Text or ILT_Ref. + */ +class ILinkedText +{ + public: + VIRTUAL_DESTRUCTOR(ILinkedText) + enum Kind { Kind_Text, Kind_Ref }; + virtual Kind kind() const = 0; +}; + +/*! \brief Plain text fragment. + */ +class ILT_Text : public ILinkedText +{ + public: + VIRTUAL_DESTRUCTOR(ILT_Text) + virtual const IString *text() const = 0; +}; + +/*! \brief Reference to an object. + */ +class ILT_Ref : public ILinkedText +{ + public: + VIRTUAL_DESTRUCTOR(ILT_Ref) + enum TargetKind { Member, Compound }; + virtual const IString *id() const = 0; + virtual TargetKind targetKind() const = 0; + virtual const IString *external() const = 0; + virtual const IString *text() const = 0; +}; + +/*! \brief Iterates over a list of ILinkedText fragments. + */ +class ILinkedTextIterator +{ + public: + VIRTUAL_DESTRUCTOR(ILinkedTextIterator) + virtual ILinkedText *toFirst() = 0; + virtual ILinkedText *toLast() = 0; + virtual ILinkedText *toNext() = 0; + virtual ILinkedText *toPrev() = 0; + virtual ILinkedText *current() const = 0; + virtual void release() = 0; +}; + +/*! \brief Representation of a parameter of a function. */ +class IParam +{ + public: + VIRTUAL_DESTRUCTOR(IParam) + virtual ILinkedTextIterator *type() const = 0; + virtual const IString * declarationName() const = 0; + virtual const IString * definitionName() const = 0; + virtual const IString * attrib() const = 0; + virtual const IString * arraySpecifier() const = 0; + virtual ILinkedTextIterator *defaultValue() const = 0; + virtual IDocRoot *briefDescription() const = 0; +}; + +class IParamIterator +{ + public: + VIRTUAL_DESTRUCTOR(IParamIterator) + virtual IParam *toFirst() = 0; + virtual IParam *toLast() = 0; + virtual IParam *toNext() = 0; + virtual IParam *toPrev() = 0; + virtual IParam *current() const = 0; + virtual void release() = 0; +}; + +class IMemberReference +{ + public: + VIRTUAL_DESTRUCTOR(IMemberReference) + virtual IMember *member() const = 0; + virtual const IString * name() const = 0; + virtual const IString * scope() const = 0; + virtual const IString * protection() const = 0; + virtual const IString * virtualness() const = 0; + virtual const IString * ambiguityScope() const = 0; +}; + +class IMemberReferenceIterator +{ + public: + VIRTUAL_DESTRUCTOR(IMemberReferenceIterator) + virtual IMemberReference *toFirst() = 0; + virtual IMemberReference *toLast() = 0; + virtual IMemberReference *toNext() = 0; + virtual IMemberReference *toPrev() = 0; + virtual IMemberReference *current() const = 0; + virtual void release() = 0; +}; + +class IDoc +{ + public: + VIRTUAL_DESTRUCTOR(IDoc) + enum Kind + { + Invalid = 0, // 0 + Para, // 1 -> IDocPara + Text, // 2 -> IDocText + MarkupModifier, // 3 -> IDocMarkupModifier + ItemizedList, // 4 -> IDocItemizedList + OrderedList, // 5 -> IDocOrderedList + ListItem, // 6 -> IDocListItem + ParameterList, // 7 -> IDocParameterList + Parameter, // 8 -> IDocParameter + SimpleSect, // 9 -> IDocSimpleSect + Title, // 10 -> IDocTitle + Ref, // 11 -> IDocRef + VariableList, // 12 -> IDocVariableList + VariableListEntry, // 13 -> IDocVariableListEntry + HRuler, // 14 -> IDocHRuler + LineBreak, // 15 -> IDocLineBreak + ULink, // 16 -> IDocULink + EMail, // 17 -> IDocEMail + Link, // 18 -> IDocLink + ProgramListing, // 19 -> IDocProgramListing + CodeLine, // 20 -> IDocCodeLine + Highlight, // 21 -> IDocHighlight + Formula, // 22 -> IDocFormula + Image, // 23 -> IDocImage + DotFile, // 24 -> IDocDotFile + IndexEntry, // 25 -> IDocIndexEntry + Table, // 26 -> IDocTable + Row, // 27 -> IDocRow + Entry, // 28 -> IDocEntry + Section, // 29 -> IDocSection + Verbatim, // 30 -> IDocVerbatim + Copy, // 31 -> IDocCopy + TocList, // 32 -> IDocTocList + TocItem, // 33 -> IDocTocItem + Anchor, // 34 -> IDocAnchor + Symbol, // 35 -> IDocSymbol + Internal, // 36 -> IDocInternal + Root, // 37 -> IDocRoot + ParameterItem // 38 -> IDocParameterItem + }; + virtual Kind kind() const = 0; +}; + +class IDocMarkup : public IDoc +{ + public: + enum Markup + { + Normal = 0x000, + Bold = 0x001, + Emphasis = 0x002, + ComputerOutput = 0x004, + Subscript = 0x008, + Superscript = 0x010, + SmallFont = 0x020, + Center = 0x040, + Preformatted = 0x080, + Heading = 0x100 + }; +}; + +class IDocPara : public IDoc +{ + public: + virtual IDocIterator *contents() const = 0; +}; + +class IDocText : public IDocMarkup +{ + public: + virtual const IString * text() const = 0; + virtual int markup() const = 0; + virtual int headingLevel() const = 0; +}; + +class IDocMarkupModifier : public IDoc +{ + public: + virtual bool enabled() const = 0; + virtual int markup() const = 0; + virtual int headingLevel() const = 0; +}; + +class IDocItemizedList : public IDoc +{ + public: + virtual IDocIterator *elements() const = 0; +}; + +class IDocOrderedList : public IDoc +{ + public: + virtual IDocIterator *elements() const = 0; +}; + +class IDocListItem : public IDoc +{ + public: + virtual IDocIterator *contents() const = 0; +}; + +class IDocParameterList : public IDoc +{ + public: + enum Types { Param, RetVal, Exception }; + virtual Types sectType() const = 0; + virtual IDocIterator *params() const = 0; +}; + +class IDocParameterItem : public IDoc +{ + public: + virtual IDocIterator *paramNames() const = 0; + virtual IDocPara *description() const = 0; +}; + +class IDocParameter : public IDoc +{ + public: + virtual const IString * name() const = 0; +}; + +class IDocTitle : public IDoc +{ + public: + virtual IDocIterator *title() const = 0; +}; + +class IDocSimpleSect : public IDoc +{ + public: + enum Types { Invalid = 0, + See, Return, Author, Version, + Since, Date, Bug, Note, + Warning, Par, Deprecated, Pre, + Post, Invar, Remark, Attention, + Todo, Test, RCS, EnumValues, + Examples + }; + virtual Types type() const = 0; + virtual const IString * typeString() const = 0; + virtual IDocTitle *title() const = 0; + virtual IDocPara *description() const = 0; +}; + +class IDocRef : public IDoc +{ + public: + enum TargetKind { Member, Compound }; + virtual const IString * refId() const = 0; + virtual TargetKind targetKind() const = 0; + virtual const IString * external() const = 0; + virtual const IString * text() const = 0; +}; + +class IDocVariableList : public IDoc +{ + public: + virtual IDocIterator *entries() const = 0; +}; + +class IDocVariableListEntry : public IDoc +{ + public: + virtual ILinkedTextIterator * term() const = 0; + virtual IDocPara *description() const = 0; +}; + +class IDocHRuler : public IDoc +{ +}; + +class IDocLineBreak : public IDoc +{ +}; + +class IDocULink : public IDoc +{ + public: + virtual const IString * url() const = 0; + virtual const IString * text() const = 0; +}; + +class IDocEMail : public IDoc +{ + public: + virtual const IString * address() const = 0; +}; + +class IDocLink : public IDoc +{ + public: + virtual const IString * refId() const = 0; + virtual const IString * text() const = 0; +}; + +class IDocProgramListing : public IDoc +{ + public: + virtual IDocIterator *codeLines() const = 0; +}; + +class IDocCodeLine : public IDoc +{ + public: + virtual int lineNumber() const = 0; + virtual const IString * refId() const = 0; + virtual IDocIterator *codeElements() const = 0; +}; + +class IDocHighlight : public IDoc +{ + public: + enum HighlightKind + { Invalid=0, + Comment, Keyword, + KeywordType, KeywordFlow, CharLiteral, + StringLiteral, Preprocessor + }; + virtual HighlightKind highlightKind() const = 0; + virtual IDocIterator *codeElements() const = 0; +}; + +class IDocFormula : public IDoc +{ + public: + virtual const IString * id() const = 0; + virtual const IString * text() const = 0; +}; + +class IDocImage : public IDoc +{ + public: + virtual const IString * name() const = 0; + virtual const IString * caption() const = 0; +}; + +class IDocDotFile : public IDoc +{ + public: + virtual const IString * name() const = 0; + virtual const IString * caption() const = 0; +}; + +class IDocIndexEntry : public IDoc +{ + public: + virtual const IString * primary() const = 0; + virtual const IString * secondary() const = 0; +}; + +class IDocTable : public IDoc +{ + public: + virtual IDocIterator *rows() const = 0; + virtual int numColumns() const = 0; + virtual const IString * caption() const = 0; +}; + +class IDocRow : public IDoc +{ + public: + virtual IDocIterator *entries() const = 0; +}; + +class IDocEntry : public IDoc +{ + public: + virtual IDocIterator *contents() const = 0; +}; + +class IDocSection : public IDoc +{ + public: + virtual const IString * id() const = 0; + virtual int level() const = 0; + virtual IDocTitle *title() const = 0; + virtual IDocIterator *paragraphs() const = 0; + virtual IDocIterator *subSections() const = 0; + virtual IDocInternal *internal() const = 0; +}; + +class IDocInternal : public IDoc +{ + public: + virtual IDocIterator *paragraphs() const = 0; + virtual IDocIterator *subSections() const = 0; +}; + +class IDocTocList : public IDoc +{ + public: + virtual IDocIterator *elements() const = 0; +}; + +class IDocTocItem : public IDoc +{ + public: + virtual const IString *id() const = 0; + virtual const IString *title() const = 0; +}; + +class IDocCopy : public IDoc +{ + public: + virtual IDocIterator *contents() const = 0; +}; + +class IDocVerbatim : public IDoc +{ + public: + enum Types { Invalid = 0, HtmlOnly, LatexOnly, Verbatim }; + virtual const IString *text() const = 0; + virtual Types type() const = 0; +}; + +class IDocAnchor : public IDoc +{ + public: + virtual const IString *id() const = 0; +}; + +class IDocSymbol : public IDoc +{ + public: + enum Types + { Invalid = 0, + Umlaut, Acute, Grave, Circ, Tilde, Szlig, Cedil, Ring, Nbsp, Copy + }; + virtual Types type() const = 0; + virtual const IString * typeString() const = 0; + virtual char letter() const = 0; +}; + +class IDocRoot : public IDoc +{ + public: + virtual IDocIterator *contents() const = 0; + virtual IDocInternal *internal() const = 0; +}; + +class IDocIterator +{ + public: + VIRTUAL_DESTRUCTOR(IDocIterator) + virtual IDoc *toFirst() = 0; + virtual IDoc *toLast() = 0; + virtual IDoc *toNext() = 0; + virtual IDoc *toPrev() = 0; + virtual IDoc *current() const = 0; + virtual void release() = 0; +}; + +class IEdgeLabel +{ + public: + VIRTUAL_DESTRUCTOR(IEdgeLabel) + virtual const IString * label() const = 0; +}; + +class IEdgeLabelIterator +{ + public: + VIRTUAL_DESTRUCTOR(IEdgeLabelIterator) + virtual IEdgeLabel *toFirst() = 0; + virtual IEdgeLabel *toLast() = 0; + virtual IEdgeLabel *toNext() = 0; + virtual IEdgeLabel *toPrev() = 0; + virtual IEdgeLabel *current() const = 0; + virtual void release() = 0; +}; + +class IChildNode +{ + public: + VIRTUAL_DESTRUCTOR(IChildNode) + enum NodeRelation { PublicInheritance, ProtectedInheritance, + PrivateInheritance, Usage, TemplateInstance + }; + virtual INode * node() const = 0; + virtual NodeRelation relation() const = 0; + virtual const IString * relationString() const = 0; + virtual IEdgeLabelIterator *edgeLabels() const = 0; +}; + +class IChildNodeIterator +{ + public: + VIRTUAL_DESTRUCTOR(IChildNodeIterator) + virtual IChildNode *toFirst() = 0; + virtual IChildNode *toLast() = 0; + virtual IChildNode *toNext() = 0; + virtual IChildNode *toPrev() = 0; + virtual IChildNode *current() const = 0; + virtual void release() = 0; +}; + +class INode +{ + public: + VIRTUAL_DESTRUCTOR(INode) + virtual const IString * id() const = 0; + virtual const IString * label() const = 0; + virtual const IString * linkId() const = 0; + virtual IChildNodeIterator *children() const = 0; +}; + +class INodeIterator +{ + public: + VIRTUAL_DESTRUCTOR(INodeIterator) + virtual INode *toFirst() = 0; + virtual INode *toLast() = 0; + virtual INode *toNext() = 0; + virtual INode *toPrev() = 0; + virtual INode *current() const = 0; + virtual void release() = 0; +}; + +class IGraph +{ + public: + VIRTUAL_DESTRUCTOR(IGraph) + virtual INodeIterator *nodes() const = 0; +}; + +class IMember +{ + public: + VIRTUAL_DESTRUCTOR(IMember) + enum MemberKind { Invalid=0, + Define, Property, Variable, Typedef, Enum, + Function, Signal, Prototype, Friend, DCOP, Slot, + EnumValue + }; + virtual ICompound *compound() const = 0; + virtual ISection *section() const = 0; + virtual MemberKind kind() const = 0; + virtual const IString * kindString() const = 0; + virtual const IString * id() const = 0; + virtual const IString * protection() const = 0; + virtual const IString * virtualness() const = 0; + virtual ILinkedTextIterator *type() const = 0; + virtual const IString * typeString() const = 0; + virtual const IString * name() const = 0; + virtual const IString * readAccessor() const = 0; + virtual const IString * writeAccessor() const = 0; + virtual const IString * definition() const = 0; + virtual const IString * argsstring() const = 0; + virtual bool isConst() const = 0; + virtual bool isVolatile() const = 0; + virtual bool isStatic() const = 0; + virtual bool isExplicit() const = 0; + virtual bool isInline() const = 0; + virtual bool isMutable() const = 0; + virtual bool isReadable() const = 0; + virtual bool isWritable() const = 0; + virtual IParamIterator *parameters() const = 0; + virtual IParamIterator *templateParameters() const = 0; + virtual ILinkedTextIterator *initializer() const = 0; + virtual ILinkedTextIterator *exceptions() const = 0; + virtual IMemberReferenceIterator *references() const = 0; + virtual IMemberReferenceIterator *referencedBy() const = 0; + virtual const IString *bodyFile() const = 0; + virtual int bodyStart() const = 0; + virtual int bodyEnd() const = 0; + virtual const IString * definitionFile() const = 0; + virtual int definitionLine() const = 0; + virtual IMemberReference *reimplements() const = 0; + virtual IMemberReferenceIterator *reimplementedBy() const = 0; + virtual IDocRoot *briefDescription() const = 0; + virtual IDocRoot *detailedDescription() const = 0; + virtual IDocRoot *inbodyDescription() const = 0; +}; + +class IDefine : public IMember +{ + public: +}; + +class IProperty : public IMember +{ + public: +}; + +class IVariable : public IMember +{ + public: +}; + +class ITypedef : public IMember +{ + public: +}; + +class IFunction : public IMember +{ + public: +}; + +class ISignal : public IMember +{ + public: +}; + +class IPrototype : public IMember +{ + public: +}; + +class IFriend : public IMember +{ + public: +}; + +class IDCOP : public IMember +{ + public: +}; + +class ISlot : public IMember +{ + public: +}; + +class IEnumValue : public IMember +{ + public: + virtual const IString * name() const = 0; +}; + +/*! \brief Include relation + */ +class IInclude +{ + public: + VIRTUAL_DESTRUCTOR(IInclude) + virtual const IString * name() const = 0; + virtual const IString * refId() const = 0; + virtual bool isLocal() const = 0; +}; + +class IIncludeIterator +{ + public: + VIRTUAL_DESTRUCTOR(IIncludeIterator) + virtual IInclude *toFirst() = 0; + virtual IInclude *toLast() = 0; + virtual IInclude *toNext() = 0; + virtual IInclude *toPrev() = 0; + virtual IInclude *current() const = 0; + virtual void release() = 0; +}; + +class IMemberIterator +{ + public: + VIRTUAL_DESTRUCTOR(IMemberIterator) + virtual IMember *toFirst() = 0; + virtual IMember *toLast() = 0; + virtual IMember *toNext() = 0; + virtual IMember *toPrev() = 0; + virtual IMember *current() const = 0; + virtual void release() = 0; +}; + +class IEnum : public IMember +{ + public: + virtual IMemberIterator *enumValues() const = 0; +}; + +/*! \brief The interface to a section in the object model. + * + * A compound can have a number of sections, where each + * section contains a set of members with the properties implied by + * the section kind. The kind() method returns the kind of the section. + * The members of the section can be accessed via members(). Apart + * from using kind(), some of the individual properties of the section can + * also be inspected via isStatic(), isPublic(), isProtected() and + * isPrivate(). + */ +class ISection +{ + public: + VIRTUAL_DESTRUCTOR(ISection) + /*! Possible section types */ + enum SectionKind + { Invalid=0, + UserDefined, //!< A user defined member group + PubTypes, //!< Public member typedefs + PubFuncs, //!< Public member functions + PubAttribs, //!< Public member attributes + PubSlots, //!< Public Qt Slots + Signals, //!< Qt Signals + DCOPFuncs, //!< KDE-DCOP interface functions + Properties, //!< IDL properties + Events, //!< C# events + PubStatFuncs, //!< Public static member functions + PubStatAttribs, //!< Public static attributes + ProTypes, //!< Protected member typedefs + ProFuncs, //!< Protected member functions + ProAttribs, //!< Protected member attributes + ProSlots, //!< Protected slots + ProStatFuncs, //!< Protected static member functions + ProStatAttribs, //!< Protected static member attributes + PacTypes, //!< Package member typedefs + PacFuncs, //!< Package member functions + PacAttribs, //!< Package member attributes + PacStatFuncs, //!< Package static member functions + PacStatAttribs, //!< Package static member attributes + PriTypes, //!< Private member typedefs + PriFuncs, //!< Private member functions + PriAttribs, //!< Private member attributes + PriSlots, //!< Private Qt slots + PriStatFuncs, //!< Private static member functions + PriStatAttribs, //!< Private static member attributes + Friend, //!< Friends + Related, //!< Function marked as related + Defines, //!< Preprocessor defines + Prototypes, //!< Global function prototypes + Typedefs, //!< Global typedefs + Enums, //!< Enumerations + Functions, //!< Global functions + Variables //!< Global variables + }; + + /*! Returns a string representation of the value returned by kind() */ + virtual const IString * kindString() const = 0; + + /*! Returns what kind of section this is */ + virtual SectionKind kind() const = 0; + + /*! Returns the description attached to this section (for user defined + * sections, also known as member groups). + */ + virtual IDocRoot *description() const = 0; + + /*! Returns an iterator for the members of this section */ + virtual IMemberIterator *members() const = 0; + + /*! Returns \c true if this section contains statics */ + virtual bool isStatic() const = 0; + + /*! Returns \c true if this section belongs to a + * public section of a class + */ + virtual bool isPublic() const = 0; + + /*! Returns \c true if this section belongs to a + * private section of a class + */ + virtual bool isPrivate() const = 0; + + /*! Returns \c true if this section belongs to a + * protected section of a class + * */ + virtual bool isProtected() const = 0; +}; + +class IUserDefined : public ISection +{ + public: + virtual const IString * header() const = 0; +}; + +class ISectionIterator +{ + public: + VIRTUAL_DESTRUCTOR(ISectionIterator) + virtual ISection *toFirst() = 0; + virtual ISection *toLast() = 0; + virtual ISection *toNext() = 0; + virtual ISection *toPrev() = 0; + virtual ISection *current() const = 0; + virtual void release() = 0; +}; + +/*! \brief The interface to a compound in the object model. + * + * A compound has a name which can be obtained via the name() method + * and a unique id, which is return via the id() method. + * A compound consists zero or more members which are grouped into sections. + * The sections() method can be used to access the individual sections. + * Alternatively, members can be obtained by name or id. There are + * different types of compounds. The kind() method returns what kind of + * compound this is. Depending on the return value one can dynamically + * cast an interface pointer to an more specialised interface that provides + * additional methods. + * Example: + * \code + * ICompound *comp=...; + * if (comp->kind()==ICompound::Class) + * { + * IClass *cls = dynamic_cast(comp); + * // use methods of IClass + * } + * \endcode + * The documentation that is provided by a compound is available via + * the briefDescription() and detailedDescription() methods. + * To avoid excessive memory usage, release() should be called (once) on each + * compound interface pointer that is no longer needed. + */ +class ICompound +{ + public: + VIRTUAL_DESTRUCTOR(ICompound) + /*! Represents the kind of compounds recognised by doxygen. */ + enum CompoundKind { Invalid=0, + Class, Struct, Union, Interface, Protocol, Category, + Exception, File, Namespace, Group, Page, Example, Dir + }; + + /*! Returns the name of this compound */ + virtual const IString * name() const = 0; + + /*! Returns the id of this compound. The id is a + * unique string representing a specific compound object. + */ + virtual const IString * id() const = 0; + + /*! Returns the kind of compound. See #CompoundKind for possible + * values. + */ + virtual CompoundKind kind() const = 0; + + /*! Returns a string representation of the compound kind. + * @see kind() + */ + virtual const IString * kindString() const = 0; + + /*! Returns an iterator for the different member sections in this + * compound. + */ + virtual ISectionIterator *sections() const = 0; + + /*! Returns a tree-structured representation of the brief + * description that is attached to this compound. + */ + virtual IDocRoot *briefDescription() const = 0; + + /*! Returns a tree-structured representation of the detailed + * description that is attached to this compound. + */ + virtual IDocRoot *detailedDescription() const = 0; + + /*! Returns an interface to a member given its id. + * @param id The member id. + */ + virtual IMember *memberById(const char * id) const = 0; + + /*! Returns a list of all members within the compound having a certain + * name. Member overloading is the reason why there can be more than + * one member. + * @param name The name of the member. + */ + virtual IMemberIterator *memberByName(const char * name) const = 0; + + /*! Decreases the reference counter for this compound. If it reaches + * zero, the memory for the compound will be released. + */ + virtual void release() = 0; +}; + +class ICompoundIterator +{ + public: + VIRTUAL_DESTRUCTOR(ICompoundIterator) + virtual void toFirst() = 0; + virtual void toLast() = 0; + virtual void toNext() = 0; + virtual void toPrev() = 0; + virtual ICompound *current() const = 0; + virtual void release() = 0; +}; + +class IRelatedCompound +{ + public: + VIRTUAL_DESTRUCTOR(IRelatedCompound) + enum Protection { Public, Protected, Private }; + enum Kind { Normal, Virtual }; + virtual ICompound *compound() const = 0; + virtual Protection protection() const = 0; + virtual Kind kind() const = 0; + virtual const IString *name() const = 0; + +}; + +class IRelatedCompoundIterator +{ + public: + VIRTUAL_DESTRUCTOR(IRelatedCompoundIterator) + virtual IRelatedCompound *toFirst() = 0; + virtual IRelatedCompound *toLast() = 0; + virtual IRelatedCompound *toNext() = 0; + virtual IRelatedCompound *toPrev() = 0; + virtual IRelatedCompound *current() const = 0; + virtual void release() = 0; +}; + +/*! \brief The interface to a class in the object model. + */ +class IClass : public ICompound +{ + public: + virtual IGraph *inheritanceGraph() const = 0; + virtual IGraph *collaborationGraph() const = 0; + virtual IRelatedCompoundIterator *baseCompounds() const = 0; + virtual IRelatedCompoundIterator *derivedCompounds() const = 0; + virtual ICompoundIterator *nestedCompounds() const = 0; + virtual IParamIterator *templateParameters() const = 0; + virtual const IString *locationFile() const = 0; + virtual int locationLine() const = 0; + virtual const IString *locationBodyFile() const = 0; + virtual int locationBodyStartLine() const = 0; + virtual int locationBodyEndLine() const = 0; + + // TODO: + // class: + // listOfAllMembers() + // protection() + // isAbstract() +}; + +/*! \brief The interface to a struct in the object model. + */ +class IStruct : public ICompound +{ + public: + virtual ICompoundIterator *nestedCompounds() const = 0; + virtual IRelatedCompoundIterator *baseCompounds() const = 0; + virtual IRelatedCompoundIterator *derivedCompounds() const = 0; + virtual const IString *locationFile() const = 0; + virtual int locationLine() const = 0; + virtual int locationBodyStartLine() const = 0; + virtual int locationBodyEndLine() const = 0; +}; + +/*! \brief The interface to a union in the object model. + */ +class IUnion : public ICompound +{ + public: + virtual ICompoundIterator *nestedCompounds() const = 0; +}; + +/*! \brief The interface to a Java/IDL interface in the object model. + */ +class IInterface : public ICompound +{ + public: + virtual IRelatedCompoundIterator *baseCompounds() const = 0; + virtual IRelatedCompoundIterator *derivedCompounds() const = 0; +}; + + +/*! \brief The interface to a Java/IDL exception in the object model. + */ +class IException : public ICompound +{ +}; + +/*! \brief The interface to a namespace in the object model. + */ +class INamespace : public ICompound +{ + public: + virtual ICompoundIterator *nestedCompounds() const = 0; +}; + +/*! \brief The interface to a file in the object model. + */ +class IFile : public ICompound +{ + public: + virtual IGraph *includeDependencyGraph() const = 0; + virtual IGraph *includedByDependencyGraph() const = 0; + virtual IDocProgramListing *source() const = 0; + virtual ICompoundIterator *nestedCompounds() const = 0; + + virtual IIncludeIterator *includes() const = 0; + virtual IIncludeIterator *includedBy() const = 0; + + // ICompound *innerNamespaces() + // ICompoundIterator *innerClasses() +}; + +/*! \brief The interface to a group in the object model. + */ +class IGroup : public ICompound +{ + public: + virtual ICompoundIterator *nestedCompounds() const = 0; + // group: + // Title() + // innerFile() + // innerPage() +}; + +/*! \brief The interface to a page in the object model. + */ +class IPage : public ICompound +{ + public: + virtual const IDocTitle *title() const = 0; +}; + +/*! Root node of the object model. */ +class IDoxygen +{ + public: + VIRTUAL_DESTRUCTOR(IDoxygen) + + /*! Returns an iterator that can be used to iterate over the list + * of compounds found in the project. + */ + virtual ICompoundIterator *compounds() const = 0; + + /*! Returns a compound given its unique \a id. If you have a + * compound id this function is much more efficient than iterating + * over the compound list. Returns 0 if the id is not valid. + */ + virtual ICompound *compoundById(const char * id) const = 0; + + /*! Returns a compound given its name (including the scope). + * Returns 0 if the name is not found in the project. + */ + virtual ICompound *compoundByName(const char * name) const = 0; + + /*! Returns an interface to a compound containing a member given it the + * member's id. Given the ICompound interface one can use the same id + * to obtain the IMember interface. + * @param id The member id. + */ + virtual ICompound *memberById(const char * id) const = 0; + + /*! Returns a list of all compounds containing at least one members + * with a certain name. Each compound can be asked to return the + * list of members with that name. + * @param name The name of the member. + */ + virtual ICompoundIterator *memberByName(const char * name) const = 0; + + /*! Releases the memory for the object hierarchy obtained by + * createdObjecModelFromXML(). First release all iterators before calling + * this function. + */ + virtual void release() = 0; + + /*! Sets the debug level. + * - 0 all debugging messages are disabled (the default). + * - 1 display important messages only + * - 2 display any messages. + */ + virtual void setDebugLevel(int level) = 0; + + /*! Reads an XML directory produced by doxygen and builds up a data + * structure representing the contents of the XML files in the directory. + */ + virtual bool readXMLDir(const char *xmlDirName) = 0; +}; + +/*! Factory method that creates an empty object model for a doxygen generated XML file. + * Use the readXMLDir() method to build the model from an XML output + * directory containing doxygen output. + */ +IDoxygen *createObjectModel(); + +#endif diff --git a/trunk/addon/doxmlparser/src/Makefile.in b/trunk/addon/doxmlparser/src/Makefile.in new file mode 100644 index 0000000..049f969 --- /dev/null +++ b/trunk/addon/doxmlparser/src/Makefile.in @@ -0,0 +1,13 @@ +all clean depend: Makefile.doxmlparser + $(MAKE) -f Makefile.doxmlparser $@ + +distclean: clean + $(RM) -rf Makefile.doxmlparser doxmlparser.pro Makefile obj + +tmake: + $(ENV) $(PERL) $(TMAKE) doxmlparser.pro >Makefile.doxmlparser + +Makefile.doxmlparser: doxmlparser.pro + $(ENV) $(PERL) $(TMAKE) doxmlparser.pro >Makefile.doxmlparser + +install: diff --git a/trunk/addon/doxmlparser/src/basehandler.cpp b/trunk/addon/doxmlparser/src/basehandler.cpp new file mode 100644 index 0000000..02d98c2 --- /dev/null +++ b/trunk/addon/doxmlparser/src/basehandler.cpp @@ -0,0 +1,3 @@ +#include "basehandler.h" + +QXmlLocator * LocatorContainer::s_theLocator=0; diff --git a/trunk/addon/doxmlparser/src/basehandler.h b/trunk/addon/doxmlparser/src/basehandler.h new file mode 100644 index 0000000..b1bfe87 --- /dev/null +++ b/trunk/addon/doxmlparser/src/basehandler.h @@ -0,0 +1,325 @@ +/****************************************************************************** + * + * $Id$ + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#ifndef _BASEHANDLER_H +#define _BASEHANDLER_H + +#include +#include +#include + +#include "debug.h" + +//----------------------------------------------------------------------------- + +class IBaseHandler +{ + public: + virtual void setDelegate(QXmlDefaultHandler *delegate) = 0; + virtual QXmlDefaultHandler *delegate() const = 0; + virtual ~IBaseHandler() {} +}; + +//----------------------------------------------------------------------------- + +class IFallBackHandler +{ + public: + virtual bool handleStartElement(const QString & name, + const QXmlAttributes & attrib) = 0; + virtual bool handleEndElement(const QString &name) = 0; + virtual ~IFallBackHandler() {} +}; + +//----------------------------------------------------------------------------- + +template class ElementMapper +{ + class StartElementHandler + { + typedef void (T::*Handler)(const QXmlAttributes &attrib); + public: + StartElementHandler() : m_parent(0) {} + StartElementHandler(T *parent, Handler h) + : m_parent(parent), m_handler(h) {} + void operator()(const QXmlAttributes &attrib) + { if (m_parent) (m_parent->*m_handler)(attrib); } + private: + T *m_parent; + Handler m_handler; + }; + + class EndElementHandler + { + typedef void (T::*Handler)(); + public: + EndElementHandler() : m_parent(0) {} + EndElementHandler(T *parent, Handler h) + : m_parent(parent), m_handler(h) {} + void operator()() + { if (m_parent) (m_parent->*m_handler)(); } + private: + T *m_parent; + Handler m_handler; + }; + + public: + typedef StartElementHandler StartElementHandlerT; + typedef EndElementHandler EndElementHandlerT; + + ElementMapper() : m_startHandlers(67), m_endHandlers(67) + { + m_startHandlers.setAutoDelete(TRUE); + m_endHandlers.setAutoDelete(TRUE); + } + virtual ~ElementMapper() + { + } + + void addStartHandler(const char *key) + { + m_startHandlers.insert(key,new StartElementHandlerT); + } + + void addStartHandler(const char *key, T *obj, void (T::*handler)(const QXmlAttributes &)) + { + m_startHandlers.insert(key,new StartElementHandlerT(obj,handler)); + } + + void addEndHandler(const char *key) + { + m_endHandlers.insert(key,new EndElementHandlerT); + } + + void addEndHandler(const char *key, T *obj, void (T::*handler)()) + { + m_endHandlers.insert(key,new EndElementHandlerT(obj,handler)); + } + + + protected: + QDict m_startHandlers; + QDict m_endHandlers; +}; + +//----------------------------------------------------------------------------- + +struct LocatorContainer +{ + static QXmlLocator *s_theLocator; +}; + +//----------------------------------------------------------------------------- + +template class BaseHandler : public QXmlDefaultHandler, + public ElementMapper, + public LocatorContainer, + public IBaseHandler +{ + public: + typedef typename ElementMapper::StartElementHandlerT StartElementHandlerT; + typedef typename ElementMapper::EndElementHandlerT EndElementHandlerT; + + BaseHandler() : m_delegateHandler(0), m_fallBackHandler(0) + { + } + + virtual ~BaseHandler() + { + ASSERT(m_delegateHandler==0); + } + + virtual bool startDocument() + { + return TRUE; + } + + virtual bool startElement( const QString & namespaceURI, + const QString & localName, + const QString & name, + const QXmlAttributes & attrib + ) + { + if (m_delegateHandler) + { + return m_delegateHandler->startElement(namespaceURI,localName,name,attrib); + } + if (!m_skipUntil.isEmpty()) // skip mode + { + if (m_skipUntil==name) m_skipCount++; + debug(1,"line %d, col %d: skipping start tag %s count=%d\n", + s_theLocator->lineNumber(),s_theLocator->columnNumber(), + name.data(),m_skipCount); + return TRUE; + } + + StartElementHandlerT *handler = ElementMapper::m_startHandlers[name]; + if (handler) + { + (*handler)(attrib); + //printf("found start tag %s\n",name.data()); + } + else if (!m_fallBackHandler || + !m_fallBackHandler->handleStartElement(name,attrib) + ) + { + debug(1,"line %d, col %d: found unexpected tag `%s', skipping until matching end tag\n", + s_theLocator->lineNumber(),s_theLocator->columnNumber(), + name.data()); + m_skipUntil = name; + m_skipCount=1; + } + return TRUE; + } + + virtual bool endElement( const QString& namespaceURI, const QString& localName, const QString& name ) + { + if (m_delegateHandler) + { + return m_delegateHandler->endElement(namespaceURI,localName,name); + } + + if (name==m_skipUntil) + { + m_skipCount--; + debug(1,"line %d, col %d: skipping end tag %s count=%d\n", + s_theLocator->lineNumber(),s_theLocator->columnNumber(), + name.data(),m_skipCount); + if (m_skipCount==0) + { + m_skipUntil=""; + } + //printf("found end tag %s\n",name.data()); + } + else if (m_skipUntil.isEmpty()) + { + EndElementHandlerT *handler = ElementMapper::m_endHandlers[name]; + if (handler) + { + (*handler)(); + //printf("found end tag %s\n",name.data()); + } + else if (m_fallBackHandler) + { + m_fallBackHandler->handleEndElement(name); + } + } + m_curString=""; + return TRUE; + } + + bool skippedEntity ( const QString &s ) + { + if (m_delegateHandler) + { + return m_delegateHandler->skippedEntity(s); + } + + debug(1,"line %d, col %d: Skipped unhandled entity %s\n", + s_theLocator->lineNumber(),s_theLocator->columnNumber(), + s.data()); + return TRUE; + } + + /*! called when a number of characters are received by the parser. + * \param ch the characters. + */ + virtual bool characters ( const QString & ch ) + { + if (m_delegateHandler) + { + return m_delegateHandler->characters(ch); + } + + //printf("Found characters \"%s\"\n",ch.data()); + m_curString+=ch; + return TRUE; + } + + void setDelegate(QXmlDefaultHandler *delegate) + { + m_delegateHandler = delegate; + } + + QXmlDefaultHandler *delegate() const + { + return m_delegateHandler; + } + + void setFallBackHandler(IFallBackHandler *h) + { + m_fallBackHandler = h; + } + + IFallBackHandler *fallBackHandler() const + { + return m_fallBackHandler; + } + + void setDocumentLocator( QXmlLocator * locator ) + { + debug(2,"setDocumentLocator(%p)\n",locator); + s_theLocator = locator; + } + + protected: + QString m_curString; + QString m_skipUntil; + int m_skipCount; + QXmlDefaultHandler *m_delegateHandler; + IFallBackHandler *m_fallBackHandler; +}; + +//----------------------------------------------------------------------------- + +template class BaseFallBackHandler : public ElementMapper, + public IFallBackHandler +{ + public: + typedef typename ElementMapper::StartElementHandlerT StartElementHandlerT; + typedef typename ElementMapper::EndElementHandlerT EndElementHandlerT; + + BaseFallBackHandler() + { + } + virtual ~BaseFallBackHandler() + { + } + + bool handleStartElement(const QString & name, + const QXmlAttributes & attrib) + { + StartElementHandlerT *handler = ElementMapper::m_startHandlers[name]; + if (handler) + { + (*handler)(attrib); + return TRUE; + } + return FALSE; + } + bool handleEndElement(const QString &name) + { + EndElementHandlerT *handler = ElementMapper::m_endHandlers[name]; + if (handler) + { + (*handler)(); + return TRUE; + } + return FALSE; + } +}; + + +#endif diff --git a/trunk/addon/doxmlparser/src/baseiterator.h b/trunk/addon/doxmlparser/src/baseiterator.h new file mode 100644 index 0000000..a1d6f87 --- /dev/null +++ b/trunk/addon/doxmlparser/src/baseiterator.h @@ -0,0 +1,50 @@ +/****************************************************************************** + * + * $Id$ + * + * + * Copyright (C) 1997-2012 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. + * + */ +#ifndef BASEITERATOR_H +#define BASEITERATOR_H + +#include +#include + +template class BaseIterator : + public Intf, public QListIterator +{ + public: + BaseIterator(const QList &list) : QListIterator(list) {} + virtual ~BaseIterator() {} + virtual ElemIntf *toFirst() { return QListIterator::toFirst(); } + virtual ElemIntf *toLast() { return QListIterator::toLast(); } + virtual ElemIntf *toNext() { return QListIterator::operator++(); } + virtual ElemIntf *toPrev() { return QListIterator::operator--(); } + virtual ElemIntf *current() const { return QListIterator::current(); } + virtual void release() { delete this; } +}; + +template + class BaseIteratorVia : + public Intf, public QListIterator +{ + public: + BaseIteratorVia(const QList &list) : QListIterator(list) {} + virtual ~BaseIteratorVia() {} + virtual ElemIntf *toFirst() { return static_cast(QListIterator::toFirst()); } + virtual ElemIntf *toLast() { return static_cast(QListIterator::toLast()); } + virtual ElemIntf *toNext() { return static_cast(QListIterator::operator++()); } + virtual ElemIntf *toPrev() { return static_cast(QListIterator::operator--()); } + virtual ElemIntf *current() const { return static_cast(QListIterator::current()); } + virtual void release() { delete this; } +}; + +#endif diff --git a/trunk/addon/doxmlparser/src/compoundhandler.cpp b/trunk/addon/doxmlparser/src/compoundhandler.cpp new file mode 100644 index 0000000..42acc0e --- /dev/null +++ b/trunk/addon/doxmlparser/src/compoundhandler.cpp @@ -0,0 +1,650 @@ +/****************************************************************************** + * + * $Id$ + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#include "mainhandler.h" +#include "compoundhandler.h" +#include "dochandler.h" +#include "debug.h" +#include "graphhandler.h" +#include "sectionhandler.h" +#include "paramhandler.h" +#include "loamhandler.h" +#include "memberhandler.h" + +//---------------------------------------------------------------------------- + +IncludeHandler::IncludeHandler(IBaseHandler *parent,const char *endtag) : + m_parent(parent) +{ + addEndHandler(endtag,this,&IncludeHandler::endInclude); +} + +IncludeHandler::~IncludeHandler() +{ +} + +void IncludeHandler::startInclude(const QXmlAttributes &attrib) +{ + m_curString = ""; + m_refId = attrib.value("refid"); + m_isLocal = attrib.value("local")=="yes"; + m_parent->setDelegate(this); +} + +void IncludeHandler::endInclude() +{ + m_name = m_curString; + m_parent->setDelegate(0); + debug(2,"Found include %s\n",m_name.data()); +} + +//---------------------------------------------------------------------------- + +class CompoundIdIterator : public ICompoundIterator, + public QListIterator +{ + public: + CompoundIdIterator(const MainHandler *m,const QList &list) : + QListIterator(list), m_mainHandler(m) {} + virtual ~CompoundIdIterator() {} + + virtual void toFirst() + { + QListIterator::toFirst(); + } + virtual void toLast() + { + QListIterator::toLast(); + } + virtual void toNext() + { + QListIterator::operator++(); + } + virtual void toPrev() + { + QListIterator::operator--(); + } + virtual ICompound *current() const + { + QString *id = QListIterator::current(); + return id ? m_mainHandler->compoundById(*id) : 0; + } + virtual void release() + { delete this; } + + private: + const MainHandler *m_mainHandler; +}; + +//---------------------------------------------------------------------------- + +ICompound *RelatedCompound::compound() const +{ + return m_parent->m_mainHandler->compoundById(m_id); +} + +//---------------------------------------------------------------------------- + +class CompoundErrorHandler : public QXmlErrorHandler +{ + public: + virtual ~CompoundErrorHandler() {} + bool warning( const QXmlParseException & ) + { + return FALSE; + } + bool error( const QXmlParseException & ) + { + return FALSE; + } + bool fatalError( const QXmlParseException &exception ) + { + debug(1,"Fatal error at line %d column %d: %s\n", + exception.lineNumber(),exception.columnNumber(), + exception.message().data()); + return FALSE; + } + QString errorString() { return ""; } + + private: + QString errorMsg; +}; + +//---------------------------------------------------------------------------- + +class CompoundTypeMap +{ + public: + CompoundTypeMap() + { + m_map.setAutoDelete(TRUE); + m_map.insert("class", new int(ICompound::Class)); + m_map.insert("struct", new int(ICompound::Struct)); + m_map.insert("union", new int(ICompound::Union)); + m_map.insert("interface",new int(ICompound::Interface)); + m_map.insert("protocol", new int(ICompound::Protocol)); + m_map.insert("category", new int(ICompound::Category)); + m_map.insert("exception",new int(ICompound::Exception)); + m_map.insert("file", new int(ICompound::File)); + m_map.insert("namespace",new int(ICompound::Namespace)); + m_map.insert("group", new int(ICompound::Group)); + m_map.insert("page", new int(ICompound::Page)); + m_map.insert("example", new int(ICompound::Example)); + m_map.insert("dir", new int(ICompound::Dir)); + } + virtual ~CompoundTypeMap() + { + } + ICompound::CompoundKind map(const QString &s) + { + int *val = m_map.find(s); + if (val==0) + { + debug(1,"Warning: `%s' is an invalid compound type\n",s.data()); + return ICompound::Invalid; + } + else return (ICompound::CompoundKind)*val; + } + private: + QDict m_map; +}; + +static CompoundTypeMap *s_typeMap; + +void compoundhandler_init() +{ + s_typeMap = new CompoundTypeMap; +} + +void compoundhandler_exit() +{ + delete s_typeMap; +} + +//---------------------------------------------------------------------------- + +CompoundHandler::CompoundHandler(const QString &xmlDir) + : m_titleHandler(0), + m_includeDependencyGraph(0), + m_includedByDependencyGraph(0), + m_templateParamList(0), + m_brief(0), + m_detailed(0), + m_inheritanceGraph(0), + m_collaborationGraph(0), + m_programListing(0), + m_members(0), + m_xmlDir(xmlDir), + m_refCount(1), + m_memberDict(257), + m_memberNameDict(257), + m_mainHandler(0) +{ + m_superClasses.setAutoDelete(TRUE); + m_subClasses.setAutoDelete(TRUE); + m_sections.setAutoDelete(TRUE); + m_memberNameDict.setAutoDelete(TRUE); + m_innerCompounds.setAutoDelete(TRUE); + m_includes.setAutoDelete(TRUE); + m_includedBy.setAutoDelete(TRUE); + + addStartHandler("doxygen"); + addEndHandler("doxygen"); + + addStartHandler("compounddef",this,&CompoundHandler::startCompound); + addEndHandler("compounddef",this,&CompoundHandler::endCompound); + + addStartHandler("compoundname"); + addEndHandler("compoundname",this,&CompoundHandler::endCompoundName); + + addStartHandler("title",this,&CompoundHandler::startTitle); + + addStartHandler("basecompoundref",this,&CompoundHandler::startSuperClass); + addEndHandler("basecompoundref",this,&CompoundHandler::endSuperClass); + + addStartHandler("derivedcompoundref",this,&CompoundHandler::startSubClass); + addEndHandler("derivedcompoundref",this,&CompoundHandler::endSubClass); + + addStartHandler("includes",this,&CompoundHandler::startIncludes); + addStartHandler("includedby",this,&CompoundHandler::startIncludedBy); + + addStartHandler("incdepgraph",this,&CompoundHandler::startIncludeDependencyGraph); + + addStartHandler("invincdepgraph",this,&CompoundHandler::startIncludedByDependencyGraph); + + addStartHandler("innerdir",this,&CompoundHandler::startInnerDir); + addEndHandler("innerdir"); + + addStartHandler("innerfile",this,&CompoundHandler::startInnerFile); + addEndHandler("innerfile"); + + addStartHandler("innerclass",this,&CompoundHandler::startInnerClass); + addEndHandler("innerclass"); + + addStartHandler("innernamespace",this,&CompoundHandler::startInnerNamespace); + addEndHandler("innernamespace"); + + addStartHandler("innerpage",this,&CompoundHandler::startInnerPage); + addEndHandler("innerpage"); + + addStartHandler("innergroup",this,&CompoundHandler::startInnerGroup); + addEndHandler("innergroup"); + + addStartHandler("templateparamlist",this,&CompoundHandler::startTemplateParamList); + + addStartHandler("sectiondef",this,&CompoundHandler::startSection); + + addStartHandler("briefdescription",this,&CompoundHandler::startBriefDesc); + + addStartHandler("detaileddescription",this,&CompoundHandler::startDetailedDesc); + + addStartHandler("inheritancegraph",this,&CompoundHandler::startInheritanceGraph); + + addStartHandler("collaborationgraph",this,&CompoundHandler::startCollaborationGraph); + + addStartHandler("programlisting",this,&CompoundHandler::startProgramListing); + + addStartHandler("location",this,&CompoundHandler::startLocation); + addEndHandler("location"); + + addStartHandler("listofallmembers",this,&CompoundHandler::startListOfAllMembers); +} + +CompoundHandler::~CompoundHandler() +{ + debug(2,"CompoundHandler::~CompoundHandler()\n"); + delete m_titleHandler; + delete m_brief; + delete m_detailed; + delete m_programListing; + delete m_inheritanceGraph; + delete m_collaborationGraph; + delete m_includeDependencyGraph; + delete m_includedByDependencyGraph; + delete m_templateParamList; + delete m_members; +} + +void CompoundHandler::startSection(const QXmlAttributes& attrib) +{ + SectionHandler *sectHandler = new SectionHandler(this); + sectHandler->startSection(attrib); + m_sections.append(sectHandler); +} + +void CompoundHandler::startBriefDesc(const QXmlAttributes& attrib) +{ + DocHandler *docHandler = new DocHandler(this); + docHandler->startDoc(attrib); + m_brief = docHandler; +} + +void CompoundHandler::startDetailedDesc(const QXmlAttributes& attrib) +{ + DocHandler *docHandler = new DocHandler(this); + docHandler->startDoc(attrib); + m_detailed = docHandler; +} + +void CompoundHandler::startProgramListing(const QXmlAttributes& attrib) +{ + ProgramListingHandler *plHandler = new ProgramListingHandler(this); + plHandler->startProgramListing(attrib); + m_programListing = plHandler; +} + +void CompoundHandler::startIncludes(const QXmlAttributes& attrib) +{ + IncludeHandler *inc = new IncludeHandler(this,"includes"); + m_includes.append(inc); + inc->startInclude(attrib); +} + +void CompoundHandler::startIncludedBy(const QXmlAttributes& attrib) +{ + IncludeHandler *inc = new IncludeHandler(this,"includedby"); + m_includedBy.append(inc); + inc->startInclude(attrib); +} + +void CompoundHandler::startCompound(const QXmlAttributes& attrib) +{ + m_id = attrib.value("id"); + m_kindString = attrib.value("kind"); + m_kind = s_typeMap->map(m_kindString); + m_protection = attrib.value("prot"); + debug(2,"startCompound(id=`%s' type=`%s')\n",m_id.data(),m_kindString.data()); +} + +void CompoundHandler::endCompound() +{ + debug(2,"endCompound()\n"); +} + +void CompoundHandler::startLocation(const QXmlAttributes& attrib) +{ + m_defFile = attrib.value("file"); + m_defLine = attrib.value("line").toInt(); + m_defBodyFile = attrib.value("bodyfile"); + m_defBodyStart = attrib.value("bodystart").toInt(); + m_defBodyEnd = attrib.value("bodyend").toInt(); +} + +void CompoundHandler::endCompoundName() +{ + m_name = m_curString.stripWhiteSpace(); + debug(2,"Compound name `%s'\n",m_name.data()); +} + +void CompoundHandler::startInnerClass(const QXmlAttributes& attrib) +{ + m_innerCompounds.append(new QString(attrib.value("refid"))); +} + +void CompoundHandler::startInnerNamespace(const QXmlAttributes& attrib) +{ + m_innerCompounds.append(new QString(attrib.value("refid"))); +} + +void CompoundHandler::startInnerFile(const QXmlAttributes& attrib) +{ + m_innerCompounds.append(new QString(attrib.value("refid"))); +} + +void CompoundHandler::startInnerGroup(const QXmlAttributes& attrib) +{ + m_innerCompounds.append(new QString(attrib.value("refid"))); +} + +void CompoundHandler::startInnerPage(const QXmlAttributes& attrib) +{ + m_innerCompounds.append(new QString(attrib.value("refid"))); +} + +void CompoundHandler::startInnerDir(const QXmlAttributes& attrib) +{ + m_innerCompounds.append(new QString(attrib.value("refid"))); +} + +void CompoundHandler::startTemplateParamList(const QXmlAttributes& attrib) +{ + m_templateParamList = new TemplateParamListHandler(this); + m_templateParamList->startTemplateParamList(attrib); +} + +void CompoundHandler::startListOfAllMembers(const QXmlAttributes& attrib) +{ + m_members = new ListOfAllMembersHandler(this); + m_members->startListOfAllMembers(attrib); +} + +void CompoundHandler::startSuperClass(const QXmlAttributes& attrib) +{ + IRelatedCompound::Protection prot = IRelatedCompound::Public; + QString protString = attrib.value("prot"); + if (protString=="protected") + { + prot = IRelatedCompound::Protected; + } + else if (protString=="private") + { + prot = IRelatedCompound::Private; + } + IRelatedCompound::Kind kind = IRelatedCompound::Normal; + QString kindString = attrib.value("virt"); + if (kindString=="virtual") kind = IRelatedCompound::Virtual; + + RelatedCompound *sc=new RelatedCompound( + this, + attrib.value("refid"), + prot, + kind + ); + debug(2,"super class id=`%s' prot=`%s' virt=`%s'\n", + attrib.value("refid").data(), + protString.data(), + kindString.data()); + m_superClasses.append(sc); + m_curString = ""; +} + +void CompoundHandler::endSuperClass() +{ + m_superClasses.getLast()->setName(m_curString); +} + +void CompoundHandler::startSubClass(const QXmlAttributes& attrib) +{ + IRelatedCompound::Protection prot = IRelatedCompound::Public; + QString protString = attrib.value("prot"); + if (protString=="protected") prot = IRelatedCompound::Protected; + else if (protString=="private") prot = IRelatedCompound::Private; + + IRelatedCompound::Kind kind = IRelatedCompound::Normal; + QString kindString = attrib.value("virt"); + if (kindString=="virtual") kind = IRelatedCompound::Virtual; + + RelatedCompound *sc = new RelatedCompound( + this, + attrib.value("refid"), + prot, + kind + ); + debug(2,"sub class id=`%s' prot=`%s' virt=`%s'\n", + attrib.value("refid").data(), + protString.data(), + kindString.data()); + m_subClasses.append(sc); + m_curString = ""; +} + +void CompoundHandler::endSubClass() +{ + m_subClasses.getLast()->setName(m_curString); +} + +void CompoundHandler::startTitle(const QXmlAttributes& attrib) +{ + ASSERT(m_titleHandler==0); + m_titleHandler = new TitleHandler(this); + m_titleHandler->startTitle(attrib); +} + +bool CompoundHandler::parseXML(const char *compId) +{ + QFile xmlFile(m_xmlDir+"/"+compId+".xml"); + if (!xmlFile.exists()) return FALSE; + CompoundErrorHandler errorHandler; + QXmlInputSource source( xmlFile ); + QXmlSimpleReader reader; + reader.setContentHandler( this ); + reader.setErrorHandler( &errorHandler ); + reader.parse( source ); + return TRUE; +} + +void CompoundHandler::initialize(MainHandler *mh) +{ + m_mainHandler = mh; + QListIterator msi(m_sections); + SectionHandler *sec; + for (;(sec=msi.current());++msi) + { + sec->initialize(this); + } + if (m_members) + { + m_members->initialize(mh); + } +} + +void CompoundHandler::insertMember(MemberHandler *mh) +{ + m_memberDict.insert(mh->id()->latin1(),mh); + mh->initialize(m_mainHandler); + QList *mhl = m_memberNameDict.find(mh->id()->latin1()); + if (mhl==0) + { + mhl = new QList; + m_memberNameDict.insert(mh->name()->latin1(),mhl); + } + mhl->append(mh); +} + +ICompound *CompoundHandler::toICompound() const +{ + switch (m_kind) + { + case IClass::Class: return (IClass *)this; + case IStruct::Struct: return (IStruct *)this; + case IUnion::Union: return (IUnion *)this; + case IException::Exception: return (IException *)this; + case IInterface::Interface: return (IInterface *)this; + case INamespace::Namespace: return (INamespace *)this; + case IFile::File: return (IFile *)this; + case IGroup::Group: return (IGroup *)this; + case IPage::Page: return (IPage *)this; + default: return 0; + } + return 0; +} + +void CompoundHandler::release() +{ + debug(2,"CompoundHandler::release() %d->%d\n",m_refCount,m_refCount-1); + if (--m_refCount<=0) + { + m_mainHandler->unloadCompound(this); + delete this; + } +} + +ISectionIterator *CompoundHandler::sections() const +{ + return new SectionIterator(m_sections); +} + +IMemberIterator *CompoundHandler::memberByName(const char *name) const +{ + QList *ml = m_memberNameDict[name]; + if (ml==0) return 0; + return new MemberIterator(*ml); +} + +void CompoundHandler::startInheritanceGraph(const QXmlAttributes &attrib) +{ + m_inheritanceGraph = new GraphHandler(this,"inheritancegraph"); + m_inheritanceGraph->startGraph(attrib); +} + +void CompoundHandler::startCollaborationGraph(const QXmlAttributes &attrib) +{ + m_collaborationGraph = new GraphHandler(this,"collaborationgraph"); + m_collaborationGraph->startGraph(attrib); +} + +void CompoundHandler::startIncludeDependencyGraph(const QXmlAttributes &attrib) +{ + m_includeDependencyGraph = new GraphHandler(this,"incdepgraph"); + m_includeDependencyGraph->startGraph(attrib); +} + +void CompoundHandler::startIncludedByDependencyGraph(const QXmlAttributes &attrib) +{ + m_includedByDependencyGraph = new GraphHandler(this,"invincdepgraph"); + m_includedByDependencyGraph->startGraph(attrib); +} + +IDocRoot *CompoundHandler::briefDescription() const +{ + return m_brief; +} + +IDocRoot *CompoundHandler::detailedDescription() const +{ + return m_detailed; +} + +IMember *CompoundHandler::memberById(const char *id) const +{ + return (IFunction*)m_memberDict[id]; +} + +IGraph *CompoundHandler::inheritanceGraph() const +{ + return m_inheritanceGraph; +} + +IGraph *CompoundHandler::collaborationGraph() const +{ + return m_collaborationGraph; +} + +IGraph *CompoundHandler::includeDependencyGraph() const +{ + return m_includeDependencyGraph; +} + +IGraph *CompoundHandler::includedByDependencyGraph() const +{ + return m_includedByDependencyGraph; +} + +IRelatedCompoundIterator *CompoundHandler::baseCompounds() const +{ + return new RelatedCompoundIterator(m_superClasses); +} + +IRelatedCompoundIterator *CompoundHandler::derivedCompounds() const +{ + return new RelatedCompoundIterator(m_subClasses); +} + +ICompoundIterator *CompoundHandler::nestedCompounds() const +{ + return new CompoundIdIterator(m_mainHandler,m_innerCompounds); +} + +IDocProgramListing *CompoundHandler::source() const +{ + return m_programListing; +} + +IIncludeIterator *CompoundHandler::includes() const +{ + return new IncludeIterator(m_includes); +} + +IIncludeIterator *CompoundHandler::includedBy() const +{ + return new IncludeIterator(m_includedBy); +} + +IParamIterator *CompoundHandler::templateParameters() const +{ + return m_templateParamList ? m_templateParamList->templateParams() : 0; +} + +const IDocTitle *CompoundHandler::title() const +{ + return m_titleHandler; +} + +IMemberReferenceIterator *CompoundHandler::members() const +{ + return m_members ? m_members->members() : 0; +} + + diff --git a/trunk/addon/doxmlparser/src/compoundhandler.h b/trunk/addon/doxmlparser/src/compoundhandler.h new file mode 100644 index 0000000..9c081ed --- /dev/null +++ b/trunk/addon/doxmlparser/src/compoundhandler.h @@ -0,0 +1,236 @@ +/****************************************************************************** + * + * $Id$ + * + * + * Copyright (C) 1997-2012 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. + * + */ +#ifndef _COMPOUNDHANDLER_H +#define _COMPOUNDHANDLER_H + +#include +#include +#include +#include + +#include "stringimpl.h" +#include "basehandler.h" +#include "baseiterator.h" + +class MainHandler; +class DocHandler; +class ProgramListingHandler; +class GraphHandler; +class MemberHandler; +class CompoundHandler; +class SectionHandler; +class ParamHandler; +class TemplateParamListHandler; +class TitleHandler; +class ListOfAllMembersHandler; + +class IncludeHandler : public IInclude, public BaseHandler +{ + public: + IncludeHandler(IBaseHandler *parent,const char *endtag); + virtual ~IncludeHandler(); + + void startInclude(const QXmlAttributes &attrib); + void endInclude(); + + // IInclude + virtual const IString * name() const + { return &m_name; } + virtual const IString * refId() const + { return &m_refId; } + virtual bool isLocal() const + { return &m_isLocal; } + + private: + IBaseHandler *m_parent; + StringImpl m_name; // element's content + StringImpl m_refId; // refid + bool m_isLocal; // local +}; + +class IncludeIterator : public BaseIterator +{ + public: + IncludeIterator(const QList &list) : + BaseIterator(list) {} +}; + + +class RelatedCompound : public IRelatedCompound +{ + public: + RelatedCompound(CompoundHandler *parent, + const QString &id, + Protection prot, + Kind kind + ) : + m_parent(parent), m_id(id), m_protection(prot), m_kind(kind) {} + virtual ~RelatedCompound() {} + void setName(const QString &str) { m_name = str; } + + virtual ICompound *compound() const; + virtual Protection protection() const { return m_protection; } + virtual Kind kind() const { return m_kind; } + virtual const IString *name() const { return &m_name; } + + private: + CompoundHandler *m_parent; + QString m_id; // refid + Protection m_protection; // prot + Kind m_kind; // virt + StringImpl m_name; // element's content +}; + +class RelatedCompoundIterator : public BaseIterator +{ + public: + RelatedCompoundIterator(const QList &list) : + BaseIterator(list) {} +}; + + +class CompoundHandler : public IClass, + public IStruct, + public IUnion, + public IException, + public IInterface, + public INamespace, + public IFile, + public IGroup, + public IPage, + public BaseHandler +{ + friend class RelatedCompound; + + public: + virtual void startSection(const QXmlAttributes& attrib); + virtual void startCompound(const QXmlAttributes& attrib); + virtual void startSuperClass(const QXmlAttributes& attrib); + virtual void endSuperClass(); + virtual void startSubClass(const QXmlAttributes& attrib); + virtual void endSubClass(); + virtual void endCompound(); + virtual void endCompoundName(); + virtual void startBriefDesc(const QXmlAttributes& attrib); + virtual void startDetailedDesc(const QXmlAttributes& attrib); + virtual void startLocation(const QXmlAttributes& attrib); + virtual void startProgramListing(const QXmlAttributes& attrib); + virtual void startInheritanceGraph(const QXmlAttributes& attrib); + virtual void startCollaborationGraph(const QXmlAttributes& attrib); + virtual void startIncludeDependencyGraph(const QXmlAttributes& attrib); + virtual void startIncludedByDependencyGraph(const QXmlAttributes& attrib); + virtual void startIncludes(const QXmlAttributes& attrib); + virtual void startIncludedBy(const QXmlAttributes& attrib); + virtual void startInnerDir(const QXmlAttributes& attrib); + virtual void startInnerClass(const QXmlAttributes& attrib); + virtual void startInnerNamespace(const QXmlAttributes& attrib); + virtual void startInnerFile(const QXmlAttributes& attrib); + virtual void startInnerGroup(const QXmlAttributes& attrib); + virtual void startInnerPage(const QXmlAttributes& attrib); + virtual void startTitle(const QXmlAttributes& attrib); + virtual void startTemplateParamList(const QXmlAttributes& attrib); + virtual void startListOfAllMembers(const QXmlAttributes& attrib); + virtual void addref() { m_refCount++; } + + CompoundHandler(const QString &dirName); + virtual ~CompoundHandler(); + bool parseXML(const char *compId); + void initialize(MainHandler *mh); + void insertMember(MemberHandler *mh); + ICompound *toICompound() const; + + // ICompound implementation + const IString *name() const { return &m_name; } + const IString *id() const { return &m_id; } + CompoundKind kind() const { return m_kind; } + const IString *kindString() const { return &m_kindString; } + ISectionIterator *sections() const; + IDocRoot *briefDescription() const; + IDocRoot *detailedDescription() const; + IMember *memberById(const char *id) const; + IMemberIterator *memberByName(const char *name) const; + IParamIterator *templateParameters() const; + void release(); + + // IClass implementation + IGraph *inheritanceGraph() const; + IGraph *collaborationGraph() const; + IRelatedCompoundIterator *baseCompounds() const; + IRelatedCompoundIterator *derivedCompounds() const; + ICompoundIterator *nestedCompounds() const; + ICompoundIterator *nestedGroup() const; + const IString *locationFile() const { return &m_defFile; } + int locationLine() const { return m_defLine; } + const IString *locationBodyFile() const { return &m_defBodyFile; } + int locationBodyStartLine() const { return m_defBodyStart; } + int locationBodyEndLine() const { return m_defBodyEnd; } + IMemberReferenceIterator *members() const; + + // IFile implementation + IGraph *includeDependencyGraph() const; + IGraph *includedByDependencyGraph() const; + IDocProgramListing *source() const; + IIncludeIterator *includes() const; + IIncludeIterator *includedBy() const; + + // IPage implementation + const IDocTitle *title() const; + + private: + // XML elements: + // ------------- + StringImpl m_name; // compoundname + TitleHandler* m_titleHandler; // title + QList m_subClasses; // basecompoundref + QList m_superClasses; // derivedcompoundref + QList m_includes; // includes + QList m_includedBy; // includedBy + GraphHandler* m_includeDependencyGraph; // incdepgraph + GraphHandler* m_includedByDependencyGraph; // invincdepgraph + QList m_innerCompounds; // innerdir/innerfile/innerclass/innernamespace/innergroup + TemplateParamListHandler* m_templateParamList; // templateparamlist + QList m_sections; // sectiondef + DocHandler* m_brief; // briefdescription + DocHandler* m_detailed; // detaileddescription + GraphHandler* m_inheritanceGraph; // inheritancegraph + GraphHandler* m_collaborationGraph; // collaborationgraph + ProgramListingHandler* m_programListing; // programlisting + // location + StringImpl m_defFile; // - file + int m_defLine; // - line + StringImpl m_defBodyFile; // - bodyfile + int m_defBodyStart; // - bodystart + int m_defBodyEnd; // - bodyend + ListOfAllMembersHandler* m_members; // listofallmember + + // XML attributes: + // --------------- + StringImpl m_id; // id + CompoundKind m_kind; // kind + StringImpl m_kindString; // kind as a string + StringImpl m_protection; // prot + + // local variables + QString m_xmlDir; // directory where the info is found + int m_refCount; // object reference counter + QDict m_memberDict; // id->member lookup + QDict > m_memberNameDict; // name->memberlist lookup + MainHandler* m_mainHandler; // parent object +}; + +void compoundhandler_init(); +void compoundhandler_exit(); + +#endif diff --git a/trunk/addon/doxmlparser/src/debug.cpp b/trunk/addon/doxmlparser/src/debug.cpp new file mode 100644 index 0000000..a8be32c --- /dev/null +++ b/trunk/addon/doxmlparser/src/debug.cpp @@ -0,0 +1,24 @@ +#include +#include +#include + +#include "debug.h" + +static int s_debugLevel = 0; + +void debug(int level,const char *msg,...) +{ + if (level<=s_debugLevel) + { + va_list args; + va_start(args, msg); + vfprintf(stderr, msg, args); + va_end(args); + } +} + +void setDebugLevel(int level) +{ + s_debugLevel = level; +} + diff --git a/trunk/addon/doxmlparser/src/debug.h b/trunk/addon/doxmlparser/src/debug.h new file mode 100644 index 0000000..c77f7fe --- /dev/null +++ b/trunk/addon/doxmlparser/src/debug.h @@ -0,0 +1,7 @@ +#ifndef _DEBUG_H +#define _DEBUG_H + +void debug(int level,const char *msg,...); +void setDebugLevel(int level); + +#endif diff --git a/trunk/addon/doxmlparser/src/dochandler.cpp b/trunk/addon/doxmlparser/src/dochandler.cpp new file mode 100644 index 0000000..f277094 --- /dev/null +++ b/trunk/addon/doxmlparser/src/dochandler.cpp @@ -0,0 +1,2240 @@ +/****************************************************************************** + * + * $Id$ + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#include + +#include "dochandler.h" +#include "debug.h" +#include "linkedtexthandler.h" + + +//---------------------------------------------------------------------- + +class TypeNameMapper +{ + public: + TypeNameMapper() + { + m_map.insert("see", SimpleSectHandler::See); + m_map.insert("return", SimpleSectHandler::Return); + m_map.insert("author", SimpleSectHandler::Author); + m_map.insert("version", SimpleSectHandler::Version); + m_map.insert("since", SimpleSectHandler::Since); + m_map.insert("date", SimpleSectHandler::Date); + m_map.insert("bug", SimpleSectHandler::Bug); + m_map.insert("note", SimpleSectHandler::Note); + m_map.insert("warning", SimpleSectHandler::Warning); + m_map.insert("par", SimpleSectHandler::Par); + m_map.insert("deprecated",SimpleSectHandler::Deprecated); + m_map.insert("pre", SimpleSectHandler::Pre); + m_map.insert("post", SimpleSectHandler::Post); + m_map.insert("invariant", SimpleSectHandler::Invar); + m_map.insert("remark", SimpleSectHandler::Remark); + m_map.insert("attention", SimpleSectHandler::Attention); + m_map.insert("todo", SimpleSectHandler::Todo); + m_map.insert("test", SimpleSectHandler::Test); + m_map.insert("rcs", SimpleSectHandler::RCS); + m_map.insert("enumvalues",SimpleSectHandler::EnumValues); + m_map.insert("examples", SimpleSectHandler::Examples); + } + SimpleSectHandler::Types stringToType(const QString &typeStr) + { + return m_map[typeStr]; + } + private: + QMap m_map; +}; + +class HighlightMapper +{ + public: + HighlightMapper() + { + m_map.insert("comment", HighlightHandler::Comment); + m_map.insert("keyword", HighlightHandler::Keyword); + m_map.insert("keywordtype", HighlightHandler::KeywordType); + m_map.insert("keywordflow", HighlightHandler::KeywordFlow); + m_map.insert("charliteral", HighlightHandler::CharLiteral); + m_map.insert("stringliteral", HighlightHandler::StringLiteral); + m_map.insert("preprocessor", HighlightHandler::Preprocessor); + } + HighlightHandler::HighlightKind stringToKind(const QString &kindStr) + { + return m_map[kindStr]; + } + private: + QMap m_map; +}; + +static TypeNameMapper *s_typeMapper; +static HighlightMapper *s_highlightMapper; + +void dochandler_init() +{ + s_typeMapper = new TypeNameMapper; + s_highlightMapper = new HighlightMapper; +} + +void dochandler_exit() +{ + delete s_typeMapper; + delete s_highlightMapper; +} + +//---------------------------------------------------------------------- +// MarkupHandler +//---------------------------------------------------------------------- + +MarkupHandler::MarkupHandler(QList &children,QString &curString) + : m_children(children), m_curString(curString), + m_curMarkup(IDocMarkup::Normal), m_headingLevel(0) +{ + addStartHandler("bold",this,&MarkupHandler::startBold); + addEndHandler("bold",this,&MarkupHandler::endBold); + + addStartHandler("emphasis",this,&MarkupHandler::startEmphasis); + addEndHandler("emphasis",this,&MarkupHandler::endEmphasis); + + addStartHandler("computeroutput",this,&MarkupHandler::startComputerOutput); + addEndHandler("computeroutput",this,&MarkupHandler::endComputerOutput); + + addStartHandler("center",this,&MarkupHandler::startCenter); + addEndHandler("center",this,&MarkupHandler::endCenter); + + addStartHandler("small",this,&MarkupHandler::startSmallFont); + addEndHandler("small",this,&MarkupHandler::endSmallFont); + + addStartHandler("subscript",this,&MarkupHandler::startSubscript); + addEndHandler("subscript",this,&MarkupHandler::endSubscript); + + addStartHandler("superscript",this,&MarkupHandler::startSuperscript); + addEndHandler("superscript",this,&MarkupHandler::endSuperscript); + + addStartHandler("preformatted",this,&MarkupHandler::startPreformatted); + addEndHandler("preformatted",this,&MarkupHandler::endPreformatted); + + addStartHandler("heading1",this,&MarkupHandler::startHeading1); + addEndHandler("heading1",this,&MarkupHandler::endHeading1); + + addStartHandler("heading2",this,&MarkupHandler::startHeading2); + addEndHandler("heading2",this,&MarkupHandler::endHeading2); + + addStartHandler("heading3",this,&MarkupHandler::startHeading3); + addEndHandler("heading3",this,&MarkupHandler::endHeading3); + + addStartHandler("heading4",this,&MarkupHandler::startHeading4); + addEndHandler("heading4",this,&MarkupHandler::endHeading4); + + addStartHandler("heading5",this,&MarkupHandler::startHeading5); + addEndHandler("heading5",this,&MarkupHandler::endHeading5); + + addStartHandler("heading6",this,&MarkupHandler::startHeading6); + addEndHandler("heading6",this,&MarkupHandler::endHeading6); +} + +MarkupHandler::~MarkupHandler() +{ +} + +void MarkupHandler::addTextNode() +{ + if (!m_curString.isEmpty()) + { + m_children.append(new TextNode(m_curString,m_curMarkup,m_headingLevel)); + debug(2,"addTextNode() text=%s markup=%x\n",m_curString.data(),m_curMarkup); + m_curString=""; + } +} + +void MarkupHandler::startBold(const QXmlAttributes & /*attrib*/) +{ + addTextNode(); + m_children.append(new MarkupModifierNode(IDocMarkup::Bold,TRUE)); + m_curMarkup |= IDocMarkup::Bold; +} + +void MarkupHandler::endBold() +{ + addTextNode(); + m_children.append(new MarkupModifierNode(IDocMarkup::Bold,FALSE)); + m_curMarkup &= ~IDocMarkup::Bold; +} + +void MarkupHandler::startEmphasis(const QXmlAttributes & /*attrib*/) +{ + addTextNode(); + m_children.append(new MarkupModifierNode(IDocMarkup::Emphasis,TRUE)); + m_curMarkup |= IDocMarkup::Emphasis; +} + +void MarkupHandler::endEmphasis() +{ + addTextNode(); + m_children.append(new MarkupModifierNode(IDocMarkup::Emphasis,FALSE)); + m_curMarkup &= ~IDocMarkup::Emphasis; +} + +void MarkupHandler::startComputerOutput(const QXmlAttributes & /*attrib*/) +{ + addTextNode(); + m_children.append(new MarkupModifierNode(IDocMarkup::ComputerOutput,TRUE)); + m_curMarkup |= IDocMarkup::ComputerOutput; +} + +void MarkupHandler::endComputerOutput() +{ + addTextNode(); + m_children.append(new MarkupModifierNode(IDocMarkup::ComputerOutput,FALSE)); + m_curMarkup &= ~IDocMarkup::ComputerOutput; +} + +void MarkupHandler::startCenter(const QXmlAttributes & /*attrib*/) +{ + addTextNode(); + m_children.append(new MarkupModifierNode(IDocMarkup::Center,TRUE)); + m_curMarkup |= IDocMarkup::Center; +} + +void MarkupHandler::endCenter() +{ + addTextNode(); + m_children.append(new MarkupModifierNode(IDocMarkup::Center,FALSE)); + m_curMarkup &= ~IDocMarkup::Center; +} + +void MarkupHandler::startSmallFont(const QXmlAttributes & /*attrib*/) +{ + addTextNode(); + m_children.append(new MarkupModifierNode(IDocMarkup::SmallFont,TRUE)); + m_curMarkup |= IDocMarkup::SmallFont; +} + +void MarkupHandler::endSmallFont() +{ + addTextNode(); + m_children.append(new MarkupModifierNode(IDocMarkup::SmallFont,FALSE)); + m_curMarkup &= ~IDocMarkup::SmallFont; +} + +void MarkupHandler::startSubscript(const QXmlAttributes & /*attrib*/) +{ + addTextNode(); + m_children.append(new MarkupModifierNode(IDocMarkup::Subscript,TRUE)); + m_curMarkup |= IDocMarkup::Subscript; +} + +void MarkupHandler::endSubscript() +{ + addTextNode(); + m_children.append(new MarkupModifierNode(IDocMarkup::Subscript,FALSE)); + m_curMarkup &= ~IDocMarkup::Subscript; +} + +void MarkupHandler::startSuperscript(const QXmlAttributes & /*attrib*/) +{ + addTextNode(); + m_children.append(new MarkupModifierNode(IDocMarkup::Superscript,TRUE)); + m_curMarkup |= IDocMarkup::Superscript; +} + +void MarkupHandler::endSuperscript() +{ + addTextNode(); + m_children.append(new MarkupModifierNode(IDocMarkup::Superscript,FALSE)); + m_curMarkup &= ~IDocMarkup::Superscript; +} + +void MarkupHandler::startPreformatted(const QXmlAttributes & /*attrib*/) +{ + addTextNode(); + m_children.append(new MarkupModifierNode(IDocMarkup::Preformatted,TRUE)); + m_curMarkup |= IDocMarkup::Preformatted; +} + +void MarkupHandler::endPreformatted() +{ + addTextNode(); + m_children.append(new MarkupModifierNode(IDocMarkup::Preformatted,FALSE)); + m_curMarkup &= ~IDocMarkup::Preformatted; +} + +void MarkupHandler::startHeading1(const QXmlAttributes & /*attrib*/) +{ + addTextNode(); + m_children.append(new MarkupModifierNode(IDocMarkup::Heading,TRUE,1)); + m_curMarkup |= IDocMarkup::Heading; + m_headingLevel=1; +} + +void MarkupHandler::endHeading1() +{ + addTextNode(); + m_children.append(new MarkupModifierNode(IDocMarkup::Heading,FALSE,1)); + m_curMarkup &= ~IDocMarkup::Heading; + m_headingLevel=0; +} + +void MarkupHandler::startHeading2(const QXmlAttributes & /*attrib*/) +{ + addTextNode(); + m_children.append(new MarkupModifierNode(IDocMarkup::Heading,TRUE,2)); + m_curMarkup |= IDocMarkup::Heading; + m_headingLevel=2; +} + +void MarkupHandler::endHeading2() +{ + addTextNode(); + m_children.append(new MarkupModifierNode(IDocMarkup::Heading,FALSE,2)); + m_curMarkup &= ~IDocMarkup::Heading; + m_headingLevel=0; +} + +void MarkupHandler::startHeading3(const QXmlAttributes & /*attrib*/) +{ + addTextNode(); + m_children.append(new MarkupModifierNode(IDocMarkup::Heading,TRUE,3)); + m_curMarkup |= IDocMarkup::Heading; + m_headingLevel=3; +} + +void MarkupHandler::endHeading3() +{ + addTextNode(); + m_children.append(new MarkupModifierNode(IDocMarkup::Heading,FALSE,3)); + m_curMarkup &= ~IDocMarkup::Heading; + m_headingLevel=0; +} + +void MarkupHandler::startHeading4(const QXmlAttributes & /*attrib*/) +{ + addTextNode(); + m_children.append(new MarkupModifierNode(IDocMarkup::Heading,TRUE,4)); + m_curMarkup |= IDocMarkup::Heading; + m_headingLevel=4; +} + +void MarkupHandler::endHeading4() +{ + addTextNode(); + m_children.append(new MarkupModifierNode(IDocMarkup::Heading,FALSE,4)); + m_curMarkup &= ~IDocMarkup::Heading; + m_headingLevel=0; +} + +void MarkupHandler::startHeading5(const QXmlAttributes & /*attrib*/) +{ + addTextNode(); + m_children.append(new MarkupModifierNode(IDocMarkup::Heading,TRUE,5)); + m_curMarkup |= IDocMarkup::Heading; + m_headingLevel=5; +} + +void MarkupHandler::endHeading5() +{ + addTextNode(); + m_children.append(new MarkupModifierNode(IDocMarkup::Heading,FALSE,5)); + m_curMarkup &= ~IDocMarkup::Heading; + m_headingLevel=0; +} + +void MarkupHandler::startHeading6(const QXmlAttributes & /*attrib*/) +{ + addTextNode(); + m_children.append(new MarkupModifierNode(IDocMarkup::Heading,TRUE,6)); + m_curMarkup |= IDocMarkup::Heading; + m_headingLevel=6; +} + +void MarkupHandler::endHeading6() +{ + addTextNode(); + m_children.append(new MarkupModifierNode(IDocMarkup::Heading,FALSE,6)); + m_curMarkup &= ~IDocMarkup::Heading; + m_headingLevel=0; +} + + +//---------------------------------------------------------------------- +// ListItemHandler +//---------------------------------------------------------------------- + +ListItemHandler::ListItemHandler(IBaseHandler *parent) + : m_parent(parent) +{ + m_children.setAutoDelete(TRUE); + + addEndHandler("listitem",this,&ListItemHandler::endListItem); + + addStartHandler("para",this,&ListItemHandler::startParagraph); +} + +ListItemHandler::~ListItemHandler() +{ +} + +void ListItemHandler::startListItem(const QXmlAttributes& /*attrib*/) +{ + m_parent->setDelegate(this); + debug(2,"start list item handler\n"); +} + +void ListItemHandler::endListItem() +{ + debug(2,"end list item handler\n"); + m_parent->setDelegate(0); +} + +void ListItemHandler::startParagraph(const QXmlAttributes& attrib) +{ + ParagraphHandler *parHandler = new ParagraphHandler(this); + parHandler->startParagraph(attrib); + m_children.append(parHandler); +} + +IDocIterator *ListItemHandler::contents() const +{ + return new ListItemIterator(*this); +} + +//---------------------------------------------------------------------- +// OrderedListHandler +//---------------------------------------------------------------------- + +OrderedListHandler::OrderedListHandler(IBaseHandler *parent) : m_parent(parent) +{ + m_children.setAutoDelete(TRUE); + addEndHandler("orderedlist",this,&OrderedListHandler::endOrderedList); + addStartHandler("listitem",this,&OrderedListHandler::startOrderedListItem); +} + +OrderedListHandler::~OrderedListHandler() +{ +} + +void OrderedListHandler::startOrderedList(const QXmlAttributes& /*attrib*/) +{ + m_parent->setDelegate(this); +} + +void OrderedListHandler::endOrderedList() +{ + m_parent->setDelegate(0); +} + +void OrderedListHandler::startOrderedListItem(const QXmlAttributes& attrib) +{ + ListItemHandler *liHandler = new ListItemHandler(this); + liHandler->startListItem(attrib); + m_children.append(liHandler); +} + +IDocIterator *OrderedListHandler::elements() const +{ + return new OrderedListIterator(*this); +} + +//---------------------------------------------------------------------- +// ItemizedListHandler +//---------------------------------------------------------------------- + +ItemizedListHandler::ItemizedListHandler(IBaseHandler *parent) : m_parent(parent) +{ + m_children.setAutoDelete(TRUE); + addEndHandler("itemizedlist",this,&ItemizedListHandler::endItemizedList); + addStartHandler("listitem",this,&ItemizedListHandler::startItemizedListItem); +} + +ItemizedListHandler::~ItemizedListHandler() +{ +} + +void ItemizedListHandler::startItemizedList(const QXmlAttributes& /*attrib*/) +{ + m_parent->setDelegate(this); +} + +void ItemizedListHandler::endItemizedList() +{ + m_parent->setDelegate(0); +} + +void ItemizedListHandler::startItemizedListItem(const QXmlAttributes& attrib) +{ + ListItemHandler *liHandler = new ListItemHandler(this); + liHandler->startListItem(attrib); + m_children.append(liHandler); +} + +IDocIterator *ItemizedListHandler::elements() const +{ + return new ItemizedListIterator(*this); +} + +//---------------------------------------------------------------------- +// TocListHandler +//---------------------------------------------------------------------- + +TocListHandler::TocListHandler(IBaseHandler *parent) : m_parent(parent) +{ + m_children.setAutoDelete(TRUE); + addEndHandler("toclist",this,&TocListHandler::endTocList); + addStartHandler("tocitem",this,&TocListHandler::startTocItem); +} + +TocListHandler::~TocListHandler() +{ +} + +void TocListHandler::startTocList(const QXmlAttributes& /*attrib*/) +{ + m_parent->setDelegate(this); +} + +void TocListHandler::endTocList() +{ + m_parent->setDelegate(0); +} + +void TocListHandler::startTocItem(const QXmlAttributes& attrib) +{ + TocItemHandler *tiHandler = new TocItemHandler(this); + tiHandler->startTocItem(attrib); + m_children.append(tiHandler); +} + +IDocIterator *TocListHandler::elements() const +{ + return new TocListIterator(*this); +} + +//---------------------------------------------------------------------- +// TocItemHandler +//---------------------------------------------------------------------- + +TocItemHandler::TocItemHandler(IBaseHandler *parent) : m_parent(parent) +{ + addEndHandler("tocitem",this,&TocItemHandler::endTocItem); +} + +TocItemHandler::~TocItemHandler() +{ +} + +void TocItemHandler::startTocItem(const QXmlAttributes& attrib) +{ + m_parent->setDelegate(this); + m_id = attrib.value("id"); + m_curString=""; +} + +void TocItemHandler::endTocItem() +{ + m_title = m_curString; + m_parent->setDelegate(0); +} + +//---------------------------------------------------------------------- +// ParameterHandler +//---------------------------------------------------------------------- + +ParameterHandler::ParameterHandler(IBaseHandler *parent) : + m_parent(parent) +{ + addEndHandler("parametername",this,&ParameterHandler::endParameterName); +} + +ParameterHandler::~ParameterHandler() +{ +} + +void ParameterHandler::startParameterName(const QXmlAttributes& /*attrib*/) +{ + m_parent->setDelegate(this); +} + +void ParameterHandler::endParameterName() +{ + m_name = m_curString; + debug(2,"parameter %s\n",m_name.data()); + m_curString=""; + m_parent->setDelegate(0); +} + +//---------------------------------------------------------------------- +// ParameterListHandler +//---------------------------------------------------------------------- + +ParameterItemHandler::ParameterItemHandler(IBaseHandler *parent) + : m_parent(parent) +{ + addEndHandler("parameteritem",this,&ParameterItemHandler::endParameterItem); + addStartHandler("parameternamelist"); + addEndHandler("parameternamelist"); + addStartHandler("parametername",this,&ParameterItemHandler::startParameterName); + addStartHandler("parameterdescription"); + addEndHandler("parameterdescription"); + addStartHandler("para",this,&ParameterItemHandler::startParagraph); + m_parameters.setAutoDelete(TRUE); + m_description = 0; +} + +ParameterItemHandler::~ParameterItemHandler() +{ + delete m_description; +} + +void ParameterItemHandler::startParameterItem(const QXmlAttributes&) +{ + m_parent->setDelegate(this); +} + +void ParameterItemHandler::endParameterItem() +{ + m_parent->setDelegate(0); +} + +void ParameterItemHandler::startParameterName(const QXmlAttributes& attrib) +{ + ParameterHandler *param = new ParameterHandler(this); + m_parameters.append(param); + param->startParameterName(attrib); +} + +void ParameterItemHandler::startParagraph(const QXmlAttributes& attrib) +{ + m_description = new ParagraphHandler(this); + m_description->startParagraph(attrib); +} + +IDocIterator *ParameterItemHandler::paramNames() const +{ + return new ParameterItemIterator(*this); +} + +//---------------------------------------------------------------------- +// ParameterListHandler +//---------------------------------------------------------------------- + +ParameterListHandler::ParameterListHandler(IBaseHandler *parent) + : m_parent(parent) +{ + addEndHandler("parameterlist",this,&ParameterListHandler::endParameterList); + addStartHandler("parameteritem",this,&ParameterListHandler::startParameterItem); + m_paramItems.setAutoDelete(TRUE); +} + +ParameterListHandler::~ParameterListHandler() +{ +} + +void ParameterListHandler::startParameterList(const QXmlAttributes& attrib) +{ + QString kind = attrib.value("kind"); + if (kind=="retval") m_type=RetVal; + else if (kind=="exception") m_type=Exception; + else if (kind=="param") m_type=Param; + else + { + debug(1,"Error: invalid parameterlist type: %s\n",kind.data()); + } + debug(2,"parameterlist kind=%s\n",kind.data()); + m_parent->setDelegate(this); +} + +void ParameterListHandler::endParameterList() +{ + m_parent->setDelegate(0); +} + +void ParameterListHandler::startParameterItem(const QXmlAttributes& attrib) +{ + ParameterItemHandler *paramItem = new ParameterItemHandler(this); + m_paramItems.append(paramItem); + paramItem->startParameterItem(attrib); +} + +IDocIterator *ParameterListHandler::params() const +{ + return new ParameterListIterator(*this); +} + +//---------------------------------------------------------------------- +// LinkHandler +//---------------------------------------------------------------------- + +LinkHandler::LinkHandler(IBaseHandler *parent) + : m_parent(parent) +{ + addEndHandler("link",this,&LinkHandler::endLink); +} + +LinkHandler::~LinkHandler() +{ +} + +void LinkHandler::startLink(const QXmlAttributes& attrib) +{ + m_parent->setDelegate(this); + debug(2,"Start link\n"); + m_ref = attrib.value("linkend"); + m_curString=""; +} + +void LinkHandler::endLink() +{ + m_text = m_curString; + m_curString=""; + m_parent->setDelegate(0); + debug(2,"End link\n"); +} + +//---------------------------------------------------------------------- +// EMailHandler +//---------------------------------------------------------------------- + +EMailHandler::EMailHandler(IBaseHandler *parent) + : m_parent(parent) +{ + addEndHandler("email",this,&EMailHandler::endEMail); +} + +EMailHandler::~EMailHandler() +{ +} + +void EMailHandler::startEMail(const QXmlAttributes& /*attrib*/) +{ + m_parent->setDelegate(this); + debug(2,"Start email\n"); + m_curString=""; +} + +void EMailHandler::endEMail() +{ + m_address = m_curString; + m_curString=""; + m_parent->setDelegate(0); + debug(2,"End email\n"); +} + +//---------------------------------------------------------------------- +// ULinkHandler +//---------------------------------------------------------------------- + +ULinkHandler::ULinkHandler(IBaseHandler *parent) + : m_parent(parent) +{ + addEndHandler("ulink",this,&ULinkHandler::endULink); +} + +ULinkHandler::~ULinkHandler() +{ +} + +void ULinkHandler::startULink(const QXmlAttributes& attrib) +{ + m_parent->setDelegate(this); + debug(2,"Start ulink\n"); + m_url = attrib.value("url"); + m_curString=""; +} + +void ULinkHandler::endULink() +{ + m_text = m_curString; + m_curString=""; + m_parent->setDelegate(0); + debug(2,"End ulink\n"); +} + +//---------------------------------------------------------------------- +// LineBreakHandler +//---------------------------------------------------------------------- + +LineBreakHandler::LineBreakHandler(IBaseHandler *parent) + : m_parent(parent) +{ + addEndHandler("linebreak",this,&LineBreakHandler::endLineBreak); +} + +LineBreakHandler::~LineBreakHandler() +{ +} + +void LineBreakHandler::startLineBreak(const QXmlAttributes& /*attrib*/) +{ + m_parent->setDelegate(this); + debug(2,"Start linebreak\n"); +} + +void LineBreakHandler::endLineBreak() +{ + m_parent->setDelegate(0); + debug(2,"End linebreak\n"); +} + +//---------------------------------------------------------------------- +// HRulerHandler +//---------------------------------------------------------------------- + +HRulerHandler::HRulerHandler(IBaseHandler *parent) + : m_parent(parent) +{ + addEndHandler("hruler",this,&HRulerHandler::endHRuler); +} + +HRulerHandler::~HRulerHandler() +{ +} + +void HRulerHandler::startHRuler(const QXmlAttributes& /*attrib*/) +{ + m_parent->setDelegate(this); + debug(2,"Start hruler\n"); +} + +void HRulerHandler::endHRuler() +{ + m_parent->setDelegate(0); + debug(2,"End hruler\n"); +} + +//---------------------------------------------------------------------- +// RefHandler +//---------------------------------------------------------------------- + +RefHandler::RefHandler(IBaseHandler *parent) + : m_parent(parent) +{ + addEndHandler("ref",this,&RefHandler::endRef); +} + +RefHandler::~RefHandler() +{ +} + +void RefHandler::startRef(const QXmlAttributes& attrib) +{ + m_parent->setDelegate(this); + m_refId = attrib.value("refid"); + m_extId = attrib.value("external"); + ASSERT(attrib.value("kindref")=="compound" || + attrib.value("kindref")=="member"); + m_targetKind = attrib.value("kindref")=="compound" ? Compound : Member; + debug(2,"Start ref refId=%s\n",m_refId.data()); + m_curString=""; +} + +void RefHandler::endRef() +{ + m_linkText = m_curString; + m_parent->setDelegate(0); + debug(2,"End ref: text=`%s'\n",m_linkText.data()); +} + + +//---------------------------------------------------------------------- +// TitleHandler +//---------------------------------------------------------------------- + +TitleHandler::TitleHandler(IBaseHandler *parent) + : m_parent(parent) +{ + m_children.setAutoDelete(TRUE); + m_markupHandler = new MarkupHandler(m_children,m_curString); + setFallBackHandler(m_markupHandler); + addStartHandler("ref",this,&TitleHandler::startRef); + addEndHandler("title",this,&TitleHandler::endTitle); +} + +TitleHandler::~TitleHandler() +{ + delete m_markupHandler; +} + +void TitleHandler::startTitle(const QXmlAttributes& /*attrib*/) +{ + m_parent->setDelegate(this); + debug(2,"Start title\n"); + m_curString=""; +} + +void TitleHandler::endTitle() +{ + addTextNode(); + m_parent->setDelegate(0); + debug(2,"End title\n"); +} + +void TitleHandler::addTextNode() +{ + if (!m_curString.isEmpty()) + { + m_children.append( + new TextNode( + m_curString, + m_markupHandler->markup(), + m_markupHandler->headingLevel() + ) + ); + debug(2,"addTextNode() text=\"%s\" markup=%x headingLevel=%d\n", + m_curString.data(),m_markupHandler->markup(),m_markupHandler->headingLevel()); + m_curString=""; + } +} + +void TitleHandler::startRef(const QXmlAttributes& attrib) +{ + RefHandler *ref = new RefHandler(this); + ref->startRef(attrib); + m_children.append(ref); +} + +IDocIterator *TitleHandler::title() const +{ + return new TitleIterator(*this); +} + +//---------------------------------------------------------------------- +// SimpleSectHandler +//---------------------------------------------------------------------- + +SimpleSectHandler::SimpleSectHandler(IBaseHandler *parent) + : m_parent(parent), m_paragraph(0), m_title(0) +{ + addStartHandler("title",this,&SimpleSectHandler::startTitle); + addStartHandler("para",this,&SimpleSectHandler::startParagraph); + addEndHandler("simplesect",this,&SimpleSectHandler::endSimpleSect); +} + +SimpleSectHandler::~SimpleSectHandler() +{ +} + +void SimpleSectHandler::startSimpleSect(const QXmlAttributes& attrib) +{ + m_typeString = attrib.value("kind"); + m_type = s_typeMapper->stringToType(m_typeString); + debug(2,"start simple section %s\n",m_typeString.data()); + m_parent->setDelegate(this); +} + +void SimpleSectHandler::endSimpleSect() +{ + debug(2,"end simple section\n"); + m_parent->setDelegate(0); +} + +void SimpleSectHandler::startTitle(const QXmlAttributes& attrib) +{ + ASSERT(m_title==0); + m_title = new TitleHandler(this); + m_title->startTitle(attrib); +} + +void SimpleSectHandler::startParagraph(const QXmlAttributes& attrib) +{ + ASSERT(m_paragraph==0); + m_paragraph = new ParagraphHandler(this); + m_paragraph->startParagraph(attrib); +} + +//---------------------------------------------------------------------- +// VariableListEntryHandler +//---------------------------------------------------------------------- + +VariableListEntryHandler::VariableListEntryHandler(IBaseHandler *parent) + : m_parent(parent), m_description(0), m_linkedTextHandler(0) +{ + addStartHandler("term",this,&VariableListEntryHandler::startTerm); + addEndHandler("term",this,&VariableListEntryHandler::endTerm); + addStartHandler("para",this,&VariableListEntryHandler::startParagraph); + addEndHandler("varlistentry",this,&VariableListEntryHandler::endVarListEntry); + addEndHandler("listitem",this,&VariableListEntryHandler::endListItem); +} + +VariableListEntryHandler::~VariableListEntryHandler() +{ + delete m_description; +} + +void VariableListEntryHandler::startVarListEntry(const QXmlAttributes& /*attrib*/) +{ + m_parent->setDelegate(this); + debug(2,"start varlistentry\n"); +} + +void VariableListEntryHandler::endVarListEntry() +{ + m_parent->setDelegate(0); + debug(2,"end varlistentry\n"); +} + +void VariableListEntryHandler::startListItem(const QXmlAttributes& /*attrib*/) +{ + m_parent->setDelegate(this); + debug(2,"start listitem\n"); +} + +void VariableListEntryHandler::endListItem() +{ + m_parent->setDelegate(0); + debug(2,"end listitem\n"); +} + +void VariableListEntryHandler::startTerm(const QXmlAttributes& /*attrib*/) +{ + m_curString=""; + m_linkedTextHandler = new LinkedTextHandler(this,m_term); + m_linkedTextHandler->start("term"); +} + +void VariableListEntryHandler::endTerm() +{ + delete m_linkedTextHandler; +} + +void VariableListEntryHandler::startParagraph(const QXmlAttributes& attrib) +{ + ASSERT(m_description==0); + m_description = new ParagraphHandler(this); + m_description->startParagraph(attrib); +} + +ILinkedTextIterator *VariableListEntryHandler::term() const +{ + return new LinkedTextIterator(m_term); +} + + +//---------------------------------------------------------------------- +// VariableListHandler +//---------------------------------------------------------------------- + +VariableListHandler::VariableListHandler(IBaseHandler *parent) + : m_parent(parent) +{ + m_entries.setAutoDelete(TRUE); + addStartHandler("varlistentry",this,&VariableListHandler::startVarListEntry); + addStartHandler("listitem",this,&VariableListHandler::startListItem); + addEndHandler("variablelist",this,&VariableListHandler::endVariableList); +} + +VariableListHandler::~VariableListHandler() +{ +} + +void VariableListHandler::startVariableList(const QXmlAttributes& /*attrib*/) +{ + m_parent->setDelegate(this); + debug(2,"start variablelist\n"); +} + +void VariableListHandler::endVariableList() +{ + debug(2,"end variablelist\n"); + m_parent->setDelegate(0); +} + +void VariableListHandler::startVarListEntry(const QXmlAttributes& attrib) +{ + VariableListEntryHandler *vle = new VariableListEntryHandler(this); + vle->startVarListEntry(attrib); + m_curEntry = vle; + m_entries.append(vle); +} + +void VariableListHandler::startListItem(const QXmlAttributes& attrib) +{ + ASSERT(m_curEntry!=0); + m_curEntry->startListItem(attrib); +} + +IDocIterator *VariableListHandler::entries() const +{ + return new VariableListIterator(*this); +} + +//---------------------------------------------------------------------- +// HighlightHandler +//---------------------------------------------------------------------- + +HighlightHandler::HighlightHandler(IBaseHandler *parent) + : m_parent(parent) +{ + m_children.setAutoDelete(TRUE); + addEndHandler("highlight",this,&HighlightHandler::endHighlight); + addStartHandler("ref",this,&HighlightHandler::startRef); + addStartHandler("sp",this,&HighlightHandler::startSpace); + m_hl = IDocHighlight::Invalid; +} + +HighlightHandler::~HighlightHandler() +{ +} + +void HighlightHandler::startHighlight(const QXmlAttributes& attrib) +{ + m_hlString = attrib.value("class"); + m_hl = s_highlightMapper->stringToKind(m_hlString); + m_curString=""; + m_parent->setDelegate(this); + debug(2,"start highlight\n"); +} + +void HighlightHandler::endHighlight() +{ + addTextNode(); + debug(2,"end highlight class=`%s'\n",m_hlString.data()); + m_parent->setDelegate(0); +} + +void HighlightHandler::startRef(const QXmlAttributes& attrib) +{ + addTextNode(); + RefHandler *rh = new RefHandler(this); + m_children.append(rh); + rh->startRef(attrib); +} + +void HighlightHandler::startSpace(const QXmlAttributes&) +{ + m_curString=" "; + addTextNode(); +} + +void HighlightHandler::addTextNode() +{ + if (!m_curString.isEmpty()) + { + m_children.append(new TextNode(m_curString,IDocMarkup::Normal,0)); + debug(2,"addTextNode() text=\"%s\"\n", + m_curString.data()); + m_curString=""; + } +} + +IDocIterator *HighlightHandler::codeElements() const +{ + return new HighlightIterator(*this); +} + +//---------------------------------------------------------------------- +// CodeLineHandler +//---------------------------------------------------------------------- + +CodeLineHandler::CodeLineHandler(IBaseHandler *parent) + : m_parent(parent) +{ + m_children.setAutoDelete(TRUE); + addEndHandler("codeline",this,&CodeLineHandler::endCodeLine); + addEndHandler("linenumber",this,&CodeLineHandler::endLineNumber); + addStartHandler("highlight",this,&CodeLineHandler::startHighlight); + addStartHandler("ref",this,&CodeLineHandler::startRef); + m_lineNumber = 0; +} + +CodeLineHandler::~CodeLineHandler() +{ +} + +void CodeLineHandler::startCodeLine(const QXmlAttributes& /*attrib*/) +{ + m_parent->setDelegate(this); + debug(2,"start codeline\n"); +} + +void CodeLineHandler::endCodeLine() +{ + addTextNode(); + debug(2,"end codeline\n"); + m_parent->setDelegate(0); +} + +void CodeLineHandler::startLineNumber(const QXmlAttributes& attrib) +{ + m_parent->setDelegate(this); + debug(2,"start linenumber\n"); + m_lineNumber = attrib.value("line").toInt(); + m_refId = attrib.value("refid"); +} + +void CodeLineHandler::endLineNumber() +{ + m_parent->setDelegate(0); +} + +void CodeLineHandler::startHighlight(const QXmlAttributes& attrib) +{ + addTextNode(); + HighlightHandler *hlh = new HighlightHandler(this); + m_children.append(hlh); + hlh->startHighlight(attrib); +} + +void CodeLineHandler::startRef(const QXmlAttributes& attrib) +{ + addTextNode(); + RefHandler *rh = new RefHandler(this); + m_children.append(rh); + rh->startRef(attrib); +} + +void CodeLineHandler::addTextNode() +{ + if (!m_curString.isEmpty()) + { + m_children.append(new TextNode(m_curString,IDocMarkup::Normal,0)); + debug(2,"addTextNode() text=\"%s\"\n", + m_curString.data()); + m_curString=""; + } +} + +IDocIterator *CodeLineHandler::codeElements() const +{ + return new CodeLineIterator(*this); +} + + +//---------------------------------------------------------------------- +// ProgramListingHandler +//---------------------------------------------------------------------- + +ProgramListingHandler::ProgramListingHandler(IBaseHandler *parent) + : m_parent(parent) +{ + m_children.setAutoDelete(TRUE); + m_hasLineNumber=FALSE; + addEndHandler("programlisting",this,&ProgramListingHandler::endProgramListing); + + addStartHandler("linenumber",this,&ProgramListingHandler::startLineNumber); + addStartHandler("codeline",this,&ProgramListingHandler::startCodeLine); +} + +ProgramListingHandler::~ProgramListingHandler() +{ +} + +void ProgramListingHandler::startProgramListing(const QXmlAttributes& /*attrib*/) +{ + m_parent->setDelegate(this); + debug(2,"start programlisting\n"); +} + +void ProgramListingHandler::endProgramListing() +{ + debug(2,"end programlisting\n"); + m_parent->setDelegate(0); +} + +void ProgramListingHandler::startLineNumber(const QXmlAttributes& attrib) +{ + CodeLineHandler *clh = new CodeLineHandler(this); + m_children.append(clh); + m_hasLineNumber=TRUE; + clh->startLineNumber(attrib); +} + +void ProgramListingHandler::startCodeLine(const QXmlAttributes& attrib) +{ + CodeLineHandler *clh = 0; + if (!m_hasLineNumber) + { + clh = new CodeLineHandler(this); + m_children.append(clh); + } + else + { + clh = m_children.getLast(); + } + ASSERT(clh!=0); + clh->startCodeLine(attrib); + m_hasLineNumber=FALSE; +} + +IDocIterator *ProgramListingHandler::codeLines() const +{ + return new ProgramListingIterator(*this); +} + + + +//---------------------------------------------------------------------- +// FormulaHandler +//---------------------------------------------------------------------- + +FormulaHandler::FormulaHandler(IBaseHandler *parent) + : m_parent(parent) +{ + addEndHandler("formula",this,&FormulaHandler::endFormula); +} + +FormulaHandler::~FormulaHandler() +{ +} + +void FormulaHandler::startFormula(const QXmlAttributes& attrib) +{ + m_id = attrib.value("id"); + m_curString=""; + m_parent->setDelegate(this); +} + +void FormulaHandler::endFormula() +{ + m_text = m_curString; + debug(2,"formula id=`%s' text=`%s'\n",m_id.data(),m_text.data()); + m_parent->setDelegate(0); +} + +//---------------------------------------------------------------------- +// AnchorHandler +//---------------------------------------------------------------------- + +AnchorHandler::AnchorHandler(IBaseHandler *parent) + : m_parent(parent) +{ + addEndHandler("anchor",this,&AnchorHandler::endAnchor); +} + +AnchorHandler::~AnchorHandler() +{ +} + +void AnchorHandler::startAnchor(const QXmlAttributes& attrib) +{ + m_id = attrib.value("id"); + m_parent->setDelegate(this); +} + +void AnchorHandler::endAnchor() +{ + debug(2,"anchor id=`%s'\n",m_id.data()); + m_parent->setDelegate(0); +} + +//---------------------------------------------------------------------- +// ImageHandler +//---------------------------------------------------------------------- + +ImageHandler::ImageHandler(IBaseHandler *parent) + : m_parent(parent) +{ + addEndHandler("image",this,&ImageHandler::endImage); +} + +ImageHandler::~ImageHandler() +{ +} + +void ImageHandler::startImage(const QXmlAttributes& attrib) +{ + m_name = attrib.value("name"); + m_curString=""; + m_parent->setDelegate(this); +} + +void ImageHandler::endImage() +{ + m_caption = m_curString; + debug(2,"image name=`%s' caption=`%s'\n",m_name.data(),m_caption.data()); + m_parent->setDelegate(0); +} + +//---------------------------------------------------------------------- +// DotFileHandler +//---------------------------------------------------------------------- + +DotFileHandler::DotFileHandler(IBaseHandler *parent) + : m_parent(parent) +{ + addEndHandler("dotfile",this,&DotFileHandler::endDotFile); +} + +DotFileHandler::~DotFileHandler() +{ +} + +void DotFileHandler::startDotFile(const QXmlAttributes& attrib) +{ + m_name = attrib.value("name"); + m_curString=""; + m_parent->setDelegate(this); +} + +void DotFileHandler::endDotFile() +{ + m_caption = m_curString; + debug(2,"image name=`%s' caption=`%s'\n",m_name.data(),m_caption.data()); + m_parent->setDelegate(0); +} + +//---------------------------------------------------------------------- +// IndexEntryHandler +//---------------------------------------------------------------------- + +IndexEntryHandler::IndexEntryHandler(IBaseHandler *parent) + : m_parent(parent) +{ + addEndHandler("indexentry",this,&IndexEntryHandler::endIndexEntry); + addStartHandler("primaryie",this,&IndexEntryHandler::startPrimaryIE); + addEndHandler("primaryie",this,&IndexEntryHandler::endPrimaryIE); + addStartHandler("secondaryie",this,&IndexEntryHandler::startSecondaryIE); + addEndHandler("secondaryie",this,&IndexEntryHandler::endSecondaryIE); +} + +IndexEntryHandler::~IndexEntryHandler() +{ +} + +void IndexEntryHandler::startIndexEntry(const QXmlAttributes& /*attrib*/) +{ + debug(2,"start index entry\n"); + m_parent->setDelegate(this); +} + +void IndexEntryHandler::endIndexEntry() +{ + debug(2,"index entry primary=`%s' secondary=`%s'\n", + m_primary.data(),m_secondary.data()); + m_parent->setDelegate(0); +} + +void IndexEntryHandler::startPrimaryIE(const QXmlAttributes& /*attrib*/) +{ + m_curString=""; +} + +void IndexEntryHandler::endPrimaryIE() +{ + m_primary = m_curString; +} + +void IndexEntryHandler::startSecondaryIE(const QXmlAttributes& /*attrib*/) +{ + m_curString=""; +} + +void IndexEntryHandler::endSecondaryIE() +{ + m_secondary = m_curString; +} + +//---------------------------------------------------------------------- +// EntryHandler +//---------------------------------------------------------------------- + +EntryHandler::EntryHandler(IBaseHandler *parent) + : m_parent(parent) +{ + m_children.setAutoDelete(TRUE); + addEndHandler("entry",this,&EntryHandler::endEntry); + addStartHandler("para",this,&EntryHandler::startParagraph); +} + +EntryHandler::~EntryHandler() +{ +} + +void EntryHandler::startEntry(const QXmlAttributes&) +{ + m_parent->setDelegate(this); +} + +void EntryHandler::endEntry() +{ + m_parent->setDelegate(0); +} + +void EntryHandler::startParagraph(const QXmlAttributes& attrib) +{ + ParagraphHandler *ph = new ParagraphHandler(this); + ph->startParagraph(attrib); + m_children.append(ph); +} + +IDocIterator *EntryHandler::contents() const +{ + return new EntryIterator(*this); +} + +//---------------------------------------------------------------------- +// RowHandler +//---------------------------------------------------------------------- + +RowHandler::RowHandler(IBaseHandler *parent) + : m_parent(parent) +{ + m_children.setAutoDelete(TRUE); + addEndHandler("row",this,&RowHandler::endRow); + addStartHandler("entry",this,&RowHandler::startEntry); +} + +RowHandler::~RowHandler() +{ +} + +void RowHandler::startRow(const QXmlAttributes&) +{ + m_parent->setDelegate(this); +} + +void RowHandler::endRow() +{ + m_parent->setDelegate(0); +} + +void RowHandler::startEntry(const QXmlAttributes& attrib) +{ + EntryHandler *eh = new EntryHandler(this); + eh->startEntry(attrib); + m_children.append(eh); +} + +IDocIterator *RowHandler::entries() const +{ + return new RowIterator(*this); +} + +//---------------------------------------------------------------------- +// TableHandler +//---------------------------------------------------------------------- + +TableHandler::TableHandler(IBaseHandler *parent) + : m_parent(parent) +{ + m_children.setAutoDelete(TRUE); + addEndHandler("table",this,&TableHandler::endTable); + addStartHandler("row",this,&TableHandler::startRow); + addStartHandler("caption",this,&TableHandler::startCaption); + addEndHandler("caption",this,&TableHandler::endCaption); +} + +TableHandler::~TableHandler() +{ +} + +void TableHandler::startTable(const QXmlAttributes& attrib) +{ + m_parent->setDelegate(this); + m_numColumns = attrib.value("cols").toInt(); + debug(2,"table cols=%d\n",m_numColumns); +} + +void TableHandler::endTable() +{ + m_parent->setDelegate(0); +} + +void TableHandler::startRow(const QXmlAttributes& attrib) +{ + RowHandler *rh = new RowHandler(this); + rh->startRow(attrib); + m_children.append(rh); +} + +void TableHandler::startCaption(const QXmlAttributes& /*attrib*/) +{ + m_curString=""; +} + +void TableHandler::endCaption() +{ + m_caption = m_curString; +} + +IDocIterator *TableHandler::rows() const +{ + return new TableIterator(*this); +} + +//---------------------------------------------------------------------- +// CopyHandler +//---------------------------------------------------------------------- + +CopyHandler::CopyHandler(IBaseHandler *parent) + : m_parent(parent) +{ + m_children.setAutoDelete(TRUE); + + addEndHandler("copydoc",this,&CopyHandler::endCopy); + + addStartHandler("para",this,&CopyHandler::startParagraph); +} + +CopyHandler::~CopyHandler() +{ +} + +void CopyHandler::startCopy(const QXmlAttributes& /*attrib*/) +{ + m_parent->setDelegate(this); + debug(2,"start copy handler\n"); +} + +void CopyHandler::endCopy() +{ + debug(2,"end copy handler\n"); + m_parent->setDelegate(0); +} + +void CopyHandler::startParagraph(const QXmlAttributes& attrib) +{ + ParagraphHandler *parHandler = new ParagraphHandler(this); + parHandler->startParagraph(attrib); + m_children.append(parHandler); +} + +IDocIterator *CopyHandler::contents() const +{ + return new CopyIterator(*this); +} + +//---------------------------------------------------------------------- +// VerbatimHandler +//---------------------------------------------------------------------- + +VerbatimHandler::VerbatimHandler(IBaseHandler *parent) + : m_parent(parent), m_type(IDocVerbatim::Invalid) +{ + addEndHandler("verbatim",this,&VerbatimHandler::endVerbatim); + addEndHandler("latexonly",this,&VerbatimHandler::endVerbatim); + addEndHandler("htmlonly",this,&VerbatimHandler::endVerbatim); +} + +VerbatimHandler::~VerbatimHandler() +{ +} + +void VerbatimHandler::startVerbatim(const QXmlAttributes&,Types type) +{ + m_type = type; + m_parent->setDelegate(this); + m_curString=""; +} + +void VerbatimHandler::endVerbatim() +{ + m_text = m_curString; + m_parent->setDelegate(0); +} + + +//---------------------------------------------------------------------- +// SymbolHandler +//---------------------------------------------------------------------- + +SymbolHandler::SymbolHandler(IBaseHandler *parent,Types type) + : m_parent(parent), m_letter('\0'), m_type(type) +{ + addEndHandler("symbol"); + switch (type) + { + case IDocSymbol::Invalid: m_typeString="invalid"; break; + case IDocSymbol::Umlaut: m_typeString="umlaut"; break; + case IDocSymbol::Acute: m_typeString="acute"; break; + case IDocSymbol::Grave: m_typeString="grave"; break; + case IDocSymbol::Circ: m_typeString="circ"; break; + case IDocSymbol::Tilde: m_typeString="tilde"; break; + case IDocSymbol::Szlig: m_typeString="szlig"; break; + case IDocSymbol::Cedil: m_typeString="cedil"; break; + case IDocSymbol::Ring: m_typeString="ring"; break; + case IDocSymbol::Nbsp: m_typeString="nbsp"; break; + case IDocSymbol::Copy: m_typeString="copy"; break; + } +} + +SymbolHandler::~SymbolHandler() +{ +} + +void SymbolHandler::startSymbol(const QXmlAttributes& attrib) +{ + QString ls = attrib.value("char"); + if (!ls.isEmpty()) m_letter = ls.latin1()[0]; +} + +//---------------------------------------------------------------------- +// ParagraphHandler +//---------------------------------------------------------------------- + +ParagraphHandler::ParagraphHandler(IBaseHandler *parent) + : m_parent(parent) +{ + m_children.setAutoDelete(TRUE); + + m_markupHandler = new MarkupHandler(m_children,m_curString); + + // preformatted + setFallBackHandler(m_markupHandler); + + addEndHandler("para",this,&ParagraphHandler::endParagraph); + + addStartHandler("linebreak",this,&ParagraphHandler::startLineBreak); + addStartHandler("hruler",this,&ParagraphHandler::startHRuler); + addStartHandler("programlisting",this,&ParagraphHandler::startProgramListing); + addStartHandler("verbatim",this,&ParagraphHandler::startVerbatim); + addStartHandler("indexentry",this,&ParagraphHandler::startIndexEntry); + addStartHandler("orderedlist",this,&ParagraphHandler::startOrderedList); + addStartHandler("itemizedlist",this,&ParagraphHandler::startItemizedList); + addStartHandler("simplesect",this,&ParagraphHandler::startSimpleSect); + // TODO: title + addStartHandler("variablelist",this,&ParagraphHandler::startVariableList); + addStartHandler("table",this,&ParagraphHandler::startTable); + // TODO: heading + addStartHandler("image",this,&ParagraphHandler::startImage); + addStartHandler("dotfile",this,&ParagraphHandler::startDotFile); + addStartHandler("toclist",this,&ParagraphHandler::startTocList); + // TODO: language??? + addStartHandler("parameterlist",this,&ParagraphHandler::startParameterList); + // TODO: xrefsect + addStartHandler("copydoc",this,&ParagraphHandler::startCopyDoc); + + addStartHandler("ref",this,&ParagraphHandler::startRef); + addStartHandler("ulink",this,&ParagraphHandler::startULink); + addStartHandler("email",this,&ParagraphHandler::startEMail); + addStartHandler("link",this,&ParagraphHandler::startLink); + addStartHandler("formula",this,&ParagraphHandler::startFormula); + addStartHandler("latexonly",this,&ParagraphHandler::startHtmlOnly); + addStartHandler("htmlonly",this,&ParagraphHandler::startLatexOnly); + addStartHandler("umlaut",this,&ParagraphHandler::startUmlaut); + addStartHandler("acute",this,&ParagraphHandler::startAcute); + addStartHandler("grave",this,&ParagraphHandler::startGrave); + addStartHandler("circ",this,&ParagraphHandler::startCirc); + addStartHandler("tilde",this,&ParagraphHandler::startTilde); + addStartHandler("szlig",this,&ParagraphHandler::startSzlig); + addStartHandler("cedil",this,&ParagraphHandler::startCedil); + addStartHandler("ring",this,&ParagraphHandler::startRing); + addStartHandler("nbsp",this,&ParagraphHandler::startNbsp); + addStartHandler("copy",this,&ParagraphHandler::startCopy); + addStartHandler("anchor",this,&ParagraphHandler::startAnchor); +} + +ParagraphHandler::~ParagraphHandler() +{ + delete m_markupHandler; +} + +void ParagraphHandler::startParagraph(const QXmlAttributes& /*attrib*/) +{ + m_parent->setDelegate(this); + debug(2,"para\n"); +} + +void ParagraphHandler::endParagraph() +{ + addTextNode(); + debug(2,"end para\n"); + m_parent->setDelegate(0); +} + +void ParagraphHandler::startItemizedList(const QXmlAttributes& attrib) +{ + addTextNode(); + ItemizedListHandler *listHandler = new ItemizedListHandler(this); + listHandler->startItemizedList(attrib); + m_children.append(listHandler); +} + +void ParagraphHandler::startOrderedList(const QXmlAttributes& attrib) +{ + addTextNode(); + OrderedListHandler *listHandler = new OrderedListHandler(this); + listHandler->startOrderedList(attrib); + m_children.append(listHandler); +} + +void ParagraphHandler::startParameterList(const QXmlAttributes& attrib) +{ + addTextNode(); + ParameterListHandler *listHandler = new ParameterListHandler(this); + listHandler->startParameterList(attrib); + m_children.append(listHandler); +} + +void ParagraphHandler::startSimpleSect(const QXmlAttributes& attrib) +{ + addTextNode(); + SimpleSectHandler *sectHandler = new SimpleSectHandler(this); + sectHandler->startSimpleSect(attrib); + m_children.append(sectHandler); +} + +void ParagraphHandler::startRef(const QXmlAttributes& attrib) +{ + addTextNode(); + RefHandler *ref = new RefHandler(this); + ref->startRef(attrib); + m_children.append(ref); +} + +void ParagraphHandler::startVariableList(const QXmlAttributes& attrib) +{ + addTextNode(); + VariableListHandler *vl = new VariableListHandler(this); + vl->startVariableList(attrib); + m_children.append(vl); +} + +void ParagraphHandler::startHRuler(const QXmlAttributes& attrib) +{ + addTextNode(); + HRulerHandler *hr = new HRulerHandler(this); + hr->startHRuler(attrib); + m_children.append(hr); +} + +void ParagraphHandler::startLineBreak(const QXmlAttributes& attrib) +{ + addTextNode(); + LineBreakHandler *lb = new LineBreakHandler(this); + lb->startLineBreak(attrib); + m_children.append(lb); +} + +void ParagraphHandler::startULink(const QXmlAttributes& attrib) +{ + addTextNode(); + ULinkHandler *uh = new ULinkHandler(this); + uh->startULink(attrib); + m_children.append(uh); +} + +void ParagraphHandler::startEMail(const QXmlAttributes& attrib) +{ + addTextNode(); + EMailHandler *eh = new EMailHandler(this); + eh->startEMail(attrib); + m_children.append(eh); +} + +void ParagraphHandler::startLink(const QXmlAttributes& attrib) +{ + addTextNode(); + LinkHandler *lh = new LinkHandler(this); + lh->startLink(attrib); + m_children.append(lh); +} + +void ParagraphHandler::startProgramListing(const QXmlAttributes& attrib) +{ + addTextNode(); + ProgramListingHandler *pl = new ProgramListingHandler(this); + pl->startProgramListing(attrib); + m_children.append(pl); +} + +void ParagraphHandler::startFormula(const QXmlAttributes& attrib) +{ + addTextNode(); + FormulaHandler *fh = new FormulaHandler(this); + fh->startFormula(attrib); + m_children.append(fh); +} + +void ParagraphHandler::startImage(const QXmlAttributes& attrib) +{ + addTextNode(); + ImageHandler *ih = new ImageHandler(this); + ih->startImage(attrib); + m_children.append(ih); +} + +void ParagraphHandler::startDotFile(const QXmlAttributes& attrib) +{ + addTextNode(); + DotFileHandler *df = new DotFileHandler(this); + df->startDotFile(attrib); + m_children.append(df); +} + +void ParagraphHandler::startIndexEntry(const QXmlAttributes& attrib) +{ + addTextNode(); + IndexEntryHandler *df = new IndexEntryHandler(this); + df->startIndexEntry(attrib); + m_children.append(df); +} + +void ParagraphHandler::startTable(const QXmlAttributes& attrib) +{ + addTextNode(); + TableHandler *th = new TableHandler(this); + th->startTable(attrib); + m_children.append(th); +} + +void ParagraphHandler::startVerbatim(const QXmlAttributes& attrib) +{ + addTextNode(); + VerbatimHandler *vh = new VerbatimHandler(this); + vh->startVerbatim(attrib,IDocVerbatim::Verbatim); + m_children.append(vh); +} + +void ParagraphHandler::startHtmlOnly(const QXmlAttributes& attrib) +{ + addTextNode(); + VerbatimHandler *vh = new VerbatimHandler(this); + vh->startVerbatim(attrib,IDocVerbatim::HtmlOnly); + m_children.append(vh); +} + +void ParagraphHandler::startLatexOnly(const QXmlAttributes& attrib) +{ + addTextNode(); + VerbatimHandler *vh = new VerbatimHandler(this); + vh->startVerbatim(attrib,IDocVerbatim::LatexOnly); + m_children.append(vh); +} + +void ParagraphHandler::startUmlaut(const QXmlAttributes& attrib) +{ + addTextNode(); + SymbolHandler *sh = new SymbolHandler(this,IDocSymbol::Umlaut); + sh->startSymbol(attrib); + m_children.append(sh); +} + +void ParagraphHandler::startAcute(const QXmlAttributes& attrib) +{ + addTextNode(); + SymbolHandler *sh = new SymbolHandler(this,IDocSymbol::Acute); + sh->startSymbol(attrib); + m_children.append(sh); +} + +void ParagraphHandler::startGrave(const QXmlAttributes& attrib) +{ + addTextNode(); + SymbolHandler *sh = new SymbolHandler(this,IDocSymbol::Grave); + sh->startSymbol(attrib); + m_children.append(sh); +} + +void ParagraphHandler::startCirc(const QXmlAttributes& attrib) +{ + addTextNode(); + SymbolHandler *sh = new SymbolHandler(this,IDocSymbol::Circ); + sh->startSymbol(attrib); + m_children.append(sh); +} + +void ParagraphHandler::startTilde(const QXmlAttributes& attrib) +{ + addTextNode(); + SymbolHandler *sh = new SymbolHandler(this,IDocSymbol::Tilde); + sh->startSymbol(attrib); + m_children.append(sh); +} + +void ParagraphHandler::startSzlig(const QXmlAttributes& attrib) +{ + addTextNode(); + SymbolHandler *sh = new SymbolHandler(this,IDocSymbol::Szlig); + sh->startSymbol(attrib); + m_children.append(sh); +} + +void ParagraphHandler::startCedil(const QXmlAttributes& attrib) +{ + addTextNode(); + SymbolHandler *sh = new SymbolHandler(this,IDocSymbol::Cedil); + sh->startSymbol(attrib); + m_children.append(sh); +} + +void ParagraphHandler::startRing(const QXmlAttributes& attrib) +{ + addTextNode(); + SymbolHandler *sh = new SymbolHandler(this,IDocSymbol::Ring); + sh->startSymbol(attrib); + m_children.append(sh); +} + +void ParagraphHandler::startNbsp(const QXmlAttributes& attrib) +{ + addTextNode(); + SymbolHandler *sh = new SymbolHandler(this,IDocSymbol::Nbsp); + sh->startSymbol(attrib); + m_children.append(sh); +} + +void ParagraphHandler::startCopy(const QXmlAttributes& attrib) +{ + addTextNode(); + SymbolHandler *sh = new SymbolHandler(this,IDocSymbol::Copy); + sh->startSymbol(attrib); + m_children.append(sh); +} + +void ParagraphHandler::startAnchor(const QXmlAttributes& attrib) +{ + addTextNode(); + AnchorHandler *ah = new AnchorHandler(this); + ah->startAnchor(attrib); + m_children.append(ah); +} + +void ParagraphHandler::startCopyDoc(const QXmlAttributes& attrib) +{ + addTextNode(); + CopyHandler *ch = new CopyHandler(this); + ch->startCopy(attrib); + m_children.append(ch); +} + +void ParagraphHandler::startTocList(const QXmlAttributes& attrib) +{ + addTextNode(); + TocListHandler *th = new TocListHandler(this); + th->startTocList(attrib); + m_children.append(th); +} + +void ParagraphHandler::addTextNode() +{ + if (!m_curString.isEmpty()) + { + m_children.append( + new TextNode( + m_curString, + m_markupHandler->markup(), + m_markupHandler->headingLevel() + ) + ); + debug(2,"addTextNode() text=\"%s\" markup=%x headingLevel=%d\n", + m_curString.data(),m_markupHandler->markup(),m_markupHandler->headingLevel()); + m_curString=""; + } +} + +IDocIterator *ParagraphHandler::contents() const +{ + return new ParagraphIterator(*this); +} + +//---------------------------------------------------------------------- +// DocSectionHandler +//---------------------------------------------------------------------- + +DocSectionHandler::DocSectionHandler(IBaseHandler *parent,int level) + : m_parent(parent), m_internal(0), m_level(level), m_title(0) +{ + QString sectionKey; + m_paragraphs.setAutoDelete(TRUE); + m_subsections.setAutoDelete(TRUE); + addStartHandler("title",this,&DocSectionHandler::startTitle); + addStartHandler("para",this,&DocSectionHandler::startParagraph); + if (level<6) + { + sectionKey.sprintf("sect%d",level+1); + addStartHandler(sectionKey,this,&DocSectionHandler::startSubSection); + } + addStartHandler("internal",this,&DocSectionHandler::startInternal); + sectionKey.sprintf("sect%d",level); + addEndHandler(sectionKey,this,&DocSectionHandler::endDocSection); +} + +DocSectionHandler::~DocSectionHandler() +{ +} + +void DocSectionHandler::startDocSection(const QXmlAttributes& attrib) +{ + m_parent->setDelegate(this); + debug(2,"Start docsection\n"); + m_id = attrib.value("id"); +} + +void DocSectionHandler::endDocSection() +{ + m_parent->setDelegate(0); + debug(2,"End docsection\n"); +} + +void DocSectionHandler::startSubSection(const QXmlAttributes& attrib) +{ + DocSectionHandler *secHandler = new DocSectionHandler(this,m_level+1); + secHandler->startDocSection(attrib); + m_subsections.append(secHandler); +} + +void DocSectionHandler::startParagraph(const QXmlAttributes& attrib) +{ + ParagraphHandler *parHandler = new ParagraphHandler(this); + parHandler->startParagraph(attrib); + m_paragraphs.append(parHandler); +} + +void DocSectionHandler::startInternal(const QXmlAttributes& attrib) +{ + m_internal = new DocInternalHandler(this,m_level); + m_internal->startInternal(attrib); +} + +void DocSectionHandler::startTitle(const QXmlAttributes& attrib) +{ + m_title = new TitleHandler(this); + m_title->startTitle(attrib); +} + +IDocIterator *DocSectionHandler::paragraphs() const +{ + return new DocSectionParaIterator(*this); +} + +IDocIterator *DocSectionHandler::subSections() const +{ + return new DocSectionSubIterator(*this); +} + +IDocInternal *DocSectionHandler::internal() const +{ + return m_internal; +} + +//---------------------------------------------------------------------- +// DocInternal +//---------------------------------------------------------------------- + +DocInternalHandler::DocInternalHandler(IBaseHandler *parent,int level) + : m_parent(parent), m_level(level) +{ + m_paragraphs.setAutoDelete(TRUE); + m_subsections.setAutoDelete(TRUE); + addStartHandler("para",this,&DocInternalHandler::startParagraph); + QString sectionKey; + sectionKey.sprintf("sect%d",level+1); + addStartHandler(sectionKey,this,&DocInternalHandler::startSubSection); + addEndHandler("internal",this,&DocInternalHandler::endInternal); +} + +DocInternalHandler::~DocInternalHandler() +{ +} + +void DocInternalHandler::startInternal(const QXmlAttributes&) +{ + m_parent->setDelegate(this); + debug(2,"Start internal\n"); +} + +void DocInternalHandler::endInternal() +{ + m_parent->setDelegate(0); + debug(2,"End internal\n"); +} + +void DocInternalHandler::startSubSection(const QXmlAttributes& attrib) +{ + DocSectionHandler *secHandler = new DocSectionHandler(this,m_level+1); + secHandler->startDocSection(attrib); + m_subsections.append(secHandler); +} + +void DocInternalHandler::startParagraph(const QXmlAttributes& attrib) +{ + ParagraphHandler *parHandler = new ParagraphHandler(this); + parHandler->startParagraph(attrib); + m_paragraphs.append(parHandler); +} + +IDocIterator *DocInternalHandler::paragraphs() const +{ + return new DocInternalParaIterator(*this); +} + +IDocIterator *DocInternalHandler::subSections() const +{ + return new DocInternalSubIterator(*this); +} + + +//---------------------------------------------------------------------- +// DocHandler +//---------------------------------------------------------------------- + +DocHandler::DocHandler(IBaseHandler *parent) : m_parent(parent) +{ + m_children.setAutoDelete(TRUE); + + addEndHandler("briefdescription",this,&DocHandler::endDoc); + addEndHandler("detaileddescription",this,&DocHandler::endDoc); + addEndHandler("inbodydescription",this,&DocHandler::endDoc); + //addEndHandler("internal"); // TODO: implement this as a section + addStartHandler("internal",this,&DocHandler::startInternal); + + addStartHandler("para",this,&DocHandler::startParagraph); + addStartHandler("sect1",this,&DocHandler::startSect1); + addStartHandler("title",this,&DocHandler::startTitle); + //addStartHandler("internal"); +} + +DocHandler::~DocHandler() +{ +} + +void DocHandler::startDoc(const QXmlAttributes& /*attrib*/) +{ + m_parent->setDelegate(this); + debug(2,"start dochandler\n"); +} + +void DocHandler::endDoc() +{ + debug(2,"end dochandler\n"); + m_parent->setDelegate(0); +} + +void DocHandler::startParagraph(const QXmlAttributes& attrib) +{ + ParagraphHandler *parHandler = new ParagraphHandler(this); + parHandler->startParagraph(attrib); + m_children.append(parHandler); +} + +void DocHandler::startSect1(const QXmlAttributes& attrib) +{ + DocSectionHandler *secHandler = new DocSectionHandler(this,1); + secHandler->startDocSection(attrib); + m_children.append(secHandler); +} + +void DocHandler::startTitle(const QXmlAttributes& attrib) +{ + TitleHandler *titleHandler = new TitleHandler(this); + titleHandler->startTitle(attrib); + m_children.append(titleHandler); +} + +void DocHandler::startInternal(const QXmlAttributes& attrib) +{ + m_internal = new DocInternalHandler(this,1); + m_internal->startInternal(attrib); +} + +IDocIterator *DocHandler::contents() const +{ + return new DocIterator(*this); +} + +IDocInternal *DocHandler::internal() const +{ + return m_internal; +} + diff --git a/trunk/addon/doxmlparser/src/dochandler.h b/trunk/addon/doxmlparser/src/dochandler.h new file mode 100644 index 0000000..829d977 --- /dev/null +++ b/trunk/addon/doxmlparser/src/dochandler.h @@ -0,0 +1,1352 @@ +/****************************************************************************** + * + * $Id$ + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#ifndef _DOCHANDLER_H +#define _DOCHANDLER_H + +#include +#include +#include + +#include +#include "stringimpl.h" +#include "basehandler.h" +#include "baseiterator.h" + +class ParagraphHandler; +class DocInternalHandler; +class LinkedTextImpl; +class LinkedTextHandler; + +//----------------------------------------------------------------------------- + +class DocImpl : public IDoc { public: virtual ~DocImpl() {} }; + +#define DEFINE_CLS_IMPL(cls) \ + class cls##Impl : public I##cls, public DocImpl { public: virtual ~cls##Impl() {} } + +DEFINE_CLS_IMPL(DocMarkup); +DEFINE_CLS_IMPL(DocPara); +DEFINE_CLS_IMPL(DocText); +DEFINE_CLS_IMPL(DocMarkupModifier); +DEFINE_CLS_IMPL(DocItemizedList); +DEFINE_CLS_IMPL(DocOrderedList); +DEFINE_CLS_IMPL(DocListItem); +DEFINE_CLS_IMPL(DocParameterList); +DEFINE_CLS_IMPL(DocParameterItem); +DEFINE_CLS_IMPL(DocParameter); +DEFINE_CLS_IMPL(DocTitle); +DEFINE_CLS_IMPL(DocSimpleSect); +DEFINE_CLS_IMPL(DocRef); +DEFINE_CLS_IMPL(DocVariableList); +DEFINE_CLS_IMPL(DocVariableListEntry); +DEFINE_CLS_IMPL(DocHRuler); +DEFINE_CLS_IMPL(DocLineBreak); +DEFINE_CLS_IMPL(DocULink); +DEFINE_CLS_IMPL(DocEMail); +DEFINE_CLS_IMPL(DocLink); +DEFINE_CLS_IMPL(DocProgramListing); +DEFINE_CLS_IMPL(DocCodeLine); +DEFINE_CLS_IMPL(DocHighlight); +DEFINE_CLS_IMPL(DocFormula); +DEFINE_CLS_IMPL(DocImage); +DEFINE_CLS_IMPL(DocDotFile); +DEFINE_CLS_IMPL(DocIndexEntry); +DEFINE_CLS_IMPL(DocTable); +DEFINE_CLS_IMPL(DocRow); +DEFINE_CLS_IMPL(DocEntry); +DEFINE_CLS_IMPL(DocSection); +DEFINE_CLS_IMPL(DocVerbatim); +DEFINE_CLS_IMPL(DocCopy); +DEFINE_CLS_IMPL(DocTocList); +DEFINE_CLS_IMPL(DocTocItem); +DEFINE_CLS_IMPL(DocAnchor); +DEFINE_CLS_IMPL(DocSymbol); +DEFINE_CLS_IMPL(DocInternal); +DEFINE_CLS_IMPL(DocRoot); + +//----------------------------------------------------------------------------- + + +/*! \brief Node representing a piece of text. + * + */ +class TextNode : public DocTextImpl +{ + public: + TextNode(const QString &t,int markup,int level) + : m_text(t), m_markup(markup), m_headingLevel(level) {} + virtual ~TextNode() {} + + // IDocText + virtual Kind kind() const { return DocImpl::Text; } + virtual const IString *text() const { return &m_text; } + virtual int markup() const { return m_markup; } + virtual int headingLevel() const { return m_headingLevel; } + + private: + StringImpl m_text; + int m_markup; + int m_headingLevel; +}; + +//----------------------------------------------------------------------------- + +/*! \brief Node representing a change in the markup style. + * + */ +class MarkupModifierNode : public DocMarkupModifierImpl +{ + public: + MarkupModifierNode(int markup,bool enabled,int level=0) + : m_markup(markup), m_enabled(enabled), m_headingLevel(level) {} + virtual ~MarkupModifierNode() {} + + // IDocMarkupModifier + virtual Kind kind() const { return DocImpl::MarkupModifier; } + virtual bool enabled() const { return m_enabled; } + virtual int markup() const { return m_markup; } + virtual int headingLevel() const { return m_headingLevel; } + + private: + int m_markup; + bool m_enabled; + int m_headingLevel; +}; + + +//----------------------------------------------------------------------------- + +/*! \brief Handles markup commands in the XML input. + * + */ +class MarkupHandler : public BaseFallBackHandler +{ + public: + MarkupHandler(QList &children,QString &curString); + virtual ~MarkupHandler(); + int markup() const { return m_curMarkup; } + int headingLevel() const { return m_headingLevel; } + + virtual void startBold(const QXmlAttributes &attrib); + virtual void endBold(); + virtual void startEmphasis(const QXmlAttributes &attrib); + virtual void endEmphasis(); + virtual void startComputerOutput(const QXmlAttributes &attrib); + virtual void endComputerOutput(); + virtual void startCenter(const QXmlAttributes &attrib); + virtual void endCenter(); + virtual void startSmallFont(const QXmlAttributes &attrib); + virtual void endSmallFont(); + virtual void startSubscript(const QXmlAttributes &attrib); + virtual void endSubscript(); + virtual void startSuperscript(const QXmlAttributes &attrib); + virtual void endSuperscript(); + virtual void startPreformatted(const QXmlAttributes &attrib); + virtual void endPreformatted(); + virtual void startHeading1(const QXmlAttributes &attrib); + virtual void endHeading1(); + virtual void startHeading2(const QXmlAttributes &attrib); + virtual void endHeading2(); + virtual void startHeading3(const QXmlAttributes &attrib); + virtual void endHeading3(); + virtual void startHeading4(const QXmlAttributes &attrib); + virtual void endHeading4(); + virtual void startHeading5(const QXmlAttributes &attrib); + virtual void endHeading5(); + virtual void startHeading6(const QXmlAttributes &attrib); + virtual void endHeading6(); + + + private: + void addTextNode(); + + QList &m_children; + QString &m_curString; + int m_curMarkup; + int m_headingLevel; +}; + +//----------------------------------------------------------------------------- + +/*! \brief Node representing a paragraph of text and commands. + * + */ +// children: itemizedlist, orderedlist, parameterlist, simplesect, ref, +// variablelist, hruler, linebreak, ulink, email, link +// programlisting, formula, image, dotfile, indexentry, +// table +// +// children handled by MarkupHandler: +// bold, computeroutput, emphasis, center, +// small, subscript, superscript. +// +class ParagraphHandler : public DocParaImpl, + public BaseHandler +{ + friend class ParagraphIterator; + + public: + virtual void startParagraph(const QXmlAttributes& attrib); + virtual void endParagraph(); + virtual void startItemizedList(const QXmlAttributes& attrib); + virtual void startOrderedList(const QXmlAttributes& attrib); + virtual void startParameterList(const QXmlAttributes& attrib); + virtual void startSimpleSect(const QXmlAttributes& attrib); + virtual void startRef(const QXmlAttributes& attrib); + virtual void startVariableList(const QXmlAttributes& attrib); + virtual void startHRuler(const QXmlAttributes& attrib); + virtual void startLineBreak(const QXmlAttributes& attrib); + virtual void startULink(const QXmlAttributes& attrib); + virtual void startEMail(const QXmlAttributes& attrib); + virtual void startLink(const QXmlAttributes& attrib); + virtual void startProgramListing(const QXmlAttributes& attrib); + virtual void startFormula(const QXmlAttributes& attrib); + virtual void startImage(const QXmlAttributes& attrib); + virtual void startDotFile(const QXmlAttributes& attrib); + virtual void startIndexEntry(const QXmlAttributes& attrib); + virtual void startTable(const QXmlAttributes& attrib); + virtual void startVerbatim(const QXmlAttributes& attrib); + virtual void startHtmlOnly(const QXmlAttributes& attrib); + virtual void startLatexOnly(const QXmlAttributes& attrib); + virtual void startUmlaut(const QXmlAttributes& attrib); + virtual void startAcute(const QXmlAttributes& attrib); + virtual void startGrave(const QXmlAttributes& attrib); + virtual void startCirc(const QXmlAttributes& attrib); + virtual void startTilde(const QXmlAttributes& attrib); + virtual void startSzlig(const QXmlAttributes& attrib); + virtual void startCedil(const QXmlAttributes& attrib); + virtual void startRing(const QXmlAttributes& attrib); + virtual void startNbsp(const QXmlAttributes& attrib); + virtual void startCopy(const QXmlAttributes& attrib); + virtual void startAnchor(const QXmlAttributes& attrib); + virtual void startCopyDoc(const QXmlAttributes& attrib); + virtual void startTocList(const QXmlAttributes& attrib); + + ParagraphHandler(IBaseHandler *parent); + virtual ~ParagraphHandler(); + + // IDocPara + virtual Kind kind() const { return DocImpl::Para; } + virtual IDocIterator *contents() const; + + private: + void addTextNode(); + IBaseHandler *m_parent; + QList m_children; + MarkupHandler *m_markupHandler; +}; + +class ParagraphIterator : public BaseIteratorVia +{ + public: + ParagraphIterator(const ParagraphHandler &handler) : + BaseIteratorVia(handler.m_children) {} +}; + +//----------------------------------------------------------------------------- + +/*! \brief Node representing a list item. + * + */ +class ListItemHandler : public DocListItemImpl, public BaseHandler +{ + friend class ListItemIterator; + public: + ListItemHandler(IBaseHandler *parent); + virtual ~ListItemHandler(); + virtual void startListItem(const QXmlAttributes& attrib); + virtual void endListItem(); + virtual void startParagraph(const QXmlAttributes& attrib); + + // IDocItem + virtual Kind kind() const { return DocImpl::ListItem; } + virtual IDocIterator *contents() const; + + private: + IBaseHandler *m_parent; + QList m_children; +}; + +class ListItemIterator : public BaseIteratorVia +{ + public: + ListItemIterator(const ListItemHandler &handler) : + BaseIteratorVia(handler.m_children) {} +}; + + +//----------------------------------------------------------------------------- + +/*! \brief Node representing list of items. + * + */ +class OrderedListHandler : public DocOrderedListImpl, public BaseHandler +{ + friend class OrderedListIterator; + public: + OrderedListHandler(IBaseHandler *parent); + virtual ~OrderedListHandler(); + virtual void startOrderedList(const QXmlAttributes& attrib); + virtual void endOrderedList(); + virtual void startOrderedListItem(const QXmlAttributes& attrib); + + // IDocOrderedList + virtual Kind kind() const { return DocImpl::OrderedList; } + virtual IDocIterator *elements() const; + + private: + IBaseHandler *m_parent; + QList m_children; +}; + +class OrderedListIterator : public BaseIteratorVia +{ + public: + OrderedListIterator(const OrderedListHandler &handler) : + BaseIteratorVia(handler.m_children) {} +}; + +//----------------------------------------------------------------------------- + +/*! \brief Node representing table of contents list. + * + */ +class TocListHandler : public DocTocListImpl, public BaseHandler +{ + friend class TocListIterator; + public: + TocListHandler(IBaseHandler *parent); + virtual ~TocListHandler(); + virtual void startTocList(const QXmlAttributes& attrib); + virtual void endTocList(); + virtual void startTocItem(const QXmlAttributes& attrib); + + // IDocTocList + virtual Kind kind() const { return DocImpl::TocList; } + virtual IDocIterator *elements() const; + + private: + IBaseHandler *m_parent; + QList m_children; +}; + +class TocListIterator : public BaseIteratorVia +{ + public: + TocListIterator(const TocListHandler &handler) : + BaseIteratorVia(handler.m_children) {} +}; + +//----------------------------------------------------------------------------- + +/*! \brief Node representing a table of contents item. + * + */ +class TocItemHandler : public DocTocItemImpl, public BaseHandler +{ + friend class TocItemIterator; + public: + TocItemHandler(IBaseHandler *parent); + virtual ~TocItemHandler(); + virtual void startTocItem(const QXmlAttributes& attrib); + virtual void endTocItem(); + + // IDocItem + virtual Kind kind() const { return DocImpl::TocItem; } + virtual const IString *id() const { return &m_id; } + virtual const IString *title() const { return &m_title; } + + private: + IBaseHandler *m_parent; + StringImpl m_id; + StringImpl m_title; +}; + +//----------------------------------------------------------------------------- + +/*! \brief Node representing list of items. + * + */ +class ItemizedListHandler : public DocItemizedListImpl, public BaseHandler +{ + friend class ItemizedListIterator; + public: + ItemizedListHandler(IBaseHandler *parent); + virtual ~ItemizedListHandler(); + virtual void startItemizedList(const QXmlAttributes& attrib); + virtual void endItemizedList(); + virtual void startItemizedListItem(const QXmlAttributes& attrib); + + // IDocItemizedList + virtual Kind kind() const { return DocImpl::ItemizedList; } + virtual IDocIterator *elements() const; + + private: + IBaseHandler *m_parent; + QList m_children; +}; + +class ItemizedListIterator : public BaseIteratorVia +{ + public: + ItemizedListIterator(const ItemizedListHandler &handler) : + BaseIteratorVia(handler.m_children) {} +}; + + +//----------------------------------------------------------------------------- +/*! \brief Node representing a parameter. + * + */ +class ParameterHandler : public DocParameterImpl, + public BaseHandler +{ + public: + ParameterHandler(IBaseHandler *parent); + virtual ~ParameterHandler(); + virtual void startParameterName(const QXmlAttributes& attrib); + virtual void endParameterName(); + + // IDocParameter + virtual Kind kind() const { return DocImpl::Parameter; } + virtual const IString *name() const { return &m_name; } + + private: + IBaseHandler *m_parent; + StringImpl m_name; +}; + +//----------------------------------------------------------------------------- + +/* \brief Node representing a list of param names with a single description. + * + */ +class ParameterItemHandler : public DocParameterItemImpl, + public BaseHandler +{ + friend class ParameterItemIterator; + public: + ParameterItemHandler(IBaseHandler *parent); + virtual ~ParameterItemHandler(); + virtual void startParameterItem(const QXmlAttributes& attrib); + virtual void endParameterItem(); + virtual void startParameterName(const QXmlAttributes& attrib); + virtual void startParagraph(const QXmlAttributes& attrib); + + // IDocParameterItem + virtual Kind kind() const { return DocImpl::ParameterItem; } + virtual IDocIterator *paramNames() const; + virtual IDocPara *description() const { return m_description; } + + private: + IBaseHandler *m_parent; + QList m_parameters; + ParagraphHandler *m_description; +}; + +class ParameterItemIterator : public BaseIteratorVia +{ + public: + ParameterItemIterator(const ParameterItemHandler &handler) : + BaseIteratorVia(handler.m_parameters) {} +}; + +//----------------------------------------------------------------------------- + +/* \brief Node representing a parameter section. + * + */ +class ParameterListHandler : public DocParameterListImpl, + public BaseHandler +{ + friend class ParameterListIterator; + public: + ParameterListHandler(IBaseHandler *parent); + virtual ~ParameterListHandler(); + virtual void startParameterList(const QXmlAttributes& attrib); + virtual void endParameterList(); + virtual void startParameterItem(const QXmlAttributes& attrib); + + // IDocParameterList + virtual Kind kind() const { return DocImpl::ParameterList; } + virtual Types sectType() const { return m_type; } + virtual IDocIterator *params() const; + + private: + IBaseHandler *m_parent; + QList m_paramItems; + Types m_type; +}; + +class ParameterListIterator : public BaseIteratorVia +{ + public: + ParameterListIterator(const ParameterListHandler &handler) : + BaseIteratorVia(handler.m_paramItems) {} +}; + +//----------------------------------------------------------------------------- + +/* \brief Node representing a horizontal ruler + * + */ +class LineBreakHandler : public DocLineBreakImpl, public BaseHandler +{ + public: + LineBreakHandler(IBaseHandler *parent); + virtual ~LineBreakHandler(); + + void startLineBreak(const QXmlAttributes& attrib); + void endLineBreak(); + + // IDocLineBreak + virtual Kind kind() const { return DocImpl::LineBreak; } + + private: + IBaseHandler *m_parent; +}; + +//----------------------------------------------------------------------------- + +/* \brief Node representing a link to section + * + */ +class LinkHandler : public DocLinkImpl, public BaseHandler +{ + public: + LinkHandler(IBaseHandler *parent); + virtual ~LinkHandler(); + + void startLink(const QXmlAttributes& attrib); + void endLink(); + + // IDocLink + virtual Kind kind() const { return DocImpl::Link; } + virtual const IString *refId() const { return &m_ref; } + virtual const IString *text() const { return &m_text; } + + private: + IBaseHandler *m_parent; + StringImpl m_ref; + StringImpl m_text; +}; + + +//----------------------------------------------------------------------------- + +/* \brief Node representing a link to an email address + * + */ +class EMailHandler : public DocEMailImpl, public BaseHandler +{ + public: + EMailHandler(IBaseHandler *parent); + virtual ~EMailHandler(); + + void startEMail(const QXmlAttributes& attrib); + void endEMail(); + + // IDocEMail + virtual Kind kind() const { return DocImpl::EMail; } + virtual const IString *address() const { return &m_address; } + + private: + IBaseHandler *m_parent; + StringImpl m_address; +}; + + +//----------------------------------------------------------------------------- + +/* \brief Node representing a link to an URL + * + */ +class ULinkHandler : public DocULinkImpl, public BaseHandler +{ + public: + ULinkHandler(IBaseHandler *parent); + virtual ~ULinkHandler(); + + void startULink(const QXmlAttributes& attrib); + void endULink(); + + // IDocULink + virtual Kind kind() const { return DocImpl::ULink; } + virtual const IString * url() const { return &m_url; } + virtual const IString * text() const { return &m_text; } + + private: + IBaseHandler *m_parent; + StringImpl m_url; + StringImpl m_text; +}; + +//----------------------------------------------------------------------------- + +/* \brief Node representing a horizontal ruler + * + */ +class HRulerHandler : public DocHRulerImpl, public BaseHandler +{ + public: + HRulerHandler(IBaseHandler *parent); + virtual ~HRulerHandler(); + + void startHRuler(const QXmlAttributes& attrib); + void endHRuler(); + + // IDocHRuler + virtual Kind kind() const { return DocImpl::HRuler; } + + private: + IBaseHandler *m_parent; +}; + +//----------------------------------------------------------------------------- + +/* \brief Node representing a reference to another item + * + */ +class RefHandler : public DocRefImpl, public BaseHandler +{ + public: + RefHandler(IBaseHandler *parent); + virtual ~RefHandler(); + void startRef(const QXmlAttributes& attrib); + void endRef(); + + // IDocRef + virtual Kind kind() const { return DocImpl::Ref; } + virtual const IString *refId() const { return &m_refId; } + virtual TargetKind targetKind() const { return m_targetKind; } + virtual const IString *external() const { return &m_extId; } + virtual const IString *text() const { return &m_linkText; } + + private: + IBaseHandler *m_parent; + StringImpl m_refId; + StringImpl m_extId; + StringImpl m_linkText; + TargetKind m_targetKind; +}; + +//----------------------------------------------------------------------------- + +/* \brief Node representing the title of a section + * + */ +// children: text, ref +// children handled by MarkupHandler: +// bold, computeroutput, emphasis, center, +// small, subscript, superscript. +class TitleHandler : public DocTitleImpl, public BaseHandler +{ + friend class TitleIterator; + public: + TitleHandler(IBaseHandler *parent); + virtual ~TitleHandler(); + virtual void startTitle(const QXmlAttributes& attrib); + virtual void endTitle(); + virtual void startRef(const QXmlAttributes& attrib); + void addTextNode(); + + // IDocTitle + virtual Kind kind() const { return DocImpl::Title; } + virtual IDocIterator *title() const; + + private: + IBaseHandler *m_parent; + QList m_children; + MarkupHandler *m_markupHandler; +}; + +class TitleIterator : public BaseIteratorVia +{ + public: + TitleIterator(const TitleHandler &handler) : + BaseIteratorVia(handler.m_children) {} +}; + +//----------------------------------------------------------------------------- + +/* \brief Node representing a simple section with an unnumbered header. + * + */ +// children: title, para +class SimpleSectHandler : public DocSimpleSectImpl, + public BaseHandler +{ + public: + SimpleSectHandler(IBaseHandler *parent); + virtual ~SimpleSectHandler(); + virtual void startSimpleSect(const QXmlAttributes& attrib); + virtual void endSimpleSect(); + virtual void startTitle(const QXmlAttributes& attrib); + virtual void startParagraph(const QXmlAttributes& attrib); + + // IDocSimpleSect + virtual Kind kind() const { return DocImpl::SimpleSect; } + virtual Types type() const { return m_type; } + virtual const IString *typeString() const { return &m_typeString; } + virtual IDocTitle *title() const { return m_title; } + virtual IDocPara *description() const { return m_paragraph; } + + private: + IBaseHandler *m_parent; + ParagraphHandler *m_paragraph; + Types m_type; + StringImpl m_typeString; + TitleHandler *m_title; +}; + +//----------------------------------------------------------------------------- + +/* \brief Node representing an named item of a VariableList. + * + */ +class VariableListEntryHandler : public DocVariableListEntryImpl, + public BaseHandler +{ + public: + virtual void startVarListEntry(const QXmlAttributes& attrib); + virtual void endVarListEntry(); + virtual void startListItem(const QXmlAttributes& attrib); + virtual void endListItem(); + virtual void startTerm(const QXmlAttributes& attrib); + virtual void endTerm(); + virtual void startParagraph(const QXmlAttributes& attrib); + + VariableListEntryHandler(IBaseHandler *parent); + virtual ~VariableListEntryHandler(); + + // IDocVariableListEntry + virtual Kind kind() const { return DocImpl::VariableListEntry; } + virtual ILinkedTextIterator *term() const; + virtual IDocPara *description() const { return m_description; } + + private: + IBaseHandler* m_parent; + QList m_term; + ParagraphHandler* m_description; + LinkedTextHandler* m_linkedTextHandler; +}; + +//----------------------------------------------------------------------------- + +/*! \brief Node representing a list of named items. + * + */ +// children: varlistentry, listitem +class VariableListHandler : public DocVariableListImpl, + public BaseHandler +{ + friend class VariableListIterator; + + public: + virtual void startVariableList(const QXmlAttributes& attrib); + virtual void endVariableList(); + virtual void startVarListEntry(const QXmlAttributes& attrib); + virtual void startListItem(const QXmlAttributes& attrib); + + VariableListHandler(IBaseHandler *parent); + virtual ~VariableListHandler(); + + // IDocVariableList + virtual Kind kind() const { return DocImpl::VariableList; } + virtual IDocIterator *entries() const; + + private: + IBaseHandler *m_parent; + QList m_entries; + VariableListEntryHandler *m_curEntry; +}; + +class VariableListIterator : public BaseIteratorVia +{ + public: + VariableListIterator(const VariableListHandler &handler) : + BaseIteratorVia(handler.m_entries) {} +}; + +//----------------------------------------------------------------------------- + +/*! \brief Node representing a highlighted text fragment. + * + */ +// children: ref +class HighlightHandler : public DocHighlightImpl, public BaseHandler +{ + friend class HighlightIterator; + public: + HighlightHandler(IBaseHandler *parent); + virtual ~HighlightHandler(); + void startHighlight(const QXmlAttributes& attrib); + void endHighlight(); + virtual void startRef(const QXmlAttributes&); + virtual void startSpace(const QXmlAttributes&); + + // IDocHighlight + virtual Kind kind() const { return DocImpl::Highlight; } + virtual HighlightKind highlightKind() const { return m_hl; } + virtual IDocIterator *codeElements() const; + + private: + void addTextNode(); + + IBaseHandler *m_parent; + HighlightKind m_hl; + QString m_hlString; + QList m_children; +}; + +class HighlightIterator : public BaseIteratorVia +{ + public: + HighlightIterator(const HighlightHandler &handler) : + BaseIteratorVia(handler.m_children) {} +}; + +//----------------------------------------------------------------------------- + +/*! \brief Node representing a line of code. + * + */ +// children: linenumber, highlight, anchor, ref +class CodeLineHandler : public DocCodeLineImpl, public BaseHandler +{ + friend class CodeLineIterator; + public: + + virtual void startCodeLine(const QXmlAttributes&); + virtual void endCodeLine(); + virtual void startLineNumber(const QXmlAttributes&); + virtual void endLineNumber(); + virtual void startHighlight(const QXmlAttributes&); + virtual void startRef(const QXmlAttributes&); + + CodeLineHandler(IBaseHandler *parent); + virtual ~CodeLineHandler(); + + // IDocCodeLine + virtual Kind kind() const { return DocImpl::CodeLine; } + virtual int lineNumber() const { return m_lineNumber; } + virtual const IString *refId() const { return &m_refId; } + virtual IDocIterator *codeElements() const; + + private: + void addTextNode(); + + IBaseHandler *m_parent; + int m_lineNumber; + StringImpl m_refId; + QList m_children; +}; + +class CodeLineIterator : public BaseIteratorVia +{ + public: + CodeLineIterator(const CodeLineHandler &handler) : + BaseIteratorVia(handler.m_children) {} +}; + +//----------------------------------------------------------------------------- + +/*! \brief Node representing a program listing + * + */ +// children: codeline, linenumber +class ProgramListingHandler : public DocProgramListingImpl, public BaseHandler +{ + friend class ProgramListingIterator; + public: + virtual void startProgramListing(const QXmlAttributes& attrib); + virtual void endProgramListing(); + virtual void startCodeLine(const QXmlAttributes&); + virtual void startLineNumber(const QXmlAttributes&); + + ProgramListingHandler(IBaseHandler *parent); + virtual ~ProgramListingHandler(); + + // IDocProgramListing + virtual Kind kind() const { return DocImpl::ProgramListing; } + virtual IDocIterator *codeLines() const; + + private: + IBaseHandler *m_parent; + QList m_children; + bool m_hasLineNumber; +}; + +//----------------------------------------------------------------------------- + +class ProgramListingIterator : public BaseIteratorVia +{ + public: + ProgramListingIterator(const ProgramListingHandler &handler) : + BaseIteratorVia(handler.m_children) {} +}; + +//----------------------------------------------------------------------------- + +/*! \brief Node representing a formula. + * + */ +// children: - +class FormulaHandler : public DocFormulaImpl, public BaseHandler +{ + public: + FormulaHandler(IBaseHandler *parent); + virtual ~FormulaHandler(); + void startFormula(const QXmlAttributes& attrib); + void endFormula(); + + // IDocFormula + virtual Kind kind() const { return DocImpl::Formula; } + virtual const IString *id() const { return &m_id; } + virtual const IString *text() const { return &m_text; } + + private: + IBaseHandler *m_parent; + StringImpl m_id; + StringImpl m_text; +}; + +//----------------------------------------------------------------------------- + +/*! \brief Node representing an image. + * + */ +// children: - +class ImageHandler : public DocImageImpl, public BaseHandler +{ + public: + ImageHandler(IBaseHandler *parent); + virtual ~ImageHandler(); + void startImage(const QXmlAttributes& attrib); + void endImage(); + + // IDocImage + virtual Kind kind() const { return DocImpl::Image; } + virtual const IString *name() const { return &m_name; } + virtual const IString *caption() const { return &m_caption; } + + private: + IBaseHandler *m_parent; + StringImpl m_name; + StringImpl m_caption; +}; + + +//----------------------------------------------------------------------------- +/*! \brief Node representing an anchor. + * + */ +// children: - +class AnchorHandler : public DocAnchorImpl, public BaseHandler +{ + public: + AnchorHandler(IBaseHandler *parent); + virtual ~AnchorHandler(); + void startAnchor(const QXmlAttributes& attrib); + void endAnchor(); + + // IDocAnchor + virtual Kind kind() const { return DocImpl::Anchor; } + virtual const IString *id() const { return &m_id; } + + private: + IBaseHandler *m_parent; + StringImpl m_id; +}; + +//----------------------------------------------------------------------------- + +/*! \brief Node representing a dot file. + * + */ +// children: - +class DotFileHandler : public DocDotFileImpl, public BaseHandler +{ + public: + DotFileHandler(IBaseHandler *parent); + virtual ~DotFileHandler(); + void startDotFile(const QXmlAttributes& attrib); + void endDotFile(); + + // IDocDotFile + virtual Kind kind() const { return DocImpl::DotFile; } + virtual const IString *name() const { return &m_name; } + virtual const IString *caption() const { return &m_caption; } + + private: + IBaseHandler *m_parent; + StringImpl m_name; + StringImpl m_caption; +}; + +//----------------------------------------------------------------------------- + +/*! \brief Node representing an entry in the index. + * + */ +// children: - +class IndexEntryHandler : public DocIndexEntryImpl, public BaseHandler +{ + public: + IndexEntryHandler(IBaseHandler *parent); + virtual ~IndexEntryHandler(); + void startIndexEntry(const QXmlAttributes& attrib); + void endIndexEntry(); + void startPrimaryIE(const QXmlAttributes& attrib); + void endPrimaryIE(); + void startSecondaryIE(const QXmlAttributes& attrib); + void endSecondaryIE(); + + // IDocIndexEntry + virtual Kind kind() const { return DocImpl::IndexEntry; } + virtual const IString *primary() const { return &m_primary; } + virtual const IString *secondary() const { return &m_secondary; } + + private: + IBaseHandler *m_parent; + StringImpl m_primary; + StringImpl m_secondary; +}; + +//----------------------------------------------------------------------------- + +/*! \brief Node representing an entry in the table entry. + * + */ +// children: para +class EntryHandler : public DocEntryImpl, public BaseHandler +{ + friend class EntryIterator; + public: + EntryHandler(IBaseHandler *parent); + virtual ~EntryHandler(); + void startEntry(const QXmlAttributes& attrib); + void endEntry(); + void startParagraph(const QXmlAttributes& attrib); + + // IDocEntry + virtual Kind kind() const { return DocImpl::Entry; } + virtual IDocIterator *contents() const; + + private: + IBaseHandler *m_parent; + QList m_children; +}; + +class EntryIterator : public BaseIteratorVia +{ + public: + EntryIterator(const EntryHandler &handler) : + BaseIteratorVia(handler.m_children) {} +}; + +//----------------------------------------------------------------------------- + +/*! \brief Node representing an entry in the table row. + * + */ +// children: entry +class RowHandler : public DocRowImpl, public BaseHandler +{ + friend class RowIterator; + public: + RowHandler(IBaseHandler *parent); + virtual ~RowHandler(); + void startRow(const QXmlAttributes& attrib); + void endRow(); + void startEntry(const QXmlAttributes& attrib); + + // IDocRow + virtual Kind kind() const { return DocImpl::Row; } + virtual IDocIterator *entries() const; + + private: + IBaseHandler *m_parent; + QList m_children; +}; + +class RowIterator : public BaseIteratorVia +{ + public: + RowIterator(const RowHandler &handler) : + BaseIteratorVia(handler.m_children) {} +}; + +//----------------------------------------------------------------------------- + +/*! \brief Node representing an entry in the table. + * + */ +// children: row, caption +class TableHandler : public DocTableImpl, public BaseHandler +{ + friend class TableIterator; + public: + TableHandler(IBaseHandler *parent); + virtual ~TableHandler(); + void startTable(const QXmlAttributes& attrib); + void endTable(); + void startRow(const QXmlAttributes& attrib); + void startCaption(const QXmlAttributes& attrib); + void endCaption(); + + // IDocTable + virtual Kind kind() const { return DocImpl::Table; } + virtual IDocIterator *rows() const; + virtual int numColumns() const { return m_numColumns; } + virtual const IString *caption() const { return &m_caption; } + + private: + IBaseHandler *m_parent; + QList m_children; + int m_numColumns; + StringImpl m_caption; +}; + +class TableIterator : public BaseIteratorVia +{ + public: + TableIterator(const TableHandler &handler) : + BaseIteratorVia(handler.m_children) {} +}; + +//----------------------------------------------------------------------------- + +/*! \brief Node representing a copied piece of documentation. + * + */ +class CopyHandler : public DocCopyImpl, public BaseHandler +{ + friend class CopyIterator; + public: + CopyHandler(IBaseHandler *parent); + virtual ~CopyHandler(); + virtual void startCopy(const QXmlAttributes& attrib); + virtual void endCopy(); + virtual void startParagraph(const QXmlAttributes& attrib); + + // IDocCopy + virtual Kind kind() const { return DocImpl::Copy; } + virtual IDocIterator *contents() const; + + private: + IBaseHandler *m_parent; + QList m_children; +}; + +class CopyIterator : public BaseIteratorVia +{ + public: + CopyIterator(const CopyHandler &handler) : + BaseIteratorVia(handler.m_children) {} +}; + +//----------------------------------------------------------------------------- + +/*! \brief Node representing an preformatted section + */ +class VerbatimHandler : public DocVerbatimImpl, + public BaseHandler +{ + public: + VerbatimHandler(IBaseHandler *parent); + virtual ~VerbatimHandler(); + void startVerbatim(const QXmlAttributes& attrib,Types type); + void endVerbatim(); + + // IDocVerbatim + virtual Kind kind() const { return DocImpl::Verbatim; } + virtual const IString *text() const { return &m_text; } + virtual Types type() const { return m_type; } + + private: + IBaseHandler *m_parent; + StringImpl m_text; + Types m_type; +}; + + +//----------------------------------------------------------------------------- + +/*! \brief Node representing an special symbol. + * + */ +// children: - +class SymbolHandler : public DocSymbolImpl, public BaseHandler +{ + public: + SymbolHandler(IBaseHandler *parent,Types type); + virtual ~SymbolHandler(); + void startSymbol(const QXmlAttributes& attrib); + void endSymbol(); + + // IDocSymbol + virtual Kind kind() const { return DocImpl::Symbol; } + virtual Types type() const { return m_type; } + virtual const IString *typeString() const { return &m_typeString; } + virtual char letter() const { return m_letter; } + + private: + IBaseHandler *m_parent; + char m_letter; + Types m_type; + StringImpl m_typeString; +}; + + +//----------------------------------------------------------------------------- + +/*! \brief Node representing a section. + * + */ +// children: title, para, sect(n+1) +class DocSectionHandler : public DocSectionImpl, public BaseHandler +{ + friend class DocSectionParaIterator; + friend class DocSectionSubIterator; + public: + DocSectionHandler(IBaseHandler *parent,int level); + virtual ~DocSectionHandler(); + virtual void startDocSection(const QXmlAttributes& attrib); + virtual void endDocSection(); + virtual void startTitle(const QXmlAttributes& attrib); + virtual void startSubSection(const QXmlAttributes& attrib); + virtual void startParagraph(const QXmlAttributes& attrib); + virtual void startInternal(const QXmlAttributes& attrib); + + // IDocSection + virtual Kind kind() const { return DocImpl::Section; } + virtual const IString *id() const { return &m_id; } + virtual int level() const { return m_level; } + virtual IDocTitle *title() const { return m_title; } + virtual IDocIterator *paragraphs() const; + virtual IDocIterator *subSections() const; + virtual IDocInternal *internal() const; + + private: + IBaseHandler *m_parent; + QList m_paragraphs; + QList m_subsections; + DocInternalHandler *m_internal; + StringImpl m_id; + int m_level; + TitleHandler *m_title; +}; + +class DocSectionParaIterator : public BaseIteratorVia +{ + public: + DocSectionParaIterator(const DocSectionHandler &handler) : + BaseIteratorVia(handler.m_paragraphs) {} +}; + +class DocSectionSubIterator : public BaseIteratorVia +{ + public: + DocSectionSubIterator(const DocSectionHandler &handler) : + BaseIteratorVia(handler.m_subsections) {} +}; + +//----------------------------------------------------------------------------- + +class DocInternalHandler : public DocInternalImpl, public BaseHandler +{ + public: + friend class DocInternalParaIterator; + friend class DocInternalSubIterator; + DocInternalHandler(IBaseHandler *parent,int level); + virtual ~DocInternalHandler(); + virtual void startInternal(const QXmlAttributes& attrib); + virtual void endInternal(); + virtual void startSubSection(const QXmlAttributes& attrib); + virtual void startParagraph(const QXmlAttributes& attrib); + + // IDocInternal + virtual Kind kind() const { return DocImpl::Internal; } + virtual IDocIterator *paragraphs() const; + virtual IDocIterator *subSections() const; + + private: + IBaseHandler *m_parent; + QList m_paragraphs; + QList m_subsections; + int m_level; +}; + +class DocInternalParaIterator : public BaseIteratorVia +{ + public: + DocInternalParaIterator(const DocInternalHandler &handler) : + BaseIteratorVia(handler.m_paragraphs) {} +}; + +class DocInternalSubIterator : public BaseIteratorVia +{ + public: + DocInternalSubIterator(const DocInternalHandler &handler) : + BaseIteratorVia(handler.m_subsections) {} +}; + + +//----------------------------------------------------------------------------- + +/*! \brief Node representing a documentation block. + * + */ +// children: para, title, sect1, internal +class DocHandler : public DocRootImpl, public BaseHandler +{ + friend class DocIterator; + public: + virtual void startDoc(const QXmlAttributes& attrib); + virtual void endDoc(); + virtual void startParagraph(const QXmlAttributes& attrib); + virtual void startSect1(const QXmlAttributes& attrib); + virtual void startTitle(const QXmlAttributes& attrib); + virtual void startInternal(const QXmlAttributes& attrib); + + DocHandler(IBaseHandler *parent); + virtual ~DocHandler(); + + // IDocRoot + virtual Kind kind() const { return DocImpl::Root; } + virtual IDocIterator *contents() const; + virtual IDocInternal *internal() const; + + private: + IBaseHandler *m_parent; + QList m_children; + DocInternalHandler *m_internal; +}; + +class DocIterator : public BaseIteratorVia +{ + public: + DocIterator(const DocHandler &handler) : + BaseIteratorVia(handler.m_children) {} +}; + +//----------------------------------------------------------------------------- + +void dochandler_init(); +void dochandler_exit(); + +#endif diff --git a/trunk/addon/doxmlparser/src/doxmlintf.h b/trunk/addon/doxmlparser/src/doxmlintf.h new file mode 120000 index 0000000..1b1e847 --- /dev/null +++ b/trunk/addon/doxmlparser/src/doxmlintf.h @@ -0,0 +1 @@ +../include/doxmlintf.h \ No newline at end of file diff --git a/trunk/addon/doxmlparser/src/doxmlparser.pro.in b/trunk/addon/doxmlparser/src/doxmlparser.pro.in new file mode 100644 index 0000000..841a46c --- /dev/null +++ b/trunk/addon/doxmlparser/src/doxmlparser.pro.in @@ -0,0 +1,27 @@ +TEMPLATE = lib.t +CONFIG = console staticlib warn_on $extraopts +HEADERS = basehandler.h mainhandler.h \ + compoundhandler.h sectionhandler.h \ + memberhandler.h paramhandler.h \ + dochandler.h linkedtexthandler.h \ + debug.h graphhandler.h stringimpl.h \ + loamhandler.h +SOURCES = mainhandler.cpp \ + compoundhandler.cpp sectionhandler.cpp \ + memberhandler.cpp paramhandler.cpp \ + dochandler.cpp linkedtexthandler.cpp \ + basehandler.cpp debug.cpp graphhandler.cpp \ + loamhandler.cpp +unix:LIBS += -L../../../lib -lqtools +win32:INCLUDEPATH += . +win32-mingw:LIBS += -L../../../lib -lqtools +win32-msvc:LIBS += qtools.lib shell32.lib +win32-msvc:TMAKE_LFLAGS += /LIBPATH:....\\..\lib +win32-borland:LIBS += qtools.lib doxycfg.lib shell32.lib +win32-borland:TMAKE_LFLAGS += -L..\..\..\lib +win32:TMAKE_CXXFLAGS += -DQT_NODLL +DESTDIR = ../lib +OBJECTS_DIR = ../objects +TARGET = doxmlparser +INCLUDEPATH += ../../../qtools ../include + diff --git a/trunk/addon/doxmlparser/src/graphhandler.cpp b/trunk/addon/doxmlparser/src/graphhandler.cpp new file mode 100644 index 0000000..7816970 --- /dev/null +++ b/trunk/addon/doxmlparser/src/graphhandler.cpp @@ -0,0 +1,216 @@ +#include "graphhandler.h" + +class EdgeRelationMapper +{ + public: + EdgeRelationMapper() + { + m_map.insert("public-inheritance", IChildNode::PublicInheritance); + m_map.insert("protected-inheritance", IChildNode::ProtectedInheritance); + m_map.insert("private-inheritance", IChildNode::PrivateInheritance); + m_map.insert("usage", IChildNode::Usage); + m_map.insert("template-instance", IChildNode::TemplateInstance); + } + IChildNode::NodeRelation stringToNodeRelation(const QString &nrStr) + { + return m_map[nrStr]; + } + private: + QMap m_map; +}; + +static EdgeRelationMapper *s_edgeRelationMapper; + +void graphhandler_init() +{ + s_edgeRelationMapper = new EdgeRelationMapper; +} + +void graphhandler_exit() +{ + delete s_edgeRelationMapper; +} + +//------------------------------------------------------------------------ + +GraphHandler::GraphHandler(IBaseHandler *parent,const char *endTag) + : m_parent(parent) +{ + addEndHandler(endTag,this,&GraphHandler::endGraph); + addStartHandler("node",this,&GraphHandler::startNode); + m_nodes.setAutoDelete(TRUE); + m_nodeDict = new QDict(1009); +} + +GraphHandler::~GraphHandler() +{ + delete m_nodeDict; +} + +void GraphHandler::startGraph(const QXmlAttributes &) +{ + debug(2,"startGraph\n"); + m_parent->setDelegate(this); +} + +void GraphHandler::endGraph() +{ + debug(2,"endGraph\n"); + m_parent->setDelegate(0); +} + +void GraphHandler::startNode(const QXmlAttributes &attrib) +{ + NodeHandler *n = new NodeHandler(this); + n->startNode(attrib); + m_nodes.append(n); + m_nodeDict->insert(attrib.value("id"),n); +} + +INodeIterator *GraphHandler::nodes() const +{ + return new NodeIterator(*this); +} + +NodeHandler *GraphHandler::getNodeById(const QString &id) const +{ + return m_nodeDict->find(id); +} + +//------------------------------------------------------------------------ + +NodeHandler::NodeHandler(GraphHandler *gh) + : m_parent(gh), m_graph(gh) +{ + addEndHandler("node",this,&NodeHandler::endNode); + addStartHandler("link",this,&NodeHandler::startLink); + addEndHandler("link",this,&NodeHandler::endLink); + addStartHandler("label",this,&NodeHandler::startLabel); + addEndHandler("label",this,&NodeHandler::endLabel); + addStartHandler("childnode",this,&NodeHandler::startChildNode); + m_children.setAutoDelete(TRUE); +} + +NodeHandler::~NodeHandler() +{ +} + +void NodeHandler::startNode(const QXmlAttributes &attrib) +{ + debug(2,"startNode\n"); + m_parent->setDelegate(this); + m_id = attrib.value("id"); +} + +void NodeHandler::endNode() +{ + debug(2,"endNode\n"); + m_parent->setDelegate(0); +} + +void NodeHandler::startLink(const QXmlAttributes &attrib) +{ + m_link = attrib.value("refid"); +} + +void NodeHandler::endLink() +{ +} + +void NodeHandler::startLabel(const QXmlAttributes &/*attrib*/) +{ + m_curString=""; +} + +void NodeHandler::endLabel() +{ + m_label = m_curString; +} + +void NodeHandler::startChildNode(const QXmlAttributes &attrib) +{ + ChildNodeHandler *cnh = new ChildNodeHandler(this,m_graph); + cnh->startChildNode(attrib); + m_children.append(cnh); +} + +IChildNodeIterator *NodeHandler::children() const +{ + return new ChildNodeIterator(*this); +} + +//------------------------------------------------------------------------ + +ChildNodeHandler::ChildNodeHandler(IBaseHandler *parent,GraphHandler *gh) + : m_parent(parent), m_graph(gh) +{ + addEndHandler("childnode",this,&ChildNodeHandler::endChildNode); + addStartHandler("edgelabel",this,&ChildNodeHandler::startEdgeLabel); + m_edgeLabels.setAutoDelete(TRUE); +} + +ChildNodeHandler::~ChildNodeHandler() +{ +} + +void ChildNodeHandler::startChildNode(const QXmlAttributes &attrib) +{ + debug(2,"startChildNode\n"); + m_id = attrib.value("refid"); + m_relationString = attrib.value("relation"); + m_relation = s_edgeRelationMapper->stringToNodeRelation(m_relationString); + m_parent->setDelegate(this); +} + +void ChildNodeHandler::endChildNode() +{ + debug(2,"endChildNode\n"); + m_parent->setDelegate(0); +} + + +void ChildNodeHandler::startEdgeLabel(const QXmlAttributes &attrib) +{ + EdgeLabelHandler *elh = new EdgeLabelHandler(this); + elh->startEdgeLabel(attrib); + m_edgeLabels.append(elh); +} + +IEdgeLabelIterator *ChildNodeHandler::edgeLabels() const +{ + return new EdgeLabelIterator(*this); +} + +INode *ChildNodeHandler::node() const +{ + return m_graph->getNodeById(m_id); +} + +//----------------------------------------------------------------------- + +EdgeLabelHandler::EdgeLabelHandler(IBaseHandler *parent) + : m_parent(parent) +{ + addEndHandler("edgelabel",this,&EdgeLabelHandler::endEdgeLabel); +} + +EdgeLabelHandler::~EdgeLabelHandler() +{ +} + +void EdgeLabelHandler::startEdgeLabel(const QXmlAttributes &) +{ + m_parent->setDelegate(this); + m_curString=""; +} + +void EdgeLabelHandler::endEdgeLabel() +{ + m_label=m_curString; + m_parent->setDelegate(0); +} + + + + + diff --git a/trunk/addon/doxmlparser/src/graphhandler.h b/trunk/addon/doxmlparser/src/graphhandler.h new file mode 100644 index 0000000..acce157 --- /dev/null +++ b/trunk/addon/doxmlparser/src/graphhandler.h @@ -0,0 +1,154 @@ +/****************************************************************************** + * + * $Id$ + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#ifndef _GRAPHHANDLER_H +#define _GRAPHHANDLER_H + +#include "stringimpl.h" +#include "doxmlintf.h" +#include "basehandler.h" +#include "baseiterator.h" + +class NodeHandler; +class ChildNodeHandler; +class EdgeLabelHandler; + +class GraphHandler : public IGraph, public BaseHandler +{ + friend class NodeIterator; + public: + GraphHandler(IBaseHandler *parent,const char *endTag); + virtual ~GraphHandler(); + + void startGraph(const QXmlAttributes &attrib); + void endGraph(); + void startNode(const QXmlAttributes &attrib); + NodeHandler *getNodeById(const QString &id) const; + + // IGraph + virtual INodeIterator *nodes() const; + + private: + IBaseHandler *m_parent; + QList m_nodes; + QDict *m_nodeDict; +}; + +//---------------------------------------------------------------------- + +class NodeHandler : public INode, public BaseHandler +{ + friend class ChildNodeIterator; + public: + NodeHandler(GraphHandler *gh); + virtual ~NodeHandler(); + + void startNode(const QXmlAttributes &attrib); + void endNode(); + void startLabel(const QXmlAttributes &attrib); + void endLabel(); + void startLink(const QXmlAttributes &attrib); + void endLink(); + void startChildNode(const QXmlAttributes &attrib); + + // INode + virtual const IString *id() const { return &m_id; } + virtual const IString *label() const { return &m_label; } + virtual const IString *linkId() const { return &m_link; } + virtual IChildNodeIterator *children() const; + + private: + IBaseHandler *m_parent; + StringImpl m_id; + StringImpl m_label; + StringImpl m_link; + QList m_children; + GraphHandler *m_graph; +}; + +class NodeIterator : public BaseIterator +{ + public: + NodeIterator(const GraphHandler &handler) : + BaseIterator(handler.m_nodes) {} +}; + +//---------------------------------------------------------------------- + +class ChildNodeHandler : public IChildNode, public BaseHandler +{ + friend class EdgeLabelIterator; + public: + ChildNodeHandler(IBaseHandler *parent,GraphHandler *gh); + virtual ~ChildNodeHandler(); + + void startChildNode(const QXmlAttributes &attrib); + void endChildNode(); + void startEdgeLabel(const QXmlAttributes &attrib); + + // IChildNode + virtual INode *node() const; + virtual NodeRelation relation() const { return m_relation; } + virtual const IString * relationString() const { return &m_relationString; } + virtual IEdgeLabelIterator *edgeLabels() const; + + private: + IBaseHandler *m_parent; + QString m_id; + NodeRelation m_relation; + StringImpl m_relationString; + QList m_edgeLabels; + GraphHandler *m_graph; +}; + +class ChildNodeIterator : public BaseIterator +{ + public: + ChildNodeIterator(const NodeHandler &handler) : + BaseIterator(handler.m_children) {} +}; + +//---------------------------------------------------------------------- + +class EdgeLabelHandler : public IEdgeLabel, public BaseHandler +{ + friend class EdgeLabelIterator; + public: + EdgeLabelHandler(IBaseHandler *parent); + virtual ~EdgeLabelHandler(); + + void startEdgeLabel(const QXmlAttributes &attrib); + void endEdgeLabel(); + + // IEdgeLabel + virtual const IString *label() const { return &m_label; } + + private: + IBaseHandler *m_parent; + StringImpl m_label; +}; + +class EdgeLabelIterator : public BaseIterator +{ + public: + EdgeLabelIterator(const ChildNodeHandler &handler) : + BaseIterator(handler.m_edgeLabels) {} +}; + +void graphhandler_init(); +void graphhandler_exit(); + +#endif + diff --git a/trunk/addon/doxmlparser/src/linkedtexthandler.cpp b/trunk/addon/doxmlparser/src/linkedtexthandler.cpp new file mode 100644 index 0000000..a921b6c --- /dev/null +++ b/trunk/addon/doxmlparser/src/linkedtexthandler.cpp @@ -0,0 +1,133 @@ +/****************************************************************************** + * + * $Id$ + * + * + * Copyright (C) 1997-2012 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. + * + */ +#include "linkedtexthandler.h" +#include "debug.h" +#include +#include "stringimpl.h" + +class LT_Text : public LinkedTextImpl, public ILT_Text +{ + public: + LT_Text(const QString &text) : m_text(text) {} + virtual ~LT_Text() {} + + // ILT_Text + virtual const IString *text() const { return &m_text; } + virtual Kind kind() const { return LinkedTextImpl::Kind_Text; } + private: + StringImpl m_text; +}; + +class LT_Ref : public LinkedTextImpl, public ILT_Ref +{ + public: + LT_Ref() {} + virtual ~LT_Ref() {} + void setRefId(const QString &refId) { m_refId=refId; } + void setText(const QString &text) { m_text=text; } + void setExtId(const QString &extId) { m_extId=extId; } + void setTargetKind(TargetKind k) { m_targetKind=k; } + + // ILT_Ref + virtual const IString *text() const { return &m_text; } + virtual const IString * id() const { return &m_refId; } + virtual TargetKind targetKind() const { return m_targetKind; } + virtual const IString *external() const { return &m_extId; } + virtual Kind kind() const { return LinkedTextImpl::Kind_Ref; } + + private: + StringImpl m_refId; + StringImpl m_extId; + StringImpl m_text; + TargetKind m_targetKind; +}; + +LinkedTextHandler::LinkedTextHandler(IBaseHandler *parent, + QList &children + ) + : m_parent(parent), m_children(children) +{ + addStartHandler("ref",this,&LinkedTextHandler::startRef); + addEndHandler("ref",this,&LinkedTextHandler::endRef); + m_children.setAutoDelete(TRUE); + m_ref=0; +} + +LinkedTextHandler::~LinkedTextHandler() +{ +} + +void LinkedTextHandler::start(const char *endTag) +{ + addEndHandler(endTag,this,&LinkedTextHandler::end); + m_parent->setDelegate(this); + m_curString=""; +} + +void LinkedTextHandler::end() +{ + if (!m_curString.isEmpty()) + { + m_children.append(new LT_Text(m_curString)); + debug(2,"LinkedTextHandler: add text `%s'\n",m_curString.data()); + m_curString=""; + } + m_parent->setDelegate(0); +} + +void LinkedTextHandler::startRef(const QXmlAttributes& attrib) +{ + if (!m_curString.isEmpty()) + { + m_children.append(new LT_Text(m_curString)); + debug(2,"LinkedTextHandler: add text `%s'\n",m_curString.data()); + m_curString=""; + } + ASSERT(m_ref==0); + m_ref = new LT_Ref; + m_ref->setRefId(attrib.value("refid")); + m_ref->setExtId(attrib.value("external")); + ASSERT(attrib.value("kindref")=="compound" || attrib.value("kindref")=="member"); + m_ref->setTargetKind(attrib.value("kindref")=="compound" ? ILT_Ref::Compound : ILT_Ref::Member); +} + +void LinkedTextHandler::endRef() +{ + m_ref->setText(m_curString); + m_children.append(m_ref); + debug(2,"LinkedTextHandler: add ref `%s'\n",m_ref->text()->latin1()); + m_ref=0; +} + +QString LinkedTextHandler::toString(const QList &list) +{ + QListIterator li(list); + QString result; + LinkedTextImpl *lt; + for (li.toFirst();(lt=li.current());++li) + { + switch(lt->kind()) + { + case ILinkedText::Kind_Text: + result+=dynamic_cast(lt)->text()->latin1(); + break; + case ILinkedText::Kind_Ref: + result+=dynamic_cast(lt)->text()->latin1(); + break; + } + } + return result; +} + diff --git a/trunk/addon/doxmlparser/src/linkedtexthandler.h b/trunk/addon/doxmlparser/src/linkedtexthandler.h new file mode 100644 index 0000000..83cc4d8 --- /dev/null +++ b/trunk/addon/doxmlparser/src/linkedtexthandler.h @@ -0,0 +1,54 @@ +/****************************************************************************** + * + * $Id$ + * + * + * Copyright (C) 1997-2012 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. + * + */ +#ifndef LINKEDTEXTHANDLER_H +#define LINKEDTEXTHANDLER_H + +#include "baseiterator.h" +#include "basehandler.h" + +class LT_Ref; +class LinkedTextImpl : public ILinkedText +{ + public: + virtual ~LinkedTextImpl() {} +}; + +class LinkedTextHandler : public BaseHandler +{ + public: + LinkedTextHandler(IBaseHandler *parent,QList &children); + virtual ~LinkedTextHandler(); + virtual void start(const char *endTag); + virtual void end(); + virtual void startRef(const QXmlAttributes& attrib); + virtual void endRef(); + static QString toString(const QList &list); + + // ILinkedText + + private: + IBaseHandler *m_parent; + QList &m_children; + LT_Ref *m_ref; +}; + +class LinkedTextIterator : public BaseIterator +{ + public: + LinkedTextIterator(const QList &list) : + BaseIterator(list) {} +}; + +#endif diff --git a/trunk/addon/doxmlparser/src/loamhandler.cpp b/trunk/addon/doxmlparser/src/loamhandler.cpp new file mode 100644 index 0000000..a939b7b --- /dev/null +++ b/trunk/addon/doxmlparser/src/loamhandler.cpp @@ -0,0 +1,75 @@ +#include "loamhandler.h" +#include "memberhandler.h" + + +ListOfAllMembersHandler::ListOfAllMembersHandler(IBaseHandler *parent) : m_parent(parent) +{ + m_members.setAutoDelete(TRUE); + + addStartHandler("member",this,&ListOfAllMembersHandler::startMember); + addStartHandler("name",this,&ListOfAllMembersHandler::startName); + addEndHandler("name",this,&ListOfAllMembersHandler::endName); + addStartHandler("scope",this,&ListOfAllMembersHandler::startScope); + addEndHandler("scope",this,&ListOfAllMembersHandler::endScope); + + addEndHandler("listofallmembers",this,&ListOfAllMembersHandler::endListOfAllMembers); +} + +void ListOfAllMembersHandler::initialize(MainHandler *mh) +{ + QListIterator mli(m_members); + MemberReference *mr; + for (;(mr=mli.current());++mli) + { + mr->initialize(mh); + } +} + +void ListOfAllMembersHandler::startMember(const QXmlAttributes& attrib) +{ + MemberReference *mr = new MemberReference; + mr->m_memId = attrib.value("refid"); + mr->m_virtualness = attrib.value("virt"); + mr->m_protection = attrib.value("prot"); + mr->m_ambiguityScope = attrib.value("ambiguityscope"); + m_members.append(new MemberReference); +} + +void ListOfAllMembersHandler::startName(const QXmlAttributes&) +{ + m_curString=""; +} + +void ListOfAllMembersHandler::endName() +{ + ASSERT(m_members.getLast()); + m_members.getLast()->m_name = m_curString; +} + +void ListOfAllMembersHandler::startScope(const QXmlAttributes&) +{ + m_curString=""; +} + +void ListOfAllMembersHandler::endScope() +{ + ASSERT(m_members.getLast()); + m_members.getLast()->m_scope = m_curString; +} + +void ListOfAllMembersHandler::startListOfAllMembers(const QXmlAttributes& /*attrib*/) +{ + m_parent->setDelegate(this); + debug(2,"listofallmembers start\n"); +} + +void ListOfAllMembersHandler::endListOfAllMembers() +{ + m_parent->setDelegate(0); + debug(2,"listofallmembers end\n"); +} + +IMemberReferenceIterator *ListOfAllMembersHandler::members() const +{ + return new MemberReferenceIterator(m_members); +} diff --git a/trunk/addon/doxmlparser/src/loamhandler.h b/trunk/addon/doxmlparser/src/loamhandler.h new file mode 100644 index 0000000..b7c6397 --- /dev/null +++ b/trunk/addon/doxmlparser/src/loamhandler.h @@ -0,0 +1,52 @@ +/****************************************************************************** + * + * $Id$ + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#ifndef _LOAMHANDLER_H +#define _LOAMHANDLER_H + +#include +#include +#include + +#include "basehandler.h" + +class MainHandler; +class MemberReference; + +class ListOfAllMembersHandler : public BaseHandler +{ + public: + virtual void startMember(const QXmlAttributes& attrib); + virtual void startName(const QXmlAttributes& attrib); + virtual void endName(); + virtual void startScope(const QXmlAttributes& attrib); + virtual void endScope(); + virtual void startListOfAllMembers(const QXmlAttributes& attrib); + virtual void endListOfAllMembers(); + + ListOfAllMembersHandler(IBaseHandler *parent); + virtual ~ListOfAllMembersHandler() {} + + void initialize(MainHandler *mh); + + virtual IMemberReferenceIterator *members() const; + + protected: + IBaseHandler *m_parent; + QList m_members; +}; + +#endif + diff --git a/trunk/addon/doxmlparser/src/mainhandler.cpp b/trunk/addon/doxmlparser/src/mainhandler.cpp new file mode 100644 index 0000000..bc211b8 --- /dev/null +++ b/trunk/addon/doxmlparser/src/mainhandler.cpp @@ -0,0 +1,299 @@ +/****************************************************************************** + * + * $Id$ + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#include +#include "mainhandler.h" +#include "compoundhandler.h" +#include "sectionhandler.h" +#include "graphhandler.h" +#include "dochandler.h" +#include "memberhandler.h" +#include "debug.h" + + +class ErrorHandler : public QXmlErrorHandler +{ + public: + virtual ~ErrorHandler() {} + bool warning( const QXmlParseException & ) + { + return FALSE; + } + bool error( const QXmlParseException & ) + { + return FALSE; + } + bool fatalError( const QXmlParseException &exception ) + { + debug(1,"Fatal error at line %d column %d: %s\n", + exception.lineNumber(),exception.columnNumber(), + exception.message().data()); + return FALSE; + } + QString errorString() { return ""; } + + private: + QString errorMsg; +}; + +//-------------------------------------------------------------------------- + +class CompoundEntryIterator : public ICompoundIterator, + public QListIterator +{ + public: + CompoundEntryIterator(const MainHandler *m,const QList &list) : + QListIterator(list), m_mainHandler(m) {} + virtual ~CompoundEntryIterator() {} + + virtual void toFirst() + { + QListIterator::toFirst(); + } + virtual void toLast() + { + QListIterator::toLast(); + } + virtual void toNext() + { + QListIterator::operator++(); + } + virtual void toPrev() + { + QListIterator::operator--(); + } + virtual ICompound *current() const + { + CompoundEntry *ch = QListIterator::current(); + return ch ? m_mainHandler->compoundById(ch->id) : 0; + } + virtual void release() + { delete this; } + + private: + const MainHandler *m_mainHandler; +}; + +//-------------------------------------------------------------------------- + +MainHandler::MainHandler() : m_compoundDict(2999), m_compoundNameDict(2999), + m_memberDict(12251), m_memberNameDict(12251), + m_compoundsLoaded(1009) +{ + m_compounds.setAutoDelete(TRUE); + m_memberNameDict.setAutoDelete(TRUE); + addStartHandler("doxygenindex"); + addEndHandler("doxygenindex"); + addStartHandler("compound",this,&MainHandler::startCompound); + addEndHandler("compound"); + addStartHandler("member",this,&MainHandler::startMember); + addEndHandler("member",this,&MainHandler::endMember); + addStartHandler("name",this,&MainHandler::startName); + addEndHandler("name",this,&MainHandler::endName); + m_curCompound = 0; + m_insideMember = FALSE; +} + +MainHandler::~MainHandler() +{ + debug(2,"MainHandler::~MainHandler()\n"); +} + +void MainHandler::startCompound(const QXmlAttributes& attrib) +{ + m_curCompound = new CompoundEntry(257); + m_curCompound->id = attrib.value("refid"); + m_compounds.append(m_curCompound); + m_compoundDict.insert(m_curCompound->id,m_curCompound); +} + +void MainHandler::startName(const QXmlAttributes& /*attrib*/) +{ + m_curString = ""; +} + +void MainHandler::endName() +{ + if (m_insideMember) + { + m_curMember->name = m_curString; + } + else + { + m_curCompound->name = m_curString; + m_compoundNameDict.insert(m_curString,m_curCompound); + } +} + +void MainHandler::startMember(const QXmlAttributes& attrib) +{ + m_insideMember = TRUE; + m_curMember = new MemberEntry; + m_curMember->id = attrib.value("refid"); + m_curMember->compound = m_curCompound; + m_memberDict.insert(m_curMember->id,m_curMember); +} + +void MainHandler::endMember() +{ + m_curCompound->memberDict.insert(m_curMember->name,m_curMember); + QList *cel=0; + if ((cel=m_memberNameDict.find(m_curMember->name))==0) + { + cel = new QList; + m_memberNameDict.insert(m_curMember->name,cel); + } + cel->append(m_curCompound); + m_insideMember = FALSE; +} + +void MainHandler::setDebugLevel(int level) +{ + ::setDebugLevel(level); +} + +void MainHandler::dump() +{ + QListIterator cli(m_compounds); + CompoundEntry *ce; + for (cli.toFirst();(ce=cli.current());++cli) + { + debug(2,"compound id=`%s' name=`%s'\n",ce->id.data(),ce->name.data()); + QDictIterator mdi(ce->memberDict); + MemberEntry *me; + for (mdi.toFirst();(me=mdi.current());++mdi) + { + debug(2," member id=`%s' name=`%s'\n",me->id.data(),me->name.data()); + } + } +} + +bool MainHandler::readXMLDir(const char * xmlDirName) +{ + m_xmlDirName = xmlDirName; + QString xmlFileName=m_xmlDirName+"/index.xml"; + QFile xmlFile(xmlFileName); + //printf("Trying %s xmlFile.exists()=%d isReadable()=%d\n", + // xmlFileName.data(),xmlFile.exists(),xmlFile.isReadable()); + if (xmlFile.exists()) + { + ErrorHandler errorHandler; + QXmlInputSource source( xmlFile ); + QXmlSimpleReader reader; + reader.setContentHandler( this ); + reader.setErrorHandler( &errorHandler ); + reader.parse( source ); + dump(); + return TRUE; + } + return FALSE; +} + +ICompoundIterator *MainHandler::compounds() const +{ + return new CompoundEntryIterator(this,m_compounds); +} + +ICompound *MainHandler::compoundById(const char *id) const +{ + QString ids = id; + if (ids.isEmpty()) return 0; + CompoundHandler *ch = m_compoundsLoaded[ids]; + if (ch) // compound already in memory + { + ch->addref(); // returning alias -> increase reference counter + return ch->toICompound(); + } + CompoundEntry *ce = m_compoundDict.find(ids); + if (ce==0) return 0; // id not found + // create and load a new compound + ch = new CompoundHandler(m_xmlDirName); + if (!ch->parseXML(id)) + { + // compound could not be initialized. + delete ch; + return 0; + } + + // we disregard the constness here, because the object stays conceptually + // unchanged. + MainHandler *that = (MainHandler *)this; + ch->initialize(that); + //printf("loading compound %s in memory\n",id); + that->m_compoundsLoaded.insert(id,ch); + return ch->toICompound(); +} + +void MainHandler::unloadCompound(CompoundHandler *ch) +{ + //printf("unloading compound %s from memory\n",ch->id()->latin1()); + bool result = m_compoundsLoaded.remove(ch->id()->latin1()); + if (!result) debug(1,"Failed to unload component!\n"); +} + +ICompound *MainHandler::compoundByName(const char *name) const +{ + QString nameStr = name; + if (nameStr.isEmpty()) return 0; + CompoundEntry *ce = m_compoundNameDict[name]; + if (ce==0) return 0; // name not found + return compoundById(ce->id); +} + +ICompound *MainHandler::memberById(const char *id) const +{ + QString ids = id; + if (ids.isEmpty()) return 0; + MemberEntry *me = m_memberDict[id]; + if (me==0) return 0; // id not found + return compoundById(me->compound->id); +} + +ICompoundIterator *MainHandler::memberByName(const char *name) const +{ + QString nameStr = name; + if (nameStr.isEmpty()) return 0; + QList *cel = m_memberNameDict[name]; + if (cel==0) return 0; // name not found + return new CompoundEntryIterator(this,*cel); +} + +IDoxygen *createObjectModel() +{ + compoundhandler_init(); + sectionhandler_init(); + memberhandler_init(); + dochandler_init(); + graphhandler_init(); + return new MainHandler; +} + +void MainHandler::release() +{ + //printf("MainHandler::release()\n"); + QDictIterator chi(m_compoundsLoaded); + CompoundHandler *ch; + for (chi.toFirst();(ch=chi.current());++chi) + { + debug(1,"Compound %s not released\n",ch->name()->latin1()); + } + graphhandler_exit(); + dochandler_exit(); + memberhandler_exit(); + sectionhandler_exit(); + compoundhandler_exit(); + delete this; +} + diff --git a/trunk/addon/doxmlparser/src/mainhandler.h b/trunk/addon/doxmlparser/src/mainhandler.h new file mode 100644 index 0000000..7b9e7fc --- /dev/null +++ b/trunk/addon/doxmlparser/src/mainhandler.h @@ -0,0 +1,82 @@ +/****************************************************************************** + * + * $Id$ + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#ifndef _MAINHANDLER_H +#define _MAINHANDLER_H + +#include + +#include +#include "basehandler.h" + +class CompoundHandler; +struct CompoundEntry; + +struct IndexEntry +{ + QString id; + QString name; +}; + +struct MemberEntry : public IndexEntry +{ + CompoundEntry *compound; +}; + +struct CompoundEntry : public IndexEntry +{ + CompoundEntry(int size) : memberDict(size) + { memberDict.setAutoDelete(TRUE); } + QDict memberDict; +}; + +class MainHandler : public IDoxygen, public BaseHandler +{ + public: + virtual void startCompound(const QXmlAttributes& attrib); + virtual void startMember(const QXmlAttributes& attrib); + virtual void endMember(); + virtual void startName(const QXmlAttributes& attrib); + virtual void endName(); + MainHandler(); + virtual ~MainHandler(); + + // IDoxygen + ICompoundIterator *compounds() const; + ICompound *compoundById(const char *id) const; + virtual ICompound *compoundByName(const char *name) const; + virtual ICompound *memberById(const char *id) const; + virtual ICompoundIterator *memberByName(const char *name) const; + + virtual void release(); + void setDebugLevel(int level); + bool readXMLDir(const char *dirName); + void dump(); + void unloadCompound(CompoundHandler *ch); + + private: + CompoundEntry *m_curCompound; + MemberEntry *m_curMember; + QList m_compounds; + QDict m_compoundDict; + QDict m_compoundNameDict; + QDict m_memberDict; + QDict > m_memberNameDict; + QString m_xmlDirName; + QDict m_compoundsLoaded; + bool m_insideMember; +}; + +#endif diff --git a/trunk/addon/doxmlparser/src/memberhandler.cpp b/trunk/addon/doxmlparser/src/memberhandler.cpp new file mode 100644 index 0000000..1b87a2c --- /dev/null +++ b/trunk/addon/doxmlparser/src/memberhandler.cpp @@ -0,0 +1,600 @@ +/****************************************************************************** + * + * $Id$ + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#include "memberhandler.h" +#include "sectionhandler.h" +#include "dochandler.h" +#include "mainhandler.h" +#include "linkedtexthandler.h" +#include "paramhandler.h" +#include "compoundhandler.h" +#include "debug.h" + +//------------------------------------------------------------------------------ + +class MemberTypeMap +{ + public: + MemberTypeMap() + { + m_map.setAutoDelete(TRUE); + m_map.insert("define",new int(IMember::Define)); + m_map.insert("property",new int(IMember::Property)); + m_map.insert("variable",new int(IMember::Variable)); + m_map.insert("typedef",new int(IMember::Typedef)); + m_map.insert("enum",new int(IMember::Enum)); + m_map.insert("function",new int(IMember::Function)); + m_map.insert("signal",new int(IMember::Signal)); + m_map.insert("prototype",new int(IMember::Prototype)); + m_map.insert("friend",new int(IMember::Friend)); + m_map.insert("dcop",new int(IMember::DCOP)); + m_map.insert("slot",new int(IMember::Slot)); + m_map.insert("enumvalue",new int(IMember::EnumValue)); + } + IMember::MemberKind map(const QString &s) + { + int *val = m_map.find(s); + if (val==0) + { + debug(1,"Warning: `%s' is an invalid member type\n",s.data()); + return IMember::Invalid; + } + else return (IMember::MemberKind)*val; + } + private: + QDict m_map; +}; + +static MemberTypeMap *s_typeMap; + +void memberhandler_init() +{ + s_typeMap = new MemberTypeMap; +} + +void memberhandler_exit() +{ + delete s_typeMap; +} + +//------------------------------------------------------------------------------ + +void MemberReference::initialize(MainHandler *mh) +{ + m_mainHandler = mh; +} + +IMember *MemberReference::member() const +{ + //return m_mainHandler->memberById(m_memId); + return 0; +} + +//------------------------------------------------------------------------------ + + +#if 0 +EnumValueHandler::EnumValueHandler(IBaseHandler *parent) : + m_parent(parent), m_brief(0), m_detailed(0), m_linkedTextHandler(0) +{ + addEndHandler("enumvalue",this,&EnumValueHandler::endEnumValue); + + addStartHandler("name",this,&EnumValueHandler::startName); + addEndHandler("name",this,&EnumValueHandler::endName); + addStartHandler("initializer",this,&EnumValueHandler::startInitializer); + + addStartHandler("briefdescription",this,&EnumValueHandler::startBriefDesc); + + addStartHandler("detaileddescription",this,&EnumValueHandler::startDetailedDesc); + + m_initializer.setAutoDelete(TRUE); +} + +EnumValueHandler::~EnumValueHandler() +{ + delete m_brief; + delete m_detailed; + delete m_linkedTextHandler; +} + +void EnumValueHandler::startEnumValue(const QXmlAttributes& /*attrib*/) +{ + m_parent->setDelegate(this); +} + +void EnumValueHandler::endEnumValue() +{ + m_parent->setDelegate(0); +} + +void EnumValueHandler::startName(const QXmlAttributes& /*attrib*/) +{ + m_curString=""; +} + +void EnumValueHandler::endName() +{ + m_name = m_curString; +} + +void EnumValueHandler::startInitializer(const QXmlAttributes& /*attrib*/) +{ + delete m_linkedTextHandler; + m_linkedTextHandler = new LinkedTextHandler(this,m_initializer); + m_linkedTextHandler->start("initializer"); +} + +void EnumValueHandler::startBriefDesc(const QXmlAttributes& attrib) +{ + DocHandler *docHandler = new DocHandler(this); + docHandler->startDoc(attrib); + m_brief = docHandler; +} + +void EnumValueHandler::startDetailedDesc(const QXmlAttributes& attrib) +{ + DocHandler *docHandler = new DocHandler(this); + docHandler->startDoc(attrib); + m_detailed = docHandler; +} +#endif + +//------------------------------------------------------------------------------ + +MemberHandler::MemberHandler(IBaseHandler *parent) + : m_brief(0), m_detailed(0), m_inbody(0), + m_compound(0), m_section(0), m_parent(parent) +{ + //printf("MemberHandler::MemberHandler() %p\n",this); + addEndHandler("memberdef",this,&MemberHandler::endMember); + + addStartHandler("templateparamlist",this,&MemberHandler::startTemplateParamList); + addEndHandler("templateparamlist",this,&MemberHandler::endTemplateParamList); + + addStartHandler("type",this,&MemberHandler::startType); + + addStartHandler("definition",this,&MemberHandler::startDefinition); + addEndHandler("definition",this,&MemberHandler::endDefinition); + + addStartHandler("argsstring",this,&MemberHandler::startArgsString); + addEndHandler("argsstring",this,&MemberHandler::endArgsString); + + addStartHandler("name",this,&MemberHandler::startName); + addEndHandler("name",this,&MemberHandler::endName); + + addStartHandler("read",this,&MemberHandler::startRead); + addEndHandler("read",this,&MemberHandler::endRead); + + addStartHandler("write",this,&MemberHandler::startWrite); + addEndHandler("write",this,&MemberHandler::endWrite); + + addStartHandler("reimplements",this,&MemberHandler::startReimplements); + addEndHandler("reimplements",this,&MemberHandler::endReimplements); + + addStartHandler("reimplementedby",this,&MemberHandler::startReimplementedBy); + addEndHandler("reimplementedby",this,&MemberHandler::endReimplementedBy); + + addStartHandler("param",this,&MemberHandler::startParam); + + addStartHandler("enumvalue",this,&MemberHandler::startEnumValue2); + addEndHandler("enumvalue",this,&MemberHandler::endMember); + + addStartHandler("initializer",this,&MemberHandler::startInitializer); + addStartHandler("exceptions",this,&MemberHandler::startException); + + addStartHandler("briefdescription",this,&MemberHandler::startBriefDesc); + + addStartHandler("detaileddescription",this,&MemberHandler::startDetailedDesc); + + addStartHandler("inbodydescription",this,&MemberHandler::startInbodyDesc); + + addStartHandler("location",this,&MemberHandler::startLocation); + addEndHandler("location"); + + addStartHandler("references",this,&MemberHandler::startReferences); + addEndHandler("references",this,&MemberHandler::endReferences); + + addStartHandler("referencedby",this,&MemberHandler::startReferencedBy); + addEndHandler("referencedby",this,&MemberHandler::endReferencedBy); + + m_type.setAutoDelete(TRUE); + m_initializer.setAutoDelete(TRUE); + m_exception.setAutoDelete(TRUE); + m_params.setAutoDelete(TRUE); + m_references.setAutoDelete(TRUE); + m_referencedBy.setAutoDelete(TRUE); + m_reimplements = 0; + m_reimplementedBy.setAutoDelete(TRUE); + m_enumValues.setAutoDelete(TRUE); + m_linkedTextHandler = 0; + m_defLine=0; + m_bodyStart=0; + m_bodyEnd=0; + m_insideTemplateParamList=FALSE; + m_hasTemplateParamList=FALSE; +} + +MemberHandler::~MemberHandler() +{ + debug(2,"MemberHandler::~MemberHandler() %p\n",this); + delete m_brief; + delete m_detailed; + delete m_inbody; + delete m_linkedTextHandler; + delete m_reimplements; +} + +void MemberHandler::startMember(const QXmlAttributes& attrib) +{ + m_parent->setDelegate(this); + m_kindString = attrib.value("kind"); + //printf("startMember kindString=`%s'\n",m_kindString.data()); + m_kind = s_typeMap->map(m_kindString); + m_id = attrib.value("id"); + m_protection = attrib.value("prot"); + m_isStatic = attrib.value("static")=="yes"; + m_isConst = attrib.value("const")=="yes"; + m_isExplicit = attrib.value("explicit")=="yes"; + m_isInline = attrib.value("inline")=="yes"; + m_virtualness = attrib.value("virt"); + m_isVolatile = attrib.value("volatile")=="yes"; + m_isMutable = attrib.value("mutable")=="yes"; + m_isReadable = attrib.value("readable")=="yes"; + m_isWritable = attrib.value("writable")=="yes"; + + debug(2,"member kind=`%s' id=`%s' prot=`%s' virt=`%s'\n", + m_kindString.data(),m_id.data(),m_protection.data(),m_virtualness.data()); +} + +void MemberHandler::startEnumValue(const QXmlAttributes& attrib) +{ + m_parent->setDelegate(this); + m_kindString = "enumvalue"; + //printf("startEnumValue kindString=`%s'\n",m_kindString.data()); + m_kind = s_typeMap->map(m_kindString); + m_id = attrib.value("id"); + m_protection = attrib.value("prot"); + m_isStatic = FALSE; + m_isConst = FALSE; + m_isExplicit = FALSE; + m_isInline = FALSE; + m_virtualness = "non-virtual"; + m_isVolatile = FALSE; + m_isMutable = FALSE; + m_isReadable = FALSE; + m_isWritable = FALSE; + debug(2,"member kind=`%s' id=`%s' prot=`%s' virt=`%s'\n", + m_kindString.data(),m_id.data(),m_protection.data(),m_virtualness.data()); +} + +void MemberHandler::startEnumValue2(const QXmlAttributes& attrib) +{ + MemberHandler *mh = new MemberHandler(this); + mh->startEnumValue(attrib); + m_enumValues.append(mh); +} + + +void MemberHandler::startBriefDesc(const QXmlAttributes& attrib) +{ + DocHandler *docHandler = new DocHandler(this); + docHandler->startDoc(attrib); + m_brief = docHandler; +} + +void MemberHandler::startDetailedDesc(const QXmlAttributes& attrib) +{ + DocHandler *docHandler = new DocHandler(this); + docHandler->startDoc(attrib); + m_detailed = docHandler; +} + +void MemberHandler::startInbodyDesc(const QXmlAttributes& attrib) +{ + DocHandler *docHandler = new DocHandler(this); + docHandler->startDoc(attrib); + m_inbody = docHandler; +} + +void MemberHandler::startLocation(const QXmlAttributes& attrib) +{ + m_defFile = attrib.value("file"); + m_bodyFile = attrib.value("bodyfile"); + QCString s; + s = attrib.value("line"); + if (!s.isEmpty()) m_defLine=s.toInt(); + s = attrib.value("bodystart"); + if (!s.isEmpty()) m_bodyStart=s.toInt(); + s = attrib.value("bodyend"); + if (!s.isEmpty()) m_bodyEnd=s.toInt(); +} + +void MemberHandler::startReferences(const QXmlAttributes& attrib) +{ + MemberReference *mr = new MemberReference; + mr->m_memId = attrib.value("refid"); + m_references.append(mr); + m_curString=""; +} + +void MemberHandler::endReferences() +{ + m_references.getLast()->m_name = m_curString; +} + +void MemberHandler::startReferencedBy(const QXmlAttributes& attrib) +{ + MemberReference *mr = new MemberReference; + mr->m_memId = attrib.value("refid"); + m_referencedBy.append(mr); + m_curString=""; +} + +void MemberHandler::endReferencedBy() +{ + m_referencedBy.getLast()->m_name = m_curString; +} + +void MemberHandler::startReimplements(const QXmlAttributes& attrib) +{ + m_reimplements = new MemberReference; + m_reimplements->m_memId = attrib.value("refid"); + m_curString=""; +} + +void MemberHandler::endReimplements() +{ + m_reimplements->m_name = m_curString; +} + +void MemberHandler::startReimplementedBy(const QXmlAttributes& attrib) +{ + MemberReference *mr = new MemberReference; + mr->m_memId = attrib.value("refid"); + m_reimplementedBy.append(mr); + m_curString=""; +} + +void MemberHandler::endReimplementedBy() +{ + m_reimplementedBy.getLast()->m_name = m_curString; +} + +void MemberHandler::endMember() +{ + m_parent->setDelegate(0); +} + +void MemberHandler::startType(const QXmlAttributes &) +{ + debug(2,"startType!\n"); + delete m_linkedTextHandler; + m_linkedTextHandler = new LinkedTextHandler(this,m_type); + m_linkedTextHandler->start("type"); +} + +void MemberHandler::startInitializer(const QXmlAttributes &) +{ + debug(2,"startInitializer!\n"); + delete m_linkedTextHandler; + m_linkedTextHandler = new LinkedTextHandler(this,m_initializer); + m_linkedTextHandler->start("initializer"); +} + +void MemberHandler::startException(const QXmlAttributes &) +{ + debug(2,"startException!\n"); + delete m_linkedTextHandler; + m_linkedTextHandler = new LinkedTextHandler(this,m_exception); + m_linkedTextHandler->start("exceptions"); +} + +void MemberHandler::startName(const QXmlAttributes &) +{ + m_curString=""; +} + +void MemberHandler::endName() +{ + m_name = m_curString.stripWhiteSpace(); + debug(2,"member name=`%s'\n",m_name.data()); +} + +void MemberHandler::startRead(const QXmlAttributes &) +{ + m_curString=""; +} + +void MemberHandler::endRead() +{ + m_read = m_curString.stripWhiteSpace(); + debug(2,"member read=`%s'\n",m_read.data()); +} + +void MemberHandler::startWrite(const QXmlAttributes &) +{ + m_curString=""; +} + +void MemberHandler::endWrite() +{ + m_write = m_curString.stripWhiteSpace(); + debug(2,"member write=`%s'\n",m_write.data()); +} + +void MemberHandler::startDefinition(const QXmlAttributes&) +{ + m_curString=""; +} + +void MemberHandler::endDefinition() +{ + m_definition = m_curString.stripWhiteSpace(); + debug(2,"definition=%s\n",m_definition.data()); +} + +void MemberHandler::startArgsString(const QXmlAttributes&) +{ + m_curString=""; +} + +void MemberHandler::endArgsString() +{ + m_argsstring = m_curString.stripWhiteSpace(); + debug(2,"arggstring=%s\n",m_argsstring.data()); +} + +void MemberHandler::startParam(const QXmlAttributes& attrib) +{ + ParamHandler *paramHandler = new ParamHandler(this); + paramHandler->startParam(attrib); + if (m_insideTemplateParamList) + { + m_templateParams.append(paramHandler); + } + else + { + m_params.append(paramHandler); + } +} + +void MemberHandler::startTemplateParamList(const QXmlAttributes&) +{ + m_insideTemplateParamList = TRUE; + m_hasTemplateParamList = TRUE; +} + +void MemberHandler::endTemplateParamList() +{ + m_insideTemplateParamList = FALSE; +} + +void MemberHandler::initialize(MainHandler *mh) +{ + { + QListIterator mli(m_references); + MemberReference *mr; + for (;(mr=mli.current());++mli) + { + mr->initialize(mh); + } + } + { + QListIterator mli(m_referencedBy); + MemberReference *mr; + for (;(mr=mli.current());++mli) + { + mr->initialize(mh); + } + } + { + QListIterator mli(m_reimplementedBy); + MemberReference *mr; + for (;(mr=mli.current());++mli) + { + mr->initialize(mh); + } + } + if (m_reimplements) m_reimplements->initialize(mh); +} + +void MemberHandler::setCompoundHandler(CompoundHandler *c) +{ + m_compound = c; +} + +ICompound *MemberHandler::compound() const +{ + m_compound->addref(); + return m_compound->toICompound(); +} + +void MemberHandler::setSectionHandler(SectionHandler *c) +{ + m_section = c; +} + +ISection *MemberHandler::section() const +{ + return m_section; +} + +IMemberIterator *MemberHandler::enumValues() const +{ + return new MemberIterator(m_enumValues); +} + +ILinkedTextIterator *MemberHandler::type() const +{ + return new LinkedTextIterator(m_type); +} + +const IString *MemberHandler::typeString() const +{ + MemberHandler *that = (MemberHandler *)this; + that->m_typeString = LinkedTextHandler::toString(m_type); + return &m_typeString; +} + +IParamIterator *MemberHandler::parameters() const +{ + return new ParamIterator(m_params); +} + +IParamIterator *MemberHandler::templateParameters() const +{ + return m_hasTemplateParamList ? new ParamIterator(m_templateParams) : 0; +} + +IMemberReferenceIterator *MemberHandler::references() const +{ + return new MemberReferenceIterator(m_references); +} + +IMemberReferenceIterator *MemberHandler::referencedBy() const +{ + return new MemberReferenceIterator(m_referencedBy); +} + +ILinkedTextIterator *MemberHandler::initializer() const +{ + return new LinkedTextIterator(m_initializer); +} + +ILinkedTextIterator *MemberHandler::exceptions() const +{ + return new LinkedTextIterator(m_exception); +} + +IMemberReferenceIterator *MemberHandler::reimplementedBy() const +{ + return new MemberReferenceIterator(m_reimplementedBy); +} + +IDocRoot *MemberHandler::briefDescription() const +{ + return m_brief; +} + +IDocRoot *MemberHandler::detailedDescription() const +{ + return m_detailed; +} + +IDocRoot *MemberHandler::inbodyDescription() const +{ + return m_inbody; +} + diff --git a/trunk/addon/doxmlparser/src/memberhandler.h b/trunk/addon/doxmlparser/src/memberhandler.h new file mode 100644 index 0000000..f80a4eb --- /dev/null +++ b/trunk/addon/doxmlparser/src/memberhandler.h @@ -0,0 +1,252 @@ +/****************************************************************************** + * + * $Id$ + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#ifndef _MEMBERHANDLER_H +#define _MEMBERHANDLER_H + +#include +#include +#include +#include + +#include "basehandler.h" +#include "baseiterator.h" +#include "stringimpl.h" + +class MainHandler; +class CompoundHandler; +class SectionHandler; +class ParamHandler; +class LinkedTextImpl; +class LinkedTextHandler; +class DocHandler; + +class MemberReference : public IMemberReference +{ + public: + virtual ~MemberReference() {} + virtual IMember *member() const; + virtual const IString *name() const { return &m_name; } + virtual const IString *scope() const { return &m_scope; } + virtual const IString *protection() const { return &m_protection; } + virtual const IString *virtualness() const { return &m_virtualness; } + virtual const IString *ambiguityScope() const { return &m_ambiguityScope; } + void initialize(MainHandler *m); + + QString m_memId; + StringImpl m_name; + StringImpl m_scope; + StringImpl m_virtualness; + StringImpl m_protection; + StringImpl m_ambiguityScope; + MainHandler *m_mainHandler; +}; + +class MemberReferenceIterator : public BaseIterator +{ + public: + MemberReferenceIterator(const QList &list) : + BaseIterator(list) {} +}; + +class MemberHandler : public IDefine, + public IProperty, + public IVariable, + public ITypedef, + public IFunction, + public ISignal, + public IPrototype, + public IFriend, + public IDCOP, + public ISlot, + public IEnum, + public IEnumValue, + public BaseHandler +{ + public: + virtual void startMember(const QXmlAttributes& attrib); + virtual void endMember(); + virtual void startParam(const QXmlAttributes& attrib); + virtual void startType(const QXmlAttributes& attrib); + virtual void startName(const QXmlAttributes& attrib); + virtual void endName(); + virtual void startRead(const QXmlAttributes& attrib); + virtual void endRead(); + virtual void startWrite(const QXmlAttributes& attrib); + virtual void endWrite(); + virtual void startDefinition(const QXmlAttributes& attrib); + virtual void endDefinition(); + virtual void startArgsString(const QXmlAttributes& attrib); + virtual void endArgsString(); + virtual void startBriefDesc(const QXmlAttributes& attrib); + virtual void startDetailedDesc(const QXmlAttributes& attrib); + virtual void startInbodyDesc(const QXmlAttributes& attrib); + virtual void startLocation(const QXmlAttributes& attrib); + virtual void startReferences(const QXmlAttributes& attrib); + virtual void endReferences(); + virtual void startReferencedBy(const QXmlAttributes& attrib); + virtual void endReferencedBy(); + virtual void startReimplements(const QXmlAttributes& attrib); + virtual void endReimplements(); + virtual void startReimplementedBy(const QXmlAttributes& attrib); + virtual void endReimplementedBy(); + virtual void startInitializer(const QXmlAttributes& attrib); + virtual void startException(const QXmlAttributes& attrib); + virtual void startEnumValue(const QXmlAttributes& attrib); + virtual void startEnumValue2(const QXmlAttributes& attrib); + virtual void startTemplateParamList(const QXmlAttributes &attrib); + virtual void endTemplateParamList(); + + MemberHandler(IBaseHandler *parent); + virtual ~MemberHandler(); + + // IMember implementation + virtual ICompound *compound() const; + virtual ISection *section() const; + virtual MemberKind kind() const + { return m_kind; } + virtual const IString *kindString() const + { return &m_kindString; } + virtual const IString *id() const + { return &m_id; } + virtual const IString *protection() const + { return &m_protection; } + virtual const IString *virtualness() const + { return &m_virtualness; } + virtual const IString *name() const + { return &m_name; } + virtual const IString *readAccessor() const + { return &m_read; } + virtual const IString *writeAccessor() const + { return &m_write; } + virtual const IString *definition() const + { return &m_definition; } + virtual const IString *argsstring() const + { return &m_argsstring; } + virtual bool isConst() const + { return m_isConst; } + virtual bool isVolatile() const + { return m_isVolatile; } + virtual bool isStatic() const + { return m_isStatic; } + virtual bool isExplicit() const + { return m_isExplicit; } + virtual bool isInline() const + { return m_isInline; } + virtual bool isMutable() const + { return m_isMutable; } + virtual bool isReadable() const + { return m_isReadable; } + virtual bool isWritable() const + { return m_isWritable; } + virtual ILinkedTextIterator *type() const; + virtual const IString *typeString() const; + virtual IParamIterator *parameters() const; + virtual IParamIterator *templateParameters() const; + virtual IMemberReferenceIterator *references() const; + virtual IMemberReferenceIterator *referencedBy() const; + virtual ILinkedTextIterator *initializer() const; + virtual ILinkedTextIterator *exceptions() const; + virtual const IString *bodyFile() const + { return &m_bodyFile; } + virtual int bodyStart() const + { return m_bodyStart; } + virtual int bodyEnd() const + { return m_bodyEnd; } + virtual const IString *definitionFile() const + { return &m_defFile; } + virtual int definitionLine() const + { return m_defLine; } + virtual IMemberReference *reimplements() const + { return m_reimplements; } + virtual IMemberReferenceIterator *reimplementedBy() const; + virtual IDocRoot *briefDescription() const; + virtual IDocRoot *detailedDescription() const; + virtual IDocRoot *inbodyDescription() const; + + // IEnum + virtual IMemberIterator *enumValues() const; + + void initialize(MainHandler *m); + void setCompoundHandler(CompoundHandler *c); + void setSectionHandler(SectionHandler *s); + + private: + // XML elements: + // ----------------- + QList m_templateParams; // templateparamlist + QList m_type; // type + StringImpl m_definition; // definition + StringImpl m_argsstring; // argsstring + StringImpl m_name; // name + StringImpl m_read; // read + StringImpl m_write; // write + MemberReference *m_reimplements; // reimplements + QList m_reimplementedBy; // reimplementedby + QList m_params; // param + QList m_enumValues; // enumvalue + QList m_initializer; // initializer + QList m_exception; // exceptions + DocHandler *m_brief; // briefdescription + DocHandler *m_detailed; // detaileddescription + DocHandler *m_inbody; // inbodydescription + // location + StringImpl m_defFile; // - file + int m_defLine; // - line + StringImpl m_bodyFile; // - bodyfile + int m_bodyStart; // - bodystart + int m_bodyEnd; // - bodyend + QList m_references; // references + QList m_referencedBy; // referencedby + + // XML attributes: + // --------------- + MemberKind m_kind; // kind + StringImpl m_kindString; // kind as a string + StringImpl m_id; // id + StringImpl m_protection; // prot + bool m_isStatic; // static + bool m_isConst; // const + bool m_isExplicit; // explicit + bool m_isInline; // inline + StringImpl m_virtualness; // virt + bool m_isVolatile; // volatile + bool m_isMutable; // mutable + bool m_isReadable; // readable + bool m_isWritable; // writable + + CompoundHandler *m_compound; + SectionHandler *m_section; + StringImpl m_typeString; + LinkedTextHandler *m_linkedTextHandler; + bool m_insideTemplateParamList; + bool m_hasTemplateParamList; + IBaseHandler *m_parent; +}; + +class MemberIterator : public BaseIteratorVia +{ + public: + MemberIterator(const QList &list) : + BaseIteratorVia(list) {} +}; + +void memberhandler_init(); +void memberhandler_exit(); + +#endif diff --git a/trunk/addon/doxmlparser/src/paramhandler.cpp b/trunk/addon/doxmlparser/src/paramhandler.cpp new file mode 100644 index 0000000..124fde0 --- /dev/null +++ b/trunk/addon/doxmlparser/src/paramhandler.cpp @@ -0,0 +1,158 @@ +/****************************************************************************** + * + * $Id$ + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#include "paramhandler.h" +#include "memberhandler.h" +#include "linkedtexthandler.h" +#include "debug.h" +#include "dochandler.h" + +TemplateParamListHandler::TemplateParamListHandler(IBaseHandler *parent) : m_parent(parent) +{ + addStartHandler("param",this,&TemplateParamListHandler::startParam); + + addEndHandler("templateparamlist",this,&TemplateParamListHandler::endTemplateParamList); +} + +void TemplateParamListHandler::startParam(const QXmlAttributes& attrib) +{ + ParamHandler *ph = new ParamHandler(this); + ph->startParam(attrib); + m_templateParams.append(ph); +} + +void TemplateParamListHandler::endParam() +{ +} + +void TemplateParamListHandler::startTemplateParamList(const QXmlAttributes& /*attrib*/) +{ + m_parent->setDelegate(this); + debug(2,"templateparamlist\n"); +} + +void TemplateParamListHandler::endTemplateParamList() +{ + m_parent->setDelegate(0); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////// + +ParamHandler::ParamHandler(IBaseHandler *parent) : m_brief(0), m_parent(parent) +{ + addEndHandler("param",this,&ParamHandler::endParam); + + addStartHandler("type",this,&ParamHandler::startType); + + addStartHandler("declname"); + addEndHandler("declname",this,&ParamHandler::endDeclName); + + addStartHandler("defname"); + addEndHandler("defname",this,&ParamHandler::endDefName); + + addStartHandler("array"); + addEndHandler("array",this,&ParamHandler::endArray); + + addStartHandler("attribute"); + addEndHandler("attribute",this,&ParamHandler::endAttrib); + + addStartHandler("briefdescription",this,&ParamHandler::startBriefDesc); + + addStartHandler("defval",this,&ParamHandler::startDefVal); + + m_linkedTextHandler = 0; +} + +ParamHandler::~ParamHandler() +{ + delete m_brief; + delete m_linkedTextHandler; +} + +void ParamHandler::startParam(const QXmlAttributes& /*attrib*/) +{ + m_parent->setDelegate(this); + debug(2,"param\n"); +} + +void ParamHandler::endParam() +{ + m_parent->setDelegate(0); +} + +void ParamHandler::startType(const QXmlAttributes& /*attrib*/) +{ + delete m_linkedTextHandler; + m_linkedTextHandler = new LinkedTextHandler(this,m_type); + m_linkedTextHandler->start("type"); + debug(2,"param type\n"); +} + +void ParamHandler::endDeclName() +{ + m_declName = m_curString.stripWhiteSpace(); + debug(2,"member declName=`%s'\n",m_declName.data()); +} + +void ParamHandler::endDefName() +{ + m_defName = m_curString.stripWhiteSpace(); + debug(2,"member defName=`%s'\n",m_defName.data()); +} + +void ParamHandler::endAttrib() +{ + m_attrib = m_curString.stripWhiteSpace(); + debug(2,"member attrib=`%s'\n",m_attrib.data()); +} + +void ParamHandler::endArray() +{ + m_array = m_curString.stripWhiteSpace(); + debug(2,"member array=`%s'\n",m_array.data()); +} + +void ParamHandler::startDefVal(const QXmlAttributes& /*attrib*/) +{ + delete m_linkedTextHandler; + m_linkedTextHandler = new LinkedTextHandler(this,m_defVal); + m_linkedTextHandler->start("defval"); + debug(2,"member defVal\n"); +} + +void ParamHandler::startBriefDesc(const QXmlAttributes& attrib) +{ + DocHandler *docHandler = new DocHandler(this); + docHandler->startDoc(attrib); + m_brief = docHandler; +} + +ILinkedTextIterator *ParamHandler::type() const +{ + return new LinkedTextIterator(m_type); +} + +ILinkedTextIterator *ParamHandler::defaultValue() const +{ + return new LinkedTextIterator(m_defVal); +} + +IDocRoot *ParamHandler::briefDescription() const +{ + return m_brief; +} + + + diff --git a/trunk/addon/doxmlparser/src/paramhandler.h b/trunk/addon/doxmlparser/src/paramhandler.h new file mode 100644 index 0000000..64b89a2 --- /dev/null +++ b/trunk/addon/doxmlparser/src/paramhandler.h @@ -0,0 +1,103 @@ +/****************************************************************************** + * + * $Id$ + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#ifndef _PARAMHANDLER_H +#define _PARAMHANDLER_H + +#include +#include +#include +#include + +#include "stringimpl.h" +#include "basehandler.h" +#include "baseiterator.h" + +class LinkedTextImpl; +class LinkedTextHandler; +class DocHandler; + + +class ParamHandler : public IParam, public BaseHandler +{ + public: + virtual void startParam(const QXmlAttributes& attrib); + virtual void endParam(); + virtual void startType(const QXmlAttributes& attrib); + virtual void endDeclName(); + virtual void endDefName(); + virtual void endAttrib(); + virtual void endArray(); + virtual void startDefVal(const QXmlAttributes& attrib); + virtual void startBriefDesc(const QXmlAttributes& attrib); + + ParamHandler(IBaseHandler *parent); + virtual ~ParamHandler(); + + // IParam + virtual ILinkedTextIterator *type() const; + virtual const IString * declarationName() const { return &m_declName; } + virtual const IString * definitionName() const { return &m_defName; } + virtual const IString * attrib() const { return &m_attrib; } + virtual const IString * arraySpecifier() const { return &m_array; } + virtual ILinkedTextIterator *defaultValue() const; + virtual IDocRoot *briefDescription() const; + + private: + + // XML elements: + // ------------- + QList m_type; // type + StringImpl m_declName; // declname + StringImpl m_defName; // defname + StringImpl m_array; // array + QList m_defVal; // defval + DocHandler *m_brief; // briefdescription + + StringImpl m_attrib; // TODO: not yet in XML output + + IBaseHandler *m_parent; + LinkedTextHandler *m_linkedTextHandler; +}; + +class ParamIterator : public BaseIterator +{ + public: + ParamIterator(const QList &list) : + BaseIterator(list) {} +}; + +class TemplateParamListHandler : public BaseHandler +{ + public: + + virtual void startParam(const QXmlAttributes& attrib); + virtual void endParam(); + + virtual void startTemplateParamList(const QXmlAttributes& attrib); + virtual void endTemplateParamList(); + + TemplateParamListHandler(IBaseHandler *parent); + virtual ~TemplateParamListHandler() {} + + ParamIterator* templateParams() { return new ParamIterator(m_templateParams); } + + protected: + IBaseHandler *m_parent; + QList m_templateParams; +}; + + +#endif diff --git a/trunk/addon/doxmlparser/src/sectionhandler.cpp b/trunk/addon/doxmlparser/src/sectionhandler.cpp new file mode 100644 index 0000000..f9bf147 --- /dev/null +++ b/trunk/addon/doxmlparser/src/sectionhandler.cpp @@ -0,0 +1,168 @@ +/****************************************************************************** + * + * $Id$ + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#include "mainhandler.h" +#include "compoundhandler.h" +#include "sectionhandler.h" +#include "memberhandler.h" +#include "dochandler.h" +#include "debug.h" + +class SectionTypeMap +{ + public: + SectionTypeMap() : m_map(37) + { + m_map.setAutoDelete(TRUE); + m_map.insert("user-defined",new int(ISection::UserDefined)); + m_map.insert("public-type",new int(ISection::PubTypes)); + m_map.insert("public-func",new int(ISection::PubFuncs)); + m_map.insert("public-attrib",new int(ISection::PubAttribs)); + m_map.insert("public-slot",new int(ISection::PubSlots)); + m_map.insert("signal",new int(ISection::Signals)); + m_map.insert("dcop-func",new int(ISection::DCOPFuncs)); + m_map.insert("property",new int(ISection::Properties)); + m_map.insert("event",new int(ISection::Events)); + m_map.insert("public-static-func",new int(ISection::PubStatFuncs)); + m_map.insert("public-static-attrib",new int(ISection::PubStatAttribs)); + m_map.insert("protected-type",new int(ISection::ProTypes)); + m_map.insert("protected-func",new int(ISection::ProFuncs)); + m_map.insert("protected-attrib",new int(ISection::ProAttribs)); + m_map.insert("protected-slot",new int(ISection::ProSlots)); + m_map.insert("protected-static-func",new int(ISection::ProStatFuncs)); + m_map.insert("protected-static-attrib",new int(ISection::ProStatAttribs)); + m_map.insert("package-type",new int(ISection::PacTypes)); + m_map.insert("package-func",new int(ISection::PacFuncs)); + m_map.insert("package-attrib",new int(ISection::PacAttribs)); + m_map.insert("package-static-func",new int(ISection::PacStatFuncs)); + m_map.insert("package-static-attrib",new int(ISection::PacStatAttribs)); + m_map.insert("private-type",new int(ISection::PriTypes)); + m_map.insert("private-func",new int(ISection::PriFuncs)); + m_map.insert("private-attrib",new int(ISection::PriAttribs)); + m_map.insert("private-slot",new int(ISection::PriSlots)); + m_map.insert("private-static-func",new int(ISection::PriStatFuncs)); + m_map.insert("private-static-attrib",new int(ISection::PriStatAttribs)); + m_map.insert("friend",new int(ISection::Friend)); + m_map.insert("related",new int(ISection::Related)); + m_map.insert("define",new int(ISection::Defines)); + m_map.insert("prototype",new int(ISection::Prototypes)); + m_map.insert("typedef",new int(ISection::Typedefs)); + m_map.insert("enum",new int(ISection::Enums)); + m_map.insert("func",new int(ISection::Functions)); + m_map.insert("var",new int(ISection::Variables)); + } + ISection::SectionKind map(const QString &s) + { + int *val = m_map.find(s); + if (val==0) + { + debug(1,"Warning: `%s' is an invalid section type\n",s.data()); + return ISection::Invalid; + } + else return (ISection::SectionKind)*val; + } + private: + QDict m_map; +}; + +static SectionTypeMap *s_typeMap; + +void sectionhandler_init() +{ + s_typeMap = new SectionTypeMap; +} + +void sectionhandler_exit() +{ + delete s_typeMap; +} + +SectionHandler::SectionHandler(IBaseHandler *parent) : m_parent(parent) +{ + //printf("SectionHandler::SectionHandler()\n"); + m_members.setAutoDelete(TRUE); + addEndHandler("sectiondef",this,&SectionHandler::endSection); + addStartHandler("memberdef",this,&SectionHandler::startMember); + addStartHandler("header",this,&SectionHandler::startHeader); + addEndHandler("header",this,&SectionHandler::endHeader); + addStartHandler("description",this,&SectionHandler::startDescription); +} + +SectionHandler::~SectionHandler() +{ + debug(2,"SectionHandler::~SectionHandler()\n"); +} + +void SectionHandler::startSection(const QXmlAttributes& attrib) +{ + m_parent->setDelegate(this); + m_kindString = attrib.value("kind"); + m_kind = s_typeMap->map(m_kindString); + debug(2,"section kind=`%s'\n",m_kindString.data()); +} + +void SectionHandler::startDescription(const QXmlAttributes& attrib) +{ + DocHandler *docHandler = new DocHandler(this); + docHandler->startDoc(attrib); + m_description = docHandler; +} + +void SectionHandler::endSection() +{ + m_parent->setDelegate(0); +} + +void SectionHandler::startMember(const QXmlAttributes& attrib) +{ + MemberHandler *memHandler = new MemberHandler(this); + memHandler->startMember(attrib); + m_members.append(memHandler); +} + +void SectionHandler::startHeader(const QXmlAttributes&) +{ + m_header=""; + m_curString=""; +} + +void SectionHandler::endHeader() +{ + m_header = m_curString.stripWhiteSpace(); + debug(2,"member header=`%s'\n",m_header.data()); +} + +void SectionHandler::initialize(CompoundHandler *ch) +{ + QListIterator mli(m_members); + MemberHandler *mh; + for (;(mh=mli.current());++mli) + { + mh->setCompoundHandler(ch); + ch->insertMember(mh); + mh->setSectionHandler(this); + } +} + +IDocRoot *SectionHandler::description() const +{ + return m_description; +} + +IMemberIterator *SectionHandler::members() const +{ + return new MemberIterator(m_members); +} + diff --git a/trunk/addon/doxmlparser/src/sectionhandler.h b/trunk/addon/doxmlparser/src/sectionhandler.h new file mode 100644 index 0000000..86aad3b --- /dev/null +++ b/trunk/addon/doxmlparser/src/sectionhandler.h @@ -0,0 +1,102 @@ +/****************************************************************************** + * + * $Id$ + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#ifndef _SECTIONHANDLER_H +#define _SECTIONHANDLER_H + +#include +#include +#include +#include + +#include "basehandler.h" + +class SectionIterator : + public BaseIterator +{ + public: + SectionIterator(const QList &list) : + BaseIterator(list) {} +}; + + +class SectionHandler : public IUserDefined, public BaseHandler +{ + public: + virtual void startMember(const QXmlAttributes& attrib); + virtual void startHeader(const QXmlAttributes& attrib); + virtual void startSection(const QXmlAttributes& attrib); + virtual void startDescription(const QXmlAttributes& attrib); + virtual void endSection(); + virtual void endHeader(); + + SectionHandler(IBaseHandler *parent); + virtual ~SectionHandler(); + + // ISection + virtual const IString *kindString() const + { return &m_kindString; } + virtual SectionKind kind() const + { return m_kind; } + IDocRoot *description() const; + virtual IMemberIterator *members() const; + virtual bool isStatic() const + { + return m_kind==PubStatFuncs || m_kind==PubStatAttribs || + m_kind==ProStatFuncs || m_kind==ProStatAttribs || + m_kind==PriStatFuncs || m_kind==PriStatAttribs; + } + virtual bool isPublic() const + { + return !isProtected() && !isPrivate(); + } + virtual bool isProtected() const + { + return m_kind==ProTypes || m_kind==ProFuncs || m_kind==ProAttribs || + m_kind==ProSlots || m_kind==ProStatFuncs || m_kind==ProStatAttribs; + } + virtual bool isPrivate() const + { + return m_kind==PriTypes || m_kind==PriFuncs || m_kind==PriAttribs || + m_kind==PriSlots || m_kind==PriStatFuncs || m_kind==PriStatAttribs; + } + + void initialize(CompoundHandler *c); + + // IUserDefined implementation + virtual const IString *header() const + { + return &m_header; + } + + private: + IBaseHandler *m_parent; + + // XML elements: + // ------------- + StringImpl m_header; // header + DocHandler* m_description; // description + QList m_members; // memberdef + + // XML attributes: + // --------------- + SectionKind m_kind; // kind + StringImpl m_kindString; // kind as a string +}; + +void sectionhandler_init(); +void sectionhandler_exit(); + +#endif diff --git a/trunk/addon/doxmlparser/src/stringimpl.h b/trunk/addon/doxmlparser/src/stringimpl.h new file mode 100644 index 0000000..013858f --- /dev/null +++ b/trunk/addon/doxmlparser/src/stringimpl.h @@ -0,0 +1,30 @@ +#ifndef STRINGIMPL_H +#define STRINGIMPL_H + +#include +#include "doxmlintf.h" + +class StringImpl : public QString, public IString +{ + public: + StringImpl() {} + StringImpl(const QString &str) : QString(str) {} + StringImpl &operator=(const QString &str) + { QString::operator=(str); return *this; } + virtual ~StringImpl() {} + + // IString + const char *latin1() const + { return QString::latin1(); } + const char *utf8() const + { return QString::utf8(); } + unsigned short unicodeCharAt(int index) const + { return QString::unicode()[index].unicode(); } + bool isEmpty() const + { return QString::isEmpty(); } + int length() const + { return QString::length(); } +}; + +#endif + diff --git a/trunk/addon/doxmlparser/test/Makefile.in b/trunk/addon/doxmlparser/test/Makefile.in new file mode 100644 index 0000000..1dfbd17 --- /dev/null +++ b/trunk/addon/doxmlparser/test/Makefile.in @@ -0,0 +1,13 @@ +all clean depend: Makefile.xmlparse + $(MAKE) -f Makefile.xmlparse $@ + +distclean: clean + $(RM) -rf Makefile.xmlparse xmlparse.pro Makefile obj + +tmake: + $(ENV) $(PERL) $(TMAKE) xmlparse.pro >Makefile.xmlparse + +Makefile.xmlparse: xmlparse.pro + $(ENV) $(PERL) $(TMAKE) xmlparse.pro >Makefile.xmlparse + +install: diff --git a/trunk/addon/doxmlparser/test/main.cpp b/trunk/addon/doxmlparser/test/main.cpp new file mode 100644 index 0000000..5f37c81 --- /dev/null +++ b/trunk/addon/doxmlparser/test/main.cpp @@ -0,0 +1,759 @@ +/****************************************************************************** + * + * $Id$ + * + * + * Copyright (C) 1997-2006 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. + * + */ + +#include +#include +#include +#include + +/*! Dumps the contents of a hyperlinked text fragment as plain text to the + * output. + */ +QString linkedTextToString(ILinkedTextIterator *ti) +{ + QString result; + ILinkedText *lt=0; + for (ti->toFirst();(lt=ti->current());ti->toNext()) + { + switch (lt->kind()) + { + case ILinkedText::Kind_Text: // plain text + result+=dynamic_cast(lt)->text()->latin1(); break; + case ILinkedText::Kind_Ref: // a link + result+=dynamic_cast(lt)->text()->latin1(); break; + } + } + return result; +} + +/*! Macro for printing an indented message. */ +#define InPrint(x) printf("%s",indent.latin1()), printf x; + +/*! Dumps the contents of a documentation block to stdout. + * @note This function will call itself recursively. + * @param doc The root of the documentation tree. + * @param level The indent level. + */ +void DumpDoc(IDoc *doc,int level) +{ + if (doc==0) return; + QString indent; + indent.fill(' ',level); + //printf(" doc node kind=`%d'\n",doc->kind()); + switch (doc->kind()) + { + case IDoc::Para: + { + InPrint(("\n")); + IDocPara *par = dynamic_cast(doc); + ASSERT(par!=0); + IDocIterator *di = par->contents(); + IDoc *pdoc; + for (di->toFirst();(pdoc=di->current());di->toNext()) + { + DumpDoc(pdoc,level+1); + } + di->release(); + InPrint(("\n")); + } + break; + case IDoc::Text: + { + IDocText *txt = dynamic_cast(doc); + ASSERT(txt!=0); + InPrint(("\n", + txt->text()->latin1(),txt->markup(),txt->headingLevel())); + } + break; + case IDoc::MarkupModifier: + { + IDocMarkupModifier *md = dynamic_cast(doc); + ASSERT(md!=0); + InPrint(("\n", + md->enabled(),md->markup(),md->headingLevel())); + } + break; + case IDoc::ItemizedList: + { + InPrint(("\n")); + IDocItemizedList *list = dynamic_cast(doc); + ASSERT(list!=0); + IDocIterator *di = list->elements(); + IDoc *pdoc; + for (di->toFirst();(pdoc=di->current());di->toNext()) + { + DumpDoc(pdoc,level+1); + } + di->release(); + InPrint(("\n")); + } + break; + case IDoc::OrderedList: + { + InPrint(("\n")); + IDocOrderedList *list = dynamic_cast(doc); + ASSERT(list!=0); + IDocIterator *di = list->elements(); + IDoc *pdoc; + for (di->toFirst();(pdoc=di->current());di->toNext()) + { + DumpDoc(pdoc,level+1); + } + di->release(); + InPrint(("\n")); + } + break; + case IDoc::ListItem: + { + InPrint(("\n")); + IDocListItem *li = dynamic_cast(doc); + ASSERT(li!=0); + IDocIterator *di = li->contents(); + IDoc *pdoc; + for (di->toFirst();(pdoc=di->current());di->toNext()) + { + DumpDoc(pdoc,level+1); + } + di->release(); + InPrint(("\n")); + } + break; + case IDoc::ParameterItem: + { + IDocParameterItem *item = dynamic_cast(doc); + InPrint(("\n")); + IDocIterator *di = item->paramNames(); + IDoc *pdoc; + for (di->toFirst();(pdoc=di->current());di->toNext()) + { + DumpDoc(pdoc,level+1); + } + di->release(); + DumpDoc(item->description(),level+1); + InPrint(("\n")); + } + break; + case IDoc::ParameterList: + { + IDocParameterList *list = dynamic_cast(doc); + InPrint(("\n",list->sectType())); + IDocIterator *di = list->params(); + IDoc *pdoc; + for (di->toFirst();(pdoc=di->current());di->toNext()) + { + DumpDoc(pdoc,level+1); + } + di->release(); + InPrint(("\n")); + ASSERT(list!=0); + } + break; + case IDoc::Parameter: + { + IDocParameter *par = dynamic_cast(doc); + ASSERT(par!=0); + InPrint(("\n",par->name()->latin1())); + } + break; + case IDoc::SimpleSect: + { + IDocSimpleSect *ss = dynamic_cast(doc); + ASSERT(ss!=0); + InPrint(("\n",ss->typeString()->latin1())); + DumpDoc(ss->title(),level+1); + DumpDoc(ss->description(),level+1); + InPrint(("\n")); + } + break; + case IDoc::Title: + { + InPrint(("\n")); + IDocTitle *t = dynamic_cast<IDocTitle*>(doc); + ASSERT(t!=0); + IDocIterator *di = t->title(); + IDoc *pdoc; + for (di->toFirst();(pdoc=di->current());di->toNext()) + { + DumpDoc(pdoc,level+1); + } + InPrint(("<title/>\n")); + } + break; + case IDoc::Ref: + { + IDocRef *ref = dynamic_cast<IDocRef*>(doc); + ASSERT(ref!=0); + InPrint(("<ref id=%s text=%s/>\n", + ref->refId()->latin1(),ref->text()->latin1())); + } + break; + case IDoc::VariableList: + { + InPrint(("<variablelist>\n")); + IDocVariableList *vl = dynamic_cast<IDocVariableList*>(doc); + ASSERT(vl!=0); + IDocIterator *di = vl->entries(); + IDoc *pdoc; + for (di->toFirst();(pdoc=di->current());di->toNext()) + { + DumpDoc(pdoc,level+1); + } + di->release(); + InPrint(("<variablelist/>\n")); + } + break; + case IDoc::VariableListEntry: + { + IDocVariableListEntry *vle = dynamic_cast<IDocVariableListEntry*>(doc); + ASSERT(vle!=0); + ILinkedTextIterator *lti = vle->term(); + QString term = linkedTextToString(lti); + lti->release(); + InPrint(("<variablelistentry term=%s>\n",term.latin1())); + DumpDoc(vle->description(),level+1); + InPrint(("<variablelistentry/>\n")); + } + break; + case IDoc::HRuler: + { + IDocHRuler *hr = dynamic_cast<IDocHRuler*>(doc); + ASSERT(hr!=0); + InPrint(("<hruler/>\n")); + } + break; + case IDoc::LineBreak: + { + IDocLineBreak *lb = dynamic_cast<IDocLineBreak*>(doc); + ASSERT(lb!=0); + InPrint(("<linebreak/>\n")); + } + break; + case IDoc::ULink: + { + IDocULink *ul = dynamic_cast<IDocULink*>(doc); + ASSERT(ul!=0); + InPrint(("<ulink url=`%s' text=`%s'/>\n",ul->url()->latin1(),ul->text()->latin1())); + } + break; + case IDoc::EMail: + { + IDocEMail *em = dynamic_cast<IDocEMail*>(doc); + ASSERT(em!=0); + InPrint(("<email address=`%s'/>\n",em->address()->latin1())); + } + break; + case IDoc::Link: + { + IDocLink *lk = dynamic_cast<IDocLink*>(doc); + ASSERT(lk!=0); + InPrint(("<link refid=`%s' text=`%s'/>\n",lk->refId()->latin1(),lk->text()->latin1())); + } + break; + case IDoc::ProgramListing: + { + IDocProgramListing *pl = dynamic_cast<IDocProgramListing*>(doc); + ASSERT(pl!=0); + InPrint(("<programlisting>\n")); + IDocIterator *cli = pl->codeLines(); + IDoc *cl; + for (cli->toFirst();(cl=cli->current());cli->toNext()) + { + DumpDoc(cl,level+1); + } + cli->release(); + InPrint(("</programlisting>\n")); + } + break; + case IDoc::CodeLine: + { + IDocCodeLine *cl = dynamic_cast<IDocCodeLine*>(doc); + ASSERT(cl!=0); + InPrint(("<codeline lineNumber=%d refId=`%s'>\n",cl->lineNumber(),cl->refId()->latin1())); + IDocIterator *cei = cl->codeElements(); + IDoc *ce; + for (cei->toFirst();(ce=cei->current());cei->toNext()) + { + DumpDoc(ce,level+1); + } + cei->release(); + InPrint(("</codeline>\n")); + } + break; + case IDoc::Highlight: + { + IDocHighlight *hl = dynamic_cast<IDocHighlight*>(doc); + ASSERT(hl!=0); + InPrint(("<highlight kind=%d>\n",hl->kind())); + IDocIterator *cei = hl->codeElements(); + IDoc *ce; + for (cei->toFirst();(ce=cei->current());cei->toNext()) + { + DumpDoc(ce,level+1); + } + cei->release(); + InPrint(("</highlight>\n")); + } + break; + case IDoc::Formula: + { + IDocFormula *fm = dynamic_cast<IDocFormula*>(doc); + ASSERT(fm!=0); + InPrint(("<formula id=`%s' text=`%s'/>\n",fm->id()->latin1(),fm->text()->latin1())); + } + break; + case IDoc::Image: + { + IDocImage *img = dynamic_cast<IDocImage*>(doc); + ASSERT(img!=0); + InPrint(("<image name=`%s' caption=`%s'/>\n",img->name()->latin1(),img->caption()->latin1())); + } + break; + case IDoc::DotFile: + { + IDocDotFile *df = dynamic_cast<IDocDotFile*>(doc); + ASSERT(df!=0); + InPrint(("<dotfile name=`%s' caption=`%s'/>\n",df->name()->latin1(),df->caption()->latin1())); + } + break; + case IDoc::IndexEntry: + { + IDocIndexEntry *ie = dynamic_cast<IDocIndexEntry*>(doc); + ASSERT(ie!=0); + InPrint(("<indexentry primary=`%s' secondary=`%s'/>\n",ie->primary()->latin1(),ie->secondary()->latin1())); + } + break; + case IDoc::Table: + { + IDocTable *tbl = dynamic_cast<IDocTable*>(doc); + ASSERT(tbl!=0); + InPrint(("<table numcols=%d caption=`%s'>\n",tbl->numColumns(),tbl->caption()->latin1())); + IDocIterator *ri = tbl->rows(); + IDoc *row; + for (ri->toFirst();(row=ri->current());ri->toNext()) + { + DumpDoc(row,level+1); + } + ri->release(); + InPrint(("</table>\n")); + } + break; + case IDoc::Row: + { + IDocRow *row = dynamic_cast<IDocRow*>(doc); + ASSERT(row!=0); + InPrint(("<row>\n")); + IDocIterator *ei = row->entries(); + IDoc *e; + for (ei->toFirst();(e=ei->current());ei->toNext()) + { + DumpDoc(e,level+1); + } + ei->release(); + InPrint(("</row>\n")); + } + break; + case IDoc::Entry: + { + IDocEntry *ent = dynamic_cast<IDocEntry*>(doc); + ASSERT(ent!=0); + InPrint(("<entry>\n")); + IDocIterator *di = ent->contents(); + IDoc *pdoc; + for (di->toFirst();(pdoc=di->current());di->toNext()) + { + DumpDoc(pdoc,level+1); + } + di->release(); + InPrint(("</entry>\n")); + } + break; + case IDoc::Section: + { + IDocSection *sec = dynamic_cast<IDocSection*>(doc); + ASSERT(sec!=0); + InPrint(("<section id=`%s' level=%d>\n", + sec->id()->latin1(),sec->level())); + DumpDoc(sec->title(),level+1); + IDocIterator *di = sec->paragraphs(); + IDoc *pdoc; + for (di->toFirst();(pdoc=di->current());di->toNext()) + { + DumpDoc(pdoc,level+1); + } + di=sec->subSections(); + for (di->toFirst();(pdoc=di->current());di->toNext()) + { + DumpDoc(pdoc,level+1); + } + IDocInternal *intern = sec->internal(); + if (intern) + { + DumpDoc(intern,level+1); + } + InPrint(("</section>\n")); + } + break; + case IDoc::Internal: + { + IDocInternal *intern = dynamic_cast<IDocInternal*>(doc); + ASSERT(intern!=0); + InPrint(("<internal>\n")); + IDocIterator *di = intern->paragraphs(); + IDoc *pdoc; + for (di->toFirst();(pdoc=di->current());di->toNext()) + { + DumpDoc(pdoc,level+1); + } + di=intern->subSections(); + for (di->toFirst();(pdoc=di->current());di->toNext()) + { + DumpDoc(pdoc,level+1); + } + InPrint(("</internal>\n")); + } + break; + case IDoc::Copy: + { + IDocCopy *cpy = dynamic_cast<IDocCopy*>(doc); + ASSERT(cpy!=0); + InPrint(("<copydoc>\n")); + IDocIterator *di = cpy->contents(); + IDoc *pdoc; + for (di->toFirst();(pdoc=di->current());di->toNext()) + { + DumpDoc(pdoc,level+1); + } + di->release(); + InPrint(("<copydoc/>\n")); + } + break; + case IDoc::TocItem: + { + IDocTocItem *ti = dynamic_cast<IDocTocItem*>(doc); + ASSERT(ti!=0); + InPrint(("<tocitem id=\"%s\" title=\"%s\"/>\n", + ti->id()->latin1(),ti->title()->latin1())); + } + break; + case IDoc::TocList: + { + IDocTocList *tl = dynamic_cast<IDocTocList*>(doc); + ASSERT(tl!=0); + InPrint(("<toclist>\n")); + IDocIterator *di = tl->elements(); + IDoc *pdoc; + for (di->toFirst();(pdoc=di->current());di->toNext()) + { + DumpDoc(pdoc,level+1); + } + di->release(); + InPrint(("<toclist/>\n")); + } + break; + case IDoc::Verbatim: + { + IDocVerbatim *vt = dynamic_cast<IDocVerbatim*>(doc); + ASSERT(vt!=0); + const char *s=0; + switch (vt->type()) + { + case IDocVerbatim::Verbatim: s="verbatim"; break; + case IDocVerbatim::HtmlOnly: s="htmlonly"; break; + case IDocVerbatim::LatexOnly: s="latexonly"; break; + default: + printf("Invalid verbatim type!\n"); + } + InPrint(("<verbatim %s>\n",s)); + InPrint(("%s",vt->text()->latin1())); + InPrint(("</verbatim>\n")); + } + break; + case IDoc::Anchor: + { + IDocAnchor *anc = dynamic_cast<IDocAnchor*>(doc); + ASSERT(anc!=0); + InPrint(("<anchor id='%s'/>\n",anc->id()->latin1())); + } + break; + case IDoc::Symbol: + { + IDocSymbol *sym = dynamic_cast<IDocSymbol*>(doc); + ASSERT(sym!=0); + InPrint(("<symbol type=%s letter=%c/>\n", + sym->typeString()->latin1(),sym->letter())); + } + break; + case IDoc::Root: + { + InPrint(("<root>\n")); + IDocRoot *root = dynamic_cast<IDocRoot*>(doc); + ASSERT(root!=0); + IDocIterator *di = root->contents(); + IDoc *pdoc; + for (di->toFirst();(pdoc=di->current());di->toNext()) + { + DumpDoc(pdoc,level+1); + } + di->release(); + InPrint(("</root>\n")); + } + break; + + default: + printf("Found unsupported node type %d!\n",doc->kind()); + break; + } +} + +void DumpGraph(IGraph *graph) +{ + if (graph==0) { printf(" --- no graph ---\n"); return; } + printf(" --- graph ----\n"); + INodeIterator *ni = graph->nodes(); + INode *node; + for (ni->toFirst();(node=ni->current());ni->toNext()) + { + printf(" --- node id=%s label=%s linkId=%s\n", + node->id()->latin1(), + node->label()->latin1(), + node->linkId()->latin1() + ); + IChildNodeIterator *cni = node->children(); + IChildNode *cn; + for (cni->toFirst();(cn=cni->current());cni->toNext()) + { + printf(" + child id=%s label=%s relation=%s\n", + cn->node()->id()->latin1(), + cn->node()->label()->latin1(), + cn->relationString()->latin1() + ); + IEdgeLabelIterator *eli = cn->edgeLabels(); + IEdgeLabel *el; + for (eli->toFirst();(el=eli->current());eli->toNext()) + { + printf(" edgeLabel=%s\n",el->label()->latin1()); + } + eli->release(); + } + cni->release(); + } + ni->release(); + printf(" --- end graph ----\n"); + +} + +void DumpParamList(IParamIterator *pli,int indent) +{ + QString indentStr; + indentStr.fill(' ',indent); + IParam *par; + for (pli->toFirst();(par=pli->current());pli->toNext()) + { + ILinkedTextIterator *lti = par->type(); + QString parType = linkedTextToString(lti); + lti->release(); + lti = par->defaultValue(); + QString defVal = linkedTextToString(lti); + lti->release(); + printf("%sParam type=%s decl_name=%s def_name=%s defvalue=%s\n", + indentStr.data(), parType.latin1(), + par->declarationName()->latin1(), + par->definitionName()->latin1(), + defVal.latin1()); + } +} + +int main(int argc,char **argv) +{ + if (argc!=2) + { + printf("Usage: %s xmldir\n",argv[0]); + exit(1); + } + + IDoxygen *dox = createObjectModel(); + + dox->setDebugLevel(4); + + if (!dox->readXMLDir(argv[1])) + { + printf("Error reading %s/index.xml\n",argv[1]); + exit(1); + } + + ICompoundIterator *cli = dox->compounds(); + ICompound *comp; + printf("--- compound list ---------\n"); + for (cli->toFirst();(comp=cli->current());cli->toNext()) + { + printf("Compound name=%s id=%s kind=%s\n", + comp->name()->latin1(),comp->id()->latin1(),comp->kindString()->latin1()); + + ISectionIterator *sli = comp->sections(); + ISection *sec; + for (sli->toFirst();(sec=sli->current());sli->toNext()) + { + printf(" Section kind=%s\n",sec->kindString()->latin1()); + IMemberIterator *mli = sec->members(); + IMember *mem; + if( sec->kind() == ISection::UserDefined ) + { + IUserDefined *group = dynamic_cast<IUserDefined*>(sec); + printf(" Title=%s\n", group->header()->latin1() ); + } + for (mli->toFirst();(mem=mli->current());mli->toNext()) + { + ILinkedTextIterator *lti = mem->type(); + printf(" Member type=%s name=%s\n", + linkedTextToString(lti).latin1(),mem->name()->latin1()); + lti->release(); + + IParamIterator *pli = mem->parameters(); + DumpParamList(pli,6); + pli->release(); + IMemberReferenceIterator *mri = mem->references(); + IMemberReference *mr; + for (mri->toFirst();(mr=mri->current());mri->toNext()) + { + IMember *memr = mr->member(); + printf(" References %s at line %d\n", + mr->name()->latin1(),memr->bodyStart()); + } + + mri->release(); + mri = mem->referencedBy(); + for (mri->toFirst();(mr=mri->current());mri->toNext()) + { + IMember *memr = mr->member(); + printf(" ReferencedBy %s at line %d\n", + mr->name()->latin1(),memr->bodyStart()); + } + mri->release(); + + if (mem->kind()==IMember::Enum) // we have found an enum + { + IEnum *e = dynamic_cast<IEnum*>(mem); + IMemberIterator *evi = e->enumValues(); // get the enum values + IMember *mev; + for (evi->toFirst();(mev=evi->current());evi->toNext()) + { + IEnumValue *ev = dynamic_cast<IEnumValue*>(mev); + ILinkedTextIterator *lti = ev->initializer(); + QString init = linkedTextToString(lti); + lti->release(); + printf(" Enum value `%s' init=`%s'\n", + ev->name()->latin1(),init.latin1()); + } + evi->release(); + } + + pli = mem->templateParameters(); + if (pli) + { + printf(" Template parameters\n"); + DumpParamList(pli,8); + pli->release(); + } + + IDoc *doc = mem->briefDescription(); + if (doc) + { + printf("===== brief description ==== \n"); + DumpDoc(doc,0); + } + + doc = mem->detailedDescription(); + if (doc) + { + printf("===== detailed description ==== \n"); + DumpDoc(doc,0); + } + } + mli->release(); + } + sli->release(); + + IDoc *doc = comp->briefDescription(); + if (doc) + { + printf("===== brief description ==== \n"); + DumpDoc(doc,0); + } + + doc = comp->detailedDescription(); + if (doc) + { + printf("===== detailed description ==== \n"); + DumpDoc(doc,0); + } + + if (comp->kind()==ICompound::Class) + { + IClass *cls = dynamic_cast<IClass*>(comp); + ASSERT(cls!=0); + + printf("==== inheritance graph ==== \n"); + DumpGraph(cls->inheritanceGraph()); + + printf("==== collabration graph ==== \n"); + DumpGraph(cls->collaborationGraph()); + + printf("==== base classes ==== \n"); + IRelatedCompoundIterator *bcli = cls->baseCompounds(); + IRelatedCompound *bClass; + for (bcli->toFirst();(bClass=bcli->current());bcli->toNext()) + { + ICompound *bc = bClass->compound(); + printf(" + class %s\n",bc->name()->latin1()); + bc->release(); + } + bcli->release(); + + printf("==== derived classes ==== \n"); + IRelatedCompoundIterator *dcli = cls->derivedCompounds(); + IRelatedCompound *dClass; + for (dcli->toFirst();(dClass=dcli->current());dcli->toNext()) + { + ICompound *dc = dClass->compound(); + printf(" + class %s\n",dc->name()->latin1()); + dc->release(); + } + dcli->release(); + } + else if (comp->kind()==ICompound::File) + { + IFile *file = dynamic_cast<IFile*>(comp); + ASSERT(file!=0); + + printf("==== include dependency graph ==== \n"); + DumpGraph(file->includeDependencyGraph()); + + printf("==== included by dependency graph ==== \n"); + DumpGraph(file->includedByDependencyGraph()); + + printf("==== source ====\n"); + DumpDoc(file->source(),0); + } + + comp->release(); + } + cli->release(); + printf("---------------------------\n"); + + dox->release(); + + return 0; +} + diff --git a/trunk/addon/doxmlparser/test/xmlparse.pro.in b/trunk/addon/doxmlparser/test/xmlparse.pro.in new file mode 100644 index 0000000..cfb95be --- /dev/null +++ b/trunk/addon/doxmlparser/test/xmlparse.pro.in @@ -0,0 +1,20 @@ +TEMPLATE = app.t +CONFIG = console warn_on $extraopts +HEADERS = +SOURCES = main.cpp +unix:LIBS += -L../../../lib -L../lib -ldoxmlparser -lqtools +win32:INCLUDEPATH += . +win32-mingw:LIBS += -L../../../lib -L../lib -ldoxmlparser -lqtools +win32-msvc:LIBS += doxmlparser.lib qtools.lib shell32.lib +win32-msvc:TMAKE_LFLAGS += /LIBPATH:..\..\..\lib;..\lib +win32-borland:LIBS += doxmlparser.lib qtools.lib shell32.lib +win32-borland:TMAKE_LFLAGS += -L..\..\..\lib -L..\lib +win32:TMAKE_CXXFLAGS += -DQT_NODLL +DESTDIR = +OBJECTS_DIR = ../objects +TARGET = xmlparse +INCLUDEPATH += ../../../qtools ../include +DEPENDPATH += ../include +unix:TARGETDEPS = ../lib/libdoxmlparser.a +win32:TARGETDEPS = ..\lib\doxmlparser.lib + diff --git a/trunk/addon/doxyapp/Makefile.in b/trunk/addon/doxyapp/Makefile.in new file mode 100644 index 0000000..c5acd67 --- /dev/null +++ b/trunk/addon/doxyapp/Makefile.in @@ -0,0 +1,17 @@ + +all clean depend distclean: Makefile.doxyapp + $(MAKE) -f Makefile.doxyapp $@ + +distclean: clean + $(RM) -rf Makefile doxyapp.pro Makefile.doxyapp + +tmake: + $(ENV) $(PERL) $(TMAKE) doxyapp.pro >Makefile.doxyapp + +strip: + strip doxyapp + +Makefile.doxyapp: doxyapp.pro + $(ENV) $(PERL) $(TMAKE) doxyapp.pro >Makefile.doxyapp + +install: diff --git a/trunk/addon/doxyapp/README b/trunk/addon/doxyapp/README new file mode 100644 index 0000000..f92e106 --- /dev/null +++ b/trunk/addon/doxyapp/README @@ -0,0 +1,8 @@ +This directory contains an example of how to use doxygen as +an "source parsing engine" in an application. It shows how to configure doxygen +from the application and shows how to run doxygen without generating output, +and then uses the information about the symbols found in the source code. + +Note that if you use this approach your application should be licensed under the GPL. + + diff --git a/trunk/addon/doxyapp/doxyapp.cpp b/trunk/addon/doxyapp/doxyapp.cpp new file mode 100644 index 0000000..ffee3c7 --- /dev/null +++ b/trunk/addon/doxyapp/doxyapp.cpp @@ -0,0 +1,314 @@ +/****************************************************************************** + * + * Copyright (C) 1997-2012 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. + * + */ + +/** @file + * @brief Example of how to use doxygen as part of another GPL applications + * + * This example shows how to configure and run doxygen programmatically from + * within an application without generating the usual output. + * The example should work on any Unix like OS (including Linux and Mac OS X). + * + * This example shows how to use to code parser to get cross-references information + * and it also shows how to look up symbols in a program parsed by doxygen and + * show some information about them. + */ + +#include <stdlib.h> +#include <unistd.h> +#include "doxygen.h" +#include "outputgen.h" +#include "parserintf.h" + +class XRefDummyCodeGenerator : public CodeOutputInterface +{ + public: + XRefDummyCodeGenerator(FileDef *fd) : m_fd(fd) {} + ~XRefDummyCodeGenerator() {} + + // these are just null functions, they can be used to produce a syntax highlighted + // and cross-linked version of the source code, but who needs that anyway ;-) + void codify(const char *) {} + void writeCodeLink(const char *,const char *,const char *,const char *,const char *) {} + void startCodeLine() {} + void endCodeLine() {} + void startCodeAnchor(const char *) {} + void endCodeAnchor() {} + void startFontClass(const char *) {} + void endFontClass() {} + void writeCodeAnchor(const char *) {} + void writeLineNumber(const char *,const char *,const char *,int) {} + + // here we are presented with the symbols found by the code parser + void linkableSymbol(int l, const char *sym,Definition *symDef,Definition *context) + { + QCString ctx; + if (context) // the context of the symbol is known + { + if (context->definitionType()==Definition::TypeMember) // it is inside a member + { + Definition *parentContext = context->getOuterScope(); + if (parentContext && parentContext->definitionType()==Definition::TypeClass) + // it is inside a member of a class + { + ctx.sprintf("inside %s %s of %s %s", + ((MemberDef *)context)->memberTypeName().data(), + context->name().data(), + ((ClassDef*)parentContext)->compoundTypeString().data(), + parentContext->name().data()); + } + else if (parentContext==Doxygen::globalScope) // it is inside a global member + { + ctx.sprintf("inside %s %s", + ((MemberDef *)context)->memberTypeName().data(), + context->name().data()); + } + } + if (ctx.isEmpty()) // it is something else (class, or namespace member, ...) + { + ctx.sprintf("in %s",context->name().data()); + } + } + printf("Found symbol %s at line %d of %s %s\n", + sym,l,m_fd->getDefFileName().data(),ctx.data()); + if (symDef && context) // in this case the definition of the symbol is + // known to doxygen. + { + printf("-> defined at line %d of %s\n", + symDef->getDefLine(),symDef->getDefFileName().data()); + } + } + private: + FileDef *m_fd; +}; + +static void findXRefSymbols(FileDef *fd) +{ + // get the interface to a parser that matches the file extension + ParserInterface *pIntf=Doxygen::parserManager->getParser(fd->getDefFileExtension()); + + // reset the parsers state + pIntf->resetCodeParserState(); + + // create a new backend object + XRefDummyCodeGenerator *xrefGen = new XRefDummyCodeGenerator(fd); + + // parse the source code + pIntf->parseCode(*xrefGen, + 0, + fileToString(fd->absFilePath()), + FALSE, + 0, + fd); + + // dismiss the object. + delete xrefGen; +} + +static void listSymbol(Definition *d) +{ + if (d!=Doxygen::globalScope && // skip the global namespace symbol + d->name().at(0)!='@' // skip anonymous stuff + ) + { + printf("%s\n", + d->name().data()); + } +} + +static void listSymbols() +{ + QDictIterator<DefinitionIntf> sli(*Doxygen::symbolMap); + DefinitionIntf *di; + for (sli.toFirst();(di=sli.current());++sli) + { + if (di->definitionType()==DefinitionIntf::TypeSymbolList) // list of symbols + // with same name + { + DefinitionListIterator dli(*(DefinitionList*)di); + Definition *d; + // for each symbol + for (dli.toFirst();(d=dli.current());++dli) + { + listSymbol(d); + } + } + else // single symbol + { + listSymbol((Definition*)di); + } + } +} + +static void lookupSymbol(Definition *d) +{ + if (d!=Doxygen::globalScope && // skip the global namespace symbol + d->name().at(0)!='@' // skip anonymous stuff + ) + { + printf("Symbol info\n"); + printf("-----------\n"); + printf("Name: %s\n",d->name().data()); + printf("File: %s\n",d->getDefFileName().data()); + printf("Line: %d\n",d->getDefLine()); + // depending on the definition type we can case to the appropriate + // derived to get additional information + switch (d->definitionType()) + { + case Definition::TypeClass: + { + ClassDef *cd = (ClassDef *)d; + printf("Kind: %s\n",cd->compoundTypeString().data()); + } + break; + case Definition::TypeFile: + { + FileDef *fd = (FileDef *)d; + printf("Kind: File: #includes %d other files\n", + fd->includeFileList() ? fd->includeFileList()->count() : 0); + } + break; + case Definition::TypeNamespace: + { + NamespaceDef *nd = (NamespaceDef *)d; + printf("Kind: Namespace: contains %d classes and %d namespaces\n", + nd->getClassSDict() ? nd->getClassSDict()->count() : 0, + nd->getNamespaceSDict() ? nd->getNamespaceSDict()->count() : 0); + } + break; + case Definition::TypeMember: + { + MemberDef *md = (MemberDef *)d; + printf("Kind: %s\n",md->memberTypeName().data()); + } + break; + default: + // ignore groups/pages/packages/dirs for now + break; + } + } +} + +static void lookupSymbols(const QCString &sym) +{ + if (!sym.isEmpty()) + { + DefinitionIntf *di = Doxygen::symbolMap->find(sym); + if (di) + { + if (di->definitionType()==DefinitionIntf::TypeSymbolList) + { + DefinitionListIterator dli(*(DefinitionList*)di); + Definition *d; + // for each symbol with the given name + for (dli.toFirst();(d=dli.current());++dli) + { + lookupSymbol(d); + } + } + else + { + lookupSymbol((Definition*)di); + } + } + else + { + printf("Unknown symbol\n"); + } + } +} + +int main(int argc,char **argv) +{ + char cmd[256]; + + if (argc<2) + { + printf("Usage: %s [source_file | source_dir]\n",argv[0]); + exit(1); + } + + // initialize data structures + initDoxygen(); + + // setup the non-default configuration options + + // we need a place to put intermediate files + Config_getString("OUTPUT_DIRECTORY")="/tmp/doxygen"; + // disable html output + Config_getBool("GENERATE_HTML")=FALSE; + // disable latex output + Config_getBool("GENERATE_LATEX")=FALSE; + // be quiet + Config_getBool("QUIET")=TRUE; + // turn off warnings + Config_getBool("WARNINGS")=FALSE; + Config_getBool("WARN_IF_UNDOCUMENTED")=FALSE; + Config_getBool("WARN_IF_DOC_ERROR")=FALSE; + // Extract as much as possible + Config_getBool("EXTRACT_ALL")=TRUE; + Config_getBool("EXTRACT_STATIC")=TRUE; + Config_getBool("EXTRACT_PRIVATE")=TRUE; + Config_getBool("EXTRACT_LOCAL_METHODS")=TRUE; + // Extract source browse information, needed + // to make doxygen gather the cross reference info + Config_getBool("SOURCE_BROWSER")=TRUE; + + // set the input + Config_getList("INPUT").append(argv[1]); + + // check and finialize the configuration + checkConfiguration(); + adjustConfiguration(); + + // parse the files + parseInput(); + + // iterate over the input files + FileNameListIterator fnli(*Doxygen::inputNameList); + FileName *fn; + // foreach file with a certain name + for (fnli.toFirst();(fn=fnli.current());++fnli) + { + FileNameIterator fni(*fn); + FileDef *fd; + // for each file definition + for (;(fd=fni.current());++fni) + { + // get the references (linked and unlinked) found in this file + findXRefSymbols(fd); + } + } + + // remove temporary files + if (!Doxygen::objDBFileName.isEmpty()) unlink(Doxygen::objDBFileName); + if (!Doxygen::entryDBFileName.isEmpty()) unlink(Doxygen::entryDBFileName); + // clean up after us + rmdir("/tmp/doxygen"); + + while (1) + { + printf("> Type a symbol name or\n> .list for a list of symbols or\n> .quit to exit\n> "); + fgets(cmd,256,stdin); + QCString s(cmd); + if (s.at(s.length()-1)=='\n') s=s.left(s.length()-1); // strip trailing \n + if (s==".list") + listSymbols(); + else if (s==".quit") + exit(0); + else + lookupSymbols(s); + } +} + diff --git a/trunk/addon/doxyapp/doxyapp.pro.in b/trunk/addon/doxyapp/doxyapp.pro.in new file mode 100644 index 0000000..68fea3d --- /dev/null +++ b/trunk/addon/doxyapp/doxyapp.pro.in @@ -0,0 +1,12 @@ +TEMPLATE = app.t +CONFIG = console warn_on debug +HEADERS = +SOURCES = doxyapp.cpp +LIBS += -L../../lib -L../../lib -ldoxygen -lqtools -lmd5 -ldoxycfg -lpng +DESTDIR = +OBJECTS_DIR = ../../objects +TARGET = ../../bin/doxyapp +INCLUDEPATH += ../../qtools ../../src +DEPENDPATH += ../../src +TARGETDEPS = ../../lib/libdoxygen.a + diff --git a/trunk/addon/doxywizard/Makefile.in b/trunk/addon/doxywizard/Makefile.in new file mode 100644 index 0000000..5b0876e --- /dev/null +++ b/trunk/addon/doxywizard/Makefile.in @@ -0,0 +1,39 @@ +# +# +# +# Copyright (C) 1997-2012 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. +# + +QMAKE=qmake $(MKSPECS) + +all: Makefile.doxywizard + $(MAKE) -f Makefile.doxywizard + +Makefile.doxywizard: doxywizard.pro + $(QMAKE) doxywizard.pro -o Makefile.doxywizard + +qmake: + $(QMAKE) doxywizard.pro -o Makefile.doxywizard + +clean: Makefile.doxywizard + $(MAKE) -f Makefile.doxywizard clean + +distclean: Makefile.doxywizard + $(MAKE) -f Makefile.doxywizard distclean + $(RM) Makefile.doxywizard + +install: + $(INSTTOOL) -d $(INSTALL)/bin + $(INSTTOOL) -m 755 ../../bin/doxywizard $(INSTALL)/bin + $(INSTTOOL) -d $(INSTALL)/$(MAN1DIR) + cat ../../doc/doxywizard.1 | sed -e "s/DATE/$(DATE)/g" -e "s/VERSION/$(VERSION)/g" > doxywizard.1 + $(INSTTOOL) -m 644 doxywizard.1 $(INSTALL)/$(MAN1DIR)/doxywizard.1 + rm doxywizard.1 + +FORCE: diff --git a/trunk/addon/doxywizard/README b/trunk/addon/doxywizard/README new file mode 100644 index 0000000..57705f0 --- /dev/null +++ b/trunk/addon/doxywizard/README @@ -0,0 +1,3 @@ +Doxywizard is a graphical front-end to read/edit/write doxygen configuration +files and to launch doxygen. It requires Qt version 4.3 or higher. + diff --git a/trunk/addon/doxywizard/config.h b/trunk/addon/doxywizard/config.h new file mode 100644 index 0000000..d40f1f4 --- /dev/null +++ b/trunk/addon/doxywizard/config.h @@ -0,0 +1,18 @@ +#ifndef CONFIG_H +#define CONFIG_H + +#include <QHash> +#include <QString> + +class Input; +class QTextStream; +class QTextCodec; + +bool parseConfig( + const QString &fileName, + const QHash<QString,Input *> &options + ); + +void writeStringValue(QTextStream &t,QTextCodec *codec,const QString &s); + +#endif diff --git a/trunk/addon/doxywizard/config.l b/trunk/addon/doxywizard/config.l new file mode 100644 index 0000000..fa49eba --- /dev/null +++ b/trunk/addon/doxywizard/config.l @@ -0,0 +1,555 @@ +/****************************************************************************** + * + * $Id: config_templ.l,v 1.8 2001/01/01 10:15:16 root Exp $ + * + * Copyright (C) 1997-2012 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. + * + */ + +%{ + +/* + * includes + */ +#include "config.h" +#include "input.h" +#include <QtCore> + +#define MAX_INCLUDE_DEPTH 10 + + +/* ----------------------------------------------------------------- + * + * static variables + */ + +struct ConfigFileState +{ + int lineNr; + FILE *file; + YY_BUFFER_STATE oldState; + YY_BUFFER_STATE newState; + QString fileName; +}; + +static const QHash<QString,Input*> *g_options; +static FILE *g_file; +static QString g_yyFileName; +static QString g_includeName; +static QVariant g_includePathList; +static QStack<ConfigFileState*> g_includeStack; +static int g_includeDepth; +static QVariant *g_arg; +static Input *g_curOption=0; +static QString g_elemStr; +static QTextCodec *g_codec = QTextCodec::codecForName("UTF-8"); +static QString g_codecName = QString::fromAscii("UTF-8"); +static int g_lastState; +static QByteArray g_tmpString; + +/* ----------------------------------------------------------------- + */ +#undef YY_INPUT +#define YY_INPUT(buf,result,max_size) result=yyread(buf,max_size); + +static int yyread(char *buf,int maxSize) +{ + // no file included + if (g_includeStack.isEmpty()) + { + return fread(buf,1,maxSize,g_file); + } + else + { + return fread(buf,1,maxSize,g_includeStack.top()->file); + } +} + +void config_err(const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + vfprintf(stderr, fmt, args); + va_end(args); +} +void config_warn(const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + vfprintf(stderr, fmt, args); + va_end(args); +} + +static void substEnvVarsInStrList(QStringList &sl); +static void substEnvVarsInString(QString &s); + +static void checkEncoding() +{ + Input *option = g_options->value(QString::fromAscii("DOXYFILE_ENCODING")); + if (option && option->value().toString()!=g_codecName) + { + QTextCodec *newCodec = QTextCodec::codecForName(option->value().toString().toAscii()); + if (newCodec) + { + g_codec = newCodec; + g_codecName = option->value().toString(); + } + } +} + +static FILE *tryPath(const QString &path,const QString &fileName) +{ + QString absName=!path.isEmpty() ? path+QString::fromAscii("/")+fileName : fileName; + QFileInfo fi(absName); + if (fi.exists() && fi.isFile()) + { + FILE *f = fopen(absName.toLocal8Bit(),"r"); + if (f==NULL) + config_err("Error: could not open file %s for reading\n",absName.toLatin1().data()); + else + return f; + } + return NULL; +} + +static FILE *findFile(const QString &fileName) +{ + if (QFileInfo(fileName).isAbsolute()) // absolute path + { + return tryPath(QString(), fileName); + } + + // relative path, try with include paths in the list + QStringList sl = g_includePathList.toStringList(); + substEnvVarsInStrList(sl); + foreach (QString s, sl) + { + FILE *f = tryPath(s,fileName); + if (f) return f; + } + // try cwd if g_includePathList fails + return tryPath(QString::fromAscii("."),fileName); +} + +static void readIncludeFile(const QString &incName) +{ + if (g_includeDepth==MAX_INCLUDE_DEPTH) + { + config_err("Error: maximum include depth (%d) reached, %s is not included. Aborting...\n", + MAX_INCLUDE_DEPTH,qPrintable(incName)); + exit(1); + } + + QString inc = incName; + substEnvVarsInString(inc); + inc = inc.trimmed(); + uint incLen = inc.length(); + if (inc.at(0)==QChar::fromAscii('"') && + inc.at(incLen-1)==QChar::fromAscii('"')) // strip quotes + { + inc=inc.mid(1,incLen-2); + } + + FILE *f = findFile(inc); + if (f) // see if the include file can be found + { + // For debugging +#if SHOW_INCLUDES + for (i=0;i<includeStack.count();i++) msg(" "); + msg("@INCLUDE = %s: parsing...\n",inc.toLatin1().data()); +#endif + + // store the state of the old file + ConfigFileState *fs=new ConfigFileState; + fs->oldState=YY_CURRENT_BUFFER; + fs->fileName=g_yyFileName; + fs->file=f; + // push the state on the stack + g_includeStack.push(fs); + // set the scanner to the include file + yy_switch_to_buffer(yy_create_buffer(f, YY_BUF_SIZE)); + fs->newState=YY_CURRENT_BUFFER; + g_yyFileName=inc; + g_includeDepth++; + } + else + { + config_err("Error: @INCLUDE = %s: not found!\n",inc.toLatin1().data()); + exit(1); + } +} + + +%} + +%option nounput +%option noyywrap +%option yylineno + +%x Start +%x SkipComment +%x SkipInvalid +%x GetString +%x GetStrList +%x GetQuotedString +%x GetEnvVar +%x Include + +%% + +<*>\0x0d +<Start,GetString,GetStrList,SkipInvalid>"#" { BEGIN(SkipComment); } +<Start>[a-z_A-Z][a-z_A-Z0-9]*[ \t]*"=" { QString cmd = g_codec->toUnicode(yytext); + cmd=cmd.left(cmd.length()-1).trimmed(); + g_curOption = g_options->value(cmd); + if (g_curOption==0) // oops not known + { + config_err("Warning: ignoring unsupported tag `%s' at line %d, file %s\n", + qPrintable(cmd),yylineno,qPrintable(g_yyFileName)); + BEGIN(SkipInvalid); + } + else // known tag + { + //option->setEncoding(encoding); + g_arg = &g_curOption->value(); + switch(g_curOption->kind()) + { + case Input::StrList: + g_elemStr = QString(); + *g_arg = QStringList(); + BEGIN(GetStrList); + break; + case Input::String: + BEGIN(GetString); + break; + case Input::Int: + BEGIN(GetString); + break; + case Input::Bool: + BEGIN(GetString); + break; + case Input::Obsolete: + config_err("Warning: Tag `%s' at line %d of file %s has become obsolete.\n" + "To avoid this warning please update your configuration " + "file using \"doxygen -u\"\n", qPrintable(cmd), + yylineno,qPrintable(g_yyFileName)); + BEGIN(SkipInvalid); + break; + } + } + } +<Start>[a-z_A-Z][a-z_A-Z0-9]*[ \t]*"+=" { QString cmd=g_codec->toUnicode(yytext); + cmd=cmd.left(cmd.length()-2).trimmed(); + g_curOption = g_options->value(cmd); + if (g_curOption==0) // oops not known + { + config_err("Warning: ignoring unsupported tag `%s' at line %d, file %s\n", + yytext,yylineno,qPrintable(g_yyFileName)); + BEGIN(SkipInvalid); + } + else // known tag + { + switch(g_curOption->kind()) + { + case Input::StrList: + g_arg = &g_curOption->value(); + g_elemStr=QString(); + BEGIN(GetStrList); + break; + case Input::String: + case Input::Int: + case Input::Bool: + config_err("Warning: operator += not supported for `%s'. Ignoring line at line %d, file %s\n", + yytext,yylineno,qPrintable(g_yyFileName)); + BEGIN(SkipInvalid); + break; + case Input::Obsolete: + config_err("Warning: Tag `%s' at line %d of file %s has become obsolete.\n" + "To avoid this warning please update your configuration " + "file using \"doxygen -u\"\n", + qPrintable(cmd),yylineno,qPrintable(g_yyFileName)); + BEGIN(SkipInvalid); + break; + } + } + } +<Start>"@INCLUDE_PATH"[ \t]*"=" { BEGIN(GetStrList); g_arg=&g_includePathList; *g_arg = QStringList(); g_elemStr=QString(); } + /* include a config file */ +<Start>"@INCLUDE"[ \t]*"=" { BEGIN(Include);} +<Include>([^ \"\t\r\n]+)|("\""[^\n\"]+"\"") { + readIncludeFile(g_codec->toUnicode(yytext)); + BEGIN(Start); + } +<<EOF>> { + //printf("End of include file\n"); + //printf("Include stack depth=%d\n",g_includeStack.count()); + if (g_includeStack.isEmpty()) + { + //printf("Terminating scanner!\n"); + yyterminate(); + } + else + { + ConfigFileState *fs = g_includeStack.pop(); + fclose(fs->file); + YY_BUFFER_STATE oldBuf = YY_CURRENT_BUFFER; + yy_switch_to_buffer( fs->oldState ); + yy_delete_buffer( oldBuf ); + g_yyFileName=fs->fileName; + delete fs; + g_includeDepth--; + } + } + +<Start>[a-z_A-Z0-9]+ { config_err("Warning: ignoring unknown tag `%s' at line %d, file %s\n",yytext,yylineno,qPrintable(g_yyFileName)); } +<GetString,SkipInvalid>\n { BEGIN(Start); } +<GetStrList>\n { + if (!g_elemStr.isEmpty()) + { + //printf("elemStr1=`%s'\n",elemStr.toLatin1().data()); + *g_arg = QVariant(g_arg->toStringList() << g_elemStr); + } + BEGIN(Start); + } +<GetStrList>[ \t]+ { + if (!g_elemStr.isEmpty()) + { + //printf("elemStr2=`%s'\n",elemStr.toLatin1().data()); + *g_arg = QVariant(g_arg->toStringList() << g_elemStr); + } + g_elemStr = QString(); + } +<GetString>[^ \"\t\r\n]+ { + *g_arg = QVariant(g_codec->toUnicode(yytext)); + checkEncoding(); + } +<GetString,GetStrList,SkipInvalid>"\"" { g_lastState=YY_START; + BEGIN(GetQuotedString); + g_tmpString=""; + } +<GetQuotedString>"\""|"\n" { + // we add a bogus space to signal that the string was quoted. This space will be stripped later on. + g_tmpString+=" "; + //printf("Quoted String = `%s'\n",tmpString.toLatin1().data()); + if (g_lastState==GetString) + { + *g_arg = g_codec->toUnicode(g_tmpString); + checkEncoding(); + } + else + { + g_elemStr+=g_codec->toUnicode(g_tmpString); + } + if (*yytext=='\n') + { + config_err("Warning: Missing end quote (\") on line %d, file %s\n",yylineno, + qPrintable(g_yyFileName)); + } + BEGIN(g_lastState); + } +<GetQuotedString>"\\\"" { + g_tmpString+='"'; + } +<GetQuotedString>. { g_tmpString+=*yytext; } +<GetStrList>[^ \#\"\t\r\n]+ { + g_elemStr+=g_codec->toUnicode(yytext); + } +<SkipComment>\n { BEGIN(Start); } +<SkipComment>\\[ \r\t]*\n { BEGIN(Start); } +<*>\\[ \r\t]*\n { } +<*>\n +<*>. + +%% + +/*@ ---------------------------------------------------------------------------- + */ + +static void substEnvVarsInString(QString &s) +{ + static QRegExp re(QString::fromAscii("\\$\\([a-z_A-Z0-9]+\\)")); + if (s.isEmpty()) return; + int p=0; + int i,l; + //printf("substEnvVarInString(%s) start\n",s.toLatin1().data()); + while ((i=re.indexIn(s,p))!=-1) + { + l = re.matchedLength(); + //printf("Found environment var s.mid(%d,%d)=`%s'\n",i+2,l-3,s.mid(i+2,l-3).toLatin1().data()); + QString env=g_codec->toUnicode(getenv(s.mid(i+2,l-3).toLatin1())); + substEnvVarsInString(env); // recursively expand variables if needed. + s = s.left(i)+env+s.right(s.length()-i-l); + p=i+env.length(); // next time start at the end of the expanded string + } + s=s.trimmed(); // to strip the bogus space that was added when an argument + // has quotes + //printf("substEnvVarInString(%s) end\n",s.toLatin1().data()); +} + +static void substEnvVarsInStrList(QStringList &sl) +{ + QStringList out; + + foreach (QString result, sl) + { + // an argument with quotes will have an extra space at the end, so wasQuoted will be TRUE. + bool wasQuoted = (result.indexOf(QChar::fromAscii(' '))!=-1) || + (result.indexOf(QChar::fromAscii('\t'))!=-1); + // here we strip the quote again + substEnvVarsInString(result); + + //printf("Result %s was quoted=%d\n",result.toLatin1().data(),wasQuoted); + + if (!wasQuoted) /* as a result of the expansion, a single string + may have expanded into a list, which we'll + add to sl. If the orginal string already + contained multiple elements no further + splitting is done to allow quoted items with spaces! */ + { + int l=result.length(); + int i,p=0; + // skip spaces + // search for a "word" + for (i=0;i<l;i++) + { + QChar c=0; + // skip until start of new word + while (i<l && ((c=result.at(i))==QChar::fromAscii(' ') || c==QChar::fromAscii('\t'))) i++; + p=i; // p marks the start index of the word + // skip until end of a word + while (i<l && ((c=result.at(i))!=QChar::fromAscii(' ') && + c!=QChar::fromAscii('\t') && + c!=QChar::fromAscii('"'))) i++; + if (i<l) // not at the end of the string + { + if (c==QChar::fromAscii('"')) // word within quotes + { + p=i+1; + for (i++;i<l;i++) + { + c=result.at(i); + if (c==QChar::fromAscii('"')) // end quote + { + out += result.mid(p,i-p); + p=i+1; + break; + } + else if (c==QChar::fromAscii('\\')) // skip escaped stuff + { + i++; + } + } + } + else if (c==QChar::fromAscii(' ') || c==QChar::fromAscii('\t')) // separator + { + out += result.mid(p,i-p); + p=i+1; + } + } + } + if (p!=l) // add the leftover as a string + { + out += result.right(l-p); + } + } + else // just goto the next element in the list + { + out += result; + } + } + sl = out; +} + +//-------------------------------------------------------------------------- + +bool parseConfig( + const QString &fileName, + const QHash<QString,Input *> &options + ) +{ + QHashIterator<QString, Input*> i(options); + g_file = fopen(fileName.toLocal8Bit(),"r"); + if (g_file==NULL) return false; + + // reset all values + i.toFront(); + while (i.hasNext()) + { + i.next(); + if (i.value()) + { + i.value()->reset(); + } + } + + // parse config file + g_options = &options; + g_yyFileName = fileName; + g_includeStack.clear(); + g_includeDepth = 0; + configrestart( configin ); + BEGIN( Start ); + configlex(); + + // update the values in the UI + i.toFront(); + while (i.hasNext()) + { + i.next(); + if (i.value()) + { + //printf("Updating: %s\n",qPrintable(i.key())); + i.value()->update(); + } + else + { + printf("Invalid option: %s\n",qPrintable(i.key())); + } + } + fclose(g_file); + return true; +} + +void writeStringValue(QTextStream &t,QTextCodec *codec,const QString &s) +{ + QChar c; + bool needsEscaping=FALSE; + // convert the string back to it original encoding + //QByteArray se = codec->fromUnicode(s); + t.setCodec(codec); + const QChar *p=s.data(); + if (!s.isEmpty() && !p->isNull()) + { + while (!(c=*p++).isNull() && !needsEscaping) + { + needsEscaping = (c==QChar::fromAscii(' ') || + c==QChar::fromAscii('\n') || + c==QChar::fromAscii('\t') || + c==QChar::fromAscii('"')); + } + if (needsEscaping) + { + t << "\""; + p=s.data(); + while (!p->isNull()) + { + if (*p ==QChar::fromAscii(' ') && + *(p+1)==QChar::fromAscii('\0')) break; // skip inserted space at the end + if (*p ==QChar::fromAscii('"')) t << "\\"; // escape quotes + t << *p++; + } + t << "\""; + } + else + { + t << s; + } + } +} + diff --git a/trunk/addon/doxywizard/doxywizard.cpp b/trunk/addon/doxywizard/doxywizard.cpp new file mode 100644 index 0000000..fe8c961 --- /dev/null +++ b/trunk/addon/doxywizard/doxywizard.cpp @@ -0,0 +1,639 @@ +#include <QtGui> +#include "doxywizard.h" +#include "version.h" +#include "expert.h" +#include "wizard.h" + +#ifdef WIN32 +#include <windows.h> +#endif + +#define MAX_RECENT_FILES 10 + +const int messageTimeout = 5000; //!< status bar message timeout in millisec. + +MainWindow &MainWindow::instance() +{ + static MainWindow *theInstance = new MainWindow; + return *theInstance; +} + +MainWindow::MainWindow() + : m_settings(QString::fromAscii("Doxygen.org"), QString::fromAscii("Doxywizard")) +{ + QMenu *file = menuBar()->addMenu(tr("File")); + file->addAction(tr("Open..."), + this, SLOT(openConfig()), Qt::CTRL+Qt::Key_O); + m_recentMenu = file->addMenu(tr("Open recent")); + file->addAction(tr("Save"), + this, SLOT(saveConfig()), Qt::CTRL+Qt::Key_S); + file->addAction(tr("Save as..."), + this, SLOT(saveConfigAs()), Qt::SHIFT+Qt::CTRL+Qt::Key_S); + file->addAction(tr("Quit"), + this, SLOT(quit()), Qt::CTRL+Qt::Key_Q); + + QMenu *settings = menuBar()->addMenu(tr("Settings")); + settings->addAction(tr("Reset to factory defaults"), + this,SLOT(resetToDefaults())); + settings->addAction(tr("Use current settings at startup"), + this,SLOT(makeDefaults())); + settings->addAction(tr("Clear recent list"), + this,SLOT(clearRecent())); + + QMenu *help = menuBar()->addMenu(tr("Help")); + help->addAction(tr("Online manual"), + this, SLOT(manual()), Qt::Key_F1); + help->addAction(tr("About"), + this, SLOT(about()) ); + + m_expert = new Expert; + m_wizard = new Wizard(m_expert->modelData()); + + // ----------- top part ------------------ + QWidget *topPart = new QWidget; + QVBoxLayout *rowLayout = new QVBoxLayout(topPart); + + // select working directory + QHBoxLayout *dirLayout = new QHBoxLayout; + m_workingDir = new QLineEdit; + m_selWorkingDir = new QPushButton(tr("Select...")); + dirLayout->addWidget(m_workingDir); + dirLayout->addWidget(m_selWorkingDir); + + //------------- bottom part -------------- + QWidget *runTab = new QWidget; + QVBoxLayout *runTabLayout = new QVBoxLayout(runTab); + + // run doxygen + QHBoxLayout *runLayout = new QHBoxLayout; + m_run = new QPushButton(tr("Run doxygen")); + m_run->setEnabled(false); + m_runStatus = new QLabel(tr("Status: not running")); + m_saveLog = new QPushButton(tr("Save log...")); + m_saveLog->setEnabled(false); + QPushButton *showSettings = new QPushButton(tr("Show configuration")); + runLayout->addWidget(m_run); + runLayout->addWidget(m_runStatus); + runLayout->addStretch(1); + runLayout->addWidget(showSettings); + runLayout->addWidget(m_saveLog); + + // output produced by doxygen + runTabLayout->addLayout(runLayout); + runTabLayout->addWidget(new QLabel(tr("Output produced by doxygen"))); + QGridLayout *grid = new QGridLayout; + m_outputLog = new QTextEdit; + m_outputLog->setReadOnly(true); + m_outputLog->setFontFamily(QString::fromAscii("courier")); + m_outputLog->setMinimumWidth(600); + grid->addWidget(m_outputLog,0,0); + grid->setColumnStretch(0,1); + grid->setRowStretch(0,1); + QHBoxLayout *launchLayout = new QHBoxLayout; + m_launchHtml = new QPushButton(tr("Show HTML output")); + launchLayout->addWidget(m_launchHtml); + + launchLayout->addStretch(1); + grid->addLayout(launchLayout,1,0); + runTabLayout->addLayout(grid); + + QTabWidget *tabs = new QTabWidget; + tabs->addTab(m_wizard,tr("Wizard")); + tabs->addTab(m_expert,tr("Expert")); + tabs->addTab(runTab,tr("Run")); + + rowLayout->addWidget(new QLabel(tr("Step 1: Specify the working directory from which doxygen will run"))); + rowLayout->addLayout(dirLayout); + rowLayout->addWidget(new QLabel(tr("Step 2: Configure doxygen using the Wizard and/or Expert tab, then switch to the Run tab to generate the documentation"))); + rowLayout->addWidget(tabs); + + setCentralWidget(topPart); + statusBar()->showMessage(tr("Welcome to Doxygen"),messageTimeout); + + m_runProcess = new QProcess; + m_running = false; + m_timer = new QTimer; + + // connect signals and slots + connect(tabs,SIGNAL(currentChanged(int)),SLOT(selectTab(int))); + connect(m_selWorkingDir,SIGNAL(clicked()),SLOT(selectWorkingDir())); + connect(m_recentMenu,SIGNAL(triggered(QAction*)),SLOT(openRecent(QAction*))); + connect(m_workingDir,SIGNAL(returnPressed()),SLOT(updateWorkingDir())); + connect(m_runProcess,SIGNAL(readyReadStandardOutput()),SLOT(readStdout())); + connect(m_runProcess,SIGNAL(finished(int, QProcess::ExitStatus)),SLOT(runComplete())); + connect(m_timer,SIGNAL(timeout()),SLOT(readStdout())); + connect(m_run,SIGNAL(clicked()),SLOT(runDoxygen())); + connect(m_launchHtml,SIGNAL(clicked()),SLOT(showHtmlOutput())); + connect(m_saveLog,SIGNAL(clicked()),SLOT(saveLog())); + connect(showSettings,SIGNAL(clicked()),SLOT(showSettings())); + connect(m_expert,SIGNAL(changed()),SLOT(configChanged())); + + loadSettings(); + updateLaunchButtonState(); + m_modified = false; + updateTitle(); + m_wizard->refresh(); +} + +void MainWindow::closeEvent(QCloseEvent *event) +{ + if (discardUnsavedChanges()) + { + saveSettings(); + event->accept(); + } + else + { + event->ignore(); + } +} + +void MainWindow::quit() +{ + if (discardUnsavedChanges()) + { + saveSettings(); + } + QApplication::exit(0); +} + +void MainWindow::setWorkingDir(const QString &dirName) +{ + QDir::setCurrent(dirName); + m_workingDir->setText(dirName); + m_run->setEnabled(!dirName.isEmpty()); +} + +void MainWindow::selectWorkingDir() +{ + QString dirName = QFileDialog::getExistingDirectory(this, + tr("Select working directory"),m_workingDir->text()); + if (!dirName.isEmpty()) + { + setWorkingDir(dirName); + } +} + +void MainWindow::updateWorkingDir() +{ + setWorkingDir(m_workingDir->text()); +} + +void MainWindow::manual() +{ + QDesktopServices::openUrl(QUrl(QString::fromAscii("http://www.doxygen.org/manual.html"))); +} + +void MainWindow::about() +{ + QString msg; + QTextStream t(&msg,QIODevice::WriteOnly); + t << QString::fromAscii("<qt><center>A tool to configure and run doxygen version ")+ + QString::fromAscii(versionString)+ + QString::fromAscii(" on your source files.</center><p><br>" + "<center>Written by<br> Dimitri van Heesch<br>© 2000-2012</center><p>" + "</qt>"); + QMessageBox::about(this,tr("Doxygen GUI"),msg); +} + +void MainWindow::openConfig() +{ + if (discardUnsavedChanges(false)) + { + QString fn = QFileDialog::getOpenFileName(this, + tr("Open configuration file"), + m_workingDir->text()); + if (!fn.isEmpty()) + { + loadConfigFromFile(fn); + } + } +} + +void MainWindow::updateConfigFileName(const QString &fileName) +{ + if (m_fileName!=fileName) + { + m_fileName = fileName; + QString curPath = QFileInfo(fileName).path(); + setWorkingDir(curPath); + addRecentFile(fileName); + updateTitle(); + } +} + +void MainWindow::loadConfigFromFile(const QString & fileName) +{ + m_expert->loadConfig(fileName); + m_wizard->refresh(); + updateConfigFileName(fileName); + updateLaunchButtonState(); + m_modified = false; + updateTitle(); +} + +void MainWindow::saveConfig(const QString &fileName) +{ + if (fileName.isEmpty()) return; + QFile f(fileName); + if (!f.open(QIODevice::WriteOnly)) + { + QMessageBox::warning(this, + tr("Error saving"), + tr("Error: cannot open the file ")+fileName+tr(" for writing!\n")+ + tr("Reason given: ")+f.error()); + return; + } + QTextStream t(&f); + m_expert->writeConfig(t,false); + updateConfigFileName(fileName); + m_modified = false; + updateTitle(); +} + +bool MainWindow::saveConfig() +{ + if (m_fileName.isEmpty()) + { + return saveConfigAs(); + } + else + { + saveConfig(m_fileName); + return true; + } +} + +bool MainWindow::saveConfigAs() +{ + QString fileName = QFileDialog::getSaveFileName(this, QString(), + m_workingDir->text()+QString::fromAscii("/Doxyfile")); + if (fileName.isEmpty()) return false; + saveConfig(fileName); + return true; +} + +void MainWindow::makeDefaults() +{ + if (QMessageBox::question(this,tr("Use current setting at startup?"), + tr("Do you want to save the current settings " + "and use them next time Doxywizard starts?"), + QMessageBox::Save| + QMessageBox::Cancel)==QMessageBox::Save) + { + //printf("MainWindow:makeDefaults()\n"); + m_expert->saveSettings(&m_settings); + m_settings.setValue(QString::fromAscii("wizard/loadsettings"), true); + m_settings.sync(); + } +} + +void MainWindow::clearRecent() +{ + if (QMessageBox::question(this,tr("Clear the list of recent files?"), + tr("Do you want to clear the list of recently " + "loaded configuration files?"), + QMessageBox::Yes| + QMessageBox::Cancel)==QMessageBox::Yes) + { + m_recentMenu->clear(); + m_recentFiles.clear(); + for (int i=0;i<MAX_RECENT_FILES;i++) + { + m_settings.setValue(QString().sprintf("recent/config%d",i++),QString::fromAscii("")); + } + m_settings.sync(); + } + +} + +void MainWindow::resetToDefaults() +{ + if (QMessageBox::question(this,tr("Reset settings to their default values?"), + tr("Do you want to revert all settings back " + "to their original values?"), + QMessageBox::Reset| + QMessageBox::Cancel)==QMessageBox::Reset) + { + //printf("MainWindow:resetToDefaults()\n"); + m_expert->resetToDefaults(); + m_settings.setValue(QString::fromAscii("wizard/loadsettings"), false); + m_settings.sync(); + m_wizard->refresh(); + } +} + +void MainWindow::loadSettings() +{ + QVariant geometry = m_settings.value(QString::fromAscii("main/geometry"), QVariant::Invalid); + QVariant state = m_settings.value(QString::fromAscii("main/state"), QVariant::Invalid); + QVariant wizState = m_settings.value(QString::fromAscii("wizard/state"), QVariant::Invalid); + QVariant loadSettings = m_settings.value(QString::fromAscii("wizard/loadsettings"), QVariant::Invalid); + QVariant workingDir = m_settings.value(QString::fromAscii("wizard/workingdir"), QVariant::Invalid); + + if (geometry !=QVariant::Invalid) restoreGeometry(geometry.toByteArray()); + if (state !=QVariant::Invalid) restoreState (state.toByteArray()); + if (wizState !=QVariant::Invalid) m_wizard->restoreState(wizState.toByteArray()); + if (loadSettings!=QVariant::Invalid && loadSettings.toBool()) + { + m_expert->loadSettings(&m_settings); + if (workingDir!=QVariant::Invalid && QDir(workingDir.toString()).exists()) + { + setWorkingDir(workingDir.toString()); + } + } + + for (int i=0;i<MAX_RECENT_FILES;i++) + { + QString entry = m_settings.value(QString().sprintf("recent/config%d",i)).toString(); + if (!entry.isEmpty() && QFileInfo(entry).exists()) + { + addRecentFile(entry); + } + } + +} + +void MainWindow::saveSettings() +{ + QSettings settings(QString::fromAscii("Doxygen.org"), QString::fromAscii("Doxywizard")); + + m_settings.setValue(QString::fromAscii("main/geometry"), saveGeometry()); + m_settings.setValue(QString::fromAscii("main/state"), saveState()); + m_settings.setValue(QString::fromAscii("wizard/state"), m_wizard->saveState()); + m_settings.setValue(QString::fromAscii("wizard/workingdir"), m_workingDir->text()); +} + +void MainWindow::selectTab(int id) +{ + if (id==0) m_wizard->refresh(); +} + +void MainWindow::addRecentFile(const QString &fileName) +{ + int i=m_recentFiles.indexOf(fileName); + if (i!=-1) m_recentFiles.removeAt(i); + + // not found + if (m_recentFiles.count() < MAX_RECENT_FILES) // append + { + m_recentFiles.prepend(fileName); + } + else // add + drop last item + { + m_recentFiles.removeLast(); + m_recentFiles.prepend(fileName); + } + m_recentMenu->clear(); + i=0; + foreach( QString str, m_recentFiles ) + { + m_recentMenu->addAction(str); + m_settings.setValue(QString().sprintf("recent/config%d",i++),str); + } + for (;i<MAX_RECENT_FILES;i++) + { + m_settings.setValue(QString().sprintf("recent/config%d",i++),QString::fromAscii("")); + } +} + +void MainWindow::openRecent(QAction *action) +{ + if (discardUnsavedChanges(false)) + { + loadConfigFromFile(action->text()); + } +} + +void MainWindow::runDoxygen() +{ + if (!m_running) + { + QString doxygenPath; +#if defined(Q_OS_MACX) + doxygenPath = qApp->applicationDirPath()+QString::fromAscii("/../Resources/"); + qDebug() << tr("Doxygen path: ") << doxygenPath; + if ( !QFile(doxygenPath + QString::fromAscii("doxygen")).exists() ) + { + // No doygen binary in the resources, if there is a system doxygen binary, use that instead + if ( QFile(QString::fromAscii("/usr/local/bin/doxygen")).exists() ) + { + doxygenPath = QString::fromAscii("/usr/local/bin/"); + } + else + { + qDebug() << tr("Can't find the doxygen command, make sure it's in your $$PATH"); + doxygenPath = QString::fromAscii(""); + } + } + qDebug() << tr("Getting doxygen from: ") << doxygenPath; +#endif + + m_runProcess->setReadChannel(QProcess::StandardOutput); + m_runProcess->setProcessChannelMode(QProcess::MergedChannels); + m_runProcess->setWorkingDirectory(m_workingDir->text()); + QStringList env=QProcess::systemEnvironment(); + // set PWD environment variable to m_workingDir + env.replaceInStrings(QRegExp(QString::fromAscii("^PWD=(.*)"),Qt::CaseInsensitive), + QString::fromAscii("PWD=")+m_workingDir->text()); + m_runProcess->setEnvironment(env); + + QStringList args; + args << QString::fromAscii("-b"); // make stdout unbuffered + args << QString::fromAscii("-"); // read config from stdin + + m_outputLog->clear(); + m_runProcess->start(doxygenPath + QString::fromAscii("doxygen"), args); + + if (!m_runProcess->waitForStarted()) + { + m_outputLog->append(QString::fromAscii("*** Failed to run doxygen\n")); + return; + } + QTextStream t(m_runProcess); + m_expert->writeConfig(t,false); + m_runProcess->closeWriteChannel(); + + if (m_runProcess->state() == QProcess::NotRunning) + { + m_outputLog->append(QString::fromAscii("*** Failed to run doxygen\n")); + } + else + { + m_saveLog->setEnabled(false); + m_running=true; + m_run->setText(tr("Stop doxygen")); + m_runStatus->setText(tr("Status: running")); + m_timer->start(1000); + } + } + else + { + m_running=false; + m_run->setText(tr("Run doxygen")); + m_runStatus->setText(tr("Status: not running")); + m_runProcess->kill(); + m_timer->stop(); + //updateRunnable(m_workingDir->text()); + } +} + +void MainWindow::readStdout() +{ + if (m_running) + { + QByteArray data = m_runProcess->readAllStandardOutput(); + QString text = QString::fromLocal8Bit(data); + if (!text.isEmpty()) + { + m_outputLog->append(text.trimmed()); + } + } +} + +void MainWindow::runComplete() +{ + if (m_running) + { + m_outputLog->append(tr("*** Doxygen has finished\n")); + } + else + { + m_outputLog->append(tr("*** Cancelled by user\n")); + } + m_outputLog->ensureCursorVisible(); + m_run->setText(tr("Run doxygen")); + m_runStatus->setText(tr("Status: not running")); + m_running=false; + updateLaunchButtonState(); + //updateRunnable(m_workingDir->text()); + m_saveLog->setEnabled(true); +} + +void MainWindow::updateLaunchButtonState() +{ + m_launchHtml->setEnabled(m_expert->htmlOutputPresent(m_workingDir->text())); +#if 0 + m_launchPdf->setEnabled(m_expert->pdfOutputPresent(m_workingDir->text())); +#endif +} + +void MainWindow::showHtmlOutput() +{ + QString indexFile = m_expert->getHtmlOutputIndex(m_workingDir->text()); + QFileInfo fi(indexFile); + // TODO: the following doesn't seem to work with IE +#ifdef WIN32 + //QString indexUrl(QString::fromAscii("file:///")); + ShellExecute(NULL, L"open", fi.absoluteFilePath().utf16(), NULL, NULL, SW_SHOWNORMAL); +#else + QString indexUrl(QString::fromAscii("file://")); + indexUrl+=fi.absoluteFilePath(); + QDesktopServices::openUrl(QUrl(indexUrl)); +#endif +} + +void MainWindow::saveLog() +{ + QString fn = QFileDialog::getSaveFileName(this, tr("Save log file"), + m_workingDir->text()+ + QString::fromAscii("/doxygen_log.txt")); + if (!fn.isEmpty()) + { + QFile f(fn); + if (f.open(QIODevice::WriteOnly)) + { + QTextStream t(&f); + t << m_outputLog->toPlainText(); + statusBar()->showMessage(tr("Output log saved"),messageTimeout); + } + else + { + QMessageBox::warning(0,tr("Warning"), + tr("Cannot open file ")+fn+tr(" for writing. Nothing saved!"),tr("ok")); + } + } +} + +void MainWindow::showSettings() +{ + QString text; + QTextStream t(&text); + m_expert->writeConfig(t,true); + m_outputLog->clear(); + m_outputLog->append(text); + m_outputLog->ensureCursorVisible(); + m_saveLog->setEnabled(true); +} + +void MainWindow::configChanged() +{ + m_modified = true; + updateTitle(); +} + +void MainWindow::updateTitle() +{ + QString title = tr("Doxygen GUI frontend"); + if (m_modified) + { + title+=QString::fromAscii(" +"); + } + if (!m_fileName.isEmpty()) + { + title+=QString::fromAscii(" (")+m_fileName+QString::fromAscii(")"); + } + setWindowTitle(title); +} + +bool MainWindow::discardUnsavedChanges(bool saveOption) +{ + if (m_modified) + { + QMessageBox::StandardButton button; + if (saveOption) + { + button = QMessageBox::question(this, + tr("Unsaved changes"), + tr("Unsaved changes will be lost! Do you want to save the configuration file?"), + QMessageBox::Save | + QMessageBox::Discard | + QMessageBox::Cancel + ); + if (button==QMessageBox::Save) + { + return saveConfig(); + } + } + else + { + button = QMessageBox::question(this, + tr("Unsaved changes"), + tr("Unsaved changes will be lost! Do you want to continue?"), + QMessageBox::Discard | + QMessageBox::Cancel + ); + } + return button==QMessageBox::Discard; + } + return true; +} + +//----------------------------------------------------------------------- + +int main(int argc,char **argv) +{ + QApplication a(argc,argv); + MainWindow &main = MainWindow::instance(); + if (argc==2 && argv[1][0]!='-') // name of config file as an argument + { + main.loadConfigFromFile(QString::fromLocal8Bit(argv[1])); + } + else if (argc>1) + { + printf("Usage: %s [config file]\n",argv[0]); + exit(1); + } + main.show(); + return a.exec(); +} diff --git a/trunk/addon/doxywizard/doxywizard.h b/trunk/addon/doxywizard/doxywizard.h new file mode 100644 index 0000000..46cd748 --- /dev/null +++ b/trunk/addon/doxywizard/doxywizard.h @@ -0,0 +1,84 @@ +#ifndef DOXYWIZARD_H +#define DOXYWIZARD_H + +#include <QMainWindow> +#include <QSettings> +#include <QStringList> + +class Expert; +class Wizard; +class QLabel; +class QLineEdit; +class QPushButton; +class QTextEdit; +class QMenu; +class QProcess; +class QTimer; + +class MainWindow : public QMainWindow +{ + Q_OBJECT + + public: + static MainWindow &instance(); + void loadConfigFromFile(const QString &fileName); + void loadSettings(); + void saveSettings(); + void closeEvent(QCloseEvent *event); + QString configFileName() const { return m_fileName; } + void updateTitle(); + + public slots: + void manual(); + void about(); + void openConfig(); + bool saveConfig(); + bool saveConfigAs(); + void makeDefaults(); + void resetToDefaults(); + void selectTab(int); + void quit(); + + private slots: + void openRecent(QAction *action); + void selectWorkingDir(); + void updateWorkingDir(); + void runDoxygen(); + void readStdout(); + void runComplete(); + void showHtmlOutput(); + void saveLog(); + void showSettings(); + void configChanged(); + void clearRecent(); + + private: + MainWindow(); + void saveConfig(const QString &fileName); + void addRecentFile(const QString &fileName); + void updateConfigFileName(const QString &fileName); + void setWorkingDir(const QString &dirName); + void updateLaunchButtonState(); + bool discardUnsavedChanges(bool saveOption=true); + + QLineEdit *m_workingDir; + QPushButton *m_selWorkingDir; + QPushButton *m_run; + QPushButton *m_saveLog; + QPushButton *m_launchHtml; + QPushButton *m_launchPdf; + QTextEdit *m_outputLog; + QLabel *m_runStatus; + Expert *m_expert; + Wizard *m_wizard; + QString m_fileName; + QSettings m_settings; + QMenu *m_recentMenu; + QStringList m_recentFiles; + QProcess *m_runProcess; + QTimer *m_timer; + bool m_running; + bool m_modified; +}; + +#endif diff --git a/trunk/addon/doxywizard/doxywizard.ico b/trunk/addon/doxywizard/doxywizard.ico new file mode 100644 index 0000000..10d1755 Binary files /dev/null and b/trunk/addon/doxywizard/doxywizard.ico differ diff --git a/trunk/addon/doxywizard/doxywizard.pro.in b/trunk/addon/doxywizard/doxywizard.pro.in new file mode 100644 index 0000000..3b40576 --- /dev/null +++ b/trunk/addon/doxywizard/doxywizard.pro.in @@ -0,0 +1,28 @@ +###################################################################### +# Automatically generated by qmake (2.01a) zo okt 19 12:50:02 2008 +###################################################################### + +TEMPLATE = app +DESTDIR = ../../bin +TARGET = +DEPENDPATH += . +INCLUDEPATH += . +QT += xml +CONFIG += $extraopts +OBJECTS_DIR = obj +MOC_DIR = moc +RCC_DIR = rcc +DEFINES += QT_NO_CAST_FROM_ASCII QT_NO_CAST_TO_ASCII + +macx-g++ { + CONFIG += x86 ppc +} + +# Input +HEADERS += doxywizard.h version.h expert.h config.h helplabel.h \ + inputbool.h inputstring.h inputint.h inputstrlist.h wizard.h +SOURCES += doxywizard.cpp ../../src/version.cpp expert.cpp wizard.cpp \ + inputbool.cpp inputstring.cpp inputint.cpp inputstrlist.cpp +LEXSOURCES += config.l +RESOURCES += doxywizard.qrc +win32:RC_FILE += doxywizard.rc diff --git a/trunk/addon/doxywizard/doxywizard.qrc b/trunk/addon/doxywizard/doxywizard.qrc new file mode 100644 index 0000000..88316ed --- /dev/null +++ b/trunk/addon/doxywizard/doxywizard.qrc @@ -0,0 +1,11 @@ +<!DOCTYPE RCC><RCC version="1.0"> +<qresource prefix="/"> + <file alias="config.xml">../../src/config.xml</file> + <file>images/add.png</file> + <file>images/del.png</file> + <file>images/file.png</file> + <file>images/folder.png</file> + <file>images/refresh.png</file> + <file>images/tunecolor.png</file> +</qresource> +</RCC> diff --git a/trunk/addon/doxywizard/doxywizard.rc b/trunk/addon/doxywizard/doxywizard.rc new file mode 100644 index 0000000..7f5327c --- /dev/null +++ b/trunk/addon/doxywizard/doxywizard.rc @@ -0,0 +1 @@ +IDI_ICON1 ICON DISCARDABLE "doxywizard.ico" diff --git a/trunk/addon/doxywizard/expert.cpp b/trunk/addon/doxywizard/expert.cpp new file mode 100644 index 0000000..4bbb104 --- /dev/null +++ b/trunk/addon/doxywizard/expert.cpp @@ -0,0 +1,561 @@ +#include "expert.h" +#include "inputbool.h" +#include "inputstring.h" +#include "inputint.h" +#include "inputstring.h" +#include "inputstrlist.h" +#include <QtGui> +#include <QtXml> +#include "config.h" +#include "version.h" + +#undef SA +#define SA(x) QString::fromAscii(x) + +static QString convertToComment(const QString &s) +{ + if (s.isEmpty()) + { + return QString(); + } + else + { + return SA("# ")+ + s.trimmed().replace(SA("\n"),SA("\n# "))+ + SA("\n"); + } +} + +//------------------------------------------------------------------------------------ + +Expert::Expert() +{ + m_treeWidget = new QTreeWidget; + m_treeWidget->setColumnCount(1); + m_topicStack = new QStackedWidget; + m_inShowHelp = FALSE; + + QFile file(SA(":/config.xml")); + QString err; + int errLine,errCol; + QDomDocument configXml; + if (file.open(QIODevice::ReadOnly)) + { + if (!configXml.setContent(&file,false,&err,&errLine,&errCol)) + { + QString msg = tr("Error parsing internal config.xml at line %1 column %2.\n%3"). + arg(errLine).arg(errCol).arg(err); + QMessageBox::warning(this, tr("Error"), msg); + exit(1); + } + } + m_rootElement = configXml.documentElement(); + + createTopics(m_rootElement); + m_helper = new QTextEdit; + m_helper->setReadOnly(true); + m_splitter = new QSplitter(Qt::Vertical); + m_splitter->addWidget(m_treeWidget); + m_splitter->addWidget(m_helper); + + QWidget *rightSide = new QWidget; + QGridLayout *grid = new QGridLayout(rightSide); + m_prev = new QPushButton(tr("Previous")); + m_prev->setEnabled(false); + m_next = new QPushButton(tr("Next")); + grid->addWidget(m_topicStack,0,0,1,2); + grid->addWidget(m_prev,1,0,Qt::AlignLeft); + grid->addWidget(m_next,1,1,Qt::AlignRight); + grid->setColumnStretch(0,1); + grid->setRowStretch(0,1); + + addWidget(m_splitter); + addWidget(rightSide); + connect(m_next,SIGNAL(clicked()),SLOT(nextTopic())); + + connect(m_prev,SIGNAL(clicked()),SLOT(prevTopic())); +} + +Expert::~Expert() +{ + QHashIterator<QString,Input*> i(m_options); + while (i.hasNext()) + { + i.next(); + delete i.value(); + } +} + +void Expert::createTopics(const QDomElement &rootElem) +{ + QList<QTreeWidgetItem*> items; + QDomElement childElem = rootElem.firstChildElement(); + while (!childElem.isNull()) + { + if (childElem.tagName()==SA("group")) + { + QString name = childElem.attribute(SA("name")); + items.append(new QTreeWidgetItem((QTreeWidget*)0,QStringList(name))); + QWidget *widget = createTopicWidget(childElem); + m_topics[name] = widget; + m_topicStack->addWidget(widget); + } + childElem = childElem.nextSiblingElement(); + } + m_treeWidget->setHeaderLabels(QStringList() << SA("Topics")); + m_treeWidget->insertTopLevelItems(0,items); + connect(m_treeWidget, + SIGNAL(currentItemChanged(QTreeWidgetItem *,QTreeWidgetItem *)), + this, + SLOT(activateTopic(QTreeWidgetItem *,QTreeWidgetItem *))); +} + + +QWidget *Expert::createTopicWidget(QDomElement &elem) +{ + QScrollArea *area = new QScrollArea; + QWidget *topic = new QWidget; + QGridLayout *layout = new QGridLayout(topic); + QDomElement child = elem.firstChildElement(); + int row=0; + while (!child.isNull()) + { + QString type = child.attribute(SA("type")); + if (type==SA("bool")) + { + InputBool *boolOption = + new InputBool( + layout,row, + child.attribute(SA("id")), + child.attribute(SA("defval"))==SA("1"), + child.attribute(SA("docs")) + ); + m_options.insert( + child.attribute(SA("id")), + boolOption + ); + connect(boolOption,SIGNAL(showHelp(Input*)),SLOT(showHelp(Input*))); + connect(boolOption,SIGNAL(changed()),SIGNAL(changed())); + } + else if (type==SA("string")) + { + InputString::StringMode mode; + QString format = child.attribute(SA("format")); + if (format==SA("dir")) + { + mode = InputString::StringDir; + } + else if (format==SA("file")) + { + mode = InputString::StringFile; + } + else // format=="string" + { + mode = InputString::StringFree; + } + InputString *stringOption = + new InputString( + layout,row, + child.attribute(SA("id")), + child.attribute(SA("defval")), + mode, + child.attribute(SA("docs")), + child.attribute(SA("abspath")) + ); + m_options.insert( + child.attribute(SA("id")), + stringOption + ); + connect(stringOption,SIGNAL(showHelp(Input*)),SLOT(showHelp(Input*))); + connect(stringOption,SIGNAL(changed()),SIGNAL(changed())); + } + else if (type==SA("enum")) + { + InputString *enumList = new InputString( + layout,row, + child.attribute(SA("id")), + child.attribute(SA("defval")), + InputString::StringFixed, + child.attribute(SA("docs")) + ); + QDomElement enumVal = child.firstChildElement(); + while (!enumVal.isNull()) + { + enumList->addValue(enumVal.attribute(SA("name"))); + enumVal = enumVal.nextSiblingElement(); + } + enumList->setDefault(); + + m_options.insert(child.attribute(SA("id")),enumList); + connect(enumList,SIGNAL(showHelp(Input*)),SLOT(showHelp(Input*))); + connect(enumList,SIGNAL(changed()),SIGNAL(changed())); + } + else if (type==SA("int")) + { + InputInt *intOption = + new InputInt( + layout,row, + child.attribute(SA("id")), + child.attribute(SA("defval")).toInt(), + child.attribute(SA("minval")).toInt(), + child.attribute(SA("maxval")).toInt(), + child.attribute(SA("docs")) + ); + m_options.insert( + child.attribute(SA("id")), + intOption + ); + connect(intOption,SIGNAL(showHelp(Input*)),SLOT(showHelp(Input*))); + connect(intOption,SIGNAL(changed()),SIGNAL(changed())); + } + else if (type==SA("list")) + { + InputStrList::ListMode mode; + QString format = child.attribute(SA("format")); + if (format==SA("dir")) + { + mode = InputStrList::ListDir; + } + else if (format==SA("file")) + { + mode = InputStrList::ListFile; + } + else if (format==SA("filedir")) + { + mode = InputStrList::ListFileDir; + } + else // format=="string" + { + mode = InputStrList::ListString; + } + QStringList sl; + QDomElement listVal = child.firstChildElement(); + while (!listVal.isNull()) + { + sl.append(listVal.attribute(SA("name"))); + listVal = listVal.nextSiblingElement(); + } + InputStrList *listOption = + new InputStrList( + layout,row, + child.attribute(SA("id")), + sl, + mode, + child.attribute(SA("docs")) + ); + m_options.insert( + child.attribute(SA("id")), + listOption + ); + connect(listOption,SIGNAL(showHelp(Input*)),SLOT(showHelp(Input*))); + connect(listOption,SIGNAL(changed()),SIGNAL(changed())); + } + else if (type==SA("obsolete")) + { + // ignore + } + else // should not happen + { + printf("Unsupported type %s\n",qPrintable(child.attribute(SA("type")))); + } + child = child.nextSiblingElement(); + } + + // compute dependencies between options + child = elem.firstChildElement(); + while (!child.isNull()) + { + QString dependsOn = child.attribute(SA("depends")); + QString id = child.attribute(SA("id")); + if (!dependsOn.isEmpty()) + { + Input *parentOption = m_options[dependsOn]; + Input *thisOption = m_options[id]; + Q_ASSERT(parentOption); + Q_ASSERT(thisOption); + if (parentOption && thisOption) + { + //printf("Adding dependency '%s' (%p)->'%s' (%p)\n", + // qPrintable(dependsOn),parentOption, + // qPrintable(id),thisOption); + parentOption->addDependency(thisOption); + } + } + child = child.nextSiblingElement(); + } + + // set initial dependencies + QHashIterator<QString,Input*> i(m_options); + while (i.hasNext()) + { + i.next(); + if (i.value()) + { + i.value()->updateDependencies(); + } + } + + layout->setRowStretch(row,1); + layout->setColumnStretch(1,2); + layout->setSpacing(5); + topic->setLayout(layout); + area->setWidget(topic); + area->setWidgetResizable(true); + return area; +} + +void Expert::activateTopic(QTreeWidgetItem *item,QTreeWidgetItem *) +{ + if (item) + { + QWidget *w = m_topics[item->text(0)]; + m_topicStack->setCurrentWidget(w); + m_prev->setEnabled(m_topicStack->currentIndex()!=0); + m_next->setEnabled(m_topicStack->currentIndex()!=m_topicStack->count()-1); + } +} + +void Expert::loadSettings(QSettings *s) +{ + QHashIterator<QString,Input*> i(m_options); + while (i.hasNext()) + { + i.next(); + QVariant var = s->value(SA("config/")+i.key()); + if (i.value()) + { + //printf("Loading key %s: type=%d value='%s'\n",qPrintable(i.key()),var.type(),qPrintable(var.toString())); + i.value()->value() = var; + i.value()->update(); + } + } +} + +void Expert::saveSettings(QSettings *s) +{ + QHashIterator<QString,Input*> i(m_options); + while (i.hasNext()) + { + i.next(); + //printf("Saving key %s: type=%d value='%s'\n",qPrintable(i.key()),i.value()->value().type(),qPrintable(i.value()->value().toString())); + if (i.value()) + { + s->setValue(SA("config/")+i.key(),i.value()->value()); + } + } +} + +void Expert::loadConfig(const QString &fileName) +{ + //printf("Expert::loadConfig(%s)\n",qPrintable(fileName)); + parseConfig(fileName,m_options); +} + +void Expert::saveTopic(QTextStream &t,QDomElement &elem,QTextCodec *codec, + bool brief) +{ + // write group header + t << endl; + t << "#---------------------------------------------------------------------------" << endl; + t << "# " << elem.attribute(SA("docs")) << endl; + t << "#---------------------------------------------------------------------------" << endl; + + // write options... + QDomElement childElem = elem.firstChildElement(); + while (!childElem.isNull()) + { + QString type = childElem.attribute(SA("type")); + QString name = childElem.attribute(SA("id")); + QHash<QString,Input*>::const_iterator i = m_options.find(name); + if (i!=m_options.end()) + { + Input *option = i.value(); + if (!brief) + { + t << endl; + t << convertToComment(childElem.attribute(SA("docs"))); + t << endl; + } + t << name.leftJustified(23) << "= "; + if (option) + { + option->writeValue(t,codec); + } + t << endl; + } + childElem = childElem.nextSiblingElement(); + } + +} + +bool Expert::writeConfig(QTextStream &t,bool brief) +{ + if (!brief) + { + // write global header + t << "# Doxyfile " << versionString << endl << endl; // TODO: add version + t << "# This file describes the settings to be used by the documentation system\n"; + t << "# doxygen (www.doxygen.org) for a project\n"; + t << "#\n"; + t << "# All text after a hash (#) is considered a comment and will be ignored\n"; + t << "# The format is:\n"; + t << "# TAG = value [value, ...]\n"; + t << "# For lists items can also be appended using:\n"; + t << "# TAG += value [value, ...]\n"; + t << "# Values that contain spaces should be placed between quotes (\" \")\n"; + } + + QTextCodec *codec = 0; + Input *option = m_options[QString::fromAscii("DOXYFILE_ENCODING")]; + if (option) + { + codec = QTextCodec::codecForName(option->value().toString().toAscii()); + if (codec==0) // fallback: use UTF-8 + { + codec = QTextCodec::codecForName("UTF-8"); + } + } + QDomElement childElem = m_rootElement.firstChildElement(); + while (!childElem.isNull()) + { + saveTopic(t,childElem,codec,brief); + childElem = childElem.nextSiblingElement(); + } + return true; +} + +QByteArray Expert::saveInnerState () const +{ + return m_splitter->saveState(); +} + +bool Expert::restoreInnerState ( const QByteArray & state ) +{ + return m_splitter->restoreState(state); +} + +void Expert::showHelp(Input *option) +{ + if (!m_inShowHelp) + { + m_inShowHelp = TRUE; + m_helper->setText( + QString::fromAscii("<qt><b>")+option->id()+ + QString::fromAscii("</b><br>")+ + option->docs(). + replace(QChar::fromAscii('\n'),QChar::fromAscii(' '))+ + QString::fromAscii("<qt>") + ); + m_inShowHelp = FALSE; + } +} + +void Expert::nextTopic() +{ + m_topicStack->setCurrentIndex(m_topicStack->currentIndex()+1); + m_next->setEnabled(m_topicStack->count()!=m_topicStack->currentIndex()+1); + m_prev->setEnabled(m_topicStack->currentIndex()!=0); + m_treeWidget->setCurrentItem(m_treeWidget->invisibleRootItem()->child(m_topicStack->currentIndex())); +} + +void Expert::prevTopic() +{ + m_topicStack->setCurrentIndex(m_topicStack->currentIndex()-1); + m_next->setEnabled(m_topicStack->count()!=m_topicStack->currentIndex()+1); + m_prev->setEnabled(m_topicStack->currentIndex()!=0); + m_treeWidget->setCurrentItem(m_treeWidget->invisibleRootItem()->child(m_topicStack->currentIndex())); +} + +void Expert::resetToDefaults() +{ + //printf("Expert::makeDefaults()\n"); + QHashIterator<QString,Input*> i(m_options); + while (i.hasNext()) + { + i.next(); + if (i.value()) + { + i.value()->reset(); + } + } +} + +static bool stringVariantToBool(const QVariant &v) +{ + QString s = v.toString().toLower(); + return s==QString::fromAscii("yes") || s==QString::fromAscii("true") || s==QString::fromAscii("1"); +} + +static bool getBoolOption( + const QHash<QString,Input*>&model,const QString &name) +{ + Input *option = model[name]; + Q_ASSERT(option!=0); + return stringVariantToBool(option->value()); +} + +static QString getStringOption( + const QHash<QString,Input*>&model,const QString &name) +{ + Input *option = model[name]; + Q_ASSERT(option!=0); + return option->value().toString(); +} + + +bool Expert::htmlOutputPresent(const QString &workingDir) const +{ + bool generateHtml = getBoolOption(m_options,QString::fromAscii("GENERATE_HTML")); + if (!generateHtml || workingDir.isEmpty()) return false; + QString indexFile = getHtmlOutputIndex(workingDir); + QFileInfo fi(indexFile); + return fi.exists() && fi.isFile(); +} + +QString Expert::getHtmlOutputIndex(const QString &workingDir) const +{ + QString outputDir = getStringOption(m_options,QString::fromAscii("OUTPUT_DIRECTORY")); + QString htmlOutputDir = getStringOption(m_options,QString::fromAscii("HTML_OUTPUT")); + //printf("outputDir=%s\n",qPrintable(outputDir)); + //printf("htmlOutputDir=%s\n",qPrintable(htmlOutputDir)); + QString indexFile = workingDir; + if (QFileInfo(outputDir).isAbsolute()) // override + { + indexFile = outputDir; + } + else // append + { + indexFile += QString::fromAscii("/")+outputDir; + } + if (QFileInfo(htmlOutputDir).isAbsolute()) // override + { + indexFile = htmlOutputDir; + } + else // append + { + indexFile += QString::fromAscii("/")+htmlOutputDir; + } + indexFile+=QString::fromAscii("/index.html"); + return indexFile; +} + +bool Expert::pdfOutputPresent(const QString &workingDir) const +{ + bool generateLatex = getBoolOption(m_options,QString::fromAscii("GENERATE_LATEX")); + bool pdfLatex = getBoolOption(m_options,QString::fromAscii("USE_PDFLATEX")); + if (!generateLatex || !pdfLatex) return false; + QString latexOutput = getStringOption(m_options,QString::fromAscii("LATEX_OUTPUT")); + QString indexFile; + if (QFileInfo(latexOutput).isAbsolute()) + { + indexFile = latexOutput+QString::fromAscii("/refman.pdf"); + } + else + { + indexFile = workingDir+QString::fromAscii("/")+ + latexOutput+QString::fromAscii("/refman.pdf"); + } + QFileInfo fi(indexFile); + return fi.exists() && fi.isFile(); +} + diff --git a/trunk/addon/doxywizard/expert.h b/trunk/addon/doxywizard/expert.h new file mode 100644 index 0000000..8d43161 --- /dev/null +++ b/trunk/addon/doxywizard/expert.h @@ -0,0 +1,65 @@ +#ifndef EXPERT_H +#define EXPERT_H + +#include <QSplitter> +#include <QDomElement> +#include <QHash> + +class QTreeWidget; +class QTreeWidgetItem; +class QStackedWidget; +class QSettings; +class QTextEdit; +class QTextCodec; +class QPushButton; +class Input; + +class Expert : public QSplitter +{ + Q_OBJECT + + public: + Expert(); + ~Expert(); + void loadSettings(QSettings *); + void saveSettings(QSettings *); + void loadConfig(const QString &fileName); + bool writeConfig(QTextStream &t,bool brief); + QByteArray saveInnerState () const; + bool restoreInnerState ( const QByteArray & state ); + const QHash<QString,Input*> &modelData() const { return m_options; } + void resetToDefaults(); + bool htmlOutputPresent(const QString &workingDir) const; + bool pdfOutputPresent(const QString &workingDir) const; + QString getHtmlOutputIndex(const QString &workingDir) const; + + public slots: + void activateTopic(QTreeWidgetItem *,QTreeWidgetItem *); + QWidget *createTopicWidget(QDomElement &elem); + + private slots: + void showHelp(Input *); + void nextTopic(); + void prevTopic(); + + signals: + void changed(); + + private: + void createTopics(const QDomElement &); + void saveTopic(QTextStream &t,QDomElement &elem,QTextCodec *codec,bool brief); + + QSplitter *m_splitter; + QTextEdit *m_helper; + QTreeWidget *m_treeWidget; + QStackedWidget *m_topicStack; + QHash<QString,QWidget *> m_topics; + QHash<QString,QObject *> m_optionWidgets; + QHash<QString,Input *> m_options; + QPushButton *m_next; + QPushButton *m_prev; + QDomElement m_rootElement; + bool m_inShowHelp; +}; + +#endif diff --git a/trunk/addon/doxywizard/helplabel.h b/trunk/addon/doxywizard/helplabel.h new file mode 100644 index 0000000..07e2932 --- /dev/null +++ b/trunk/addon/doxywizard/helplabel.h @@ -0,0 +1,33 @@ +#ifndef HELPLABEL_H +#define HELPLABEL_H + +#include <QLabel> +#include <QMenu> + +class HelpLabel : public QLabel +{ + Q_OBJECT + public: + HelpLabel(const QString &text) : QLabel(text) + { setContextMenuPolicy(Qt::CustomContextMenu); + connect(this,SIGNAL(customContextMenuRequested(const QPoint&)), + this,SLOT(showMenu(const QPoint&))); + } + signals: + void enter(); + void reset(); + private slots: + void showMenu(const QPoint &p) + { + QMenu menu(this); + QAction *a = menu.addAction(tr("Reset to default")); + if (menu.exec(mapToGlobal(p))==a) + { + reset(); + } + } + protected: + void enterEvent( QEvent * event ) { enter(); QLabel::enterEvent(event); } +}; + +#endif diff --git a/trunk/addon/doxywizard/images/add.png b/trunk/addon/doxywizard/images/add.png new file mode 100644 index 0000000..30a7090 Binary files /dev/null and b/trunk/addon/doxywizard/images/add.png differ diff --git a/trunk/addon/doxywizard/images/del.png b/trunk/addon/doxywizard/images/del.png new file mode 100644 index 0000000..ceb6a60 Binary files /dev/null and b/trunk/addon/doxywizard/images/del.png differ diff --git a/trunk/addon/doxywizard/images/file.png b/trunk/addon/doxywizard/images/file.png new file mode 100644 index 0000000..e204f67 Binary files /dev/null and b/trunk/addon/doxywizard/images/file.png differ diff --git a/trunk/addon/doxywizard/images/folder.png b/trunk/addon/doxywizard/images/folder.png new file mode 100644 index 0000000..2e420e0 Binary files /dev/null and b/trunk/addon/doxywizard/images/folder.png differ diff --git a/trunk/addon/doxywizard/images/refresh.png b/trunk/addon/doxywizard/images/refresh.png new file mode 100644 index 0000000..fd6d565 Binary files /dev/null and b/trunk/addon/doxywizard/images/refresh.png differ diff --git a/trunk/addon/doxywizard/images/tunecolor.png b/trunk/addon/doxywizard/images/tunecolor.png new file mode 100644 index 0000000..bf7be83 Binary files /dev/null and b/trunk/addon/doxywizard/images/tunecolor.png differ diff --git a/trunk/addon/doxywizard/input.h b/trunk/addon/doxywizard/input.h new file mode 100644 index 0000000..dd1773c --- /dev/null +++ b/trunk/addon/doxywizard/input.h @@ -0,0 +1,34 @@ +#ifndef INPUT_H +#define INPUT_H + +#include <QVariant> + +class QTextStream; +class QTextCodec; + +class Input +{ + public: + enum Kind + { + Bool, + Int, + String, + StrList, + Obsolete + }; + virtual ~Input() {} + virtual QVariant &value() = 0; + virtual void update() = 0; + virtual Kind kind() const = 0; + virtual QString docs() const = 0; + virtual QString id() const = 0; + virtual void addDependency(Input *option) = 0; + virtual void setEnabled(bool) = 0; + virtual void updateDependencies() = 0; + virtual void reset() = 0; + virtual void writeValue(QTextStream &t,QTextCodec *codec) = 0; +}; + + +#endif diff --git a/trunk/addon/doxywizard/inputbool.cpp b/trunk/addon/doxywizard/inputbool.cpp new file mode 100644 index 0000000..cd83f88 --- /dev/null +++ b/trunk/addon/doxywizard/inputbool.cpp @@ -0,0 +1,110 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#include "inputbool.h" +#include "helplabel.h" +#include <QtGui> + +InputBool::InputBool( QGridLayout *layout, int &row, + const QString &id, bool checked, + const QString &docs ) + : m_default(checked), m_docs(docs), m_id(id) +{ + m_lab = new HelpLabel(id); + m_cb = new QCheckBox; + layout->addWidget(m_lab,row, 0); + layout->addWidget(m_cb,row, 1); + m_enabled = true; + m_state=!checked; // force update + setValue(checked); + connect( m_cb, SIGNAL(toggled(bool)), SLOT(setValue(bool)) ); + connect( m_lab, SIGNAL(enter()), SLOT(help()) ); + connect( m_lab, SIGNAL(reset()), SLOT(reset()) ); + row++; +} + +void InputBool::help() +{ + showHelp(this); +} + +void InputBool::setEnabled(bool b) +{ + m_enabled = b; + m_cb->setEnabled(b); + updateDependencies(); +} + +void InputBool::updateDependencies() +{ + for (int i=0;i<m_dependencies.count();i++) + { + m_dependencies[i]->setEnabled(m_enabled && m_state); + } +} + +void InputBool::setValue( bool s ) +{ + if (m_state!=s) + { + m_state=s; + updateDefault(); + updateDependencies(); + m_cb->setChecked( s ); + m_value = m_state; + emit changed(); + } +} + +void InputBool::updateDefault() +{ + if (m_state==m_default) + { + m_lab->setText(QString::fromAscii("<qt>")+m_id+QString::fromAscii("</qt")); + } + else + { + m_lab->setText(QString::fromAscii("<qt><font color='red'>")+m_id+QString::fromAscii("</font></qt>")); + } +} + +QVariant &InputBool::value() +{ + return m_value; +} + +void InputBool::update() +{ + QString v = m_value.toString().toLower(); + m_state = (v==QString::fromAscii("yes") || + v==QString::fromAscii("true") || + v==QString::fromAscii("1")); + m_cb->setChecked( m_state ); + updateDefault(); + updateDependencies(); +} + +void InputBool::reset() +{ + setValue(m_default); +} + +void InputBool::writeValue(QTextStream &t,QTextCodec *codec) +{ + if (m_state) + t << codec->fromUnicode(QString::fromAscii("YES")); + else + t << codec->fromUnicode(QString::fromAscii("NO")); +} + diff --git a/trunk/addon/doxywizard/inputbool.h b/trunk/addon/doxywizard/inputbool.h new file mode 100644 index 0000000..63d16e6 --- /dev/null +++ b/trunk/addon/doxywizard/inputbool.h @@ -0,0 +1,70 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#ifndef _INPUTBOOL_H +#define _INPUTBOOL_H + +#include "input.h" +#include <QObject> + +class QCheckBox; +class QGridLayout; +class QLabel; + +class InputBool : public QObject, public Input +{ + Q_OBJECT + + public: + InputBool(QGridLayout *layout,int &row,const QString &id, + bool enabled, const QString &docs ); + + // Input + QVariant &value(); + void update(); + Kind kind() const { return Bool; } + QString docs() const { return m_docs; } + QString id() const { return m_id; } + void addDependency(Input *option) { m_dependencies+=option; } + void setEnabled(bool); + void updateDependencies(); + void writeValue(QTextStream &t,QTextCodec *codec); + + public slots: + void reset(); + void setValue(bool); + + signals: + void changed(); + void toggle(QString,bool); + void showHelp(Input *); + + private slots: + void help(); + + private: + void updateDefault(); + bool m_state; + bool m_default; + bool m_enabled; + QVariant m_value; + QCheckBox *m_cb; + QString m_docs; + QList<Input*> m_dependencies; + QString m_id; + QLabel *m_lab; + +}; + +#endif diff --git a/trunk/addon/doxywizard/inputint.cpp b/trunk/addon/doxywizard/inputint.cpp new file mode 100644 index 0000000..08df309 --- /dev/null +++ b/trunk/addon/doxywizard/inputint.cpp @@ -0,0 +1,96 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#include "inputint.h" +#include "helplabel.h" + +#include <QtGui> + +InputInt::InputInt( QGridLayout *layout,int &row, + const QString & id, + int defVal, int minVal,int maxVal, + const QString & docs ) + : m_default(defVal), m_minVal(minVal), m_maxVal(maxVal), m_docs(docs), m_id(id) +{ + m_lab = new HelpLabel(id); + m_sp = new QSpinBox; + m_sp->setMinimum(minVal); + m_sp->setMaximum(maxVal); + m_sp->setSingleStep(1); + m_val=defVal-1; // force update + setValue(defVal); + + layout->addWidget( m_lab, row, 0 ); + layout->addWidget( m_sp, row, 1 ); + + connect(m_sp, SIGNAL(valueChanged(int)), + this, SLOT(setValue(int)) ); + connect( m_lab, SIGNAL(enter()), SLOT(help()) ); + connect( m_lab, SIGNAL(reset()), SLOT(reset()) ); + row++; +} + +void InputInt::help() +{ + showHelp(this); +} + + +void InputInt::setValue(int val) +{ + val = qMax(m_minVal,val); + val = qMin(m_maxVal,val); + if (val!=m_val) + { + m_val = val; + m_sp->setValue(val); + m_value = m_val; + if (m_val==m_default) + { + m_lab->setText(QString::fromAscii("<qt>")+m_id+QString::fromAscii("</qt")); + } + else + { + m_lab->setText(QString::fromAscii("<qt><font color='red'>")+m_id+QString::fromAscii("</font></qt>")); + } + emit changed(); + } +} + +void InputInt::setEnabled(bool state) +{ + m_lab->setEnabled(state); + m_sp->setEnabled(state); +} + +QVariant &InputInt::value() +{ + return m_value; +} + +void InputInt::update() +{ + setValue(m_value.toInt()); +} + +void InputInt::reset() +{ + setValue(m_default); +} + +void InputInt::writeValue(QTextStream &t,QTextCodec *) +{ + t << m_val; +} + diff --git a/trunk/addon/doxywizard/inputint.h b/trunk/addon/doxywizard/inputint.h new file mode 100644 index 0000000..9ac506d --- /dev/null +++ b/trunk/addon/doxywizard/inputint.h @@ -0,0 +1,70 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#ifndef _INPUTINT_H +#define _INPUTINT_H + +#include "input.h" +#include <QObject> + +class QGridLayout; +class QLabel; +class QSpinBox; + +class InputInt : public QObject, public Input +{ + Q_OBJECT + + public: + InputInt( QGridLayout *layout,int &row, + const QString &id, int defVal, + int minVal, int maxVal, + const QString &docs ); + ~InputInt(){}; + + // Input + QVariant &value(); + void update(); + Kind kind() const { return Int; } + QString docs() const { return m_docs; } + QString id() const { return m_id; } + void addDependency(Input *) { Q_ASSERT(false); } + void setEnabled(bool); + void updateDependencies() {} + void writeValue(QTextStream &t,QTextCodec *codec); + + public slots: + void reset(); + void setValue(int val); + + private slots: + void help(); + + signals: + void changed(); + void showHelp(Input *); + + private: + QLabel *m_lab; + QSpinBox *m_sp; + int m_val; + int m_default; + int m_minVal; + int m_maxVal; + QVariant m_value; + QString m_docs; + QString m_id; +}; + +#endif diff --git a/trunk/addon/doxywizard/inputstring.cpp b/trunk/addon/doxywizard/inputstring.cpp new file mode 100644 index 0000000..c0b92b3 --- /dev/null +++ b/trunk/addon/doxywizard/inputstring.cpp @@ -0,0 +1,193 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#include "inputstring.h" +#include "helplabel.h" +#include "doxywizard.h" +#include "config.h" + +#include <QtGui> + +InputString::InputString( QGridLayout *layout,int &row, + const QString & id, const QString &s, + StringMode m, const QString &docs, + const QString &absPath ) + : m_default(s), m_sm(m), m_index(0), m_docs(docs), m_id(id), + m_absPath(absPath==QString::fromAscii("1")) +{ + m_lab = new HelpLabel(id); + if (m==StringFixed) + { + layout->addWidget( m_lab, row, 0 ); + m_com = new QComboBox; + layout->addWidget( m_com, row, 1, 1, 3, Qt::AlignLeft ); + m_le=0; + m_br=0; + row++; + } + else + { + layout->addWidget( m_lab, row, 0 ); + m_le = new QLineEdit; + m_le->setText( s ); + //layout->setColumnMinimumWidth(2,150); + if (m==StringFile || m==StringDir) + { + layout->addWidget( m_le, row, 1 ); + m_br = new QToolBar; + m_br->setIconSize(QSize(24,24)); + if (m==StringFile) + { + QAction *file = m_br->addAction(QIcon(QString::fromAscii(":/images/file.png")),QString(),this,SLOT(browse())); + file->setToolTip(tr("Browse to a file")); + } + else + { + QAction *dir = m_br->addAction(QIcon(QString::fromAscii(":/images/folder.png")),QString(),this,SLOT(browse())); + dir->setToolTip(tr("Browse to a folder")); + } + layout->addWidget( m_br,row,2 ); + } + else + { + layout->addWidget( m_le, row, 1, 1, 2 ); + m_br=0; + } + m_com=0; + row++; + } + + if (m_le) connect( m_le, SIGNAL(textChanged(const QString&)), + this, SLOT(setValue(const QString&)) ); + if (m_com) connect( m_com, SIGNAL(activated(const QString &)), + this, SLOT(setValue(const QString &)) ); + m_str = s+QChar::fromAscii('!'); // force update + setValue(s); + connect( m_lab, SIGNAL(enter()), SLOT(help()) ); + connect( m_lab, SIGNAL(reset()), SLOT(reset()) ); +} + +void InputString::help() +{ + showHelp(this); +} + + +InputString::~InputString() +{ +} + + +void InputString::setValue(const QString &s) +{ + if (m_str!=s) + { + m_str = s; + m_value = m_str; + if (m_str==m_default) + { + m_lab->setText(QString::fromAscii("<qt>")+m_id+QString::fromAscii("</qt")); + } + else + { + m_lab->setText(QString::fromAscii("<qt><font color='red'>")+m_id+QString::fromAscii("</font></qt>")); + } + if (m_le && m_le->text()!=m_str) m_le->setText( m_str ); + emit changed(); + } +} + +void InputString::setEnabled(bool state) +{ + m_lab->setEnabled(state); + if (m_le) m_le->setEnabled(state); + if (m_br) m_br->setEnabled(state); + if (m_com) m_com->setEnabled(state); +} + +void InputString::browse() +{ + QString path = QFileInfo(MainWindow::instance().configFileName()).path(); + if (m_sm==StringFile) + { + QString fileName = QFileDialog::getOpenFileName(&MainWindow::instance(), + tr("Select file"),path); + if (!fileName.isNull()) + { + QDir dir(path); + if (!MainWindow::instance().configFileName().isEmpty() && dir.exists()) + { + fileName = m_absPath ? fileName : dir.relativeFilePath(fileName); + } + setValue(fileName); + } + } + else // sm==StringDir + { + QString dirName = QFileDialog::getExistingDirectory(&MainWindow::instance(), + tr("Select directory"),path); + if (!dirName.isNull()) + { + QDir dir(path); + if (!MainWindow::instance().configFileName().isEmpty() && dir.exists()) + { + dirName = m_absPath ? dirName : dir.relativeFilePath(dirName); + } + setValue(dirName); + } + } +} + +void InputString::clear() +{ + setValue(QString()); +} + +void InputString::addValue(QString s) +{ + if (m_sm==StringFixed) + { + m_values.append(s); + m_com->addItem(s); + } +} + +void InputString::setDefault() +{ + int index = m_values.indexOf(m_str); + if (index!=-1 && m_com) m_com->setCurrentIndex(index); +} + +QVariant &InputString::value() +{ + return m_value; +} + +void InputString::update() +{ + setValue(m_value.toString().trimmed()); + setDefault(); +} + +void InputString::reset() +{ + setValue(m_default); + setDefault(); +} + +void InputString::writeValue(QTextStream &t,QTextCodec *codec) +{ + writeStringValue(t,codec,m_str); +} + diff --git a/trunk/addon/doxywizard/inputstring.h b/trunk/addon/doxywizard/inputstring.h new file mode 100644 index 0000000..b957bfa --- /dev/null +++ b/trunk/addon/doxywizard/inputstring.h @@ -0,0 +1,90 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#ifndef _INPUTSTRING_H +#define _INPUTSTRING_H + +#include "input.h" + +#include <QObject> +#include <QMap> +#include <QStringList> + +class QLabel; +class QLineEdit; +class QToolBar; +class QComboBox; +class QGridLayout; + +class InputString : public QObject, public Input +{ + Q_OBJECT + + public: + enum StringMode { StringFree=0, + StringFile=1, + StringDir=2, + StringFixed=3 + }; + + InputString( QGridLayout *layout,int &row, + const QString &id, const QString &s, + StringMode m, + const QString &docs, + const QString &absPath = QString() ); + ~InputString(); + void addValue(QString s); + void setDefault(); + + // Input + QVariant &value(); + void update(); + Kind kind() const { return String; } + QString docs() const { return m_docs; } + QString id() const { return m_id; } + void addDependency(Input *) { Q_ASSERT(false); } + void setEnabled(bool); + void updateDependencies() {} + void writeValue(QTextStream &t,QTextCodec *codec); + + public slots: + void reset(); + void setValue(const QString&); + + signals: + void changed(); + void showHelp(Input *); + + private slots: + void browse(); + void clear(); + void help(); + + private: + QLabel *m_lab; + QLineEdit *m_le; + QToolBar *m_br; + QComboBox *m_com; + QString m_str; + QString m_default; + StringMode m_sm; + QStringList m_values; + int m_index; + QVariant m_value; + QString m_docs; + QString m_id; + bool m_absPath; +}; + +#endif diff --git a/trunk/addon/doxywizard/inputstrlist.cpp b/trunk/addon/doxywizard/inputstrlist.cpp new file mode 100644 index 0000000..bca92e2 --- /dev/null +++ b/trunk/addon/doxywizard/inputstrlist.cpp @@ -0,0 +1,254 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#include "inputstrlist.h" +#include "helplabel.h" +#include "doxywizard.h" +#include "config.h" + +#include <QtGui> + +InputStrList::InputStrList( QGridLayout *layout,int &row, + const QString & id, + const QStringList &sl, ListMode lm, + const QString & docs) + : m_default(sl), m_strList(sl), m_docs(docs), m_id(id) +{ + m_lab = new HelpLabel( id ); + + m_le = new QLineEdit; + m_le->clear(); + + QToolBar *toolBar = new QToolBar; + toolBar->setIconSize(QSize(24,24)); + m_add = toolBar->addAction(QIcon(QString::fromAscii(":/images/add.png")),QString(), + this,SLOT(addString())); + m_add->setToolTip(tr("Add item")); + m_del = toolBar->addAction(QIcon(QString::fromAscii(":/images/del.png")),QString(), + this,SLOT(delString())); + m_del->setToolTip(tr("Delete selected item")); + m_upd = toolBar->addAction(QIcon(QString::fromAscii(":/images/refresh.png")),QString(), + this,SLOT(updateString())); + m_upd->setToolTip(tr("Update selected item")); + + m_lb = new QListWidget; + //m_lb->setMinimumSize(400,100); + foreach (QString s, m_strList) m_lb->addItem(s); + + m_brFile=0; + m_brDir=0; + if (lm!=ListString) + { + if (lm&ListFile) + { + m_brFile = toolBar->addAction(QIcon(QString::fromAscii(":/images/file.png")),QString(), + this,SLOT(browseFiles())); + m_brFile->setToolTip(tr("Browse to a file")); + } + if (lm&ListDir) + { + m_brDir = toolBar->addAction(QIcon(QString::fromAscii(":/images/folder.png")),QString(), + this,SLOT(browseDir())); + m_brDir->setToolTip(tr("Browse to a folder")); + } + } + QHBoxLayout *rowLayout = new QHBoxLayout; + rowLayout->addWidget( m_le ); + rowLayout->addWidget( toolBar ); + layout->addWidget( m_lab, row,0 ); + layout->addLayout( rowLayout, row,1,1,2 ); + layout->addWidget( m_lb, row+1,1,1,2 ); + row+=2; + + m_value = m_strList; + + connect(m_le, SIGNAL(returnPressed()), + this, SLOT(addString()) ); + connect(m_lb, SIGNAL(currentTextChanged(const QString &)), + this, SLOT(selectText(const QString &))); + connect( m_lab, SIGNAL(enter()), SLOT(help()) ); + connect( m_lab, SIGNAL(reset()), SLOT(reset()) ); +} + +void InputStrList::help() +{ + showHelp(this); +} + + +void InputStrList::addString() +{ + if (!m_le->text().isEmpty()) + { + m_lb->addItem(m_le->text()); + m_strList.append(m_le->text()); + m_value = m_strList; + updateDefault(); + emit changed(); + m_le->clear(); + } +} + +void InputStrList::delString() +{ + if (m_lb->currentRow()!=-1) + { + int itemIndex = m_lb->currentRow(); + delete m_lb->currentItem(); + m_strList.removeAt(itemIndex); + m_value = m_strList; + updateDefault(); + emit changed(); + } +} + +void InputStrList::updateString() +{ + if (m_lb->currentRow()!=-1 && !m_le->text().isEmpty()) + { + m_lb->currentItem()->setText(m_le->text()); + m_strList.insert(m_lb->currentRow(),m_le->text()); + m_strList.removeAt(m_lb->currentRow()+1); + m_value = m_strList; + updateDefault(); + emit changed(); + } +} + +void InputStrList::selectText(const QString &s) +{ + m_le->setText(s); +} + +void InputStrList::setEnabled(bool state) +{ + m_lab->setEnabled(state); + m_le->setEnabled(state); + m_add->setEnabled(state); + m_del->setEnabled(state); + m_upd->setEnabled(state); + m_lb->setEnabled(state); + if (m_brFile) m_brFile->setEnabled(state); + if (m_brDir) m_brDir->setEnabled(state); +} + +void InputStrList::browseFiles() +{ + QString path = QFileInfo(MainWindow::instance().configFileName()).path(); + QStringList fileNames = QFileDialog::getOpenFileNames(); + + if (!fileNames.isEmpty()) + { + QStringList::Iterator it; + for ( it= fileNames.begin(); it != fileNames.end(); ++it ) + { + QString fileName; + QDir dir(path); + if (!MainWindow::instance().configFileName().isEmpty() && dir.exists()) + { + fileName = dir.relativeFilePath(*it); + } + if (fileName.isEmpty()) + { + fileName = *it; + } + m_lb->addItem(fileName); + m_strList.append(fileName); + m_value = m_strList; + updateDefault(); + emit changed(); + } + m_le->setText(m_strList[0]); + } +} + +void InputStrList::browseDir() +{ + QString path = QFileInfo(MainWindow::instance().configFileName()).path(); + QString dirName = QFileDialog::getExistingDirectory(); + + if (!dirName.isNull()) + { + QDir dir(path); + if (!MainWindow::instance().configFileName().isEmpty() && dir.exists()) + { + dirName = dir.relativeFilePath(dirName); + } + if (dirName.isEmpty()) + { + dirName=QString::fromAscii("."); + } + m_lb->addItem(dirName); + m_strList.append(dirName); + m_value = m_strList; + updateDefault(); + emit changed(); + m_le->setText(dirName); + } +} + +void InputStrList::setValue(const QStringList &sl) +{ + m_le->clear(); + m_lb->clear(); + m_strList = sl; + for (int i=0;i<m_strList.size();i++) + { + m_lb->addItem(m_strList[i].trimmed()); + } + updateDefault(); +} + +QVariant &InputStrList::value() +{ + return m_value; +} + +void InputStrList::update() +{ + setValue(m_value.toStringList()); +} + +void InputStrList::updateDefault() +{ + if (m_strList==m_default) + { + m_lab->setText(QString::fromAscii("<qt>")+m_id+QString::fromAscii("</qt")); + } + else + { + m_lab->setText(QString::fromAscii("<qt><font color='red'>")+m_id+QString::fromAscii("</font></qt>")); + } +} + +void InputStrList::reset() +{ + setValue(m_default); +} + +void InputStrList::writeValue(QTextStream &t,QTextCodec *codec) +{ + bool first=TRUE; + foreach (QString s, m_strList) + { + if (!first) + { + t << " \\" << endl; + t << " "; + } + first=FALSE; + writeStringValue(t,codec,s); + } +} + diff --git a/trunk/addon/doxywizard/inputstrlist.h b/trunk/addon/doxywizard/inputstrlist.h new file mode 100644 index 0000000..0201aee --- /dev/null +++ b/trunk/addon/doxywizard/inputstrlist.h @@ -0,0 +1,91 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#ifndef _INPUTSTRLIST_H +#define _INPUTSTRLIST_H + +#include "input.h" + +#include <QObject> +#include <QStringList> + +class QLabel; +class QLineEdit; +class QPushButton; +class QListWidget; +class QStringList; +class QGridLayout; +class QAction; + +class InputStrList : public QObject, public Input +{ + Q_OBJECT + + public: + enum ListMode { ListString = 0, + ListFile = 1, + ListDir = 2, + ListFileDir = ListFile | ListDir + }; + + InputStrList( QGridLayout *layout,int &row, + const QString &id, const QStringList &sl, + ListMode v, const QString &docs); + void setValue(const QStringList &sl); + + QVariant &value(); + void update(); + Kind kind() const { return StrList; } + QString docs() const { return m_docs; } + QString id() const { return m_id; } + void addDependency(Input *) { Q_ASSERT(false); } + void setEnabled(bool); + void updateDependencies() {} + void writeValue(QTextStream &t,QTextCodec *codec); + + public slots: + void reset(); + + signals: + void changed(); + void showHelp(Input *); + + private slots: + void addString(); + void delString(); + void updateString(); + void selectText(const QString &s); + void browseFiles(); + void browseDir(); + void help(); + + private: + void updateDefault(); + QLabel *m_lab; + QLineEdit *m_le; + QAction *m_add; + QAction *m_del; + QAction *m_upd; + QAction *m_brFile; + QAction *m_brDir; + QListWidget *m_lb; + QStringList m_default; + QStringList m_strList; + QVariant m_value; + QString m_docs; + QString m_id; + +}; + +#endif diff --git a/trunk/addon/doxywizard/version.h b/trunk/addon/doxywizard/version.h new file mode 100644 index 0000000..4752520 --- /dev/null +++ b/trunk/addon/doxywizard/version.h @@ -0,0 +1,23 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#ifndef VERSION_H +#define VERSION_H + +extern char versionString[]; + +#endif diff --git a/trunk/addon/doxywizard/wizard.cpp b/trunk/addon/doxywizard/wizard.cpp new file mode 100644 index 0000000..ce989e7 --- /dev/null +++ b/trunk/addon/doxywizard/wizard.cpp @@ -0,0 +1,1295 @@ +#include "wizard.h" +#include "input.h" +#include "doxywizard.h" + +#include <math.h> +#include <QtGui> + +// options configurable via the wizard +#define STR_PROJECT_NAME QString::fromAscii("PROJECT_NAME") +#define STR_PROJECT_LOGO QString::fromAscii("PROJECT_LOGO") +#define STR_PROJECT_BRIEF QString::fromAscii("PROJECT_BRIEF") +#define STR_INPUT QString::fromAscii("INPUT") +#define STR_OUTPUT_DIRECTORY QString::fromAscii("OUTPUT_DIRECTORY") +#define STR_PROJECT_NUMBER QString::fromAscii("PROJECT_NUMBER") +#define STR_RECURSIVE QString::fromAscii("RECURSIVE") +#define STR_OPTIMIZE_OUTPUT_FOR_C QString::fromAscii("OPTIMIZE_OUTPUT_FOR_C") +#define STR_OPTIMIZE_OUTPUT_JAVA QString::fromAscii("OPTIMIZE_OUTPUT_JAVA") +#define STR_OPTIMIZE_FOR_FORTRAN QString::fromAscii("OPTIMIZE_FOR_FORTRAN") +#define STR_OPTIMIZE_OUTPUT_VHDL QString::fromAscii("OPTIMIZE_OUTPUT_VHDL") +#define STR_CPP_CLI_SUPPORT QString::fromAscii("CPP_CLI_SUPPORT") +#define STR_HIDE_SCOPE_NAMES QString::fromAscii("HIDE_SCOPE_NAMES") +#define STR_EXTRACT_ALL QString::fromAscii("EXTRACT_ALL") +#define STR_SOURCE_BROWSER QString::fromAscii("SOURCE_BROWSER") +#define STR_GENERATE_HTML QString::fromAscii("GENERATE_HTML") +#define STR_GENERATE_LATEX QString::fromAscii("GENERATE_LATEX") +#define STR_GENERATE_MAN QString::fromAscii("GENERATE_MAN") +#define STR_GENERATE_RTF QString::fromAscii("GENERATE_RTF") +#define STR_GENERATE_XML QString::fromAscii("GENERATE_XML") +#define STR_GENERATE_HTMLHELP QString::fromAscii("GENERATE_HTMLHELP") +#define STR_GENERATE_TREEVIEW QString::fromAscii("GENERATE_TREEVIEW") +#define STR_USE_PDFLATEX QString::fromAscii("USE_PDFLATEX") +#define STR_PDF_HYPERLINKS QString::fromAscii("PDF_HYPERLINKS") +#define STR_SEARCHENGINE QString::fromAscii("SEARCHENGINE") +#define STR_HAVE_DOT QString::fromAscii("HAVE_DOT") +#define STR_CLASS_DIAGRAMS QString::fromAscii("CLASS_DIAGRAMS") +#define STR_CLASS_GRAPH QString::fromAscii("CLASS_GRAPH") +#define STR_COLLABORATION_GRAPH QString::fromAscii("COLLABORATION_GRAPH") +#define STR_GRAPHICAL_HIERARCHY QString::fromAscii("GRAPHICAL_HIERARCHY") +#define STR_INCLUDE_GRAPH QString::fromAscii("INCLUDE_GRAPH") +#define STR_INCLUDED_BY_GRAPH QString::fromAscii("INCLUDED_BY_GRAPH") +#define STR_CALL_GRAPH QString::fromAscii("CALL_GRAPH") +#define STR_CALLER_GRAPH QString::fromAscii("CALLER_GRAPH") +#define STR_HTML_COLORSTYLE_HUE QString::fromAscii("HTML_COLORSTYLE_HUE") +#define STR_HTML_COLORSTYLE_SAT QString::fromAscii("HTML_COLORSTYLE_SAT") +#define STR_HTML_COLORSTYLE_GAMMA QString::fromAscii("HTML_COLORSTYLE_GAMMA") + +static bool g_optimizeMapping[6][6] = +{ + // A: OPTIMIZE_OUTPUT_FOR_C + // B: OPTIMIZE_OUTPUT_JAVA + // C: OPTIMIZE_FOR_FORTRAN + // D: OPTIMIZE_OUTPUT_VHDL + // E: CPP_CLI_SUPPORT + // F: HIDE_SCOPE_NAMES + // A B C D E F + { false,false,false,false,false,false }, // 0: C++ + { false,false,false,false,true, false }, // 1: C++/CLI + { false,true, false,false,false,false }, // 2: C#/Java + { true, false,false,false,false,true }, // 3: C/PHP + { false,false,true, false,false,false }, // 4: Fortran + { false,false,false,true, false,false }, // 5: VHDL +}; + +static QString g_optimizeOptionNames[6] = +{ + STR_OPTIMIZE_OUTPUT_FOR_C, + STR_OPTIMIZE_OUTPUT_JAVA, + STR_OPTIMIZE_FOR_FORTRAN, + STR_OPTIMIZE_OUTPUT_VHDL, + STR_CPP_CLI_SUPPORT, + STR_HIDE_SCOPE_NAMES +}; + +//========================================================================== + +static bool stringVariantToBool(const QVariant &v) +{ + QString s = v.toString().toLower(); + return s==QString::fromAscii("yes") || s==QString::fromAscii("true") || s==QString::fromAscii("1"); +} + +static bool getBoolOption( + const QHash<QString,Input*>&model,const QString &name) +{ + Input *option = model[name]; + Q_ASSERT(option!=0); + return stringVariantToBool(option->value()); +} + +static int getIntOption( + const QHash<QString,Input*>&model,const QString &name) +{ + Input *option = model[name]; + Q_ASSERT(option!=0); + return option->value().toInt(); +} + +static QString getStringOption( + const QHash<QString,Input*>&model,const QString &name) +{ + Input *option = model[name]; + Q_ASSERT(option!=0); + return option->value().toString(); +} + +static void updateBoolOption( + const QHash<QString,Input*>&model,const QString &name,bool bNew) +{ + Input *option = model[name]; + Q_ASSERT(option!=0); + bool bOld = stringVariantToBool(option->value()); + if (bOld!=bNew) + { + option->value()=QString::fromAscii(bNew ? "true" : "false"); + option->update(); + } +} + +static void updateIntOption( + const QHash<QString,Input*>&model,const QString &name,int iNew) +{ + Input *option = model[name]; + Q_ASSERT(option!=0); + int iOld = option->value().toInt(); + if (iOld!=iNew) + { + option->value()=QString::fromAscii("%1").arg(iNew); + option->update(); + } +} + + +static void updateStringOption( + const QHash<QString,Input*>&model,const QString &name,const QString &s) +{ + Input *option = model[name]; + Q_ASSERT(option!=0); + if (option->value().toString()!=s) + { + option->value() = s; + option->update(); + } +} + +//========================================================================== + +TuneColorDialog::TuneColorDialog(int hue,int sat,int gamma,QWidget *parent) : QDialog(parent) +{ + setWindowTitle(tr("Tune the color of the HTML output")); + QGridLayout *layout = new QGridLayout(this); + m_image = new QImage(QString::fromAscii(":/images/tunecolor.png")); + m_imageLab = new QLabel; + updateImage(hue,sat,gamma); + layout->addWidget(new QLabel(tr("Example output: use the sliders on the right to adjust the color")),0,0); + layout->addWidget(m_imageLab,1,0); + QHBoxLayout *buttonsLayout = new QHBoxLayout; + + QPushButton *okButton = new QPushButton(tr("Ok")); + connect(okButton,SIGNAL(clicked()),SLOT(accept())); + okButton->setDefault(true); + QPushButton *cancelButton = new QPushButton(tr("Cancel")); + connect(cancelButton,SIGNAL(clicked()),SLOT(reject())); + + ColorPicker *huePicker = new ColorPicker(ColorPicker::Hue); + huePicker->setCol(hue,sat,gamma); + huePicker->setFixedWidth(20); + layout->addWidget(huePicker,1,1); + ColorPicker *satPicker = new ColorPicker(ColorPicker::Saturation); + satPicker->setCol(hue,sat,gamma); + satPicker->setFixedWidth(20); + layout->addWidget(satPicker,1,2); + ColorPicker *gamPicker = new ColorPicker(ColorPicker::Gamma); + gamPicker->setCol(hue,sat,gamma); + gamPicker->setFixedWidth(20); + layout->addWidget(gamPicker,1,3); + + connect(huePicker,SIGNAL(newHsv(int,int,int)),satPicker,SLOT(setCol(int,int,int))); + connect(satPicker,SIGNAL(newHsv(int,int,int)),huePicker,SLOT(setCol(int,int,int))); + connect(huePicker,SIGNAL(newHsv(int,int,int)),gamPicker,SLOT(setCol(int,int,int))); + connect(satPicker,SIGNAL(newHsv(int,int,int)),gamPicker,SLOT(setCol(int,int,int))); + connect(gamPicker,SIGNAL(newHsv(int,int,int)),satPicker,SLOT(setCol(int,int,int))); + connect(gamPicker,SIGNAL(newHsv(int,int,int)),huePicker,SLOT(setCol(int,int,int))); + connect(huePicker,SIGNAL(newHsv(int,int,int)),this,SLOT(updateImage(int,int,int))); + connect(satPicker,SIGNAL(newHsv(int,int,int)),this,SLOT(updateImage(int,int,int))); + connect(gamPicker,SIGNAL(newHsv(int,int,int)),this,SLOT(updateImage(int,int,int))); + + buttonsLayout->addStretch(); + buttonsLayout->addWidget(okButton); + buttonsLayout->addWidget(cancelButton); + layout->addLayout(buttonsLayout,5,0,1,4); +} + +void hsl2rgb(double h,double s,double l, + double *pRed,double *pGreen,double *pBlue) +{ + double v; + double r,g,b; + + r = l; // default to gray + g = l; + b = l; + v = (l <= 0.5) ? (l * (1.0 + s)) : (l + s - l * s); + if (v > 0) + { + double m; + double sv; + int sextant; + double fract, vsf, mid1, mid2; + + m = l + l - v; + sv = (v - m ) / v; + h *= 6.0; + sextant = (int)h; + fract = h - sextant; + vsf = v * sv * fract; + mid1 = m + vsf; + mid2 = v - vsf; + switch (sextant) + { + case 0: + r = v; + g = mid1; + b = m; + break; + case 1: + r = mid2; + g = v; + b = m; + break; + case 2: + r = m; + g = v; + b = mid1; + break; + case 3: + r = m; + g = mid2; + b = v; + break; + case 4: + r = mid1; + g = m; + b = v; + break; + case 5: + r = v; + g = m; + b = mid2; + break; + } + } + *pRed = r; + *pGreen = g; + *pBlue = b; +} + + + +void TuneColorDialog::updateImage(int hue,int sat,int gam) +{ + QImage coloredImg(m_image->width(),m_image->height(),QImage::Format_RGB32); + uint *srcPixel = (uint *)m_image->scanLine(0); + uint *dstPixel = (uint *)coloredImg.scanLine(0); + uint nrPixels = coloredImg.width()*coloredImg.height(); + for (uint i=0;i<nrPixels;i++,srcPixel++,dstPixel++) + { + QColor c = QColor::fromRgb(*srcPixel); + double r,g,b; + hsl2rgb(hue/359.0, sat/255.0, pow(c.green()/255.0,gam/100.0),&r,&g,&b); + *dstPixel = qRgb((int)(r*255.0),(int)(g*255.0),(int)(b*255.0)); + } + m_imageLab->setPixmap(QPixmap::fromImage(coloredImg)); + m_hue = hue; + m_sat = sat; + m_gam = gam; +} + +int TuneColorDialog::getHue() const +{ + return m_hue; +} + +int TuneColorDialog::getSaturation() const +{ + return m_sat; +} + +int TuneColorDialog::getGamma() const +{ + return m_gam; +} + +//========================================================================== + +ColorPicker::ColorPicker(Mode m) +{ + m_hue = 220; + m_gam = 100; + m_sat = 100; + m_mode = m; + m_pix = 0; +} + +ColorPicker::~ColorPicker() +{ + delete m_pix; +} + +void ColorPicker::paintEvent(QPaintEvent*) +{ + int w = width() - 5; + + QRect r(0, foff, w, height() - 2*foff); + int wi = r.width() - 2; + int hi = r.height() - 2; + if (!m_pix || m_pix->height() != hi || m_pix->width() != wi) + { + delete m_pix; + QImage img(wi, hi, QImage::Format_RGB32); + int y; + uint *pixel = (uint *) img.scanLine(0); + for (y = 0; y < hi; y++) + { + const uint *end = pixel + wi; + int yh = y2hue(y+coff); + int ys = y2sat(y+coff); + int yg = y2gam(y+coff); + while (pixel < end) + { + QColor c; + c.setHsv(yh, ys, (int)(255*pow(0.7,yg/100.0))); + *pixel = c.rgb(); + ++pixel; + } + } + m_pix = new QPixmap(QPixmap::fromImage(img)); + } + QPainter p(this); + p.drawPixmap(1, coff, *m_pix); + const QPalette &g = palette(); + qDrawShadePanel(&p, r, g, true); + p.setPen(g.foreground().color()); + p.setBrush(g.foreground()); + QPolygon a; + int y = m_mode==Hue ? hue2y(m_hue) : + m_mode==Saturation ? sat2y(m_sat) : + gam2y(m_gam); + a.setPoints(3, w, y, w+5, y+5, w+5, y-5); + p.eraseRect(w, 0, 5, height()); + p.drawPolygon(a); +} + +void ColorPicker::mouseMoveEvent(QMouseEvent *m) +{ + if (m_mode==Hue) setHue(y2hue(m->y())); + else if (m_mode==Saturation) setSat(y2sat(m->y())); + else setGam(y2gam(m->y())); +} + +void ColorPicker::mousePressEvent(QMouseEvent *m) +{ + if (m_mode==Hue) setHue(y2hue(m->y())); + else if (m_mode==Saturation) setSat(y2sat(m->y())); + else setGam(y2gam(m->y())); +} + +void ColorPicker::setHue(int h) +{ + if (h==m_hue) return; + m_hue = qMax(0,qMin(h,359)); + delete m_pix; m_pix=0; + repaint(); + emit newHsv(m_hue,m_sat,m_gam); +} + +void ColorPicker::setSat(int s) +{ + if (s==m_sat) return; + m_sat = qMax(0,qMin(s,255)); + delete m_pix; m_pix=0; + repaint(); + emit newHsv(m_hue,m_sat,m_gam); +} + +void ColorPicker::setGam(int g) +{ + if (g==m_gam) return; + m_gam = qMax(40,qMin(g,240)); + delete m_pix; m_pix=0; + repaint(); + emit newHsv(m_hue,m_sat,m_gam); +} + +void ColorPicker::setCol(int h, int s, int g) +{ + if (m_hue!=h || m_sat!=s || m_gam!=g) + { + m_hue = h; + m_sat = s; + m_gam = g; + delete m_pix; m_pix=0; + repaint(); + } +} + +int ColorPicker::y2hue(int y) +{ + int d = height() - 2*coff - 1; + return m_mode==Hue ? (y - coff)*359/d : m_hue; +} + +int ColorPicker::hue2y(int v) +{ + int d = height() - 2*coff - 1; + return coff + v*d/359; +} + +int ColorPicker::y2sat(int y) +{ + int d = height() - 2*coff - 1; + return m_mode==Saturation ? 255 - (y - coff)*255/d : m_sat; +} + +int ColorPicker::sat2y(int v) +{ + int d = height() - 2*coff - 1; + return coff + (255-v)*d/255; +} + +int ColorPicker::y2gam(int y) +{ + int d = height() - 2*coff - 1; + return m_mode==Gamma ? 240 - (y - coff)*200/d : m_gam; +} + +int ColorPicker::gam2y(int g) +{ + int d = height() - 2*coff - 1; + return coff + (240-g)*d/200; +} + +//========================================================================== + +Step1::Step1(Wizard *wizard,const QHash<QString,Input*> &modelData) : m_wizard(wizard), m_modelData(modelData) +{ + QVBoxLayout *layout = new QVBoxLayout(this); + layout->setMargin(4); + layout->setSpacing(8); + QLabel *l = new QLabel(this); + l->setText(tr("Provide some information " + "about the project you are documenting")); + layout->addWidget(l); + QWidget *w = new QWidget( this ); + QGridLayout *grid = new QGridLayout(w); + grid->setSpacing(10); + + // project name + QLabel *projName = new QLabel(this); + projName->setText(tr("Project name:")); + projName->setAlignment(Qt::AlignRight|Qt::AlignVCenter); + // project brief + QLabel *projBrief = new QLabel(this); + projBrief->setText(tr("Project synopsis:")); + projBrief->setAlignment(Qt::AlignRight|Qt::AlignVCenter); + // project version + QLabel *projVersion = new QLabel(this); + projVersion->setText(tr("Project version or id:")); + projVersion->setAlignment(Qt::AlignRight|Qt::AlignVCenter); + // project icon + QLabel *projLogo = new QLabel(this); + projLogo->setText(tr("Project logo:")); + projLogo->setAlignment(Qt::AlignRight|Qt::AlignVCenter); + + grid->addWidget(projName,0,0); + grid->addWidget(projBrief,1,0); + grid->addWidget(projVersion,2,0); + grid->addWidget(projLogo,3,0); + + m_projName = new QLineEdit; + m_projBrief = new QLineEdit; + m_projNumber = new QLineEdit; + QPushButton *projIconSel = new QPushButton(this); + projIconSel->setText(tr("Select...")); + QPixmap pm(QSize(120,55)); + pm.fill(); + m_projIconLab = new QLabel; + m_projIconLab->setPixmap(pm); + + grid->addWidget(m_projName,0,1,1,2); + grid->addWidget(m_projBrief,1,1,1,2); + grid->addWidget(m_projNumber,2,1,1,2); + grid->addWidget(projIconSel,3,1); + grid->addWidget(m_projIconLab,3,2); + + grid->setColumnStretch(2,1); + + w->setLayout(grid); + + layout->addWidget(w); + + //--------------------------------------------------- + QFrame *f = new QFrame( this ); + f->setFrameStyle( QFrame::HLine | QFrame::Sunken ); + layout->addWidget(f); + + l = new QLabel(this); + l->setText(tr("Specify the directory to scan for source code")); + layout->addWidget(l); + QWidget *row = new QWidget; + QHBoxLayout *rowLayout = new QHBoxLayout(row); + rowLayout->setSpacing(10); + l = new QLabel(this); + l->setText(tr("Source code directory:")); + rowLayout->addWidget(l); + m_sourceDir = new QLineEdit; + m_srcSelectDir = new QPushButton(this); + m_srcSelectDir->setText(tr("Select...")); + rowLayout->addWidget(m_sourceDir); + rowLayout->addWidget(m_srcSelectDir); + layout->addWidget(row); + + m_recursive = new QCheckBox(this); + m_recursive->setText(tr("Scan recursively")); + m_recursive->setChecked(TRUE); + layout->addWidget(m_recursive); + + //--------------------------------------------------- + f = new QFrame( this ); + f->setFrameStyle( QFrame::HLine | QFrame::Sunken ); + layout->addWidget(f); + + l = new QLabel(this); + l->setText(tr("Specify the directory where doxygen should " + "put the generated documentation")); + layout->addWidget(l); + row = new QWidget; + rowLayout = new QHBoxLayout(row); + rowLayout->setSpacing(10); + l = new QLabel(this); + l->setText(tr("Destination directory:")); + rowLayout->addWidget(l); + m_destDir = new QLineEdit; + m_dstSelectDir = new QPushButton(this); + m_dstSelectDir->setText(tr("Select...")); + rowLayout->addWidget(m_destDir); + rowLayout->addWidget(m_dstSelectDir); + layout->addWidget(row); + layout->addStretch(1); + setLayout(layout); + + connect(projIconSel,SIGNAL(clicked()), + this,SLOT(selectProjectIcon())); + connect(m_srcSelectDir,SIGNAL(clicked()), + this,SLOT(selectSourceDir())); + connect(m_dstSelectDir,SIGNAL(clicked()), + this,SLOT(selectDestinationDir())); + connect(m_projName,SIGNAL(textChanged(const QString &)),SLOT(setProjectName(const QString &))); + connect(m_projBrief,SIGNAL(textChanged(const QString &)),SLOT(setProjectBrief(const QString &))); + connect(m_projNumber,SIGNAL(textChanged(const QString &)),SLOT(setProjectNumber(const QString &))); + connect(m_sourceDir,SIGNAL(textChanged(const QString &)),SLOT(setSourceDir(const QString &))); + connect(m_recursive,SIGNAL(stateChanged(int)),SLOT(setRecursiveScan(int))); + connect(m_destDir,SIGNAL(textChanged(const QString &)),SLOT(setDestinationDir(const QString &))); +} + +void Step1::selectProjectIcon() +{ + QString path = QFileInfo(MainWindow::instance().configFileName()).path(); + QString iconName = QFileDialog::getOpenFileName(this, + tr("Select project icon/image"),path); + QPixmap pm(iconName); + if (!pm.isNull()) + { + m_projIconLab->setPixmap(pm.scaledToHeight(55,Qt::SmoothTransformation)); + updateStringOption(m_modelData,STR_PROJECT_LOGO,iconName); + } +} + +void Step1::selectSourceDir() +{ + QString path = QFileInfo(MainWindow::instance().configFileName()).path(); + QString dirName = QFileDialog::getExistingDirectory(this, + tr("Select source directory"),path); + QDir dir(path); + if (!MainWindow::instance().configFileName().isEmpty() && dir.exists()) + { + dirName = dir.relativeFilePath(dirName); + } + if (dirName.isEmpty()) + { + dirName=QString::fromAscii("."); + } + m_sourceDir->setText(dirName); +} + +void Step1::selectDestinationDir() +{ + QString path = QFileInfo(MainWindow::instance().configFileName()).path(); + QString dirName = QFileDialog::getExistingDirectory(this, + tr("Select destination directory"),path); + QDir dir(path); + if (!MainWindow::instance().configFileName().isEmpty() && dir.exists()) + { + dirName = dir.relativeFilePath(dirName); + } + if (dirName.isEmpty()) + { + dirName=QString::fromAscii("."); + } + m_destDir->setText(dirName); +} + +void Step1::setProjectName(const QString &name) +{ + updateStringOption(m_modelData,STR_PROJECT_NAME,name); +} + +void Step1::setProjectBrief(const QString &desc) +{ + updateStringOption(m_modelData,STR_PROJECT_BRIEF,desc); +} + +void Step1::setProjectNumber(const QString &num) +{ + updateStringOption(m_modelData,STR_PROJECT_NUMBER,num); +} + +void Step1::setSourceDir(const QString &dir) +{ + Input *option = m_modelData[STR_INPUT]; + if (option->value().toStringList().count()>0) + { + QStringList sl = option->value().toStringList(); + if (sl[0]!=dir) + { + sl[0] = dir; + option->value() = sl; + option->update(); + } + } + else + { + option->value() = QStringList() << dir; + option->update(); + } +} + +void Step1::setDestinationDir(const QString &dir) +{ + updateStringOption(m_modelData,STR_OUTPUT_DIRECTORY,dir); +} + +void Step1::setRecursiveScan(int s) +{ + updateBoolOption(m_modelData,STR_RECURSIVE,s==Qt::Checked); +} + +void Step1::init() +{ + Input *option; + m_projName->setText(getStringOption(m_modelData,STR_PROJECT_NAME)); + m_projBrief->setText(getStringOption(m_modelData,STR_PROJECT_BRIEF)); + m_projNumber->setText(getStringOption(m_modelData,STR_PROJECT_NUMBER)); + QString iconName = getStringOption(m_modelData,STR_PROJECT_LOGO); + if (!iconName.isEmpty()) + { + QPixmap pm(iconName); + if (!pm.isNull()) + { + m_projIconLab->setPixmap(pm.scaledToHeight(55,Qt::SmoothTransformation)); + } + } + else + { + QPixmap pm(QSize(120,55)); + pm.fill(); + m_projIconLab->setPixmap(pm); + } + option = m_modelData[STR_INPUT]; + if (option->value().toStringList().count()>0) + { + m_sourceDir->setText(option->value().toStringList().first()); + } + m_recursive->setChecked( + getBoolOption(m_modelData,STR_RECURSIVE) ? Qt::Checked : Qt::Unchecked); + m_destDir->setText(getStringOption(m_modelData,STR_OUTPUT_DIRECTORY)); +} + + +//========================================================================== + +Step2::Step2(Wizard *wizard,const QHash<QString,Input*> &modelData) + : m_wizard(wizard), m_modelData(modelData) +{ + QRadioButton *r; + QVBoxLayout *layout = new QVBoxLayout(this); + + //--------------------------------------------------- + m_extractModeGroup = new QButtonGroup(this); + m_extractMode = new QGroupBox(this); + m_extractMode->setTitle(tr("Select the desired extraction mode:")); + QGridLayout *gbox = new QGridLayout( m_extractMode ); + r = new QRadioButton(tr("Documented entities only")); + r->setChecked(true); + m_extractModeGroup->addButton(r, 0); + gbox->addWidget(r,1,0); + // 1 -> EXTRACT_ALL = NO + r = new QRadioButton(tr("All Entities")); + m_extractModeGroup->addButton(r, 1); + gbox->addWidget(r,2,0); + // 2 -> EXTRACT_ALL = YES + m_crossRef = new QCheckBox(m_extractMode); + m_crossRef->setText(tr("Include cross-referenced source code in the output")); + // m_crossRef -> SOURCE_BROWSER = YES/NO + gbox->addWidget(m_crossRef,3,0); + layout->addWidget(m_extractMode); + + //--------------------------------------------------- + QFrame *f = new QFrame( this ); + f->setFrameStyle( QFrame::HLine | QFrame::Sunken ); + layout->addWidget(f); + + m_optimizeLangGroup = new QButtonGroup(this); + m_optimizeLang = new QGroupBox(this); + m_optimizeLang->setTitle(tr("Select programming language to optimize the results for")); + gbox = new QGridLayout( m_optimizeLang ); + + r = new QRadioButton(m_optimizeLang); + r->setText(tr("Optimize for C++ output")); + r->setChecked(true); + m_optimizeLangGroup->addButton(r, 0); + // 0 -> OPTIMIZE_OUTPUT_FOR_C = NO + // OPTIMIZE_OUTPUT_JAVA = NO + // OPTIMIZE_FOR_FORTRAN = NO + // OPTIMIZE_OUTPUT_VHDL = NO + // CPP_CLI_SUPPORT = NO + // HIDE_SCOPE_NAMES = NO + gbox->addWidget(r,0,0); + r = new QRadioButton(tr("Optimize for C++/CLI output")); + gbox->addWidget(r,1,0); + m_optimizeLangGroup->addButton(r, 1); + // 1 -> OPTIMIZE_OUTPUT_FOR_C = NO + // OPTIMIZE_OUTPUT_JAVA = NO + // OPTIMIZE_FOR_FORTRAN = NO + // OPTIMIZE_OUTPUT_VHDL = NO + // CPP_CLI_SUPPORT = YES + // HIDE_SCOPE_NAMES = NO + r = new QRadioButton(tr("Optimize for Java or C# output")); + m_optimizeLangGroup->addButton(r, 2); + // 2 -> OPTIMIZE_OUTPUT_FOR_C = NO + // OPTIMIZE_OUTPUT_JAVA = YES + // OPTIMIZE_FOR_FORTRAN = NO + // OPTIMIZE_OUTPUT_VHDL = NO + // CPP_CLI_SUPPORT = NO + // HIDE_SCOPE_NAMES = NO + gbox->addWidget(r,2,0); + r = new QRadioButton(tr("Optimize for C or PHP output")); + m_optimizeLangGroup->addButton(r, 3); + // 3 -> OPTIMIZE_OUTPUT_FOR_C = YES + // OPTIMIZE_OUTPUT_JAVA = NO + // OPTIMIZE_FOR_FORTRAN = NO + // OPTIMIZE_OUTPUT_VHDL = NO + // CPP_CLI_SUPPORT = NO + // HIDE_SCOPE_NAMES = YES + gbox->addWidget(r,3,0); + r = new QRadioButton(tr("Optimize for Fortran output")); + m_optimizeLangGroup->addButton(r, 4); + // 4 -> OPTIMIZE_OUTPUT_FOR_C = NO + // OPTIMIZE_OUTPUT_JAVA = NO + // OPTIMIZE_FOR_FORTRAN = YES + // OPTIMIZE_OUTPUT_VHDL = NO + // CPP_CLI_SUPPORT = NO + // HIDE_SCOPE_NAMES = NO + gbox->addWidget(r,4,0); + r = new QRadioButton(tr("Optimize for VHDL output")); + m_optimizeLangGroup->addButton(r, 5); + // 5 -> OPTIMIZE_OUTPUT_FOR_C = NO + // OPTIMIZE_OUTPUT_JAVA = NO + // OPTIMIZE_FOR_FORTRAN = NO + // OPTIMIZE_OUTPUT_VHDL = YES + // CPP_CLI_SUPPORT = NO + // HIDE_SCOPE_NAMES = NO + gbox->addWidget(r,5,0); + + layout->addWidget(m_optimizeLang); + layout->addStretch(1); + + connect(m_crossRef,SIGNAL(stateChanged(int)), + SLOT(changeCrossRefState(int))); + connect(m_optimizeLangGroup,SIGNAL(buttonClicked(int)), + SLOT(optimizeFor(int))); + connect(m_extractModeGroup,SIGNAL(buttonClicked(int)), + SLOT(extractMode(int))); +} + + +void Step2::optimizeFor(int choice) +{ + for (int i=0;i<6;i++) + { + updateBoolOption(m_modelData, + g_optimizeOptionNames[i], + g_optimizeMapping[choice][i]); + } +} + +void Step2::extractMode(int choice) +{ + updateBoolOption(m_modelData,STR_EXTRACT_ALL,choice==1); +} + +void Step2::changeCrossRefState(int choice) +{ + updateBoolOption(m_modelData,STR_SOURCE_BROWSER,choice==Qt::Checked); +} + +void Step2::init() +{ + m_extractModeGroup->button( + getBoolOption(m_modelData,STR_EXTRACT_ALL) ? 1 : 0)->setChecked(true); + m_crossRef->setChecked(getBoolOption(m_modelData,STR_SOURCE_BROWSER)); + + int x=0; + if (getBoolOption(m_modelData,STR_CPP_CLI_SUPPORT)) x=1; + else if (getBoolOption(m_modelData,STR_OPTIMIZE_OUTPUT_JAVA)) x=2; + else if (getBoolOption(m_modelData,STR_OPTIMIZE_OUTPUT_FOR_C)) x=3; + else if (getBoolOption(m_modelData,STR_OPTIMIZE_FOR_FORTRAN)) x=4; + else if (getBoolOption(m_modelData,STR_OPTIMIZE_OUTPUT_VHDL)) x=5; + m_optimizeLangGroup->button(x)->setChecked(true); +} + +//========================================================================== + +Step3::Step3(Wizard *wizard,const QHash<QString,Input*> &modelData) + : m_wizard(wizard), m_modelData(modelData) +{ + QVBoxLayout *vbox = 0; + QRadioButton *r = 0; + + QGridLayout *gbox = new QGridLayout( this ); + gbox->addWidget(new QLabel(tr("Select the output format(s) to generate")),0,0); + { + m_htmlOptions = new QGroupBox(tr("HTML")); + m_htmlOptions->setCheckable(true); + // GENERATE_HTML + m_htmlOptionsGroup = new QButtonGroup(m_htmlOptions); + QRadioButton *r = new QRadioButton(tr("plain HTML")); + r->setChecked(true); + m_htmlOptionsGroup->addButton(r, 0); + vbox = new QVBoxLayout; + vbox->addWidget(r); + r = new QRadioButton(tr("with navigation panel")); + m_htmlOptionsGroup->addButton(r, 1); + // GENERATE_TREEVIEW + vbox->addWidget(r); + r = new QRadioButton(tr("prepare for compressed HTML (.chm)")); + m_htmlOptionsGroup->addButton(r, 2); + // GENERATE_HTMLHELP + vbox->addWidget(r); + m_searchEnabled=new QCheckBox(tr("With search function")); + vbox->addWidget(m_searchEnabled); + // SEARCH_ENGINE + QHBoxLayout *hbox = new QHBoxLayout; + m_tuneColor=new QPushButton(tr("Change color...")); + hbox->addWidget(m_tuneColor); + hbox->addStretch(1); + vbox->addLayout(hbox); + m_htmlOptions->setLayout(vbox); + m_htmlOptions->setChecked(true); + } + gbox->addWidget(m_htmlOptions,1,0); + + { + m_texOptions = new QGroupBox(tr("LaTeX")); + m_texOptions->setCheckable(true); + // GENERATE_LATEX + m_texOptionsGroup = new QButtonGroup(m_texOptions); + vbox = new QVBoxLayout; + r = new QRadioButton(tr("as intermediate format for hyperlinked PDF")); + m_texOptionsGroup->addButton(r, 0); + // PDF_HYPERLINKS = YES + r->setChecked(true); + vbox->addWidget(r); + r = new QRadioButton(tr("as intermediate format for PDF")); + m_texOptionsGroup->addButton(r, 1); + // PDF_HYPERLINKS = NO, USE_PDFLATEX = YES + vbox->addWidget(r); + r = new QRadioButton(tr("as intermediate format for PostScript")); + m_texOptionsGroup->addButton(r, 2); + // USE_PDFLATEX = NO + vbox->addWidget(r); + vbox->addStretch(1); + m_texOptions->setLayout(vbox); + m_texOptions->setChecked(true); + } + gbox->addWidget(m_texOptions,2,0); + + m_manEnabled=new QCheckBox(tr("Man pages")); + // GENERATE_MAN + m_rtfEnabled=new QCheckBox(tr("Rich Text Format (RTF)")); + // GENERATE_RTF + m_xmlEnabled=new QCheckBox(tr("XML")); + // GENERATE_XML + gbox->addWidget(m_manEnabled,3,0); + gbox->addWidget(m_rtfEnabled,4,0); + gbox->addWidget(m_xmlEnabled,5,0); + + gbox->setRowStretch(6,1); + connect(m_htmlOptions,SIGNAL(toggled(bool)),SLOT(setHtmlEnabled(bool))); + connect(m_texOptions,SIGNAL(toggled(bool)),SLOT(setLatexEnabled(bool))); + connect(m_manEnabled,SIGNAL(stateChanged(int)),SLOT(setManEnabled(int))); + connect(m_rtfEnabled,SIGNAL(stateChanged(int)),SLOT(setRtfEnabled(int))); + connect(m_xmlEnabled,SIGNAL(stateChanged(int)),SLOT(setXmlEnabled(int))); + connect(m_searchEnabled,SIGNAL(stateChanged(int)),SLOT(setSearchEnabled(int))); + connect(m_htmlOptionsGroup,SIGNAL(buttonClicked(int)), + SLOT(setHtmlOptions(int))); + connect(m_texOptionsGroup,SIGNAL(buttonClicked(int)), + SLOT(setLatexOptions(int))); + connect(m_tuneColor,SIGNAL(clicked()),SLOT(tuneColorDialog())); +} + +void Step3::tuneColorDialog() +{ + int hue = getIntOption(m_modelData,STR_HTML_COLORSTYLE_HUE); + int sat = getIntOption(m_modelData,STR_HTML_COLORSTYLE_SAT); + int gam = getIntOption(m_modelData,STR_HTML_COLORSTYLE_GAMMA); + TuneColorDialog tuneColor(hue,sat,gam,this); + if (tuneColor.exec()==QDialog::Accepted) + { + updateIntOption(m_modelData,STR_HTML_COLORSTYLE_HUE,tuneColor.getHue()); + updateIntOption(m_modelData,STR_HTML_COLORSTYLE_SAT,tuneColor.getSaturation()); + updateIntOption(m_modelData,STR_HTML_COLORSTYLE_GAMMA,tuneColor.getGamma()); + } +} + +void Step3::setHtmlEnabled(bool b) +{ + updateBoolOption(m_modelData,STR_GENERATE_HTML,b); +} + +void Step3::setLatexEnabled(bool b) +{ + updateBoolOption(m_modelData,STR_GENERATE_LATEX,b); +} + +void Step3::setManEnabled(int state) +{ + updateBoolOption(m_modelData,STR_GENERATE_MAN,state==Qt::Checked); +} + +void Step3::setRtfEnabled(int state) +{ + updateBoolOption(m_modelData,STR_GENERATE_RTF,state==Qt::Checked); +} + +void Step3::setXmlEnabled(int state) +{ + updateBoolOption(m_modelData,STR_GENERATE_XML,state==Qt::Checked); +} + +void Step3::setSearchEnabled(int state) +{ + updateBoolOption(m_modelData,STR_SEARCHENGINE,state==Qt::Checked); +} + +void Step3::setHtmlOptions(int id) +{ + if (id==0) // plain HTML + { + updateBoolOption(m_modelData,STR_GENERATE_HTMLHELP,false); + updateBoolOption(m_modelData,STR_GENERATE_TREEVIEW,false); + } + else if (id==1) // with navigation tree + { + updateBoolOption(m_modelData,STR_GENERATE_HTMLHELP,false); + updateBoolOption(m_modelData,STR_GENERATE_TREEVIEW,true); + } + else if (id==2) // with compiled help + { + updateBoolOption(m_modelData,STR_GENERATE_HTMLHELP,true); + updateBoolOption(m_modelData,STR_GENERATE_TREEVIEW,false); + } +} + +void Step3::setLatexOptions(int id) +{ + if (id==0) // hyperlinked PDF + { + updateBoolOption(m_modelData,STR_USE_PDFLATEX,true); + updateBoolOption(m_modelData,STR_PDF_HYPERLINKS,true); + } + else if (id==1) // PDF + { + updateBoolOption(m_modelData,STR_USE_PDFLATEX,true); + updateBoolOption(m_modelData,STR_PDF_HYPERLINKS,false); + } + else if (id==2) // PostScript + { + updateBoolOption(m_modelData,STR_USE_PDFLATEX,false); + updateBoolOption(m_modelData,STR_PDF_HYPERLINKS,false); + } +} + +void Step3::init() +{ + m_htmlOptions->setChecked(getBoolOption(m_modelData,STR_GENERATE_HTML)); + m_texOptions->setChecked(getBoolOption(m_modelData,STR_GENERATE_LATEX)); + m_manEnabled->setChecked(getBoolOption(m_modelData,STR_GENERATE_MAN)); + m_rtfEnabled->setChecked(getBoolOption(m_modelData,STR_GENERATE_RTF)); + m_xmlEnabled->setChecked(getBoolOption(m_modelData,STR_GENERATE_XML)); + m_searchEnabled->setChecked(getBoolOption(m_modelData,STR_SEARCHENGINE)); + if (getBoolOption(m_modelData,STR_GENERATE_HTMLHELP)) + { + m_htmlOptionsGroup->button(2)->setChecked(true); // compiled help + } + else if (getBoolOption(m_modelData,STR_GENERATE_TREEVIEW)) + { + m_htmlOptionsGroup->button(1)->setChecked(true); // navigation tree + } + else + { + m_htmlOptionsGroup->button(0)->setChecked(true); // plain HTML + } + if (!getBoolOption(m_modelData,STR_USE_PDFLATEX)) + { + m_texOptionsGroup->button(2)->setChecked(true); // PostScript + } + else if (!getBoolOption(m_modelData,STR_PDF_HYPERLINKS)) + { + m_texOptionsGroup->button(1)->setChecked(true); // Plain PDF + } + else + { + m_texOptionsGroup->button(0)->setChecked(true); // PDF with hyperlinks + } +} + +//========================================================================== + +Step4::Step4(Wizard *wizard,const QHash<QString,Input*> &modelData) + : m_wizard(wizard), m_modelData(modelData) +{ + m_diagramModeGroup = new QButtonGroup(this); + QGridLayout *gbox = new QGridLayout( this ); + gbox->addWidget(new QLabel(tr("Diagrams to generate")),0,0); + + QRadioButton *rb = new QRadioButton(tr("No diagrams")); + m_diagramModeGroup->addButton(rb, 0); + gbox->addWidget(rb,1,0); + // CLASS_DIAGRAMS = NO, HAVE_DOT = NO + rb->setChecked(true); + rb = new QRadioButton(tr("Use built-in class diagram generator")); + m_diagramModeGroup->addButton(rb, 1); + // CLASS_DIAGRAMS = YES, HAVE_DOT = NO + gbox->addWidget(rb,2,0); + rb = new QRadioButton(tr("Use dot tool from the GraphViz package")); + m_diagramModeGroup->addButton(rb, 2); + gbox->addWidget(rb,3,0); + // CLASS_DIAGRAMS = NO, HAVE_DOT = YES + + m_dotGroup = new QGroupBox(tr("Dot graphs to generate")); + QVBoxLayout *vbox = new QVBoxLayout; + m_dotClass=new QCheckBox(tr("Class diagrams")); + // CLASS_GRAPH + m_dotCollaboration=new QCheckBox(tr("Collaboration diagrams")); + // COLLABORATION_GRAPH + m_dotInheritance=new QCheckBox(tr("Overall Class hierarchy")); + // GRAPHICAL_HIERARCHY + m_dotInclude=new QCheckBox(tr("Include dependency graphs")); + // INCLUDE_GRAPH + m_dotIncludedBy=new QCheckBox(tr("Included by dependency graphs")); + // INCLUDED_BY_GRAPH + m_dotCall=new QCheckBox(tr("Call graphs")); + // CALL_GRAPH + m_dotCaller=new QCheckBox(tr("Called by graphs")); + // CALLER_GRAPH + vbox->addWidget(m_dotClass); + vbox->addWidget(m_dotCollaboration); + vbox->addWidget(m_dotInheritance); + vbox->addWidget(m_dotInclude); + vbox->addWidget(m_dotIncludedBy); + vbox->addWidget(m_dotCall); + vbox->addWidget(m_dotCaller); + vbox->addStretch(1); + m_dotGroup->setLayout(vbox); + m_dotClass->setChecked(true); + m_dotGroup->setEnabled(false); + gbox->addWidget(m_dotGroup,4,0); + + m_dotInclude->setChecked(true); + m_dotCollaboration->setChecked(true); + gbox->setRowStretch(5,1); + + connect(m_diagramModeGroup,SIGNAL(buttonClicked(int)), + this,SLOT(diagramModeChanged(int))); + connect(m_dotClass,SIGNAL(stateChanged(int)), + this,SLOT(setClassGraphEnabled(int))); + connect(m_dotCollaboration,SIGNAL(stateChanged(int)), + this,SLOT(setCollaborationGraphEnabled(int))); + connect(m_dotInheritance,SIGNAL(stateChanged(int)), + this,SLOT(setGraphicalHierarchyEnabled(int))); + connect(m_dotInclude,SIGNAL(stateChanged(int)), + this,SLOT(setIncludeGraphEnabled(int))); + connect(m_dotIncludedBy,SIGNAL(stateChanged(int)), + this,SLOT(setIncludedByGraphEnabled(int))); + connect(m_dotCall,SIGNAL(stateChanged(int)), + this,SLOT(setCallGraphEnabled(int))); + connect(m_dotCaller,SIGNAL(stateChanged(int)), + this,SLOT(setCallerGraphEnabled(int))); +} + +void Step4::diagramModeChanged(int id) +{ + if (id==0) // no diagrams + { + updateBoolOption(m_modelData,STR_HAVE_DOT,false); + updateBoolOption(m_modelData,STR_CLASS_DIAGRAMS,false); + } + else if (id==1) // builtin diagrams + { + updateBoolOption(m_modelData,STR_HAVE_DOT,false); + updateBoolOption(m_modelData,STR_CLASS_DIAGRAMS,true); + } + else if (id==2) // dot diagrams + { + updateBoolOption(m_modelData,STR_HAVE_DOT,true); + updateBoolOption(m_modelData,STR_CLASS_DIAGRAMS,false); + } + m_dotGroup->setEnabled(id==2); +} + +void Step4::setClassGraphEnabled(int state) +{ + updateBoolOption(m_modelData,STR_CLASS_GRAPH,state==Qt::Checked); +} + +void Step4::setCollaborationGraphEnabled(int state) +{ + updateBoolOption(m_modelData,STR_COLLABORATION_GRAPH,state==Qt::Checked); +} + +void Step4::setGraphicalHierarchyEnabled(int state) +{ + updateBoolOption(m_modelData,STR_GRAPHICAL_HIERARCHY,state==Qt::Checked); +} + +void Step4::setIncludeGraphEnabled(int state) +{ + updateBoolOption(m_modelData,STR_INCLUDE_GRAPH,state==Qt::Checked); +} + +void Step4::setIncludedByGraphEnabled(int state) +{ + updateBoolOption(m_modelData,STR_INCLUDED_BY_GRAPH,state==Qt::Checked); +} + +void Step4::setCallGraphEnabled(int state) +{ + updateBoolOption(m_modelData,STR_CALL_GRAPH,state==Qt::Checked); +} + +void Step4::setCallerGraphEnabled(int state) +{ + updateBoolOption(m_modelData,STR_CALLER_GRAPH,state==Qt::Checked); +} + +void Step4::init() +{ + if (getBoolOption(m_modelData,STR_HAVE_DOT)) + { + m_diagramModeGroup->button(2)->setChecked(true); // Dot + } + else if (getBoolOption(m_modelData,STR_CLASS_DIAGRAMS)) + { + m_diagramModeGroup->button(1)->setChecked(true); // Builtin diagrams + } + else + { + m_diagramModeGroup->button(0)->setChecked(true); // no diagrams + } + m_dotClass->setChecked(getBoolOption(m_modelData,STR_CLASS_GRAPH)); + m_dotCollaboration->setChecked(getBoolOption(m_modelData,STR_COLLABORATION_GRAPH)); + m_dotInheritance->setChecked(getBoolOption(m_modelData,STR_GRAPHICAL_HIERARCHY)); + m_dotInclude->setChecked(getBoolOption(m_modelData,STR_INCLUDE_GRAPH)); + m_dotIncludedBy->setChecked(getBoolOption(m_modelData,STR_INCLUDED_BY_GRAPH)); + m_dotCall->setChecked(getBoolOption(m_modelData,STR_CALL_GRAPH)); + m_dotCaller->setChecked(getBoolOption(m_modelData,STR_CALLER_GRAPH)); +} + +//========================================================================== + +Wizard::Wizard(const QHash<QString,Input*> &modelData, QWidget *parent) : + QSplitter(parent), m_modelData(modelData) +{ + m_treeWidget = new QTreeWidget; + m_treeWidget->setColumnCount(1); + m_treeWidget->setHeaderLabels(QStringList() << QString::fromAscii("Topics")); + QList<QTreeWidgetItem*> items; + items.append(new QTreeWidgetItem((QTreeWidget*)0,QStringList(tr("Project")))); + items.append(new QTreeWidgetItem((QTreeWidget*)0,QStringList(tr("Mode")))); + items.append(new QTreeWidgetItem((QTreeWidget*)0,QStringList(tr("Output")))); + items.append(new QTreeWidgetItem((QTreeWidget*)0,QStringList(tr("Diagrams")))); + m_treeWidget->insertTopLevelItems(0,items); + + m_topicStack = new QStackedWidget; + m_step1 = new Step1(this,modelData); + m_step2 = new Step2(this,modelData); + m_step3 = new Step3(this,modelData); + m_step4 = new Step4(this,modelData); + m_topicStack->addWidget(m_step1); + m_topicStack->addWidget(m_step2); + m_topicStack->addWidget(m_step3); + m_topicStack->addWidget(m_step4); + + QWidget *rightSide = new QWidget; + QGridLayout *grid = new QGridLayout(rightSide); + m_prev = new QPushButton(tr("Previous")); + m_prev->setEnabled(false); + m_next = new QPushButton(tr("Next")); + grid->addWidget(m_topicStack,0,0,1,2); + grid->addWidget(m_prev,1,0,Qt::AlignLeft); + grid->addWidget(m_next,1,1,Qt::AlignRight); + grid->setColumnStretch(0,1); + grid->setRowStretch(0,1); + addWidget(m_treeWidget); + addWidget(rightSide); + + connect(m_treeWidget, + SIGNAL(currentItemChanged(QTreeWidgetItem *,QTreeWidgetItem *)), + SLOT(activateTopic(QTreeWidgetItem *,QTreeWidgetItem *))); + connect(m_next,SIGNAL(clicked()),SLOT(nextTopic())); + connect(m_prev,SIGNAL(clicked()),SLOT(prevTopic())); + + refresh(); +} + +Wizard::~Wizard() +{ +} + +void Wizard::activateTopic(QTreeWidgetItem *item,QTreeWidgetItem *) +{ + if (item) + { + + QString label = item->text(0); + if (label==tr("Project")) + { + m_topicStack->setCurrentWidget(m_step1); + m_prev->setEnabled(false); + m_next->setEnabled(true); + } + else if (label==tr("Mode")) + { + m_topicStack->setCurrentWidget(m_step2); + m_prev->setEnabled(true); + m_next->setEnabled(true); + } + else if (label==tr("Output")) + { + m_topicStack->setCurrentWidget(m_step3); + m_prev->setEnabled(true); + m_next->setEnabled(true); + } + else if (label==tr("Diagrams")) + { + m_topicStack->setCurrentWidget(m_step4); + m_prev->setEnabled(true); + m_next->setEnabled(false); + } + } +} + +void Wizard::nextTopic() +{ + m_topicStack->setCurrentIndex(m_topicStack->currentIndex()+1); + m_next->setEnabled(m_topicStack->count()!=m_topicStack->currentIndex()+1); + m_prev->setEnabled(m_topicStack->currentIndex()!=0); + m_treeWidget->setCurrentItem(m_treeWidget->invisibleRootItem()->child(m_topicStack->currentIndex())); +} + +void Wizard::prevTopic() +{ + m_topicStack->setCurrentIndex(m_topicStack->currentIndex()-1); + m_next->setEnabled(m_topicStack->count()!=m_topicStack->currentIndex()+1); + m_prev->setEnabled(m_topicStack->currentIndex()!=0); + m_treeWidget->setCurrentItem(m_treeWidget->invisibleRootItem()->child(m_topicStack->currentIndex())); +} + +void Wizard::refresh() +{ + m_step1->init(); + m_step2->init(); + m_step3->init(); + m_step4->init(); +} diff --git a/trunk/addon/doxywizard/wizard.h b/trunk/addon/doxywizard/wizard.h new file mode 100644 index 0000000..99e1db5 --- /dev/null +++ b/trunk/addon/doxywizard/wizard.h @@ -0,0 +1,253 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#ifndef WIZARD_H +#define WIZARD_H + +#include <QSplitter> +#include <QHash> +#include <QDialog> + +class Input; +class QTreeWidget; +class QTreeWidgetItem; +class QStackedWidget; +class QCheckBox; +class QLineEdit; +class QPushButton; +class QRadioButton; +class QGroupBox; +class QButtonGroup; +class Wizard; +class QImage; +class QLabel; + +enum OptLang { Lang_Cpp, Lang_C, Lang_Java, Lang_CS }; +enum HtmlStyle { HS_Plain, HS_TreeView, HS_CHM }; +enum TexStyle { TS_PDFHyper, TS_PDF, TS_PS }; +enum DiagramMode { DM_None, DM_Builtin, DM_Dot }; + +class TuneColorDialog : public QDialog +{ + Q_OBJECT + + public: + TuneColorDialog(int hue,int sat,int gamma,QWidget *parent=0); + int getHue() const; + int getSaturation() const; + int getGamma() const; + + private slots: + void updateImage(int hue,int sat,int val); + + private: + QImage *m_image; + QLabel *m_imageLab; + int m_hue; + int m_sat; + int m_gam; +}; + +class ColorPicker : public QWidget +{ + Q_OBJECT +public: + enum Mode { Hue, Saturation, Gamma }; + ColorPicker(Mode m); + ~ColorPicker(); + +public slots: + void setCol(int h, int s, int g); + //void setCol(int h, int s); + +signals: + void newHsv(int h, int s, int g); + +protected: + void paintEvent(QPaintEvent*); + void mouseMoveEvent(QMouseEvent *); + void mousePressEvent(QMouseEvent *); + +private: + enum { foff = 3, coff = 4 }; //frame and contents offset + int y2hue(int y); + int y2sat(int y); + int y2gam(int y); + int hue2y(int hue); + int sat2y(int sat); + int gam2y(int gamma); + void setHue(int v); + void setSat(int v); + void setGam(int v); + + QPixmap *m_pix; + Mode m_mode; + int m_gam; + int m_hue; + int m_sat; + +}; + + +class Step1 : public QWidget +{ + Q_OBJECT + + public: + Step1(Wizard *parent,const QHash<QString,Input*> &modelData); + void init(); + + private slots: + void selectSourceDir(); + void selectDestinationDir(); + void selectProjectIcon(); + void setProjectName(const QString &name); + void setProjectBrief(const QString &desc); + void setProjectNumber(const QString &num); + void setSourceDir(const QString &dir); + void setDestinationDir(const QString &dir); + void setRecursiveScan(int); + + private: + QLineEdit *m_projName; + QLineEdit *m_projBrief; + QLineEdit *m_projNumber; + QLineEdit *m_sourceDir; + QLineEdit *m_destDir; + QLabel *m_projIconLab; + QCheckBox *m_recursive; + QPushButton *m_srcSelectDir; + QPushButton *m_dstSelectDir; + Wizard *m_wizard; + const QHash<QString,Input *> &m_modelData; +}; + +class Step2 : public QWidget +{ + Q_OBJECT + public: + Step2(Wizard *parent,const QHash<QString,Input*> &modelData); + void init(); + + private slots: + void optimizeFor(int choice); + void extractMode(int choice); + void changeCrossRefState(int choice); + + private: + QGroupBox *m_extractMode; + QGroupBox *m_optimizeLang; + QButtonGroup *m_extractModeGroup; + QButtonGroup *m_optimizeLangGroup; + QCheckBox *m_crossRef; + Wizard *m_wizard; + const QHash<QString,Input *> &m_modelData; +}; + +class Step3 : public QWidget +{ + Q_OBJECT + + public: + Step3(Wizard *parent,const QHash<QString,Input*> &modelData); + void init(); + + private slots: + void setHtmlEnabled(bool); + void setLatexEnabled(bool); + void setManEnabled(int); + void setRtfEnabled(int); + void setXmlEnabled(int); + void setSearchEnabled(int); + void setHtmlOptions(int); + void setLatexOptions(int); + void tuneColorDialog(); + + private: + QGroupBox *m_texOptions; + QButtonGroup *m_texOptionsGroup; + QGroupBox *m_htmlOptions; + QButtonGroup *m_htmlOptionsGroup; + QCheckBox *m_htmlEnabled; + QCheckBox *m_latexEnabled; + QCheckBox *m_manEnabled; + QCheckBox *m_rtfEnabled; + QCheckBox *m_xmlEnabled; + QCheckBox *m_searchEnabled; + QPushButton *m_tuneColor; + Wizard *m_wizard; + const QHash<QString,Input *> &m_modelData; +}; + +class Step4 : public QWidget +{ + Q_OBJECT + + public: + Step4(Wizard *parent,const QHash<QString,Input*> &modelData); + void init(); + + private slots: + void diagramModeChanged(int); + void setClassGraphEnabled(int state); + void setCollaborationGraphEnabled(int state); + void setGraphicalHierarchyEnabled(int state); + void setIncludeGraphEnabled(int state); + void setIncludedByGraphEnabled(int state); + void setCallGraphEnabled(int state); + void setCallerGraphEnabled(int state); + + private: + QGroupBox *m_diagramMode; + QButtonGroup *m_diagramModeGroup; + QGroupBox *m_dotGroup; + QCheckBox *m_dotClass; + QCheckBox *m_dotCollaboration; + QCheckBox *m_dotInclude; + QCheckBox *m_dotIncludedBy; + QCheckBox *m_dotInheritance; + QCheckBox *m_dotCall; + QCheckBox *m_dotCaller; + Wizard *m_wizard; + const QHash<QString,Input *> &m_modelData; +}; + +class Wizard : public QSplitter +{ + Q_OBJECT + public: + Wizard(const QHash<QString,Input*> &modelData, QWidget *parent=0); + ~Wizard(); + + public slots: + void refresh(); + + private slots: + void activateTopic(QTreeWidgetItem *item,QTreeWidgetItem *); + void nextTopic(); + void prevTopic(); + + private: + const QHash<QString,Input *> &m_modelData; + QTreeWidget *m_treeWidget; + QStackedWidget *m_topicStack; + Step1 *m_step1; + Step2 *m_step2; + Step3 *m_step3; + Step4 *m_step4; + QPushButton *m_next; + QPushButton *m_prev; +}; + +#endif diff --git a/trunk/configure b/trunk/configure new file mode 100755 index 0000000..204c7fe --- /dev/null +++ b/trunk/configure @@ -0,0 +1,674 @@ +#!/bin/sh +# +# $Id$ +# +# Copyright (C) 1997-2012 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. +# +# shell script to configure doxygen + +doxygen_version_major=1 +doxygen_version_minor=8 +doxygen_version_revision=0 + +#NOTE: Setting version_mmn to "NO" will omit mmn info from the package. +doxygen_version_mmn=NO + +bin_dirs=`echo $PATH | sed -e "s/:/ /g"` + +f_debug=NO +f_shared=YES +f_make=NO +f_dot=NO +f_perl=NO +f_plf_auto=NO +f_prefix=/usr/local +f_insttool=NO +f_english=NO +f_wizard=NO +f_app=NO +f_thread=NO +f_flex=NO +f_bison=NO +f_langs=nl,sv,cz,fr,id,it,de,jp,je,es,fi,ru,hr,pl,pt,hu,kr,ke,ro,si,cn,no,mk,br,dk,sk,ua,gr,tw,sr,ca,lt,za,ar,fa,sc,vi,tr,eo,am + +while test -n "$1"; do + case $1 in + --prefix | -prefix) + shift; f_prefix=$1 + ;; + --docdir | -docdir) + shift; f_docdir=$1 + ;; + --shared | -shared) + f_shared=YES + ;; + --static | -static) + f_shared=NO + ;; + --release | -release) + f_debug=NO + ;; + --debug | -debug) + f_debug=YES + ;; + --english-only | -english-only) + f_english=YES + ;; + --enable-langs | -enable-langs) + shift; f_langs=$1 + ;; + --platform | -platform) + shift; f_platform=$1 + ;; + --make | -make) + shift; f_make=$1 + ;; + --dot | -dot) + shift; f_dot=$1 + ;; + --perl | -perl) + shift; f_perl=$1 + ;; + --flex | -flex) + shift; f_flex=$1 + ;; + --bison | -bison) + shift; f_bison=$1 + ;; + --install | -install) + shift; f_insttool=$1 + ;; + --with-doxywizard | -with-doxywizard) + f_wizard=YES + ;; + --with-doxyapp | -with-doxyapp) + f_app=YES + ;; + -h | -help | --help) + f_help=y + ;; + *) + echo $1: unknown argument + f_help=y + f_error=y + ;; + esac + shift +done + +if test "$f_help" = y; then + cat <<EOF +Usage: $0 [--help] [--shared] [--static] [--release] [--debug] + [--perl name] [--flex name] [--bison name] [--make name] + [--dot name] [--platform target] [--prefix dir] [--docdir dir] + [--install name] [--english-only] [----enable-langs list] + [--with-doxywizard] [--with-doxyapp] + +Options: + + --help Print this help + --shared | --static Build using shared or static linking + [default: shared] + --release | --debug Build for release or debug + [default: release] + --perl name Use \`name' as the name of the perl interpreter + [default: autodetect] + --flex name Use \`name' as the name of the GNU lexical scanner + [default: autodetect] + --bison name Use \`name' as the name of the GNU compiler generator + [default: autodetect] + --make name Use \`name' as the name of the GNU make tool + [default: autodetect] + --dot name Use \`name' as the name of the dot tool that + is part of the Graphviz package. + [default: autodetect] + --platform target Do not detect platform but use \`target' instead. + See PLATFORMS for a list of possibilities + --prefix dir Installation prefix directory (doxygen will be + put in PREFIX/bin/doxygen) + [default: $f_prefix] + --docdir dir Documentation is installed in DOCDIR/ + [default: PREFIX/share/doc/packages/doxygen] + --install name Use \`name' as the name of the GNU install tool + [default: autodetect] + --english-only Include support for English only. + --enable-langs list Include support for output languages listed in list. + [default: $f_langs] + --with-doxywizard Build the GUI frontend for doxygen. This + requires Qt 3.3.x + --with-doxyapp Example showing how to embed doxygen in an application. + +EOF + test "$f_error" = y && exit 1 + exit 0; +fi + +u_release=`(uname -r) 2>/dev/null` || u_release=unknown +u_system=`(uname -s) 2>/dev/null` || u_system=unknown + +if test -z "$f_platform"; then + f_platforms="`cat PLATFORMS`" + + case "$u_system:$u_release" in + AIX*) + f_platform=aix-xlc + ;; + BeOS*) + f_platform=beos-g++ + ;; + dgux:*) + f_platform=dgux-g++ + ;; + Darwin:*) + f_platform=macosx-c++ + if test "$f_insttool" = NO; then + f_insttool=/usr/bin/install + fi + ;; + FreeBSD:*) + f_platform=freebsd-g++ + if test "$f_insttool" = NO; then + f_insttool=/usr/bin/install + fi + ;; + HP-UX:*) + f_platform=hpux-g++ + if test "$f_insttool" = NO; then + f_insttool=/usr/bin/install + fi + ;; + IRIX64:*) + f_platform=irix-64 + ;; + IRIX:*) + f_platform=irix-n32 + ;; + Linux:*|GNU:*|GNU/*:*) + f_platform=linux-g++ + ;; + NetBSD:*) + f_platform=netbsd-g++ + ;; + OpenBSD:*) + f_platform=openbsd-g++ + ;; + OSF1:*) + f_platform=osf1-g++ + ;; + QNX:*) + f_platform=qnx-g++ + ;; + *:3.2) + f_platform=sco-g++ + ;; + SunOS:4*) + f_platform=sunos-g++ + ;; + SunOS:5*) + f_platform=solaris-g++ + if test "$f_insttool" = NO; then + f_insttool=/usr/bin/install + fi + ;; + ULTRIX:*) + f_platform=ultrix-g++ + ;; + UNIX_SV:4.2*) + f_platform=unixware-g++ + ;; + Cygwin:*|CYGWIN*) + f_platform=win32-g++ + ;; + *MiNT:*) + f_platform=m68k-atari-mint-g++ + ;; + *) + echo + echo "Your platform was not recognised by this configure script" + echo "Please use the -platform option to specify one of platforms" + echo "in this list:" + echo + for p in $f_platforms + do + echo " $0 $* -platform $p" + done + echo + exit 2 + esac + echo " Autodetected platform $f_platform... " + f_plf_auto=YES +fi + +if test -z "$f_docdir"; then + f_docdir='$(INSTALL)/share/doc/packages/doxygen' +fi + +if test "$f_plf_auto" = NO; then + echo -n " Checking for platform $f_platform... " + if test '!' -d tmake/lib/$f_platform; then + echo "not supported!" + echo + exit 2 + fi + echo "supported" +fi + +#- check for qt -------------------------------------------------------------- + +if test "$f_wizard" = YES; then + if test -z "$QTDIR"; then + echo " QTDIR environment variable not set!" + echo -n " Checking for Qt..." + for d in /usr/{lib,share,qt}/{qt-4,qt4,qt,qt*,4} /usr; do + if test -x "$d/bin/qmake"; then + QTDIR=$d + fi + done + else + echo " Detected Qt via the QTDIR environment variable..." + echo -n " " + fi + if test -z "$QTDIR"; then + echo "QTDIR not set and Qt not found at standard locations!" + echo + echo "Set the QTDIR environment variable such that \$QTDIR/bin/qmake exists." + echo "check the Qt installation instructions!" + exit 2 + fi +fi + +# - check for make ------------------------------------------------------------ + +echo -n " Checking for GNU make tool... " +if test "$f_make" = NO; then + make_names="gmake make" + make_dirs="$bin_dirs /usr/bin /usr/local/bin /bin /sbin" + make_prog=NO + for i in $make_names; do + for j in $make_dirs; do + if test -x "$j/$i"; then + if test -n "`$j/$i --version 2>/dev/null | grep GNU`"; then + make_prog="$j/$i" + break 2 + fi + fi + done + done + f_make="$make_prog" +fi + +if test "$f_make" = NO; then + echo "not found!"; + echo + exit 2 +fi +echo "using $f_make" + +# - check for install ------------------------------------------------------------ + +echo -n " Checking for GNU install tool... " +if test "$f_insttool" = NO; then + install_names="ginstall install" + install_dirs="$bin_dirs /usr/bin /usr/local/bin /bin /sbin /usr/ucb" + install_prog=NO + install_found=NO + for i in $install_names; do + for j in $install_dirs; do + if test -x "$j/$i"; then + if test -n "`$j/$i --version 2>/dev/null | grep utils`"; then + install_found=YES + install_prog="$j/$i" + break 2 + fi + fi + done + done + f_insttool="$install_prog" +fi + +if test "$f_insttool" = NO; then + if test "$install_found" = YES; then + echo; + else + echo "not found!"; + echo + fi + echo "GNU version of install is required: this is part of the fileutils/coreutils package: " + echo "see http://www.gnu.org/software/fileutils/fileutils.html" + echo + exit 2 +fi +echo "using $f_insttool"; + + +# - check for dot ------------------------------------------------------------ + +echo -n " Checking for dot (part of GraphViz)... " +if test "$f_dot" = NO; then + dot_dirs="$bin_dirs /usr/bin /usr/local/bin /bin /sbin" + dot_prog=NO + for j in $dot_dirs; do + if test -x "$j/dot"; then + dot_prog="$j/dot" + break 2 + fi + done + f_dot="$dot_prog" +fi + +if test "$f_dot" = NO; then + echo "not found!"; +else + echo "using $f_dot" +fi + +# - check for perl ------------------------------------------------------------ + +echo -n " Checking for perl... " +if test "$f_perl" = NO; then + perl_names="perl perl5" + perl_dirs="$bin_dirs /usr/bin /usr/local/bin /bin /sbin" + perl_prog=NO + perl_found=NO + for i in $perl_names; do + for j in $perl_dirs; do + if test -x "$j/$i"; then + perl_found=YES + if $j/$i -e 'require 5.000;' 2>/dev/null ; then + perl_prog="$j/$i" + break 2 + fi + fi + done + done + f_perl="$perl_prog" +fi + +if test "$f_perl" = NO; then + if test "$perl_found" = YES; then + echo "version is too old (5.000 or higher is required)." + else + echo "not found!"; + fi + echo + exit 2 +fi +echo "using $f_perl"; + +# - check for flex ------------------------------------------------------------ + +echo -n " Checking for flex... " +if test "$f_flex" = NO; then + flex_dirs="$bin_dirs /usr/bin /usr/local/bin /bin" + flex_prog=NO + flex_found=NO + for j in $flex_dirs; do + if test -x "$j/flex"; then + flex_found=YES + flex_prog="$j/flex" + break + fi + done + f_flex="$flex_prog" +fi + +if test "$f_flex" = NO; then + echo "not found!"; + exit 2 +else + echo "using $f_flex" +fi + +# - check for bison ------------------------------------------------------------ + +echo -n " Checking for bison... " +if test "$f_bison" = NO; then + bison_dirs="$bin_dirs /usr/bin /usr/local/bin /bin" + bison_prog=NO + bison_found=NO + for j in $bison_dirs; do + if test -x "$j/bison"; then + bison_found=YES + bison_prog="$j/bison" + break + fi + done + f_bison="$bison_prog" +fi + +if test "$f_bison" = NO; then + echo "not found!"; + exit 2 +else + echo "using $f_bison" +fi + +# ----------------------------------------------------------------------------- + +# +# Make VERSION file +# +echo " Creating VERSION file." +# Output should be something like 1.4.5-20051010 +if test "x$doxygen_version_mmn" = "xNO"; then + echo "$doxygen_version_major.$doxygen_version_minor.$doxygen_version_revision" > VERSION +else + echo "$doxygen_version_major.$doxygen_version_minor.$doxygen_version_revision-$doxygen_version_mmn" > VERSION +fi + +test -f .makeconfig && rm .makeconfig +test -f .tmakeconfig && rm .tmakeconfig + +configPWD=`pwd` + +cat > .makeconfig <<EOF +DOXYGEN = $configPWD +TMAKEPATH = $configPWD/tmake/lib/$f_platform +ENV = env TMAKEPATH=\$(TMAKEPATH) +TMAKE = $configPWD/tmake/bin/tmake +MAKE = $f_make +PERL = $f_perl +RM = rm -f +CP = cp +VERSION = `cat VERSION` +INSTALL = $f_prefix +INSTTOOL = $f_insttool +DOXYDOCS = .. +DOCDIR = $f_docdir +QTDIR = $QTDIR +EOF + +if test "$f_dot" != NO; then + cat >> .makeconfig <<EOF +HAVE_DOT = $f_dot +EOF +fi + +if test "$f_platform" = "m68k-atari-mint-g++"; then + cat >> .makeconfig <<EOF +TMAKE += -unix +EOF +fi + +if test "$f_platform" = "macosx-c++"; then + cat >> .makeconfig <<EOF +MKSPECS = -spec macx-g++ +EOF +fi +if test "$f_platform" = "macosx-uni-c++"; then + cat >> .makeconfig <<EOF +MKSPECS = -spec macx-g++ +EOF + fi + + +# Make doxygen.spec... +# +echo " Created doxygen.spec file, for rpm generation." + +echo "%define version $doxygen_version_major.$doxygen_version_minor.$doxygen_version_revision" > spec.tmp +if test "$doxygen_version_mmn" = NO; then + echo "%define revision 1" >> spec.tmp + echo "%define mmn 1" >> spec.tmp +else + echo "%define revision $doxygen_version_mmn" >> spec.tmp + echo "%define mmn $doxygen_version_mmn" >> spec.tmp +fi + +mkdir -p packages +mkdir -p packages/rpm + +cat spec.tmp ./packages/rpm/doxygen.spec.in > ./packages/rpm/doxygen.spec + +rm -f spec.tmp + + +# make .tmakeconfig +# +touch .tmakeconfig +if test "$f_shared" = NO; then + if test "$f_platform" = "osf1-cxx" -o "$f_platform" = "irix-n32"; then + cat >> .tmakeconfig <<EOF + TMAKE_LFLAGS += -non_shared +EOF + elif test "$f_platform" = "solaris-cc"; then + cat >> .tmakeconfig <<EOF + TMAKE_LFLAGS += -Bstatic +EOF + elif test "$f_platform" = "hpux-cc"; then + cat >> .tmakeconfig <<EOF + TMAKE_LFLAGS += -noshared +EOF + else + cat >> .tmakeconfig <<EOF + TMAKE_LFLAGS += -static +EOF + fi +fi +if test "$f_platform" = "hpux-g++" -o "$f_platform" = "linux-g++"; then + cat >> .tmakeconfig <<EOF + TMAKE_CXXFLAGS += -D_LARGEFILE_SOURCE +EOF +fi +if test "$f_platform" = "macosx-uni-c++"; then + if test -n "`ls /Developer/SDKs/MacOSX10.*.sdk 2>/dev/null`"; then + mac_sdk=MacOSX10.4u.sdk + fi + if test -n "`ls /Developer/SDKs/MacOSX10.5*.sdk 2>/dev/null`"; then + mac_sdk=MacOSX10.5.sdk + fi + if test -n $mac_sdk; then + cat >> .tmakeconfig <<EOF + TMAKE_CFLAGS += -isysroot /Developer/SDKs/$mac_sdk + TMAKE_CXXFLAGS += -isysroot /Developer/SDKs/$mac_sdk + TMAKE_LFLAGS += -Wl,-syslibroot,/Developer/SDKs/$mac_sdk +EOF + fi +fi +if test "$f_wizard" = YES; then + cat >> .tmakeconfig <<EOF +TMAKE_MOC = $QTDIR/bin/moc +EOF +fi + +if test "$f_english" = YES; then + cat >> .tmakeconfig <<EOF +TMAKE_CXXFLAGS += -DENGLISH_ONLY +EOF +fi + +f_inmakefiles="Makefile.in qtools/Makefile.in src/Makefile.in examples/Makefile.in doc/Makefile.in addon/doxywizard/Makefile.in addon/doxmlparser/src/Makefile.in addon/doxmlparser/test/Makefile.in addon/doxmlparser/examples/metrics/Makefile.in libmd5/Makefile.in addon/doxyapp/Makefile.in" + +for i in $f_inmakefiles ; do + SRC=$i + DST=`echo $i|sed 's%\(.*\).in$%\1%'` + TIME=`date` + cat > $DST <<EOF +# +# This file was generated from `basename $i` on $TIME +# + +EOF + cat .makeconfig >> $DST + if test $i = Makefile.in; then + echo "" >> $DST + echo "all: src/version.cpp " >> $DST + echo " \$(MAKE) -C qtools" >> $DST + echo " \$(MAKE) -C libmd5" >> $DST + echo " \$(MAKE) -C src" >> $DST + if test $f_wizard = YES; then + echo " \$(MAKE) MAN1DIR=\$(MAN1DIR) -C addon/doxywizard" >> $DST + fi + if test $f_app = YES; then + echo " \$(MAKE) -C addon/doxyapp" >> $DST + fi + echo "" >> $DST + echo "doxywizard_install:" >> $DST + if test $f_wizard = YES; then + echo " \$(MAKE) MAN1DIR=\$(MAN1DIR) -C addon/doxywizard install" >> $DST + fi + echo "" >> $DST + fi + if test $f_wizard = YES; then + sed -e "s/%%WITHDOXYWIZARD%% /--with doxywizard /g" $SRC >> $DST + else + sed -e "s/%%WITHDOXYWIZARD%% //g" $SRC >> $DST + fi + echo " Created $DST from $SRC..." +done + +cat src/libdoxycfg.t.in | sed -e "s|%%FLEX%%|$f_flex|g" -e "s|%%BISON%%|$f_bison|g" > src/libdoxycfg.t +cat src/libdoxygen.t.in | sed -e "s|%%FLEX%%|$f_flex|g" -e "s|%%BISON%%|$f_bison|g" > src/libdoxygen.t + +f_inprofiles="qtools/qtools.pro.in src/libdoxygen.pro.in src/libdoxycfg.pro.in src/doxygen.pro.in addon/doxywizard/doxywizard.pro.in addon/doxmlparser/src/doxmlparser.pro.in addon/doxmlparser/test/xmlparse.pro.in addon/doxmlparser/examples/metrics/metrics.pro.in libmd5/libmd5.pro.in addon/doxyapp/doxyapp.pro.in" + +for i in $f_inprofiles ; do + SRC=$i + DST=`echo $i|sed 's%\(.*\).in$%\1%'` + TIME=`date` + cat > $DST <<EOF +# +# This file was generated from `basename $i` on $TIME +# + +EOF + if test "$f_debug" = NO; then + realopts="release" + else + realopts="debug" + fi + #if test "$f_thread" = YES; then + # realopts="$realopts thread" + #fi + cat $SRC .tmakeconfig | sed -e "s/\$extraopts/$realopts/g" >> $DST + echo " Created $DST from $SRC..." +done + +# - generating src/lang_cfg.h + +if test -f "src/lang_cfg.h"; then + chmod u+w src/lang_cfg.h # make sure file can be overwritten +fi +echo -n " Generating src/lang_cfg.h..." +echo $f_langs | $f_perl -e '@l=split(/,/,<STDIN>); + chomp @l; + @allowed=(split(/,/,"NL,SV,CZ,FR,ID,IT,DE,JP,JE,ES,FI,RU,HR,PL,PT,HU,KR,KE,RO,SI,CN,NO,MK,BR,DK,SK,UA,GR,TW,SR,CA,LT,ZA,AR,FA,SC,VI,TR,EO,AM")); + foreach my $elem (@l){ + $elem =~ tr/a-z/A-Z/; + $r=0; + foreach my $tst (@allowed){ + if ($tst eq $elem) { $r=1; last; } + } + if ($r!=1) { die "ERROR: Invalid language $elem was selected!\n"; } + print "#define LANG_$elem\n"; + };' > ./src/lang_cfg.h +echo diff --git a/trunk/configure.bin b/trunk/configure.bin new file mode 100755 index 0000000..e69de29 diff --git a/trunk/doc/Doxyfile b/trunk/doc/Doxyfile new file mode 100644 index 0000000..0d1381e --- /dev/null +++ b/trunk/doc/Doxyfile @@ -0,0 +1,53 @@ +# +# +# +# Copyright (C) 1997-1999 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. + +PROJECT_NAME = +OUTPUT_DIRECTORY = .. +HTML_HEADER = +HTML_FOOTER = +QUIET = NO +WARNINGS = YES +DISABLE_INDEX = YES +GENERATE_TREEVIEW = YES +EXTRACT_ALL = NO +EXTRACT_PRIVATE = NO +GENERATE_MAN = NO +GENERATE_LATEX = YES +GENERATE_HTML = YES +GENERATE_HTMLHELP = NO +GENERATE_RTF = NO +GENERATE_XML = NO +HTML_COLORSTYLE_SAT = 0 +ENABLED_SECTIONS = logo_on +ENABLE_PREPROCESSING = NO +CASE_SENSE_NAMES = NO +IMAGE_PATH = . +INPUT = index.doc install.doc starting.doc docblocks.doc markdown.doc \ + grouping.doc formulas.doc diagrams.doc preprocessing.doc \ + autolink.doc output.doc searching.doc customize.doc custcmd.doc \ + external.doc faq.doc trouble.doc features.doc \ + doxygen_usage.doc doxywizard_usage.doc \ + config.doc commands.doc htmlcmds.doc xmlcmds.doc language.doc \ + perlmod.doc perlmod_tree.doc arch.doc +FILE_PATTERNS = *.cpp *.h *.doc +EXAMPLE_PATH = ../examples +RECURSIVE = NO +TAGFILES = +ALLEXTERNALS = NO +PERL_PATH = /usr/bin/perl +SEARCHENGINE = NO +PDF_HYPERLINKS = YES +USE_PDFLATEX = YES +STRIP_CODE_COMMENTS = NO +HTML_STYLESHEET = doxygen_manual.css diff --git a/trunk/doc/Makefile.in b/trunk/doc/Makefile.in new file mode 100644 index 0000000..aaa9b0e --- /dev/null +++ b/trunk/doc/Makefile.in @@ -0,0 +1,36 @@ +# +# +# +# Copyright (C) 1997-2012 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. + +all: language FORCE + DOXYGEN_DOCDIR=$(DOXYDOCS); \ + export DOXYGEN_DOCDIR; \ + VERSION=$(VERSION) ; \ + export VERSION; \ + $(DOXYGEN)/bin/doxygen + @rm -f ../latex/refman.tex + @cp doxygen_logo*.gif ../html + @cp Makefile.latex ../latex/Makefile + @sed -e "s/\$$VERSION/$(VERSION)/g" doxygen_manual.tex >../latex/doxygen_manual.tex + @sed -e "s/\$$VERSION/$(VERSION)/g" doxygen.sty >../latex/doxygen.sty + @epstopdf doxygen_logo.eps --outfile=../latex/doxygen_logo.pdf + +clean: + rm -rf ../html ../latex *.bak + +language: language.doc + +language.doc: $(wildcard ../src/translator*.h) maintainers.txt language.tpl translator.py + python translator.py + +FORCE: diff --git a/trunk/doc/Makefile.latex b/trunk/doc/Makefile.latex new file mode 100644 index 0000000..a13b90f --- /dev/null +++ b/trunk/doc/Makefile.latex @@ -0,0 +1,25 @@ +# +# +# +# Copyright (C) 1997-2012 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. + +all: doxygen_manual.pdf + +doxygen_manual.pdf: doxygen_manual.tex doxygen.sty + echo "Running latex..." + pdflatex doxygen_manual.tex + echo "Running makeindex..." + makeindex doxygen_manual.idx + echo "Rerunning latex...." + pdflatex doxygen_manual.tex +clean: + rm -f *.ps *.dvi *.aux *.toc *.idx *.ind *.ilg *.log doxygen_manual.pdf diff --git a/trunk/doc/Makefile.win_make.in b/trunk/doc/Makefile.win_make.in new file mode 100644 index 0000000..07c0679 --- /dev/null +++ b/trunk/doc/Makefile.win_make.in @@ -0,0 +1,36 @@ +# +# +# +# Copyright (C) 1997-2012 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. + +all: language FORCE + @xcopy /s /q /i ..\examples ..\html\examples + set DOXYGEN_DOCDIR=. & \ + set VERSION=$(VERSION) & \ + $(DOXYGEN)\bin\doxygen + @del ..\latex\refman.tex + @copy doxygen_logo*.gif ..\html + @copy Makefile.latex ..\latex\Makefile + @sed -e "s/\$$VERSION/$(VERSION)/g" doxygen_manual.tex >..\latex\doxygen_manual.tex + @sed -e "s/\$$VERSION/$(VERSION)/g" doxygen.sty >..\latex\doxygen.sty + @epstopdf doxygen_logo.eps --outfile=..\latex\doxygen_logo.pdf + +clean: + del /s /q ..\html ..\latex + del translator_report.txt *.bak + +language: language.doc + +language.doc: maintainers.txt language.tpl translator.py + set DOXYGEN_DOCDIR=. & set VERSION=$(VERSION) & python translator.py + +FORCE: diff --git a/trunk/doc/Makefile.win_nmake.in b/trunk/doc/Makefile.win_nmake.in new file mode 100644 index 0000000..af8711c --- /dev/null +++ b/trunk/doc/Makefile.win_nmake.in @@ -0,0 +1,38 @@ +# +# +# +# Copyright (C) 1997-2012 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. + +all: language FORCE + @xcopy /s /q /i ..\examples ..\html\examples + set DOXYGEN_DOCDIR=. + set VERSION=$(VERSION) + $(DOXYGEN)\bin\doxygen + @del ..\latex\refman.tex + @copy doxygen_logo*.gif ..\html + @copy Makefile.latex ..\latex\Makefile + @sed -e "s/\$$VERSION/$(VERSION)/g" doxygen_manual.tex >..\latex\doxygen_manual.tex + @sed -e "s/\$$VERSION/$(VERSION)/g" doxygen.sty >..\latex\doxygen.sty + @epstopdf doxygen_logo.eps --outfile=..\latex\doxygen_logo.pdf + +clean: + del /s /q ..\html ..\latex + del translator_report.txt *.bak + +language: language.doc + +language.doc: maintainers.txt language.tpl translator.py + set DOXYGEN_DOCDIR=. + set VERSION=$(VERSION) + python translator.py + +FORCE: diff --git a/trunk/doc/arch.doc b/trunk/doc/arch.doc new file mode 100644 index 0000000..f89b12a --- /dev/null +++ b/trunk/doc/arch.doc @@ -0,0 +1,242 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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 Doxygen's Internals + +<h3>Doxygen's internals</h3> + +<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 <code>src/config.h</code>. The parser itself is written using \c flex +and can be found in <code>src/config.l</code>. 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 in C++ and can be found in src/docparser.cpp. The +tokens that are eaten by the parser come from src/doctokenizer.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 validatingParseDoc() +declared in \c src/docparser.h. For simple texts with special +commands \c validatingParseText() 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/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\) (-i )?-P([a-zA-Z]+)YY -t $file/(LEX) -d \1-P\2YY -t $file/g ) { + print "Enabling debug info for $file\n"; + } + elsif ( s/\(LEX\) -d (-i )?-P([a-zA-Z]+)YY -t $file/(LEX) \1-P\2YY -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/trunk/doc/archoverview.eps b/trunk/doc/archoverview.eps new file mode 100644 index 0000000..b41d36c --- /dev/null +++ b/trunk/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/trunk/doc/archoverview.gif b/trunk/doc/archoverview.gif new file mode 100644 index 0000000..f404076 Binary files /dev/null and b/trunk/doc/archoverview.gif differ diff --git a/trunk/doc/autolink.doc b/trunk/doc/autolink.doc new file mode 100644 index 0000000..7dcb328 --- /dev/null +++ b/trunk/doc/autolink.doc @@ -0,0 +1,134 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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 autolink Automatic link generation + + \tableofcontents + + Most documentation systems have special `see also' sections where links + to other pieces of documentation can be inserted. + Although doxygen also has a command to start such a section (See section + \ref cmdsa "\\sa"), it does allow you to put these kind of links anywhere in the + documentation. + For \f$\mbox{\LaTeX}\f$ documentation a reference to the page number + is written instead of a link. Furthermore, the index at the end of the + document can be used to quickly find the documentation of a member, class, + namespace or file. + For man pages no reference information is generated. + + The next sections show how to generate links to the various documented + entities in a source file. + + \section linkurl Links to web pages and mail addresses + + Doxygen will automatically replace any URLs and mail addresses found in the + documentation by links (in HTML). To manually specify link text, use the + HTML '<tt>a</tt>' tag: + \verbatim <a href="linkURL">link text</a> \endverbatim + which will be automatically translated to other output formats by Doxygen. + + \section linkclass Links to classes + + All words in the documentation that correspond to a documented class and + contain at least one non-lower case character will automatically be + replaced by a link to the page containing the + documentation of the class. If you want to prevent that a word + that corresponds to a documented class is replaced by a link you + should put a \% in front of the word. + To link to an all lower case symbol, use \ref cmdref "\\ref". + + \section linkfile Links to files + + All words that contain a dot (<tt>.</tt>) that is not the last character + in the word are considered to be file names. + If the word is indeed the name of a documented input file, a link will + automatically be created to the documentation of that file. + + \section linkfunc Links to functions + + Links to functions are created if one of the following patterns is + encountered: + <ol> + <li><tt>\<functionName\>"("\<argument-list\>")"</tt> + <li><tt>\<functionName\>"()"</tt> + <li><tt>"::"\<functionName\></tt> + <li><tt>(\<className\>"::")<sup>n</sup>\<functionName\>"("\<argument-list\>")"</tt> + <li><tt>(\<className\>"::")<sup>n</sup>\<functionName\>"("\<argument-list\>")"\<modifiers\></tt> + <li><tt>(\<className\>"::")<sup>n</sup>\<functionName\>"()"</tt> + <li><tt>(\<className\>"::")<sup>n</sup>\<functionName\></tt> + </ol> + where n\>0. + + \par Note 1: + Function arguments should be specified with correct types, i.e. + 'fun(const std::string&,bool)' or '()' to match any prototype. + \par Note 2: + Member function modifiers (like 'const' and 'volatile') + are required to identify the target, i.e. 'func(int) const' and 'fun(int)' + target different member functions. + \par Note 3: + For JavaDoc compatibility a \# may be used instead of a :: in + the patterns above. + \par Note 4: + In the documentation of a class containing a member foo, + a reference to a global variable is made using "::foo", whereas \#foo + will link to the member. + + For non overloaded members the argument list may be omitted. + + If a function is overloaded and no matching argument list is specified + (i.e. pattern 2 or 6 is used), a link will be created to the + documentation of one of the overloaded members. + + For member functions the class scope (as used in patterns 4 to 7) may + be omitted, if: + <ol> + <li>The pattern points to a documented member that belongs to the same class + as the documentation block that contains the pattern. + <li>The class that corresponds to the documentation blocks that contains + the pattern has a base class that contains a documented member + that matches the pattern. + </ol> + + \section linkother Links to other members + + All of these entities can be linked to in the same way as described in the + previous section. For sake of clarity it is advised to only use + patterns 3 and 7 in this case. + + \par Example: + \verbinclude autolink.cpp + \htmlonly + Click <a href="$(DOXYGEN_DOCDIR)/examples/autolink/html/index.html">here</a> + for the corresponding HTML documentation that is generated by Doxygen. + \endhtmlonly + + \section resolving typedefs + + Typedefs that involve classes, structs and unions, like +\verbatim +typedef struct StructName TypeName +\endverbatim + create an alias for StructName, so links will be generated to StructName, + when either StructName itself or TypeName is encountered. + + \par Example: + \verbinclude restypedef.cpp + \htmlonly + Click <a href="$(DOXYGEN_DOCDIR)/examples/restypedef/html/restypedef_8cpp.html">here</a> + for the corresponding HTML documentation that is generated by Doxygen. + \endhtmlonly +*/ diff --git a/trunk/doc/commands.doc b/trunk/doc/commands.doc new file mode 100644 index 0000000..27b18d6 --- /dev/null +++ b/trunk/doc/commands.doc @@ -0,0 +1,2876 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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 commands Special Commands + +\section cmd_intro Introduction + +All commands in the documentation start with a backslash (<b>\\</b>) or an +at-sign (<b>\@</b>). If you prefer you can replace all commands starting with a +backslash below by their counterparts that start with an at-sign. + +Some commands have one or more arguments. +Each argument has a certain range: +<ul> +<li>If \<sharp\> braces are used the argument is a single word. +<li>If (round) braces are used the argument extends until the end of the line + on which the command was found. +<li>If {curly} braces are used the argument extends until the next paragraph. + Paragraphs are delimited by a blank line or by a section indicator. +</ul> +If in addition to the above argument specifiers [square] brackets are used the argument is optional. + +Here is an alphabetically sorted list of all commands with references to their +documentation: +\secreflist +\refitem cmda \\a +\refitem cmdaddindex \\addindex +\refitem cmdaddtogroup \\addtogroup +\refitem cmdanchor \\anchor +\refitem cmdarg \\arg +\refitem cmdattention \\attention +\refitem cmdauthor \\author +\refitem cmdauthors \\authors +\refitem cmdb \\b +\refitem cmdbrief \\brief +\refitem cmdbug \\bug +\refitem cmdc \\c +\refitem cmdcallgraph \\callgraph +\refitem cmdcallergraph \\callergraph +\refitem cmdcategory \\category +\refitem cmdcite \\cite +\refitem cmdclass \\class +\refitem cmdcode \\code +\refitem cmdcond \\cond +\refitem cmdcopybrief \\copybrief +\refitem cmdcopydetails \\copydetails +\refitem cmdcopydoc \\copydoc +\refitem cmdcopyright \\copyright +\refitem cmddate \\date +\refitem cmddef \\def +\refitem cmddefgroup \\defgroup +\refitem cmddeprecated \\deprecated +\refitem cmddetails \\details +\refitem cmddir \\dir +\refitem cmddontinclude \\dontinclude +\refitem cmddot \\dot +\refitem cmddotfile \\dotfile +\refitem cmde \\e +\refitem cmdelse \\else +\refitem cmdelseif \\elseif +\refitem cmdem \\em +\refitem cmdendcode \\endcode +\refitem cmdendcond \\endcond +\refitem cmdenddot \\enddot +\refitem cmdendhtmlonly \\endhtmlonly +\refitem cmdendif \\endif +\refitem cmdendinternal \\endinternal +\refitem cmdendlatexonly \\endlatexonly +\refitem cmdendlink \\endlink +\refitem cmdendmanonly \\endmanonly +\refitem cmdendmsc \\endmsc +\refitem cmdendrtfonly \\endrtfonly +\refitem cmdendverbatim \\endverbatim +\refitem cmdendxmlonly \\endxmlonly +\refitem cmdenum \\enum +\refitem cmdexample \\example +\refitem cmdexception \\exception +\refitem cmdextends \\extends +\refitem cmdfdollar \\f\$ +\refitem cmdfbropen \\f[ +\refitem cmdfbrclose \\f] +\refitem cmdfcurlyopen \\f{ +\refitem cmdfcurlyclose \\f} +\refitem cmdfile \\file +\refitem cmdfn \\fn +\refitem cmdheaderfile \\headerfile +\refitem cmdhideinitializer \\hideinitializer +\refitem cmdhtmlinclude \\htmlinclude +\refitem cmdhtmlonly \\htmlonly +\refitem cmdif \\if +\refitem cmdifnot \\ifnot +\refitem cmdimage \\image +\refitem cmdimplements \\implements +\refitem cmdinclude \\include +\refitem cmdincludelineno \\includelineno +\refitem cmdingroup \\ingroup +\refitem cmdinternal \\internal +\refitem cmdinvariant \\invariant +\refitem cmdinterface \\interface +\refitem cmdlatexonly \\latexonly +\refitem cmdli \\li +\refitem cmdline \\line +\refitem cmdlink \\link +\refitem cmdmainpage \\mainpage +\refitem cmdmanonly \\manonly +\refitem cmdmemberof \\memberof +\refitem cmdmsc \\msc +\refitem cmdmscfile \\mscfile +\refitem cmdn \\n +\refitem cmdname \\name +\refitem cmdnamespace \\namespace +\refitem cmdnosubgrouping \\nosubgrouping +\refitem cmdnote \\note +\refitem cmdoverload \\overload +\refitem cmdp \\p +\refitem cmdpackage \\package +\refitem cmdpage \\page +\refitem cmdpar \\par +\refitem cmdparagraph \\paragraph +\refitem cmdparam \\param +\refitem cmdpost \\post +\refitem cmdpre \\pre +\refitem cmdprivate \\private +\refitem cmdprivate \\privatesection +\refitem cmdproperty \\property +\refitem cmdprotected \\protected +\refitem cmdprotected \\protectedsection +\refitem cmdprotocol \\protocol +\refitem cmdpublic \\public +\refitem cmdpublic \\publicsection +\refitem cmdref \\ref +\refitem cmdrelated \\related +\refitem cmdrelates \\relates +\refitem cmdrelatedalso \\relatedalso +\refitem cmdrelatesalso \\relatesalso +\refitem cmdremark \\remark +\refitem cmdremarks \\remarks +\refitem cmdresult \\result +\refitem cmdreturn \\return +\refitem cmdreturns \\returns +\refitem cmdretval \\retval +\refitem cmdrtfonly \\rtfonly +\refitem cmdsa \\sa +\refitem cmdsection \\section +\refitem cmdsee \\see +\refitem cmdshort \\short +\refitem cmdshowinitializer \\showinitializer +\refitem cmdsince \\since +\refitem cmdskip \\skip +\refitem cmdskipline \\skipline +\refitem cmdsnippet \\snippet +\refitem cmdstruct \\struct +\refitem cmdsubpage \\subpage +\refitem cmdsubsection \\subsection +\refitem cmdsubsubsection \\subsubsection +\refitem cmdtableofcontents \\tableofcontents +\refitem cmdtest \\test +\refitem cmdthrow \\throw +\refitem cmdthrows \\throws +\refitem cmdtodo \\todo +\refitem cmdtparam \\tparam +\refitem cmdtypedef \\typedef +\refitem cmdunion \\union +\refitem cmduntil \\until +\refitem cmdvar \\var +\refitem cmdverbatim \\verbatim +\refitem cmdverbinclude \\verbinclude +\refitem cmdversion \\version +\refitem cmdwarning \\warning +\refitem cmdweakgroup \\weakgroup +\refitem cmdxmlonly \\xmlonly +\refitem cmdxrefitem \\xrefitem +\refitem cmddollar \\\$ +\refitem cmdat \\\@ +\refitem cmdbackslash \\\\ +\refitem cmdamp \\\& +\refitem cmdtilde \\~ +\refitem cmdlt \\\< +\refitem cmdgt \\\> +\refitem cmdhash \\\# +\refitem cmdperc \\\% +\refitem cmdquot \\\" +\refitem cmdchardot \\\. +\refitem cmddcolon \:: +\endsecreflist + +The following subsections provide a list of all commands that are recognized by +doxygen. Unrecognized commands are treated as normal text. + + +\htmlonly <center> \endhtmlonly +<h2> +\htmlonly --- \endhtmlonly +Structural indicators +\htmlonly --- \endhtmlonly +</h2> +\htmlonly </center> \endhtmlonly + +\section cmdaddtogroup \\addtogroup <name> [(title)] + \addindex \\addtogroup + Defines a group just like \ref cmddefgroup "\\defgroup", but in contrast to + that command using the same \<name\> more than once will not result in a warning, + but rather one group with a merged documentation and the first title found in + any of the commands. + + The title is optional, so this command can also be used to add a number of + entities to an existing group using \@{ and \@} like this: + +\verbatim + /*! \addtogroup mygrp + * Additional documentation for group 'mygrp' + * @{ + */ + + /*! + * A function + */ + void func1() + { + } + + /*! Another function */ + void func2() + { + } + + /*! @} */ +\endverbatim + + \sa page \ref grouping "Grouping", sections \ref cmddefgroup "\\defgroup", \ref cmdingroup "\\ingroup", and + \ref cmdweakgroup "\\weakgroup". + +<hr> +\section cmdcallgraph \\callgraph + + \addindex \\callgraph + When this command is put in a comment block of a function or method + and \ref cfg_have_dot "HAVE_DOT" is set to YES, then doxygen will + generate a call graph for that function (provided the implementation of the + function or method calls other documented functions). The call graph will be + generated regardless of the value of \ref cfg_call_graph "CALL_GRAPH". + \note The completeness (and correctness) of the call graph depends on the + doxygen code parser which is not perfect. + + \sa section \ref cmdcallergraph "\\callergraph". + +<hr> +\section cmdcallergraph \\callergraph + + \addindex \\callergraph + When this command is put in a comment block of a function or method + and \ref cfg_have_dot "HAVE_DOT" is set to YES, then doxygen will + generate a caller graph for that function (provided the implementation of the + function or method calls other documented functions). The caller graph will be + generated regardless of the value of \ref cfg_caller_graph "CALLER_GRAPH". + \note The completeness (and correctness) of the caller graph depends on the + doxygen code parser which is not perfect. + + \sa section \ref cmdcallgraph "\\callgraph". + +<hr> +\section cmdcategory \\category <name> [<header-file>] [<header-name>] + + \addindex \\category + For Objective-C only: Indicates that a comment block contains documentation + for a class category with name \<name\>. The arguments are + equal to the \\class command. + + \sa section \ref cmdclass "\\class". + +<hr> +\section cmdclass \\class <name> [<header-file>] [<header-name>] + + \addindex \\class + Indicates that a comment block contains documentation for a + class with name \<name\>. Optionally a header file and a header name + can be specified. If the header-file is specified, a link to a verbatim copy + of the header will be included in the HTML documentation. + The \<header-name\> argument can be used to overwrite the + name of the link that is used in the class documentation to something other + than \<header-file\>. This can be useful if the include name is not located + on the default include path (like \<X11/X.h\>). With the \<header-name\> + argument you can also specify how the include statement should look like, + by adding either quotes or sharp brackets around the name. + Sharp brackets are used if just the name is given. Note that the + last two arguments can also be specified using + the \ref cmdheaderfile "\\headerfile" command. + + \par Example: + \verbinclude class.h + \htmlonly + Click <a href="$(DOXYGEN_DOCDIR)/examples/class/html/index.html">here</a> + for the corresponding HTML documentation that is generated by doxygen. + \endhtmlonly + +<hr> +\section cmddef \\def <name> + + \addindex \\def + Indicates that a comment block contains documentation for a + \c \#define macro. + + \par Example: + \verbinclude define.h + \htmlonly + Click <a href="$(DOXYGEN_DOCDIR)/examples/define/html/define_8h.html">here</a> + for the corresponding HTML documentation that is generated by doxygen. + \endhtmlonly + +<hr> +\section cmddefgroup \\defgroup <name> (group title) + + \addindex \\defgroup + Indicates that a comment block contains documentation for a + \ref modules "group" of classes, files or namespaces. This can be used to + categorize classes, files or namespaces, and document those + categories. You can also use groups as members of other groups, + thus building a hierarchy of groups. + + The \<name\> argument should be a single-word identifier. + + \sa page \ref grouping "Grouping", sections \ref cmdingroup "\\ingroup", \ref cmdaddtogroup "\\addtogroup", and + \ref cmdweakgroup "\\weakgroup". + +<hr> +\section cmddir \\dir [<path fragment>] + + \addindex \\dir + Indicates that a comment block contains documentation for a directory. + The "path fragment" argument should include the directory name and + enough of the path to be unique with respect to the other directories + in the project. + The \ref cfg_show_dirs "SHOW_DIRECTORIES" option determines whether + or not the directory information is shown and the + \ref cfg_strip_from_path "STRIP_FROM_PATH" option determines what is + stripped from the full path before it appears in the output. + +<hr> +\section cmdenum \\enum <name> + + \addindex \\enum + Indicates that a comment block contains documentation for an + enumeration, with name \<name\>. If the enum is a member of a class and + the documentation block is located outside the class definition, + the scope of the class should be specified as well. + If a comment block is located directly in front of an enum declaration, + the \\enum comment may be omitted. + + \par Note: + The type of an anonymous enum cannot be documented, but the values + of an anonymous enum can. + + \par Example: + \verbinclude enum.h + \htmlonly + Click <a href="$(DOXYGEN_DOCDIR)/examples/enum/html/class_test.html">here</a> + for the corresponding HTML documentation that is generated by doxygen. + \endhtmlonly + +<hr> +\section cmdexample \\example <file-name> + + \addindex \\example + Indicates that a comment block contains documentation for a source code + example. The name of the source file is \<file-name\>. The text of + this file will be included in the documentation, just after the + documentation contained in the comment block. All examples are placed + in a list. The source code is scanned for documented members and classes. + If any are found, the names are cross-referenced with the documentation. + Source files or directories can be specified using the + \ref cfg_example_path "EXAMPLE_PATH" + tag of doxygen's configuration file. + + If \<file-name\> itself is not unique for the set of example files specified + by the + \ref cfg_example_path "EXAMPLE_PATH" tag, you can include part of the absolute path + to disambiguate it. + + If more than one source file is needed for the example, + the \\include command can be used. + + \par Example: + \verbinclude example.cpp + Where the example file \c example_test.cpp looks as follows: + \verbinclude example_test.cpp + \htmlonly + Click <a href="$(DOXYGEN_DOCDIR)/examples/example/html/examples.html">here</a> + for the corresponding HTML documentation that is generated by doxygen. + \endhtmlonly + + \sa section \ref cmdinclude "\\include". + +<hr> +\section cmdendinternal \\endinternal + + \addindex \\endinternal + This command ends a documentation fragment that was started with a + \ref cmdinternal "\\internal" command. The text between \c \\internal and + \c \\endinternal will only be visible + if \ref cfg_internal_docs "INTERNAL_DOCS" is set to YES. + +<hr> +\section cmdextends \\extends <name> + + \addindex \\extends + This command can be used to manually indicate an inheritance relation, + when the programming language does not support this concept natively + (e.g. C). + + The file \c manual.c in the example directory shows how to use this command. + + \htmlonly + Click <a href="$(DOXYGEN_DOCDIR)/examples/manual/html/index.html">here</a> + for the corresponding HTML documentation that is generated by doxygen. + \endhtmlonly + + \sa section \ref cmdimplements "\\implements" and section + \ref cmdmemberof "\\memberof" + +<hr> +\section cmdfile \\file [<name>] + + \addindex \\file + Indicates that a comment block contains documentation for a source or + header file with name \<name\>. The file name may include (part of) the + path if the file-name alone is not unique. If the file name is omitted + (i.e. the line after \\file is left blank) then the documentation block that + contains the \\file command will belong to the file it is located in. + + \par Important: + The documentation of global functions, variables, typedefs, and enums will + only be included in the output if the file they are in is documented as well. + + \par Example: + \verbinclude file.h + \htmlonly + Click <a href="$(DOXYGEN_DOCDIR)/examples/file/html/file_8h.html">here</a> + for the corresponding HTML documentation that is generated by doxygen. + \endhtmlonly + + \note In the above example \ref cfg_javadoc_autobrief "JAVADOC_AUTOBRIEF" + has been set to YES in the configuration file. + +<hr> +\section cmdfn \\fn (function declaration) + + \addindex \\fn + Indicates that a comment block contains documentation for a function + (either global or as a member of a class). This command is \em only + needed if a comment block is \e not placed in front (or behind) + the function declaration or definition. + + If your comment block \e is in front of the function + declaration or definition this command can (and to avoid redundancy + should) be omitted. + + A full function declaration including arguments should be specified after the + \\fn command on a \e single line, since the argument ends at the end + of the line! + + This command is equivalent to \\var, \\typedef, and \\property. + + \warning Do not use this command + if it is not absolutely needed, since it will lead to duplication of + information and thus to errors. + + \par Example: + \verbinclude func.h + \htmlonly + Click <a href="$(DOXYGEN_DOCDIR)/examples/func/html/class_test.html">here</a> + for the corresponding HTML documentation that is generated by doxygen. + \endhtmlonly + + + \sa sections \ref cmdvar "\\var", \ref cmdproperty "\\property", and + \ref cmdtypedef "\\typedef". + +<hr> +\section cmdheaderfile \\headerfile <header-file> [<header-name>] + + \addindex \\headerfile + Intended to be used for class, struct, or union documentation, where + the documentation is in front of the definition. The arguments of + this command are the same as the second and third argument of + \ref cmdclass "\\class". + The \<header-file\> name refers to the file that should be included by the + application to obtain the definition of the class, struct, or union. + The \<header-name\> argument can be used to overwrite the + name of the link that is used in the class documentation to something other + than \<header-file\>. This can be useful if the include name is not located + on the default include path (like \<X11/X.h\>). + + With the \<header-name\> + argument you can also specify how the include statement should look like, + by adding either double quotes or sharp brackets around the name. + By default sharp brackets are used if just the name is given. + + If a pair of double quotes is given for either the \<header-file\> or + \<header-name\> argument, the current file (in which the command was found) + will be used but with quotes. So for a comment block with a \\headerfile + command inside a file test.h, the following three commands are equivalent: + \verbatim + \headerfile test.h "test.h" + \headerfile test.h "" + \headerfile "" \endverbatim + To get sharp brackets you do not need to specify anything, + but if you want to be explicit you could use any of the following: + \verbatim + \headerfile test.h <test.h> + \headerfile test.h <> + \headerfile <> \endverbatim + + To globally reverse the default include representation to + local includes you can set + \ref cfg_force_local_includes "FORCE_LOCAL_INCLUDES" to \c YES. + + To disable the include information altogether set + \ref cfg_show_include_files "SHOW_INCLUDE_FILES" to \c NO. + +<hr> +\section cmdhideinitializer \\hideinitializer + + \addindex \\hideinitializer + By default the value of a define and the initializer of a variable + are displayed unless they are longer than 30 lines. By putting + this command in a comment block of a define or variable, the + initializer is always hidden. The maximum number of initialization lines + can be changed by means of the configuration parameter + \ref cfg_max_initializer_lines "MAX_INITIALIZER_LINES", the default + value is 30. + + \sa section \ref cmdshowinitializer "\\showinitializer". + +<hr> +\section cmdimplements \\implements <name> + + \addindex \\implements + This command can be used to manually indicate an inheritance relation, + when the programming language does not support this concept natively + (e.g. C). + + The file \c manual.c in the example directory shows how to use this command. + + \htmlonly + Click <a href="$(DOXYGEN_DOCDIR)/examples/manual/html/index.html">here</a> + for the corresponding HTML documentation that is generated by doxygen. + \endhtmlonly + + \sa section \ref cmdextends "\\extends" and section + \ref cmdmemberof "\\memberof" + +<hr> +\section cmdingroup \\ingroup (<groupname> [<groupname> <groupname>]) + + \addindex \\ingroup + If the \\ingroup command is placed in a comment block of a + class, file or namespace, then it will be added to the group or + groups identified by \<groupname\>. + + \sa page \ref grouping "Grouping", sections \ref cmddefgroup "\\defgroup", + \ref cmdaddtogroup "\\addtogroup", and \ref cmdweakgroup "\\weakgroup" + +<hr> +\section cmdinterface \\interface <name> [<header-file>] [<header-name>] + + \addindex \\interface + Indicates that a comment block contains documentation for an + interface with name \<name\>. The arguments are equal to the arguments of the \\class + command. + + \sa section \ref cmdclass "\\class". + +<hr> +\section cmdinternal \\internal + + \addindex \\internal + This command starts a documentation fragment that is meant for internal + use only. The fragment naturally ends at the end of the comment block. + You can also force the internal section to end earlier by using the + \ref cmdendinternal "\\endinternal" command. + + If the \\internal command is put inside a section + (see for example \ref cmdsection "\\section") all subsections after the + command are considered to be internal as well. Only a new section at the + same level will end the fragment that is considered internal. + + You can use \ref cfg_internal_docs "INTERNAL_DOCS" in the config file + to show (\c YES) or hide (\c NO) the internal documentation. + + \sa section \ref cmdendinternal "\\endinternal". + +<hr> +\section cmdmainpage \\mainpage [(title)] + + \addindex \\mainpage + + If the \\mainpage command is placed in a comment block the + block is used to customize the index page (in HTML) or + the first chapter (in \f$\mbox{\LaTeX}\f$). + + The title argument is optional and replaces the default title that + doxygen normally generates. If you do not want any title you can + specify \c notitle as the argument of \\mainpage. + + Here is an example: +\verbatim +/*! \mainpage My Personal Index Page + * + * \section intro_sec Introduction + * + * This is the introduction. + * + * \section install_sec Installation + * + * \subsection step1 Step 1: Opening the box + * + * etc... + */ +\endverbatim + + You can refer to the main page using \\ref index. + + \sa section \ref cmdsection "\\section", + section \ref cmdsubsection "\\subsection", and + section \ref cmdpage "\\page". + +<hr> +\section cmdmemberof \\memberof <name> + + \addindex \\memberof + This command makes a function a member of a class in a similar way + as \ref cmdrelates "\\relates" does, only with this command the function + is represented as a real member of the class. + This can be useful when the programming language does not support + the concept of member functions natively (e.g. C). + + It is also possible to use this command together with + \ref cmdpublic "\\public", \ref cmdprotected "\\protected" or + \ref cmdprivate "\\private". + + The file \c manual.c in the example directory shows how to use this command. + + \htmlonly + Click <a href="$(DOXYGEN_DOCDIR)/examples/manual/html/index.html">here</a> + for the corresponding HTML documentation that is generated by doxygen. + \endhtmlonly + + \sa sections \ref cmdextends "\\extends", \ref cmdimplements "\\implements", + \ref cmdpublic "\\public", \ref cmdprotected "\\protected" and + \ref cmdprivate "\\private". + +<hr> +\section cmdname \\name [(header)] + + \addindex \\name + + This command turns a comment block into a header + definition of a member group. The + comment block should be followed by a + <code>//\@{ ... //\@}</code> block containing the + members of the group. + + See section \ref memgroup for an example. + +<hr> +\section cmdnamespace \\namespace <name> + + \addindex \\namespace + Indicates that a comment block contains documentation for a + namespace with name \<name\>. + +<hr> +\section cmdnosubgrouping \\nosubgrouping + + \addindex \\nosubgrouping + This command can be put in the documentation + of a class. It can be used in combination with member grouping + to avoid that doxygen puts a member group as a subgroup of a + Public/Protected/Private/... section. + + \sa sections \ref cmdpublicsection "\\publicsection", + \ref cmdprotectedsection "\\protectedsection" and + \ref cmdprivatesection "\\privatesection". +<hr> +\section cmdoverload \\overload [(function declaration)] + + \addindex \\overload + This command can be used to generate the following + standard text for an overloaded member function: + + > This is an overloaded member function, provided for convenience. + > It differs from the above function only in what argument(s) it accepts. + + If the documentation for the overloaded member function is not located + in front of the function declaration or definition, the optional + argument should be used to specify the correct function. + + Any other documentation that is inside the documentation block will + by appended after the generated message. + + \par Note 1: + You are responsible that there is indeed an + earlier documented member that is overloaded by this one. + To prevent that document reorders the documentation you should set + \ref cfg_sort_member_docs "SORT_MEMBER_DOCS" to NO in this case. + \par Note 2: + The \\overload command does not work inside a one-line comment. + \par Example: + \verbinclude examples/overload.cpp + \htmlonly + Click <a href="$(DOXYGEN_DOCDIR)/examples/overload/html/class_test.html">here</a> + for the corresponding HTML documentation that is generated by doxygen. + \endhtmlonly + +<hr> +\section cmdpackage \\package <name> + + \addindex \\package + Indicates that a comment block contains documentation for a + Java package with name \<name\>. + +<hr> +\section cmdpage \\page <name> (title) + + \addindex \\page + Indicates that a comment block contains a piece of documentation that is + not directly related to one specific class, file or member. + The HTML generator creates a page containing the documentation. The + \f$\mbox{\LaTeX}\f$ generator + starts a new section in the chapter 'Page documentation'. + + \par Example: + \verbinclude page.doc + \htmlonly + Click <a href="$(DOXYGEN_DOCDIR)/examples/page/html/pages.html">here</a> + for the corresponding HTML documentation that is generated by doxygen. + \endhtmlonly + + \par Note: + The \<name\> argument consists of a combination of letters and number + digits. If you wish to use upper case letters (e.g. \c MYPAGE1), or + mixed case letters (e.g. \c MyPage1) in the \<name\> argument, you + should set \c CASE_SENSE_NAMES to \c YES. However, this is advisable + only if your file system is case sensitive. Otherwise (and for better + portability) you should use all lower case letters (e.g. \c mypage1) + for \<name\> in all references to the page. + + \sa section \ref cmdsection "\\section", section + \ref cmdsubsection "\\subsection", and section + \ref cmdref "\\ref". + +<hr> +\section cmdprivate \\private + + \addindex \\private + Indicates that the member documented in the comment block is private, + i.e., should only be accessed by other members in the same class. + + Note that Doxygen automatically detects the protection level of members + in object-oriented languages. This command is intended for use only when + the language does not support the concept of protection level natively + (e.g. C, PHP 4). + + For starting a section of private members, in a way similar to the + "private:" class marker in C++, use \\privatesection. + + \sa sections \ref cmdmemberof "\\memberof", \ref cmdpublic "\\public", + \ref cmdprotected "\\protected" and \ref cmdprivatesection "\\privatesection". + +<hr> +\section cmdprivatesection \\privatesection + + \addindex \\privatesection + Starting a section of private members, in a way similar to the + "private:" class marker in C++. + Indicates that the member documented in the comment block is private, + i.e., should only be accessed by other members in the same class. + + \sa sections \ref cmdmemberof "\\memberof", \ref cmdpublic "\\public", + \ref cmdprotected "\\protected" and \ref cmdprivate "\\private". + +<hr> +\section cmdproperty \\property (qualified property name) + + \addindex \\property + Indicates that a comment block contains documentation for a + property (either global or as a member of a class). + This command is equivalent to \\var, \\typedef, and \\fn. + + \sa sections \ref cmdfn "\\fn", \ref cmdtypedef "\\typedef", and + \ref cmdvar "\\var". + +<hr> +\section cmdprotected \\protected + + \addindex \\protected + Indicates that the member documented in the comment block is protected, + i.e., should only be accessed by other members in the same or derived + classes. + + Note that Doxygen automatically detects the protection level of members + in object-oriented languages. This command is intended for use only when + the language does not support the concept of protection level natively + (e.g. C, PHP 4). + + For starting a section of protected members, in a way similar to the + "protected:" class marker in C++, use \\protectedsection. + + \sa sections \ref cmdmemberof "\\memberof", \ref cmdpublic "\\public", + \ref cmdprivate "\\private" and \ref cmdprotectedsection "\\protectedsection". + +<hr> +\section cmdprotectedsection \\protectedsection + + \addindex \\protectedsection + Starting a section of protected members, in a way similar to the + "protected:" class marker in C++. + Indicates that the member documented in the comment block is protected, + i.e., should only be accessed by other members in the same or derived + classes. + + \sa sections \ref cmdmemberof "\\memberof", \ref cmdpublic "\\public", + \ref cmdprivate "\\private" and \ref cmdprotected "\\protected". + +<hr> +\section cmdprotocol \\protocol <name> [<header-file>] [<header-name>] + + \addindex \\protocol + Indicates that a comment block contains documentation for a + protocol in Objective-C with name \<name\>. The arguments are equal + to the \\class command. + + \sa section \ref cmdclass "\\class". + +<hr> +\section cmdpublic \\public + + \addindex \\public + Indicates that the member documented in the comment block is public, + i.e., can be accessed by any other class or function. + + Note that Doxygen automatically detects the protection level of members + in object-oriented languages. This command is intended for use only when + the language does not support the concept of protection level natively + (e.g. C, PHP 4). + + For starting a section of public members, in a way similar to the + "public:" class marker in C++, use \\publicsection. + + \sa sections \ref cmdmemberof "\\memberof", \ref cmdprotected "\\protected", + \ref cmdprivate "\\private" and \ref cmdpublicsection "\\publicsection". + +<hr> +\section cmdpublicsection \\publicsection + + \addindex \\publicsection + Starting a section of public members, in a way similar to the + "public:" class marker in C++. + Indicates that the member documented in the comment block is public, + i.e., can be accessed by any other class or function. + + \sa sections \ref cmdmemberof "\\memberof", \ref cmdprotected "\\protected", + \ref cmdprivate "\\private" and \ref cmdpublic "\\public". + +<hr> +\section cmdrelates \\relates <name> + + \addindex \\relates + This command can be used in the documentation of a non-member function + \<name\>. It puts the function inside the 'related function' section + of the class documentation. This command is useful for documenting + non-friend functions that are nevertheless strongly coupled to a certain + class. It prevents the need of having to document a file, but + only works for functions. + + \par Example: + \verbinclude relates.cpp + \htmlonly + Click <a href="$(DOXYGEN_DOCDIR)/examples/relates/html/class_string.html">here</a> + for the corresponding HTML documentation that is generated by doxygen. + \endhtmlonly + +<hr> +\section cmdrelated \\related <name> + + \addindex related + Equivalent to \ref cmdrelates "\\relates" + +<hr> +\section cmdrelatesalso \\relatesalso <name> + + \addindex \\relatesalso + This command can be used in the documentation of a non-member function + \<name\>. It puts the function both inside the 'related function' section + of the class documentation as well as leaving it at its normal file documentation + location. This command is useful for documenting + non-friend functions that are nevertheless strongly coupled to a certain + class. It only works for functions. + +<hr> +\section cmdrelatedalso \\relatedalso <name> + + \addindex relatedalso + Equivalent to \ref cmdrelatesalso "\\relatesalso" + +<hr> +\section cmdshowinitializer \\showinitializer + + \addindex \\showinitializer + By default the value of a define and the initializer of a variable + are only displayed if they are less than 30 lines long. By putting + this command in a comment block of a define or variable, the + initializer is shown unconditionally. + The maximum number of initialization lines + can be changed by means of the configuration parameter + \ref cfg_max_initializer_lines "MAX_INITIALIZER_LINES", the default value is + 30. + + \sa section \ref cmdhideinitializer "\\hideinitializer". + +<hr> +\section cmdstruct \\struct <name> [<header-file>] [<header-name>] + + \addindex \\struct + Indicates that a comment block contains documentation for a + struct with name \<name\>. The arguments are equal to the arguments of the \\class + command. + + \sa section \ref cmdclass "\\class". + +<hr> +\section cmdtypedef \\typedef (typedef declaration) + + \addindex \\typedef + Indicates that a comment block contains documentation for a + typedef (either global or as a member of a class). + This command is equivalent to \\var, \\property, and \\fn. + + \sa section \ref cmdfn "\\fn", \ref cmdproperty "\\property", and + \ref cmdvar "\\var". + +<hr> +\section cmdunion \\union <name> [<header-file>] [<header-name>] + + \addindex \\union + Indicates that a comment block contains documentation for a + union with name \<name\>. The arguments are equal to the arguments of the \\class + command. + + \sa section \ref cmdclass "\\class". + +<hr> +\section cmdvar \\var (variable declaration) + + \addindex \\var + Indicates that a comment block contains documentation for a variable or + enum value (either global or as a member of a class). + This command is equivalent to \\typedef, \\property, and \\fn. + + \sa section \ref cmdfn "\\fn", \ref cmdproperty "\\property", and \ref cmdtypedef "\\typedef". + +<hr> +\section cmdweakgroup \\weakgroup <name> [(title)] + \addindex \\addtogroup + Can be used exactly like \ref cmdaddtogroup "\\addtogroup", but has + a lower priority when it comes to resolving conflicting grouping + definitions. + + \sa page \ref grouping "Grouping" and section \ref cmdaddtogroup "\\addtogroup". + +<hr> + +\htmlonly <center> \endhtmlonly +<h2> +\htmlonly --- \endhtmlonly +Section indicators +\htmlonly --- \endhtmlonly +</h2> +\htmlonly </center>\endhtmlonly + +<hr> +\section cmdattention \\attention { attention text } + + \addindex \\attention + Starts a paragraph where a message that needs attention may be entered. + The paragraph will be indented. + The text of the paragraph has no special internal structure. All visual + enhancement commands may be used inside the paragraph. + Multiple adjacent \\attention commands will be joined into a single paragraph. + The \\attention command ends when a blank line or some other + sectioning command is encountered. + +<hr> +\section cmdauthor \\author { list of authors } + + \addindex \\author + Starts a paragraph where one or more author names may be entered. + The paragraph will be indented. + The text of the paragraph has no special internal structure. All visual + enhancement commands may be used inside the paragraph. + Multiple adjacent \\author commands will be joined into a single paragraph. + Each author description will start a new line. Alternatively, one \\author command + may mention several authors. The \\author command ends when a blank line or some other + sectioning command is encountered. + + \par Example: + \verbinclude author.cpp + \htmlonly + Click <a href="$(DOXYGEN_DOCDIR)/examples/author/html/class_some_nice_class.html">here</a> + for the corresponding HTML documentation that is generated by doxygen. + \endhtmlonly + +<hr> +\section cmdauthors \\authors { list of authors } + + \addindex \\authors + Equivalent to \ref cmdauthor "\\author". + +<hr> +\section cmdbrief \\brief { brief description } + + \addindex \\brief + Starts a paragraph that serves as a brief description. For classes and files + the brief description will be used in lists and at the start of the + documentation page. For class and file members, the brief description + will be placed at the declaration of the member and prepended to the + detailed description. A brief description may span several lines (although + it is advised to keep it brief!). A brief description ends when a + blank line or another sectioning command is encountered. If multiple + \\brief commands are present they will be joined. See section + \ref cmdauthor "\\author" for an example. + + Synonymous to \\short. + +<hr> +\section cmdbug \\bug { bug description } + + \addindex \\bug + Starts a paragraph where one or more bugs may be reported. + The paragraph will be indented. + The text of the paragraph has no special internal structure. All visual + enhancement commands may be used inside the paragraph. + Multiple adjacent \\bug commands will be joined into a single paragraph. + Each bug description will start on a new line. + Alternatively, one \\bug command may mention + several bugs. The \\bug command ends when a blank line or some other + sectioning command is encountered. See section \ref cmdauthor "\\author" + for an example. + +<hr> +\section cmdcond \\cond [<section-label>] + + \addindex \\cond + Starts a conditional section that ends with a corresponding + \ref cmdendcond "\\endcond" command, which is typically found in + another comment block. The main purpose of this pair of + commands is to (conditionally) exclude part of a file from processing + (in older version of doxygen this could only be achieved using C preprocessor commands). + + The section between \\cond and \\endcond commands can be included by + adding its section label to the \ref cfg_enabled_sections "ENABLED_SECTIONS" + configuration option. If the section label is omitted, the section will + be excluded from processing unconditionally. + + For conditional sections within a comment block one should + use a \ref cmdif "\\if" ... \ref cmdendif "\\endif" block. + + Conditional sections can be nested. In this case a nested section will only + be shown if it and its containing section are included. + + Here is an example showing the commands in action: + +\verbatim +/** An interface */ +class Intf +{ + public: + /** A method */ + virtual void func() = 0; + + /// @cond TEST + + /** A method used for testing */ + virtual void test() = 0; + + /// @endcond +}; + +/// @cond DEV +/* + * The implementation of the interface + */ +class Implementation : public Intf +{ + public: + void func(); + + /// @cond TEST + void test(); + /// @endcond + + /// @cond + /** This method is obsolete and does + * not show up in the documentation. + */ + void obsolete(); + /// @endcond +}; + +/// @endcond +\endverbatim + +The output will be different depending on whether or not \c ENABLED_SECTIONS +contains \c TEST, or \c DEV + + \sa section \ref cmdendcond "\\endcond". + +<hr> +\section cmdcopyright \\copyright { copyright description } + + \addindex \\copyright + Starts a paragraph where the copyright of an entity can be described. + This paragraph will be indented. + The text of the paragraph has no special internal structure. + See section \ref cmdauthor "\\author" for an example. + +<hr> +\section cmddate \\date { date description } + + \addindex \\date + Starts a paragraph where one or more dates may be entered. + The paragraph will be indented. + The text of the paragraph has no special internal structure. All visual + enhancement commands may be used inside the paragraph. + Multiple adjacent \\date commands will be joined into a single paragraph. + Each date description will start on a new line. + Alternatively, one \\date command may mention + several dates. The \\date command ends when a blank line or some other + sectioning command is encountered. See section \ref cmdauthor "\\author" + for an example. + +<hr> +\section cmddeprecated \\deprecated { description } + + \addindex \\deprecated + Starts a paragraph indicating that this documentation block belongs to + a deprecated entity. Can be used to describe alternatives, + expected life span, etc. + +<hr> +\section cmddetails \\details { detailed description } + + \addindex \\details + Just like \ref cmdbrief "\\brief" starts a brief description, \\details + starts the detailed description. You can also start a new paragraph (blank line) + then the \\details command is not needed. + +<hr> +\section cmdelse \\else + + \addindex \\else + Starts a conditional section if the previous conditional section + was not enabled. The previous section should have been started with + a \c \\if, \c \\ifnot, or \c \\elseif command. + + \sa \ref cmdif "\\if", \ref cmdifnot "\\ifnot", \ref cmdelseif "\\elseif", + \ref cmdendif "\\endif." + +<hr> +\section cmdelseif \\elseif <section-label> + + \addindex \\elseif + Starts a conditional documentation section if the previous section + was not enabled. A conditional section is + disabled by default. To enable it you must put the + section-label after the \ref cfg_enabled_sections "ENABLED_SECTIONS" + tag in the configuration + file. Conditional blocks can be nested. A nested section is + only enabled if all enclosing sections are enabled as well. + + \sa sections \ref cmdendif "\\endif", \ref cmdifnot "\\ifnot", + \ref cmdelse "\\else", and \ref cmdelseif "\\elseif". + +<hr> +\section cmdendcond \\endcond + + \addindex \\endcond + Ends a conditional section that was started by \ref cmdcond "\\cond". + + \sa section \ref cmdcond "\\cond". + +<hr> +\section cmdendif \\endif + + \addindex \\endif + Ends a conditional section that was started by \c \\if or \c \\ifnot + For each \c \\if or \c \\ifnot one and only one matching \c \\endif must follow. + + \sa sections \ref cmdif "\\if" and \ref cmdifnot "\\ifnot". + +<hr> +\section cmdexception \\exception <exception-object> { exception description } + + \addindex \\exception + Starts an exception description for an exception object with name + \<exception-object\>. Followed by a description of the exception. + The existence of the exception object is not checked. + The text of the paragraph has no special internal structure. All visual + enhancement commands may be used inside the paragraph. + Multiple adjacent \\exception commands will be joined into a single paragraph. + Each exception description will start on a new line. + The \\exception description ends when a blank line or some other + sectioning command is encountered. See section \ref cmdfn "\\fn" for an + example. + +<hr> +\section cmdif \\if <section-label> + + \addindex \\if + Starts a conditional documentation section. The section ends + with a matching \c \\endif command. A conditional section is + disabled by default. To enable it you must put the + section-label after the \ref cfg_enabled_sections "ENABLED_SECTIONS" + tag in the configuration + file. Conditional blocks can be nested. A nested section is + only enabled if all enclosing sections are enabled as well. + + \par Example: +\verbatim + /*! Unconditionally shown documentation. + * \if Cond1 + * Only included if Cond1 is set. + * \endif + * \if Cond2 + * Only included if Cond2 is set. + * \if Cond3 + * Only included if Cond2 and Cond3 are set. + * \endif + * More text. + * \endif + * Unconditional text. + */ +\endverbatim + + You can also use conditional commands inside aliases. To + document a class in two languages you could for instance use: + +\par Example 2: +\verbatim +/*! \english + * This is English. + * \endenglish + * \dutch + * Dit is Nederlands. + * \enddutch + */ +class Example +{ +}; +\endverbatim + + Where the following aliases are defined in the configuration file: + +\verbatim +ALIASES = "english=\if english" \ + "endenglish=\endif" \ + "dutch=\if dutch" \ + "enddutch=\endif" +\endverbatim + + and \c ENABLED_SECTIONS can be used to enable either \c english or \c dutch. + + \sa sections \ref cmdendif "\\endif", \ref cmdifnot "\\ifnot", + \ref cmdelse "\\else", and \ref cmdelseif "\\elseif". + +<hr> +\section cmdifnot \\ifnot <section-label> + + \addindex \\ifnot + Starts a conditional documentation section. The section ends + with a matching \c \\endif command. This conditional section is + enabled by default. To disable it you must put the + section-label after the \ref cfg_enabled_sections "ENABLED_SECTIONS" + tag in the configuration + file. + + \sa sections \ref cmdendif "\\endif", \ref cmdif "\\if", + \ref cmdelse "\\else", and \ref cmdelseif "\\elseif". + +<hr> +\section cmdinvariant \\invariant { description of invariant } + + \addindex \\invariant + Starts a paragraph where the invariant of an entity can be described. + The paragraph will be indented. + The text of the paragraph has no special internal structure. All visual + enhancement commands may be used inside the paragraph. + Multiple adjacent \\invariant commands will be joined into a single paragraph. + Each invariant description will start on a new line. + Alternatively, one \\invariant command may mention + several invariants. The \\invariant command ends when a blank line or some other + sectioning command is encountered. + +<hr> +\section cmdnote \\note { text } + + \addindex \\note + Starts a paragraph where a note can be entered. The paragraph will be + indented. The text of the paragraph has no special internal structure. + All visual enhancement commands may be used inside the paragraph. + Multiple adjacent \\note commands will be joined into a single paragraph. + Each note description will start on a new line. + Alternatively, one \\note command may mention + several notes. The \\note command ends when a blank line or some other + sectioning command is encountered. See section \ref cmdpar "\\par" + for an example. + +<hr> +\section cmdpar \\par [(paragraph title)] { paragraph } + + \addindex \\par + If a paragraph title is given this command starts a paragraph with a + user defined heading. The heading extends until the end of the + line. The paragraph following the command will be indented. + + If no paragraph title is given this command will start a new paragraph. + This will also work inside other paragraph commands + (like \\param or \\warning) without ending that command. + + The text of the paragraph has no special internal structure. All visual + enhancement commands may be used inside the paragraph. + The \\par command ends when a blank line or some other + sectioning command is encountered. + + \par Example: + \verbinclude par.cpp + \htmlonly + Click <a href="$(DOXYGEN_DOCDIR)/examples/par/html/class_test.html">here</a> + for the corresponding HTML documentation that is generated by doxygen. + \endhtmlonly + +<hr> +\section cmdparam \\param [(dir)] <parameter-name> { parameter description } + + \addindex \\param + Starts a parameter description for a function parameter with name + \<parameter-name\>, followed by a description of the parameter. + The existence of the parameter is checked and a warning is given if + the documentation of this (or any other) parameter is missing or not + present in the function declaration or definition. + + The \\param command has an optional attribute, (dir), specifying the direction + of the parameter. Possible values are "[in]", "[in,out]", and "[out]", + note the [square] brackets in this description. + When a parameter is both input and output, [in,out] is used as attribute. + Here is an example for the function memcpy: + \code +/*! + * Copies bytes from a source memory area to a destination memory area, + * where both areas may not overlap. + * @param[out] dest The memory area to copy to. + * @param[in] src The memory area to copy from. + * @param[in] n The number of bytes to copy + */ +void memcpy(void *dest, const void *src, size_t n); + \endcode + + The parameter description is a paragraph with no special internal structure. + All visual enhancement commands may be used inside the paragraph. + + Multiple adjacent \\param commands will be joined into a single paragraph. + Each parameter description will start on a new line. + The \\param description ends when a blank line or some other + sectioning command is encountered. See section \ref cmdfn "\\fn" for an + example. + + Note that you can also document multiple parameters with a single + \\param command using a comma separated list. Here is an example: + +\code +/** Sets the position. + * @param x,y,z Coordinates of the position in 3D space. + */ +void setPosition(double x,double y,double z,double t) +{ +} +\endcode + + Note that for PHP one can also specify the type (or types if you + separate them with a pipe symbol) which are allowed for a parameter + (as this is not part of the definition). + The syntax is the same as for phpDocumentor, i.e. +\verbatim +@param datatype1|datatype2 $paramname description +\endverbatim + +<hr> +\section cmdtparam \\tparam <template-parameter-name> { description } + + \addindex \\tparam + Starts a template parameter for a class or function template parameter + with name \<template-parameter-name\>, followed by a description of the + template parameter. + + Otherwise similar to \ref cmdparam "\\param". + +<hr> +\section cmdpost \\post { description of the postcondition } + + \addindex \\post + Starts a paragraph where the postcondition of an entity can be described. + The paragraph will be indented. + The text of the paragraph has no special internal structure. All visual + enhancement commands may be used inside the paragraph. + Multiple adjacent \\post commands will be joined into a single paragraph. + Each postcondition will start on a new line. + Alternatively, one \\post command may mention + several postconditions. The \\post command ends when a blank line or some other + sectioning command is encountered. + +<hr> +\section cmdpre \\pre { description of the precondition } + + \addindex \\pre + Starts a paragraph where the precondition of an entity can be described. + The paragraph will be indented. + The text of the paragraph has no special internal structure. All visual + enhancement commands may be used inside the paragraph. + Multiple adjacent \\pre commands will be joined into a single paragraph. + Each precondition will start on a new line. + Alternatively, one \\pre command may mention + several preconditions. The \\pre command ends when a blank line or some other + sectioning command is encountered. + +<hr> +\section cmdremark \\remark { remark text } + + \addindex \\remark + Starts a paragraph where one or more remarks may be entered. + The paragraph will be indented. + The text of the paragraph has no special internal structure. All visual + enhancement commands may be used inside the paragraph. + Multiple adjacent \\remark commands will be joined into a single paragraph. + Each remark will start on a new line. + Alternatively, one \\remark command may mention + several remarks. The \\remark command ends when a blank line or some other + sectioning command is encountered. + +<hr> +\section cmdremarks \\remarks { remark text } + + \addindex \\remarks + Equivalent to \ref cmdremark "\\remark". + +<hr> +\section cmdresult \\result { description of the result value } + + \addindex \\result + Equivalent to \ref cmdreturn "\\return". + +<hr> +\section cmdreturn \\return { description of the return value } + + \addindex \\return + Starts a return value description for a function. + The text of the paragraph has no special internal structure. All visual + enhancement commands may be used inside the paragraph. + Multiple adjacent \\return commands will be joined into a single paragraph. + The \\return description ends when a blank line or some other + sectioning command is encountered. See section \ref cmdfn "\\fn" for an + example. + +<hr> +\section cmdreturns \\returns { description of the return value } + + \addindex \\returns + Equivalent to \ref cmdreturn "\\return". + +<hr> +\section cmdretval \\retval <return value> { description } + + \addindex \\retval + Starts a description for a function's return value with name + \<return value\>, followed by a description of the return value. + The text of the paragraph that forms the description has no special + internal structure. All visual enhancement commands may be used inside the + paragraph. + Multiple adjacent \\retval commands will be joined into a single paragraph. + Each return value description will start on a new line. + The \\retval description ends when a blank line or some other + sectioning command is encountered. + +<hr> +\section cmdsa \\sa { references } + + \addindex \\sa + Starts a paragraph where one or more cross-references to classes, + functions, methods, variables, files or URL may be specified. + Two names joined by either <code>::</code> or <code>\#</code> + are understood as referring to a class and one of its members. + One of several overloaded methods or constructors + may be selected by including a parenthesized list of argument types after + the method name. + + Synonymous to \\see. + + \sa section \ref autolink "autolink" for information on how to create links + to objects. + +<hr> +\section cmdsee \\see { references } + + \addindex \\see + Equivalent to \ref cmdsa "\\sa". Introduced for compatibility with Javadoc. + +<hr> +\section cmdshort \\short { short description } + + \addindex \\short + Equivalent to \ref cmdbrief "\\brief". + +<hr> +\section cmdsince \\since { text } + + \addindex \\since + This tag can be used to specify since when (version or time) an + entity is available. The paragraph that follows \\since does not have any + special internal structure. All visual enhancement commands may be + used inside the paragraph. The \\since description ends when a blank + line or some other sectioning command is encountered. + +<hr> +\section cmdtest \\test { paragraph describing a test case } + + \addindex \\test + Starts a paragraph where a test case can be described. + The description will also add the test case to a separate test list. + The two instances of the description will be cross-referenced. + Each test case in the test list will be preceded by a header that + indicates the origin of the test case. + +<hr> +\section cmdthrow \\throw <exception-object> { exception description } + + \addindex \\throw + Synonymous to \\exception (see section \ref cmdexception "\\exception"). + + \par Note: + the tag \\throws is a synonym for this tag. + + \sa section \ref cmdexception "\\exception" + +<hr> +\section cmdthrows \\throws <exception-object> { exception description } + + \addindex \\throws + Equivalent to \ref cmdthrow "\\throw". + +<hr> +\section cmdtodo \\todo { paragraph describing what is to be done } + + \addindex \\todo + Starts a paragraph where a TODO item is described. + The description will also add an item to a separate TODO list. + The two instances of the description will be cross-referenced. + Each item in the TODO list will be preceded by a header that + indicates the origin of the item. + +<hr> +\section cmdversion \\version { version number } + + \addindex \\version + Starts a paragraph where one or more version strings may be entered. + The paragraph will be indented. + The text of the paragraph has no special internal structure. All visual + enhancement commands may be used inside the paragraph. + Multiple adjacent \\version commands will be joined into a single paragraph. + Each version description will start on a new line. + Alternatively, one \\version command may mention + several version strings. + The \\version command ends when a blank line or some other + sectioning command is encountered. + See section \ref cmdauthor "\\author" for an example. + +<hr> +\section cmdwarning \\warning { warning message } + + \addindex \\warning + Starts a paragraph where one or more warning messages may be entered. + The paragraph will be indented. + The text of the paragraph has no special internal structure. All visual + enhancement commands may be used inside the paragraph. + Multiple adjacent \\warning commands will be joined into a single paragraph. + Each warning description will start on a new line. + Alternatively, one \\warning command may mention + several warnings. The \\warning command ends when a blank line or some other + sectioning command is encountered. See section \ref cmdauthor "\\author" + for an example. + +<hr> +\section cmdxrefitem \\xrefitem <key> "(heading)" "(list title)" { text } + + \addindex \\xrefitem + This command is a generalization of commands such as \ref cmdtodo "\\todo" + and \ref cmdbug "\\bug". + It can be used to create user-defined text sections which are automatically + cross-referenced between the place of occurrence and a related page, + which will be generated. On the related page all sections of + the same type will be collected. + + The first argument \<key\> is an + identifier uniquely representing the type of the section. The second argument + is a quoted string representing the heading of the section under which + text passed as the fourth argument is put. The third argument (list title) + is used as the title for the related page containing all items with the + same key. The keys "todo", "test", "bug" and "deprecated" are predefined. + + To get an idea on how to use the \\xrefitem command and what its effect + is, consider the todo list, which (for English output) can be seen an + alias for the command + \verbatim \xrefitem todo "Todo" "Todo List" \endverbatim + + Since it is very tedious and error-prone to repeat the first three + parameters of the command for each section, the command is meant to + be used in combination with the \ref cfg_aliases "ALIASES" option in the + configuration file. + To define a new command \\reminder, for instance, one should add the following + line to the configuration file: + \verbatim ALIASES += "reminder=\xrefitem reminders \"Reminder\" \"Reminders\"" \endverbatim + Note the use of escaped quotes for the second and third argument of the + \\xrefitem command. + +<hr> + +\htmlonly <center> \endhtmlonly +<h2> +\htmlonly --- \endhtmlonly +Commands to create links +\htmlonly --- \endhtmlonly +</h2> +\htmlonly </center>\endhtmlonly + +<hr> +\section cmdaddindex \\addindex (text) + + \addindex \\addindex + This command adds (text) to the \f$\mbox{\LaTeX}\f$ index. + +<hr> +\section cmdanchor \\anchor <word> + + \addindex \\anchor + This command places an invisible, named anchor into the documentation + to which you can refer with the \\ref command. + + \note Anchors can currently only be put into a comment block + that is marked as a page (using \ref cmdpage "\\page") or mainpage + (\ref cmdmainpage "\\mainpage"). + + \sa section \ref cmdref "\\ref". + +<hr> +\section cmdcite \\cite <label> + + \addindex \\cite + Adds a bibliographic reference in the text and in the list of bibliographic + references. The \<label\> must be a valid BibTeX label that can be found + in one of the .bib files listed in \ref cfg_cite_bib_files "CITE_BIB_FILES". + For the LaTeX output the formatting of the reference in the text can be + configured with \ref cfg_latex_bib_style "LATEX_BIB_STYLE". For other + output formats a fixed representation is used. Note that using this + command requires the \c bibtex tool to be present in the search path. + +<hr> +\section cmdendlink \\endlink + + \addindex \\endlink + This command ends a link that is started with the \\link command. + + \sa section \ref cmdlink "\\link". + +<hr> +\section cmdlink \\link <link-object> + + \addindex \\link + The links that are automatically generated by doxygen always have the + name of the object they point to as link-text. + + The \\link command can be used to create a link to an object (a file, + class, or member) with a user specified link-text. + The link command should end with an \\endlink command. All text between + the \\link and \\endlink commands serves as text for a link to + the \<link-object\> specified as the first argument of \\link. + + See section \ref autolink "autolink" for more information on automatically + generated links and valid link-objects. + +<hr> +\section cmdref \\ref <name> ["(text)"] + + \addindex \\ref + Creates a reference to a named section, subsection, page or anchor. + For HTML documentation the reference command will generate a link to + the section. For a section or subsection the title of the section will be + used as the text of the link. For an anchor the optional text between quotes + will be used or \<name\> if no text is specified. + For \f$\mbox{\LaTeX}\f$ documentation the reference command will + generate a section number for sections or the text followed by a + page number if \<name\> refers to an anchor. + + \sa + Section \ref cmdpage "\\page" for an example of the \\ref command. + +<hr> +\section cmdsubpage \\subpage <name> ["(text)"] + + \addindex \\subpage + This command can be used to create a hierarchy of pages. The + same structure can be made using the \ref cmddefgroup "\\defgroup" and + \ref cmdingroup "\\ingroup" commands, but for pages the \\subpage command + is often more convenient. The main page (see \ref cmdmainpage "\\mainpage") + is typically the root of hierarchy. + + This command behaves similar as \ref cmdref "\\ref" in the sense that + it creates a reference to a page labeled \<name\> with the optional + link text as specified in the second argument. + + It differs from the \\ref command in that it only works for pages, + and creates a parent-child relation between pages, where the + child page (or sub page) is identified by label \<name\>. + + See the \ref cmdsection "\\section" + and \ref cmdsubsection "\\subsection" commands if you want to add structure + without creating multiple pages. + + \note Each page can be the sub page of only one other page and + no cyclic relations are allowed, i.e. the page hierarchy must have a tree + structure. + + Here is an example: +\verbatim +/*! \mainpage A simple manual + +Some general info. + +This manual is divided in the following sections: +- \subpage intro +- \subpage advanced "Advanced usage" +*/ + +//----------------------------------------------------------- + +/*! \page intro Introduction +This page introduces the user to the topic. +Now you can proceed to the \ref advanced "advanced section". +*/ + +//----------------------------------------------------------- + +/*! \page advanced Advanced Usage +This page is for advanced users. +Make sure you have first read \ref intro "the introduction". +*/ +\endverbatim + +<hr> +\section cmdtableofcontents \\tableofcontents + + \addindex \\tableofcontents + Creates a table of contents at the top of a page, listing all + sections and subsections in the page. + + \warning This command only works inside related page documentation and + \e not in other documentation blocks and only has effect in the + HTML output! + +<hr> +\section cmdsection \\section <section-name> (section title) + + \addindex \\section + Creates a section with name \<section-name\>. The title of the + section should be specified as the second argument of the \\section + command. + + \warning This command only works inside related page documentation and + \e not in other documentation blocks! + + \sa + Section \ref cmdpage "\\page" for an example of the + \ref cmdsection "\\section" command. + +<hr> +\section cmdsubsection \\subsection <subsection-name> (subsection title) + + \addindex \\subsection + Creates a subsection with name \<subsection-name\>. The title of the + subsection should be specified as the second argument of the \\subsection + command. + + \warning This command only works inside a section of a related page + documentation block and + \e not in other documentation blocks! + + \sa + Section \ref cmdpage "\\page" for an example of the + \ref cmdsubsection "\\subsection" command. + +<hr> +\section cmdsubsubsection \\subsubsection <subsubsection-name> (subsubsection title) + + \addindex \\subsubsection + Creates a subsubsection with name \<subsubsection-name\>. The title of the + subsubsection should be specified as the second argument of the + \\subsubsection command. + + \warning This command only works inside a subsection of a + related page documentation block and + \e not in other documentation blocks! + + \sa + Section \ref cmdpage "\\page" for an example of the + \ref cmdsection "\\section" command and + \ref cmdsubsection "\\subsection" command. + +<hr> +\section cmdparagraph \\paragraph <paragraph-name> (paragraph title) + + \addindex \\paragraph + Creates a named paragraph with name \<paragraph-name\>. The title of the + paragraph should be specified as the second argument of the + \\paragraph command. + + \warning This command only works inside a subsubsection of a + related page documentation block and + \e not in other documentation blocks! + +<hr> + +\htmlonly <center> \endhtmlonly +<h2> +\htmlonly --- \endhtmlonly +Commands for displaying examples +\htmlonly --- \endhtmlonly +</h2> +\htmlonly </center>\endhtmlonly + +<hr> +\section cmddontinclude \\dontinclude <file-name> + + \addindex \\dontinclude + This command can be used to parse a source file without actually + verbatim including it in the documentation (as the \\include command does). + This is useful if you want to divide the source file into smaller pieces and + add documentation between the pieces. + Source files or directories can be specified using the + \ref cfg_example_path "EXAMPLE_PATH" + tag of doxygen's configuration file. + + The class and member declarations and definitions inside the code fragment + are 'remembered' during the parsing of the comment block that contained + the \\dontinclude command. + + For line by line descriptions of source files, one or more lines + of the example can be displayed using the \\line, \\skip, \\skipline, and + \\until commands. An internal pointer is used for these commands. The + \\dontinclude command sets the pointer to the first line of the example. + + \par Example: + \verbinclude include.cpp + Where the example file \c example_test.cpp looks as follows: + \verbinclude example_test.cpp + \htmlonly + Click <a href="$(DOXYGEN_DOCDIR)/examples/include/html/example.html">here</a> + for the corresponding HTML documentation that is generated by doxygen. + \endhtmlonly + + Alternatively, the \ref cmdsnippet "\\snippet" command can be used to + include only a fragment of a source file. For this to work the + fragment has to be marked. + + \sa sections \ref cmdline "\\line", \ref cmdskip "\\skip", + \ref cmdskipline "\\skipline", \ref cmduntil "\\until", and + \ref cmdinclude "\\include". + +<hr> +\section cmdinclude \\include <file-name> + + \addindex \\include + This command can be used to include a source file as a block of code. + The command takes the name of an include file as an argument. + Source files or directories can be specified using the + \ref cfg_example_path "EXAMPLE_PATH" + tag of doxygen's configuration file. + + If \<file-name\> itself is not unique for the set of example files specified + by the \ref cfg_example_path "EXAMPLE_PATH" tag, you can include part + of the absolute path to disambiguate it. + + Using the \\include command is equivalent to inserting the file into + the documentation block and surrounding it + with \ref cmdcode "\\code" and \ref cmdendcode "\\endcode" commands. + + The main purpose of the \\include command is to avoid code + duplication in case of example blocks that consist of multiple + source and header files. + + For a line by line description of a source files use the + \ref cmddontinclude "\\dontinclude" command in combination with + the \ref cmdline "\\line", \ref cmdskip "\\skip", + \ref cmdskipline "\\skipline", + and \\until commands. + + Alternatively, the \ref cmdsnippet "\\snippet" command can be used to + include only a fragment of a source file. For this to work the + fragment has to be marked. + + \note Doxygen's special commands do not work inside blocks of code. + It is allowed to nest C-style comments inside a code block though. + + \sa sections \ref cmdexample "\\example", \ref cmddontinclude "\\dontinclude", and + \ref cmdverbatim "\\verbatim". + +<hr> +\section cmdincludelineno \\includelineno <file-name> + + \addindex \\includelineno + This command works the same way as \\include, but will add line + numbers to the included file. + + \sa section \ref cmdinclude "\\include". + +<hr> +\section cmdline \\line ( pattern ) + + \addindex \\line + This command searches line by line through the example that was last + included using \\include or \\dontinclude until it finds a non-blank + line. If that line contains the specified pattern, it is written + to the output. + + The internal pointer that is used to keep track of the current line in + the example, is set to the start of the line following the non-blank + line that was found (or to the end of the example if no such line could + be found). + + See section \ref cmddontinclude "\\dontinclude" for an example. + +<hr> +\section cmdskip \\skip ( pattern ) + + \addindex \\skip + This command searches line by line through the example that was last + included using \\include or \\dontinclude until it finds a line that contains + the specified pattern. + + The internal pointer that is used to keep track of the current line in + the example, is set to the start of the line that contains the specified + pattern (or to the end of the example if the pattern could not be found). + + See section \ref cmddontinclude "\\dontinclude" for an example. + +<hr> +\section cmdskipline \\skipline ( pattern ) + + \addindex \\skipline + This command searches line by line through the example that was last + included using \\include or \\dontinclude until it finds a line that contains + the specified pattern. It then writes the line to the output. + + The internal pointer that is used to keep track of the current line in + the example, is set to the start of the line following the line that is + written (or to the end of the example if the pattern could not be found). + + \par Note: + The command: + \verbatim\skipline pattern\endverbatim + is equivalent to: +\verbatim +\skip pattern +\line pattern\endverbatim + + See section \ref cmddontinclude "\\dontinclude" for an example. + +<hr> +\section cmdsnippet \\snippet <file-name> ( block_id ) + + \addindex \\snippet + Where the \ref cmdinclude "\\include" command can be used to include + a complete file as source code, this command can be used to quote only + a fragment of a source file. + + For example, the putting the following command in the documentation, + references a snippet in file \c example.cpp residing in a subdirectory + which should be pointed to by \ref cfg_example_path "EXAMPLE_PATH". + +\verbatim + \snippet snippets/example.cpp Adding a resource +\endverbatim + + The text following the file name is the unique identifier for the snippet. + This is used to delimit the quoted code in the relevant snippet file as + shown in the following example that corresponds to the above \\snippet + command: + +\code + QImage image(64, 64, QImage::Format_RGB32); + image.fill(qRgb(255, 160, 128)); + +//! [Adding a resource] + document->addResource(QTextDocument::ImageResource, + QUrl("mydata://image.png"), QVariant(image)); +//! [Adding a resource] + ... +\endcode + + Note that the lines containing the block markers will not be included, + so the output will be: + +\code + document->addResource(QTextDocument::ImageResource, + QUrl("mydata://image.png"), QVariant(image)); +\endcode + + Note also that the [block_id] markers should appear exactly twice in the + source file. + + see section \ref cmddontinclude "\\dontinclude" for an alternative way + to include fragments of a source file that does not require markers. + +<hr> +\section cmduntil \\until ( pattern ) + + \addindex \\until + This command writes all lines of the example that was last + included using \\include or \\dontinclude to the output, until it finds + a line containing the specified pattern. The line containing the pattern + will be written as well. + + The internal pointer that is used to keep track of the current line in + the example, is set to the start of the line following last written + line (or to the end of the example if the pattern could not be found). + + See section \ref cmddontinclude "\\dontinclude" for an example. + +<hr> +\section cmdverbinclude \\verbinclude <file-name> + + \addindex \\verbinclude + This command includes the file \<file-name\> verbatim in the documentation. + The command is equivalent to pasting the file in the documentation and + placing \\verbatim and \\endverbatim commands around it. + + Files or directories that doxygen should look for can be specified using the + \ref cfg_example_path "EXAMPLE_PATH" tag of doxygen's configuration file. + +<hr> +\section cmdhtmlinclude \\htmlinclude <file-name> + + \addindex \\htmlinclude + This command includes the file \<file-name\> as is in the HTML documentation. + The command is equivalent to pasting the file in the documentation and + placing \\htmlonly and \\endhtmlonly commands around it. + + Files or directories that doxygen should look for can be specified using the + \ref cfg_example_path "EXAMPLE_PATH" tag of doxygen's configuration file. + +<hr> + +\htmlonly <center> \endhtmlonly +<h2> +\htmlonly --- \endhtmlonly +Commands for visual enhancements +\htmlonly --- \endhtmlonly +</h2> +\htmlonly </center>\endhtmlonly + +\section cmda \\a <word> + + \addindex \\a + Displays the argument \<word\> in italics. + Use this command to emphasize words. + Use this command to refer to member arguments in the running text. + + \par Example: + \verbatim + ... the \a x and \a y coordinates are used to ... + \endverbatim + This will result in the following text:<br><br> + ... the \a x and \a y coordinates are used to ... + + Equivalent to \ref cmda "\\e" and \ref cmdem "\\em". + To emphasize multiple words use \<em\>multiple words\</em\>. + +<hr> +\section cmdarg \\arg { item-description } + + \addindex \\arg + This command has one argument that continues until the first + blank line or until another \\arg is encountered. + The command can be used to generate a simple, not nested list of + arguments. + Each argument should start with a \\arg command. + + \par Example: + Typing: + \verbatim + \arg \c AlignLeft left alignment. + \arg \c AlignCenter center alignment. + \arg \c AlignRight right alignment + + No other types of alignment are supported. + \endverbatim + will result in the following text:<br><br> + <ul> + <li> \c AlignLeft left alignment. + <li> \c AlignCenter center alignment. + <li> \c AlignRight right alignment + </ul><br> + No other types of alignment are supported. + + \par Note: + For nested lists, HTML commands should be used. + + Equivalent to \ref cmdli "\\li" + + +<hr> +\section cmdb \\b <word> + + \addindex \\b + Displays the argument \<word\> using a bold font. + Equivalent to \<b\>word\</b\>. + To put multiple words in bold use \<b\>multiple words\</b\>. + +<hr> +\section cmdc \\c <word> + + \addindex \\c + Displays the argument \<word\> using a typewriter font. + Use this to refer to a word of code. + Equivalent to \<tt\>word\</tt\>. + + \par Example: + Typing: + \verbatim + ... This function returns \c void and not \c int ... + \endverbatim + will result in the following text:<br><br> + ... This function returns \c void and not \c int ... + + Equivalent to \ref cmdp "\\p" + To have multiple words in typewriter font use \<tt\>multiple words\</tt\>. + +<hr> +\section cmdcode \\code [ '{'<word>'}'] + + \addindex \\code + Starts a block of code. A code block is treated differently + from ordinary text. It is interpreted as source code. The names of + classes and members and other documented entities are automatically + replaced by links to the documentation. + + By default the language that is assumed for syntax highlighting is based + on the location where the \\code block was found. If this part of + a Python file for instance, the syntax highlight will be done according + to the Python syntax. + + If it unclear from the context which language is meant (for instance the + comment is in a .txt or .markdown file) then you can also explicitly + indicate the language, by putting the file extension typically + that doxygen associated with the language in curly brackets after the + code block. Here is an example: + +\verbatim + \code{.py} + class Python: + pass + \endcode + + \code{.cpp} + class Cpp {}; + \endcode +\endverbatim + + \sa section \ref cmdendcode "\\endcode" and section \ref cmdverbatim "\\verbatim". + +<hr> +\section cmdcopydoc \\copydoc <link-object> + + \addindex \\copydoc + Copies a documentation block from the object specified by \<link-object\> + and pastes it at the location of the command. This command can be useful + to avoid cases where a documentation block would otherwise have to be + duplicated or it can be used to extend the documentation of an inherited + member. + + The link object can point to a member (of a class, file or group), + a class, a namespace, a group, a page, or a file (checked in that order). + Note that if the object pointed to is a member (function, variable, + typedef, etc), the compound (class, file, or group) containing it + should also be documented for the copying to work. + + To copy the documentation for a member of a + class one can, for instance, put the following in the documentation: + +\verbatim + /*! @copydoc MyClass::myfunction() + * More documentation. + */ +\endverbatim + + if the member is overloaded, you should specify the argument types + explicitly (without spaces!), like in the following: + +\verbatim + //! @copydoc MyClass::myfunction(type1,type2) +\endverbatim + + Qualified names are only needed if the context in which the documentation + block is found requires them. + + The \\copydoc command can be used recursively, but cycles in the \\copydoc + relation will be broken and flagged as an error. + + Note that <code>\\copydoc foo()</code> is roughly equivalent to doing: +\verbatim + \brief \copybrief foo() + \details \copydetails foo() +\endverbatim + See \ref cmdcopybrief "\\copybrief" and + \ref cmdcopydetails "\\copydetails" for copying only the brief or + detailed part of the comment block. + +<hr> +\section cmdcopybrief \\copybrief <link-object> + +Works in a similar way as \ref cmdcopydoc "\\copydoc" but will +only copy the brief description, not the detailed documentation. + +<hr> +\section cmdcopydetails \\copydetails <link-object> + +Works in a similar way as \ref cmdcopydoc "\\copydoc" but will +only copy the detailed documentation, not the brief description. + +<hr> +\section cmddot \\dot + + \addindex \\dot + Starts a text fragment which should contain a valid description of a + dot graph. The text fragment ends with \ref cmdenddot "\\enddot". + Doxygen will pass the text on to dot and include the resulting + image (and image map) into the output. + The nodes of a graph can be made clickable by using the URL attribute. + By using the command \\ref inside the URL value you can conveniently + link to an item inside doxygen. Here is an example: +\code +/*! class B */ +class B {}; + +/*! class C */ +class C {}; + +/*! \mainpage + * + * Class relations expressed via an inline dot graph: + * \dot + * digraph example { + * node [shape=record, fontname=Helvetica, fontsize=10]; + * b [ label="class B" URL="\ref B"]; + * c [ label="class C" URL="\ref C"]; + * b -> c [ arrowhead="open", style="dashed" ]; + * } + * \enddot + * Note that the classes in the above graph are clickable + * (in the HTML output). + */ +\endcode + +<hr> +\section cmdmsc \\msc + + \addindex \\msc + Starts a text fragment which should contain a valid description of a + message sequence chart. See http://www.mcternan.me.uk/mscgen/ for examples. + The text fragment ends with \ref cmdendmsc "\\endmsc". + \note The text fragment should only include the part of the message + sequence chart that is + within the <code>msc {...}</code> block. + \note You need to install the <code>mscgen</code> tool, if you want to use this + command. + +Here is an example of the use of the \\msc command. +\code +/** Sender class. Can be used to send a command to the server. + * The receiver will acknowledge the command by calling Ack(). + * \msc + * Sender,Receiver; + * Sender->Receiver [label="Command()", URL="\ref Receiver::Command()"]; + * Sender<-Receiver [label="Ack()", URL="\ref Ack()", ID="1"]; + * \endmsc + */ +class Sender +{ + public: + /** Acknowledgement from server */ + void Ack(bool ok); +}; + +/** Receiver class. Can be used to receive and execute commands. + * After execution of a command, the receiver will send an acknowledgement + * \msc + * Receiver,Sender; + * Receiver<-Sender [label="Command()", URL="\ref Command()"]; + * Receiver->Sender [label="Ack()", URL="\ref Sender::Ack()", ID="1"]; + * \endmsc + */ +class Receiver +{ + public: + /** Executable a command on the server */ + void Command(int commandId); +}; + +\endcode + + \sa section \ref cmdmscfile "\\mscfile". + +<hr> +\section cmddotfile \\dotfile <file> ["caption"] + + \addindex \\dotfile + Inserts an image generated by dot from \<file\> into the documentation. + + The first argument specifies the file name of the image. + doxygen will look for files in the paths (or files) that you specified + after the \ref cfg_dotfile_dirs "DOTFILE_DIRS" tag. + If the dot file is found it will be used as an input file to the dot tool. + The resulting image will be put into the correct output directory. + If the dot file name contains spaces you'll have to put quotes ("...") around it. + + The second argument is optional and can be used to specify the caption + that is displayed below the image. This argument has to be specified + between quotes even if it does not contain any spaces. The quotes are + stripped before the caption is displayed. + +<hr> +\section cmdmscfile \\mscfile <file> ["caption"] + + \addindex \\mscfile + Inserts an image generated by mscgen from \<file\> into the documentation. + See http://www.mcternan.me.uk/mscgen/ for examples. + + The first argument specifies the file name of the image. + doxygen will look for files in the paths (or files) that you specified + after the \ref cfg_mscfile_dirs "MSCFILE_DIRS" tag. + If the msc file is found it will be used as an input file to the mscgen tool. + The resulting image will be put into the correct output directory. + If the msc file name contains spaces you'll have to put quotes ("...") around it. + + The second argument is optional and can be used to specify the caption + that is displayed below the image. This argument has to be specified + between quotes even if it does not contain any spaces. The quotes are + stripped before the caption is displayed. + + \sa section \ref cmdmsc "\\msc". + +<hr> +\section cmde \\e <word> + + \addindex \\e + Displays the argument \<word\> in italics. + Use this command to emphasize words. + + \par Example: + Typing: + \verbatim + ... this is a \e really good example ... + \endverbatim + will result in the following text:<br><br> + ... this is a \e really good example ... + + Equivalent to \ref cmda "\\a" and \ref cmdem "\\em". + To emphasize multiple words use \<em\>multiple words\</em\>. + +<hr> +\section cmdem \\em <word> + + \addindex \\em + Displays the argument \<word\> in italics. + Use this command to emphasize words. + + \par Example: + Typing: + \verbatim + ... this is a \em really good example ... + \endverbatim + will result in the following text:<br><br> + ... this is a \em really good example ... + + Equivalent to \ref cmda "\\a" and \ref cmde "\\e". + To emphasize multiple words use \<em\>multiple words\</em\>. + +<hr> +\section cmdendcode \\endcode + + \addindex \\endcode + Ends a block of code. + \sa section \ref cmdcode "\\code" + +<hr> +\section cmdenddot \\enddot + + \addindex \\enddot + Ends a blocks that was started with \ref cmddot "\\dot". + +<hr> +\section cmdendmsc \\endmsc + + \addindex \\endmsc + Ends a blocks that was started with \ref cmdmsc "\\msc". + +<hr> +\section cmdendhtmlonly \\endhtmlonly + + \addindex \\endhtmlonly + Ends a block of text that was started with a \\htmlonly command. + + \sa section \ref cmdhtmlonly "\\htmlonly". + +<hr> +\section cmdendlatexonly \\endlatexonly + + \addindex \\endlatexonly + Ends a block of text that was started with a \\latexonly command. + + \sa section \ref cmdlatexonly "\\latexonly". + +<hr> +\section cmdendmanonly \\endmanonly + + \addindex \\endmanonly + Ends a block of text that was started with a \\manonly command. + + \sa section \ref cmdmanonly "\\manonly". + +<hr> +\section cmdendrtfonly \\endrtfonly + + \addindex \\endrtfonly + Ends a block of text that was started with a \\rtfonly command. + + \sa section \ref cmdrtfonly "\\rtfonly". + + +<hr> +\section cmdendverbatim \\endverbatim + + \addindex \\endverbatim + Ends a block of text that was started with a \\verbatim command. + + \sa section \ref cmdverbatim "\\verbatim". + +<hr> +\section cmdendxmlonly \\endxmlonly + + \addindex \\endxmlonly + Ends a block of text that was started with a \\xmlonly command. + + \sa section \ref cmdxmlonly "\\xmlonly". + +<hr> +\section cmdfdollar \\f$ + + \addindex \\f\$ + + Marks the start and end of an in-text formula. + \sa section \ref formulas "formulas" for an example. + +<hr> +\section cmdfbropen \\f[ + + \addindex \\f[ + + Marks the start of a long formula that is displayed + centered on a separate line. + \sa section \ref cmdfbrclose "\\f]" and section \ref formulas "formulas". + +<hr> +\section cmdfbrclose \\f] + + \addindex \\f] + + Marks the end of a long formula that is displayed + centered on a separate line. + \sa section \ref cmdfbropen "\\f[" and section \ref formulas "formulas". + +<hr> +\section cmdfcurlyopen \\f{environment}{ + + Marks the start of a formula that is in a specific environment. + \note The second { is optional and is only to help editors (such as Vim) to + do proper syntax highlighting by making the number of opening and closing braces + the same. + \sa section \ref cmdfcurlyclose "\\f}" and section \ref formulas "formulas". + +<hr> +\section cmdfcurlyclose \\f} + + Marks the end of a formula that is in a specific environment. + \sa section \ref cmdfcurlyopen "\\f{" and section \ref formulas "formulas". + +<hr> +\section cmdhtmlonly \\htmlonly + + \addindex \\htmlonly + Starts a block of text that will be verbatim included in the + generated HTML documentation only. The block ends with a + \ref cmdhtmlonly "\\endhtmlonly" command. + + This command can be used to include HTML code that is too complex + for doxygen (i.e. applets, java-scripts, and HTML tags that + require attributes). You can use the \\latexonly and \\endlatexonly + pair to provide a proper \f$\mbox{\LaTeX}\f$ alternative. + + \note environment variables (like \$(HOME) ) are resolved inside a + HTML-only block. + + \sa section \ref cmdmanonly "\\manonly", section + \ref cmdlatexonly "\\latexonly", and section + \ref cmdrtfonly "\\rtfonly". + +<hr> +\section cmdimage \\image <format> <file> ["caption"] [<sizeindication>=<size>] + + \addindex \\image + Inserts an image into the documentation. This command is format + specific, so if you want to insert an image for more than one + format you'll have to repeat this command for each format. + + The first argument specifies the output format. Currently, the + following values are supported: \c html, \c latex and \c rtf. + + The second argument specifies the file name of the image. + doxygen will look for files in the paths (or files) that you specified + after the \ref cfg_image_path "IMAGE_PATH" tag. + If the image is found it will be copied to the correct output directory. + If the image name contains spaces you'll have to put quotes ("...") around it. + You can also specify an absolute URL instead of a file name, but then + doxygen does not copy the image nor check its existence. + + The third argument is optional and can be used to specify the caption + that is displayed below the image. This argument has to be specified + on a single line and between quotes even if it does not contain any + spaces. The quotes are stripped before the caption is displayed. + + The fourth argument is also optional and can be used to specify the + width or height of the image. This is only useful + for \f$\mbox{\LaTeX}\f$ output + (i.e. format=<code>latex</code>). The \c sizeindication can be + either \c width or \c height. The size should be a valid + size specifier in \f$\mbox{\LaTeX}\f$ (for example <code>10cm</code> or + <code>6in</code> or a symbolic width like <code>\\textwidth</code>). + + Here is example of a comment block: + +\verbatim + /*! Here is a snapshot of my new application: + * \image html application.jpg + * \image latex application.eps "My application" width=10cm + */ +\endverbatim + + And this is an example of how the relevant part of the configuration file + may look: + +\verbatim + IMAGE_PATH = my_image_dir +\endverbatim + + \warning The image format for HTML is limited to what your + browser supports. For \f$\mbox{\LaTeX}\f$, the image format + must be Encapsulated PostScript (eps). + <br><br> + Doxygen does not check if the image is in the correct format. + So \e you have to make sure this is the case! + +<hr> +\section cmdlatexonly \\latexonly + + \addindex \\latexonly + Starts a block of text that will be verbatim included in the + generated \f$\mbox{\LaTeX}\f$ documentation only. The block ends with a + \ref cmdendlatexonly "\\endlatexonly" command. + + This command can be used to include \f$\mbox{\LaTeX}\f$ code that is too + complex for doxygen (i.e. images, formulas, special characters). You can + use the \\htmlonly and \\endhtmlonly pair to provide a proper HTML + alternative. + + \b Note: + environment variables (like \$(HOME) ) are resolved inside a + \f$\mbox{\LaTeX}\f$-only block. + + \sa section \ref cmdrtfonly "\\rtfonly", + section \ref cmdxmlonly "\\xmlonly", + section \ref cmdmanonly "\\manonly", and + section \ref cmdhtmlonly "\\htmlonly". + +<hr> +\section cmdmanonly \\manonly + + \addindex \\manonly + Starts a block of text that will be verbatim included in the + generated MAN documentation only. The block ends with a + \ref cmdendmanonly "\\endmanonly" command. + + This command can be used to include groff code directly into + MAN pages. You can use the \\htmlonly and \\latexonly and + \\endhtmlonly and \\endlatexonly pairs to provide proper + HTML and \f$\mbox{\LaTeX}\f$ alternatives. + + \sa section \ref cmdhtmlonly "\\htmlonly", + section \ref cmdxmlonly "\\xmlonly", + section \ref cmdrtfonly "\\rtfonly", and + section \ref cmdlatexonly "\\latexonly". + +<hr> +\section cmdli \\li { item-description } + + \addindex \\li + This command has one argument that continues until the first + blank line or until another \\li is encountered. + The command can be used to generate a simple, not nested list of + arguments. + Each argument should start with a \\li command. + + \par Example: + Typing: + \verbatim + \li \c AlignLeft left alignment. + \li \c AlignCenter center alignment. + \li \c AlignRight right alignment + + No other types of alignment are supported. + \endverbatim + will result in the following text:<br><br> + <ul> + <li> \c AlignLeft left alignment. + <li> \c AlignCenter center alignment. + <li> \c AlignRight right alignment + </ul><br> + No other types of alignment are supported. + + \par Note: + For nested lists, HTML commands should be used. + + Equivalent to \ref cmdarg "\\arg" + +<hr> +\section cmdn \\n + + \addindex \\n + Forces a new line. Equivalent to \<br\> and inspired by + the printf function. + +<hr> +\section cmdp \\p <word> + + \addindex \\p + Displays the parameter \<word\> using a typewriter font. + You can use this command to refer to member function parameters in + the running text. + + \par Example: + \verbatim + ... the \p x and \p y coordinates are used to ... + \endverbatim + This will result in the following text:<br><br> + ... the \p x and \p y coordinates are used to ... + + Equivalent to \ref cmdc "\\c" + To have multiple words in typewriter font use \<tt\>multiple words\</tt\>. + +<hr> +\section cmdrtfonly \\rtfonly + + \addindex \\rtfonly + Starts a block of text that will be verbatim included in the + generated RTF documentation only. The block ends with a + \ref cmdendrtfonly "\\endrtfonly" command. + + This command can be used to include RTF code that is too complex + for doxygen. + + \b Note: + environment variables (like \$(HOME) ) are resolved inside a + RTF-only block. + + \sa section \ref cmdmanonly "\\manonly", section + \ref cmdxmlonly "\\xmlonly", section + \ref cmdlatexonly "\\latexonly", and section + \ref cmdhtmlonly "\\htmlonly". + +<hr> +\section cmdverbatim \\verbatim + + \addindex \\verbatim + Starts a block of text that will be verbatim included in + the documentation. The block should end with a + \ref cmdendverbatim "\\endverbatim" block. + All commands are disabled in a verbatim block. + + \warning Make sure you include a \\endverbatim command for each + \\verbatim command or the parser will get confused! + + \sa section \ref cmdcode "\\code", and + section \ref cmdverbinclude "\\verbinclude". + +<hr> +\section cmdxmlonly \\xmlonly + + \addindex \\xmlonly + Starts a block of text that will be verbatim included in the + generated XML output only. The block ends with a + endxmlonly command. + + This command can be used to include custom XML tags. + + \sa section \ref cmdmanonly "\\manonly", section + \ref cmdrtfonly "\\rtfonly", section + \ref cmdlatexonly "\\latexonly", and section + \ref cmdhtmlonly "\\htmlonly". + +<hr> +\section cmdbackslash \\\\ + + \addindex \\\\ + This command writes a backslash character (\\) to the + output. The backslash has to be escaped in some + cases because doxygen uses it to detect commands. + +<hr> +\section cmdat \\\@ + + \addindex \\\@ + This command writes an at-sign (\@) to the output. + The at-sign has to be escaped in some cases + because doxygen uses it to detect JavaDoc commands. + +<hr> +\section cmdtilde \\~[LanguageId] + \addindex \\~ + This command enables/disables a language specific filter. This can be + used to put documentation for different language into one comment block + and use the \c OUTPUT_LANGUAGE tag to filter out only a specific language. + Use \\~language_id to enable output for a specific language only and + \\~ to enable output for all languages (this is also the default mode). + + Example: +\verbatim +/*! \~english This is english \~dutch Dit is Nederlands \~german Dieses ist + deutsch. \~ output for all languages. + */ +\endverbatim + + +<hr> +\section cmdamp \\\& + + \addindex \\\& + This command writes the \& character to output. + This character has to be escaped because it has a special meaning in HTML. + +<hr> +\section cmddollar \\\$ + + \addindex \\\$ + This command writes the \$ character to the output. + This character has to be escaped in some cases, because it is used to expand + environment variables. + +<hr> +\section cmdhash \\\# + + \addindex \\\# + This command writes the \# character to the output. This + character has to be escaped in some cases, because it is used to refer + to documented entities. + +<hr> +\section cmdlt \\\< + + \addindex \\\< + This command writes the \< character to the output. + This character has to be escaped because it has a special meaning in HTML. + +<hr> +\section cmdgt \\\> + + \addindex \\\> + This command writes the \> character to the output. This + character has to be escaped because it has a special meaning in HTML. + +<hr> +\section cmdperc \\\% + + \addindex \\\% + This command writes the \% character to the output. This + character has to be escaped in some cases, because it is used to + prevent auto-linking to word that is also a documented class or struct. + +<hr> +\section cmdquot \\" + + \addindex \\\" + This command writes the \" character to the output. This + character has to be escaped in some cases, because it is used in pairs + to indicate an unformatted text fragment. + +<hr> +\section cmdchardot \\. + + \addindex \\\. + This command writes a dot to the output. This can be useful to + prevent ending a brief description when JAVADOC_AUTOBRIEF is enabled + or to prevent starting a numbered list when the dot follows a number at + the start of a line. + +<hr> +\section cmddcolon \\:: + + \addindex \\\:: + This command write a double colon (\::) to the output. This + character sequence has to be escaped in some cases, because it is used + to ref to documented entities. + +<hr> +\htmlonly <center> \endhtmlonly +<h2> +\htmlonly --- \endhtmlonly +Commands included for Qt compatibility +\htmlonly --- \endhtmlonly +</h2> +\htmlonly </center>\endhtmlonly + +The following commands are supported to remain compatible to the Qt class +browser generator. Do \e not use these commands in your own documentation. +<ul> +<li>\\annotatedclasslist +<li>\\classhierarchy +<li>\\define +<li>\\functionindex +<li>\\header +<li>\\headerfilelist +<li>\\inherit +<li>\\l +<li>\\postheader +</ul> +<hr> + +*/ + diff --git a/trunk/doc/config.doc b/trunk/doc/config.doc new file mode 100644 index 0000000..c84b19f --- /dev/null +++ b/trunk/doc/config.doc @@ -0,0 +1,2657 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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 config Configuration + +\tableofcontents +\section config_format Format + +A configuration file is a free-form ASCII text file with a structure +that is similar to that of a Makefile, with the 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. + +The file essentially consists of a list of assignment statements. +Each statement consists of a \c TAG_NAME written in capitals, +followed by the <code>=</code> character and one or more values. If the same tag +is assigned more than once, the last assignment overwrites any earlier +assignment. For options that take a list as their argument, +the <code>+=</code> operator can be used instead of <code>=</code> to append +new values to the list. Values are sequences of non-blanks. If the value should +contain one or more blanks it must be surrounded by quotes ("..."). +Multiple lines can be concatenated by inserting a backslash (\\) +as the last character of a line. Environment variables can be expanded +using the pattern <code>\$(ENV_VARIABLE_NAME)</code>. + +You can also include part of a configuration file from another configuration +file using a <code>\@INCLUDE</code> tag as follows: +\verbatim +@INCLUDE = config_file_name +\endverbatim +The include file is searched in the current working directory. You can +also specify a list of directories that should be searched before looking +in the current working directory. Do this by putting a <code>\@INCLUDE_PATH</code> tag +with these paths before the <code>\@INCLUDE</code> tag, e.g.: +\verbatim +@INCLUDE_PATH = my_config_dir +\endverbatim + +The configuration options can be divided into several categories. +Below is an alphabetical index of the tags that are recognized +followed by the descriptions of the tags grouped by category. + +\secreflist +\refitem cfg_abbreviate_brief ABBREVIATE_BRIEF +\refitem cfg_aliases ALIASES +\refitem cfg_allexternals ALLEXTERNALS +\refitem cfg_alphabetical_index ALPHABETICAL_INDEX +\refitem cfg_always_detailed_sec ALWAYS_DETAILED_SEC +\refitem cfg_binary_toc BINARY_TOC +\refitem cfg_brief_member_desc BRIEF_MEMBER_DESC +\refitem cfg_builtin_stl_support BUILTIN_STL_SUPPORT +\refitem cfg_call_graph CALL_GRAPH +\refitem cfg_caller_graph CALLER_GRAPH +\refitem cfg_case_sense_names CASE_SENSE_NAMES +\refitem cfg_chm_file CHM_FILE +\refitem cfg_chm_index_encoding CHM_INDEX_ENCODING +\refitem cfg_cite_bib_files CITE_BIB_FILES +\refitem cfg_class_diagrams CLASS_DIAGRAMS +\refitem cfg_class_graph CLASS_GRAPH +\refitem cfg_collaboration_graph COLLABORATION_GRAPH +\refitem cfg_cols_in_alpha_index COLS_IN_ALPHA_INDEX +\refitem cfg_compact_latex COMPACT_LATEX +\refitem cfg_compact_rtf COMPACT_RTF +\refitem cfg_cpp_cli_support CPP_CLI_SUPPORT +\refitem cfg_create_subdirs CREATE_SUBDIRS +\refitem cfg_directory_graph DIRECTORY_GRAPH +\refitem cfg_disable_index DISABLE_INDEX +\refitem cfg_distribute_group_doc DISTRIBUTE_GROUP_DOC +\refitem cfg_docset_bundle_id DOCSET_BUNDLE_ID +\refitem cfg_docset_feedname DOCSET_FEEDNAME +\refitem cfg_docset_publisher_id DOCSET_PUBLISHER_ID +\refitem cfg_docset_publisher_name DOCSET_PUBLISHER_NAME +\refitem cfg_dot_cleanup DOT_CLEANUP +\refitem cfg_dot_fontname DOT_FONTNAME +\refitem cfg_dot_fontpath DOT_FONTPATH +\refitem cfg_dot_fontsize DOT_FONTSIZE +\refitem cfg_dot_graph_max_nodes DOT_GRAPH_MAX_NODES +\refitem cfg_dot_image_format DOT_IMAGE_FORMAT +\refitem cfg_dot_multi_targets DOT_MULTI_TARGETS +\refitem cfg_dot_num_threads DOT_NUM_THREADS +\refitem cfg_dot_path DOT_PATH +\refitem cfg_dot_transparent DOT_TRANSPARENT +\refitem cfg_dotfile_dirs DOTFILE_DIRS +\refitem cfg_doxyfile_encoding DOXYFILE_ENCODING +\refitem cfg_eclipse_doc_id ECLIPSE_DOC_ID +\refitem cfg_enable_preprocessing ENABLE_PREPROCESSING +\refitem cfg_enabled_sections ENABLED_SECTIONS +\refitem cfg_enum_values_per_line ENUM_VALUES_PER_LINE +\refitem cfg_example_path EXAMPLE_PATH +\refitem cfg_example_patterns EXAMPLE_PATTERNS +\refitem cfg_example_recursive EXAMPLE_RECURSIVE +\refitem cfg_exclude EXCLUDE +\refitem cfg_exclude_patterns EXCLUDE_PATTERNS +\refitem cfg_exclude_symbols EXCLUDE_SYMBOLS +\refitem cfg_exclude_symlinks EXCLUDE_SYMLINKS +\refitem cfg_expand_as_defined EXPAND_AS_DEFINED +\refitem cfg_expand_only_predef EXPAND_ONLY_PREDEF +\refitem cfg_ext_links_in_window EXT_LINKS_IN_WINDOW +\refitem cfg_extension_mapping EXTENSION_MAPPING +\refitem cfg_external_groups EXTERNAL_GROUPS +\refitem cfg_extra_packages EXTRA_PACKAGES +\refitem cfg_extract_all EXTRACT_ALL +\refitem cfg_extract_anon_nspaces EXTRACT_ANON_NSPACES +\refitem cfg_extract_local_classes EXTRACT_LOCAL_CLASSES +\refitem cfg_extract_local_methods EXTRACT_LOCAL_METHODS +\refitem cfg_extract_private EXTRACT_PRIVATE +\refitem cfg_extract_static EXTRACT_STATIC +\refitem cfg_file_patterns FILE_PATTERNS +\refitem cfg_file_version_filter FILE_VERSION_FILTER +\refitem cfg_filter_patterns FILTER_PATTERNS +\refitem cfg_filter_source_files FILTER_SOURCE_FILES +\refitem cfg_filter_source_patterns FILTER_SOURCE_PATTERNS +\refitem cfg_force_local_includes FORCE_LOCAL_INCLUDES +\refitem cfg_formula_fontsize FORMULA_FONTSIZE +\refitem cfg_formula_transparent FORMULA_TRANSPARENT +\refitem cfg_full_path_names FULL_PATH_NAMES +\refitem cfg_generate_autogen_def GENERATE_AUTOGEN_DEF +\refitem cfg_generate_buglist GENERATE_BUGLIST +\refitem cfg_generate_chi GENERATE_CHI +\refitem cfg_generate_deprecatedlist GENERATE_DEPRECIATEDLIST +\refitem cfg_generate_docset GENERATE_DOCSET +\refitem cfg_generate_eclipsehelp GENERATE_ECLIPSEHELP +\refitem cfg_generate_html GENERATE_HTML +\refitem cfg_generate_htmlhelp GENERATE_HTMLHELP +\refitem cfg_generate_latex GENERATE_LATEX +\refitem cfg_generate_legend GENERATE_LEGEND +\refitem cfg_generate_man GENERATE_MAN +\refitem cfg_generate_perlmod GENERATE_PERLMOD +\refitem cfg_generate_qhp GENERATE_QHP +\refitem cfg_generate_rtf GENERATE_RTF +\refitem cfg_generate_tagfile GENERATE_TAGFILE +\refitem cfg_generate_testlist GENERATE_TESTLIST +\refitem cfg_generate_todolist GENERATE_TODOLIST +\refitem cfg_generate_treeview GENERATE_TREEVIEW +\refitem cfg_generate_xml GENERATE_XML +\refitem cfg_graphical_hierarchy GRAPHICAL_HIERARCHY +\refitem cfg_group_graphs GROUP_GRAPHS +\refitem cfg_have_dot HAVE_DOT +\refitem cfg_hhc_location HHC_LOCATION +\refitem cfg_hide_friend_compounds HIDE_FRIEND_COMPOUNDS +\refitem cfg_hide_in_body_docs HIDE_IN_BODY_DOCS +\refitem cfg_hide_scope_names HIDE_SCOPE_NAMES +\refitem cfg_hide_undoc_classes HIDE_UNDOC_CLASSES +\refitem cfg_hide_undoc_members HIDE_UNDOC_MEMBERS +\refitem cfg_hide_undoc_relations HIDE_UNDOC_RELATIONS +\refitem cfg_html_align_members HTML_ALIGN_MEMBERS +\refitem cfg_html_colorstyle_gamma HTML_COLORSTYLE_GAMMA +\refitem cfg_html_colorstyle_hue HTML_COLORSTYLE_HUE +\refitem cfg_html_colorstyle_sat HTML_COLORSTYLE_SAT +\refitem cfg_html_dynamic_sections HTML_DYNAMIC_SECTIONS +\refitem cfg_html_extra_files HTML_EXTRA_FILES +\refitem cfg_html_file_extension HTML_FILE_EXTENSION +\refitem cfg_html_footer HTML_FOOTER +\refitem cfg_html_header HTML_HEADER +\refitem cfg_html_output HTML_OUTPUT +\refitem cfg_html_stylesheet HTML_STYLESHEET +\refitem cfg_html_timestamp HTML_TIMESTAMP +\refitem cfg_idl_property_support IDL_PROPERTY_SUPPORT +\refitem cfg_ignore_prefix IGNORE_PREFIX +\refitem cfg_image_path IMAGE_PATH +\refitem cfg_include_file_patterns INCLUDE_FILE_PATTERNS +\refitem cfg_include_graph INCLUDE_GRAPH +\refitem cfg_include_path INCLUDE_PATH +\refitem cfg_included_by_graph INCLUDED_BY_GRAPH +\refitem cfg_inherit_docs INHERIT_DOCS +\refitem cfg_inline_grouped_classes INLINE_GROUPED_CLASSES +\refitem cfg_inline_info INLINE_INFO +\refitem cfg_inline_inherited_memb INLINE_INHERITED_MEMB +\refitem cfg_inline_sources INLINE_SOURCES +\refitem cfg_input INPUT +\refitem cfg_input_encoding INPUT_ENCODING +\refitem cfg_input_filter INPUT_FILTER +\refitem cfg_interactive_svg INTERACTIVE_SVG +\refitem cfg_internal_docs INTERNAL_DOCS +\refitem cfg_javadoc_autobrief JAVADOC_AUTOBRIEF +\refitem cfg_latex_batchmode LATEX_BATCHMODE +\refitem cfg_latex_bib_style LATEX_BIB_STYLE +\refitem cfg_latex_cmd_name LATEX_CMD_NAME +\refitem cfg_latex_footer LATEX_FOOTER +\refitem cfg_latex_header LATEX_HEADER +\refitem cfg_latex_hide_indices LATEX_HIDE_INDICES +\refitem cfg_latex_output LATEX_OUTPUT +\refitem cfg_latex_source_code LATEX_SOURCE_CODE +\refitem cfg_layout_file LAYOUT_FILE +\refitem cfg_lookup_cache_size LOOKUP_CACHE_SIZE +\refitem cfg_macro_expansion MACRO_EXPANSION +\refitem cfg_makeindex_cmd_name MAKEINDEX_CMD_NAME +\refitem cfg_man_extension MAN_EXTENSION +\refitem cfg_man_links MAN_LINKS +\refitem cfg_man_output MAN_OUTPUT +\refitem cfg_markdown_support MARKDOWN_SUPPORT +\refitem cfg_mathjax_extensions MATHJAX_EXTENSIONS +\refitem cfg_mathjax_relpath MATHJAX_RELPATH +\refitem cfg_max_dot_graph_depth MAX_DOT_GRAPH_DEPTH +\refitem cfg_max_initializer_lines MAX_INITIALIZER_LINES +\refitem cfg_mscfile_dirs MSCFILE_DIRS +\refitem cfg_mscgen_path MSCGEN_PATH +\refitem cfg_multiline_cpp_is_brief MULTILINE_CPP_IS_BRIEF +\refitem cfg_optimize_for_fortran OPTIMIZE_FOR_FORTRAN +\refitem cfg_optimize_output_for_c OPTIMIZE_OUTPUT_FOR_C +\refitem cfg_optimize_output_java OPTIMIZE_OUTPUT_JAVA +\refitem cfg_optimize_output_vhdl OPTIMIZE_OUTPUT_VHDL +\refitem cfg_output_directory OUTPUT_DIRECTORY +\refitem cfg_output_language OUTPUT_LANGUAGE +\refitem cfg_paper_type PAPER_TYPE +\refitem cfg_pdf_hyperlinks PDF_HYPERLINKS +\refitem cfg_perl_path PERL_PATH +\refitem cfg_perlmod_latex PERLMOD_LATEX +\refitem cfg_perlmod_makevar_prefix PERLMOD_MAKEVAR_PREFIX +\refitem cfg_perlmod_pretty PERLMOD_PRETTY +\refitem cfg_predefined PREDEFINED +\refitem cfg_project_brief PROJECT_BRIEF +\refitem cfg_project_logo PROJECT_LOGO +\refitem cfg_project_name PROJECT_NAME +\refitem cfg_project_number PROJECT_NUMBER +\refitem cfg_qch_file QCH_FILE +\refitem cfg_qhg_location QHG_LOCATION +\refitem cfg_qhp_cust_filter_attrs QHP_CUST_FILTER_ATTRS +\refitem cfg_qhp_cust_filter_name QHP_CUST_FILTER_NAME +\refitem cfg_qhp_namespace QHP_NAMESPACE +\refitem cfg_qhp_sect_filter_attrs QHP_SECT_FILTER_ATTRS +\refitem cfg_qhp_virtual_folder QHP_VIRTUAL_FOLDER +\refitem cfg_qt_autobrief QT_AUTOBRIEF +\refitem cfg_quiet QUIET +\refitem cfg_recursive RECURSIVE +\refitem cfg_referenced_by_relation REFERENCED_BY_RELATION +\refitem cfg_references_link_source REFERENCES_LINK_SOURCE +\refitem cfg_references_relation REFERENCES_RELATION +\refitem cfg_repeat_brief REPEAT_BRIEF +\refitem cfg_rtf_extensions_file RTF_EXTENSIONS_FILE +\refitem cfg_rtf_hyperlinks RTF_HYPERLINKS +\refitem cfg_rtf_output RTF_OUTPUT +\refitem cfg_rtf_stylesheet_file RTF_STYLESHEET_FILE +\refitem cfg_search_includes SEARCH_INCLUDES +\refitem cfg_searchengine SEARCHENGINE +\refitem cfg_separate_member_pages SEPARATE_MEMBER_PAGES +\refitem cfg_server_based_search SERVER_BASED_SEARCH +\refitem cfg_short_names SHORT_NAMES +\refitem cfg_show_dirs SHOW_DIRECTORIES +\refitem cfg_show_files SHOW_FILES +\refitem cfg_show_include_files SHOW_INCLUDE_FILES +\refitem cfg_show_namespaces SHOW_NAMESPACES +\refitem cfg_show_used_files SHOW_USED_FILES +\refitem cfg_sip_support SIP_SUPPORT +\refitem cfg_skip_function_macros SKIP_FUNCTION_MACROS +\refitem cfg_sort_brief_docs SORT_BRIEF_DOCS +\refitem cfg_sort_by_scope_name SORT_BY_SCOPE_NAME +\refitem cfg_sort_group_names SORT_GROUP_NAMES +\refitem cfg_sort_member_docs SORT_MEMBER_DOCS +\refitem cfg_sort_members_constructors_first SORT_MEMBERS_CTORS_1ST +\refitem cfg_source_browser SOURCE_BROWSER +\refitem cfg_strip_code_comments STRIP_CODE_COMMENTS +\refitem cfg_strip_from_inc_path STRIP_FROM_INC_PATH +\refitem cfg_strip_from_path STRIP_FROM_PATH +\refitem cfg_subgrouping SUBGROUPING +\refitem cfg_symbol_cache_size SYMBOL_CACHE_SIZE +\refitem cfg_tab_size TAB_SIZE +\refitem cfg_tagfiles TAGFILES +\refitem cfg_template_relations TEMPLATE_RELATIONS +\refitem cfg_toc_expand TOC_EXPAND +\refitem cfg_treeview_width TREEVIEW_WIDTH +\refitem cfg_typedef_hides_struct TYPEDEF_HIDES_STRUCT +\refitem cfg_uml_limit_num_fields UML_LIMIT_NUM_FIELDS +\refitem cfg_uml_look UML_LOOK +\refitem cfg_use_htags USE_HTAGS +\refitem cfg_use_inline_trees USE_INLINE_TREES +\refitem cfg_use_mathjax USE_MATHJAX +\refitem cfg_use_pdflatex USE_PDFLATEX +\refitem cfg_verbatim_headers VERBATIM_HEADERS +\refitem cfg_warn_format WARN_FORMAT +\refitem cfg_warn_if_doc_error WARN_IF_DOC_ERROR +\refitem cfg_warn_if_undocumented WARN_IF_UNDOCUMENTED +\refitem cfg_warn_logfile WARN_LOGFILE +\refitem cfg_warn_no_paramdoc WARN_NO_PARAMDOC +\refitem cfg_warnings WARNINGS +\refitem cfg_xml_dtd XML_DTD +\refitem cfg_xml_output XML_OUTPUT +\refitem cfg_xml_programlisting XML_PROGRAMLISTING +\refitem cfg_xml_schema XML_SCHEMA +\endsecreflist + +\section config_project Project related options +\anchor cfg_doxyfile_encoding +<dl> + +<dt>\c DOXYFILE_ENCODING <dd> + \addindex DOXYFILE_ENCODING + This tag specifies the encoding used for all characters in the config file that + follow. The default is UTF-8 which is also the encoding used for all text before + the first occurrence of this tag. Doxygen uses libiconv (or the iconv built into + libc) for the transcoding. See http://www.gnu.org/software/libiconv for the list of + possible encodings. + +\anchor cfg_project_name +<dt>\c PROJECT_NAME <dd> + \addindex PROJECT_NAME + The \c PROJECT_NAME tag is a single word (or a sequence of words + surrounded by double-quotes) that should identify the project for which the + documentation is generated. This name is used in the title of most + generated pages and in a few other places. + +\anchor cfg_project_number +<dt>\c PROJECT_NUMBER <dd> + \addindex PROJECT_NUMBER + The \c PROJECT_NUMBER tag can be used to enter a project or revision number. + This could be handy for archiving the generated documentation or + if some version control system is used. + +\anchor cfg_project_brief +<dt>\c PROJECT_BRIEF <dd> + Using the \c PROJECT_BRIEF tag one can provide an optional one line description + for a project that appears at the top of each page and should give viewer + a quick idea about the purpose of the project. Keep the description short. + +\anchor cfg_project_logo +<dt>\c PROJECT_LOGO <dd> + With the \c PROJECT_LOGO tag one can specify an logo or icon that is + included in the documentation. The maximum height of the logo should not + exceed 55 pixels and the maximum width should not exceed 200 pixels. + Doxygen will copy the logo to the output directory. + +\anchor cfg_output_directory +<dt>\c OUTPUT_DIRECTORY <dd> + \addindex OUTPUT_DIRECTORY + The \c OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) + path into which the generated documentation will be written. + If a relative path is entered, it will be relative to the location + where doxygen was started. If left blank the current directory will be used. + +\anchor cfg_create_subdirs +<dt>\c CREATE_SUBDIRS <dd> + \addindex CREATE_SUBDIRS + If the \c CREATE_SUBDIRS tag is set to \c YES, then doxygen will create + 4096 sub-directories (in 2 levels) under the output directory of each output + format and will distribute the generated files over these directories. + Enabling this option can be useful when feeding doxygen a huge amount of source + files, where putting all generated files in the same directory would otherwise + causes performance problems for the file system. + +\anchor cfg_output_language +<dt>\c OUTPUT_LANGUAGE <dd> + \addindex OUTPUT_LANGUAGE + The \c OUTPUT_LANGUAGE tag is used to specify the language in which all + documentation generated by doxygen is written. Doxygen will use this + information to generate all constant output in the proper language. + The default language is English, other supported languages are: + Afrikaans, Arabic, Brazilian, Catalan, Chinese, Croatian, Czech, Danish, Dutch, + Finnish, French, German, Greek, Hungarian, Italian, Japanese, Korean, + Lithuanian, Norwegian, Persian, Polish, Portuguese, Romanian, Russian, Serbian, + Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, and Ukrainian. + +\anchor cfg_brief_member_desc +<dt>\c BRIEF_MEMBER_DESC <dd> + \addindex BRIEF_MEMBER_DESC + If the \c BRIEF_MEMBER_DESC tag is set to \c YES (the default) doxygen will + include brief member descriptions after the members that are listed in + the file and class documentation (similar to JavaDoc). + Set to NO to disable this. + +\anchor cfg_repeat_brief +<dt>\c REPEAT_BRIEF <dd> + \addindex REPEAT_BRIEF + If the \c REPEAT_BRIEF tag is set to \c YES (the default) doxygen will + prepend the brief description of a member or function before the detailed + description + + \par Note: + If both \c HIDE_UNDOC_MEMBERS and \c BRIEF_MEMBER_DESC are set to \c NO, the + brief descriptions will be completely suppressed. + +\anchor cfg_abbreviate_brief +<dt>\c ABBREVIATE_BRIEF <dd> + \addindex ABBREVIATE_BRIEF + This tag implements a quasi-intelligent brief description abbreviator + that is used to form the text in various listings. Each string + in this list, if found as the leading text of the brief description, will be + stripped from the text and the result after processing the whole list, is used + as the annotated text. Otherwise, the brief description is used as-is. If left + blank, the following values are used ("\$name" is automatically replaced with the + name of the entity): "The $name class" "The $name widget" "The $name file" + "is" "provides" "specifies" "contains" "represents" "a" "an" "the". + +\anchor cfg_always_detailed_sec +<dt>\c ALWAYS_DETAILED_SEC <dd> + \addindex ALWAYS_DETAILED_SEC + If the \c ALWAYS_DETAILED_SEC and \c REPEAT_BRIEF tags are both set to \c YES then + doxygen will generate a detailed section even if there is only a brief + description. + +\anchor cfg_inline_inherited_memb +<dt>\c INLINE_INHERITED_MEMB <dd> +\addindex INLINE_INHERITED_MEMB + If the \c INLINE_INHERITED_MEMB tag is set to \c YES, doxygen will show all inherited + members of a class in the documentation of that class as if those members were + ordinary class members. Constructors, destructors and assignment operators of + the base classes will not be shown. + +\anchor cfg_full_path_names +<dt>\c FULL_PATH_NAMES <dd> + \addindex FULL_PATH_NAMES + If the \c FULL_PATH_NAMES tag is set to \c YES doxygen will prepend the full + path before files name in the file list and in the header files. If set + to NO the shortest path that makes the file name unique will be used + +\anchor cfg_strip_from_path +<dt>\c STRIP_FROM_PATH <dd> + \addindex STRIP_FROM_PATH + If the \c FULL_PATH_NAMES tag is set to \c YES then the \c STRIP_FROM_PATH tag + can be used to strip a user-defined part of the path. Stripping is + only done if one of the specified strings matches the left-hand part of the + path. The tag can be used to show relative paths in the file list. + If left blank the directory from which doxygen is run is used as the + path to strip. + +\anchor cfg_strip_from_inc_path +<dt>\c STRIP_FROM_INC_PATH <dd> + \addindex STRIP_FROM_INC_PATH + The \c STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of + the path mentioned in the documentation of a class, which tells + the reader which header file to include in order to use a class. + If left blank only the name of the header file containing the class + definition is used. Otherwise one should specify the include paths that + are normally passed to the compiler using the -I flag. + +\anchor cfg_short_names +<dt>\c SHORT_NAMES <dd> + \addindex SHORT_NAMES + If the \c SHORT_NAMES tag is set to \c YES, doxygen will generate much shorter + (but less readable) file names. This can be useful is your file systems + doesn't support long names like on DOS, Mac, or CD-ROM. + +\anchor cfg_javadoc_autobrief +<dt>\c JAVADOC_AUTOBRIEF <dd> + \addindex JAVADOC_AUTOBRIEF + If the \c JAVADOC_AUTOBRIEF is set to \c YES then doxygen + will interpret the first line (until the first dot) of a JavaDoc-style + comment as the brief description. If set to NO (the default), the + Javadoc-style will behave just like regular Qt-style comments + (thus requiring an explicit \@brief command for a brief description.) + +\anchor cfg_qt_autobrief +<dt>\c QT_AUTOBRIEF <dd> + \addindex QT_AUTOBRIEF + If the \c QT_AUTOBRIEF is set to \c YES then doxygen + will interpret the first line (until the first dot) of a Qt-style + comment as the brief description. If set to NO (the default), the + Qt-style will behave just like regular Qt-style comments (thus + requiring an explicit \\brief command for a brief description.) + +\anchor cfg_markdown_support +<dt>\c MARKDOWN_SUPPORT <dd> + \addindex MARKDOWN_SUPPORT + If \c MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all + comments according to the Markdown format, which allows for more readable + documentation. See http://daringfireball.net/projects/markdown/ for details. + The output of markdown processing is further processed by doxygen, so you + can mix doxygen, HTML, and XML commands with Markdown formatting. + Disable only in case of backward compatibilities issues. + +\anchor cfg_builtin_stl_support +<dt>\c BUILTIN_STL_SUPPORT <dd> + \addindex BUILTIN_STL_SUPPORT + If you use STL classes (i.e. std::string, std::vector, etc.) but do not want to + include (a tag file for) the STL sources as input, then you should + set this tag to \c YES in order to let doxygen match functions declarations and + definitions whose arguments contain STL classes (e.g. func(std::string); versus + func(std::string) {}). This also make the inheritance and collaboration + diagrams that involve STL classes more complete and accurate. + +\anchor cfg_cpp_cli_support +<dt>\c CPP_CLI_SUPPORT <dd> + \addindex CPP_CLI_SUPPORT + If you use Microsoft's C++/CLI language, you should set this option to YES to + enable parsing support. + +\anchor cfg_sip_support +<dt>\c SIP_SUPPORT <dd> + \addindex OPTIMIZE_OUTPUT_SIP + Set the SIP_SUPPORT tag to YES if your project consists + of <a href="http://www.riverbankcomputing.co.uk/sip/">sip</a> sources only. + Doxygen will parse them like normal C++ but will assume all classes use public + instead of private inheritance when no explicit protection keyword is present. + +\anchor cfg_idl_property_support +<dt>\c IDL_PROPERTY_SUPPORT <dd> + \addindex IDL_PROPERTY_SUPPORT + For Microsoft's IDL there are propget and propput attributes to indicate getter + and setter methods for a property. Setting this option to \c YES (the default) + will make doxygen to replace the get and set methods by a property in the + documentation. This will only work if the methods are indeed getting or + setting a simple type. If this is not the case, or you want to show the + methods anyway, you should set this option to \c NO. + +\anchor cfg_distribute_group_doc +<dt>\c DISTRIBUTE_GROUP_DOC <dd> + \addindex DISTRIBUTE_GROUP_DOC + If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC + tag is set to YES, then doxygen will reuse the documentation of the first + member in the group (if any) for the other members of the group. By default + all members of a group must be documented explicitly. + +\anchor cfg_multiline_cpp_is_brief +<dt>\c MULTILINE_CPP_IS_BRIEF <dd> + \addindex MULTILINE_CPP_IS_BRIEF + The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen + treat a multi-line C++ special comment block (i.e. a block of //! or /// + comments) as a brief description. This used to be the default behavior. + The new default is to treat a multi-line C++ comment block as a detailed + description. Set this tag to YES if you prefer the old behavior instead. + Note that setting this tag to YES also means that rational rose comments + are not recognized any more. + +<!-- +\anchor cfg_details_at_top +<dt>\c DETAILS_AT_TOP <dd> + \addindex DETAILS_AT_TOP + If the DETAILS_AT_TOP tag is set to YES then Doxygen + will output the detailed description near the top, like JavaDoc. + If set to NO, the detailed description appears after the member + documentation. +--> + +\anchor cfg_inherit_docs +<dt>\c INHERIT_DOCS <dd> + \addindex INHERIT_DOCS + If the \c INHERIT_DOCS tag is set to \c YES (the default) then an undocumented + member inherits the documentation from any documented member that it + re-implements. + +\anchor cfg_separate_member_pages +<dt>\c SEPARATE_MEMBER_PAGES <dd> + \addindex SEPARATE_MEMBER_PAGES + If the \c SEPARATE_MEMBER_PAGES tag is set to \c YES, then doxygen will produce + a new page for each member. If set to \c NO, the documentation of a member will + be part of the file/class/namespace that contains it. + +\anchor cfg_tab_size +<dt>\c TAB_SIZE <dd> + \addindex TAB_SIZE + the \c TAB_SIZE tag can be used to set the number of spaces in a tab. + Doxygen uses this value to replace tabs by spaces in code fragments. + +\anchor cfg_aliases +<dt>\c ALIASES <dd> + \addindex ALIASES + This tag can be used to specify a number of aliases that acts + as commands in the documentation. An alias has the form +\verbatim + name=value +\endverbatim + For example adding +\verbatim + "sideeffect=\par Side Effects:\n" +\endverbatim + will allow you to + put the command \\sideeffect (or \@sideeffect) in the documentation, which + will result in a user-defined paragraph with heading "Side Effects:". + You can put \\n's in the value part of an alias to insert newlines. + +\anchor cfg_optimize_output_for_c +<dt>\c OPTIMIZE_OUTPUT_FOR_C <dd> + \addindex OPTIMIZE_OUTPUT_FOR_C + Set the \c OPTIMIZE_OUTPUT_FOR_C tag to \c YES if your project consists + of C sources only. Doxygen will then generate output that is more tailored + for C. For instance, some of the names that are used will be different. + The list of all members will be omitted, etc. + +\anchor cfg_optimize_output_java +<dt>\c OPTIMIZE_OUTPUT_JAVA <dd> + \addindex OPTIMIZE_OUTPUT_JAVA + Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or + Python sources only. Doxygen will then generate output that is more tailored + for that language. For instance, namespaces will be presented as packages, + qualified scopes will look different, etc. + +\anchor cfg_optimize_for_fortran +<dt>\c OPTIMIZE_FOR_FORTRAN <dd> + \addindex OPTIMIZE_FOR_FORTRAN + Set the \c OPTIMIZE_FOR_FORTRAN tag to \c YES if your project consists of Fortran + sources. Doxygen will then generate output that is tailored for Fortran. + +\anchor cfg_optimize_output_vhdl +<dt>\c OPTIMIZE_OUTPUT_VHDL <dd> + \addindex OPTIMIZE_OUTPUT_VHDL + Set the \c OPTIMIZE_OUTPUT_VHDL tag to \c YES if your project consists of VHDL + sources. Doxygen will then generate output that is tailored for VHDL. + +\anchor cfg_extension_mapping +<dt>\c EXTENSION_MAPPING <dd> + \addindex EXTENSION_MAPPING + Doxygen selects the parser to use depending on the extension of the files it parses. + With this tag you can assign which parser to use for a given extension. + Doxygen has a built-in mapping, but you can override or extend it using this tag. + The format is ext=language, where ext is a file extension, and language is one of + the parsers supported by doxygen: IDL, Java, Javascript, C#, C, C++, D, PHP, + Objective-C, Python, Fortran, VHDL. For instance to make doxygen treat + .inc files as Fortran files (default is PHP), and .f files as C (default is Fortran), + use: inc=Fortran f=C + +\anchor cfg_subgrouping +<dt>\c SUBGROUPING <dd> + \addindex SUBGROUPING + Set the \c SUBGROUPING tag to \c YES (the default) to allow class member groups of + the same type (for instance a group of public functions) to be put as a + subgroup of that type (e.g. under the Public Functions section). Set it to + \c NO to prevent subgrouping. Alternatively, this can be done per class using + the \ref cmdnosubgrouping "\\nosubgrouping" command. + +\anchor cfg_inline_grouped_classes +<dt>\c INLINE_GROUPED_CLASSES <dd> + \addindex INLINE_GROUPED_CLASSES +When the \c INLINE_GROUPED_CLASSES tag is set to \c YES, classes, structs and +unions are shown inside the group in which they are included +(e.g. using @@ingroup) instead of on a separate page (for HTML and Man pages) +or section (for LaTeX and RTF). Note that this feature does not work in +combination with \ref cfg_separate_member_pages "SEPARATE_MEMBER_PAGES". + +\anchor cfg_typedef_hides_struct +<dt>\c TYPEDEF_HIDES_STRUCT <dd> + \addindex TYPEDEF_HIDES_STRUCT + When \c TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum + is documented as struct, union, or enum with the name of the typedef. So + <code>typedef struct TypeS {} TypeT</code>, will appear in the documentation as a struct + with name \c TypeT. When disabled the typedef will appear as a member of a file, + namespace, or class. And the struct will be named \c TypeS. This can typically + be useful for C code in case the coding convention dictates that all compound + types are typedef'ed and only the typedef is referenced, never the tag name. + +\anchor cfg_symbol_cache_size +<dt>\c SYMBOL_CACHE_SIZE <dd> + \addindex SYMBOL_CACHE_SIZE + The \c SYMBOL_CACHE_SIZE determines the size of the internal cache use to + determine which symbols to keep in memory and which to flush to disk. + When the cache is full, less often used symbols will be written to disk. + For small to medium size projects (<1000 input files) the default value is + probably good enough. For larger projects a too small cache size can cause + doxygen to be busy swapping symbols to and from disk most of the time + causing a significant performance penalty. + If the system has enough physical memory increasing the cache will improve the + performance by keeping more symbols in memory. Note that the value works on + a logarithmic scale so increasing the size by one will roughly double the + memory usage. The cache size is given by this formula: + \f$2^{(16+\mbox{SYMBOL\_CACHE\_SIZE})}\f$. The valid range is 0..9, the default is 0, + corresponding to a cache size of \f$2^{16} = 65536\f$ symbols. + +\anchor cfg_lookup_cache_size +<dt>\c LOOKUP_CACHE_SIZE <dd> + \addindex LOOKUP_CACHE_SIZE + Similar to the \c SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be + set using \c LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given + their name and scope. Since this can be an expensive process and often the + same symbol appear multiple times in the code, doxygen keeps a cache of + pre-resolved symbols. If the cache is too small doxygen will become slower. + If the cache is too large, memory is wasted. The cache size is given by this + formula: \f$2^{(16+\mbox{LOOKUP\_CACHE\_SIZE})}\f$. The valid range is 0..9, the default is 0, + corresponding to a cache size of \f$2^{16} = 65536\f$ symbols. + +</dl> + +\section config_build Build related options +\anchor cfg_extract_all +<dl> + +<dt>\c EXTRACT_ALL <dd> + \addindex EXTRACT_ALL + If the \c EXTRACT_ALL tag is set to \c YES doxygen will assume all + entities in documentation are documented, even if no documentation was + available. Private class members and static file members will be hidden + unless the \c EXTRACT_PRIVATE and \c EXTRACT_STATIC tags are set to \c YES + + \par Note: + This will also disable the warnings about undocumented members + that are normally produced when \c WARNINGS is set to \c YES + +\anchor cfg_extract_private +<dt>\c EXTRACT_PRIVATE <dd> + \addindex EXTRACT_PRIVATE + If the \c EXTRACT_PRIVATE tag is set to \c YES all private members of a + class will be included in the documentation. + +\anchor cfg_extract_static +<dt>\c EXTRACT_STATIC <dd> + \addindex EXTRACT_STATIC + If the \c EXTRACT_STATIC tag is set to \c YES all static members of a file + will be included in the documentation. + +\anchor cfg_extract_local_classes +<dt>\c EXTRACT_LOCAL_CLASSES <dd> + \addindex EXTRACT_LOCAL_CLASSES + If the \c EXTRACT_LOCAL_CLASSES tag is set to \c YES classes (and structs) + defined locally in source files will be included in the documentation. + If set to NO only classes defined in header files are included. Does not + have any effect for Java sources. + +\anchor cfg_extract_anon_nspaces +<dt>\c EXTRACT_ANON_NSPACES <dd> + \addindex EXTRACT_ANON_NSPACES + If this flag is set to YES, the members of anonymous namespaces will be extracted + and appear in the documentation as a namespace called 'anonymous_namespace{file}', + where file will be replaced with the base name of the file that contains the anonymous + namespace. By default anonymous namespace are hidden. + +\anchor cfg_extract_local_methods +<dt>\c EXTRACT_LOCAL_METHODS <dd> + \addindex EXTRACT_LOCAL_METHODS + This flag is only useful for Objective-C code. When set to \c YES local + methods, which are defined in the implementation section but not in + the interface are included in the documentation. + If set to \c NO (the default) only methods in the interface are included. + +\anchor cfg_hide_undoc_members +<dt>\c HIDE_UNDOC_MEMBERS <dd> + \addindex HIDE_UNDOC_MEMBERS + If the \c HIDE_UNDOC_MEMBERS tag is set to \c YES, doxygen will hide all + undocumented members inside documented classes or files. + If set to \c NO (the default) these members will be included in the + various overviews, but no documentation section is generated. + This option has no effect if \c EXTRACT_ALL is enabled. + +\anchor cfg_hide_undoc_classes +<dt>\c HIDE_UNDOC_CLASSES <dd> + \addindex HIDE_UNDOC_CLASSES + If the \c HIDE_UNDOC_CLASSESS tag is set to \c YES, doxygen will hide all + undocumented classes. + If set to \c NO (the default) these classes will be included in the + various overviews. + This option has no effect if \c EXTRACT_ALL is enabled. + +\anchor cfg_hide_friend_compounds +<dt>\c HIDE_FRIEND_COMPOUNDS <dd> + \addindex HIDE_FRIEND_COMPOUNDS + If the \c HIDE_FRIEND_COMPOUNDS tag is set to \c YES, Doxygen will hide all + friend (class|struct|union) declarations. + If set to \c NO (the default) these declarations will be included in the + documentation. + +\anchor cfg_hide_in_body_docs +<dt>\c HIDE_IN_BODY_DOCS <dd> + \addindex HIDE_IN_BODY_DOCS +If the \c HIDE_IN_BODY_DOCS tag is set to \c YES, Doxygen will hide any +documentation blocks found inside the body of a function. +If set to \c NO (the default) these blocks will be appended to the +function's detailed documentation block. + +\anchor cfg_internal_docs +<dt>\c INTERNAL_DOCS <dd> + \addindex INTERNAL_DOCS + The \c INTERNAL_DOCS tag determines if documentation + that is typed after a \ref cmdinternal "\\internal" command is included. If the tag is set + to \c NO (the default) then the documentation will be excluded. + Set it to \c YES to include the internal documentation. + +\anchor cfg_case_sense_names +<dt>\c CASE_SENSE_NAMES <dd> + \addindex CASE_SENSE_NAMES + If the \c CASE_SENSE_NAMES tag is set to \c NO then doxygen + will only generate file names in lower-case letters. If set to + \c YES upper-case letters are also allowed. This is useful if you have + classes or files whose names only differ in case and if your file system + supports case sensitive file names. Windows users are advised to set this + option to NO. + +\anchor cfg_hide_scope_names +<dt>\c HIDE_SCOPE_NAMES <dd> + \addindex HIDE_SCOPE_NAMES + If the \c HIDE_SCOPE_NAMES tag is set to \c NO (the default) then doxygen + will show members with their full class and namespace scopes in the + documentation. If set to \c YES the scope will be hidden. + +\anchor cfg_show_include_files +<dt>\c SHOW_INCLUDE_FILES <dd> + \addindex SHOW_INCLUDE_FILES + If the SHOW_INCLUDE_FILES tag is set to \c YES (the default) then doxygen + will put a list of the files that are included by a file in the documentation + of that file. + +\anchor cfg_force_local_includes +<dt>\c FORCE_LOCAL_INCLUDES <dd> + \addindex FORCE_LOCAL_INCLUDES + If the \c FORCE_LOCAL_INCLUDES tag is set to \c YES then Doxygen + will list include files with double quotes in the documentation + rather than with sharp brackets. + +\anchor cfg_inline_info +<dt>\c INLINE_INFO <dd> + \addindex INLINE_INFO + If the \c INLINE_INFO tag is set to \c YES (the default) then a tag [inline] + is inserted in the documentation for inline members. + +\anchor cfg_sort_member_docs +<dt>\c SORT_MEMBER_DOCS <dd> + \addindex SORT_MEMBER_DOCS + If the \c SORT_MEMBER_DOCS tag is set to \c YES (the default) then doxygen + will sort the (detailed) documentation of file and class members + alphabetically by member name. If set to \c NO the members will appear in + declaration order. + +\anchor cfg_sort_brief_docs +<dt>\c SORT_BRIEF_DOCS <dd> + \addindex SORT_BRIEF_DOCS + If the \c SORT_BRIEF_DOCS tag is set to \c YES then doxygen will sort the + brief descriptions of file, namespace and class members alphabetically + by member name. If set to \c NO (the default) the members will appear in + declaration order. + + +\anchor cfg_sort_group_names +<dt>\c SORT_GROUP_NAMES <dd> + \addindex SORT_GROUP_NAMES + If the \c SORT_GROUP_NAMES tag is set to \c YES then doxygen will sort the + hierarchy of group names into alphabetical order. If set to \c NO (the default) + the group names will appear in their defined order. + +\anchor cfg_sort_by_scope_name +<dt>\c SORT_BY_SCOPE_NAME <dd> + \addindex SORT_BY_SCOPE_NAME + If the \c SORT_BY_SCOPE_NAME tag is set to \c YES, the class list will be + sorted by fully-qualified names, including namespaces. If set to + NO (the default), the class list will be sorted only by class name, + not including the namespace part. + @note This option is not very useful if \c HIDE_SCOPE_NAMES is set to \c YES. + @note This option applies only to the class list, not to the + alphabetical list. + +\anchor cfg_sort_members_constructors_first +<dt>\c SORT_MEMBERS_CTORS_1ST <dd> + \addindex SORT_MEMBERS_CTORS_1ST + If the \c SORT_MEMBERS_CTORS_1ST tag is set to \c YES then doxygen + will sort the (brief and detailed) documentation of class members so that + constructors and destructors are listed first. If set to NO (the default) + the constructors will appear in the respective orders defined by + \c SORT_MEMBER_DOCS and \c SORT_BRIEF_DOCS. + @note If \c SORT_BRIEF_DOCS is set to \c NO this option is ignored for + sorting brief member documentation. + @note If \c SORT_MEMBER_DOCS is set to \c NO this option is ignored for + sorting detailed member documentation. + +\anchor cfg_generate_deprecatedlist +<dt>\c GENERATE_DEPRECATEDLIST <dd> + \addindex GENERATE_DEPRECATEDLIST + The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or + disable (NO) the deprecated list. This list is created by + putting \ref cmddeprecated "\\deprecated" + commands in the documentation. + +\anchor cfg_strict_proto_matching +<dt>\c STRICT_PROTO_MATCHING <dd> + \addindex STRICT_PROTO_MATCHING + If the \c STRICT_PROTO_MATCHING option is enabled and doxygen fails to + do proper type resolution of all parameters of a function it will reject a + match between the prototype and the implementation of a member function even + if there is only one candidate or it is obvious which candidate to choose + by doing a simple string match. By disabling \c STRICT_PROTO_MATCHING doxygen + will still accept a match between prototype and implementation in such cases. + +\anchor cfg_generate_todolist +<dt>\c GENERATE_TODOLIST <dd> + \addindex GENERATE_TODOLIST + The GENERATE_TODOLIST tag can be used to enable (YES) or + disable (NO) the todo list. This list is created by + putting \ref cmdtodo "\\todo" + commands in the documentation. + +\anchor cfg_generate_testlist +<dt>\c GENERATE_TESTLIST <dd> + \addindex GENERATE_TESTLIST + The GENERATE_TESTLIST tag can be used to enable (YES) or + disable (NO) the test list. This list is created by + putting \ref cmdtest "\\test" commands in the documentation. + +\anchor cfg_generate_buglist +<dt>\c GENERATE_BUGLIST <dd> + \addindex GENERATE_BUGLIST + The GENERATE_BUGLIST tag can be used to enable (YES) or + disable (NO) the bug list. This list is created by + putting \ref cmdbug "\\bug" commands in the documentation. + +\anchor cfg_enabled_sections +<dt>\c ENABLED_SECTIONS <dd> + \addindex ENABLED_SECTIONS + The \c ENABLED_SECTIONS tag can be used to enable conditional + documentation sections, marked by \ref cmdif "\\if" \<section-label\> ... + \ref cmdendif "\\endif" and \ref cmdcond "\\cond" \<section-label\> ... + \ref cmdendcond "\\endcond" blocks. + +\anchor cfg_max_initializer_lines +<dt>\c MAX_INITIALIZER_LINES <dd> + \addindex MAX_INITIALIZER_LINES + The \c MAX_INITIALIZER_LINES tag determines the maximum number of lines + that the initial value of a variable or define can be. If the initializer + consists of more lines than specified here it will be hidden. Use a value + of 0 to hide initializers completely. The appearance of the value of + individual variables and defines can be controlled using \ref cmdshowinitializer "\\showinitializer" + or \ref cmdhideinitializer "\\hideinitializer" command in the documentation. + +\anchor cfg_show_used_files +<dt>\c SHOW_USED_FILES <dd> + \addindex SHOW_USED_FILES + Set the \c SHOW_USED_FILES tag to \c NO to disable the list of files generated + at the bottom of the documentation of classes and structs. If set to \c YES the + list will mention the files that were used to generate the documentation. + +\anchor cfg_show_dirs +<dt>\c SHOW_DIRECTORIES <dd> + \addindex SHOW_DIRECTORIES + If the sources in your project are distributed over multiple directories + then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy + in the documentation. + +\anchor cfg_show_files +<dt>\c SHOW_FILES <dd> + \addindex SHOW_FILES + Set the \c SHOW_FILES tag to \c NO to disable the generation of the Files page. + This will remove the Files entry from the Quick Index and from the + Folder Tree View (if specified). The default is \c YES. + +\anchor cfg_show_namespaces +<dt>\c SHOW_NAMESPACES <dd> + \addindex SHOW_NAMESPACES + Set the \c SHOW_NAMESPACES tag to \c NO to disable the generation of the + Namespaces page. This will remove the Namespaces entry from the Quick Index + and from the Folder Tree View (if specified). The default is \c YES. + +\anchor cfg_file_version_filter +<dt>\c FILE_VERSION_FILTER <dd> + \addindex FILE_VERSION_FILTER + The \c FILE_VERSION_FILTER tag can be used to specify a program or script that + doxygen should invoke to get the current version for each file (typically from the + version control system). Doxygen will invoke the program by executing (via + popen()) the command <code>command input-file</code>, where \c command is + the value of the \c FILE_VERSION_FILTER tag, and \c input-file is the name + of an input file provided by doxygen. + Whatever the program writes to standard output is used as the file version. + +Example of using a shell script as a filter for Unix: +\verbatim + FILE_VERSION_FILTER = "/bin/sh versionfilter.sh" +\endverbatim + +Example shell script for CVS: +\verbatim +#!/bin/sh +cvs status $1 | sed -n 's/^[ \]*Working revision:[ \t]*\([0-9][0-9\.]*\).*/\1/p' +\endverbatim + +Example shell script for Subversion: +\verbatim +#!/bin/sh +svn stat -v $1 | sed -n 's/^[ A-Z?\*|!]\{1,15\}/r/;s/ \{1,15\}/\/r/;s/ .*//p' +\endverbatim + +Example filter for ClearCase: +\verbatim +FILE_VERSION_INFO = "cleartool desc -fmt \%Vn" +\endverbatim + +\anchor cfg_layout_file +<dt>\c LAYOUT_FILE <dd> + The \c LAYOUT_FILE tag can be used to specify a layout file which will be parsed by + doxygen. The layout file controls the global structure of the generated output files + in an output format independent way. The create the layout file that represents + doxygen's defaults, run doxygen with the -l option. You can optionally specify a + file name after the option, if omitted DoxygenLayout.xml will be used as the name + of the layout file. Note that if you run doxygen from a directory containing + a file called DoxygenLayout.xml, doxygen will parse it automatically even if + the \c LAYOUT_FILE tag is left empty. + +\anchor cfg_cite_bib_files +<dt>\c CITE_BIB_FILES <dd> + \addindex CITE_BIB_FILES + The \c CITE_BIB_FILES tag can be used to specify one or more bib files + containing the reference definitions. This must be a list of .bib files. The + .bib extension is automatically appended if omitted. This requires the + bibtex tool to be installed. See also http://en.wikipedia.org/wiki/BibTeX + for more info. For LaTeX the style of the bibliography can be controlled + using \ref cfg_latex_bib_style "LATEX_BIB_STYLE". See + also \ref cmdcite "\\cite" for info how to create references. + +</dl> + +\section messages_input Options related to warning and progress messages +\anchor cfg_quiet +<dl> + +<dt>\c QUIET <dd> + \addindex QUIET + The \c QUIET tag can be used to turn on/off the messages that are generated + to standard output by doxygen. Possible values are \c YES and \c NO, + where \c YES implies that the messages are off. + If left blank \c NO is used. + +\anchor cfg_warnings +<dt>\c WARNINGS <dd> + \addindex WARNINGS + The \c WARNINGS tag can be used to turn on/off the warning messages that are + generated to standard error by doxygen. Possible values are \c YES and \c NO, + where \c YES implies that the warnings are on. If left blank \c NO is used. + + \b Tip: Turn warnings on while writing the documentation. + +\anchor cfg_warn_if_undocumented +<dt>\c WARN_IF_UNDOCUMENTED <dd> + \addindex WARN_IF_UNDOCUMENTED + If \c WARN_IF_UNDOCUMENTED is set to \c YES, then doxygen will generate warnings + for undocumented members. If \c EXTRACT_ALL is set to \c YES then this flag will + automatically be disabled. + +\anchor cfg_warn_if_doc_error +<dt>\c WARN_IF_DOC_ERROR <dd> + \addindex WARN_IF_DOC_ERROR + If \c WARN_IF_DOC_ERROR is set to \c YES, doxygen will generate warnings for + potential errors in the documentation, such as not documenting some + parameters in a documented function, or documenting parameters that + don't exist or using markup commands wrongly. + +\anchor cfg_warn_no_paramdoc +<dt>\c WARN_NO_PARAMDOC <dd> + \addindex WARN_NO_PARAMDOC + This \c WARN_NO_PARAMDOC option can be enabled to get warnings for + functions that are documented, but have no documentation for their parameters + or return value. If set to \c NO (the default) doxygen will only warn about + wrong or incomplete parameter documentation, but not about the absence of + documentation. + +\anchor cfg_warn_format +<dt>\c WARN_FORMAT <dd> + \addindex WARN_FORMAT + The \c WARN_FORMAT tag determines the format of the warning messages that + doxygen can produce. The string should contain the <code>\$file</code>, + <code>\$line</code>, and <code>\$text</code> + tags, which will be replaced by the file and line number from which the + warning originated and the warning text. + +\anchor cfg_warn_logfile +<dt>\c WARN_LOGFILE <dd> + \addindex WARN_LOGFILE + The \c WARN_LOGFILE tag can be used to specify a file to which warning + and error messages should be written. If left blank the output is written + to stderr. + +</dl> + +\section config_input Input related options +\anchor cfg_input +<dl> + +<dt>\c INPUT <dd> + \addindex INPUT + The \c INPUT tag is used to specify the files and/or directories that contain + documented source files. You may enter file names like + \c myfile.cpp or directories like \c /usr/src/myproject. + Separate the files or directories with spaces.<br> + + \b Note: + If this tag is empty the current directory is searched. + +\anchor cfg_input_encoding +<dt>\c INPUT_ENCODING <dd> + \addindex INPUT_ENCODING + This tag can be used to specify the character encoding of the source files that + doxygen parses. Internally doxygen uses the UTF-8 encoding, which is also the default + input encoding. Doxygen uses libiconv (or the iconv built into libc) for the transcoding. + See <a href="http://www.gnu.org/software/libiconv">the libiconv documentation</a> for + the list of possible encodings. + +\anchor cfg_file_patterns +<dt>\c FILE_PATTERNS <dd> + \addindex FILE_PATTERNS + If the value of the \c INPUT tag contains directories, you can use the + \c FILE_PATTERNS tag to specify one or more wildcard patterns + (like \c *.cpp and \c *.h ) to filter out the source-files + in the directories. If left blank the following patterns are tested: + <code> + *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh + *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py + *.f90 *.f *.vhd *.vhdl + </code> + +\anchor cfg_recursive +<dt>\c RECURSIVE <dd> + \addindex RECURSIVE + The \c RECURSIVE tag can be used to specify whether or not subdirectories + should be searched for input files as well. Possible values are \c YES + and \c NO. If left blank \c NO is used. + +\anchor cfg_exclude +<dt>\c EXCLUDE <dd> + \addindex EXCLUDE + The \c EXCLUDE tag can be used to specify files and/or directories that should be + excluded from the \c INPUT source files. This way you can easily exclude a + subdirectory from a directory tree whose root is specified with the \c INPUT tag. + Note that relative paths are relative to the directory from which doxygen is run. + +\anchor cfg_exclude_symlinks +<dt>\c EXCLUDE_SYMLINKS <dd> + \addindex EXCLUDE_SYMLINKS + The \c EXCLUDE_SYMLINKS tag can be used to select whether or not files or directories + that are symbolic links (a Unix file system feature) are excluded from the input. + +\anchor cfg_exclude_patterns +<dt>\c EXCLUDE_PATTERNS <dd> + \addindex EXCLUDE_PATTERNS + If the value of the \c INPUT tag contains directories, you can use the + \c EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude + certain files from those directories. + +\anchor cfg_exclude_symbols +<dt>\c EXCLUDE_SYMBOLS <dd> +The \c EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +(namespaces, classes, functions, etc.) that should be excluded from the +output. The symbol name can be a fully qualified name, a word, or if the +wildcard * is used, a substring. Examples: ANamespace, AClass, +AClass::ANamespace, ANamespace::*Test + + Note that the wildcards are matched against the file with absolute path, + so to exclude all test directories use the pattern + `*``/test/``*` + +\anchor cfg_example_path +<dt>\c EXAMPLE_PATH <dd> + \addindex EXAMPLE_PATH + The \c EXAMPLE_PATH tag can be used to specify one or more files or + directories that contain example code fragments that are included (see + the \\include command in section \ref cmdinclude "\\include"). + +\anchor cfg_example_recursive +<dt>\c EXAMPLE_RECURSIVE <dd> + \addindex EXAMPLE_RECURSIVE + If the \c EXAMPLE_RECURSIVE tag is set to \c YES then subdirectories will be + searched for input files to be used with the \\include or \\dontinclude + commands irrespective of the value of the \c RECURSIVE tag. + Possible values are \c YES and \c NO. If left blank \c NO is used. + +\anchor cfg_example_patterns +<dt>\c EXAMPLE_PATTERNS <dd> + \addindex EXAMPLE_PATTERNS + If the value of the \c EXAMPLE_PATH tag contains directories, you can use the + \c EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like `*.cpp` + and `*.h`) to filter out the source-files in the directories. If left + blank all files are included. + +\anchor cfg_image_path +<dt>\c IMAGE_PATH <dd> + \addindex IMAGE_PATH + The \c IMAGE_PATH tag can be used to specify one or more files or + directories that contain images that are to be included in the + documentation (see the \ref cmdimage "\\image" command). + +\anchor cfg_input_filter +<dt>\c INPUT_FILTER <dd> + \addindex INPUT_FILTER + The \c INPUT_FILTER tag can be used to specify a program that doxygen should + invoke to filter for each input file. Doxygen will invoke the filter program + by executing (via popen()) the command: +\verbatim <filter> <input-file> +\endverbatim + + where \<filter\> + is the value of the \c INPUT_FILTER tag, and \<input-file\> is the name of an + input file. Doxygen will then use the output that the filter program writes + to standard output. + +\anchor cfg_filter_patterns +<dt>\c FILTER_PATTERNS <dd> + \addindex FILTER_PATTERNS + The \c FILTER_PATTERNS tag can be used to specify filters on a per file pattern + basis. Doxygen will compare the file name with each pattern and apply the + filter if there is a match. The filters are a list of the form: + pattern=filter (like `*.cpp=my_cpp_filter`). See \c INPUT_FILTER for further + info on how filters are used. If \c FILTER_PATTERNS is empty or if + none of the patterns match the file name, \c INPUT_FILTER is applied. + +\anchor cfg_filter_source_files +<dt>\c FILTER_SOURCE_FILES <dd> + \addindex FILTER_SOURCE_FILES + If the \c FILTER_SOURCE_FILES tag is set to \c YES, the input filter (if set using + \ref cfg_input_filter "INPUT_FILTER" ) will also be used to filter the input + files that are used for producing the source files to browse + (i.e. when SOURCE_BROWSER is set to YES). + +\anchor cfg_filter_source_patterns +<dt>\c FILTER_SOURCE_PATTERNS <dd> + \addindex FILTER_SOURCE_PATTERNS + The \c FILTER_SOURCE_PATTERNS tag can be used to specify source filters per + file pattern. A pattern will override the setting for \c FILTER_PATTERN (if any) + and it is also possible to disable source filtering for a specific pattern + using `*.ext=` (so without naming a filter). This option only has effect when + \c FILTER_SOURCE_FILES is enabled. + +</dl> + +\section sourcebrowser_index Source browsing related options +\anchor cfg_source_browser +<dl> + +<dt>\c SOURCE_BROWSER <dd> + \addindex SOURCE_BROWSER + If the \c SOURCE_BROWSER tag is set to \c YES then a list of source files will + be generated. Documented entities will be cross-referenced with these sources. + Note: To get rid of all source code in the generated output, make sure also + \c VERBATIM_HEADERS is set to NO. + +\anchor cfg_inline_sources +<dt>\c INLINE_SOURCES <dd> + \addindex INLINE_SOURCES + Setting the \c INLINE_SOURCES tag to \c YES will include the body + of functions, classes and enums directly into the documentation. + +\anchor cfg_strip_code_comments +<dt>\c STRIP_CODE_COMMENTS <dd> + \addindex STRIP_CODE_COMMENTS + Setting the \c STRIP_CODE_COMMENTS tag to \c YES (the default) will instruct + doxygen to hide any special comment blocks from generated source code + fragments. Normal C and C++ comments will always remain visible. + +\anchor cfg_referenced_by_relation +<dt>\c REFERENCED_BY_RELATION <dd> + \addindex REFERENCED_BY_RELATION + If the \c REFERENCED_BY_RELATION tag is set to \c YES + then for each documented function all documented + functions referencing it will be listed. + +\anchor cfg_references_relation +<dt>\c REFERENCES_RELATION <dd> + \addindex REFERENCES_RELATION + If the \c REFERENCES_RELATION tag is set to \c YES + then for each documented function all documented entities + called/used by that function will be listed. + +\anchor cfg_references_link_source +<dt>\c REFERENCES_LINK_SOURCE <dd> + \addindex REFERENCES_LINK_SOURCE + If the \c REFERENCES_LINK_SOURCE tag is set to \c YES (the default) + and SOURCE_BROWSER tag is set to \c YES, then the hyperlinks from + functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will + link to the source code. Otherwise they will link to the documentation. + +\anchor cfg_verbatim_headers +<dt>\c VERBATIM_HEADERS <dd> + \addindex VERBATIM_HEADERS + If the \c VERBATIM_HEADERS tag is set the \c YES (the default) then doxygen + will generate a verbatim copy of the header file for each class for + which an include is specified. Set to NO to disable this. + \sa Section \ref cmdclass "\\class". + +\anchor cfg_use_htags +<dt>\c USE_HTAGS <dd> + \addindex USE_HTAGS + If the \c USE_HTAGS tag is set to \c YES then the references to source code + will point to the HTML generated by the htags(1) tool instead of doxygen + built-in source browser. The htags tool is part of GNU's global source + tagging system (see http://www.gnu.org/software/global/global.html). + To use it do the following: + + -# Install the latest version of global (i.e. 4.8.6 or better) + -# Enable SOURCE_BROWSER and USE_HTAGS in the config file + -# Make sure the INPUT points to the root of the source tree + -# Run doxygen as normal + + Doxygen will invoke htags (and that will in turn invoke gtags), so these tools + must be available from the command line (i.e. in the search path). + + The result: instead of the source browser generated by doxygen, the links to + source code will now point to the output of htags. + +</dl> + +\section alphabetical_index Alphabetical index options +\anchor cfg_alphabetical_index +<dl> + +<dt>\c ALPHABETICAL_INDEX <dd> + \addindex ALPHABETICAL_INDEX + If the \c ALPHABETICAL_INDEX tag is set to \c YES, an alphabetical index + of all compounds will be generated. Enable this if the project contains + a lot of classes, structs, unions or interfaces. + +<dt>\c COLS_IN_ALPHA_INDEX <dd> + \anchor cfg_cols_in_alpha_index + \addindex COLS_IN_ALPHA_INDEX + If the alphabetical index is enabled + (see \c ALPHABETICAL_INDEX) then the \c COLS_IN_ALPHA_INDEX tag can be + used to specify the number of columns in which this list will be split (can be a number in the range [1..20]) + +\anchor cfg_ignore_prefix +<dt>\c IGNORE_PREFIX <dd> + \addindex IGNORE_PREFIX + In case all classes in a project start with a common prefix, all classes will + be put under the same header in the alphabetical index. + The \c IGNORE_PREFIX tag can be used to specify a prefix + (or a list of prefixes) that should be ignored while generating the index + headers. + +</dl> +\section html_output HTML related options +\anchor cfg_generate_html +<dl> + +<dt>\c GENERATE_HTML <dd> + \addindex GENERATE_HTML + If the \c GENERATE_HTML tag is set to \c YES (the default) doxygen will + generate HTML output + +\anchor cfg_html_output +<dt>\c HTML_OUTPUT <dd> + \addindex HTML_OUTPUT + The \c HTML_OUTPUT tag is used to specify where the HTML docs will be put. + If a relative path is entered the value of \c OUTPUT_DIRECTORY will be + put in front of it. If left blank 'html' will be used as the default path. + +\anchor cfg_html_file_extension +<dt>\c HTML_FILE_EXTENSION <dd> + \addindex HTML_FILE_EXTENSION + The \c HTML_FILE_EXTENSION tag can be used to specify the file extension for + each generated HTML page (for example: .htm, .php, .asp). If it is left blank + doxygen will generate files with .html extension. + +\anchor cfg_html_header +<dt>\c HTML_HEADER <dd> + \addindex HTML_HEADER + The \c HTML_HEADER tag can be used to specify a user-defined HTML + header file for each generated HTML page. + If the tag is left blank doxygen will generate a + standard header. + + To get valid HTML the header file that + includes any scripts and style sheets that doxygen + needs, it is highly recommended to start with a default header using +\verbatim +doxygen -w html new_header.html new_footer.html new_stylesheet.css YourConfigFile +\endverbatim + and then modify the file \c new_header.html. + + The following markers have a special meaning inside the header and footer: + <dl> + <dt><code>\$title</code><dd>will be replaced with the title of the page. + <dt><code>\$datetime</code><dd>will be replaced with current the date and time. + <dt><code>\$date</code><dd>will be replaced with the current date. + <dt><code>\$year</code><dd>will be replaces with the current year. + <dt><code>\$doxygenversion</code><dd>will be replaced with the version of doxygen + <dt><code>\$projectname</code><dd>will be replaced with the name of + the project (see \ref cfg_project_name "PROJECT_NAME") + <dt><code>\$projectnumber</code><dd>will be replaced with the project number + (see \ref cfg_project_number "PROJECT_NUMBER") + <dt><code>\$projectbrief</code><dd>will be replaced with the project brief + description (see \ref cfg_project_brief "PROJECT_BRIEF") + <dt><code>\$projectlogo</code><dd>will be replaced with the project logo + (see \ref cfg_project_logo "PROJECT_LOGO") + <dt><code>\$treeview</code><dd>will be replaced with links to + the javascript and style sheets needed for the navigation tree + (or an empty string when \ref cfg_generate_treeview "GENERATE_TREEVIEW" + is disabled). + <dt><code>\$search</code><dd>will be replaced with a links to + the javascript and style sheets needed for the search engine + (or an empty string when \ref cfg_searchengine "SEARCHENGINE" + is disabled). + <dt><code>\$mathjax</code><dd>will be replaced with a links to + the javascript and style sheets needed for the MathJax feature + (or an empty string when \ref cfg_use_mathjax "USE_MATHJAX" is disabled). + <dt><code>\$relpath\$</code><dd> + If \c CREATE_SUBDIRS is enabled, the command <code>\$relpath\$</code> can be + used to produce a relative path to the root of the HTML output directory, + e.g. use \$relpath\$doxygen.css, to refer to the standard style sheet. + </dl> + + To cope with differences in the layout of the header and footer that depend on + configuration settings, the header can also contain special blocks that + will be copied to the output or skipped depending on the configuration. + Such blocks have the following form: +\verbatim + <!--BEGIN BLOCKNAME--> + Some context copied when condition BLOCKNAME holds + <!--END BLOCKNAME--> + <!--BEGIN !BLOCKNAME--> + Some context copied when condition BLOCKNAME does not hold + <!--END !BLOCKNAME--> +\endverbatim + The following block names are supported: + <dl> + <dt><code>DISABLE_INDEX</code><dd>Content within this block is copied to the output + when the \ref cfg_disable_index "DISABLE_INDEX" option is enabled (so when the index is disabled). + <dt><code>GENERATE_TREEVIEW</code><dd>Content within this block is copied to the output + when the \ref cfg_generate_treeview "GENERATE_TREEVIEW" option is enabled. + <dt><code>SEARCHENGINE</code><dd>Content within this block is copied to the output + when the \ref cfg_searchengine "SEARCHENGINE" option is enabled. + <dt><code>PROJECT_NAME</code><dd>Content within the block is copied to the output + when the \ref cfg_project_name "PROJECT_NAME" option is not empty. + <dt><code>PROJECT_NUMBER</code><dd>Content within the block is copied to the output + when the \ref cfg_project_number "PROJECT_NUMBER" option is not empty. + <dt><code>PROJECT_BRIEF</code><dd>Content within the block is copied to the output + when the \ref cfg_project_brief "PROJECT_BRIEF" option is not empty. + <dt><code>PROJECT_LOGO</code><dd>Content within the block is copied to the output + when the \ref cfg_project_logo "PROJECT_LOGO" option is not empty. + <dt><code>TITLEAREA</code><dd>Content within this block is copied to the output + when a title is visible at the top of each page. This is the case + if either \ref cfg_project_name "PROJECT_NAME", + \ref cfg_project_brief "PROJECT_BRIEF", \ref cfg_project_logo "PROJECT_LOGO" + is filled in or if both \ref cfg_disable_index "DISABLE_INDEX" and + \ref cfg_searchengine "SEARCHENGINE" are enabled. + </dl> + + See also section \ref doxygen_usage for information on how to generate + the default header that doxygen normally uses. + + @note The header is subject to change so you typically + have to regenerate the default header when upgrading to a newer version of + doxygen. + +\anchor cfg_html_footer +<dt>\c HTML_FOOTER <dd> + \addindex HTML_FOOTER + The \c HTML_FOOTER tag can be used to specify a user-defined HTML footer for + each generated HTML page. + If the tag is left blank doxygen will generate a standard footer. + + See \ref cfg_html_header "HTML_HEADER" for more information on + how to generate a default footer and what special commands can be + used inside the footer. + + See also section \ref doxygen_usage for information on how to generate + the default footer that doxygen normally uses. + +\anchor cfg_html_stylesheet +<dt>\c HTML_STYLESHEET <dd> + \addindex HTML_STYLESHEET + The \c HTML_STYLESHEET tag can be used to specify a user-defined cascading + style sheet that is used by each HTML page. It can be used to + fine-tune the look of the HTML output. If the tag is left blank doxygen + will generate a default style sheet. + + See also section \ref doxygen_usage for information on how to generate + the style sheet that doxygen normally uses. + +\anchor cfg_html_extra_files +<dt>\c HTML_EXTRA_FILES <dd> + \addindex HTML_EXTRA_FILES + The \c HTML_EXTRA_FILES tag can be used to specify one or more extra images or + other source files which should be copied to the HTML output directory. Note + that these files will be copied to the base HTML output directory. Use the + $relpath$ marker in the \c HTML_HEADER and/or \c HTML_FOOTER files to load these + files. In the \c HTML_STYLESHEET file, use the file name only. Also note that + the files will be copied as-is; there are no commands or markers available. + +\anchor cfg_html_colorstyle_hue +<dt>\c HTML_COLORSTYLE_HUE <dd> + \addindex HTML_COLOR_STYLE_HUE + The \c HTML_COLORSTYLE_HUE tag controls the color of the HTML output. + Doxygen will adjust the colors in the stylesheet and background images + according to this color. Hue is specified as an angle on a colorwheel, + see http://en.wikipedia.org/wiki/Hue for more information. + For instance the value 0 represents red, 60 is yellow, 120 is green, + 180 is cyan, 240 is blue, 300 purple, and 360 is red again. + The allowed range is 0 to 359. + +\anchor cfg_html_colorstyle_sat +<dt>\c HTML_COLORSTYLE_SAT <dd> + \addindex HTML_COLORSTYLE_SAT + The \c HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of + the colors in the HTML output. For a value of 0 the output will use + grayscales only. A value of 255 will produce the most vivid colors. + +\anchor cfg_html_colorstyle_gamma +<dt>\c HTML_COLORSTYLE_GAMMA <dd> + The \c HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to + the luminance component of the colors in the HTML output. Values below + 100 gradually make the output lighter, whereas values above 100 make + the output darker. The value divided by 100 is the actual gamma applied, + so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, + and 100 does not change the gamma. + +\anchor cfg_html_timestamp +<dt>\c HTML_TIMESTAMP <dd> + \addindex HTML_TIMESTAMP + If the \c HTML_TIMESTAMP tag is set to \c YES then the footer of + each generated HTML page will contain the date and time when the page + was generated. Setting this to NO can help when comparing the output of + multiple runs. + +\anchor cfg_html_align_members +<dt>\c HTML_ALIGN_MEMBERS <dd> + \addindex HTML_ALIGN_MEMBERS + If the \c HTML_ALIGN_MEMBERS tag is set to \c YES, the members of classes, + files or namespaces will be aligned in HTML using tables. If set to + \c NO a bullet list will be used. + + <b>Note:</b> + Setting this tag to \c NO will become obsolete in the future, since I only + intent to support and test the aligned representation. + +\anchor cfg_html_dynamic_sections +<dt>\c HTML_DYNAMIC_SECTIONS <dd> + \addindex HTML_DYNAMIC_SECTIONS + If the \c HTML_DYNAMIC_SECTIONS tag is set to \c YES then the generated HTML + documentation will contain sections that can be hidden and shown after the + page has loaded. For this to work a browser that supports + JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox + Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). + +\anchor cfg_generate_docset +<dt>\c GENERATE_DOCSET <dd> + \addindex GENERATE_DOCSET + If the \c GENERATE_DOCSET tag is set to \c YES, additional index files + will be generated that can be used as input for + <a href="http://developer.apple.com/tools/xcode/">Apple's Xcode 3 + integrated development environment</a>, introduced with OSX 10.5 (Leopard). + To create a documentation set, doxygen will generate a Makefile in the + HTML output directory. Running \c make will produce the docset in that + directory and running <code>make install</code> will install the docset in + <code>~/Library/Developer/Shared/Documentation/DocSets</code> + so that Xcode will find it at startup. See + <a href="http://developer.apple.com/tools/creatingdocsetswithdoxygen.html"> + this article</a> for more information. + +\anchor cfg_docset_feedname +<dt>\c DOCSET_FEEDNAME <dd> + \addindex DOCSET_FEEDNAME + When \c GENERATE_DOCSET tag is set to \c YES, this tag determines the name of the + feed. A documentation feed provides an umbrella under which multiple + documentation sets from a single provider (such as a company or product suite) + can be grouped. + +\anchor cfg_docset_bundle_id +<dt>\c DOCSET_BUNDLE_ID <dd> + When \c GENERATE_DOCSET tag is set to \c YES, this tag specifies a string that + should uniquely identify the documentation set bundle. This should be a + reverse domain-name style string, e.g. <code>com.mycompany.MyDocSet</code>. + Doxygen will append <code>.docset</code> to the name. + +\anchor cfg_docset_publisher_id +<dt>\c DOCSET_PUBLISHER_ID <dd> +When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify +the documentation publisher. This should be a reverse domain-name style +string, e.g. com.mycompany.MyDocSet.documentation. + +\anchor cfg_docset_publisher_name +<dt>\c DOCSET_PUBLISHER_NAME <dd> +The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. + +\anchor cfg_generate_htmlhelp +<dt>\c GENERATE_HTMLHELP <dd> + \addindex GENERATE_HTMLHELP + If the \c GENERATE_HTMLHELP tag is set to \c YES then + doxygen generates three additional HTML index files: + \c index.hhp, \c index.hhc, and \c index.hhk. The \c index.hhp is a + project file that can be read by + <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/htmlhelp/html/vsconHH1Start.asp"> + Microsoft's HTML Help Workshop</a> + on Windows. + + The HTML Help Workshop contains a compiler that can convert all HTML output + generated by doxygen into a single compiled HTML file (.chm). Compiled + HTML files are now used as the Windows 98 help format, and will replace + the old Windows help format (.hlp) on all Windows platforms in the future. + Compressed HTML files also contain an index, a table of contents, + and you can search for words in the documentation. + The HTML workshop also contains a viewer for compressed HTML files. + +\anchor cfg_chm_file +<dt>\c CHM_FILE <dd> + \addindex CHM_FILE + If the \c GENERATE_HTMLHELP tag is set to \c YES, the \c CHM_FILE tag can + be used to specify the file name of the resulting .chm file. You + can add a path in front of the file if the result should not be + written to the html output directory. + +\anchor cfg_hhc_location +<dt>\c HHC_LOCATION <dd> + \addindex HHC_LOCATION + If the \c GENERATE_HTMLHELP tag is set to \c YES, the \c HHC_LOCATION tag can + be used to specify the location (absolute path including file name) of + the HTML help compiler (hhc.exe). If non-empty doxygen will try to run + the HTML help compiler on the generated index.hhp. + +\anchor cfg_generate_chi +<dt>\c GENERATE_CHI <dd> + \addindex GENERATE_CHI + If the \c GENERATE_HTMLHELP tag is set to \c YES, the \c GENERATE_CHI flag + controls if a separate .chi index file is generated (<code>YES</code>) or that + it should be included in the master .chm file (<code>NO</code>). + +\anchor cfg_chm_index_encoding +<dt>\c CHM_INDEX_ENCODING <dd> + \addindex CHM_INDEX_ENCODING + If the \c GENERATE_HTMLHELP tag is set to \c YES, the \c CHM_INDEX_ENCODING + is used to encode HtmlHelp index (hhk), content (hhc) and project file + content. + +\anchor cfg_binary_toc +<dt>\c BINARY_TOC <dd> + \addindex BINARY_TOC + If the \c GENERATE_HTMLHELP tag is set to \c YES, the \c BINARY_TOC flag + controls whether a binary table of contents is generated (<code>YES</code>) or a + normal table of contents (<code>NO</code>) in the .chm file. + +\anchor cfg_toc_expand +<dt>\c TOC_EXPAND <dd> + \addindex TOC_EXPAND + The \c TOC_EXPAND flag can be set to YES to add extra items for + group members to the table of contents of the HTML help documentation + and to the tree view. + +\anchor cfg_generate_qhp +<dt>\c GENERATE_QHP <dd> + \addindex GENERATE_QHP + If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE + and QHP_VIRTUAL_FOLDER are set, an additional index file will + be generated that can be used as input for Qt's qhelpgenerator + to generate a Qt Compressed Help (.qch) of the generated HTML + documentation. + +\anchor cfg_qch_file +<dt>\c QCH_FILE <dd> + \addindex QCH_FILE + If the QHG_LOCATION tag is specified, the QCH_FILE tag can + be used to specify the file name of the resulting .qch file. + The path specified is relative to the HTML output folder. + +\anchor cfg_qhp_namespace +<dt>\c QHP_NAMESPACE <dd> + \addindex QHP_NAMESPACE + The QHP_NAMESPACE tag specifies the namespace to use when generating + Qt Help Project output. For more information please see + <a href="http://doc.trolltech.com/qthelpproject.html#namespace">Qt Help Project / Namespace</a>. + +\anchor cfg_qhp_virtual_folder +<dt>\c QHP_VIRTUAL_FOLDER <dd> + \addindex QHP_VIRTUAL_FOLDER + The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when + generating Qt Help Project output. For more information please see + <a href="http://doc.trolltech.com/qthelpproject.html#virtual-folders">Qt Help Project / Virtual Folders</a>. + +\anchor cfg_qhp_cust_filter_name +<dt>\c QHP_CUST_FILTER_NAME <dd> + \addindex QHP_CUST_FILTER_NAME + If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to add. For more information please see + <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">Qt Help Project / Custom Filters</a>. + +\anchor cfg_qhp_cust_filter_attrs +<dt>\c QHP_CUST_FILTER_ATTRS <dd> + \addindex QHP_CUST_FILTER_ATTRS + The QHP_CUST_FILTER_ATTRIBUTES tag specifies the list of the attributes of the custom filter to add. + For more information please see + <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">Qt Help Project / Custom Filters</a>. + +\anchor cfg_qhp_sect_filter_attrs +<dt>\c QHP_SECT_FILTER_ATTRS <dd> + \addindex QHP_SECT_FILTER_ATTRS + The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this project's filter section matches. + <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">Qt Help Project / Filter Attributes</a>. + +\anchor cfg_qhg_location +<dt>\c QHG_LOCATION <dd> + \addindex QHG_LOCATION + If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can + be used to specify the location of Qt's qhelpgenerator. + If non-empty doxygen will try to run qhelpgenerator on the generated + .qhp file. + +\anchor cfg_generate_eclipsehelp +<dt>\c GENERATE_ECLIPSEHELP <dd> + \addindex GENERATE_ECLIPSEHELP + If the \c GENERATE_ECLIPSEHELP tag is set to \c YES, additional index files + will be generated, which together with the HTML files, form an Eclipse help + plugin. + + To install this plugin and make it available under the help contents + menu in Eclipse, the contents of the directory containing the HTML and XML + files needs to be copied into the plugins directory of eclipse. The name of + the directory within the plugins directory should be the same as + the \ref cfg_eclipse_doc_id "ECLIPSE_DOC_ID" value. + + After copying Eclipse needs to be restarted before the help appears. + +\anchor cfg_eclipse_doc_id +<dt>\c ECLIPSE_DOC_ID <dd> + \addindex ECLIPSE_DOC_ID + A unique identifier for the eclipse help plugin. When installing the plugin + the directory name containing the HTML and XML files should also have + this name. Each documentation set should have its own identifier. + +\anchor cfg_searchengine +<dt>\c SEARCHENGINE <dd> + \addindex SEARCHENGINE + + When the \c SEARCHENGINE tag is enabled doxygen will generate a search box + for the HTML output. The underlying search engine uses javascript + and DHTML and should work on any modern browser. Note that when using + HTML help (\ref cfg_generate_htmlhelp "GENERATE_HTMLHELP"), + Qt help (\ref cfg_generate_qhp "GENERATE_QHP"), or docsets + (\ref cfg_generate_docset "GENERATE_DOCSET") there is already a search + function so this one should typically be disabled. For large projects + the javascript based search engine can be slow, then enabling + \ref cfg_server_based_search "SERVER_BASED_SEARCH" may provide a + better solution. + + It is possible to search using the keyboard; + to jump to the search box use access key + S (what the access key is + depends on the OS and browser, but it is typically CTRL, ALT/option, or both). + Inside the search box use the cursor down key to jump into the search + results window, the results can be navigated using the cursor keys. + Press Enter to select an item or escape to cancel the search. The + filter options can be selected when the cursor is inside the search box + by pressing Shift+cursor down. Also here use the cursor keys to + select a filter and enter or escape to activate or cancel the filter option. + +\anchor cfg_server_based_search +<dt>\c SERVER_BASED_SEARCH <dd> + \addindex SERVER_BASED_SEARCH + +When the SERVER_BASED_SEARCH tag is enabled the search engine will be +implemented using a PHP enabled web server instead of at the web client +using Javascript. Doxygen will generate the search PHP script and index +file to put on the web server. The advantage of the server +based approach is that it scales better to large projects and also allows +full text search. The disadvantages are that it is more difficult to setup +and does not have live searching capabilities. + +\anchor cfg_disable_index +<dt>\c DISABLE_INDEX <dd> + \addindex DISABLE_INDEX + If you want full control over the layout of the generated HTML pages it + might be necessary to disable the index and replace it with your own. + The \c DISABLE_INDEX tag can be used to turn on/off the condensed index at + top of each page. A value of NO (the default) enables the index and the + value \c YES disables it. Since the tabs have the same information as the + navigation tree you can set this option to \c NO if you already set + \ref cfg_generate_treeview "GENERATE_TREEVIEW" to \c YES. + +\anchor cfg_enum_values_per_line +<dt>\c ENUM_VALUES_PER_LINE <dd> + \addindex ENUM_VALUES_PER_LINE + This tag can be used to set the number of enum values (range [0,1..20]) + that doxygen will group on one line in the generated HTML documentation. + Note that a value of 0 will completely suppress the enum values from + appearing in the overview section. + +\anchor cfg_generate_treeview +<dt>\c GENERATE_TREEVIEW <dd> + \addindex GENERATE_TREEVIEW + The GENERATE_TREEVIEW tag is used to specify whether a tree-like index + structure should be generated to display hierarchical information. + If the tag value is set to YES, a side panel will be generated + containing a tree-like index structure (just like the one that + is generated for HTML Help). For this to work a browser that supports + JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). + Windows users are probably better off using the HTML help feature. + + Via custom stylesheets (see \ref cfg_html_stylesheet "HTML_STYLESHEET") + one can further \ref doxygen_finetune "fine-tune" the look of the index. + As an example, the default style sheet generated by doxygen has an + example that shows how to put an image at the root of the tree instead of + the \ref cfg_project_name "project name". + +\anchor cfg_use_inline_trees +<dt>\c USE_INLINE_TREES <dd> + \addindex USE_INLINE_TREES +By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories, +and Class Hierarchy pages using a tree view instead of an ordered list. + +\anchor cfg_treeview_width +<dt>\c TREEVIEW_WIDTH <dd> + \addindex TREEVIEW_WIDTH + If the treeview is enabled (see \c GENERATE_TREEVIEW) then this tag can be + used to set the initial width (in pixels) of the frame in which the tree + is shown. + +\anchor cfg_ext_links_in_window +<dt>\c EXT_LINKS_IN_WINDOW <dd> + \addindex EXT_LINKS_IN_WINDOW + When the \c EXT_LINKS_IN_WINDOW option is set to \c YES doxygen will open + links to external symbols imported via tag files in a separate window. + +\anchor cfg_formula_fontsize +<dt>\c FORMULA_FONTSIZE <dd> + \addindex FORMULA_FONTSIZE + Use this tag to change the font size of Latex formulas included + as images in the HTML documentation. The default is 10. + when you change the font size after a successful doxygen run you need + to manually remove any `form_*.png` images from the HTML + output directory to force them to be regenerated. + +\anchor cfg_formula_transparent +<dt>\c FORMULA_TRANSPARENT <dd> + \addindex FORMULA_TRANSPARENT + Use the \c FORMULA_TRANPARENT tag to determine whether or not the images + generated for formulas are transparent PNGs. Transparent PNGs are + not supported properly for IE 6.0, but are supported on all modern browsers. + Note that when changing this option you need to delete any `form_*.png` files + in the HTML output before the changes have effect. + +\anchor cfg_use_mathjax +<dt>\c USE_MATHJAX <dd> + \addindex USE_MATHJAX + Enable the \c USE_MATHJAX option to render LaTeX formulas using MathJax + (see http://www.mathjax.org) which uses client side Javascript for the + rendering instead of using prerendered bitmaps. Use this if you do not + have LaTeX installed or if you want to formulas look prettier in the HTML + output. When enabled you may also need to install MathJax separately and + configure the path to it using the \ref cfg_mathjax_relpath "MATHJAX_RELPATH" + option. + +\anchor cfg_mathjax_relpath +<dt>\c MATHJAX_RELPATH <dd> + \addindex MATHJAX_RELPATH + When MathJax is enabled you need to specify the location relative to the + HTML output directory using the \c MATHJAX_RELPATH option. The destination + directory should contain the MathJax.js script. For instance, if the mathjax + directory is located at the same level as the HTML output directory, then + \c MATHJAX_RELPATH should be <code>../mathjax</code>. The default value points to + the MathJax Content Delivery Network so you can quickly see the result without + installing MathJax. However, it is strongly recommended to install a local + copy of MathJax from http://www.mathjax.org before deployment. + +\anchor cfg_mathjax_extensions +<dt>\c MATHJAX_EXTENSIONS <dd> + \addindex MATHJAX_EXTENSIONS + The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension + names that should be enabled during MathJax rendering. For example +\verbatim +MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols +\endverbatim + +</dl> +\section latex_output LaTeX related options +\anchor cfg_generate_latex +<dl> + +<dt>\c GENERATE_LATEX <dd> + \addindex GENERATE_LATEX + If the \c GENERATE_LATEX tag is set to \c YES (the default) doxygen will + generate \f$\mbox{\LaTeX}\f$ output. + +\anchor cfg_latex_output +<dt>\c LATEX_OUTPUT <dd> + \addindex LATEX_OUTPUT + The \c LATEX_OUTPUT tag is used to specify where the \f$\mbox{\LaTeX}\f$ + docs will be put. + If a relative path is entered the value of \c OUTPUT_DIRECTORY will be + put in front of it. If left blank 'latex' will be used as the default path. + +\anchor cfg_latex_cmd_name +<dt>\c LATEX_CMD_NAME <dd> + \addindex LATEX_CMD_NAME + The \c LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be invoked. + If left blank 'latex' will be used as the default command name. + Note that when enabling USE_PDFLATEX this option is only used for + generating bitmaps for formulas in the HTML output, but not in the + Makefile that is written to the output directory. + +\anchor cfg_makeindex_cmd_name +<dt>\c MAKEINDEX_CMD_NAME <dd> + \addindex MAKEINDEX_CMD_NAME + The MAKEINDEX_CMD_NAME tag can be used to specify the command name to + generate index for LaTeX. If left blank 'makeindex' will be used as the + default command name. + +\anchor cfg_compact_latex +<dt>\c COMPACT_LATEX <dd> + \addindex COMPACT_LATEX + If the \c COMPACT_LATEX tag is set to \c YES doxygen generates more compact + \f$\mbox{\LaTeX}\f$ documents. This may be useful for small projects and may help to + save some trees in general. + +\anchor cfg_paper_type +<dt>\c PAPER_TYPE <dd> + \addindex PAPER_TYPE + The \c PAPER_TYPE tag can be used to set the paper type that is used + by the printer. Possible values are: + <ul> + <li><code>a4</code> (210 x 297 mm). + <li><code>letter</code> (8.5 x 11 inches). + <li><code>legal</code> (8.5 x 14 inches). + <li><code>executive</code> (7.25 x 10.5 inches) + </ul> + If left blank a4 will be used. + +\anchor cfg_extra_packages +<dt>\c EXTRA_PACKAGES <dd> + \addindex EXTRA_PACKAGES + The \c EXTRA_PACKAGES tag can be used to specify one or more \f$\mbox{\LaTeX}\f$ + package names that should be included in the \f$\mbox{\LaTeX}\f$ output. + To get the times font for instance you can specify +\verbatim +EXTRA_PACKAGES = times +\endverbatim + If left blank no extra packages will be included. + +\anchor cfg_latex_header +<dt>\c LATEX_HEADER <dd> + \addindex LATEX_HEADER + The \c LATEX_HEADER tag can be used to specify a personal \f$\mbox{\LaTeX}\f$ + header for the generated \f$\mbox{\LaTeX}\f$ document. + The header should contain everything until the first chapter. + + If it is left blank doxygen will generate a + standard header. See section \ref doxygen_usage for information on how to + let doxygen write the default header to a separate file. + + \par Note: + Only use a user-defined header if you know what you are doing! + + The following commands have a special meaning inside the header: + <code>\$title</code>, <code>\$datetime</code>, <code>\$date</code>, + <code>\$doxygenversion</code>, <code>\$projectname</code>, + <code>\$projectnumber</code>. + Doxygen will replace them by respectively + the title of the page, the current date and time, only the current date, + the version number of doxygen, the project name (see \c PROJECT_NAME), or the + project number (see \c PROJECT_NUMBER). + +\anchor cfg_latex_footer +<dt>\c LATEX_FOOTER <dd> + \addindex LATEX_FOOTER + The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for + the generated latex document. The footer should contain everything after + the last chapter. If it is left blank doxygen will generate a + standard footer. Notice: only use this tag if you know what you are doing! + +\anchor cfg_pdf_hyperlinks +<dt>\c PDF_HYPERLINKS <dd> + \addindex PDF_HYPERLINKS + + 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 or pdflatex). + The PDF file will + 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_use_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 + + If the \c LATEX_BATCHMODE tag is set to \c YES, doxygen will add the \\batchmode. + command to the generated \f$\mbox{\LaTeX}\f$ files. This will + instruct \f$\mbox{\LaTeX}\f$ to keep running if errors occur, instead of + asking the user for help. This option is also used when generating formulas + in HTML. + +\anchor cfg_latex_bib_style +<dt>\c LATEX_BIB_STYLE <dd> + \addindex LATEX_BIB_STYLE + + The \c LATEX_BIB_STYLE tag can be used to specify the style to use for the + bibliography, e.g. \c plainnat, or \c ieeetr. The default style is + \c plain. See http://en.wikipedia.org/wiki/BibTeX and \ref cmdcite "\\cite" + for more info. + +\anchor cfg_latex_hide_indices +<dt>\c LATEX_HIDE_INDICES <dd> + \addindex LATEX_HIDE_INDICES + + If \c LATEX_HIDE_INDICES is set to \c YES then doxygen will not + include the index chapters (such as File Index, Compound Index, etc.) + in the output. + +\anchor cfg_latex_source_code + <dt>\c LATEX_SOURCE_CODE <dd> + If \c LATEX_SOURCE_CODE is set to \c YES then doxygen will include + source code with syntax highlighting in the LaTeX output. + Note that which sources are shown also depends on other settings + such as \ref cfg_source_browser "SOURCE_BROWSER". + +</dl> +\section rtf_output RTF related options +\anchor cfg_generate_rtf +<dl> + +<dt>\c GENERATE_RTF <dd> + \addindex GENERATE_RTF + If the \c GENERATE_RTF tag is set to \c YES doxygen will generate RTF output. + The RTF output is optimized for Word 97 and may not look too pretty with + other readers/editors. + +\anchor cfg_rtf_output +<dt>\c RTF_OUTPUT <dd> + \addindex RTF_OUTPUT + The \c RTF_OUTPUT tag is used to specify where the RTF docs will be put. + If a relative path is entered the value of \c OUTPUT_DIRECTORY will be + put in front of it. If left blank \c rtf will be used as the default path. + +\anchor cfg_compact_rtf +<dt>\c COMPACT_RTF <dd> + \addindex COMPACT_RTF + If the \c COMPACT_RTF tag is set to \c YES doxygen generates more compact + RTF documents. This may be useful for small projects and may help to + save some trees in general. + +\anchor cfg_rtf_hyperlinks +<dt>\c RTF_HYPERLINKS <dd> + \addindex RTF_HYPERLINKS + If the \c RTF_HYPERLINKS tag is set to \c YES, the RTF that is generated + will contain hyperlink fields. The RTF file will + contain links (just like the HTML output) instead of page references. + This makes the output suitable for online browsing using Word or some other + Word compatible reader that support those fields. + + \par note: + WordPad (write) and others do not support links. + +\anchor cfg_rtf_stylesheet_file +<dt>\c RTF_STYLESHEET_FILE <dd> + \addindex RTF_STYLESHEET_FILE + Load stylesheet definitions from file. Syntax is similar to doxygen's + config file, i.e. a series of assignments. You only have to provide + replacements, missing definitions are set to their default value. + + See also section \ref doxygen_usage for information on how to generate + the default style sheet that doxygen normally uses. + +\anchor cfg_rtf_extensions_file +<dt>\c RTF_EXTENSIONS_FILE <dd> + Set optional variables used in the generation of an RTF document. + Syntax is similar to doxygen's config file. + A template extensions file can be generated using + <code>doxygen -e rtf extensionFile</code>. + +</dl> + +\section man_output Man page related options +\anchor cfg_generate_man +<dl> + +<dt>\c GENERATE_MAN <dd> + \addindex GENERATE_MAN + If the \c GENERATE_MAN tag is set to \c YES (the default) doxygen will + generate man pages for classes and files. + +\anchor cfg_man_output +<dt>\c MAN_OUTPUT <dd> + \addindex MAN_OUTPUT + The \c MAN_OUTPUT tag is used to specify where the man pages will be put. + If a relative path is entered the value of \c OUTPUT_DIRECTORY will be + put in front of it. If left blank 'man' will be used as the default path. + A directory man3 will be created inside the directory specified by + \c MAN_OUTPUT. + +\anchor cfg_man_extension +<dt>\c MAN_EXTENSION <dd> + \addindex MAX_EXTENSION + The \c MAN_EXTENSION tag determines the extension that is added to + the generated man pages (default is the subroutine's section .3) + +\anchor cfg_man_links +<dt>\c MAN_LINKS <dd> + \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, + but without them the man command would be unable to find the correct page. + The default is \c NO. + +</dl> + +\section xml_output XML related options +\anchor cfg_generate_xml +<dl> + +<dt>\c GENERATE_XML <dd> + \addindex GENERATE_XML + If the \c GENERATE_XML tag is set to \c YES Doxygen will + generate an XML file that captures the structure of + the code including all documentation. + +\anchor cfg_xml_output +<dt>\c XML_OUTPUT <dd> + \addindex XML_OUTPUT + The \c XML_OUTPUT tag is used to specify where the XML pages will be put. + If a relative path is entered the value of \c OUTPUT_DIRECTORY will be + put in front of it. If left blank \c xml will be used as the default path. + +\anchor cfg_xml_schema +<dt>\c XML_SCHEMA <dd> + \addindex XML_SCHEMA + The \c XML_SCHEMA tag can be used to specify an XML schema, + which can be used by a validating XML parser to check the + syntax of the XML files. + +\anchor cfg_xml_dtd +<dt>\c XML_DTD <dd> + \addindex XML_DTD + The \c XML_DTD tag can be used to specify an XML DTD, + which can be used by a validating XML parser to check the + syntax of the XML files. + +\anchor cfg_xml_programlisting +<dt>\c XML_PROGRAMLISTING <dd> + \addindex XML_PROGRAMLISTING + If the \c XML_PROGRAMLISTING tag is set to \c YES Doxygen will + dump the program listings (including syntax highlighting + and cross-referencing information) to the XML output. Note that + enabling this will significantly increase the size of the XML output. + +</dl> + +\section autogen_output AUTOGEN_DEF related options +\anchor cfg_generate_autogen_def +<dl> + +<dt>\c GENERATE_AUTOGEN_DEF <dd> + \addindex GENERATE_AUTOGEN_DEF + If the \c GENERATE_AUTOGEN_DEF tag is set to \c YES Doxygen will + generate an AutoGen Definitions (see http://autogen.sf.net) file + that captures the structure of the code including all + documentation. Note that this feature is still experimental + and incomplete at the moment. + +</dl> + +\section perlmod_output PERLMOD related options +\anchor cfg_generate_perlmod +<dl> + +<dt>\c GENERATE_PERLMOD <dd> + \addindex GENERATE_PERLMOD + If the \c GENERATE_PERLMOD tag is set to \c YES Doxygen will + generate a Perl module file that captures the structure of + the code including all documentation. Note that this + feature is still experimental and incomplete at the + moment. + +\anchor cfg_perlmod_latex +<dt>\c PERLMOD_LATEX <dd> + \addindex PERLMOD_LATEX + If the \c PERLMOD_LATEX tag is set to \c YES Doxygen will generate + the necessary Makefile rules, Perl scripts and LaTeX code to be able + to generate PDF and DVI output from the Perl module output. + +\anchor cfg_perlmod_pretty +<dt>\c PERLMOD_PRETTY <dd> + \addindex PERLMOD_PRETTY + If the \c PERLMOD_PRETTY tag is set to \c YES the Perl module output will be + nicely formatted so it can be parsed by a human reader. This is useful + if you want to understand what is going on. On the other hand, if this + tag is set to \c NO the size of the Perl module output will be much smaller + and Perl will parse it just the same. + +\anchor cfg_perlmod_makevar_prefix +<dt>\c PERLMOD_MAKEVAR_PREFIX <dd> + \addindex PERLMOD_MAKEVAR_PREFIX + The names of the make variables in the generated doxyrules.make file + are prefixed with the string contained in \c PERLMOD_MAKEVAR_PREFIX. + This is useful so different doxyrules.make files included by the same + Makefile don't overwrite each other's variables. + +</dl> + +\section config_prepro Preprocessor related options +\anchor cfg_enable_preprocessing +<dl> + +<dt>\c ENABLE_PREPROCESSING <dd> + \addindex ENABLE_PREPROCESSING + If the \c ENABLE_PREPROCESSING tag is set to \c YES (the default) doxygen will + evaluate all C-preprocessor directives found in the sources and include + files. + +\anchor cfg_macro_expansion +<dt>\c MACRO_EXPANSION <dd> + \addindex MACRO_EXPANSION + If the \c MACRO_EXPANSION tag is set to \c YES doxygen will expand all macro + names in the source code. If set to \c NO (the default) only conditional + compilation will be performed. Macro expansion can be done in a controlled + way by setting \c EXPAND_ONLY_PREDEF to \c YES. + +\anchor cfg_expand_only_predef +<dt>\c EXPAND_ONLY_PREDEF <dd> + \addindex EXPAND_ONLY_PREDEF + If the \c EXPAND_ONLY_PREDEF and \c MACRO_EXPANSION tags are both set to YES + then the macro expansion is limited to the macros specified with the + \c PREDEFINED and \c EXPAND_AS_DEFINED tags. + +\anchor cfg_search_includes +<dt>\c SEARCH_INCLUDES <dd> + \addindex SEARCH_INCLUDES + If the \c SEARCH_INCLUDES tag is set to \c YES (the default) the includes files + in the \c INCLUDE_PATH (see below) will be searched if a \#include is found. + +\anchor cfg_include_path +<dt>\c INCLUDE_PATH <dd> + \addindex INCLUDE_PATH + The \c INCLUDE_PATH tag can be used to specify one or more directories that + contain include files that are not input files but should be processed by + the preprocessor. + +\anchor cfg_include_file_patterns +<dt>\c INCLUDE_FILE_PATTERNS <dd> + \addindex INCLUDE_FILE_PATTERNS + You can use the \c INCLUDE_FILE_PATTERNS tag to specify one or more wildcard + patterns (like `*.h` and `*.hpp`) to filter out the header-files in the + directories. If left blank, the patterns specified with \c FILE_PATTERNS will + be used. + +\anchor cfg_predefined +<dt>\c PREDEFINED <dd> + \addindex PREDEFINED + The \c PREDEFINED tag can be used to specify one or more macro names that + 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. To prevent + a macro definition from being undefined via \#undef or recursively expanded + use the := operator instead of the = operator. + +\anchor cfg_expand_as_defined +<dt>\c EXPAND_AS_DEFINED <dd> + \addindex EXPAND_AS_DEFINED + If the \c MACRO_EXPANSION and \c EXPAND_ONLY_PREDEF tags are set to \c YES then + this tag can be used to specify a list of macro names that should be expanded. + 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, have an all uppercase name, 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> +\section config_extref External reference options +\anchor cfg_tagfiles +<dl> + +<dt>\c TAGFILES <dd> + \addindex TAGFILES + The \c TAGFILES tag can be used to specify one or more tag files. + + See \ref external for more information about the use of tag files. + + \note + Each tag file must have a unique name + (where the name does \e not include the path). + If a tag file is not located in the directory in which doxygen + is run, you must also specify the path to the tagfile here. + +\anchor cfg_generate_tagfile +<dt>\c GENERATE_TAGFILE <dd> + \addindex GENERATE_TAGFILE + When a file name is specified after \c GENERATE_TAGFILE, doxygen will create + a tag file that is based on the input files it reads. + See section \ref external for more information about the usage of + tag files. + +\anchor cfg_allexternals +<dt>\c ALLEXTERNALS <dd> + \addindex ALLEXTERNALS + If the \c ALLEXTERNALS tag is set to \c YES all external class will be listed + in the class index. If set to \c NO only the inherited external classes + will be listed. + +\anchor cfg_external_groups +<dt>\c EXTERNAL_GROUPS <dd> + \addindex EXTERNAL_GROUPS + If the \c EXTERNAL_GROUPS tag is set to \c YES all external groups will be listed + in the modules index. If set to \c NO, only the current project's groups will + be listed. + +\anchor cfg_perl_path +<dt>\c PERL_PATH <dd> + \addindex PERL_PATH + The \c PERL_PATH should be the absolute path and name of the perl script + interpreter (i.e. the result of '<tt>which perl</tt>'). + +</dl> +\section config_dot Dot options +\anchor cfg_class_diagrams +<dl> + +<dt>\c CLASS_DIAGRAMS <dd> + \addindex CLASS_DIAGRAMS + If the \c CLASS_DIAGRAMS tag is set to \c YES (the default) doxygen will + generate a class diagram (in HTML and \f$\mbox{\LaTeX}\f$) for classes with base or +super classes. Setting the tag to NO turns the diagrams off. Note that +this option also works with HAVE_DOT disabled, but it is recommended to +install and use dot, since it yields more powerful graphs. + +\anchor cfg_mscgen_path +<dt>\c MSCGEN_PATH <dd> + \addindex MSCGEN_PATH + You can define message sequence charts within doxygen comments using the \ref cmdmsc "\\msc" + command. Doxygen will then run the <a href="http://www.mcternan.me.uk/mscgen/">mscgen tool</a>) to + produce the chart and insert it in the documentation. The <code>MSCGEN_PATH</code> tag allows you to + specify the directory where the mscgen tool resides. If left empty the tool is assumed to + be found in the default search path. + +\anchor cfg_have_dot +<dt>\c HAVE_DOT <dd> + \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 + 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) + +\anchor cfg_dot_num_threads +<dt>\c DOT_NUM_THREADS <dd> + \addindex DOT_NUM_THREADS + The \c DOT_NUM_THREADS specifies the number of dot invocations doxygen is + allowed to run in parallel. When set to 0 (the default) doxygen will + base this on the number of processors available in the system. You can set it + explicitly to a value larger than 0 to get control over the balance + between CPU load and processing speed. + +\anchor cfg_dot_fontname +<dt>\c DOT_FONTNAME <dd> + \addindex DOT_FONTNAME + By default doxygen will use the Helvetica font for all dot files that + doxygen generates. + When you want a differently looking font you can specify the font name + using \c DOT_FONTNAME. You need to make sure dot is able to find the font, + which can be done by putting it in a standard location or by setting the + \c DOTFONTPATH environment variable or by setting \c DOT_FONTPATH to the + directory containing the font. + +\anchor cfg_dot_fontsize +<dt>\c DOT_FONTSIZE <dd> +The \c DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. +The default size is 10pt. + +\anchor cfg_dot_fontpath +<dt>\c DOT_FONTPATH <dd> + \addindex DOT_FONTPATH + By default doxygen will tell dot to use the output directory to look for the + \c FreeSans.ttf font (which doxygen will put there itself). If you specify a + different font using \c DOT_FONTNAME you can set the path where dot + can find it using this tag. + +\anchor cfg_class_graph +<dt>\c CLASS_GRAPH <dd> + \addindex CLASS_GRAPH + If the \c CLASS_GRAPH and \c HAVE_DOT tags are set to \c YES then doxygen + will generate a graph for each documented class showing the direct and + indirect inheritance relations. Setting this tag to \c YES will force + the \c CLASS_DIAGRAMS tag to NO. + +\anchor cfg_collaboration_graph +<dt>\c COLLABORATION_GRAPH <dd> + \addindex COLLABORATION_GRAPH + If the \c COLLABORATION_GRAPH and \c HAVE_DOT tags are set to \c YES then doxygen + will generate a graph for each documented class showing the direct and + indirect implementation dependencies (inheritance, containment, and + class references variables) of the class with other documented classes. + +\anchor cfg_group_graphs +<dt>\c GROUP_GRAPHS <dd> + \addindex GROUP_GRAPHS + If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen + will generate a graph for groups, showing the direct groups dependencies. + +\anchor cfg_uml_look +<dt>\c UML_LOOK <dd> + \addindex UML_LOOK + If the UML_LOOK tag is set to YES doxygen will generate inheritance and + collaboration diagrams in a style similar to the OMG's Unified Modeling + Language. + +\anchor cfg_uml_limit_num_fields +<dt>\c UML_LIMIT_NUM_FIELDS <dd> + \addindex UML_LIMIT_NUM_FIELDS + If the \c UML_LOOK tag is enabled, the fields and methods are shown inside + the class node. If there are many fields or methods and many nodes the + graph may become too big to be useful. The \c UML_LIMIT_NUM_FIELDS + threshold limits the number of items for each type to make the size more + managable. Set this to 0 for no limit. Note that the threshold may be + exceeded by 50% before the limit is enforced. So when you set the threshold + to 10, up to 15 fields may appear, but if the number exceeds 15, the + total amount of fields shown is limited to 10. + +\anchor cfg_template_relations +<dt>\c TEMPLATE_RELATIONS <dd> + \addindex TEMPLATE_RELATIONS + If the \c TEMPLATE_RELATIONS and \c HAVE_DOT tags are set to \c YES then + doxygen will show the relations between templates and their instances. + +\anchor cfg_hide_undoc_relations +<dt>\c HIDE_UNDOC_RELATIONS <dd> + \addindex HIDE_UNDOC_RELATIONS + If set to YES, the inheritance and collaboration graphs will hide + inheritance and usage relations if the target is undocumented + or is not a class. + +\anchor cfg_include_graph +<dt>\c INCLUDE_GRAPH <dd> + \addindex INCLUDE_GRAPH + If the \c ENABLE_PREPROCESSING, \c SEARCH_INCLUDES, \c INCLUDE_GRAPH, and \c HAVE_DOT + tags are set to \c YES then doxygen will generate a graph for each documented file + showing the direct and indirect include dependencies of the file with other + documented files. + +\anchor cfg_included_by_graph +<dt>\c INCLUDED_BY_GRAPH <dd> + \addindex INCLUDED_BY_GRAPH + If the \c ENABLE_PREPROCESSING, \c SEARCH_INCLUDES, \c INCLUDED_BY_GRAPH, and + \c HAVE_DOT tags are set to \c YES then doxygen will generate a graph for each + documented header file showing the documented files that directly or indirectly + include this file. + +\anchor cfg_call_graph +<dt>\c CALL_GRAPH <dd> + \addindex CALL_GRAPH + If the \c CALL_GRAPH and \c HAVE_DOT tags are set to \c YES then doxygen will + generate a call dependency graph for every global function or class method. + Note that enabling this option will significantly increase the time of a run. + So in most cases it will be better to enable call graphs for selected + functions only using the \\callgraph command. + +\anchor cfg_caller_graph +<dt>\c CALLER_GRAPH <dd> + \addindex CALLER_GRAPH + If the \c CALLER_GRAPH and \c HAVE_DOT tags are set to \c YES then doxygen will + generate a caller dependency graph for every global function or class method. + Note that enabling this option will significantly increase the time of a run. + So in most cases it will be better to enable caller graphs for selected + functions only using the \\callergraph command. + +\anchor cfg_graphical_hierarchy +<dt>\c GRAPHICAL_HIERARCHY <dd> + \addindex GRAPHICAL_HIERARCHY + If the \c GRAPHICAL_HIERARCHY and \c HAVE_DOT tags are set to \c YES then + doxygen will graphical hierarchy of all classes instead of a textual one. + +\anchor cfg_directory_graph +<dt>\c DIRECTORY_GRAPH <dd> + \addindex DIRECTORY_GRAPH + If the \c DIRECTORY_GRAPH, \c SHOW_DIRECTORIES and \c HAVE_DOT options are set + to \c YES then doxygen will show the dependencies a directory has on other directories + in a graphical way. The dependency relations are determined by the \#include + relations between the files in the directories. + +\anchor cfg_dot_graph_max_nodes +<dt>\c DOT_GRAPH_MAX_NODES <dd> + \addindex DOT_GRAPH_MAX_NODES + The \c DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of + nodes that will be shown in the graph. If the number of nodes in a graph + becomes larger than this value, doxygen will truncate the graph, which is + visualized by representing a node as a red box. Note that doxygen if the number + of direct children of the root node in a graph is already larger than + \c DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note + that the size of a graph can be further restricted by \c MAX_DOT_GRAPH_DEPTH. + +\anchor cfg_max_dot_graph_depth +<dt>\c MAX_DOT_GRAPH_DEPTH <dd> + \addindex MAX_DOT_GRAPH_DEPTH + The \c MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the + graphs generated by dot. A depth value of 3 means that only nodes reachable + from the root by following a path via at most 3 edges will be shown. Nodes + that lay further from the root node will be omitted. Note that setting this + option to 1 or 2 may greatly reduce the computation time needed for large + code bases. Also note that the size of a graph can be further restricted by + \c DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction (the default). + +\anchor cfg_dot_image_format +<dt>\c DOT_IMAGE_FORMAT <dd> + \addindex DOT_IMAGE_FORMAT + The \c DOT_IMAGE_FORMAT tag can be used to set the image format of the images + generated by dot. Possible values are svg, png, jpg, or gif. + If left blank png will be used. + \note If you choose \c svg you need to set + HTML_FILE_EXTENSION to xhtml in order to make the SVG files + visible in IE 9+ (other browsers do not have this requirement). + +\anchor cfg_interactive_svg +<dt>\c INTERACTIVE_SVG <dd> + If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to + enable generation of interactive SVG images that allow zooming and panning. + Note that this requires a modern browser other than Internet Explorer. + Tested and working are Firefox, Chrome, Safari, and Opera. + \note For IE 9+ you need to set \c HTML_FILE_EXTENSION to xhtml in order + to make the SVG files visible. Older versions of IE do not have SVG support. + +\anchor cfg_dot_path +<dt>\c DOT_PATH <dd> + \addindex DOT_PATH + This tag can be used to specify the path where the dot tool can be found. + If left blank, it is assumed the dot tool can be found on the path. + +\anchor cfg_dotfile_dirs +<dt>\c DOTFILE_DIRS <dd> + \addindex DOTFILE_DIRS + This tag can be used to specify one or more directories that + contain dot files that are included in the documentation (see the + \ref cmddotfile "\\dotfile" command). + +\anchor cfg_mscfile_dirs +<dt>\c MSCFILE_DIRS <dd> + \addindex MSCFILE_DIRS + This tag can be used to specify one or more directories that + contain msc files that are included in the documentation (see the + \ref cmdmscfile "\\mscfile" command). + +\anchor cfg_dot_transparent +<dt>\c DOT_TRANSPARENT <dd> + \addindex DOT_TRANSPARENT + Set the \c DOT_TRANSPARENT tag to \c YES to generate images with a transparent + background. This is disabled by default, because dot on Windows does not + seem to support this out of the box. Warning: Depending on the platform used, + enabling this option may lead to badly anti-aliased labels on the edges of + a graph (i.e. they become hard to read). + +\anchor cfg_dot_multi_targets +<dt>\c DOT_MULTI_TARGETS <dd> + \addindex DOT_MULTI_TARGET + Set the \c DOT_MULTI_TARGETS tag to \c YES allow dot to generate multiple output + files in one run (i.e. multiple -o and -T options on the command line). This + makes dot run faster, but since only newer versions of dot (>1.8.10) + support this, this feature is disabled by default. + +\anchor cfg_generate_legend +<dt>\c GENERATE_LEGEND <dd> + \addindex GENERATE_LEGEND + If the \c GENERATE_LEGEND tag is set to \c YES (the default) doxygen will + 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 +If the \c DOT_CLEANUP tag is set to \c YES (the default) doxygen will +remove the intermediate dot files that are used to generate the various graphs. + + +</dl> +<h2>Examples</h2> + +Suppose you have a simple project consisting of two files: a source file +\c example.cc and a header file \c example.h. +Then a minimal configuration file is as simple as: +\verbatim +INPUT = example.cc example.h +\endverbatim + +Assuming the example makes use of Qt classes and perl is located +in <code>/usr/bin</code>, a more realistic configuration file would be: +\verbatim +PROJECT_NAME = Example +INPUT = example.cc example.h +WARNINGS = YES +TAGFILES = qt.tag +PERL_PATH = /usr/local/bin/perl +SEARCHENGINE = NO +\endverbatim + +To generate the documentation for the +<a href="http://www.stack.nl/~dimitri/qdbttabular/index.html">QdbtTabular</a> package +I have used the following configuration file: +\verbatim +PROJECT_NAME = QdbtTabular +OUTPUT_DIRECTORY = html +WARNINGS = YES +INPUT = examples/examples.doc src +FILE_PATTERNS = *.cc *.h +INCLUDE_PATH = examples +TAGFILES = qt.tag +PERL_PATH = /usr/bin/perl +SEARCHENGINE = YES +\endverbatim + +To regenerate the Qt-1.44 documentation from the sources, you could use the +following config file: +\verbatim +PROJECT_NAME = Qt +OUTPUT_DIRECTORY = qt_docs +HIDE_UNDOC_MEMBERS = YES +HIDE_UNDOC_CLASSES = YES +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = YES +EXPAND_ONLY_PREDEF = YES +SEARCH_INCLUDES = YES +FULL_PATH_NAMES = YES +STRIP_FROM_PATH = $(QTDIR)/ +PREDEFINED = USE_TEMPLATECLASS Q_EXPORT= \ + QArrayT:=QArray \ + QListT:=QList \ + QDictT:=QDict \ + QQueueT:=QQueue \ + QVectorT:=QVector \ + QPtrDictT:=QPtrDict \ + QIntDictT:=QIntDict \ + QStackT:=QStack \ + QDictIteratorT:=QDictIterator \ + QListIteratorT:=QListIterator \ + QCacheT:=QCache \ + QCacheIteratorT:=QCacheIterator \ + QIntCacheT:=QIntCache \ + QIntCacheIteratorT:=QIntCacheIterator \ + QIntDictIteratorT:=QIntDictIterator \ + QPtrDictIteratorT:=QPtrDictIterator +INPUT = $(QTDIR)/doc \ + $(QTDIR)/src/widgets \ + $(QTDIR)/src/kernel \ + $(QTDIR)/src/dialogs \ + $(QTDIR)/src/tools +FILE_PATTERNS = *.cpp *.h q*.doc +INCLUDE_PATH = $(QTDIR)/include +RECURSIVE = YES +\endverbatim + +For the Qt-2.1 sources I recommend to use the following settings: +\verbatim +PROJECT_NAME = Qt +PROJECT_NUMBER = 2.1 +HIDE_UNDOC_MEMBERS = YES +HIDE_UNDOC_CLASSES = YES +SOURCE_BROWSER = YES +INPUT = $(QTDIR)/src +FILE_PATTERNS = *.cpp *.h q*.doc +RECURSIVE = YES +EXCLUDE_PATTERNS = *codec.cpp moc_* */compat/* */3rdparty/* +ALPHABETICAL_INDEX = YES +COLS_IN_ALPHA_INDEX = 3 +IGNORE_PREFIX = Q +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = YES +INCLUDE_PATH = $(QTDIR)/include +PREDEFINED = Q_PROPERTY(x)= \ + Q_OVERRIDE(x)= \ + Q_EXPORT= \ + Q_ENUMS(x)= \ + "QT_STATIC_CONST=static const " \ + _WS_X11_ \ + INCLUDE_MENUITEM_DEF +EXPAND_ONLY_PREDEF = YES +EXPAND_AS_DEFINED = Q_OBJECT_FAKE Q_OBJECT ACTIVATE_SIGNAL_WITH_PARAM \ + Q_VARIANT_AS +\endverbatim + +Here doxygen's preprocessor is used to substitute some +macro names that are normally substituted by the C preprocessor, +but without doing full macro expansion. + +*/ + diff --git a/trunk/doc/custcmd.doc b/trunk/doc/custcmd.doc new file mode 100644 index 0000000..06ef0d1 --- /dev/null +++ b/trunk/doc/custcmd.doc @@ -0,0 +1,125 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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 custcmd Custom Commands + +\tableofcontents + +Doxygen provides a large number of \ref commands "special commands", +\ref xmlcmds "XML commands", and \ref htmlcmds "HTML commands". +that can be used to enhance or structure the documentation inside a comment block. +If you for some reason have a need to define new commands you can do +so by means of an \e alias definition. + +The definition of an alias should be specified in the configuration file using +the \ref cfg_aliases "ALIASES" configuration tag. + +\section custcmd_simple Simple aliases +The simplest form of an alias is a simple substitution of the form +\verbatim + name=value +\endverbatim + For example defining the following alias: +\verbatim + ALIASES += sideeffect="\par Side Effects:\n" +\endverbatim + will allow you to + put the command \\sideeffect (or \@sideeffect) in the documentation, which + will result in a user-defined paragraph with heading <b>Side Effects:</b>. + +Note that you can put \\n's in the value part of an alias to insert newlines. + +Also note that you can redefine existing special commands if you wish. + +Some commands, such as \ref cmdxrefitem "\\xrefitem" are designed to be used in +combination with aliases. + +\section custcmd_complex Aliases with arguments +Aliases can also have one or more arguments. In the alias definition you then need +to specify the number of arguments between curly braces. In the value part of the +definition you can place \\x markers, where 'x' represents the argument number starting +with 1. + +Here is an example of an alias definition with a single argument: +\verbatim +ALIASES += l{1}="\ref \1" +\endverbatim + +Inside a comment block you can use it as follows +\verbatim +/** See \l{SomeClass} for more information. */ +\endverbatim +which would be the same as writing +\verbatim +/** See \ref SomeClass for more information. */ +\endverbatim + +Note that you can overload an alias by a version with multiple arguments, for instance: +\verbatim +ALIASES += l{1}="\ref \1" +ALIASES += l{2}="\ref \1 \"\2\"" +\endverbatim +Note that the quotes inside the alias definition have to be escaped with a backslash. + +With these alias definitions, we can write +\verbatim +/** See \l{SomeClass,Some Text} for more information. */ +\endverbatim +inside the comment block and it will expand to +\verbatim +/** See \ref SomeClass "Some Text" for more information. */ +\endverbatim +where the command with a single argument would still work as shown before. + +Aliases can also be expressed in terms of other aliases, e.g. a new command +\\reminder can be expressed as a \\xrefitem via an intermediate \\xreflist command +as follows: +\verbatim +ALIASES += xreflist{3}="\xrefitem \1 \"\2\" \"\3\" " \ +ALIASES += reminder="\xreflist{reminders,Reminder,Reminders}" \ +\endverbatim + +Note that if for aliases with more than one argument a comma is used as a separator, +if you want to put a comma inside the command, you will need to escape it with a backslash, +i.e. +\verbatim +\l{SomeClass,Some text\, with an escaped comma} +\endverbatim +given the alias definition of \\l in the example above. + +\section custcmd_nesting Nesting custom command + +You can use commands as arguments of aliases, including commands +defined using aliases. + +As an example consider the following alias definitions + +\verbatim +ALIASES += Bold{1}="<b>\1</b>" +ALIASES += Emph{1}="<em>\1</em>" +\endverbatim + +Inside a comment block you can now use: +\verbatim +/** This is a \Bold{bold \Emph{and} Emphasized} text fragment. */ +\endverbatim +which will expand to +\verbatim +/** This is a <b>bold <em>and</em> Emphasized</b> text fragment. */ +\endverbatim + + +*/ diff --git a/trunk/doc/customize.doc b/trunk/doc/customize.doc new file mode 100644 index 0000000..db376a8 --- /dev/null +++ b/trunk/doc/customize.doc @@ -0,0 +1,379 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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 customize Customizing the output + +\tableofcontents + +Doxygen provides various levels of customization. +The section \ref minor_tweaks "Minor Tweaks" discusses what to +do if you want to do minor tweaking to the look and feel of the output. +The section \ref layout "Layout" show how to reorder and hide certain +information on a page. +The section \ref xmlgenerator "XML output" show how to generate +whatever output you want based on the XML output produced by doxygen. + +\section minor_tweaks Minor Tweaks + +The next subsections describe some aspects that can be tweaked with +little effort. + +\subsection minor_tweaks_colors Overall Color + +To change the overall color of the HTML output doxygen provides three options +- \ref cfg_html_colorstyle_hue "HTML_COLORSTYLE_HUE" +- \ref cfg_html_colorstyle_sat "HTML_COLORSTYLE_SAT" +- \ref cfg_html_colorstyle_gamma "HTML_COLORSTYLE_GAMMA" + +to change the hue, saturation, and gamma correction of the colors respectively. + +For your convenience the GUI frontend \ref doxywizard_usage "Doxywizard" +has a control that allows you to see the effect of changing the values of these options +on the output in real time. + +\subsection minor_tweaks_treeview Navigation + +By default doxygen shows navigation tabs on top of every HTML page, +corresponding with the following settings: + +- \ref cfg_disable_index "DISABLE_INDEX" = \c NO +- \ref cfg_generate_treeview "GENERATE_TREEVIEW" = \c NO + +you can switch to an interactive navigation tree as sidebar using + +- \ref cfg_disable_index "DISABLE_INDEX" = \c YES +- \ref cfg_generate_treeview "GENERATE_TREEVIEW" = \c YES + +or even have both forms of navigation: + +- \ref cfg_disable_index "DISABLE_INDEX" = \c NO +- \ref cfg_generate_treeview "GENERATE_TREEVIEW" = \c YES + +if you already use an external index (i.e. have one of the following +options enabled +\ref cfg_generate_htmlhelp "GENERATE_HTMLHELP", +\ref cfg_generate_eclipsehelp "GENERATE_ECLIPSEHELP", +\ref cfg_generate_qhp "GENERATE_QHP", or +\ref cfg_generate_docset "GENERATE_DOCSET") +then you can also disable all indices, like so: + +- \ref cfg_disable_index "DISABLE_INDEX" = \c YES +- \ref cfg_generate_treeview "GENERATE_TREEVIEW" = \c NO + +\subsection minor_tweaks_dynsection Dynamic Content + +To make the HTML output more interactive, doxygen provides a number of options +that are disabled by default: +- enabling \ref cfg_html_dynamic_sections "HTML_DYNAMIC_SECTIONS" will make + doxygen hide certain content (like graphs) in the HTML by default, + and let the reader expand these sections on request. +- enabling \ref cfg_use_inline_trees "USE_INLINE_TREES" will make some + tree structures in the output dynamically expandable. +- enabling \ref cfg_have_dot "HAVE_DOT" along + with \ref cfg_interactive_svg "INTERACTIVE_SVG" while setting + \ref cfg_dot_image_format "DOT_IMAGE_FORMAT" to \c svg, will make doxygen + produce SVG images that will allow the user to zoom and pan (this only + happens when the size of the images exceeds a certain size). + +\subsection minor_tweaks_header_css Header, Footer, and Stylesheet changes + +To tweak things like fonts or colors, margins, or other look \& feel +aspects of the HTML output in detail, you can create a different +<a href="http://www.w3schools.com/css/default.asp">cascading style sheet</a>. +You can also let doxygen use a custom header and footer for each HTML +page it generates, for instance to make the output conform to the style +used on the rest of your web site. + +To do this first run doxygen as follows: +\verbatim +doxygen -w html header.html footer.html customdoxygen.css +\endverbatim + +This will create 3 files: +- header.html is a HTML fragment which doxygen normally uses to start + a HTML page. Note that the fragment ends with a body tag and that is + contains a couple of commands of the form \$word. These will be replaced + by doxygen on the fly. +- footer.html is a HTML fragment which doxygen normally uses to end + a HTML page. Also here special commands can be used. This file contain the + link to www.doxygen.org and the body and html end tags. +- customdoxygen.css is the default cascading style sheet + used by doxygen. + +You should edit these files and then reference them from the config file. +- \ref cfg_html_header "HTML_HEADER" = \c header.html +- \ref cfg_html_footer "HTML_FOOTER" = \c footer.html +- \ref cfg_html_stylesheet "HTML_STYLESHEET" = \c customdoxygen.css + +See the documentation of the \ref cfg_html_header "HTML_HEADER" tag +for more information about the possible meta commands you can use inside +your custom header. + +\note You should not put the style sheet in the HTML output directory. Treat +it as a source file. Doxygen will copy it for you. + +\note If you use images or other external content in a custom header you +need to make sure these end up in the HTML output directory yourself, +for instance by writing a script that runs doxygen can then copies the +images to the output. + +\warning The structure of headers and footers may change after upgrading to +a newer version of doxygen, so if you are using a custom header or footer, +it might not produce valid output anymore after upgrading. + +\section layout Changing the layout of pages + +In some cases you may want to change the way the output is structured. +A different style sheet or custom headers and footers do not help in such +case. + +The solution doxygen provides is a layout file, which you can +modify and doxygen will use to control what information is presented, +in which order, and to some extent also how information is presented. +The layout file is an XML file. + +The default layout can be generated +by doxygen using the following command: +\verbatim +doxygen -l +\endverbatim +optionally the name of the layout file can be specified, if omitted +\c DoxygenLayout.xml will be used. + +The next step is to mention the layout file in the config file +\verbatim +LAYOUT_FILE = DoxygenLayout.xml +\endverbatim +To change the layout all you need to do is edit the layout file. + +The toplevel structure of the file looks as follows: +\verbatim +<doxygenlayout version="1.0"> + <navindex> + ... + </navindex> + <class> + ... + </class> + <namespace> + ... + </namespace> + <file> + ... + </file> + <group> + ... + </group> + <directory> + ... + </directory> +</doxygenlayout> +\endverbatim + +The root element of the XML file is \c doxygenlayout, it has an attribute named +\c version, which will be used in the future to cope with changes that are +not backward compatible. + +The first section, identified by the \c navindex element, represents the +layout of the navigation tabs displayed at the top of each HTML page. At the +same time it also controls the items in the navigation tree in case +\ref cfg_generate_treeview "GENERATE_TREEVIEW" is enabled. +Each tab is represented by a \c tab element in the XML file. + +You can hide tabs by setting the \c visible attribute to \c no. +You can also override the default title of a tab by specifying it as +the value of the \c title attribute. If the title field is the empty string +(the default) then doxygen will fill in an appropriate language specific title. + +You can reorder the tabs by moving the tab elements in the XML file +within the \c navindex element and even change the tree structure. +Do not change the value of the \c type attribute however. +Only a fixed set of types are supported, each representing a link to a +specific index. + +You can also add custom tabs using a type with name "user". Here is an +example that shows how to add a tab with title "Google" pointing to +www.google.com: + +\verbatim + <navindex> + ... + <tab type="user" url="http://www.google.com" title="Google"/> + ... + </navindex> +\endverbatim + +The url field can also be a relative URL. If the URL starts with \@ref +the link will point to a documented entities, such as a class, a function, +a group, or a related page. Suppose we have defined a page using \@page with +label mypage, then a tab with label "My Page" to this page would look +as follows: + +\verbatim + <navindex> + ... + <tab type="user" url="@ref mypage" title="My Page"/> + ... + </navindex> +\endverbatim + +You can also group tabs together in a custom group using a tab with +type "usergroup". The following example puts the above tabs in a user +defined group with title "My Group": + +\verbatim + <navindex> + ... + <tab type="usergroup" title="My Group"> + <tab type="user" url="http://www.google.com" title="Google"/> + <tab type="user" url="@ref mypage" title="My Page"/> + </tab> + ... + </navindex> +\endverbatim + +Groups can be nested to form a hierarchy. + +The elements after \c navindex represent the layout of the different +pages generated by doxygen: +- The \c class element represents the layout of all pages generated for + documented classes, structs, unions, and interfaces. +- The \c namespace element represents the layout of all pages generated for + documented namespaces (and also Java packages). +- The \c file element represents the layout of all pages generated for + documented files. +- The \c group element represents the layout of all pages generated for + documented groups (or modules). +- The \c directory element represents the layout of all pages generated for + documented directories. + +Each XML element within one of the above page elements represents a certain +piece of information. Some pieces can appear in each type of page, +others are specific for a certain type of page. +Doxygen will list the pieces in the order in which they appear +in the XML file. + +The following generic elements are possible for each page: +<dl> +<dt>\c briefdescription + <dd>Represents the brief description on a page. +<dt>\c detaileddescription + <dd>Represents the detailed description on a page. +<dt>\c authorsection + <dd>Represents the author section of a page (only used for man pages). +<dt>\c memberdecl + <dd>Represents the quick overview of members on a page (member declarations). + This elements has child elements per type of member list. + The possible child elements are not listed in detail in the document, + but the name of the element should be a good indication of the type + of members that the element represents. +<dt>\c memberdef + <dd>Represents the detailed member list on a page (member definition). + Like the \c memberdecl element, also this element has a number of + possible child elements. +</dl> + +The class page has the following specific elements: +<dl> +<dt>\c includes + <dd>Represents the include file needed to obtain the definition for + this class. +<dt>\c inheritancegraph + <dd>Represents the inheritance relations for a class. + Note that the CLASS_DIAGRAM option determines + if the inheritance relation is a list of base and derived classes or + a graph. +<dt>\c collaborationgraph + <dd>Represents the collaboration graph for a class. +<dt>\c allmemberslink + <dd>Represents the link to the list of all members for a class. +<dt>\c usedfiles + <dd>Represents the list of files from which documentation for the class was + extracted. +</dl> + +The file page has the following specific elements: +<dl> +<dt>\c includes + <dd>Represents the list of \#include statements contained in this file. +<dt>\c includegraph + <dd>Represents the include dependency graph for the file. +<dt>\c includedbygraph + <dd>Represents the included by dependency graph for the file. +<dt>\c sourcelink + <dd>Represents the link to the source code of this file. +</dl> + +The group page has a specific \c groupgraph element which represents the +graph showing the dependencies between groups. + +Similarly, the directory page has a specific \c directorygraph element +which represents the graph showing the dependencies between the directories +based on the \#include relations of the files inside the directories. + +Some elements have a \c visible attribute which can be +used to hide the fragment from the generated output, by setting the attribute's +value to "no". You can also use the value of a configuration option to +determine the visibility, by using +its name prefixed with a dollar sign, e.g. +\verbatim + ... + <includes visible="$SHOW_INCLUDE_FILES"/> + ... +\endverbatim +This was mainly added for backward compatibility. +Note that the \c visible attribute is just a hint for doxygen. +If no relevant information is available for a certain piece it is +omitted even if it is set to \c yes (i.e. no empty sections are generated). + +Some elements have a \c title attribute. This attribute can be used +to customize the title doxygen will use as a header for the piece. + +@warning at the moment you should not remove elements from the layout file +as a way to hide information. Doing so can cause broken links in the +generated output! + + +\section xmlgenerator Using the XML output + +If the above two methods still do not provide enough flexibility, you +can also use the XML output produced by doxygen as a basis to +generate the output you like. To do this set GENERATE_XML to YES. + +The XML output consists of an index file named \c index.xml which +lists all items extracted by doxygen with references to the other XML files +for details. The structure of the index is described by a schema file +\c index.xsd. All other XML files are described by the schema file +named \c compound.xsd. If you prefer one big XML file +you can combine the index and the other files using the +XSLT file \c combine.xslt. + +You can use any XML parser to parse the file or use the one that can be found +in the \c addon/doxmlparser directory of doxygen source distribution. +Look at \c addon/doxmlparser/include/doxmlintf.h for the interface of the +parser and in \c addon/doxmlparser/example for examples. + +The advantage of using the doxmlparser is that it +will only read the index file into memory and then only those XML +files that you implicitly load via navigating through the index. As a +result this works even for very large projects where reading all XML +files as one big DOM tree would not fit into memory. + +See <a href="https://github.com/michaeljones/breathe">the Breathe project</a> for +a example that uses doxygen XML output from Python to bridge it with the +<a href="http://sphinx.pocoo.org/">Sphinx</a> document generator. + + */ diff --git a/trunk/doc/dbusxml.doc b/trunk/doc/dbusxml.doc new file mode 100644 index 0000000..e487126 --- /dev/null +++ b/trunk/doc/dbusxml.doc @@ -0,0 +1,149 @@ +/*! \page dbusxml DBus XML output format + +\addindex dbusxml + +<p>Doxygen can generate documentation for DBus XML files. This way +DBus interfaces can be annotated with doxygen style comments, and +without writing custom XML parsers. Doxygen extracts its text from +all XML comments starting with '*' or '!'. An additional '<' can be +used to assign the documentation string to the previous entity instead +of the one following the comment. + +Note that before the parsing of DBus XML file works one has to +assign the .xml extension to the DBus XML parser using the +following configuration option: + +\verbatim +EXTENSION_MAPPING = xml=dbusxml +\endverbatim + +\section dbusxml_supported Supported XML elements and attributes + +<p>The following DBus XML elemets can be annotated: + +<ul> +<li><b>interface</b> + +<li><b>method</b> or <b>signal</b> + +<li><b>arg</b> + +<li><b>property</b> + +</ul> + +Additional elements are supported. These are available once +the xmlns "http://psiamp.org/dtd/doxygen_dbusxml.dtd" is +available. + +<ul> +<li><b>namespace</b>: This can be used to group other more of the +additional elemets. This element requires a <b>name</b> attribute. + +<li><b>enum</b> is used to define enums. <b>value</b> element is + then used to define the individual values in the enum. This element + requires the <b>name</b> and <b>type</b> attributes. A + optional <b>named-type</b> attribute is allowed, referrencing typed + previously defined by one of the additional elements. A enum name + can be used anywhere a type is required using the <b>named-type</b> + attribute. + +<li><b>flagset</b> is used to define sets of flags. Required and + optional attributes are identical to the ones used by <b>enum</b>. + While <b>enum</b>s assume the values to be consecutive, while + a <b>flagset</b> is values suitable for flags. A flagset name + can be used anywhere a type is required using the <b>named-type</b> + attribute. + +<li><b>struct</b> is used to define structures. A <b>name</b> + attribute is required. + +<li><b>member</b> is used to define members of <b>structs</b>. It + is valid inside <b>struct</b> elements. This + element requires <b>name</b> and <b>type</b> attributes. In + addition to (or even instead of) the <b>type</b> attribute a + <b>named-type</b> attribute may be used to reference types defined + by <b>enum</b>, <b>flagset</b> or <b>struct</b>. + +\section dbusxml_example Example + +<pre> +<?xml version="1.0" ?> +<!-- Comment --> +<!--*< File comment --> +<node name="/SomeNode" xmlns:dx="http://psiamp.org/dtd/doxygen_dbusxml.dtd"> + <!--* test struct outside a namespace and interface --> + <dx:struct name="StructOutsideNamespace"> + <!--* member 1 --> + <dx:member name="member1" type="s"/> + <!--* complex member 1 --> + <dx:member name="complexMember1" type="(ssu)"/> + </dx:struct> + + <!--* Test flag set --> + <dx:flagset name="flagset"> + <!--* Flag 1 of flagset. --> + <dx:value name="FLAG1"/> + </dx:flagset> + + <!--* namespace comment --> + <dx:namespace name="SomeNamespace"> + <!--* struct inside a namespace --> + <dx:struct name="StructInNamespace"> + <!--* member 2 --> + <dx:member name="member2" type="s"/> + </dx:struct> + </dx:namespace> + <!--* Documentation on the interface --> + <interface name="nl.stack.doxygen.test.interface"> + <!--* Test Enum documentation --> + <dx:enum name="TestEnum"> + <!--* key 1 with value 13 --> + <dx:value name="KEY1" value="13"/> + <!--* key 2 without a value --> + <dx:value name="KEY2"/> + </dx:enum> + + <!--* struct inside a interface --> + <dx:struct name="StructInInterface"> + <!--* member 3 --> + <dx:member name="member3" type="s"/> + <!--* Struct in a struct --> + <dx:struct name="StructInAStruct"> + <!--* member4 --> + <dx:member name="member4" type="s"/> + </dx:struct> + <!--* struct member --> + <dx:member name="structMembor" type="(s)" named-type="StructInAStruct"/> + </dx:struct> + <!--* Document method + + Some extended documentation for the method. + + @param[in] input blah. + @param[out] output blub + --> + <method name="method"> + <arg direction="in" name="input" type="(s(s))" named-type="::nl::stack::doxygen::test::interface::StructInInterface"/> + <arg direction="out" type="v" name="output"/> + </method> + + <signal name="signal"> + <!--*< Documentation for signal. + + @param parameter some parameter. + --> + <arg name="parameter" type="s"/> + </signal> + + <!--* property documentation --> + <property name="property" type="s" access="readwrite"/> + + <!--* property documentation read-only --> + <property name="propertyRead" type="s" access="read"/> + <!--* property documentation write-only --> + <property name="propertyWrite" type="s" access="write"/> + </interface> +</node> +</pre> +*/ diff --git a/trunk/doc/diagrams.doc b/trunk/doc/diagrams.doc new file mode 100644 index 0000000..7d488fa --- /dev/null +++ b/trunk/doc/diagrams.doc @@ -0,0 +1,148 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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 diagrams Graphs and diagrams + + Doxygen has built-in support to generate inheritance diagrams for C++ + classes. + + Doxygen can use the "dot" tool from graphviz to generate + more advanced diagrams and graphs. Graphviz is an open-source, + cross-platform graph drawing toolkit and can be found + at http://www.graphviz.org/ + + If you have the "dot" tool in the path, you can set + \ref cfg_have_dot "HAVE_DOT" to \c YES in the configuration file to + let doxygen use it. + + Doxygen uses the "dot" tool to generate the following graphs: + <ul> + <li>A graphical representation of the class hierarchy will be drawn, along + with the textual one. Currently this feature is supported for HTML only.\n + <b>Warning:</b> When you have a very large class hierarchy where many + classes derive from a common base class, the resulting image may become + too big to handle for some browsers. + <li>An inheritance graph will be generated for each documented class showing the + direct and indirect inheritance relations. This disables the + generation of the built-in class inheritance diagrams. + <li>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 only. + <li>An inverse include dependency graph is also generated showing for + a (header) file, which other files include it. + <li>A graph is drawn for each documented class and struct that shows: + <ul> + <li> the inheritance relations with base classes. + <li> the usage relations with other structs and classes (e.g. + class \c A has a member variable \c m_a of type class \c B, then + \c A has an arrow to \c B with \c m_a as label). + </ul> + <li>if \ref cfg_call_graph "CALL_GRAPH" is set to YES, a + graphical call graph is drawn for each function showing the + functions that the function directly or indirectly calls. + <li>if \ref cfg_caller_graph "CALLER_GRAPH" is set to YES, a + graphical caller graph is drawn for each function showing the + functions that the function is directly or indirectly called by. + </ul> + + Using a \ref customize "layout file" you can determine which of the + graphs are actually shown. + + The options \ref cfg_dot_graph_max_nodes "DOT_GRAPH_MAX_NODES" and + \ref cfg_max_dot_graph_depth "MAX_DOT_GRAPH_DEPTH" can be used to + limit the size of the various graphs. + + The elements in the class diagrams in HTML and RTF + have the following meaning: + <ul> + <li> A \b yellow box indicates a class. A box can have a + little marker in the lower right corner to indicate that the class + contains base classes that are hidden. + For the class diagrams the maximum tree width is currently 8 elements. + If a tree is wider some nodes will be hidden. + If the box is filled with a + dashed pattern the inheritance relation is virtual. + <li> A \b white box indicates that the documentation of the class + is currently shown. + <li> A \b gray box indicates an undocumented class. + <li> A <b>solid dark blue</b> arrow indicates public inheritance. + <li> A <b>dashed dark green</b> arrow indicates protected inheritance. + <li> A <b>dotted dark green</b> arrow indicates private inheritance. + </ul> + + The elements in the class diagram in \f$\mbox{\LaTeX}\f$ have the + following meaning: + <ul> + <li> A \b white box indicates a class. + A \b marker in the lower right corner of the box indicates that the + class has base classes that are hidden. + If the box has a \b dashed border this indicates virtual inheritance. + <li> A \b solid arrow indicates public inheritance. + <li> A \b dashed arrow indicates protected inheritance. + <li> A \b dotted arrow indicates private inheritance. + </ul> + + The elements in the graphs generated by the dot tool have the following + meaning: + <ul> + <li> A \b white box indicates a class or struct or file. + <li> A box with a \b red border indicates a node that has + \e more arrows than are shown! + In other words: the graph is \e truncated with respect to this node. + The reason why a graph is sometimes truncated is to prevent images + from becoming too large. + For the graphs generated with dot doxygen tries + to limit the width of the resulting image to 1024 pixels. + <li> A \b black box indicates that the class' documentation is currently shown. + <li> A <b>dark blue</b> arrow indicates an include relation (for the + include dependency graph) or public inheritance (for the other graphs). + <li> A <b>dark green</b> arrow indicates protected inheritance. + <li> A <b>dark red</b> arrow indicates private inheritance. + <li> A <b>purple dashed</b> arrow indicated a "usage" relation, the + edge of the arrow is labeled with the variable(s) responsible for the + relation. + Class \c A uses class \c B, if class \c A has a member variable \c m + of type C, where B is a subtype of C (e.g. `C` could be `B`, `B*`, `T\<B\>*`). + </ul> + + +Here are a couple of header files that together show the various diagrams +that doxygen can generate: + +<code>diagrams_a.h</code> +\verbinclude diagrams_a.h +<code>diagrams_b.h</code> +\verbinclude diagrams_b.h +<code>diagrams_c.h</code> +\verbinclude diagrams_c.h +<code>diagrams_d.h</code> +\verbinclude diagrams_d.h +<code>diagrams_e.h</code> +\verbinclude diagrams_e.h + + \htmlonly + Click <a href="$(DOXYGEN_DOCDIR)/examples/diagrams/html/index.html">here</a> + for the corresponding HTML documentation that is generated by doxygen<br/> + (<code>EXTRACT_ALL</code> = <code>YES</code> is used here). + \endhtmlonly + +\htmlonly +Go to the <a href="preprocessing.html">next</a> section or return to the + <a href="index.html">index</a>. +\endhtmlonly + +*/ + diff --git a/trunk/doc/docblocks.doc b/trunk/doc/docblocks.doc new file mode 100644 index 0000000..facd1b5 --- /dev/null +++ b/trunk/doc/docblocks.doc @@ -0,0 +1,600 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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 docblocks Documenting the code +\tableofcontents + +This chapter covers two topics: +1. How to put comments in your code such that doxygen incorporates them in + the documentation it generates. + This is further detailed in the \ref specialblock "next section". +2. Ways to structure the contents of a comment block such that the output + looks good, as explained in section \ref docstructure. + +\section specialblock Special comment blocks + +A special comment block is a C or C++ style comment block with some +additional markings, so doxygen knows it is a piece of structured text that +needs to end up in the generated documentation. The \ref cppblock "next" section +presents the various styles supported by doxygen. + +For Python, VHDL, Fortran, and Tcl code there are different commenting +conventions, which can be found in sections \ref pythonblocks, \ref vhdlblocks, +\ref fortranblocks, and \ref tclblocks respectively. + +\subsection cppblock Comment blocks for C-like languages (C/C++/C#/Objective-C/PHP/Java) + +For each entity in the code there are two (or in some cases three) types of descriptions, +which together form the documentation for that entity; a *brief* description and *detailed* +description, both are optional. For methods and functions there is also a third +type of description, the so called *in body* description, which consists of +the concatenation of all comment blocks found within the body of the method or function. + +Having more than one brief or detailed description is allowed (but not recommended, +as the order in which the descriptions will appear is not specified). + +As the name suggest, a brief description is +a short one-liner, whereas the detailed description provides longer, +more detailed documentation. An "in body" description can also act as a detailed +description or can describe a collection of implementation details. +For the HTML output brief descriptions are also +used to provide tooltips at places where an item is referenced. + +There are several ways to mark a comment block as a detailed description: +<ol> +<li> You can use the JavaDoc style, which consist of a C-style comment +block starting with two *'s, like this: + +\verbatim +/** + * ... text ... + */ +\endverbatim + +<li> or you can use the Qt style and add an exclamation mark (!) +after the opening of a C-style comment block, as shown in this example: + +\verbatim +/*! + * ... text ... + */ +\endverbatim + +In both cases the intermediate *'s are optional, so + +\verbatim +/*! + ... text ... +*/ +\endverbatim + +is also valid. + +<li> A third alternative is to use a block of <i>at least two</i> C++ comment +lines, where each line starts with an additional slash or an +exclamation mark. Here are examples of the two cases: + +\verbatim +/// +/// ... text ... +/// +\endverbatim + +or + +\verbatim +//! +//!... text ... +//! +\endverbatim + +Note that a blank line ends a documentation block in this case. + +<li> + +Some people like to make their comment blocks more visible in the +documentation. For this purpose you can use the following: + +\verbatim +/********************************************//** + * ... text + ***********************************************/ +\endverbatim +(note the 2 slashes to end the normal comment block and start a special comment block). + +or + +\verbatim +///////////////////////////////////////////////// +/// ... text ... +///////////////////////////////////////////////// +\endverbatim + +</ol> + +For the brief description there are also several possibilities: +<ol> +<li>One could use the \ref cmdbrief "\\brief" command with one of the +above comment blocks. This command ends at the end of a paragraph, +so the detailed description follows after an empty line. + +Here is an example: + +\verbatim +/*! \brief Brief description. + * Brief description continued. + * + * Detailed description starts here. + */ +\endverbatim + +<li>If \ref cfg_javadoc_autobrief "JAVADOC_AUTOBRIEF" is set to \c YES + in the configuration file, + then using JavaDoc style comment + blocks will automatically start a brief description which ends at the + first dot followed by a space or new line. Here is an example: + +\verbatim +/** Brief description which ends at this dot. Details follow + * here. + */ +\endverbatim +The option has the same effect for multi-line special C++ comments: +\verbatim +/// Brief description which ends at this dot. Details follow +/// here. +\endverbatim + +<li>A third option is to use a special C++ style comment which does not + span more than one line. Here are two examples: +\verbatim +/// Brief description. +/** Detailed description. */ +\endverbatim + +or + +\verbatim +//! Brief description. + +//! Detailed description +//! starts here. +\endverbatim + +Note the blank line in the last example, which is required to separate the +brief description from the block containing the detailed description. The +\ref cfg_javadoc_autobrief "JAVADOC_AUTOBRIEF" should also be set to \c NO +for this case. + +</ol> + +As you can see doxygen is quite flexible. If you have multiple +detailed descriptions, like in the following example: + +\verbatim +//! Brief description, which is +//! really a detailed description since it spans multiple lines. +/*! Another detailed description! + */ +\endverbatim + +They will be joined. Note that this is also the case if the descriptions +are at different places in the code! In this case the order will depend +on the order in which doxygen parses the code. + + +Unlike most other documentation systems, doxygen also allows you to put +the documentation of members (including global functions) in front of +the \e definition. This way the documentation can be placed in the source +file instead of the header file. This keeps the header file compact, and allows the +implementer of the members more direct access to the documentation. +As a compromise the brief description could be placed before the +declaration and the detailed description before the member definition. + +\subsubsection memberdoc Putting documentation after members + +If you want to document the members of a file, struct, union, class, or enum, +it is sometimes desired to place the documentation block after the member +instead of before. For this purpose you have to put an additional \< marker +in the comment block. Note that this also works for the parameters +of a function. + +Here are some examples: +\verbatim +int var; /*!< Detailed description after the member */ +\endverbatim +This block can be used to put a Qt style detailed +documentation block \e after a member. Other ways to do the +same are: +\verbatim +int var; /**< Detailed description after the member */ +\endverbatim +or +\verbatim +int var; //!< Detailed description after the member + //!< +\endverbatim +or +\verbatim +int var; ///< Detailed description after the member + ///< +\endverbatim + +Most often one only wants to put a brief description after a member. +This is done as follows: +\verbatim +int var; //!< Brief description after the member +\endverbatim +or +\verbatim +int var; ///< Brief description after the member +\endverbatim + +For functions one can use the \ref cmdparam "\@param" command to document the parameters +and then use <code>[in]</code>, <code>[out]</code>, <code>[in,out]</code> +to document the direction. For inline documentation this is also possible +by starting with the direction attribute, e.g. +\verbatim +void foo(int v /**< [in] docs for input parameter v. */); +\endverbatim + +Note that these blocks have the same structure and meaning as the +special comment blocks in the previous section +only the \< indicates that the member is +located in front of the block instead of after the block. + +Here is an example of the use of these comment blocks: +\include afterdoc.h + \htmlonly + Click <a href="$(DOXYGEN_DOCDIR)/examples/afterdoc/html/class_test.html">here</a> + for the corresponding HTML documentation that is generated by doxygen. + \endhtmlonly + +\warning These blocks can only be used to document \e members and \e parameters. + They cannot be used to document files, classes, unions, structs, + groups, namespaces and enums themselves. Furthermore, the structural + commands mentioned in the next section + (like <code>\\class</code>) are not allowed + inside these comment blocks. + +\subsubsection docexamples Examples + +Here is an example of a documented piece of C++ code using the Qt style: +\include qtstyle.cpp + \htmlonly + Click <a href="$(DOXYGEN_DOCDIR)/examples/qtstyle/html/class_test.html">here</a> + for the corresponding HTML documentation that is generated by doxygen. + \endhtmlonly + +The brief descriptions are included in the member overview of a +class, namespace or file and are printed using a small italic font +(this description can be hidden by setting +\ref cfg_brief_member_desc "BRIEF_MEMBER_DESC" to \c NO in +the config file). By default the brief descriptions become the first +sentence of the detailed descriptions +(but this can be changed by setting the \ref cfg_repeat_brief "REPEAT_BRIEF" +tag to \c NO). Both the brief and the detailed descriptions are optional +for the Qt style. + +By default a JavaDoc style documentation block behaves the same way as a +Qt style documentation block. This is not according the JavaDoc specification +however, where the first sentence of the documentation block is automatically +treated as a brief description. To enable this behavior you should set +\ref cfg_javadoc_autobrief "JAVADOC_AUTOBRIEF" to YES in the configuration +file. If you enable this option and want to put a dot in the middle of a +sentence without ending it, you should put a backslash and a space after it. +Here is an example: +\verbatim + /** Brief description (e.g.\ using only a few words). Details follow. */ +\endverbatim + +Here is the same piece of code as shown above, this time documented using the +JavaDoc style and \ref cfg_javadoc_autobrief "JAVADOC_AUTOBRIEF" set to YES: +\include jdstyle.cpp + \htmlonly + Click <a href="$(DOXYGEN_DOCDIR)/examples/jdstyle/html/class_test.html">here</a> + for the corresponding HTML documentation that is generated by doxygen. + \endhtmlonly + +Similarly, if one wishes the first sentence of a Qt style documentation +block to automatically be treated as a brief description, one may set +\ref cfg_qt_autobrief "QT_AUTOBRIEF" to YES in the configuration file. + +\subsubsection structuralcommands Documentation at other places + +In the examples in the previous section the comment blocks were always located *in +front* of the declaration or definition of a file, class or namespace or *in +front* or *after* one of its members. +Although this is often comfortable, there may sometimes be reasons to put the +documentation somewhere else. For documenting a file this is even +required since there is no such thing as "in front of a file". + +Doxygen allows you to put your documentation blocks practically +anywhere (the exception is inside the body of a function or inside a +normal C style comment block). + +The price you pay for not putting the +documentation block directly before (or after) an item is the need to put a +structural command inside the documentation block, which leads to some +duplication of information. So in practice you should \e avoid the use of +structural commands \e unless other requirements force you to do so. + +Structural commands (like \ref cmd_intro "all other commands") start with a backslash +(<tt>\\</tt>), or an at-sign (<tt>\@</tt>) if you prefer JavaDoc style, +followed by a command name and one or more parameters. +For instance, if you want to document the class \c Test in the example +above, you could have also put the following documentation block somewhere +in the input that is read by doxygen: +\verbatim +/*! \class Test + \brief A test class. + + A more detailed class description. +*/ +\endverbatim + +Here the special command \c \\class is used to indicate that the +comment block contains documentation for the class \c Test. +Other structural commands are: +<ul> +<li>\c \\struct to document a C-struct. +<li>\c \\union to document a union. +<li>\c \\enum to document an enumeration type. +<li>\c \\fn to document a function. +<li>\c \\var to document a variable or typedef or enum value. +<li>\c \\def to document a \#define. +<li>\c \\typedef to document a type definition. +<li>\c \\file to document a file. +<li>\c \\namespace to document a namespace. +<li>\c \\package to document a Java package. +<li>\c \\interface to document an IDL interface. +</ul> +See section \ref commands for detailed information about these and many other +commands. + +To document a member of a C++ class, you must also document the class +itself. The same holds for namespaces. To document a global C function, +typedef, enum or preprocessor definition you must first document the file +that contains it (usually this will be a header file, because that file +contains the information that is exported to other source files). + +Let's repeat that, because it is often overlooked: +to document global objects (functions, typedefs, enum, macros, etc), you +<em>must</em> document the file in which they are defined. In other words, +there <em>must</em> at least be a \verbatim /*! \file */ \endverbatim +or a \verbatim /** @file */ \endverbatim line in this file. + +Here is an example of a C header named \c structcmd.h that is documented +using structural commands: +\include structcmd.h + \htmlonly + Click <a href="$(DOXYGEN_DOCDIR)/examples/structcmd/html/structcmd_8h.html">here</a> + for the corresponding HTML documentation that is generated by doxygen. + \endhtmlonly + + Because each comment block in the example above contains a structural command, all + the comment blocks could be moved to another location or input file + (the source file for instance), without affecting the generated + documentation. The disadvantage of this approach is that prototypes are + duplicated, so all changes have to be made twice! Because of this you + should first consider if this is really needed, and avoid structural + commands if possible. I often receive examples that contain \\fn command + in comment blocks which are place in front of a function. This is clearly + a case where the \\fn command is redundant and will only lead to problems. + +\subsection pythonblocks Comment blocks in Python + +For Python there is a standard way of documenting the code using +so called documentation strings. Such strings are stored in \c __doc__ +and can be retrieved at runtime. Doxygen will extract such comments +and assume they have to be represented in a preformatted way. + +\include docstring.py + \htmlonly + Click <a href="$(DOXYGEN_DOCDIR)/examples/docstring/html/index.html">here</a> + for the corresponding HTML documentation that is generated by doxygen. + \endhtmlonly + +Note that in this case none of doxygen's \ref cmd_intro "special commands" +are supported. + +There is also another way to document Python code using comments that +start with "##". These type of comment blocks are more in line with the +way documentation blocks work for the other languages supported by doxygen +and this also allows the use of special commands. + +Here is the same example again but now using doxygen style comments: + +\include pyexample.py + \htmlonly + Click <a href="$(DOXYGEN_DOCDIR)/examples/pyexample/html/index.html">here</a> + for the corresponding HTML documentation that is generated by doxygen. + \endhtmlonly + +Since python looks more like Java than like C or C++, you should set +\ref cfg_optimize_output_java "OPTIMIZE_OUTPUT_JAVA" to \c YES in the +config file. + + +\htmlonly +Go to the <a href="lists.html">next</a> section or return to the + <a href="index.html">index</a>. +\endhtmlonly + +\subsection vhdlblocks Comment blocks in VHDL + +For VHDL a comment normally start with "--". Doxygen will extract comments +starting with "--!". There are only two types of comment blocks in VHDL; +a one line --! comment representing a brief description, and a multi-line +--! comment (where the --! prefix is repeated for each line) representing +a detailed description. + +Comments are always located in front of the item that is being documented +with one exception: for ports the comment can also be after the item +and is then treated as a brief description for the port. + +Here is an example VHDL file with doxygen comments: + +\include mux.vhdl + \htmlonly + Click <a href="$(DOXYGEN_DOCDIR)/examples/mux/html/index.html">here</a> + for the corresponding HTML documentation that is generated by doxygen. + \endhtmlonly + +To get proper looking output you need to set +\ref cfg_optimize_output_vhdl "OPTIMIZE_OUTPUT_VHDL" to \c YES in the +config file. This will also affect a number of other settings. When they +were not already set correctly doxygen will produce a warning telling which +settings where overruled. + +\subsection fortranblocks Comment blocks in Fortran + +When using doxygen for Fortran code you should +set \ref cfg_optimize_for_fortran "OPTIMIZE_FOR_FORTRAN" to \c YES. + +For Fortran "!>" or "!<" starts a comment and "!!" or "!>" can be used to +continuate a one line comment into a multi-line comment. + +Here is an example of a documented Fortran subroutine: +\verbatim + !> Build the restriction matrix for the aggregation + !! method. + !! @param aggr information about the aggregates + !! @todo Handle special case + subroutine IntRestBuild(A,aggr,Restrict,A_ghost) + implicit none + Type(SpMtx), intent(in) :: A !< our fine level matrix + Type(Aggrs), intent(in) :: aggr + Type(SpMtx), intent(out) :: Restrict !< Our restriction matrix +\endverbatim + +As a alternative you can also use comments in fixed format code: + +\verbatim +C> Function comment +C> another line of comment + function A(i) +C> input parameter + integer i + end function A +\endverbatim + +\subsection tclblocks Comment blocks in Tcl + +Doxygen documentation can be included in normal Tcl comments. + +To start a new documentation block start a line with \c ## (two hashes). +All following comment lines and continuation lines will be added to this +block. The block ends with a line not starting with a \c # (hash sign). + +A brief documentation can be added with \c ;#< (semicolon, hash and +lower then sign). The brief documentation also ends at a line not starting +with a \c # (hash sign). + +Inside doxygen comment blocks all normal doxygen markings are supported. +The only exceptions are described in the following two paragraphs. + +If a doxygen comment block ends with a line containing only +\c #\\code or \c #\@code all code until a line only containing \c #\\endcode +or \c #\@endcode is added to the generated documentation as code block. + +If a doxygen comment block ends with a line containing only +\c #\\verbatim or \c #\@verbatim all code until a line only containing +\c #\\endverbatim or \c #\@endverbatim is added verbatim to the generated +documentation. + +To detect namespaces, classes, functions and variables the following +Tcl commands are recognized. Documentation blocks can be put on the lines +before the command. + +<ul> +<li><tt>namespace eval ..</tt> Namespace +<li><tt>proc ..</tt> Function +<li><tt>variable ..</tt> Variable +<li><tt>common ..</tt> Common variable +<li><tt>itcl::class ..</tt> Class +<li><tt>itcl::body ..</tt> Class method body definition +<li><tt>oo::class create ..</tt> Class +<li><tt>oo::define ..</tt> OO Class definition +<li><tt>method ..</tt> Class method definitions +<li><tt>constructor ..</tt> Class constructor +<li><tt>destructor ..</tt> Class destructor +<li><tt>public ..</tt> Set protection level +<li><tt>protected ..</tt> Set protection level +<li><tt>private ..</tt> Set protection level +</ul> + +<!-- +To use your own keywords you an map these keyword to the recognized commands +using the \ref cfg_tcl_subs "TCL_SUBST" entry in the config file. +The entry contain a list of word-keyword mappings. To use the itcl::* +commands without the leading namespace use p.e.: + +\verbatim TCL_SUBST = class itcl:class body itcl:body \endverbatim +--> + +Following is a example using doxygen style comments: + +\include tclexample.tcl + \htmlonly + Click <a href="$(DOXYGEN_DOCDIR)/examples/tclexample/html/index.html">here</a> + for the corresponding HTML documentation that is generated by doxygen. + \endhtmlonly + +\htmlonly +Go to the <a href="lists.html">next</a> section or return to the + <a href="index.html">index</a>. +\endhtmlonly + +\section docstructure Anatomy of a comment block + +The previous section focused on how to make the comments in your code known +to doxygen, it explained the difference between a brief and a detailed description, and +the use of structural commands. + +In this section we look at the contents of the comment block itself. + +Doxygen supports various styles of formatting your comments. + +The simplest form is to use plain text. This will appear as-is in the output +and is ideal for a short description. + +For longer descriptions you often will find the +need for some more structure, like a block of verbatim text, a list, or a +simple table. For this doxygen supports the +<a href="http://daringfireball.net/projects/markdown/syntax">Markdown</a> +syntax, including parts of the +<a href="http://michelf.com/projects/php-markdown/extra/">Markdown Extra</a> +extension. + +Markdown is designed to be very easy to read and write. +It's formatting is inspired by plain text mail. +Markdown works great for simple, generic formatting, like an introduction +page for your project. Doxygen also supports reading of markdown files +directly. See \ref markdown "here" for more details regards Markdown support. + +For programming language specific formatting doxygen has two +forms of additional markup on top of Markdown formatting. + +1. <a href="http://en.wikipedia.org/wiki/Javadoc">Javadoc</a> like markup. + See \ref cmd_intro "here" for a complete overview of all commands supported by doxygen. +2. <a href="http://en.wikipedia.org/wiki/C_Sharp_(programming_language)#XML_documentation_system">XML</a> markup + as specified in the C# standard. See \ref xmlcmds "here" for the XML commands supported by doxygen. + +If this is still not enough doxygen also supports a \ref htmlcmds "subset" of +the <a href="http://en.wikipedia.org/wiki/HTML">HTML</a> markup language. + +*/ diff --git a/trunk/doc/doxygen.1 b/trunk/doc/doxygen.1 new file mode 100644 index 0000000..45090f4 --- /dev/null +++ b/trunk/doc/doxygen.1 @@ -0,0 +1,46 @@ +.TH DOXYGEN "1" "DATE" "doxygen VERSION" "User Commands" +.SH NAME +doxygen \- documentation system for various programming languages +.SH DESCRIPTION +Doxygen is a documentation system for C++, C, Java, Objective-C, IDL +(Corba and Microsoft flavors) and to some extent PHP, C#, and D. +.PP +You can use doxygen in a number of ways: +.TP +1) Use doxygen to generate a template configuration file: +.IP +doxygen [-s] \fB\-g\fR [configName] +.IP +If - is used for configName doxygen will write to standard output. +.TP +2) Use doxygen to update an old configuration file: +.IP +doxygen [-s] \fB\-u\fR [configName] +.TP +3) Use doxygen to generate documentation using an existing configuration file: +.IP +doxygen [configName] +.IP +If - is used for configName doxygen will read from standard input. +.TP +4) Use doxygen to generate a template style sheet file for RTF, HTML or Latex. +.TP +RTF: +doxygen \fB\-w\fR rtf styleSheetFile +.TP +HTML: +doxygen \fB\-w\fR html headerFile footerFile styleSheetFile [configFile] +.TP +LaTeX: doxygen \fB\-w\fR latex headerFile footerFile styleSheetFile [configFile] +.TP +5) Use doxygen to generate an rtf extensions file +.TP +RTF: +doxygen \fB\-e\fR rtf extensionsFile +.PP +If \fB\-s\fR is specified the comments in the config file will be omitted. +If configName is omitted `Doxyfile' will be used as a default. +.SH AUTHOR +Doxygen version VERSION, Copyright Dimitri van Heesch 1997-2012 +.SH SEE ALSO +doxywizard(1). diff --git a/trunk/doc/doxygen.sty b/trunk/doc/doxygen.sty new file mode 100644 index 0000000..c64fb09 --- /dev/null +++ b/trunk/doc/doxygen.sty @@ -0,0 +1,482 @@ +\NeedsTeXFormat{LaTeX2e} +\ProvidesPackage{doxygen} + +% Packages used by this style file +\RequirePackage{alltt} +\RequirePackage{array} +\RequirePackage{calc} +\RequirePackage{color} +\RequirePackage{fancyhdr} +\RequirePackage{longtable} +\RequirePackage{verbatim} +\RequirePackage{ifthen} +\RequirePackage[table]{xcolor} + +% Use helvetica font instead of times roman +\RequirePackage{helvet} +\RequirePackage{sectsty} +\RequirePackage{tocloft} +\providecommand{\rmdefault}{phv} +\providecommand{\bfdefault}{bc} + + +% Setup fancy headings +\pagestyle{fancyplain} +\newcommand{\clearemptydoublepage}{% + \newpage{\pagestyle{empty}\cleardoublepage}% +} +\renewcommand{\chaptermark}[1]{% + \markboth{#1}{}% +} +\renewcommand{\sectionmark}[1]{% + \markright{\thesection\ #1}% +} +\fancyhead[LE]{\fancyplain{}{\bfseries\thepage}} +\fancyhead[CE]{\fancyplain{}{}} +\fancyhead[RE]{\fancyplain{}{\bfseries\leftmark}} +\fancyhead[LO]{\fancyplain{}{\bfseries\rightmark}} +\fancyhead[CO]{\fancyplain{}{}} +\fancyhead[RO]{\fancyplain{}{\bfseries\thepage}} +\fancyfoot[LE]{\fancyplain{}{}} +\fancyfoot[CE]{\fancyplain{}{}} +\fancyfoot[RE]{\fancyplain{}{\bfseries\scriptsize Generated by Doxygen }} +\fancyfoot[LO]{\fancyplain{}{\bfseries\scriptsize Generated by Doxygen }} +\fancyfoot[CO]{\fancyplain{}{}} +\fancyfoot[RO]{\fancyplain{}{}} +%---------- Internal commands used in this style file ---------------- + +\newcommand\tabfill[1]{% + \dimen@\linewidth% + \advance\dimen@\@totalleftmargin% + \advance\dimen@-\dimen\@curtab% + \parbox[t]\dimen@{\raggedright #1\ifhmode\strut\fi}% +} + +\newcommand{\ensurespace}[1]{% + \begingroup + \setlength{\dimen@}{#1}% + \vskip\z@\@plus\dimen@ + \penalty -100\vskip\z@\@plus -\dimen@ + \vskip\dimen@ + \penalty 9999% + \vskip -\dimen@ + \vskip\z@skip % hide the previous |\vskip| from |\addvspace| + \endgroup +} + +% Generic environment used by all paragraph-based environments defined +% below. Note that the command \title{...} needs to be defined inside +% those environments! +\newenvironment{DoxyDesc}[1]{% + \ensurespace{4\baselineskip}% + \begin{list}{}% + {% + \settowidth{\labelwidth}{40pt}% + \setlength{\leftmargin}{\labelwidth}% + \setlength{\parsep}{0pt}% + \setlength{\itemsep}{-4pt}% + \renewcommand{\makelabel}{\entrylabel}% + }% + \item[#1]% +}{% + \end{list}% +} + +%---------- Commands used by doxygen LaTeX output generator ---------- + +% Used by <pre> ... </pre> +\newenvironment{DoxyPre}{% + \small% + \begin{alltt}% +}{% + \end{alltt}% + \normalsize% +} + +% Used by @code ... @endcode +\newenvironment{DoxyCode}{% + \footnotesize% + \verbatim% +}{% + \endverbatim% + \normalsize% +} + +% Used by @example, @include, @includelineno and @dontinclude +\newenvironment{DoxyCodeInclude}{% + \DoxyCode% +}{% + \endDoxyCode% +} + +% Used by @verbatim ... @endverbatim +\newenvironment{DoxyVerb}{% + \footnotesize% + \verbatim% +}{% + \endverbatim% + \normalsize% +} + +% Used by @verbinclude +\newenvironment{DoxyVerbInclude}{% + \DoxyVerb% +}{% + \endDoxyVerb% +} + +% Used by numbered lists (using '-#' or <ol> ... </ol>) +\newenvironment{DoxyEnumerate}{% + \enumerate% +}{% + \endenumerate% +} + +% Used by bullet lists (using '-', @li, @arg, or <ul> ... </ul>) +\newenvironment{DoxyItemize}{% + \itemize% +}{% + \enditemize% +} + +% Used by description lists (using <dl> ... </dl>) +\newenvironment{DoxyDescription}{% + \description% +}{% + \enddescription% +} + +% Used by @image, @dotfile, and @dot ... @enddot +% (only if caption is specified) +\newenvironment{DoxyImage}{% + \begin{figure}[H]% + \begin{center}% +}{% + \end{center}% + \end{figure}% +} + +% Used by @image, @dotfile, @dot ... @enddot, and @msc ... @endmsc +% (only if no caption is specified) +\newenvironment{DoxyImageNoCaption}{% +}{% +} + +% Used by @attention +\newenvironment{DoxyAttention}[1]{% + \begin{DoxyDesc}{#1}% +}{% + \end{DoxyDesc}% +} + +% Used by @author and @authors +\newenvironment{DoxyAuthor}[1]{% + \begin{DoxyDesc}{#1}% +}{% + \end{DoxyDesc}% +} + +% Used by @date +\newenvironment{DoxyDate}[1]{% + \begin{DoxyDesc}{#1}% +}{% + \end{DoxyDesc}% +} + +% Used by @invariant +\newenvironment{DoxyInvariant}[1]{% + \begin{DoxyDesc}{#1}% +}{% + \end{DoxyDesc}% +} + +% Used by @note +\newenvironment{DoxyNote}[1]{% + \begin{DoxyDesc}{#1}% +}{% + \end{DoxyDesc}% +} + +% Used by @post +\newenvironment{DoxyPostcond}[1]{% + \begin{DoxyDesc}{#1}% +}{% + \end{DoxyDesc}% +} + +% Used by @pre +\newenvironment{DoxyPrecond}[1]{% + \begin{DoxyDesc}{#1}% +}{% + \end{DoxyDesc}% +} + +% Used by @copyright +\newenvironment{DoxyCopyright}[1]{% + \begin{DoxyDesc}{#1}% +}{% + \end{DoxyDesc}% +} + +% Used by @remark +\newenvironment{DoxyRemark}[1]{% + \begin{DoxyDesc}{#1}% +}{% + \end{DoxyDesc}% +} + +% Used by @return +\newenvironment{DoxyReturn}[1]{% + \begin{DoxyDesc}{#1}% +}{% + \end{DoxyDesc}% +} + +% Used by @since +\newenvironment{DoxySince}[1]{% + \begin{DoxyDesc}{#1}% +}{% + \end{DoxyDesc}% +} + +% Used by @see +\newenvironment{DoxySeeAlso}[1]{% + \begin{DoxyDesc}{#1}% +}{% + \end{DoxyDesc}% +} + +% Used by @version +\newenvironment{DoxyVersion}[1]{% + \begin{DoxyDesc}{#1}% +}{% + \end{DoxyDesc}% +} + +% Used by @warning +\newenvironment{DoxyWarning}[1]{% + \begin{DoxyDesc}{#1}% +}{% + \end{DoxyDesc}% +} + +% Used by @internal +\newenvironment{DoxyInternal}[1]{% + \paragraph*{#1}% +}{% +} + +% Used by @par and @paragraph +\newenvironment{DoxyParagraph}[1]{% + \begin{list}{}% + {% + \settowidth{\labelwidth}{40pt}% + \setlength{\leftmargin}{\labelwidth}% + \setlength{\parsep}{0pt}% + \setlength{\itemsep}{-4pt}% + \renewcommand{\makelabel}{\entrylabel}% + }% + \item[#1]% +}{% + \end{list}% +} + +% Used by parameter lists +\newenvironment{DoxyParams}[2][]{% + \begin{DoxyDesc}{#2}% + \item[] \hspace{\fill} \vspace{-40pt}% + \settowidth{\labelwidth}{40pt}% + \setlength{\LTleft}{0pt}% + \setlength{\tabcolsep}{0.01\textwidth}% + \ifthenelse{\equal{#1}{}}% + {\begin{longtable}{|>{\raggedleft\hspace{0pt}}p{0.15\textwidth}|% + p{0.815\textwidth}|}}% + {\ifthenelse{\equal{#1}{1}}% + {\begin{longtable}{|>{\centering}p{0.10\textwidth}|% + >{\raggedleft\hspace{0pt}}p{0.15\textwidth}|% + p{0.685\textwidth}|}}% + {\begin{longtable}{|>{\centering}p{0.10\textwidth}|% + >{\centering\hspace{0pt}}p{0.15\textwidth}|% + >{\raggedleft\hspace{0pt}}p{0.15\textwidth}|% + p{0.515\textwidth}|}}% + }\hline% +}{% + \end{longtable}% + \end{DoxyDesc}% +} + +% Used for fields of simple structs +\newenvironment{DoxyFields}[1]{% + \begin{DoxyDesc}{#1}% + \item[] \hspace{\fill} \vspace{-40pt}% + \settowidth{\labelwidth}{40pt}% + \setlength{\LTleft}{0pt}% + \setlength{\tabcolsep}{0.01\textwidth}% + \begin{longtable}{|>{\raggedleft\hspace{0pt}}p{0.15\textwidth}|% + p{0.15\textwidth}|% + p{0.635\textwidth}|}% + \hline% +}{% + \end{longtable}% + \end{DoxyDesc}% +} + +% is used for parameters within a detailed function description +\newenvironment{DoxyParamCaption}{% + \renewcommand{\item}[2][]{##1 {\em ##2}}% + }{% +} + +% Used by return value lists +\newenvironment{DoxyRetVals}[1]{% + \begin{DoxyDesc}{#1}% + \begin{description}% + \item[] \hspace{\fill} \vspace{-25pt}% + \setlength{\tabcolsep}{0.01\textwidth}% + \begin{longtable}{|>{\raggedleft\hspace{0pt}}p{0.25\textwidth}|% + p{0.77\textwidth}|}% + \hline% +}{% + \end{longtable}% + \end{description}% + \end{DoxyDesc}% +} + +% Used by exception lists +\newenvironment{DoxyExceptions}[1]{% + \begin{DoxyDesc}{#1}% + \begin{description}% + \item[] \hspace{\fill} \vspace{-25pt}% + \definecolor{tableShade}{HTML}{F8F8F8}% + \rowcolors{1}{white}{tableShade}% + \arrayrulecolor{gray}% + \setlength{\tabcolsep}{0.01\textwidth}% + \begin{longtable}{|>{\raggedleft\hspace{0pt}}p{0.25\textwidth}|% + p{0.77\textwidth}|}% + \hline% +}{% + \end{longtable}% + \end{description}% + \end{DoxyDesc}% +} + +% Used by template parameter lists +\newenvironment{DoxyTemplParams}[1]{% + \begin{DoxyDesc}{#1}% + \begin{description}% + \item[] \hspace{\fill} \vspace{-25pt}% + \definecolor{tableShade}{HTML}{F8F8F8}% + \rowcolors{1}{white}{tableShade}% + \arrayrulecolor{gray}% + \setlength{\tabcolsep}{0.01\textwidth}% + \begin{longtable}{|>{\raggedleft\hspace{0pt}}p{0.25\textwidth}|% + p{0.77\textwidth}|}% + \hline% +}{% + \end{longtable}% + \end{description}% + \end{DoxyDesc}% +} + +\newcommand{\doxyref}[3]{\textbf{#1} (\textnormal{#2}\,\pageref{#3})} +\newenvironment{DoxyCompactList} +{\begin{list}{}{ + \setlength{\leftmargin}{0.5cm} + \setlength{\itemsep}{0pt} + \setlength{\parsep}{0pt} + \setlength{\topsep}{0pt} + \renewcommand{\makelabel}{\hfill}}} +{\end{list}} +\newenvironment{DoxyCompactItemize} +{ + \begin{itemize} + \setlength{\itemsep}{-3pt} + \setlength{\parsep}{0pt} + \setlength{\topsep}{0pt} + \setlength{\partopsep}{0pt} +} +{\end{itemize}} +\newcommand{\PBS}[1]{\let\temp=\\#1\let\\=\temp} +\newlength{\tmplength} +\newenvironment{TabularC}[1] +{ +\setlength{\tmplength} + {\linewidth/(#1)-\tabcolsep*2-\arrayrulewidth*(#1+1)/(#1)} + \par\begin{tabular*}{\linewidth} + {*{#1}{|>{\PBS\raggedright\hspace{0pt}}p{\the\tmplength}}|} +} +{\end{tabular*}\par} +\newcommand{\entrylabel}[1]{ + {\parbox[b]{\labelwidth-4pt}{\makebox[0pt][l]{% + \usefont{OT1}{phv}{bc}{n}\color{darkgray}#1}\vspace{1.5\baselineskip}}}} +\newenvironment{Desc} +{\begin{list}{} + { + \settowidth{\labelwidth}{40pt} + \setlength{\leftmargin}{\labelwidth} + \setlength{\parsep}{0pt} + \setlength{\itemsep}{-4pt} + \renewcommand{\makelabel}{\entrylabel} + } +} +{\end{list}} +\newsavebox{\xrefbox} +\newlength{\xreflength} +\newcommand{\xreflabel}[1]{% + \sbox{\xrefbox}{#1}% + \setlength{\xreflength}{\wd\xrefbox}% + \ifthenelse{\xreflength>\labelwidth}{% + \begin{minipage}{\textwidth}% + \setlength{\parindent}{0pt}% + \hangindent=15pt\bfseries #1\vspace{1.2\itemsep}% + \end{minipage}% + }{% + \parbox[b]{\labelwidth}{\makebox[0pt][l]{\textbf{#1}}}% + }}% +\newenvironment{DoxyRefList}{% + \begin{list}{}{% + \setlength{\labelwidth}{10pt}% + \setlength{\leftmargin}{\labelwidth}% + \addtolength{\leftmargin}{\labelsep}% + \renewcommand{\makelabel}{\xreflabel}% + }% + }% +{\end{list}} +\newenvironment{DoxyRefDesc}[1] +{\begin{list}{}{% + \renewcommand\makelabel[1]{\textbf{##1}} + \settowidth\labelwidth{\makelabel{#1}} + \setlength\leftmargin{\labelwidth+\labelsep}}} +{\end{list}} +\newenvironment{Indent} + {\begin{list}{}{\setlength{\leftmargin}{0.5cm}} + \item[]\ignorespaces} + {\unskip\end{list}} +\setlength{\parindent}{0cm} +\setlength{\parskip}{0.2cm} +\addtocounter{secnumdepth}{2} +\usepackage[T1]{fontenc} +\makeatletter +\renewcommand{\paragraph}{\@startsection{paragraph}{4}{0ex}% + {-1.0ex}% + {1.0ex}% + {\usefont{OT1}{phv}{bc}{n}\color{darkgray}}} +\renewcommand{\subparagraph}{\@startsection{subparagraph}{5}{0ex}% + {-1.0ex}% + {1.0ex}% + {\usefont{OT1}{phv}{bc}{n}\color{darkgray}}} +\makeatother +\allsectionsfont{\usefont{OT1}{phv}{bc}{n}\selectfont\color{darkgray}} +\stepcounter{secnumdepth} +\stepcounter{tocdepth} +\definecolor{comment}{rgb}{0.5,0.0,0.0} +\definecolor{keyword}{rgb}{0.0,0.5,0.0} +\definecolor{keywordtype}{rgb}{0.38,0.25,0.125} +\definecolor{keywordflow}{rgb}{0.88,0.5,0.0} +\definecolor{preprocessor}{rgb}{0.5,0.38,0.125} +\definecolor{stringliteral}{rgb}{0.0,0.125,0.25} +\definecolor{charliteral}{rgb}{0.0,0.5,0.5} +\definecolor{vhdldigit}{rgb}{1.0,0.0,1.0} +\definecolor{vhdlkeyword}{rgb}{0.43,0.0,0.43} +\definecolor{vhdllogic}{rgb}{1.0,0.0,0.0} +\definecolor{vhdlchar}{rgb}{0.0,0.0,0.0} diff --git a/trunk/doc/doxygen_logo.eps b/trunk/doc/doxygen_logo.eps new file mode 100644 index 0000000..6539c3a --- /dev/null +++ b/trunk/doc/doxygen_logo.eps @@ -0,0 +1,6322 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%BoundingBox: 0 0 634 197 +%%HiResBoundingBox: 0.000000 0.000000 634.000000 197.000000 +%......................................... +%%Creator: GNU Ghostscript 705 (epswrite) +%%CreationDate: 2002/09/28 21:44:36 +%%DocumentData: Clean7Bit +%%LanguageLevel: 2 +%%EndComments +%%BeginProlog +% This copyright applies to everything between here and the %%EndProlog: +% Copyright (C) 2002 artofcode LLC, Benicia, CA. All rights reserved. +%%BeginResource: procset GS_epswrite_2_0_1001 +/GS_epswrite_2_0_1001 80 dict dup begin +/PageSize 2 array def/setpagesize{ PageSize aload pop 3 index eq exch +4 index eq and{ pop pop pop}{ PageSize dup 1 +5 -1 roll put 0 4 -1 roll put dup null eq {false} {dup where} ifelse{ exch get exec} +{ pop/setpagedevice where +{ pop 1 dict dup /PageSize PageSize put setpagedevice} +{ /setpage where{ pop PageSize aload pop pageparams 3 {exch pop} repeat +setpage}if}ifelse}ifelse}ifelse} bind def +/!{bind def}bind def/#{load def}!/N/counttomark # +/rG{3{3 -1 roll 255 div}repeat setrgbcolor}!/G{255 div setgray}!/K{0 G}! +/r6{dup 3 -1 roll rG}!/r5{dup 3 1 roll rG}!/r3{dup rG}! +/w/setlinewidth #/J/setlinecap # +/j/setlinejoin #/M/setmiterlimit #/d/setdash #/i/setflat # +/m/moveto #/l/lineto #/c/rcurveto # +/p{N 2 idiv{N -2 roll rlineto}repeat}! +/P{N 0 gt{N -2 roll moveto p}if}! +/h{p closepath}!/H{P closepath}! +/lx{0 rlineto}!/ly{0 exch rlineto}!/v{0 0 6 2 roll c}!/y{2 copy c}! +/re{4 -2 roll m exch dup lx exch ly neg lx h}! +/^{3 index neg 3 index neg}! +/f{P fill}!/f*{P eofill}!/s{H stroke}!/S{P stroke}! +/q/gsave #/Q/grestore #/rf{re fill}! +/Y{P clip newpath}!/Y*{P eoclip newpath}!/rY{re Y}! +/|={pop exch 4 1 roll 3 array astore cvx exch 1 index def exec}! +/|{exch string readstring |=}! +/+{dup type/nametype eq{2 index 7 add -3 bitshift 2 index mul}if}! +/@/currentfile #/${+ @ |}! +/B{{2 copy string{readstring pop}aload pop 4 array astore cvx +3 1 roll}repeat pop pop true}! +/Ix{[1 0 0 1 11 -2 roll exch neg exch neg]exch}! +/,{true exch Ix imagemask}!/If{false exch Ix imagemask}!/I{exch Ix image}! +/Ic{exch Ix false 3 colorimage}! +/F{/Columns counttomark 3 add -2 roll/Rows exch/K -1/BlackIs1 true>> +/CCITTFaxDecode filter}!/FX{<</EndOfBlock false F}! +/X{/ASCII85Decode filter}!/@X{@ X}!/&2{2 index 2 index}! +/@F{@ &2<<F}!/@C{@X &2 FX}! +/$X{+ @X |}!/&4{4 index 4 index}!/$F{+ @ &4<<F |}!/$C{+ @X &4 FX |}! +/IC{3 1 roll 10 dict begin 1{/ImageType/Interpolate/Decode/DataSource +/ImageMatrix/BitsPerComponent/Height/Width}{exch def}forall +currentdict end image}! +/~{@ read {pop} if}! +end readonly def +%%EndResource +/pagesave null def +%%EndProlog +%%Page: 1 1 +%%BeginPageSetup +GS_epswrite_2_0_1001 begin +/pagesave save store 100 dict begin +0.1 0.1 scale +%%EndPageSetup +gsave mark +K +0 0 0 0 rf +Q q +0 0 250000 0 0 250000 ^ Y +q[6340 0 0 1970 0 0]concat +634 197 8[634 0 0 -197 0 197]@X false 3 +colorimage +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!r;OA,rk/1.]_qcA +r;N/?b*;hr`rH)=s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +r;OA/s8W#r]_qcAr;OA,rk/1.]_qcAr;OA,rk/1.]_qcAr;OA,rk/1.Rf*/Rr;N/_gkY.I\c;^0 +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!r;OA,rk/1.]_qcAr;OA,rk/1.]_qcAr;OA,rk/1.]_qcA +r;OA,rk/1.]_qbtr;OA,rgNcaRf*/tr;N/_rgNcaRf*/8r;M6EgkY+:X8MV0s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W#r]_qcAr;OA,rk/1.]_qcAr;OA,rk/1.]_qcAr;OA,rk/1.]_qcAr;OA,rk/1.Rf*/t +r;OA,rgNcaRf*/Rr;N/_rdaq=Qi-i5r;N/_rk/1$Qi-3gs8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!r;OA,rk/1.]_qcA +r;OA,rk/1.]_qcAr;N/_rk/1.]_qcAr;OA,rk/1.Rf*/tr;OA,rgNca]_qbtr;N/_rgNcaJGfD8 +r;M6ErgNcaRf*/tr;OA,rgNcWEW?(=s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W#rRf*/tr;N/_rk/1.]_qcAr;N/_rk/1.]_qcA +r;OA,rgNca]_qbtr;OA,rk/1.Rf*/tr;N/_rk/1.Rf*/8r;N/_rdaqGJGfD8r;N/_rk/1.Rf*/R +r;M6Hs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!r;OA,rk/1.]_qcAr;N/_rk/1.]_qcAr;N/_rk/1.]_qcAr;OA,rgNca]_qbt +r;OA,rgNcaRf*/Rr;N/_rgNcaJGfD8r;M6ErdaqG]_qcAr;N/_rgNcaJGfDZs8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W#rRf*/t +r;N/_rk/1.]_qcAr;OA,rgNca]_qcAr;N/_rk/1.Rf*/tr;OA,rgNcaRf*/tr;N/_rk/1.Rf*/8 +r;N/_rdaqGJGfCsr;N/_rk/1.]_qbZr;M6Hs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!r;OA,rk/1.Rf*/tr;OA,rk/1.Rf*/t +r;OA,rgNca]_qcAr;N/_rk/1.Rf*/tr;N/_rgNcaRf*/Rr;N/_rdaqGJGfD8r;M6ErgNcaRf*/t +r;N/_rdaqGJGfDZs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W#r]_qbtr;OA,rk/1.Rf*/tr;OA,rk/1.]_qcAr;OA,rk/1.Rf*/t +r;N/_rgNca]_qbtr;OA,rgNcaRf*/8r;M6ErgNcaJGfCsr;N/_rgNcaRf*/8r;M6Hs8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +r;N/_rk/1.Rf*/tr;OA,rgNca]_qbtr;OA,rgNca]_qbtr;OA,rgNca]_qbtr;N/_rgNcaRf*/R +r;N/_rdaqGRf*/8r;N/_rdaqG]_qcAr;N/_rdaqGJGfDZs8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W#rRf*/tr;OA,rk/1.Rf*/t +r;OA,rk/1.Rf*/tr;OA,rk/1.Rf*/tr;N/_rgNcaRf*/tr;N/_rgNcaRf*/8r;M6ErgNcaJGfCs +r;N/_rgNcaRf*/8r;M6Erk/:2s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8V`bq>^Kpr;N/_rk/1.Rf*/tr;N/_rk/1.Rf*/tr;OA,rgNcaRf*/t +r;N/_rk/1.Rf*/tr;N/_rgNcaRf*/Rr;N/_rdaqGJGfD8r;M6ErgNcaRf*/tr;N/_rdaqGJH,ZL +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +o_/+Yrk/1.]_qcAr;OA,rgNca]_qcAr;N/_rk/1.Rf*/tr;OA,rgNca]_qbtr;OA,rgNcaRf*/R +r;N/_rgNcaRf*/8r;M6ErdaqGRf*/8r;N/_rgNcaRf*/8r;M6Erk/:2s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,coC_JAp&G'lr;N/_rgNca]_qcA +r;N/_rk/1.Rf*/tr;N/_rk/1.Rf*/tr;N/_rk/1.Rf*/Rr;OA,rgNcaRf*/Rr;M6ErdaqGJGfD8 +r;M6ErdaqG]_qbtr;N/_rdaqGJGfDZs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8V`bq<[_Gkj7d9oZ$h.Rf*/tr;N/_rk/1.Rf*/tr;N/_rk/1.Rf*/t +r;N/_rk/1.]_qbtr;OA,rgNcaRf*/Rr;N/_rgNcaRf*/8r;M6ErgNcaJGfCsr;N/_rgNcaJGfCs +r;N/_rk/:2s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +o_/+Em-ilnkPXtlr;OA,rgNca]_qbtr;OA,rgNca]_qbtr;OA,rgNca]_qbtr;OA,rgNca]_qbt +r;N/_rgNcaRf*/Rr;M6ErdaqGJGfD8r;M6ErdaqGRf*/Rr;M6ErdaqGJGfDZs8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8V`bq<726kj7d9oZ$h.Rf*/t +r;N/_rk/1.Rf*/tr;N/_rgNca]_qbtr;OA,rgNca]_qcAr;N/_rgNcaRf*/Rr;N/_rgNcaRf*/8 +r;M6ErgNcaJGfCsr;N/_rdaqGRf*/8r;M6Erk/:2s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!m.9o6m-ilnkPXtlr;OA,rgNca]_qbtr;OA,rgNca]_qbt +r;N/_rk/1.Rf*/tr;N/_rgNca]_qbtr;N/_rgNcaRf*/Rr;M6ErdaqGJGfD8r;M6ErdaqGRf*/R +r;M6ErdaqGJGfDZs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8V`bq<726kj7d9oZ$h.Rf*/Rr;N/_rgNca]_qbtr;N/_rgNca]_qbtr;OA,rgNca]_qcA +r;N/_rgNca]_qbtr;N/_rgNcaRf*/8r;N/_rdaqGJGfCsr;N/_rdaqGJGfCsr;M6Erk/:2s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!o_/+Em-j0)n,2gt +r;OA,rgNca]_qbtr;N/_rk/1.Rf*/tr;N/_rgNca]_qbtr;OA,rgNca]_qbtr;N/_rgNcaRf*/R +r;N/_rdaqGRf*/8r;M6ErdaqGJGfCsr;N/_rdaqGJGfDZs8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8V`bq=OCVi8j)!oZ$h.Rf*/tr;N/_rk/1.Rf*/R +r;N/_rgNca]_qbtr;N/_rk/1.Rf*/tr;N/_rk/1.Rf*/tr;N/_rk/1.Rf*/8r;M6ErgNcaJGfCs +r;N/_rdaqGJGfCsr;M6Erk/:2s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!o_/+IoC_&&kOeKDr;N/_rgNcaRf*/Rr;N/_rgNcaRf*/Rr;N/_rgNcaRf*/t +r;N/_rk/1.Rf*/Rr;N/_rgNcaRf*/Rr;N/_rgNcaRf*/8r;M6ErdaqGJGfCsr;M6ErdaqGJGfDZ +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8V`bq<[_G +kj7d9oZ$h.Rf*/Rr;N/_rgNcaRf*/Rr;N/_rgNcaRf*/Rr;N/_rgNcaRf*/Rr;OA,rgNca]_qbt +r;OA,rgNca]_qbZr;N/_rgNcaJGfCsr;M6ErdaqGJGfCsr;M6Erk/:2s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!o_/+IoC_>6n,2gtr;N/_rgNcaRf*/R +r;N/_rgNcaRf*/Rr;N/_rgNcaRf*/Rr;OA,rgNca]_qbtr;OA,rgNcaRf*/tr;N/_rdaqGRf*/8 +r;N/_rdaqGJGfCsr;M6Erdaq=EW#gKs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s6/h<kj7d9oZ$h.Rf*/Rr;N/_rgNcaRf*/8r;N/_rgNcaJGfD8 +r;N/_rgNcaRf*/Rr;OA,rgNcaRf*/tr;N/_rgNcaRf*/Rr;N/_rgNcaJGfCsr;M6EoPsg.JGfCs +r;M6Erk/:2s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +o_/+IoC_>6n,2Ojr;N/_rdaqGRf*/8r;N/_rgNcaJGfD8r;M6ErgNcaJGfD8r;N/_rgNcaRf*/R +r;OA,rgNcaRf*/tr;N/_rdaqGJGfCsr;M6ErdaqGJGfCsr;M6Erdaq=EW#gKs8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s6/h<kj7d9oZ$h.JGfD8 +r;M6ErgNcaJGfCsr;N/_rdaqGRf*/8r;N/_rdaqGRf*/Rr;N/_rgNcaRf*/Rr;N/_rgNcaRf*/8 +r;N/_rdaqGJGfD8r;M6EoPsg.JGfCsr;M6Erk/:2s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!o_/+QpA*q=n+Z23r;M6ErgNcaJGfD8r;M6ErgNcaJGfCs +r;M6ErgNcaJGfD8r;N/_rgNcaRf*/Rr;N/_rgNca]_qbtr;N/_rgNcaJGfCsr;M6ErdaqGJGfCs +r;M6ErdaqGJGfDZs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8V`bq<726kj7d9oZ$h.JGfCsr;N/_rdaqGJGfCsr;M6ErgNcaJGfCsr;N/_rdaqGRf*/R +r;N/_rgNcaRf*/Rr;N/_rgNcaRf*/8r;M6ErdaqGJGfCsr;M6ErdaqGJGfCsr;M6Erk/:2s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!o_/+QpA*Y-kPXtl +r;N/_rdaqGJGfD8r;M6ErgNcaJGfCsr;M6ErgNcaJGfD8r;M6ErgNcaRf*/Rr;N/_rgNcaRf*/R +r;N/_rdaqGJGfCsr;N/_rdaqGJGfCsr;M6ErdaqGJGfDZs8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8V`bq<[_Gkj7d9oZ$h.Rf*/8r;N/_rdaqGJGfCs +r;M6ErdaqGRf*/8r;M6ErdaqGRf*/Rr;N/_rgNcaRf*/Rr;N/_rgNcaRf*/8r;M6ErdaqGJGfCs +r;M6ErdaqGJGfCsr;M6Erk/:2s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!o_/+IoC_>6n,2Ojr;M6ErgNcaJGfCsr;N/_rdaqGRf*/8r;M6ErgNcaRf*/8 +r;N/_rdaqGRf*/Rr;N/_rgNcaRf*/Rr;N/_rdaqGJGfCsr;M6Erdaq=EW#HKr;M6ErdaqGJGfDZ +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s6/h< +kj7d9oZ$h.JGfCsr;M6ErgNcaJGfCsr;M6ErdaqGRf*/8r;M6ErgNcaRf*/Rr;M6ErgNcaRf*/R +r;N/_rgNcaRf*/8r;M6ErdaqGJGf%Zr:G",oPsg.JGfCsr;M6Erk/:2s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!o_/+QpA*Y-kPXtlr;N/_rdaqGJGfCs +r;M6ErgNcaJGfD8r;M6ErgNcaJGfD8r;M6ErgNcaRf*/Rr;M6ErgNcaRf*/Rr;M6ErdaqGJGf%Z +r;M6EoPsg$EW#fdr;M6Erdaq=EW#gKs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8V`bq<726kj7d9oZ$h.JGfCsr;M6ErdaqGJGfCsr;N/_rdaqGJGfD8 +r;M6ErgNcaJGfD8r;M6ErgNcaRf*/Rr;M6ErgNcaJGfCsr;M6Erdaq=EW#HKr:G",oPsg.JGfCs +r;M6Erk/:2s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +o_/+QpA*q=n,2Ojr;M6ErdaqGJGfCsr;M6ErdaqGJGfCsr;N/_rdaqGJGfD8r;N/_rgNcaRf*/R +r;M6ErgNcaRf*/Rr;M6Erdaq=EW#HKr:G",oPsg$EW#HKr;M6Erdaq=EW#gKs8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s6/h<kj7d9m)8i$JGfCs +r;M6ErdaqGJGfCsr;N/_rdaqGJGfCsr;N/_rdaqGJGfD8r;M6ErgNcaJGfD8r;M6ErdaqGJGf%Z +r;M6EoPsg$EW#HKr:G",rdaq=EW#HKr;M6Erk/:2s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!o_/+IoC_>6n,2Ojr;M6ErdaqGJGfCsr;M6ErdaqGJGfCs +r;N/_rdaqGRf*/8r;N/_rdaqGRf*/8r;N/_rdaqGRf*/Rr;M6Erdaq=EW#HKr8qbloPsg$EW#HK +r;M6EoPsg$EW#gKs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8V`bq<726kj7d9m)8i$JGfCsr;M6ErdaqGJGfCsr;M6ErdaqGJGfD8r;M6ErgNcaJGfD8 +r;M6ErgNcaJGfCsr;M6ErdaqGJGf%Zr:G",oPsfkCAd^Dr:G",rdaq=EW#HKr:G",rk/:2s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!o_/+QpA*q=n,2Oj +r;M6ErdaqGJGfCsr;M6ErdaqGRf*/8r;N/_rdaqGRf*/8r;N/_rdaqGJGfCsr;N/_rdaqGRf*/8 +r;M6EoPsg$EW#HKr8qblk%ahdEW#HKr;M6EoPsfqG5V?Ps8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8V`bq<[_Gkj7d9m)8i$JGfCsr;M6ErdaqGJGfCs +r;M6ErdaqGRf*/8r;N/_rdaqGJGfCsr;N/_rdaqGJGfCsr;M6ErdaqGJGf%Zr:G",k%ahVCAd4/ +r:G",oPsg$EW#HKr8qblrk/:2s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!o_/+IoC_>6n,2Ojr;M6ErdaqGJGfCsr;M6ErdaqGRf*/Rr;M6ErgNcaJGfCs +r;M6ErdaqGJGfCsr;N/_rdaqGRf*/8r;M6EoPsg$EW"s6r8qblk%ahdEW#HKr:G",oPsg$EW#gK +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s6/h< +kj7d9m)8i$JGfCsr;M6ErdaqGJGfD8r;M6ErdaqGRf*/8r;M6ErgNcaJGfCsr;M6ErdaqGJGfCs +r;M6ErdaqGJGebWr:G",k%ahVCAd4/r8qbloPsg$EW#HKr8qblrk/:2s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!o_/+IoC_>6n,2Ojr;M6ErdaqGJGfCs +r;M6ErdaqGJGfD8r;M6ErgNcaJGfCsr;M6ErdaqGJGfCsr;M6ErdaqGJGfD8r;M6EoPsfkCAd4/ +r8qblk%ahdEW#HKr:G",oPsfqG5V?Ps8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8V`bq<726kj7d9m)8i$JGfCsr;M6ErdaqGJGfD8r;M6ErgNcaJGfCs +r;M6ErdaqGJGfCsr;M6ErdaqGJGfCsr;M6ErdaqGJGf%Zr8qblk%ahVCAd4/r8qbloPsg$EW#HK +r9SV)rk/:2s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +o_/+IoC_>6n,2Ojr;M6ErdaqGJGfCsr;M6ErdaqGRf*/8r;M6ErdaqGJGfCsr;M6ErdaqGJGfCs +r;M6ErdaqGJGfCsr;M6EoPsfkCAd4/r8qblk%ahVCAd^Dr9SV)lur=!EW#IKs8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8V`bq<726kj7d9m)8i$JGfCs +r;M6ErdaqGJGfD8r;M6ErdaqGJGfD8r;M6ErdaqGJGfCsr;M6ErdaqGJGfCsr;N/_rdaqGJGf%Z +r8qblk%ahLB)Le+r8qbloPsg$EW#HKr9SV)rk/:2s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!o_/+IoC_&&kPX\br;M6ErdaqGJGfCsr;M6ErdaqGRf*/8 +r;N/_rdaqGJGfCsr;M6ErdaqGJGfCsr;M6ErdaqGJGfCsr;M6Elur<hCAd4/r8qblk%ahVCAd^D +r9SV)oPsg$EW#IKs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8V`bq<[_Gkj7d9m)8i$JGfCsr;M6ErdaqGJGfD8r;M6ErgNcaJGfCsr;M6ErdaqGJGfCs +r;M6ErdaqGJGfCsr;M6ErdaqGJGf%Zr8qblk%ahVCAd4/r8qbloPsfqG5UuPr9SV)rk/:2s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!o_/+IoC_&&kPX\b +r;M6ErdaqGJGfCsr;M6ErdaqGJGfD8r;M6ErdaqGJGfCsr;M6ErdaqGJGfCsr;M6ErdaqGJGfCs +r;M6Ek%ahVCAd4/r7ko^k%ahVCAdFAr9SV)oPsg$EW#IKs8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8V`bq<[_Gkj7d9m)8i$JGfCsr;M6ErdaqGJGfCs +r;M6ErdaqGRf*/8r;N/_rdaqGJGfCsr;M6ErdaqGJGfCsr;M6ErdaqGJGebWr8qblk%ahVCAd4/ +r8qbloPsfqG5UuPr8qblrk/:2s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!o_/+IoC_&&kPX\br;M6ErdaqGJGfCsr;M6ErdaqGRf*/8r;M6ErdaqGJGfCs +r;M6ErdaqGJGfCsr;M6ErdaqGJGfCsr;M6Ek%ah\G5UK;r8qblk%ah\G5U]Mr9SV)oPsfkCAe(D +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8V`bq<726 +kj7d9m)8i$JGfCsr;M6ErdaqGJGfCsr;M6ErdaqGRf*/8r;N/_rdaqGRf*/8r;M6ErdaqGJGfCs +r;M6ErdaqGJGePEr8qblgh-KHCAdFAr8qbllur<nG5U]Mr8qbloZ$q2s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!o_/+QpA*Y-kPX\br;M6ErdaqGJGfCs +r;M6ErdaqGJGfCsr;M6ErdaqGRf*/8r;M6ErdaqGRf*/8r;M6ErgNcaJGfCsr;M6Ek%ah\G5UK; +r8qblk%ah\G5UK;r9SV)oPsfkCAd^js8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8V`bq<726kj7d9m)8i$JGfCsr;M6ErdaqGJGfCsr;M6ErdaqGRf*/8 +r;M6ErgNcaJGfD8r;M6ErdaqGJGfCsr;M6ErdaqGJGePEr8qblgh-KHCAdFAr9SV)k%ah\G5UK; +r7ko^oZ$q2s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +o_/+IoC_&&kPX\br;M6ErdaqGJGfCsr;M6ErdaqGJGfCsr;M6ErgNcaJGfCsr;N/_rdaqGJGfD8 +r;M6ErgNcaJGfCsr;M6Ek%ahVCAd4/r8qblk%ahVCAd4/r8qblk%ahLB)M:fs8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8V`bq=OCVi8j)!m)8i$JGfCs +r;M6ErdaqGJGfCsr;M6ErgNcaJGfCsr;N/_rdaqGJGfD8r;M6ErgNcaJGfCsr;M6Erdaq=EW"s6 +r7ko^gh-KHCAd4/r8qblk%ahVCAd4/r7ko^oZ$q2s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!o_/+IoC_&&kPX\br;M6ErdaqGJGfCsr;M6ErdaqGJGfCs +r;M6ErgNcaJGfCsr;N/_rdaqGJGfCsr;N/_rdaqGJGfCsr;M6Egh-K>B)LFrr8qblk%ahVCAck! +r8qblk%ahLB)M:fs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8VHWp%7tRi8j)!m)8i$JGfCsr;M6ErdaqGJGfCsr;M6ErdaqGJGfCsr;N/_rdaqGJGfCs +r;N/_rdaqGJGfCsr;M6ErdaqGJGe27r7ko^gh-K>B)LFrr8qblgh-K>B)Le+r7ko^oZ$q2s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!o_/+IoC_&&kPX\b +r:G",rdaqGJGfCsr;M6ErdaqGJGfCsr;M6ErdaqGJGfCsr;N/_rdaqGJGfCsr;M6ErdaqGJGfCs +r:G",k%ahD@JnV`r7ko^gh-K>B)LFrr7ko^k%ahLB)M:fs8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8V`bq<726kj7d8jMCcnJGf%Zr;M6ErdaqGJGfCs +r;M6ErdaqGJGfCsr;N/_rdaqGJGfCsr;M6ErdaqGJGfCsr;M6Erdaq=EW"<pr7#0Qe7&:)@Jnnm +r7ko^e7&:1B)LFrr7ko^oZ$q2s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!o_/+IoC_&&kPO>Vr:G",rdaqGJGfCsr;M6ErdaqGJGfCsr;M6ErdaqGJGfCs +r;M6ErdaqGJGfCsr;M6ErdaqGJGfCsr:G",e7&:)@Jn>Tr7#0Qe7&:)@JnV`r7#0Qgh-K6@Joc; +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8V`bq<726 +kj7d9m)8hoEW#HKr:G",oPsg.JGfCsr;M6ErdaqGJGfCsr;M6ErdaqGJGfCsr;M6ErdaqGJGfCs +r;M6Erdaq=EW"<pr6/IEb[(.j?2VoPr7#0Qb[(.r@JnV`r7ko^oZ$q2s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!o_/+IoC_>6n,)1^r:G",oPsg$EW#HK +r:G",oPsg.JGf%Zr;M6ErdaqGJGfCsr;M6ErdaqGJGfCsr:G",rdaq=EW#HKr9SV)e7&:!?2VoP +r6/IEb[(.j?2VoPr6/IEe7&:)@JoGZs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8V`bq<[_Gi8j)!m)8haCAd4/r:G",oPsg$EW#HKr:G",oPsg$EW#HK +r:G",oPsg.JGfCsr;M6EoPsg$EW#HKr:G",oPsfkCAc:]r5;b9b[(.b=o?3@r6/IE`**#^?2VoP +r7#0QoZ$q2s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +o_/+IoC_>6n,)1^r8qblk%ahdEW#0Hr:G",oPsg$EW#HKr:G",oPsg$EW#HKr:G",oPsg$EW#HK +r:G",oPsfqG5UuPr8qbl`**#V=o>p3r5;b9]N"gI=o?3@r5;b9`**#^?2X?7s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8V`bq=OCVi8j(ujMCcVCAd4/ +r8qblk%ah\G5U]Mr9SV)lur<nG5U]Mr9SV)lur=!EW#HKr9SV)oPsfqG5UuPr8qbllur<^B)K;@ +r5;b9`**#V=o>p3r5;b9]N"gA<;a[;r6/IEm)8r(s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!o_/+Em-j0)n,)1^r8qblk%ahVCAd4/r8qblk%ahVCAd4/ +r8qbllur<hCAdFAr9SV)lur<nG5U]Mr9SV)k%ah\G5UK;r7ko^]N"gI=o>p3r4H#,]N"gI=o>p3 +r4H#,]N"gQ?2X#Vs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W,kpA+(Hp#tc2i8j(tgopY2B)LFrr8qblk%ahVCAd4/r8qblk%ahVCAd4/r8qblk%ahVCAdFA +r8qblk%ahVCAd4/r8qblk%ahD@Jmc;r5;b9]N"gA<;a+"r4H#,]N"gA<;aC.r5;b9m)8r(s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W#r]`8$3s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8;l/r:J#,oU#LARJcDpr9KdKl^@\:RJc]D +r:J#,oZ$h$`r,JKs8W,soZ$q2s8W-!s8W-!s8W-!s8W-!s8W-!s8V`bq<[_Gm.9o.jQGI^kPEu; +r7ko^gh-K>B)LFrr7ko^gh-K>B)LFrr7ko^k%ahVCAd4/r8qblk%ahVCAd4/r8qblk%ahLB)Le+ +r7#0Q]N"gA<;aC.r4H#,Zr$\5<;a+"r3T;uZr$\5<;c'Ms8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W#rRf)fEr8qblk%ahVCAd4/ +r8qblk%ahVCAd4/r9SV)lur<mRJc]Dr:J#,oZ$q2s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!r;OA/s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8;l/r;OA/s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W,soZ$gaL]#Y1r7#0Qe7&:)@Jnnmr7ko^e7&:)@Jnnmr7#0Qgh-K>B)LFrr8qblgh-K6@Jn>T +r5;b9]N"gA<;a[;r4HkDc%GrDM#,o1qrGTfm-!U!n)39ig"bH\gopY2B)LFrr7ko^gh-K6@Jnnm +r7#0Qgh-K>B)LFrr7ko^gh-K>B)LFrr8qblgh-K>B)LFrr7ko^gh-K.?2V'+r3T;u]N"g9;#ICg +r4H#,Zr$\%9`1tcr3T;um)8r(s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!r;OA,lur<hCAd4/r8qblk%ahVCAd4/r8qblk%ahVCAd4/r8qblk%ahVCAd4/ +r8qblk%ahLB)LFrr7#0Q`**#N<;a[;qV8:PoZ$q2s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!r:H?Rk%ahD@JmK/r4H#,e;4%p`rH)=s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8;kbr:G",lur=!QiI*cs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,srk/1.Rf)et +r9SV)lur<nG5V!Ps8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,soZ$gQ?2Wi"r9SV)rgNles8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!r;OA,rk/1.]_qcAr;OA/s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8;N/r9VAugopS0YPdFS +r9KdKlur<nG5UK;r9SV)lur<hCAd4/r8qblk%ah\G5V!!r;N/bs8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8V`bq<[_Gm.9o:oC_JAp$D;C +m.9oBpA+(Hp%7tRs8W,kpA+@Sq=j7=r9VB"m)8e^_>;rjqV8:Pj.ZD2U&=5Er9KdKlur<nG5UK; +r9SV)lur<nG5V!!r;OA/s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!r9KdKe7&9n=o?KLr6/IEb[(.j?2W2\ +r7#0Qe7&:)@JnV`r7ko^e7&:)@Jnnmr7ko^gh-K>B)LFrr8qblgh-K>B)LFrr6/IE]N"g9;#ICg +r2`TiUe(Eb9`1\Wr3T;u]PQfTX8:&;r7#0Qe7&:)@JnV`r7#0Qe7&:1B)L.er7ko^e7&:1B)LFr +r7ko^gh-K>B)LFrr7ko^gh-K>B)LFrr6/IEZr$\-;#I[sr3T;uXA&Q!;#I[sr2`TiXA&Q!;#K@I +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8;l/r8qblk%ahVCAck! +r8qblgh-K>B)LFrr8qblk%ahLB)Le+r7ko^gh-KHCAck!r7ko^k%ahLB)LFrr7ko^gh-K>B)LFr +r7ko^b[(.Z<;`gkr2`Ti`*)rlYQ+Y&s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!r:G",k%ahVCAd4/ +r8qbl`**#>9`1tcr4H#/s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,slur<nG5U]M +r:G",k%ahSU&Y/ms8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!r;N/_lur<hCAd4/r8qblk%ahVCAd4/r8qblgh-Tds8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s89f<r7#0Qgh-K>B)LFrr7ko^k%ahdEW#gKs8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +r;OA,rk/1$EW#0Hr9SV)lur<nG5U]Mr9SV)lur<nG5UuPr:G",lur=!EW#HKr:H?RrgNca]_qcA +r;OA/s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8V`bq=OCVqrGTigopRnM>Y"cr2`TiZr$\==o@&er9SV)lur<hCAdFAr9SV)k%ahVCAdFA +r8qblk%ahVCAd4/r8qbllur<nG5UuPr:G",oPsg.]_qcAs8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +r9VB"m)8hg`;AW3r9KdKl^@\2U&=5Er9KdKlur<nG5U^Fkj7crjQGd\\bag[qSe<h]PRMQ;#ICg +r3T;uXA&Pn9`27or5;b9e7&:;CAd4/r9SV)k%ahVCAd4/r8qblk%ahVCAd4/r8qblk%ahVCAd4/ +r8qbloU#LT]`8$3s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8;6%r6/IE`**#V=o?3@r5;b9]N"gI=o?KLr5;b9b[(.j?2VoPr7#0Qe7&:)@JnV` +r7ko^e7&:1B)LFrr7ko^e7&:1B)LFrr7#0Qgh-K6@JnV`r5;b9Zr$\%9`1\Wr1lm]Ue(ER6N!WM +r1lm]Zr$\E?2W2\r6/IEe7&:)@JnV`r7#0Qe7&:1B)L.er7#0Qe7&:)@JnV`r7#0Qe7&:)@JnV` +r7#0Qe7&9n=o>?pr3T;uZr$\%9`1tcr2`TiUe(EZ8Go8Sr2`ThjMClrs8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W#r]_po,r7ko^gh-K>B)L.er7ko^gh-K>B)LFrr7ko^gh-K>B)LFr +r7ko^gh-K>B)LFrr7ko^gh-K>B)LFrr7ko^gh-K>B)LFrr7#0Qe7&:)@Jnnmr7#0Qe7&9n=o>?p +r1lm]XA&Q)<;PCRs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!r9SV)k%ahVCAd4/r8qblk%ahVCAd4/r3T;uXA&Pn9`2h3 +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W#`G5UK;r9SV)k%ahVCAdFAr9SV)k%ah[RK*<e +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W#r]_qDg +r8qblk%ahVCAd4/r7ko^k%ahLB)Le+r7ko^k%ahVCAck!r:J#/s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!qrGTk`**#nB)LFr +r7ko^gh-K>B)LFrr7ko^k%ahVCAdFAr;N/bs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,sm)8h^U&=5Er9SV)oPsg$EW#HKr9SV)lur<nG5U]M +r8qblk%ah\G5U]Mr9SV)lur<hCAdFAr9SV)lur<nG5U]Mr9SV)lur<nG5U]Mr:G",lur<nG5U]M +r:G",oU#LJQi-iOr;OA,rk/1.]_qcAr;OA/s8W#r]`8$3s8W,srk/:2s8;l/s8W,srk/1.]_qcA +r;OA,rgNles8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!o_/+IoC_>6n+thCqSe<hZr$\%9`1tc +r3T;u`**#nB)Le+r9SV)k%ahVCAd4/r8qblk%ahVCAd4/r8qblk%ahVCAd4/r8qblk%ahVCAd4/ +r9SV)lur<nG5U]Mr9SV)lur<nG5V!!r;OA/s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!o_/+\s8V`bq=OCVm.9o:oC_JAp$D;C +m.9oBpA+@Sq=j7=r9VB!jMC`S_>N>er8XLKgkYg_L]#Y1r7#0Qgh-KHCAd4/r9SV)lur<hCAdFA +r9SV)lur<hCAd4/r9SV)e;4"/Er<:@r2`TiXA&Q!;#ICgr3T;uXA&Pn9`2h3r7#0Qk%ahVCAd4/ +r8qblk%ahVCAd4/r8qblgh-K>B)LFrr7ko^gh-K>B)Le+r7ko^k%ahLB)Le+r7ko^lur=!`rH)= +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8:oNr5;b9]N"gI=o>p3 +r4H#,]N"gA<;a[;r4H#,`**#V=o?KLr6/IEb[(.r@JnV`r7#0Qe7&:)@JnV`r7#0Qe7&:1B)L.e +r7#0Qe7&:)@JnV`r7#0Qe7&:!?2VoPr4H#,Ue(EZ8Go8Sr1lm]S3m.D6N!oYr6/IEb[(.j?2VoP +r6/IEb[(.r@JnV`r6/IEe7&:)@Jn>Tr7#0Qe7&:)@JnV`r7#0Qe7&:)@JnV`r5;b9XA&Pn9`1tc +r2`TiXA&Pn9`1\Wr1lm]S3m.L8GqMAs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W#hQi,WN +r7ko^e7&:)@JnV`r7#0Qe7&:)@JnV`r7#0Qe7&:1B)LFrr7ko^gh-K>B)LFrr7ko^e7&:)@Jnnm +r7#0Qgh-K>B)L.er7#0Qe7&:)@JnV`r7#0Qb[(.r@JnV`r6/IEe7&9n=o>?pr1$+OUe(Eb9`2P> +r:J#/s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8;l/ +r9SV)gh-K>B)LFrr7ko^k%ahLB)Le+r7ko^k%ah<?2Uctr1lm]Zr$\\U&Y/ms8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8;5,r8qblk%ahVCAd4/r8qblk%ah\G5UK;r8qblgh-KMRK*<es8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!r;OA,oU#LBG5UK;r8qblk%ahVCAd4/r7ko^gh-K>B)LFr +r7ko^gh-K>B)L.er7ko^gh-K6@K6B-s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W#0D#DL_r7ko^e7&:1B)LFrr7#0Qgh-K>B)LFr +r7ko^k%ahLB)Le+r8qbllur=+]`8$3s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s7H$\ +qV8:Pe;4%P@JoJ8r9SV)lur<nG5U]Mr9SV)lur<nG5UK;r8qblk%ahVCAd4/r8qblk%ahVCAd4/ +r9SV)k%ahVCAd4/r8qblk%ahVCAd4/r8qblk%ahVCAd4/r8qblk%ahVCAd4/r9SV)k%ah\G5U]M +r9SV)lur<nG5U]Mr9SV)k%ahVCAdFAr9SV)lur<hCAdFAr9SV)lur<hCAd^js8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8V`bq=OCVm.9o6m-j2l\ba:%r3T;uUe(Eb9`1tcr4H#,e7&:;CAdFAr9SV)k%ahVCAd4/ +r8qblk%ahVCAd4/r8qblgh-KHCAck!r7ko^gh-K>B)LFrr8qblk%ahVCAdFAr9SV)lur<hCAd4/ +r8qblk%ahLL]$L^r:H?Us8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8V`bq=OCVm.9o:oC_JAp#tc2l.NWCgsP?/X89elqSe<h]SQHlEr<:@r2`TiUe(Er<;bln +r8qblk%ahVCAd4/r8qblk%ahVCAd4/r8qblgkYgoG5UK;r8qblk%ahVCAd4/r8qblk%ahVCAb_D +r2`TiXA&Pn9`1tcr2`TiXA&Pn9`27or7ko^k%ahVCAd4/r7ko^gh-K>B)LFrr7ko^e7&:1B)LFr +r7ko^gh-K6@Jnnmr7ko^e7&:1B)LFrr7ko^gh-K>B)LFrr7ko^k%ah\`;fl;s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8:Z-r4H#,]N"gA<;aC.r4H#,]N"gA<;a[;r4H#,]N"gA<;a[; +r5;b9`**#^?2VWDr6/IEb[(.r@JnV`r7#0Qe7&:)@JnV`r7#0Qe7&:)@Jn>Tr6/IEb[(.j?2VoP +r5;b9b[(.b=o?3@r2`TiS3m.D6N!WMr1$+OUe(F%=o?3@r6/IEb[(.j?2VoPr6/IEb[(.j?2VoP +r5;b9b[(.j?2VoPr6/IEb[(.j?2VoPr6/IEb[(.b=o>?pr2`TiXA&Pn9`1DIr2`TiS3m.D6N!?? +r1$+NjMClrs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W#_RJbQCr7#0Qb[(.r@Jn>Tr6/IEe7&:!?2VoP +r6/IEe7&:!?2W2\r7#0Qe7&:)@JnV`r7#0Qe7&:)@JnV`r7#0Qe7&:)@JnV`r7#0Qe7&:)@JnV` +r6/IEb[(.j?2VoPr6/IEb[(.j?2VoPr6/IEe7&9f<;`gkr1$+OUe(EZ8GohkqV8:Ss8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8;l/r7m)*gh-K6@Jnnmr7ko^gh-K>B)LFr +r7ko^gh-KHCAck!r7ko^]N"g)8Go8Sr3T<#s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!r9KdKgh-K>B)LFr +r8qblgh-KHCAd4/r8qbllur<hCAdFAr7m)*e7&:8U&Y/ms8W-!s8W-!s8W-!s8W-!s8W-!s8;MU +r8qblk%ahVCAd4/r8qblk%ahVCAd4/r7ko^gh-K6@Jnnmr7#0Qe7&:)@Jn>Tr7#0Qe7&:)@JnV` +r7#0QoZ$q2s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8V`bq=OCV +o_/+QpA+@Sq>/mMr4H#,e7&:1B)L.er7#0Qe7&:)@Jnnmr7ko^gh-K>B)LFrr7ko^gh-K>B)LFr +r7ko^k%ah\G5V?.s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8(NSqSe<h`**#nB)Le+r9SV)k%ahVCAdFA +r8qblk%ahVCAd4/r8qblk%ahVCAd4/r8qblk%ahVCAd4/r8qblk%ahVCAck!r7ko^k%ahLB)LFr +r8qblgh-KHCAck!r8qblgh-KHCAck!r8qblgh-K>B)Le+r8qblk%ahVCAdFAr8qblk%ahVCAd4/ +r8qblk%ahVCAd4/r8qblk%ah\G5UK;r9SV)rk/:2s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8VHWp$D;Cm.9o.jQHB`VYd`@ +r1lm]XA&Pf8GoP_r4H#,gh-KHCAd4/r8qblk%ahVCAd4/r8qblk%ahVCAd4/r8qblk%ahLB)LFr +r7ko^gh-K>B)LFrr7ko^gh-K>B)LFrr8qbllur<hCAd4/r8qblk%ahLB)Le+r8qblgh-KHCAd4/ +r9SV,s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8V`bq<[_Gm.9o6m-j0)n)39i +i8j(t`JOMo9`1\Wr1$+OUe(EZ8Go8Sr2`TiUe(EZ8Go8Sr4H#,gh-K>B)LFrr8qblgh-KHCAck! +r8qblgh-KHCAd4/r8qblk%ahLL]$:Lr7m)*k%ahLB)Le+r8qbl]N"g19`1\Wr2`TiXA&Pn9`1\W +r6/IEgh-KHCAck!r7ko^gh-K>B)LFrr7#0Qgh-K6@Jnnmr7#0Qe7&:)@JnV`r7#0Qe7&:)@JnV` +r7ko^gh-K>B)L.er7#0Qgh-K6@JnV`r7ko^gh-KV`rH)=s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8:Z- +r4H#,]N"gA<;aC.r4H#,]N"gA<;aC.r4H#,]N"gA<;aC.r4H#,]N"gA<;a[;r5;b9`**#V=o?KL +r6/IEb[(.j?2W2\r6/IEb[(.j?2VoPr6/IEb[(.b=o?3@r5;b9`**#V=o?3@r4H#,`**#N<;a+" +r1$+OS3m.D6N!WMr5;b9`**#V=o?3@r5;b9`**#V=o?3@r5;b9`**#V=o?3@r5;b9`**#^?2VWD +r6/IEb[(.b=o?KLr4H#,Ue(EZ8Go8Sr1$+OS3m.L8GnuEr1$+OS3m.D6N#l;s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W#_RJbQCr6/IEb[(.j?2VoPr6/IEb[(.j?2VWDr6/IE`**#^?2VWDr6/IEb[(.j?2VoP +r7#0Qe7&:!?2W2\r7#0Qe7&:!?2W2\r7#0Qe7&:!?2VoPr6/IEb[(.j?2VoPr5;b9b[(.j?2VoP +r6/IE`**#^?2VWDr5;b9`**#F;#HhMr1$+OPX55C8GoP_qV8:Ss8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8;N/r7#0Qb[(.r@JnV`r7#0Qe7&:)@JnV`r7ko^gh-K>B)LFrr7ko^gh-K>B)L.e +r2`TiS3m.L8Gp,:s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!o_/+Ym)8hO@JnV`r7#0Qgh-K6@Jnnmr7ko^gh-K>B)Le+ +r7ko^k%ahVCAd4/r7ko^e7&78_>jQ8s8W-!s8W-!s8W-!s8W,sgh-K>B)LFrr7m)*gh-K>B)L.e +r7#0Qe7&:)@JnV`r7#0Qe7&:)@JnV`r6/IEe7&:!?2VoPr6/IEb[(.j?2W2\s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8V`bq<[_Gm.9o6m-j0)n*'-,kj7d9]PRMa=o?cX +r7#0Qe7&:)@JnV`r7#0Qe7&:1B)LFrr7ko^gh-K6@Jnnmr7ko^gh-K>B)LFrr7ko^gh-KHCAd4/ +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8Vi[kPE]4r3T;u`**#nB)Le+r8qblk%ahVCAd4/r8qblk%ahVCAd4/r7ko^k%ahLB)Le+ +r8qblgh-K>B)LFrr7ko^gh-K>B)LFrr7ko^gh-K>B)LFrr7ko^gh-K>B)LFrr7ko^gh-K>B)LFr +r7ko^gh-K6@Jnnmr7ko^gh-K>B)LFrr8qblgh-KHCAd4/r7ko^k%ahLB)Le+r8qblk%ahVCAd4/ +r8qblk%ahVCB+>6s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W,kpA+(Hp$D;Ckj7crjQHBYM>X/?r1lm]Ue(ER6N!WMr4H#,e7&:;CAck! +r8qblgh-K>B)Le+r7ko^k%ahLB)LFrr7ko^gh-K>B)LFrr8qblgh-KHCAck!r7ko^gh-K>B)LFr +r7ko^gh-KHCAd4/r7m)*k%ahVCAck!r7ko^gh-K>B)Le+r7ko^gh-KHCAck!r9KdNs8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s6T@Mm.9o6m-ilnkLnYIg"bH;gtp`>hXA+;r1lm]S3m.D6N!?? +r1$+OUe(EZ8GnuEr1$+OS3m.d<;bN`r7ko^gh-K>B)LFrr7ko^gh-K>B)LFrr7ko^gh-K>B)LFr +r8qblk%ahVCAck!r7m)*k%ahLB)K;@r1lm]Ue(Eb9`1DIr3T;ue7&:;CAd4/r7ko^gh-K6@JnV` +r7#0Qe7&:)@JnV`r7#0Qe7&:)@JnV`r7#0Qb[(.j?2W2\r7#0Qe7&:)@JnV`r7#0Qe7&:)@JnV` +r7#0Qe7&:!?2W2\r7#0Qj.ZMQs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8:oNr5;b9]N"gA<;aC.r4H#,]N"g9;#I[s +r3T;uZr$\-;#I[sr3T;u]N"gA<;aC.r5;b9]N"gA<;a[;r5;b9`**#V=o?3@r6/IE`**#^?2VoP +r5;b9`**#V=o?3@r5;b9`**#V=o>p3r4H#,]N"gA<;a+"r4H#,]N"g9;#HhMr00MFS3m.d<;aC. +r4H#,`**#N<;a[;r4H#,]N"gA<;aC.r4H#,]N"gA<;aC.r4H#,`**#V=o?3@r5;b9`**#F;#I+[ +r1$+OUe(ER6N!??r1$+OPX4o!2Z/e*r1$+MgopbXs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W#h`r+)6r6/IEb[(.j?2VWD +r5;b9`**#V=o?3@r5;b9`**#V=o>p3r5;b9]N"gI=o?3@r5;b9b[(.b=o?3@r6/IE`**#^?2VoP +r6/IEb[(.j?2VoPr6/IEb[(.b=o?3@r5;b9`**#V=o?3@r5;b9`**#V=o?3@r5;b9`**#V=o?3@ +r5;b9`**#>9`1DIr00MFPX55;6N!WMqrGTns8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8;6%r7#0Q`**#^?2VoP +r6/IEb[(.j?2VoPr7#0Qe7&:)@JnV`r7m)*e7&:1B)L.er7ko^gh-K&=o=dVr1$+OUe(CD_>jQ8 +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +o_/+Em-j]8kPWSWr7#0Qb[(.r@JnV`r7#0Qe7&:)@Jnnmr7ko^gh-K>B)L.er7ko^e7&:1B)LFr +r7#0Q`*)rlYQ+Y&s8W-!s8W-!s8:Z-r7#0Qgh-K6@JnV`r7#0Qe7&:)@JnV`r6/IEe7&:!?2VoP +r6/IEb[(.j?2VWDr6/IEb[(.j?2VoPr6/IE]N"q2s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s7H$\kj7d%m-ilnkMYFai8j(ZjQG[Lao&56r6/IEb[(.r@Jn>Tr7#0Qe7&:)@Jnnm +r7#0Qe7&:)@JnV`r7#0Qe7&:)@JnV`r7#0Qgh-K6@Jnnmr7ko^oZ$q2s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8Vi[kPE/Sr2`Ti]N"gaB)Le+ +r7ko^gh-K>B)LFrr7ko^gh-K6@Jnnmr7#0Qgh-K6@Jnnmr7ko^e7&:1B)L.er7ko^e7&:1B)LFr +r7ko^e7&:1B)L.er7ko^e7&:)@JnV`r7#0Qe7&:1B)L.er7#0Qe7&:)@JnV`r7#0Qe7&:)@JnV` +r7#0Qgh-K>B)LFrr7ko^gkYg_B)Le+r7m)*k%ahLB)LG>r7ko^gh-KHCAckBr9SV,s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,kpA+(Hp$D;C +kj7d#gt_h?M#=&>r1$+OS3m.D6N!??r2`Tie7&:1B)LFrr7ko^k%ahLB)LFrr7ko^gh-K>B)LFr +r7ko^gh-KHCAck!r7ko^gh-K>B)LFrr7ko^gh-K>B)LFrr7#0Qgh-K>B)LFrr7ko^gh-KHCAck! +r7ko^gh-K>B)LFrr7ko^gh-K>B)LFrr7ko^gh-K>B)LFrr:J#/s8W-!s8W-!s8W-!s8W-!s8W-! +m.9o:oC_&&kMYFag"bH;gtpK/f$`(!daZk:]T2o[6N!??r1$+OS3m.D6N!??r1$+OS3m.D6N!?? +r2`Tib[(.r@JnV`r7#0Qe7&:)@JnV`r7#0Qe7&:)@JnV`r7#0Qgh-K6@Jnnmr7ko^k%ahLB)LFr +r8qblZr$[r8Go8Sr1$+O]N"gaB)LFrr7ko^e7&:1B)L.er7#0Qe7&:)@JnV`r6/IEe7&:!?2W2\ +r6/IEb[(.j?2VoPr6/IEb[(.j?2VoPr7#0Qe7&:)@Jn>Tr6/IEb[(.j?2VoPr6/IEb[(.j?2VoP +r7#0Ts8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8;N/r4HkD]N"gA<;aC.r4H#,]N"g9;#I[sr4H#,Zr$\-;#I[sr3T;uZr$\-;#I[s +r4H#,Zr$\5<;aC.r4H#,]N"gA<;aC.r5;b9]N"gA<;a[;r4H#,`**#N<;a[;r4H#,]N"gA<;aC. +r4H#,Zr$\-;#I[sr3T;uZr$\-;#I[sr3T;uXA&P^6N!??r4H#,]N"gA<;a+"r4H#,Zr$\5<;a+" +r3T;uZr$\-;#It*r4H#,]N"gA<;aC.r4H#,]N"gA<;a[;r3T;uS3m.D6N!WMr1$+OS3m.D6M$*n +o8>NuM`1L'6Mf39s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8:ATr5;b9`**#V=o?3@r5;b9`**#N<;a[;r4H#,]N"gA<;aC. +r4H#,]N"gA<;a[;r4H#,`**#N<;a[;r4H#,`**#V=o?3@r5;b9`**#V=o?3@r5;b9`**#V=o?3@ +r5;b9`**#N<;aC.r4H#,]N"gA<;aC.r4H#,`**#N<;aC.r4H#,]N"gA<;aC.r4H#,Zr$[j6M$*n +o8>O)PX55;6Mn-1s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8;6%r7#0Q`**#V=o?3@r5;b9`**#V=o?3@r6/IEb[(.j?2VoP +r69llb[(.r@JnV`r69lle7&:)@JnV`r7#0QXA&P^6N!??r2`Tls8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,coC_>6n*'-,r69ll`**#^?2VoP +r6/IEb[(.j?2W2\r7#0Qe7&:)@JnV`r7#0Qgh-K6@Jnnmr7$Q#e7&:)@JnV`r6/IE]PRH"YQ+Y& +s8W,sm)8hO@JnV`r7#0Qe7&:!?2VoPr6/IEb[(.j?2VoPr6/IEb[(.b=o?3@r5;b9`**#V=o?3@ +r5;b9`**#V=o?3@r69los8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!o_/+Em-ilnkLnYI +g"bH;gtpK/f%Jj8m&ka6]N"gQ?2VoPr6/IEb[(.j?2VoPr6/IEe7&:)@JnV`r7#0Qe7&:!?2W2\ +r7#0Qe7&:)@JnV`r7$Q#e7&:)@K6B-s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8V`bq>/'er1lm]Zr$\M@Jnnmr7ko^gh-K>B)LFrr7ko^gh-K6@JnV` +r7#0Qe7&:)@JnV`r7#0Qb[(.j?2W2\r6/IEe7&:)@JnV`r7#0Qe7&:)@JnV`r7#0Qe7&:)@JnV` +r7#0Qe7&:)@JnV`r7#0Qe7&:)@JnV`r6/IEe7&:)@Jn>Tr7#0Qe7&:)@JnV`r7#0Qgh-K>B)LFr +r7ko^gkYg_B)LFrr7ko^k%ahLB)LFrr7ko^gh-KV`rH)=s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,kpA+@Sq<[_Gkj7ckgtqM4Nr5D6r00MFPX55362Zs5 +r1$+O]N"gY@JnV`r7#0Qgh-K>B)L.er7$Q#gh-K6@Jnnmr7#0Qe7&:1B)LFrr7#0Qgh-K>B)LFr +r7ko^gh-K6@Jnnmr7#0Qe7&:)@JnV`r7ko^gh-K>L]#q>r7m)*gh-K>B)L.er7ko^e7&:)@JnV` +r7#0Qe7&:)@JnV`r7#0Qe7&:)@JoJ8s8W-!s8W-!s8W-!s8W,coC_JAp#+ooi8j(SgtpK/f#u:^ +bKS5Sbg")F`T41Lr00MFPX55362Zs5r00MFS3m.D6N!'6r00MFPX55K9`3+?r6/IEb[(.j?2VoP +r7#0Qe7&:)@JnV`r7#0Qe7&:)@JnV`r7#0Qe7&:1B)L.er7ko^gh-K>B)K#4r1$+OS3m.l=o@&e +r7ko^gh-K6@Jnnmr7#0Qe7&:!?2VoPr6/IEb[(.j?2VoPr6/IEb[(.j?2VoPr6/IE`**#^?2VWD +r6/IEb[(.j?2VoPr5;b9b[(.j?2VoPr6/IEb[(.b=o?KLr5;b9b[(.b=o?d*s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!r69llZr$\-;#I[s +r3T;uZr$\-;#I[sr3T;uZr$\-;#I[sr2`TiZr$\%9`27or3T;uZr$\%9`27or3T;uZr$\-;#I[s +r3T;uZr$\-;#I[sr3T;uZr$\-;#It*r4H#,]N"gA<;aC.r3T;uZr$\-;#ICgr3T;uXA&Pn9`1tc +r2`TiXA&Pn9`1tcr3T;uS3m.\;#I[sr3T;uZr$\-;#ICgr3T;uZr$\-;#I[sr3T;uZr$\-;#It* +r3T;u]N"gA<;aC.r4H#,]N"g9;#HhMr1$+OS3m.D6N!'6r1$+FM`10b2Y2hbr/<f8gopbXs8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8:oN +r4H#,]N"gI=o?3@r4H#,]N"gA<;aC.r4H#,]N"gA<;a+"r4H#,Zr$\-;#I[sr4H#,Zr$\-;#I[s +r3T;u]N"g9;#It*r4H#,]N"gA<;aC.r5;b9]N"gA<;a[;r5;b9`**#V=o>p3r4H#,]N"gA<;aC. +r4H#,]N"gA<;aC.r4H#,Zr$\5<;a+"r3T;uZr$\-;#It*r4H#,XA&PV61^!mqh.$.PX55362\u[ +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8;6% +r5;b9`**#V=o?3@r5;b9`**#N<;a[;r4H#,`**#V=o?3@r5;b9`**#V=o?KLr5;b9`**#^?2VWD +r5;b9b[(.j?2VWDr1$+OPX55362\BOs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W,kpA*q=n*'-,i8j)!e;4%@=o?3@r5;b9`**#^?2VWDr6/IEb[(.j?2VoP +r7#0Qe7&:)@JnW2r7#0Qe7&:)@JnV`r7#0Qb[(.r@Jn>Tr5;b9XCh=QVYBH?r7$Q#e7&:"KD`r! +r6/IEb[(.b=o?KLr5;b9`**#V=o?3@r5;b9]N"gI=o?3@r4H#,]N"gI=o>p3r4H#,]N"g9;#gRq +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,kpA*q=n)39ig"bH4eCN'tf#u:^bKS5_`4c)E8GpD/ +r5;b9b[(.j?2VoPr6/IEb[(.j?2VoPr6/IEb[(.j?2VoPr6/IEb[(.j?2VoPr6/IEb[(.j?2W2\ +r9KdNs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8V`bq=rI] +r1lm]SP8t"=o?cXr7#0Qgh-K6@JnW2r7ko^e7&:)@JnV`r7#0Qe7&:)@JnV`r6/IEb[(.j?2VoP +r6/IEb[(.j?2VoPr6/IEb[(.j?2VoPr6/IEe7&:!?2W2\r6/IEe7&:!?2VoPr6/IEb[(.j?2VoP +r6/IEb[(.j?2VoPr6/IEb[(.j?2W2\r6/IEe7&:)@JnV`r7#0Qe7&:)@Jnnmr7ko^gkYgW@JnV` +r7#0Qe7&:)@Jnnmr;OA/s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8VHWp#tc2kj7crjQGaMX7;cdo8>O)PX55362Zs5o8>O)XA&Q1=o?cXr6/IEe7&:)@JnB& +r7#0Qe7&:)@JnV`r7#0Qe7&:)@JnV`r7#0Qe7&:)@JnW2r7#0Qgh-K6M#>b2r7#0Qe7&:)@JnV` +r7#0Qe7&:)@JnV`r7#0Qe7&:1B)L.er7#0Qe7&:)@JnV`r7#0Qe7&:)@JnV`r6/IEe7&:)@JnV` +r6/IEb[(.r@K6B-s8W-!s8V`bq<[_Gkj7ckgtp`>hU9p)`5T^6`PoI%]u7n/]=bi0Uj2g%62Zs5 +o8>O)PX4o!2Z/e*r00MFPX4o!2Y2hbr1$+O`**#V=o?3@r5;b9b[(.b=o?3@r6/IE`**#^?2VoP +r6/IEc%GrD@JnV`r7#0Qe7&:)@JnV`r7#0QXA&P^6N#&5r7#0Qe7&:)@JnV`r7#0Qb[(.j?2VoP +r6/IEb[(.b=o?KLr5;b9`**#V=o?3@r5;b9`**#V=o?3@r5;b9`**#V=o?3@r5;b9`**#V=o?3@ +r5;b9`**#V=o?3@r5;b9`**#V=o?3@r5;b9`**#nL]@DSs8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!r:J#,]PRMI9`1tcr2`TiXA&Pn9`1tcr2`TiXA&Pn9`1tc +r1lm]XA&Pn9`1\Wr2`TiXA&Pf8GoP_r2`TiXA&Pn9`1tcr2`TiXA&Pn9`1tcr2`TiXA&Pn9`1tc +r3T;uXA&Q!;#ICgr3T;uZr$\%9`27or2`TiXA&Pn9`1\Wr2`TiUe(EZ8Go8Sr2`TiUe(Eb9`1tc +r2`TiXA&Pn9`1tcr2`TiXA&Pn9`1tcr2`TiXA&Pn9`1tcr3T;uZr$\-;#I[sr4HkD]N"gA<;aC. +r2`TiPX55362Zs5r00MFPX55361^!mo8>NuM`1Kt62]5gs8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!r69llZr$\-;#I[sr4H#,]N"g9;#It* +r3T;uZr$\-;#I[sr3T;uZr$\-;#ICgr3T;uXA&Pn9`1tcr3T;uXA&Pn9`27or3T;uZr$\-;#I[s +r4H#,Zr$\5<;aC.r4H#,]N"gA<;aC.r4H#,]N"gA<;aC.r3T;uZr$\-;#I[sr3T;uZr$\-;#I[s +r3T;uZr$\-;#I[sr3T;uZr$\-;#It*r3T;uPX4o!2Z&.go8>O)PX55CD?'Y9s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,rjMCc,<;aC.r4H#,]N"gA<;aC. +r4H#,]N"gA<;aC.r4H#,]PRMa=o?3@r5;b9`**#V=o?3@r5;b9`**#ND#D4Sr5;b9`**#F;#H88 +o8>O)PX53-_>jQ8s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8V`bq<[_G +i8j(ZjQGdXfDN9\r4H#,]N"gI=o?3@r5;b9`**#V=o?3@r6/IEb[(.j?2VoPr6/IEe7&:!?2Vs" +r7#0Qb[(.kKD`r!r6/IEb[(.Z<;_\<r1$+9gt_hWM#>J&r6/IEb[(.j?2VWDr5;b9`**#V=o?3@ +r5;b9`**#N<;a[;r4H#,]N"gA<;aC.r4H#,]N"gA<;aC.r3T;ue;4/)s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8V`bq<726i8j(SgtpK/f%A3i`5T^=bg")F`T41Lr2`Tib[(.b=o?3@r6/IE`**#V=o?3@ +r6/IE`**#V=o?KLr5;b9`**#^?2VWDr6/IEb[(.kKD`r!r6/IEc%H&rs8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,kpA+@Sq<726n%=\YPX55C8GpD/r6/IEb[(.r@Jn>T +r6/IEe7&:!?2W2\r69lle7&:"KD`r!r7#0Qb[(.j?2VoPr5;b9`**#V=o?3@r5;b9`**#V=o?3@ +r6/IE`**#^?2VWDr6/IE`**#V=o?KLr5;b9b[(.b=o?KLr5;b9`**#V=o?3@r5;b9`**#V=o?3@ +r6/IE`**#^?2VoPr6/IEc%GrD@JnV`r7#0Qc%GrD@Jn>Tr7#0Qb[(.r@JnB&r7#0Qe7&CWs8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8VHWp$D;Ckj7crjQG4OhW1he +r00MFPX55;6M$*no8>O)PX55S;#JOCr6/IEb[(.j?2VoPr6/IEb[(.j?2VoPr6/IEc%Gr<?2Vs" +r6/IEb[(.kKD`r!r6/IEe7&:)@JnV`r7#0Qe7&:)@JnB&r6/IEb[(.j?2VoPr7#0Qe7&:)@JnW2 +r7#0Qe7&:"KD`r!r6/IEb[(.j?2VoPr6/IEb[(.j?2VWDr5;b9b[(.b=o?KLr5;b9c%Grd`rH)= +m.9o6m-iW_hV$]@bKS5L`PoI%]t:qj]=bha['[3I[+M1!o8>NuM`10b2Y2hbo8>NuM`10b2Z/Ls +o8>O(KKB%$6N"c)r4H#,`**#N<;aC.r5;b9]PRMa=o?3@r4HkD`**#^?2VWDr5;b9b[(.kKD`r! +r7#0Qc%GrD@Jm3#r5;b9b[(.j?2VoPr6/IE`**#^?2VWDr5;b9`**#V=o?3@r5;b9`**#V=o?3@ +r5;b9`**#N<;a[;r4H#,]N"gA<;aC.r4H#,]N"gA<;a[;r4H#,`**#N<;a[;r4H#,]N"gI=o>p3 +r4H#,]N"gA<;aC.r4H#,oZ$q2s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W,rjMCbq9`1tcr1lm]Ue(Eb9`1tcr1lm]XA&Pf8Go8Sr1lm]Ue(EZ8Go8Sr1lm]Ue(EZ8GnuE +r1lm]Ue(EZ8GnuEr1lm]S3m.D6N!??r1lm]S3m.L8Go8Sr1lm]XA&Pf8GoP_r2`TiXA&Pf8GoP_ +r1lm]XA&Pf8Go8Sr1lm]S3m.D6N!WMr1$+OS3m.L8Go8Sr1lm]Ue(Eb9`1\Wr1lm]Ue(EZ8Go8S +r1lm]Ue(EZ8GoP_r2`TiXA&Pn9`1tcr2aN.Zr$\-;#I[sr3T;uZr$[r8Gn]<r/<f:N'7*'61^!m +qh.$-KKB!`3r=Rkqh.$,e?JuQs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W,s]PRMI9`27or3T;uZr$\-;#I[sr3T;uXA&Pn9`27or2`TiXA&Pn9`1tc +r2`TiUe(Eb9`1\Wr2`TiXA&Pf8GoP_r2`TiUe(Eb9`1tcr2`TiXA&Pn9`1tcr2`TiZr$\-;#I[s +r3T;u]N"g9;#I[sr3T;uZr$\-;#I[sr3T;uZr$\-;#I[sr3T;uXA&Pn9`1tcr2`TiXA&Q!;#I[s +r3T;uZr$\-;#It*r1$+NKKB!`3r=Rkr/<f:S3m/?`;fl;s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!r69llZr$\-;#I[sr3T;uZr$\-;#I[sr3T;uZr$\-;#It* +r4H#,]N"gA<;aCFr4H#,`**#ND#CqFr5;b9]PRMa=o?3@r4H#,Ue(*82Y2hbr1$+Rs8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!kj7d%m-iW_hW`SBr4HkDZr$\5<;aC. +r4H#,]N"gA<;aC.r4H#,]N"gA<;a[;r5;b9`**#^?2DNsr6/IEb[(.j?2VWDr6/IE`**#^?2V?7 +r00MFPX4NVX4c:bk1nbg`JON2=o?3@r5;b9`**#V=o?3@r4H#,`**#N<;aC.r4H#,]N"gA<;aC. +r3T;u]N"g9;#I[sr3T;uZr$\-;#ICgs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!kj7d%m-iW_hU9p) +bKS5L`Pod7`Pfa7`k8n\S3m.d<;a[;r5;b9`**#V=o?3@r5;b9`**#V=o?3@r5;b9`**#^?2VWD +r6/IE`**#V=o?KLr5;b9`**#V=o@'1s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8V`bq<[_Gq;gN)Sm;2P4oCO1r4H#,`**#V=o>pKr5;b9`**#V=o?KLr5;b9b[(.j?2VoP +r6/IEb[(.j?2VWDr5;b9`**#V=o?3@r5;b9`**#N<;a[;r5;b9`**#V=o?3@r5;b9`**#V=o?3@ +r4H#,`**#N<;a[;r4H#,`**#N<;a[;r5;b9]N"gI=o>p3r5;b9]N"gI=o?3@r5;b9`**#^?2VoP +r6/IEc%Gr<?2VoPr6/IEb[(.j?2VoPr5;b9b[(.j?2WK5s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8V`bq<[_Gkj7crjQGI^kLe#%r1-OZPX4o!2Z/Lso8>NuM`1L'6N"Jq +r5;b9b[(.b=o?3@r6/IE`**#^?2VWDr6/IE`**#V=o?3@r5;b9`**#V=o?3@r6/IE`**#^?2VoP +r6/IEc%Gr<?2Vs"r6/IEb[(.j?2VoPr6/IEb[(.kKD`r!r69llb[(.j?2VoPr6/IEb[(.b=o?3@ +r6/IE]PRMa=o>p3r5;b9`**#V=o?3@r5;b9`**#V=o?3@r5;b4m-!U!n)39ig"bH4eCMgec+CX% +['[3I['Zm8XfJP*X/rGIO_"'A2Y2hbqh.$-KKB!`3qJ7fqh.$%M`1Hc3r=Rkr1$+OZr$\5<;a+" +r3T;u]N"g9;#It*r4H#,]N"gA<;a[;r4H#,`**#V=o>p3r4H#,`**#V=o?3@r5;b9`**#V=o>p3 +r5;b9]N"gI=o?3@r5;b9]N"gI=o>p3r4H#,]N"gA<;aC.r4H#,]N"gA<;aC.r4H#,]N"gA<;a+" +r4H#,Zr$\5<;aC.r4H#,Zr$\5<;a+"r4H#,]N"gA<;aC.r3T;u]N"gA<;aC.r4H#,Zr$\5<;b!n +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8VrNYPb1er1-OZUe(EZ8Go8S +r1$+OUe(EZ8GnuEr1lm]Ue(ER6N!WMr1$+OS3m.D6N!??r1$+OS3m.D6N!??r1$+OS3m.D6N!?? +r1$+OS3m.D6N!??r1$+OS3m.D6N!??r1lm]S3m.L8Go8Sr1lm]S3m.L8GnuEr1$+OS3m.D6N!?? +r1$+OS3m.D6N!??r1$+OS3m.D6N!WMr1$+OS3m.L8GnuEr1$+OS3m.D6N!WMr1lm]Ue(EZ8GoP_ +r2`TiXA&Pn9`1tcr2`TiXChC39`1tcr1lm]N'6cj2Y2hbo8>NuM`1Hc3r=Rkqh.#sF=Qm?2Z2'\ +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,kpA+Wn;#ICg +r2`TiXA&Pn9`1u(r2`TiXA&PfD>^J/r1lm]Ue(Eb9`1\Wr1lm]Ue(EZ8Go8Sr1lm]S3m.L8GnuE +r1lm]Ue(ER6N!WMr1lm]Ue(EZ8Go8Sr1lm]XA&Pf8GoP_r2`TiXA&Pn9`1u(r3T;uZr$\%9`1tc +r3T;uXA&Pn9`1tcr2`TiXA&Pn9`1tcr2`TiXA&Pn9`1tcr2`TiXA&Pn9`27or3T;uZr$\-;#HhM +qh.$-KKB!`3qJ7fr/<f9jMClrs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W,kpA+ILkPVtlr2`TiZr$\-;#I[sr3T;uZr$\-;#I[sr3T;uZr$\-;#It*r3T;u]N"g9;#I[s +r4H#,]N"g9;#It*r4H#,]N"gA<;a+"r/<f1M`1Hc3r?:)s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!o_/+IoC_>6n)iE\g"bH\`JON";#I[sr3T;uZr$\5<;a+"r4H#,Zr$\5<;aC. +r4H#,]N"gAD#D4Sr4HkD`**#V=o>pKr5;b7`JON2=o>pKr4HkDS3m.44m]>!g"bH4eCN'tf)!@B +r4H#,]N"gA<;aC.r4H#,]N"gA<;aC.r4H#,]N"g9;#I[sr3T;uZr$\-;#I[sr3T;uXA&Pn9`27o +r2`TiZr$VSYQ+Y&s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,coC_>6n)39idaZjreCMgec,@T?`5T^6`Ppo@I/Kd2 +r5;b9]N"gI=o>p3r5;b9`**#N<;a[;r5;b9`**#V=o?3@r5;b9`**#ND#D4SqSe<h`**#V=o-*o +r5;b<s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8V`bq<[_Gkj7d#gt_Fk>k<k3 +r/<f:Zr$\5<;aC.r4H#,]N"gI=o>pKr5;b9]PRMa=o?3@r5;b9`**#V=o?3@r5;b9`**#V=o?3@ +r5;b9]N"gA<;aC.r4H#,]N"gA<;aCFr4H#,]N"gA<;aC.r4H#,]N"gA<;aC.r4H#,]N"gA<;aC. +r4H#,Zr$\5<;a+"r3T;u]N"g9;#It*r4H#,]N"gI=o?3@r5;b9`**#V=o?3@r5;b9`**#V=o?3@ +r5;b9]PRMa=o?3@r5;b9oZ$q2s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s7H$\ +m.9o6m-ilnkLnYIf>PB#PX4o!2Y2hbo8>NuM`1Hc3rG4.r5;b9`**#V=o?3@r5;b9`**#V=o>pK +r5;b9]PRMa=o>pKr5;b9]PRMa=o>pKr4H#,]PRMa=o>pKr5;b7`JON2=o?KLr5;b9b[(.b=o?KL +r5;b9c%Gr4=o?KLr6/IEb[(.j?2VoPr5;b9`**#ND#D4Sr4HkD`**#V=o>pKr5;b9]N"gA<;aC. +r4H#,]N"gA<;aCFr4H#,`**#N<;a[;q:sBUjQFt@f#u:^]=bhh]Y1AIXfJP*Unsl_V50o`Us+s3 +r/<f9HoV"V3r=Rkqh.$-KKB!`3r=Rkqg:BiF=R3Q62\)dr3T;uXA&Q!;#ICgr3T;uZr$\-;#I[s +r4H#,Zr$\-;#I[sr3T;u]N"gA<;a+"r4H#,]N"gA<;a+"r4H#,]N"g9;#It*r4H#,]N"g9;#It* +r3T;uZr$\5<;aC.r3T;u]N"g9;#I[sr3T;uZr$\-;#I[sr3T;uZr$\-;#I[sr3T;uZr$\-;#I[s +r3T;uZr$\-;#I[sr3T;uZr$\-;#I[sr3T;uZr$\-;#I[sr3T;uZr$\m`rH)=s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8(6Lr1$+OPX55;6N!'6r00MFPX55;6N!??r00MFS3m.<62[6> +r00MFS3m.<62[6>r00MFS3m.<62[6>r00MFPX55362Zs5r00MFPX55;6N!'6r00MFPX55362Zs5 +r00MFS3m.<62[6>r00MFS3m.<62[6>r00MFS3m.<62Zs5r00MFPX55362Zs5r00MFPX55362Zs5 +r00MFS3m.<62[6>r1$+OPX55;6N!??r1$+OS3m.D6N!WMr1lm]Ue(EZ8Go8Sr1lm]Ue(EZ8Go8S +r1lm]Ue(ER6M$*nqg:C#KKA^_2Z&.gqh.#sF=R0@3r=:aqh.$,bbkF?s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s88rlr1lm]Ue(EZ8Go8Sr1lm]Ue(EZ8Go8S +r1lm]Ue(EZ8GnuEr1lm]S3m.L8GnuEr1lm]S3m.D6N!WMr1$+OS3m.L8GnuEr1lm]S3m.D6N!?? +r1$+OS3m.L8Go8Sr1lm]Ue(EZ8GoP_r2`TiXA&Pn9`1u(r2`TiXChC39`1tcr2`TiXA&Pf8GoP_ +r1lm]XA&Pf8Go8Sr1lm]XA&Pf8GoP_r2`TiXA&Pn9`1tcr2`TiXA&PV60r\Cqg:BiF=Qm?2Z&.g +qrGTns8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8V`bq<726kj7d6gsQ%q8Go8S +r2`TiUe(Eb9`1tcr2`TiXA&Q!;#I[sr2`TiZr$\-;#I[sr3T;uZr$\-;#I[sr3T;uZr$\-;#I[s +r3T;uZr$[r8Ge'$qh.$-KKB"k_>jQ8s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8V`bq<726 +i8j(Sgtq8<X8K%mr2`TiXA&Pn9`27or2`TiZr$\%9`27or3T;uZr$\-;#I[sr3T;u]N"gA<;aC. +r4HkD`**#ND#CqFr5;b9]N"g!6MlEsnXa"6eCMgec-+>UbKS5nbfTdi;#I[sr3T;uZr$\-;#I[s +r3T;uZr$\-;#I[sr3T;uZr$\%9`27or2`TiXA&Pn9`1tcr2`TiXA&Pn9`1tcr2`Tls8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8V`bq<[_Gi8j(SgtpK/f#u:^`5T^6`Pod7`Q#R%r0:.WZr$\5<;aC.r4H#,]N"gA<;aC. +r4H#,]N"gA<;aC.r4H#,`**#ND#D4Sr5;b9`**#ND#D4Sr5;b9]N"gRKE(uOs8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8V`bq<[_Gkj7d%m-iW_hXR1Bqh.$-KKB%49`27or3T;uZr$\-;#@V? +r3T;uZr$\5<;aC.r4H#,]PRMa=o>pKr5;b9`**#ND#D4Sr4HkD]N"gA<;aC.r4H#,]N"g9;#It* +r3T;uZr$\-;#I[sr3T;uZr$\-;#ICgr3T;uZr$\%9`27or2`TiZr$\-;#I[sr2`TiZr$\-;#I[s +r3T;uZr$\-;#It*r4H#,]PRMa=o>pKr5;b9`**#V=o?3@r4H#,]PRMa=o>p3r5;b9]N"gA<<*!u +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!m.9o6m-ilnkLnYIg"bH:]XIEi2Y2hb +o8>NuM`1Hc3qJ7fr00MF]N"gA<;aC.r4H#,]N"gA<;aCFr4H#,]N"gAD#CqFr4H#,]N"g9;#It* +r4H#,Zr$\5<;aC.r4H#,]PRMa=o?3@r4HkD`**#V=o>pKr5;b9]PRMa=o>p3r5;b9]PRMa=o>pK +r5;b9]PRMa=o>pKr5;b9]PRMa=o>pKr4H#,]N"gA<;aC.r4HkDZr$\5<;aC.r4H#,]N"gA<;aC. +r4H#,]N"gA<9`)HdaZjkbg!c4]sP/RX/rFnSt)UQUnji_Unsm2O_"?:3;\@iluX`SHoUJ7.dV7, +o8>NnF=Qm?2Z%k]r/<f:XA&Pn9`1tcr2`TiXA&Pn9`1tcr3T;uXA&Q!;#ICgr3T;uZr$\%9`1tc +r2`TiZr$\%B)J`(r3T;uZr$\-;#I[sr3T;uZr$\-;#I[sr3T;uZr$\-;#ICgr3T;uXA&Q!;#ICg +r3T;uXA&Q!;#I[sr3T;uXA&Q!;#ICgr2`TiXA&Pn9`1tcr2`TiXA&Pn9`1tcr3T;uXA&Pn9`1tc +r3T;uXA&Pn9`1tcr2`TiXA&Pn9`1tcqTPi:s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +r9VB"Pu7ID62Zs5r00MFPX55362Zs5r00MFPX55+4oCO1r00MFN'7*'62Z[)r00M=M`1Kl4oC7% +r/<f:N'7)t4oCO1o8>O)N'7)t4oCO1r/<f:PX55362Zs5r00MFPX55362Zs5r00MFPX55362Zs5 +r00MFPX55362Zs5r00MFPX55+4oCO1r/<f:PX55362Zs5r00MFS3m.<62Zs5r1$+OPX55362Zs5 +r1$+OPX55;6N!??r1-OZSP8sP9`1GTr1-OZUe(ES9`1\Wr1lm]Ue(EZ8Go8Sr1$+NHoV"N3;\@i +qh.$-KKAIA.f4l[luX`SHoV"N3;Ujrs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!qm:DAS3m.D6N!??r1lm]SP8sW8Go#Pr1lm]SP8sO6N!??r1$+OS3m.D6N!?? +r00MFS3m.<62[6>r00MFS3m.D6N!'6r1$+OS3m.<62[6>r1$+OS3m.D6N!??r1$+OS3m.L8Go8S +r1lm]Ue(EZ8Go8Sr1lm]Ue(EZ8Go8Sr1lm]Ue(EZ8Go8Sr1lm]Ue(EZ8Go8Sr1lm]Ue(EZ8GoP_ +r1lm]XA&Pf8GoP_r2`TiUe(Eb9`1\Wr1lmTM`0pD.f4TQluX`SHoU_U2Y?_=s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s6T@Mkj7crjQGI^kLnYIqSe<hUe(EZ8Go8Sr1lm]Ue(Eb9`1\W +r2`TiXA&Pn9`1tcr2`TiXA&Pn9`1tcr2`TiXA&Pn9`1tcr2aN.XA&Pn9`27or2`TiN'7&c3;\(_ +r00MIs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s7H$\kj7crjQG4OhW`SBr3T;uUe(Eb9`1\W +r2`TiXA&Pf8GoP_r2`TiXA&Pn9`1tcr3T;uZr$\-;#I[sqm:DAZr$\5<;a+"r4H#,]PRMQ;#ICg +qg:BpM`/Mm`QQKMbKS5Sbg">Tc,@T?r4Ij`XA&Q!;#ICgr2`TiXA&Q!;#I[sr2`TiZr$\%9`27o +r2`TiXA&Pn9`1tcr1lm]XA&Pf8Go8Sr2`TiUe(EZ8GhJas8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!o_/+Em-ilnkLnYI +fZ_O^bg")F`Pfa7`5T^JXIo*B2Z0pYr3T;uZr$\-;#I[sr3T;uZr$Y,Er<RLr3T;u]PRMQ;#ItB +r4H#,]PRMYD#CqFr4H#,]PRMQ;#It*r:J#/s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s6T@M +m.9o6m-ilnkLnYIkbX@;HoUJ7.f>f'r3T;uXA&PnB)K#4r2`TiXA&Q!;#I[sr3T;tZuZ)O;#It* +r3T;u]N"g9;#ItBr3T;uZr$\5<;a+"r3T;uZr$\-;#I[sr3T;uXA&Q!;#ICgr3T;uXA&PnB)J`( +r2`TiXA&Pf8GoP_r1lm]XA&Pf8GoP_r1lm]XA&Pn9`1\Wr2`TiUe(Eb9`1tcr3T;uZr$\-;#It* +r4H#,]N"gA<;X%Cr4H#,Zr$\5<;a+"r3T;uZr$\-;#I[sr4HkGs8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!o_/+IoC_>6n)39ig"bH4eCMXP](:h<o8>NuM`1Hc3p^r<qg:BpM`1L79`2P& +r4H#,Zr$\-;#I[sr3T;uZr$\5<;a+"r3T;uZr$\-;#I[sr3T;uZr$\-;#I[sr3T;uXChC;;#I[s +r3T;u]N"gA<;aCFr4HkD]N"gAD#CqFr4H#+ZuZ)W<;aC.r4HkD]N"gA<;a+"r3T;u]N"g9;#I[s +r3T;uZr$\-;#I[sr3T;uZr$\-;#I[sr3T;uZr$\-;#I[sr3T;tZuZ)O;#I[sr3T;tZuYBRX2Mur +]=bha['Zm8Xe_ehUnsl_V50o`Us+s3o8>NnF=QX!.dV7,qh.#sF=R083:(`:luX`DF=R3Q62[fX +r2`TiXA&Pf8GoP_r1lm]Ue(Eb9`1\Wr2`TiXA&Pf8Go8Sr2`TiUe(EZ8Go8Sr1lm]XA&Pf8Go8S +r1lm]XA&Pf8Go8Sr2`TiXA&Pn9`1tcr2`TiXA&Pf8GoP_r1lm]XA&Pf8GoP_r1lm]Ue(Eb9`1\W +r2`TiUe(Eb9`1\Wr2`TiUe(EZ8GoP_r1lm]Ue(Eb9`1\Wr2`TiXA&Pf8GoP_r1lm]Ue(EZ8GnuE +r1lm]S3m.TB)ho2s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W"f9`0i4r/<f:N'7)t4oC7% +r/<f:N'7)t4oC7%r/<f:N'7)t4oC7%o8>NuM`1Hc3qJ7fo8>NuM`10b2Y2hbqh.$%M`1Hc3qJ7f +o8>NuM`1Kl4oC7%r/<f:N'7)t4oCO1r/<f:N'7)t4oC7%r/<f:N'7)t4oC7%r/<f:N'7)t4oC7% +r/<f:PX55+4oCO1r00MFPX55362Zs5r00MFPX55362Zs5r00MFPX55362Zs5r00MFS3m.<62Zs5 +r1$+OPX55<9`1GTr0:.WSP8sP9`1GTr1-OZSP8sG60r\CluX`DF=QX!.f4TQluX`DF=QX!.dV7, +luX`RbbkF?s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,q`JOMW62Zs5 +r1$+OPX55;6N!'6r1-OZPX55<9`1DIr00MFSP8sG62Zs5r00MFPX55362Zs5r00MFN'7*'62Z[) +r/<f:PX55+4oCO1r00MFPX55362Zs5r1$+OPX55;6N!??r1$+OS3m.E9`1GTr1lm]SP8sWD>^2# +r1lm]Ue(EZ8Go8Sr1-OZUe(ES9`1DIr1lm]S3m.L8Go8Sr1lm]Ue(EZ8GnuEr1lm]Ue(EZ8Go8S +r1lm]Ue(EZ8GnuEqh.#sF=QX!.dV7,qg:C$N'74@s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +o_/+Em-ilnkN:RTg"bH4eCN=.hYX[#r1$+OS3m.L8Go8Sr1lm]Ue(EZ8Go8Sr1lm]Ue(EZ8Go8S +r1lm]Ue(EZ8Go8Sr1lm]Ue(EZ8Go8Sr1lm]XA&Pf8Go8Sqg:BiF=QX!.f6Sns8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!o_/+QpA*Y-kMYFag"bH^[>t0\8Go8Sr1lm]Ue(EZ8Go8Sr1lm]Ue(EZ8Go8S +r1lm]Ue(EZ8GoP_r1n3-XA&Pn9`1tcr2aN.Zr$\%B)K#4r2`ThHoU_U2V>[NfZ_O^bg")F`QQKM +`5T^=bg#@gYl(Rrr2aN.XA&Pn9`1tcr2`TiXA&Pn9`1\Wr2`TiUe(Eb9`1\Wr1lm]Ue(EZ8Go8S +r1lm]Ue(EZ8Go8Sr1lm]XChM4s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8VHWp#tc2g"bH4eCN'tf#5PH`5T^6`Pod7`TE.\ +r1lm]XA&Pn9`1tcr2aN.XA&PnB)J`(r3T;uXChC;;#ID,r3T;uZr$\-;#I[sr3T;tZuZ)O;#I[s +r3T;u]PRWJs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s7H$\m.9o6m-ilnkLnYIdaZk"`4bMZ.f4TQ +r/<f:XA&Pf8GoP_r2`TiUe(Eb9`1tcr1lm]XChC39`1tcr2`TiZr$Y,Er<:@r3T;uXA&Q!;#I[s +r2`TiZr$\%9`1tcr2`TiXA&Pn9`1tcr1lm]XA&Pf8Go8Sr1lm]Ue(EZ8Go8Sr1lm]Ue(EZ8Go8S +r1lm]Ue(EZ8Go8Sr1$+OUe(EZ8Go8Sr1lm]Ue(EZ8GoP_r2`TiZr$\%B)K#4r3T;uXA&Q!;#I[s +r3T;uZr$\%9`27or3T;uXChC[M#[MTs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,kpA+(Hp#+oo +g"bH;gtpK/f#5PHk)EF.F=R0@3p^r<luX`SHoUJ7.f?)5r2`TiZr$\-;#ICgr3T;uXA&Q!;#ID, +r3T;uZr$\%B)K#4r2aN.XA&PnB)J`(r1n3-Ue(Eb9`1tcr2`TiXA&Pn9`1tcr2aN.Zr$\-;#I[s +r3T;uZr$\%9`27or2aN.XA&Q!;#I[sr3T;uXChC;;#ICgr2aN.Zr$\-;#I[sr3T;uXChC39`1u( +r2`TiXChC39`1u(r1lm]Ui$%29`1tcr2`TiXChC39`1tcqm:C^`PoI%]sP/RUnsl_V50o`Unji_ +Unsm2O_!g#.dV7,qg:BiF=QX!.eAQVluX`KM`1Hc3p^r<o8>O)XA&Pf8GoP_r1lm]Ue(EZ8Go8S +r1lm]Ue(EZ8Go8Sr1lm]Ue(ES9`1GTr1-OZSP8sW8Go#Pr1lm]Ue(EZ8Go8Sr1lm]Ue(EZ8Go8S +r1lm]Ue(EZ8Go8Sr1lm]Ue(EZ8Go8Sr1$+OUe(ER6N!WMr1$+OUe(ER6N!WMr1lm]Ue(ER6N!WM +r1lm]Ue(EZ8Go8Sr1lm]Ue(EZ8GnuEr1lm]S3m.D6N!??r1$+OS3m.D6N!??r1$+Om)8r(s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s800Dqh.$.N'7)t4oC7%r/<f9KKB$i4o9mnqh.$-KKB!`3r=Rk +qh.$-KKB!`3r=Rkqh.$-KKB!`3r=Rkqh.$-KKB!`3r=Rkqh.$%M`1Hc3qJ7fo8>NuM`1Kl4oCO1 +r/<f:N'7)t4oC7%r/<f:N'7)t4oC7%r/<f:N'7)t4oC7%r00MFN'7*'62Z[)r00MFN'7)t4oCO1 +r00MFN'7*'62Z[)r00MFN'7*'62Zs5r00MFPX55362[!Fr1$+OPX55362Zs5r1$+OPX55;6N!'6 +r00MFPu7IL6N!'6r/<f*F=QX!.dV7,qg:BiF=QX!.dV7,luX`DF=QX!.f.Ads8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8VoMdJT4pr00MFPX55362Zs5r00MFPX55;6N!'6 +r00MFPX55362Zs5r00MFPX55362Zs5r00MFN'7)t4oC7%r/<f1M`10b2Z/Lsr/<f:N'7*'62Z[) +r00MFPX55362Zs5r00MFPX55362Zs5r00MFSP8sP9`1DIr1$+OSP8sP9`1GTr1-OZSP8sP9`1DI +r1$+OS3m.<62[6>r1$+OS3m.<62[6>r1$+OS3m.D6N!??r1$+OSP8sO6N!WMr1-OZS3m.44m[8? +luX`DF=QX!.dV7,qm:DDs8W-!s8W-!s8W-!s8W-!s8W-!s8W,kpA+(Hp#tc2i8j(SgtpK/f$`(! +fZ_Okbffp[D>]njr1$+OS3m.D6N!??r1$+OS3m.D6N!BJr1$+OSP8sO6N!BJr1-OZSP8sP9`1GT +r1-OZSP8sP9`1GTr1-OZUe(EB4m[8?r+n1UF=R+AdJs7Hs8W-!s8W-!s8W-!s8W-!s8VHWp#tc2 +k1nbFgtqnGXSeSTr1$+OS3m.D6N!??r1$+OS3m.D6N!WMr1$+OUe(ER6N!WMr1-OZUe(EZ8Go8S +r1lm]XA&Pn9`1\Wr2`TiUe(B13;\(_fVEc8bg">Tc-+>UbKS5L`Pp$Ec,@T?bKS6/XChC+8GoP_ +r1lm]Ue(EZ8Go8Sr1lm]Ue(EZ8Go8Sr1lm]S3m.L8GnuEr1$+OUe(ER6N!WMr1$+OUe(EZ8GnuE +r9VB%s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s7H$\kj7crjQG4OhU9p)`5T^=bg")F`Pfa7aK268HoV&"8GoP_r1lm]Ue(EZ8GoQ$ +r2`TiXA&Pn9`1tcr2`TiXA&PnB)J`Br2aN.XA&PnB)J`(r2`TiUi$%*8Gqhms8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!o_/+IoC_&&kLnYIg"bH4eCN9rbN=dbluX`DF=R3a8Go8Sr1lm]Ue(EZ8Go8S +r1n3-Ue(EZ8Go8Sr2`TiXA&PnB)J`(r2`TiXA&PnB)J`(r1lm]XA&Pf8GoP_r1lm]Ue(EZ8Go8S +r1lm]Ue(EZ8Go#Pr1lm]SP8sO6N!BJr1$+OS3m.D6N!??r1$+OS3m.D6N!??r1$+OS3m.D6N!?? +r1$+OS3m.D6N!WMr1lm]Ue(EZ8Go8Sr1lm]Ue(EZ8Go8Sr1lm]Ue(EZ8GoP_r1lm]XA&Pf8GoP_ +r:J#/s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8VHWp$D;Ci8j(SgtpK/f$`(!`5T^HPC`(B.dV7, +luX`DF=QX!.dV7,r/<f:XA&Pf8Go8Sr2`TiUe(EbB)JGqr2`TiXA&Pf8GoQ$r2`TiXA&Pf8Go8S +r1lm]Ue(EZ8Go8Sr1lm]Ue(EZD>^2#r2`TiUe(Eb9`1\Wr2aN.Ue(EbB)JGqr2aN.Ue(Eb9`1tc +r2aN.XA&PnB)JGqr2`TiUe(Eb9`1]'r2`TiUi$%29`1tcr1lm]XA&Pf8Go8Sr2`TiUe(EZ8Go8S +r1lm]Ue(EZ8Go8Sr2`TiUe(Eb9`1u(`k8mi['ZX*Unji_Unsl_V50o`Us+s3luX`DF=QX!.dV7, +luX`DF=QX!.dV7,luX`DF=R0@3rGdEr1lm]Ue(EZ8Go8Sr1$+OUe(ER6N!??r1-OZS3m.E9`1GT +r1$+OS3m.D6N!'6r1$+OSP8sP9`1GTr1lm]SP8sW8GnuEr1lm]S3m.D6N!??r1$+OS3m.D6N!?? +r1$+OS3m.D6N!??r1$+OPX55;6N!??r1$+OS3m.D6N!??r1$+OS3m.D6N!??r1$+OS3m.D6N!?? +r1$+OS3m.D6N!??r00MFS3m.D6N!'6r1$+OS3m.<62JO$s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +qUDbHKKB!`3r=Rkqh.$-KKB!X3;\@iqh.$-HoV"V3r=Rkqh.$-KKB!`3r=Rkqh.$-KKB!`3r=Rk +qh.$-KKB!`3r=Rkqh.$-KKB!`3r=Rkqh.$%M`1Hc3qJ7fo8>O)N'7)t4oC7%r/<f:N'6cj2Y2hb +o8>NuM`1Kl4oC7%r/<f:N'7)t4oC7%r/<f:N'7)t4oC7%r/<f:N'7)t4oC7%r/<f:N'7)t4oC7% +r/<f:PX55+4oCO1r00MFPX55362[!Fr00MFPX55362Zs5r00MFPX55362Zs5r00MFN'7)t4m[8? +lte*:F=QX!.dV7,lte*:F=QWn.-taulte*H`2s"=s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!r1-OZN'7*'62Z[)r/<f:N'7*'62Zs5r00MFPX55362Zs5r00MFN'7*'62Z[) +r00MFN'7)t4oC7%r/<f:N'7&k3r=Rkqh.$-KKA^_2Z&.go8>O)N'6cj2Z/Lsr/<f:N'7)t4oC7% +r/<f:N'7*'62Z[)r00MFN'7*'62Z[)r00MFPu7I<4oCO1r00MFPX55362[6>r00MFPX55362Zs5 +r00MFPX55362Zs5r00MFPX55362[!Fr00MFSP8sO6N!??r1$+NHoV%F3UCi;luX`DF=QX!.f%lI +s8W-!s8W-!s8W-!s8W-!s8W-!s7H$\m.9o.jQG[\gsX^'daZjreCMgec.L7`f>PB#PX55362Zs5 +r00MFPX55362Zs5r00MFPX55362Zs5r00MFPX55362Zs5r00MFPX55362Zs5r00MFPX55362Zs5 +r00MFF#iT'.-tauqg:C's8W-!s8W-!s8W-!s8W-!s7H$\kj7crjQG4OhWE&(r1lm]PX55;6N!'6 +r00MFPX55362Zs5r1$+OPX55;6N!'6r00MFS3m.<62[6>r1$+OSP8sP9`1GTr1-OZSP8sP9`'K( +lte*4NE4]UbL4nkbKS5L`Pp$Ec.L7``5T^=bg">Tc02gEr1-OZSP8sP9`1\Wr1-OZUe(ER6N!?? +r1$+OS3m.D6N!??r1$+OUe(ER6N!??r1$+OS3m.D6N!??r1$+OS3m.TB)ho2s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,coC_>6n(HLQ +daZjkbg")F`Pfa7`5T^6`Ppu!<rA1Jr1lm]Ue(Eb9`1]'r1lm]Ue(EZD>^2#r1lm]Ui$%*8Go9# +r1lm]XA&Pf8Go8Sr1lm]Ue(EZ8Go8Sr2aN1s8W-!s8W-!s8W-!s8W-!s8W-!s8W,kpA*q=n)39i +i8j(LeCN'tf#u:^f:7<VCaeXl.f>5gr1lm]SP8sW8Go#Pr1-OZSP8sO6N!BJr1lm]SP8sW8Go#P +r1lm]Ue(EZ8GoP_r1lm]Ue(EZ8Go8Sr1-OZUe(EZ8Go#Pr1-OZSP8sP9`1GTr1-OZPu7IL6N!*G +r1$+OS3m.<62[6>r00MFPX55362[9Ir00MFS3m.<62[6>r00MFS3m.<62[6>r1$+OS3m.D6N!?? +r1-OZSP8sP9`1GTr1-OZSP8sP9`1GTqTPi2m-"<=`qSi_r:J#$pA+ags8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s7H$\kj7crjQG4OhU9p)bKS5L`Pop"V<i"HluX`DCaeXl.dLUjlte*JF#j/g6N!?? +r1-OZUe(EZ8Go#Pr1lm]SP8sW8Go#Pr1lm]Ue(EZ8Go8Sr1lm]Ue(EZ8Go#Pr1-OZUe(ES9`1GT +r1$+OSP8sP9`1GTr1-OZSP8sP9`1GTr00MFPX55+4oCO1r0:.WSP8sW8Go8Sr1lm]Ue(EZ8Go8S +r1lm]Ue(EZ8Go8Sr1lm]Ue(EZ8Go#Pr1lm]Ue(ES9`1GTr1-OZUe(ES9`1\Wr1-OZUe(EZ8Go8S +r1-OZUe(EZD7$[WUnsl_V50o`Unji_Unsm.Kk'Ic.-u%*lte*:CaeXd.-taulte*:F=QWn.-tau +qg:C$Ue(ER6N!WMr1$+OS3m.D6N!??r00MFS3m.<62Zs5r00MFPX55362Zs5r00MFPX55362Zs5 +r00MFS3m.E9`1,@r1$+OS3m.D6N!'6r1$+OPX55;6N!'6r00MFPX55362Zs5r00MFPX55362Zs5 +r00MFPX55362Zs5r00MFS3m.<62[6>r00MFS3m.<62Zs5r1$+OPX55362Zs5r00MFPX55362Zs5 +r00MFS3m.<62Zs5r1$+OUi$/3s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8VtU<Vq/'qg:C#HoV"N3;\(_ +qg:C#HoV"N3;\(_qg:C#HoV"N3;\(_qg:C#HoV"N3;\(_qg:C#HoV"V3r=:aqg:C#HoV"N3;\@i +qg:C#KKB!`3r=Rkqh.$-KKB!`3r=Rko8>NuM`10b2Y2hbo8>O(KKB$i4o9mno8>NuM`1Kl4o9mn +r/<f9KKB$i4oC7%qh.$.N'7)t4oC7%r/<f:N'7)t4oC7%r/<f:N'7)t4oC7%r/<f:N'7)t4oC7% +r00MFN'7*'62Z[)r/<f:N'7)t4oC7%r/<f:N'7)t4oC7%qh.#rA0gMX.-taulte*:CaeXd.-tau +lte*:CaeXd./Ll`s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,s]SQH<3rFq" +qh.$.N'7)t4oC7%r/<f:N'7&k3rFq"r/<f:N'7)t4oC7%r/<f:N'7)t4oC7%qh.$-KKB!`3r=Rk +qh.$-KKB!`3r=:aqh.$-KKB!`3r=Rkqh.$-KKB!`3r=:aqg:C#KKB!`3rFq"qh.$.N'7)t4oC7% +qi+VRN'7)t4oC7%r/<f:N'7)t4oC7%r/<f:N'7*'62Z[)r00MFN'7*'62Z[)r/<f:N'7)t4oC7% +r00MFPX55362Zs5r00MFPX55362Z[)lte*:CaeXd.-taulte*IKKB/5s8W-!s8W-!s8W-!s8W-! +s8W,kpA*q=n)39ig"bH;gtpK/f%A3ibKS5Sbg">Tc0r<*r/<f:N'7)t4oC7%r/<f:N'7)t4oC7% +r/<f:N'7)t4oC7%r/<f:N'7)t4oC7%r/<f:N'7)t4o:4=r/<f:PX55362Z[)lte*9A0gJO,lFHT +s8W-!s8W-!s8W-!o_/+Em-ilnkN:RTg"bH^Ui$$o62Zs5r/<f:PX55362Zs5r00MFPX55362Zs5 +r/<f:PX55362Z[)r00MFPX55+4oCRBr00MFPu7IE;>c\Vqh.$.AMN@k7+0T9daZjreCMgec-+>U +bKS5L`Pp$Ec-+>U`5T^I`4c)ED>]Var1-OZPX55362Zs5r00MFPX55362Zs5r00MFPX55362Zs5 +r00MFPX55362Zs5r00MFPX55;6N!'6r00MIs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8V`bq<726i8j(SgtpK/f#u:^bKS5L`Poj0]#V4` +qg:C$Ue(EZ8Go8Sr1lm]Ue(ES9`1GTr1$+OSP8sP9`1\Wr1-OZUe(ES9`1GTr1-OZSP8sP9`1GT +r0:.WSP8n0YlFb's8W-!s8W-!s8W-!s8W-!s8V`bq<726i8j(SgtpK/f#u:^bKS5O[B](?.dUt" +r,XmrS3m.E9`1GTr1-OZSP8sP9`1GTr1-OZSP8sP9`1GTr1-OZSP8sP9`1GTr1lm]SP8sW8Go#P +r1-OZSP8sP9`1/Qr0:.WSP8sG62Zs5r00MFN'7*'62Zs5r/<f:PX55+4oCO1r/<f:Pu7I<4oCO1 +r00MFPX55362[!Fr/<f:PX55+4oCO1r00MFN'7*'62[!Fr00MFPu7ID62Zs5r00MFPX55362[!F +r1$+OPX52RErZ1>s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!m.9o6m-ilnkLnYI +daZjkbg")F`OidrkB98ZA0gMX.-kChlXV:,A0gJO,l<6Ur1$+OS3m.=;>ctYr1-OZSP8sP9`1GT +r1-OZSP8sP9`1GTr1-OZSP8sP9`1GTr1-OZPu7IL6N!*Gr00MFSP8sG62Zs5r00MFPu7IM9_kNC +f:7<DKOX:i.dLUjlXV:-CaeXd.-taulte*IHoV"V3rG4.r1-OZSP8sW8Go#Pr1-OZSP8sP9`1GT +r1-OZSP8sP9`1GTr1-OZS3m.E9`1,@r1-OZPu7IM9`1GTr0:.WS3m.E9`1DIr1$+OUi!06Xe_eh +S=Z7HV50o`Ur\7"lte*9A0gJO,jStdlXV:-CaeXd.-taulte*:Caf1.3;f:5r1$+OPX55;6N!'6 +r00MFPX55362Z[)r00MFPX55+4oCO1r/<f:PX55+4oCO1r/<f:PX55362Zs5r00MFPX554;>cYE +r00MFPX55362Z[)r00MFN'7*'62Z[)r/<f:N'7)t4oC7%r/<f:PX55+4oCO1r00MFPX55362Z[) +r00MFPX55362Zs5r00MFPX55362Zs5r00MFPX55362Zs5r00MFN'7*'62Z[)r00MFPX55+4oCO1 +r:J#/s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s800Dr,XmrF#j,F3;dhXqg:C$F#j,F3;dhXr,XmqHoV%F3W*qY +qg:C$F#j/>3W"1`r,XmqHoV"N3;\(_qg:C#HoV"N3;\(_qg:C#HoV"N3;\(_qg:C#HoV"N3;\@i +qg:C#HoV%F3W*qYr,XmrF#j,F3;\@iqh.$-KKB!`3r=Rkqh.$-KKB!`3r=Rkqh.$-KKB!`3r=Rk +qh.$-KKB!`3r=Rkqh.$-KKB$i4oC7%qh.$-KKB$i4o9mnr/<f:N'7)t4o9mnr/<f9KKB$i4o9mn +qh.$-KKB!`3r=Rkqh.$-KKB!X39t*#lXV:,A0gMX.-kChlXV:,A0gJO,jStdlXV:;`2s"=s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8VoUiVS9hqh.$-KKB!`3r=Rkqh.$-KKB!`3r=Rk +r/<f9KKB$i4o9mnr/<f9KKB$i4o9mnqh.$-KKB!`3r=Rkqg:C#HoV"N3;\(_qg:C#HoV"N3;\(_ +qg:C$Cbu!#1$`?qlXV:&<$1F:,j/D^lXV:,Jn4)AO8Pejqi+VQKKB!`3r=Rkqh.$-KKB!`3r=n: +qh.$.N'7)t4oC7%r/<f:N'7)t4oC7%r/<f:N'7)t4oC7%r/<f:N'7)t4oC7%r/<f:N'7)t4oC7% +r/<f:N'7&c3:(H0lte*:CaeXd.-taur3_Rbs8W-!s8W-!s8W-!s8W-!s7H$\m.9o6m-j)lgtCK> +daZjreCMgec-k+mbKS5ZeCOGlMu8Msr/<f9KKB!`3r=Rkqh.$-KKB!X3;\@iqg:C#KKB!`3r=Rk +qh.$-KKB!`3r=Rkr/<f:N'7)t4o:4=r/<f:N'7)[3TjWslXV:,A0grn_#OH7s8W,kpA+(Hp#tc2 +i8j(Sgtqt:Nr4i!r/<f:N'7)t4oC7%r/<f:N'7)t4oC7%r/<f:N'7)t4oC7%r/<f:N'7)t4o:4= +r/<f:N'7)t4oC7%r/<f9KKAF0,j]=qkeaRWgtp`>hU9p)daZjkbg">Tc-+>U`5T^=bg">Tc-+>U +m^/#PN'7)t4o:4=r/<f:N'7)t4oC7%r/<f:N'7)t4oC7%r00MFN'7)t4oC7%r00MFN'7*'62Zs5 +r00MFPX55362S$0s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!m.9o6m-ilnkLnYIfZ_O^bg")F`Pfa7`5T^HPC`Ua3rGL7r1-OZSP8sP9`1GT +r1-OZSP8sP9`1GTr1-OZPu7IM9`1GTr1-OZSP8sP9`1GTr0:.WPX554;>ctYs8W-!s8W-!s8W-! +s8W-!s8W-!s7H$\kj7crjQG4OhU9p)bKS5Sbg">Tc.S&#lte*9A0h)34oCjEr1-OZSP8sP9`1/Q +r00MFSP8sG62Zs5r00MFPu7ID62[!Fr00MFPu7IE;>ctYr0:.WSP8sH;>cqNr0:.WPX55362Zs5 +r0:.WN'7)t4o:4=r/<f:N'7)t4oC7%r/<f9KKB$i4o9mnr/<f9KKB$i4oC7%r/<f9KKB$i4o:4= +r/<f:N'7)t4o:4=r/<f:N'7)t4oC7%r/<f:PX55+4oCRBr/<f:N'7*'62Z[)r00MEjMClrs8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,kpA*q=n)39ig"bH-bg")F`Pfa7]=bi$O_!W[.dLUj +k?KM">Uni7+6QlYr+n1eN'7)t4oC7%r00MFPX55362[!Fr00MFPu7ID62[!Fr0:.WPX52+<W&(I +r00MENE,n84oCO1r/<f:PX52+<W%e=r/<f:Pu6Y5LWH9^X/rG(XKAP)Xe_ehX/rG5PDdn1;sRs> +lXV:,A0gJO,jStdlte*9A0h(o3W+h!r0:.WSP8sP9`1DIr0:.WPX554;>cYEr0:.WPX554;>cYE +r00MFPX55362Zs5r00MFPX554;>cYEr00MFPu7IM9`1,@gS9t.V50o`Unji_Unsm.Kk'FZ,jStd +lXV:(>Uo&M,jStdlXV:,A0gJO,jStdr,XmrPX55362Zs5r00MFN'7)t4oC7%qh.$.N'7)t4o9mn +r/<f:N'7)t4oC7%r/<f:N'7)t4o9mnr/<f:N'7)t4oC7%r/<f:N'7)t4o9mnqh.$-KKB!`3r=Rk +qh.$-KKB!`3r=Rkqh.$-KKB!`3r=Rkr/<f:N'7)t4oC7%r/<f:N'7)t4oC7%r/<f9KKB$i4oC7% +qh.$.N'7)t4oC7%r/<f:N'7)t4oC7%r/<f:N'7)t4oC7%r/<f:N'7$eYlFb's8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +p[%)@F#j/71]2;Sr+n1eCbu!*1]2&Fr+n1eCbu!13W*qYr,XmrF#j/>3W*qYr,XmrF#j/>3W*qY +r,XmrF#j/>3W*qYr,XmrF#j,F3;dhXr,XmqHoV%F3W*qYr+n1TA0gJO,j/D^lXV:(>Uo&M,j/D^ +lXV:,A0gJO,lD^Dqh.$-HoV"N3;\(_qg:C#HoV"N3;\@iqg:C#KKB!`3r=Rkqg:C#KKB!`3r=:a +qh.$-HoV"V3r=Rkqg:C#KKB!X3;\@iqh.$-KKB!`3r=Rkqg:C#KKB!`3r=:aqh.$-HoV"V3r=:a +r,XmaA0g>C.dLUjlXV:,A0gJO,jStdk?KM&A0gJO,k&C+s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!r1n3,HoV"N3;\(_qg:C#HoV"N3;\(_qh.$-KKB!X3;\@iqh.$-KKB!`3r=Rk +qh.$-HoV"V3r=:aqh.$-HoV"N3;\(_qg:C#HoV%F3W"1`r+n1eAMN:G+6?HDj]!>`<$14$+6QlY +lte*%S:9).^!bE]fZ_O^bg"eabNQ:2qODj.KKB!`3r=Rkqh.$-KKB!`3r=Rkqh.$.N'7&k3rFq" +qh.$-KKB!`3r=Rkqh.$-KKB!`3r=Rkqh.$.N'7&k3rFq"qh.$.N'7)t4o9mnqh.#rA0gJO,jStd +lXV:,A0gMX.0'>Is8W-!s8W-!s8W-!s8W-!s8V`bq<726i8j(SgtpK/f$`(!daZk#bfe2Rc-+>U +fZ_P:SP8p.3;\@iqg:C#HoV"N3;\(_qg:C#HoV"N3;\(_qg:C#HoV"N3;\(_qh.$-KKB!`3r=Rk +qh.$-KKB!`3r=Rkqh.$.AMN@Q.d(%dlte*Em-"$7q<[_Gkj7crjQG4OhWVh\qh.$-KKB!`3r=Rk +r/<f9KKB$i4o9mnr/<f9KKB$i4oC7%r/<f:N'7)t4oC7%r/<f:N'7)t4o:4=r/<f9KKB!`3rEeM +k?KM!Xde80kMYFag"bH;gtpK/f%A3ibKS5Sbg")F`QQKM`5T^=bg"bX^&*dhqh.$-KKB!`3r=Rk +qh.$-KKB!`3r=Rkqh.$-KKB!`3r=Rkr/<f9KKB$i4oC7%qh.$.N'7&k3rFq"r/<f9KKB/5s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,kpA+(Hp#+oo +g"bH4eCMRW`Pfa7`5T^6`Pom*Z0ZQ^r00MFPX55362[!Fr00MFPu7ID62Zs5qi+VRPX554;>cYE +r0:.WPu7IE;>c\Vr0:.WPX554;>cYEr00MDbbkF?s8W-!s8W-!s8W-!s8W-!o_/+IoC_&&kLnYI +daZjkbg">Tc,@T?a0i2=CaeXd./[m;r00MFPX554;>cA9r0:.WPX55+4oCO1r0:.WN'7*'62Z[) +r00MFPX55362[!Fr00MFPX554;>cYEr/<f9NE,n84oC7%r/<f9KKB$i4o:4=qODj%U2o@cLY-`S +r+.VG>UoVU0)TNAr,XmqHoV"N3;\@iqg:C#KKAsW=Smb4qg:C#KKB!X3;\@iqh.$-KKB!`3r=Rk +qh.$-NE,n84o9mnr/<f9KKB$i4oC7%qh.$-NE,n84oCRBs8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8V`bq<[_Gi8j(Sgtp5uc-+>U`5T^-]Y1hWWp=1@j]!>`<$14$+6?HDk?KLu<$2!j3rFq" +r/<f:N'7&t<W%e=r/<f:N'7)t4oC7%r/<f:N'7)t4oC7%r/<f:N'7)t4oC7%r/<f9KKB$i4oC7% +r/<f:Pu6bAO0l:$['[3@XKAP)XfJP*X/rG(XKAP)XfJP*X/rG5PDe444Qfs!lXV:,A0g>C.dLUj +lXV:,A0gMX./SZYr/<f:PX55+4oCO1r/<f:N'7)t4oC7%r/<f:N'7&t<W%e=r/<f9NE,n84oC7% +r/<f:PX55362Z[)r00MFPX554;9,)aX/rFnSt)UQUr\7"k?KM">Uni7+6?HDlXV9o<%[HQ.,&/h +k?KM">UoYf1]31pr/<f:N'7)t4o9mnqh.$-KKB!`3r=Rkqg:C#KKB!X3;\@iqg:C#KKB!`3r=Rk +qh.$-KKB!`3r=Rkqh.$-KKB!`3r=:aqg:C#HoV"N3;\(_qg:C#HoV"N3;\(_qg:C#HoV"N3;\@i +qg:C#KKB!X3;\@iqh.$-KKB!`3r=Rkqg:C#KKB!`3r=Rkqg:C#KKB!`3r=Rkqg:C#KKB!`3r=Rk +qh.$-KKB!`3r=Rkqh.$-KKB!`3r=Rkr3_Rbs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8VqcH2M5.r+n1eAMO+!1]2&F +r+n1eAMO+!1]2&Fr+n1eCbu!*1]2&Fr+n1eCbu!*1]2;Sr+n1eF#j/71]2;Sr,XmrF#j/71]2;S +r+n1eF#j/71]1f=lXV:(>Uni7+6?HDj]!>b>Uni7+6?HDj]!>`<$14$+513_k)EEo[&hlt^$MnL +qh.$-HoV"N3;\(_qg:C#HoV"N3;\(_qg:C#HoV"N3;dhXqg:C#HoV"N3;\(_qg:C#HoV"N3;\(_ +qg:C#HoV%F3W"1`r,XmqHoV"N3;\(_r,XmqHoV%F3W*qYr,XmqHoV%F3TjWsk?KM">UnoA.d(%d +j]!>b>UnoA.cjVOk?KM5`2s"=s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,qe?Jjl3W"1` +r,XmrF#j/>3W"1`r,XmqHoV"N3;\(_qg:C#HoV"N3;\(_qg:C#HoV"N3;\(_qg:C#HoV"N3;\(_ +qg:C#HoV"N3;\(_r+n1TA0g89+6?HDj]!>b>UnoA.cjVOkB98GXImqjf%Jj8daZjreCN'tf$`(! +daZk#bfe2Rc03$KqODj.KKB!X3;\@iqh.$-KKB!X3;\@iqh.$-HoV"V3r=Rkqg:C#KKB!X3;\@i +qg:C#KKB!`3r=:aqh.$-HoV"V3r=Rkqg:C#KKB!X3;dhXk?KM&A0gJO,jStdlXV:;S9b/7s8W-! +s8W-!s8W-!s8W-!o_/+QpA*Y-kMYFag"bH;gtpK/f$`(!bKS5ZeCMgec.BnIqh.$-HoV"N3;\(_ +qg:C#HoV"N3;\(_r,XmqHoV%F3W"1`qg:C#HoV"N3;\(_qg:C#HoV"N3;\@iqg:C#KKB!`3rF%Z +j]!>`<$14$+6f#<kj7d%m-ilnkLnYIl.+D_NE,k'3;\(_qh.$-KKB!`3r=Rkqh.$-KKB!`3r=Rk +qh.$-KKB!`3r=Rkqh.$.N'7&k3r=Rkqh.$-KKB!`3r=Rkr+n1P>Unlq<p8o=kj7d%m-ilnkN:RT +daZjreCMgec.L7``5T^=bg")F`Pfa7bKS6,V2P4u3;\@iqg:C#KKB!`3r=Rkqh.$-KKB!`3r=Rk +qh.$-KKB!`3r=Rkqh.$-KKB!`3r=Rkqh.$-KKB!`3r=Rkr4Ijcs8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s7H$\kj7crjQFt@f$`(!bKS5Sbg")F`Pfa7 +ert[^HoV%_4oCO1qi+VRN'7)t4oC7%qi+VRN'7)t4o9mnr/<f:N'7&t<W%e=r00MFN'7&t<W%e= +r/<f:N'7*(;?-[rs8W-!s8W-!s8W-!s8W-!s8V`bq;C>si8j(LeCMgec,@T?`5T^6`Pp&`AER2I +lXV:<HoV%g62Z[)r0:.WN'7)t4oC7%qi+VRN'7&k3rFq"qi+VQKKB!i<VqG1r/<f:N'7)t4oC7% +r/<f:N'7)t4o9mnqh.$-KKB!`3r,"_kbX?\[B[?V]t:qj['[3P]Y1hWWlU*Hl"!'@<$13r*W'(o +qeSRqHoV"N3;\(_qg:C#HoV"N3;\(_qKuEBKKB!X3;\@iqKuEBKKB!X3;\@iqg:C#KKB!`3r=Rk +qKuEBKKB!`3r=Rkqh.$-KKAtJXT/>#s8W-!s8W-!s8W-!s8W-!s8W-!s7H$\m.9o.jQG4OhTO-f +bKS5L`PoI%]sP/RaG"-c<$14$+6?HDj]!>`<$14$+8f\)qh.$-KKB!`3r=Rkqh.$-KKB!`3r=Rk +qi+VQKKB!`3r=Rkqh.$-KKB!`3r=Rkqg:C#KKB!X3;\@iqh.$-NE,,CS&W+P]=bhh]Y1qi]sP/R +X/rG1['Zm8XfJP*X/rG(XKAP)XfJP*Unsm.Kk'4D+6?HDj]!>`<$14$+6?HDk?KLu<$2$S1])hd +qh.$-KKB!`3r=Rkqh.$-KKB!`3r=Rkqh.$.N'7&k3rFq"qh.$.N'7)t4o:4=r/<f:N'7&t<W%e= +r/<f:Pu4?RUnji_UnslrHtqhL.cjVOfi0Qb<$0dm/a$@gk?KLu<$1:..cjVOr+n1eN'7&k3r=Rk +qh.$-KKB!`3r=:aqg:C#HoV"N3;[emqg:C#HoV"N3;\(_qg:C#HoV"N3;\(_qKuEBHoV"N3;\(_ +r,XmqHoV"N3;dhXqg:C$F#j,F3;dSKr+.VKA0h%P-fn;Lqc,$AAMO+!1]2;Sqg:C#HoV%F3W"1` +qg:C$F#j,F3;\(_r,XmqHoV"N3;\(_r,XmqHoUtM=SmJ*qg:C#KKB!X3;\@iqg:C#HoV"N3;\(_ +qg:C#KKB$r;?-[rs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s7ta7r+n1eAMO*o1&G3.qckcN>V>qc1&PT;r+.V\AMO*o1&PT; +r+.V\Cbu!#1&PiDr+.V\Cbu!*1]2&Fr+n1eCbu!*1]2&Fr+n1eCbu!*1](E0j]!>`<$14$+6?HD +j]!>`<$14$+6?HDj]!>T<%[32+6QlYb`QGf`4aUKf$`(!bKS5Sbg"eabN,gRqh.$.F#j/>3W*qY +r,XmrF#j/>3W*qYqg:C$F#j/>3W*qYr,XmrF#j/>3W*qYr,XmrF#j/>3W*qYr+n1eF#j/71]2&F +r+n1eCbu!13W*\Lr,XmrF#j/>3W*qYr+.VE<$14$+6?HDj]!>`<$1:..cjVOj]!>b>Uni7+8<=C +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8V`bq>$7tr+n1eCbu!*1]2;Sr,XmrF#j/>3W*qY +r,XmrF#j/>3W"1`qg:C#FAD^\3;\(_qg:C$F#j,F3;\(_r,XmqHoV"N3;dhXr+n1TA0g89+6?HD +j]!>`<$1:..cjVOlXV:'Xde80kMYFai8j(ZjQG[\gtCK>g"bH4eCN'tf$`(!daZjkbg"eabLa\G +q36%"F#j,F3;\(_qg:C#HoV"N3;\(_qg:C$F#j,F3;\(_r,XmqHoV"N3;dhXqg:C#HoV%F3W"1` +qg:C$F#j,F3;\(_qg:C$F#iPs,iquIk?KM">UnoA.dLUjp[%)Cs8W-!s8W-!s8W-!s8W-!s7H$\ +kj7d%m-j)lgtCK>daZjreCMgec-+>UdaZjkbg#@aYkrf-qg:C$F#j/>3W*qYr,XmrF#j/>3W*qY +r,XmrF#j/>3W*qYr,XmrF#j,F3;[emqg:C#FAD^\3;dhXqg:C#HoV%81$)+Mj\6cW<$1>:Yi+U* +i8j(SgtqmtH2DtKr,XmqHoV%F3W"1`qg:C#HoV"N3;\(_qh.$-HoV"V3r=Rkqh.$-KKB!`3r45+ +qh.$-HoV"N3;\(_qh.$.F#iDg.d(tCp[%)0oC_JAp#tc2i8j(`gt^T<hU9p)bKS5Sbg">Tc-+>U +`5T^=bg")F`Rqi3qh.$-HoV"N3;\(_qfGU1HoV%F3W"1`r,XmqHoV"N3;\(_qg:C#HoV"N3;\(_ +qg:C#HoV"N3;\(_qKuEBKKAsW=TAF$s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!o_/+IoC_&&kLnYIdaZjkbg")F`Pfa7`5T^8]XmHG./SZYqh.$.N'7&k3rFq" +qh.$-KKB!`3r=Rkqh.$-KKAm\@f(g>qh.$-KKB!`3r=Rkqh.$-KKB!`3r=Rkr3_Rbs8W-!s8W-! +s8W-!s8W-!s6T@Mkj7crjQFt@f$`(!bKS5L`Pod7`Q,Bkk?KM">Uo&M,l<6Uqh.$-NE,k/3rFq" +qh.$-KKB$i4o9mnqh.$-KKB!`3r=Rkqh.$-KKB!`3r=Rkqh.$-KKB!`3r45+qh.$-KKAsW=Sn(X +k,k,m]Xl+q]">Vg]=bhh]Y1qi]t:qj['[3P]Y1hWWlU*Hk?KLi9-E:b)#I;\r+.V\F#j,F3;[em +qg:C#HoV%F3W"1`qg:C#FAD^\3;\(_qg:C#HoV"N3;S#)qg:C#HoV"N3;\(_qg:C#HoV"V3r=Rk +qh.$1s8W-!s8W-!s8W-!s8W-!s8W-!s8W,coC_&&kLnYIdaZjkbg")F`Oidr]=bheXfC&R/`]A< +fh3IL9c_n[+QZQEj\6cnF#j,F3;\(_qg:C"Hs$8n3;\(_qKuEBHoV"N3;\(_qKuEBHoUtM=SmJ* +qKuECF#j,F3;S#)r,XmpHs$<BD:m(UbKS5Sbg")F`Oidr]=bhh]Y1\Z[&^:1X/rG(XKAP)XfJP* +X/rG(XKAP)Xf.\Rgh]+7<$14$+6?HDj]!>`<$14$+6?HDj]!?"AMO(83r45+qg:C#KKAsW=SmJ* +qg:C"Hs$8n3;\@iqKuEBKKB!X3;\@iqh.$-KKB!`3r=Rkr/<f:N'7)t4o9mnq36#tV50o`Ur[Xa +j]!>T<%[32+6?HDj]!>T<%[32+5'UFj]!>`<$2$L1&H>Xqg:C#HoV"N3;[emr,XmrF#j/>3W*qY +r,XmrF#j/>3W!VYr+n1dCdIu81]2;Sr,XmrF#j/>3W*qYr,XmrF#j/>3W*qYr+n1eF#j/71](E0 +qc,$)7Mt2U)!".'j@1!>9-Dn\+QQ!/j@1!J<$2!;-i@d:r,XmrF#j/71]2;Sr+n1eCbu!13W*qY +r+n1eF#j/>3W*qYr,XmrF#j/>3W!nnr,XmrF#j/>3W"1`qg:C$F#j,F3;dhXqg:BqpA+ags8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W,qS9b$D1&FruqckcN>V>nY0)Jm+qc,$@<@@ZD-i7.$qckcN>V>qc1&G3.r+.V\AMO'e0)T98 +r+.V\AMO*o1&PT;r+.V\AMO*o1&Fruj\6cW<$0dd+QZ<<fh3I@9-Dn\+PBC1fh3IL<$0dd+QZQE +g4Wqe`4ajZhV$]@g"bH;gtpK/f$`(!daZk#bfe2Rc17TLr,XmrF#j/>3W*\Lr,XmrCbu!*1]2;S +r+n1eF#j/71]2&Fr+n1eCbu!*1]2&Fr+.V\Cbu!#1&PT;r+n1eAMO*o1&PT;r+.V\AMO*o1&PiD +r+.V\Cbu!#1$)@Vj]!>`<$14$+5'UFj]!>`<$0dd+QZQEj]!>r\YfE,s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s7H$\prgJNCbu!#1&PiDr+.V\AMO+!1]1f=r+n1eAMO+!1]2&Fr+n1eCbu!*1]2&F +r,XmrCbu!13W*qYr+n1eF#j/>3W*\Lr+n1d>V>,;+6?3;j\6cW9c`=p+6?HDj]!>fJn4-!\a8q\ +m.9oEm-!U!n*'-,kj7crjQG4OhV$]@g"bH4eCN'tf$`(!daZjkbg"eabPA9)qg:C#CdIu?3W*qY +r,XmrF#j/>3W*qYr,XmrF#j/>3W*qYr,XmrF#j/>3W*qYr,XmrF#j/>3W*qYr,XmrF#j/>3W*qY +r+.VE<$14$+6?HDj]!>`<$1t,H2mpEs8W-!s8W-!s8W-!s8W-!s8V`bq<726i8j(Sgtp`>hU9p) +daZjreCMgec.L7`bKS6%U2p0Q3W*qYr,XmrCbu!13W*\Lr,XmrCbu!13W*\Lr+n1eCbu!*1]2&F +r+n1eCbu!*1]2&Fr+n1eF#j/71]2;Sr+n1N<$10j)!".'k?KM$e^rL0hY4RXr,XmrF#j/>3W*qY +r,XmrF#j/>3W*qYqg:C$F#j/>3W"1`r,XmqHoV%F3W!nnqg:C#HoV"N3;\(_qg:C#HoV%F3TX3^ +k?KM4gsQ0%s8W-!o_/+QpA*q=n*'-,g"bH;gtpK/f#u:^bKS5L`Pp$Ec-+>UbKS5L`Pq\DH2M_D +r,XmrF#j/>3W*qYr,XmrCbu!13W*qYr,XmrF#j/>3W*qYqg:C$F#j/>3W"1`qfGU1HoV%F3W"1` +r,Xmp`2s"=s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8V`bq<726 +i8j(SgtpK/f%A3i`5T^6`Pod7`RgW/r+n1dHoV"V3r=:aqh.$-HoV"N3;S#)qh.$-HoUtM=Smb4 +qh.$-HoV"N3;\(_qKuEBHoV"N3;S#)qg:C#HoUclq>^Kps8W-!s8W-!s8W-!o_/+Em-ilnkLnYI +daZjkbg")F`Q#R%`5T^:Mga\d+6?3;r+.V[HoV"N3;\(_qg:C"Hs$9!3r=RkqKuEBKKB!`3r=Rk +qh.$-HoV"V3r=:aqKuEBHoUtM=Smb4qKuEBHoV"N3;\@iq5on)bg">Tc,@T?]=bhq`PoI%]uI^r +['[3P]Y1qi]sP/R]=bhh]Y1hWWmbuefh3IK7MsfG)>dD]r+n1eF#j/>3W*qYr,XmrF#j/>3W*qY +r,XmqCdIu?3W!VYr,XmrF#j/>3W"1`r,XmrF#j,F3;[emr,XmpHs$8n3;g1Es8W-!s8W-!s8W-! +s8W-!s8VHWp#tc2i8j(LeCMgec,@T?]=bhh]Y1\Z[)m].j@1!>6Q+rS)!".'j@1!I7Mu#&-i@d: +r,XmqCdIu?3W*qYr,XmrF#j/>3W*qYqeSRrF#j/>3W*qYr,XmrF#j/>3W*qYr+n1eF#j,F3;URp +g"bH;gtpK/f#u:^bKS5L`PoI%]t:qj['[3I['[?FWiN5'X/rG(XKAP)Xe_eh\Vbdr<$0dd+QQ!/ +fh3I@9-E=q+5':0j]!>`<$2$S1])PZqg:C#HoV"N3;dhXqg:C#FAD^\3;\(_qg:C$F#j,F3;\(_ +qg:C"Hs$8n3;\(_qKuEBKKB!X3;\@iqg:C#KKB!`3ldYJUnsm.FC*Wn+PBC1fh3I@9-E=q+5':0 +j]!>T9-E=q+5':0qckcNHoV%F3W*qYr,XmrF#j/>3W*qYr,XmrF#j/>3W*\Lr+n1eCbu!*1]2&F +r+n1eCbu!*1]2&Fr+n1eCbu!*1]2&Fr+n1eCbu!*1[BX'[uH*_D,f1U);.@pfg?Y16Q+QE);.@p +j@1!>6Q+QE)<=7(j@1!I7Mu#&-i@O1r+n1eCbu!*1]2&Fr+n1eCbu!*1]2&Fr+n1eCbu!*1]2&F +r+n1eF#j/71]2;Sr+n1eCbu!*1]2;Sr+n1eF#j/>3VhIXs8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8Vi[kPSmGqc,$@>V>nR-i6mk +qc,$@<@@ZK0)JWrqc,$@<@@ZK0)Jm+qc,$@>V>nY0)Jm+qckcN>V>nR-i7.$qckcOAMO*o1&G3. +j]!>_7Mt5]*TT[,fh3IL9c`:a)!+I4j\6cK9-E:b)!".'fi0QUXInG3kMYFakj7ckgtpuMkLnYI +g"bH;gtpK/f$`(!bKS5ZeCN9b[ek_=r+n1eAMO*o1&PiDr+.V\AMO*o1&PT;r+.V\AMO'e0)Jm+ +qckcN>V>nY0)Jm+qckcOAMO'e0)T98r+.V[>V>nY0)T98qckcOAMO*o1&PT;qckc89c`:a(thP) +fh3I@9-E=j*SF(.j\6cV7MsfO+RZUss8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,kpA+TF<W$D_ +qckcN>V>qc1&G3.qckcOAMO'e0)T98r+.V\AMO*o1&PT;r+.V\Cbu!#1&PT;r+.V\Cbu!#1&PT; +r+.V\AMN:@*TT[,j@1!I7MsfO+QQ!/fg?Y19-EJ`II-Ruo_/+QpA+@Sq=OCVo_/+IoC_>6n*'-, +i8j(ZjQG[\gtCK>daZjreCN'tf%A3ibKS5Sbg"eQ[ebARr+n1eCbu!#1&PiDr+n1eAMO+!1]2&F +r+n1eCbu!*1]1f=r+n1eAMO+!1]2&Fr+n1eCbu!*1]2&Fr+n1eCbu!#1$)@Vj\6cK9-E=j*SF(. +j]!?%s8W-!s8W-!s8W-!s8W-!s8W-!s8W,kpA*q=n)39ik1nb?eCN'tf$`(!bKS5ZeCMgec-+>U +q36%"Cbu!*1]2&Fr+n1eCbu!#1&PT;r+.V\AMO*o1&PT;r+.V\AMO*o1&PT;r+.V\Cbu!#1&PiD +r+n1eCbu!*1]1f=j@1!>9-DnT);9aQfZ_P9HoV%?1]2&Fr+n1eF#j/>3W*qYr+n1eF#j/71]2;S +r,XmrF#j/>3W*\Lr,XmrF#j/>3W*\Lr,XmrF#j/>3W!VYqc,#s9-F)LXT/>#s8W-!s8W-!s7H$\ +o_/+Em-iW_hV$]@daZk#bfe2Rc,@T?bKS5L`Pod7`QQKMfY"ZjCbu!*1]2&Fr+n1eCbu!*1]2&F +r+n1eCbu!*1]2&Fr,XmrCbu!*1]2;Sr,XmrCbu!13W*qYr,XmrF#j/>3W*qYs8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!m.9o.jQG4OhU9p)bKS5L`Pod7`Pfa7 +`k8n<CcqW31])PZqg:C#FADaT3W"1`qfGU1HoV%F3W"1`r,XmrF#j/>3W*qYr,XmqCdIu81](uS +r+n1eCbu!*1]!Ves8W-!s8W-!s8W-!s8W-!s8V`bq<726g"bH4eCMgec-+>U`5T^-]Y1qi^"QsS +fg?Y<7Mu&>1]2;Sr,XmrF#j/>3W"1`r,XmqHoV%F3W"1`qfGU1FAD^\3;\(_qfGU1HoV"N3;\(_ +qg:C#HoV"N3;\(_on[GHbfSPnhU9p)bKS5Sbg">Tc,@T?]=bhh]Y1qi]t:qj]=bhh]Y1\Z[(Eua +]=bhh]Y2CEIG$t*j@1!A4r!'I)#IPjr+n1eF#j/71](uSr+n1eCbu!*1]2&Fr+n1eCbu!*1](uS +r+n1eF#j,662YdaqeSRrF#j/>3W*\Lr,XmqFADl9s8W-!s8W-!s8W-!s7H$\m.9o.jQG4OhTO-f +`5T^-]Y1qi]sP/R\?2da9-E"R']__#gccG-4qud9']__#qckcOCbu!*1]2&Fr+n1eCbu!*1]2&F +r+n1eCbu!*1]2&Fr+n1eCbu!*1]2&Fr+n1eCbts)62YdaprgJ:m-ilnkLnYIg"bH4eCMgec,@T? +`5T^-]Y1\Z[&^:1X/rG(XKAP)XfJP*\XJc'@nPfO)!".'j@1!I7MsfO+QZ<<j@1!I7Mu#&-i@d: +r,XmrF#j/>3W*qYqg:C$F#j/>3W*qYr,XmrF#j/>3W*qYr,XmrF#j/>3W"1`r,XmqHoV"N3;dhX +qg:C#FAD^\3;\(_qg:C#KK>p*Ur[CPj@1!I7Mt2U(th7ofg?Y<7MsfG)<=7(j@1!I7Mu#&-iA$G +r+n1eF#j/71]2&Fr,XmrCbu!*1]2&Fr+n1eF#j/71]2&Fr+n1eCbu!#1&PT;r+n1eAMO*o1&PiD +r+.V\Cbu!*1](uSb`QG+St)=BS=H1@[rc*?7Mt2U(th7oj@1!I7MsoE']__#fg?Y<7MsoE']__# +j@1!`<@@]U1&PiDr+.V\AMO*o1&PT;r+.V\AMO*o1&PT;r+.V\Cbu!#1&PT;r+.V\Cbu!#1&PiD +r+.V\Cbu!*1]2&Fr+n1c`2s"=s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!q5onY<@@ZD-i6mkqc,$@<@@ZD-i6mkqc,$@<@@ZD-i6mk +qc,$@<@@ZD-i6mkqc,$@<@@ZD-i6mkqc,$@<@@ZD-i6mkqc,$)7Mt2U(th7ofg?Y44r!'I(th7o +fg?Y44r!'I(th7ofg?Y2@lDu`bNS<]kj7d%m-j0)n*'-,kj7d%m-ilnkLnYIg"bH;gtpK/f$`(! +bKS5Sbg#sJFo5f*r+.V[>V>nY0)Jm+r+.V[<@@ZD-i6mkqc,$@<@@ZD-i6mkqckcN<@@ZD-i6mk +qc,$@<@@ZD-i6mkqckcN<@@ZK0)Jm+qckcN>V>nR-eUj)fg?Y<7MsfG)<=7(gccG57MsfG);.@p +gccGH\YfE,s8W-!s8W-!s8W-!s8W-!s8W-!s8V`bq=rI]r+.V[<@@]U1&G3.qckcN>V>nY0)Jm+ +qckcN>V>nR-i7.$qc,$@>V>nY0)Jm+qckcOAMO'e0)Jm+r+.V\AMO'^-fd`6j@1!I7MsfG)<=7( +fg?Y44r!'I)!IfWo_/+\s8W-!s8W-!s8W-!s8W-!s8W-!o_/+QpA+ILkNM:$i8j(ZjQG[\gtCK> +daZjreCN'tf$`(!bKS5_`4c"p=Su_br+.V\AMO*o1&PT;r+.V[>V>nY0)T98qckcOAMO*o1&G3. +r+.V[>V>qc1&PT;r+.V\AMO'e0)T98r+.V[<@?Qc']__#gccG57MsfG)>]kKs8W-!s8W-!s8W-! +s8W-!s8W-!s7H$\p[%),m-ilnkLnYIg"bH4eCN'tf#u:^bKS5ZeCN6i^&*1:r+n1eCbu!#1&PT; +r+.V\AMO*o1&PT;r+.V\AMO*o1&PT;r+.V\AMO*o1&PT;r+.V[>V>qc1&PT;r+.V\AMO'^-epm" +j@1!I7Mu#E:AeZXr+.V\Cbu!#1&PiDr+.V\AMO*o1&PT;r+n1eAMO*o1&PT;r+n1eAMO+!1]1f= +r+n1eCbu!*1](uSr+n1d<@?He)>]kKs8W-!s8W-!s8W-!s8W-!s8V`bq<726kj7ckgtpK/f#u:^ +bKS5Sbg">Tc-+>UfZ_OW`Pp$Ec1lp#r+.V\AMO*o1&PT;r+.VYANfs&1&PT;r+n1eAMO*o1&PiD +r+.V\AMO*o1&PT;r+.V\Cbu!#1&PiDr+n1eCbtk0_#OH7s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W,kpA*q=n)39ig"bH4eCMgec-+>U`5T^6`PoooSblD7r,XmrF#j/71]2;S +r,XmrCbu!*1]2&Fr+n1dCdIu81](uSr+.V[CdIu11&PiDr+.V\Cbu!#1&PiDr+.VYjPg.=s8W-! +s8W-!s8W-!s7H$\kj7crjQG4OhU9p)bKS5L`PoI%]u7n/aK25k6Q+ZC'`1lXr+n1eCbu!*1]2&F +r+n1eCbu!*1](uSr+n1dCdIu?3W*qYr,XmrF#j/>3W*qYr,XmqCdIu?3W!VYr,XmpHs$0nal)7C +i8j(Sgtp`>hU9p)bKS5Sbg")F`Pfa7]=bhs]XkJW[(Eua]=bhh]Y1\Z['[3I['[3^HtV4u'\Phk +gccG57Mu#-0)T98r+.V\Cbu!*1]2&Fr+.V\Cbu!#1&PiDr+.V\Cbu!*1]2&Fr+n1eCbu!*1]2&F +r+n1eCbu!*1]2&Fq5on]s8W-!s8W-!s8W,coC_>6n(HLQdaZjkbg")F`Oidr]=bha['[o-EnNet +gccG-4r!'I(u.:hj@1!J9ca.J1]2&Fr+n1eCbu!*1]2&Fr+.V\Cbu!*1]1f=r+.V\AMO+!1]1f= +qeSRrCbu!*1]2&Fr+.VZ`2rV)q<726kj7crjQG4OhU9p)bKS5Sbg!c4]t:qj['[3P]Y1AIXfJP* +X/rG6Km;9M/_iN(fg?Y44qu[;);.@pfg?Y44r!'I)#IPjr+n1eCbu!*1]2&Fr+n1eCbts)62YOT +r,XmrCbu!*1](uSr+n1dCdIu81]2&Fr+n1eCbts)62YOTqeSRrF#j/>3W*qYr,XmrF#j,>:?ROT +Unsm.D,f1U);ICigccG*6Q+ZC'\kkdfg?Y44qud9'\Phkqc,$AAMO+!1]2&Fr+n1eCbu!#1&PiD +r+n1eAMO+!1]1f=r+.V\Cbu!#1&PT;r+.V\AMO*o1&PT;r+.V\AMO*o1&PT;qeSR=R>m`.S=H1@ +S=Z7HV50WQS@W9-gccG57MsoE'\kkdgccG-4qud9'\kkdgccG-4qud9'\kkdqc,$AAMO*o1&PT; +r+.V\AMO+!1\kTFr+.V\AMO*o1&PT;r+.V\AMO*o1&PT;r+.V\AMO*o1&PT;r+.V[>V>qc1&7Z( +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W,kpA+Vt1&Fruqc,$@<@@ZD-i6mkqc,$@>V>nR-i7.$qc,$@>V>nR-i6mkqckcN<@@ZD-i7.$ +qc,$@<@@ZK0)JWrqc,$@<@?Qc'\kkdgccG*6Q+QE);.@pfg?Y16Q+QE);.@pgccG-4qu^\2WifM +kj7d%m-j<4p$D;Cp[%)0oC_JAp#tc2kj7d%m-ilnkLnYIg"bH;gtpK/f$`(!bKS5qP^WF/-i6mk +qc,$@<@@ZD-i7.$qckcN>V>nY0)T98qckcN>V>nY0)Jm+qckcN>V>nY0)JWrqckcN>V>nR-i6mk +qckcN<@@ZD-i7.$qc,$)7MsoE'\kkdj@1!A4qud9'\kkdj@1!A4r!'I)#::us8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!m.9oHS9b!:0)Jm+qc,$@>V>nY0)Jm+qc,$@>V>nY0)Jm+qckcOAMO'e0)Jm+ +qckcN>V>nR-i7.$qc,$@>V>nR-i6mkj@1!I7MsoE'\kkdgccG-4qud9'\kkdk_<pRs8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!o_/+IoC_>6n*'-,i8j(Sgtp`>hV$]@daZjreCN9rbKJ,S +f>PB#Cbtrn0)Jm+qckcN>V>nY0)T98qckcN>V>qc1&G3.r+.V\AMO*o1&G3.r+.V[>V>qc1&Fru +r+.V[>V>nY0)JWrgccG-4qu[;);ICifg?Y?>UodRs8W-!s8W-!s8W-!s8W-!s8W-!s8V`bq<[_G +kj7d#gt^T<hU9p)daZjreCN9rbKJ,SbKS5`]XI`S1]1f=qckcOAMO'e0)T98qckcOAMO*o1&PT; +r+.VYANfs&1&5BDr+.V\AMO*o1&PT;r+.V[>V>qc1&PT;qckc77MsoE'`1lXr+.V\AMO*o1&PT; +qckcOAMO*o1&PT;r+.V\AMO*o1&PT;r+.V\AMO*o1&G3.r+.V\AMO*o1&PT;r+.V\AMO'^-epm" +k\Nrms8W-!s8W-!s8W-!s8W-!s8W-!s8W,kpA*q=n)iE\g"bH4eCMgec-+>U`5T^=bg")F`QQKM +`5T^ZZ`*b;62YOTqeSRqCdIr762PIaqeSRqCdIr762PIaqeSRqCdIr762PIar+n1dCdIu11&PT; +r+.V\AMO*o1&PT;qKuEFs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s6T@M +kj7ckgtpK/f%A3i`5T^6`Pod7`Pfa7g1*&<>V>qj1]1f=r+.V\AMO*o1&GcQr+.V\Cbu!#1&GcQ +r+.V\Cbts)62YOTq.2_dCdIu81](uSqeSRqCdI`MD#aP8s8W-!s8W-!s8W-!s8W,coC_>6n(HLQ +daZjkbg")F`Pfa7`k8mp]Y2C>EnihmgccGL<@@]U1&PT;q.2_eAMO*o1&5BDr+n1eAMO+!1]2&F +r+.V\Cbu!*1]1f=r+n1eCbu!*1]2&Fr+n1eCbu!*1\\GWo_/+IoC_>6n)39ig"bH;gtpK/f$`(! +bKS5L`Pod7`Oidr]=bhh]Y1\Z[(Eua['[3P]Y1qi]st2Ee6YPr6Q+QE);.@pj@1!aAMO'u62YOT +qeSRqCdIr762PIaqeSRqCdIr762YOTr+.V\AMO*o1&PiDr+n1eCbu!*1]2&Fr+n1eAMO+(3WK-Z +s8W-!s8V`bq<[_Gi8j(Sgtp5uc,@T?]=bhh]Y1\Z['[3Ia]U^\4qud9'\kkdgccG-4qud9'`1lX +r+n1eCbu!#1&PT;r+n1bANfs-1]1f=q.2_eCbts)62PIar+n1dCdIu11&PT;q.2_eCbtpXH2mpE +o_/+QpA+(Hp#+ooi8j(LeCN'tf#5PH`5T^-]Y1\Z[&^:1['[39V52.A9&)TEgccG-4qud9'\kkd +fg?Y44qud9']i%0r+.V\AMO+!1]1f=r+n1eAMO+!1]1f=r+.V\AMO*o1&PiDr+n1eAMO+!1]1f= +r+n1eAMO+!1]1f=r+n1eAMO*o1&PT;r+n1eCbts)62Gt2\XJbYV50o`UpkGTgccG-4qu[;);.@p +gccG*6Q+ZC'\kkdfg?Y44r!*Q*W0J'r+.V\AMO*o1&PT;r+.V\AMO*o1&PT;r+.V\AMO'u62Y:K +qeSRrCbts)62YOTq.2_eCbu!#1&GcQr+.V\Cbt:0Cn.)eUnslWSt)=BS=H1@S=Z7LN/$"Y+PB+" +fg?Y16Q+QE);.@pfg?Y16Q+QE);.@pfg?Y44qu[;)>n&#r+n1dCdIr762>(TqeSRrCbts)62Y:K +q.2_eCbu!#1&GcQr+n1bANfs&1&5BDr+.VYANfs&1&GcQr+.VYP]d$+s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8'[8qc,$@<@@ZD-i6mk +qc,$@<@@ZK0)JWrqckcN>V>nY0)Jm+qckcN>V>nY0)Jm+qckcN>V>nY0)Jm+qckcN>V>2E.bR0, +fg?Y16Q+!7,2#=$fh3I@6Q+QM+PB+"fh3I@6Q+!7,2#pIk01s2m-j<4p%7tRo_/+QpA+ags8W-! +o_/+QpA+@Sq=j7=kj7crjQGI^kLnYIg"bH4eCN'tf#u:^pk*&Q>V>qc1&G3.r+.V[>V>nY0)Jm+ +qckcN>V>nY0)T98qckcN>V>nY0)Jm+qckcN>V>nY0)Jm+qckcOAMO'e0)Jm+qckcN<@@ZD-epm" +gccG*6Q+ZC'\kkdfg?Y44qu[;);.@pgccG9Z`*p(s8W-!s8W-!s8W-!s8W-!s8W,kpA+OFiVRFW +qckcN>V>qc1&G3.qckcOAMO'e0)T98qckcOAMO'e0)Jm+r+.V[>V>nY0)T98qckcN>V>qc1&G3. +r+.V[<@?Qc'\Phkfg?Y44qu[;);.@pfg?Y1>s%]Pq>^Kps8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s7H$\o_/+Em-j0)n*'-,k1nbFgtp`>hU9p)bKS5ZeCMgec02L4qckcOAMO'e0)T98 +r+.V[>V>qc1&PT;r+.V\AMO*o1&PT;q.2_eAMO+!1]2&Fr+.V\AMO*o1&PT;r+n1eAMN:G+5'"! +fh3I@6Q+QE);.@pprgJQs8W-!s8W-!s8W-!s8W-!s8W-!s8W,kpA*q=n*'-,k1nbFgtp`>hTO-f +daZjkbg"eabKJ,SkbX@<AMO*o1&PT;r+.V\AMO*o1&PT;r+.VYANfs&1&5BDq.2_eAMO!l4o&YP +q.2_bANfj#4oAkGr+.V\AMO*o1&G3.j@1!aAMO*o1&PT;r+.VYANfs&1&PT;r+.V\AMO*o1&PT; +r+.V\AMO*o1&PT;r+.VYANfs&1&PT;r+.V\AMO*o1&G3.fg?Y=<$1c+q>^Kps8W-!s8W-!s8W-! +s8W-!s8W-!s7H$\kj7d%m-iW_hU9p)fZ_O^bg"eabJ_B=bKS5L`Pp$Ec-+>Upk*&QCdIr762PIa +qeSRqFADaT3W!nnr,XmqFAD^L62YdaqeSRrF#j,662PIaqeSRqCdIr762PIaqeSRoANfs&1&9nh +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!o_/+Em-ilnkLnYIdaZjkbg">Tc,@T? +`5T^:XJP#Q*W0J'r+n1dCdIr762PIaqeSRqCdIr762YdaqeSRqCdIr762PIaqeSRqCdIr762PIa +qeSRqCdIr762PIaq:sBts8W-!s8W-!s8W-!s8V`bq<726i8j(Sgtp5uc-+>U`5T^6`Pod7`Q#R% +e6YPr6Q+QE)>n&#qeSRrCbts)62PIaqeSRrCbts)62PIar+n1bANfs-1]1f=q.2_eAMO!l4oB+P +q.2_eAMO+!1\kTFqi+VUs8W-!s7H$\o_/+Em-j0)n)39ig"bH4eCN'tf#u:^`5T^6`Poj0]">Vg +`k8mi['[HX]sP/R]=bhh]Y1kEPhA\Pfg?Y16Q+QE)>dD]qeSRqCdIr762PIaqeSRqCdIr762PIa +qeSRqCdIr762PIaqeSRrAMO'u62Y:Kq.2_eCbtlu4oB+PqeSRnbJ=/Xs8W-!m.9o.jQG4OhU9p) +bKS5L`PoI%]sP/R['[3MPDe3['\Phkfg?Y16Q+QE);ICij@1!aCbu!#1&PT;qeSRrAMO!l4oB+P +qeSRqCdIu81](uSr+n1dCdIu81](uSqeSRrCbts)62Pb!o_/+\s8W-!s8W-!m.9o6m-ilnkLnYI +bKS5Sbg!c4]t:qj]=bha['[B$I+_INfg?Y16Q+QE);.@pfg?Y16Q+QE);.@pqckcOCbu!*1]2&F +r+n1dCdIu81](uSq.2_dCdIu81](uSr+n1bANfs-1\kTFr+n1dCdIr762PIar+n1dCdIl.4oB+P +qeSRrAMO*o1&GcQfo10OV50o`Unji_UnslqCg#FY)9G;kfg?Y16Q+QE);.@pfg?Y16Q+QE);.@p +qc,$ACbts)62PIaqeSRqCdIr762YOTqeSRqCdIr762PIar+n1dCdIr762PIar+n1bANfs-1](uS +qeSRrCbts)62Pb!Unsl_V50WQS=H1@W1'!ASt)=BS=H1@\n+[j6Q+!7,2#=$fg?Y16Q+QE);.@p +fh3I@6Q+QE);.@pfg?YS<@@Z[62YOTqeSRqCdIr762>(TqeSRrCbts)62PIaqeSRoANfs-1](uS +qeSRqCdIr762YOTqeSRrAMO*o1&?9"s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,lLhurg-i7.$qckcN>V>nY0)Jm+qckcN>V>nY0)Jm+ +qckcN>V>nY0)Jm+qckcN>V>nY0)Jm+qckcN>V>nY0)Jm+fh3I073]iB,0<7tfh3I073]iB,0<7t +a[IDq73]iB,0<7ta[IE.UQap.n+?>Lo_/+\s8W-!s8W-!s8W-!s8W-!s8W-!s8W,kpA+(Hp#tc2 +kj7crjQG[\gtCK>daZjreCN9rbPQ*AqckcN>V>nY0)Jm+qckcN>V>qc1&G3.qckcN>V>nY0)T98 +qckcN>V>qc1&G3.r+.V[>V>nY0)Jm+qckcOAMO'e0)Jm+qc,#s6Q+QE)9G;kfg?Y!73^DP);.@p +a[IE,6Q+!7,3H"ss8W-!s8W-!s8W-!s8W-!s8W-!s6T@Mke+.s>V>nY0)Jm+qckcOAMO'e0)T98 +r+.V[>V>qc1&PT;r+.V\AMO*o1&PT;r+.V[>V>qc1&PT;qckcOAMO'^-eUj)fg?Y!73^DP);.@p +fg?Y!73^DP)<e`;s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s7H$\ +kj7d%m-ilnkLnYIg"bH;gtpK/f$`(!fZ_O^bg#g:D#@j!r+.V\AMO*o1&PT;q.2_eAMO!l4o&YP +qeSRoANfp,62PIaqeSRoANfp,62PIaqeSRqCdIr762PIaqckbo9.JUf+NI,)fh3I.9.K4S?N:'* +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!m.9o6m-ilnkLnYIg"bH4eCN'tf#u:^daZjkbg">Tc2!TH +r+.V\AMO*o1&5BDr+.V[CdIl.4o&YPqeSRqCdIr762PIaqeSRqCdIr762PIaqeSRqCdIr762>(T +r+n1dCdIl.4o9%]qeSRqCdIr762PIaqeSRqCdIr762PIaqeSRqCdIr762PIaqfGU1CdIr762PIa +qeSRqCdIr762>(Tq.2_N9c_n[+SaI.s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8VHWp#tc2 +g"bH;gtp5uc-+>UbKS5L`Pp$Ec-+>U`5T^=bg#:PS,7;&r,XmqFAD^T:A]-.qfGU1FAD^T:A]-. +qfGU1FAD^T:A]-.qfGU1FAD^T:A]-.r,XmqFAD^L62YdaqfGU/P]d$+s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8V`bq<726g"bH4eCN'tf#u:^`5T^6`Pod7`Q3.-qckcNCdIr762PIa +r,XmqCdIr?:Af/nqfGU2F#j,>:Af/nqfGU2F#j,>:Af/nqfGU2F#j,>:Af/nqfGU1NE-#Ys8W-! +s8W-!s8W-!s8W-!o_/+Em-ilnkL.l2bKS5L`Pod7`Oidr]=bheXfC&I+N[%rj]!?!CdIr762PIa +r,XmqCdIu?3W!VYqeSRqCdIr762PIaqeSRqCdIr762PIaqeSRqCdIr762PIaqeSRqCdImPdJs7H +s8W-!s8W-!s7H$\m.9o6m-ilnkLnYIdaZjreCMRW`Pfa7`5T^-]Y1qi]t:qj]=bha['[HX]sP/R +]=bhuD,eVG,0<7ta%Io(73_VF62Ydar,XmrF#j/>3W*qYr,XmqCdIu?3W*qYqeSRqCdIr762PIa +r+n1dCdIr762PIaqeSRqCdIr762[Nqs8W,kpA+(Hp#+oog"bH-bg")F`Oidr['[3I['[3I['tEt +fg?Y16Q+QE);.@pfg?Y16Q,c$-i@d:qeSRrCbu!#1&GcQqeSRqCdIr762YOTqeSRqCdIr762PIa +qeSRqCdIu?3W!VYqeSRp`2s"=s8W-!s8W-!s8V`bq<726i8j(LeCN'tf#5PH`5T^-]Y1AIXiPTj +a%Io86Q+!7,0<7tfh3I073^DX+N[%rj]!?"Cbts)62PIaqeSRqCdIr762PIar,XmqCdIu?3W!VY +qeSRqCdIr762PIaqeSRqCdIr762PIaqeSRqCdIr762PIar+n1dCdIu81\kTFpk*%sUn+<XUnji_ +Unsl_V50o`Ur[Xaa[IDq73]iB,0<7ta[IDq73]iB,0<7ta[IDq73^hf*W'Y=qeSRqCdIr762PIa +qeSRqCdIr762PIaqeSRqCdIr762PIar+n1bANfp,62PIar+.VYANfp,62>(TqeSR]MfGf!Xe_eh +UnslWSt)=BS=H1@S=Z7@St)^3I*"f$fg?Y!73]iB,0<7ta[IDq73]iB,0<7ta[IE,6Q+!7,2#=$ +qeSRqCdIr762PIaqeSRqCdIr762PIaq.2_dCdIr762PIaqeSRqCdIr762PIaqeSRqCdIr762PIa +qeSRrF#j:#s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8VoUiVQk4k?KM6<@?s7.f33nk?KM6<@?s7.d(%dk?KM">UnoA.cjVOl"!'B>UnoA.d(%d +k?KM$A3f<_.d:J/k?KLi<%Z3\,0*>+a[IDo9.ItT.`k+'a%Io&9.J%P,0*>+a%Io(73]fi<9W]; +o_/+QpA+ags8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,kpA*q=n*'-,i8j(`gt^T<hU9p) +daZk#XIoAp0)9'Al"!'V>V>h`4o8J:qckcN>V>h`4o8J:q.2_d>V>h`4o8J:r+.V[>V>h`4o8J: +r+.V\AMO'e0)Jm+r+.V[>V>2E.`k+'a[IDq73]iB,2#U3a[IDq73]iB,0<7tfg?Y@Z`*p(s8W-! +s8W-!s8W-!s8W-!o_/+Em-jb7FnoT3q.2_bANfj#4o&YPr+.VYANfj#4o&YPq.2_bANfj#4o&YP +q.2_bANfj#4o&YPq.2_bANfs&1&5BDj]!>D73]iB,2#U3a[IDq73]iB,0<7tg20[ds8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8V`bq<[_Gkj7d%m-j)lgtCK> +daZjreCMgec-k+mf>PB"CdIl.4o&YPq.2_dCdIl.4o9%]qeSRqCdIr762PIaqeSRqCdIr762PIa +qeSRqCdIr762PIaqeSRqCdIr76.nmRa%Io&9.ItT.`k+'a]U_*s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s6T@Mkj7d#gt^T<hV$]@daZjreCMgec-+>UdaZk"`4bi"D#8$7qeSRqCdIr762PIa +qeSRqCdIr762PIaqeSRqCdIr762PIaqeSRqCdIr762PIaqeSRqCdIr762PIaqeSRqCdIr762PIa +qeSRrF#j,>:A]-.qfGU1FAD^T:A]-.qfGU1FAD^T:A]-.r,XmqFAD^L62PIaqeSRqCdI/^+3?qq +kbX@?s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!o_/+Em-ilnkLnYIdaZjreCMgec-+>U +`5T^=bg")F`RrDX`5T^jK4=_":A]-.qfGU1FAD[[=Sm28qKuEAHs$5m=SdDIqKuEAHs$5m=Sm28 +qKuEBFAD^T:A]-.qfGU1FAD^T:A\ino_/+\s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s7H$\ +m.9o.jQG4OhU9p)bKS5L`Pod7`Pfa7a0i2*<%[u`62PIar,XmqCdIr?:Af/nqfGU1CdIr?:A]-. +qfGU1FAD^T:A]-.qfGU1FAD^T:AT??qfGU0Hs$8f:AN\ms8W-!s8W-!s8W-!s8W,kpA+(Hp#+oo +g"bH4eCMgec,@T?`k8n$`PoI%]uQP#a%Io&9.KgD0)K`cqfGU1FAD^T:A]-.qfGU2F#j,>:Af/n +r,XmrF#j/>3W!nnr,XmrF#j/>3W*qYqeSRrF#j/>3Ven^s8W-!s8W-!s8W-!s8W-!s8W-!s6T@M +kj7crjQG4OhU9p)daZjd`Pod7`Oidr]=bhh]Y1\Z[(Eua['[3P]Y1\Z[(2Wia[IE,9-D>F,2#U3 +k?KM6CdIr?:A]-.qfGU1CdIr?:Af/nqfGU1CdIr?:Af/nr,XmrF#j,662PIaqeSRqCdIr762Yda +qeSRpHs$FKs6T@Mkj7ckgtpK/f#u:^`5T^-]Y1qi]sP/R\?2dQ=Za_o,0<7tfg?Y!73]iB,0<7t +q.2_dCdIr762PIaqfGU2F#j/>3W*qYqeSRqFADaT3W!nnr,XmrF#j,>:Af/nqfGU2F#j#J@fQK. +s8W-!s8W-!s7H$\m.9o6m-ilnkLnYIdaZjd`Pod7`ODY9a]U^G9.ItT.`Y13a%Io&9.J%P,0*>+ +a%IoXANfp4:A]-.qfGU1FAD^T:A]-.qfGU1FAD^T:A]-.qfGU1FAD^T:Af/nqfGU2F#j,>:Af/n +r,XmqCdIu?3W!VYqeSRqCdIr762PIaqfGTsV2r7$]rS6:Unsl_V50o`Unji_UnslrFCN?\,0<7t +a[IDq73]iB,0<7ta[IDq73]iB,0<7tj]!?"F#j,662YdaqeSRrF#j,662PIaqeSRqCdIr762PIa +qeSRqCdIr762PIaqeSRqCdIr762PIaqeSRqCdIr76-,jm\?2d,V50o`Un"$HW1'!ASt)=BS=H1@ +W1'!n73]iB,0<7ta[IDq73]iB,0<7ta[IDq73]iB,0<7ta[IDq73_V60)9'AqeSRqCdIr762PIa +qeSRqCdIr762YdaqeSRqFAD^L62PIaqfGU2F#j,662PIaqeSRqCdIr762PIao_/+\s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!pUR0a>UnoA.d(%d +k?KM">UnoA.d(%dk?KM6>V>2E.d:J/k?KM$A3f<_.d(%dl"!'B>UnuK5j)B%k?KM$A3f<_.`Y13 +\OIsg73]cF.`Y13\OIsg73]93-cne$a%Inm7OQ;H,0*>+fY"ZbpA+ags8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!o_/+IoC_>6n*'-,g"bH;gtpK/f$`(!l[i[1>UoP\4m?KB +k?KM$A3fBi5l4e=l"!'DA3g#s0'Qn3qckc<A3fs%4m?KBq.2_bANfoq0'Qn3q.2_bANfoq0)9'A +j]!>D73]iB,0<7ta[IDo9.J%P,0<7ta[IDq73]cF.d!k&s8W-!s8W-!s8W-!s8W-!s8V`bq<$Jf +q.2_bANfj#4o&YPq.2_bANfj#4o9%]qeSRoANfp,62PIaqeSRqCdIr762>(TqeSRoANfj#4o&YP +q.2_d>V=,e,0<7ta[IDq73]iB,0<7ta[IDq73_THXT/>#s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,kpA+ILkNM:$i8j(Sgtp`>hV$]@daZjkbg">Tc/kIN +q.2_dCdIr762PIaq.2_bANfj#4o&YPqeSRoANfp,62PIaqeSRqFAD^L62PIaqeSRqCdIr762PIa +qeSR]>Umia,0*>+a%Io&9.J%P,58XFs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,kpA+@Sq<726 +k1nbFgtpK/f$`(!daZjkbg">Tc-+>Uf>PB!Hs$8^62PIaqeSRqCdIr762PIaqeSRqCdIr762Pb! +qeSRqFADaT3W!nnqfGU1FAD^T:A]-.qfGU1FAD^T:A]-.qfGU1FAD^T:A]-.qfGU1FAD^T:A]-. +qfGU1FAD^T:A]-.qfGU1FAD^T:A]-.qfGU1FAD^T:?c:Sa%Io7KPphis8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s6T@Mkj7ckgtp`>hUp&qbKS5Sbg")F`QQKM`5T^=bg")F`TX.Z +qfGU1FAD[[=Sm28qfGU0Hs$5m=Sm28qKuEBFAD^T:AT??qfGU0Hs$8f:AT??qKuEAHs$5m=SdDI +qfGU0Hs$3@MuWhWs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,kpA*q=n)39idaZjreCMgec,@T? +`5T^6`PooOEr0)oqfGU1FAD^T:A]-.qfGU1FAD^T:A]-.qfGU1FAD^T:A]-.qfGU0Hs$8f:AT?? +qfGU0Hs$5m=Sm28on[Gas8W-!s8W-!s8W-!s8W-!s7H$\kj7crjQFt@f#u:^bKS5L`PoI%]t:qj +`5T^;HtUJm.`Y13qeSRpHs$8f:AT??qfGU1FAD^T:A]-.qfGU1FAD^T:A]-.qeSRqFAD^T:A]-. +qeSRqFAD^T:A]-.qfGU/gsQ0%s8W-!s8W-!s8W-!s8W-!s8W-!s8VHWp#tc2i8j(SgtpK/f$`(! +`5T^-]Y28&`O*"Z]=bha['[HX]sP/R]=bhh]Y2?q9$'LGa%Io(73]cF.f4$JqfGU1FADaT3W!nn +qeSRqFAD^L62Pb!r,XmqFAD^T:A]-.r,XmqFADaT3W*qYqeSRqFAD^T:Af/nq;gMum-ilnkLnYI +bKS5L`PoI%]sP/R['[3I['[?,MoeC3a[IDq73]iB,0<7ta[IE,9-F+J62YdaqfGU1FADaT3W!nn +qeSRqFAD^T:A]-.qfGU1FAD^T:A]-.qfGU1FAD^T:A]-.qS]K8s8W-!s8W-!s8W,kpA+(Hp#+oo +g"bH4eCMgec,@T?[sVr29.ItT.`Y13a%Io&9.ItT.`Y13a%Io8>s%t*3Vn,*qfGU0Hs$8n3;S#) +qfGU1HoV"F:AT??qfGU1FAD^T:A]-.qfGU1FAD^T:A]-.qfGU1FAD^T:A]-.qfGU2F#j,>:Af/n +qfGU/P]bTr]u7n/['[3I['ZX*Unji_Unsl_V50o`Upb)Ba[IDq73]iB,0<7ta[IDq73]iB,0<7t +a[IDq73^hm+8^.TqeSRqCdIr?:A]-.r,XmqFADaT3W!nnr,XmqFAD^L62YdaqeSRqCdIr762PIa +qeSRrF#j,662Pb!pk*%f]Y1\Z[&^:1Unsl_V50WQS=H1@S=Z7@St)=BS@Vupa[IDq73]iB,0<7t +a[IDq73]iB,0<7ta[IDq73]iB,0<7tj]!?!CdIr762PIaqeSRrF#j,662Pb!qeSRqFAD^L62Pb! +qfGU1FAD^L62Pb!qfGU1FAD^T:A]-.qeSRqCdImXiW&rXs8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,kpA+!$?KYQCfj-]&>UnoA.d(%dfi0QfA3f<_.bS)h +fj-]&>UnoA.d(%dfj-](A3fBi5hTF)k?KM$A3egR46^9@a%Inm7OQ;H,.U/j\OIsW7OQ;H,.U/j +a%Inm7OP`9-b2\o\OIsfD,g0$q>^Kps8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s7H$\kj7d%m-ilnkMYFag"bH4eCN9ZXQa7\k?KM6>V>8O5l4e=l"!'DA3fBi5l4e= +l"!'TANf9g5j;fEqckc<A3g#s0'Qn3q.2_RA3g#s0'Qn3q.2_RA3f<_.`Y13a%Io&9.J%P,.U/j +a[IDo9.ItT.`Y13a[IE;Z`*p(s8W-!s8W-!s8W-!s7H$\kj7d%Z`*\24o&YPq.2_bANfj#4o9%] +q.2_bANfp,62>(TqeSRoANfp,62>(TqeSRoANfp,62>(Tq.2_bANfj#4kWINa[IDo9.J%P,0*>+ +a%Io&9.J%P,04V#s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!o_/+IoC_>6n)39ik1nb?eCN'tf$`(!fZ_Oj`4c%a62>(TqeSRoANfp,62PIa +qeSRqCdIr762PIaqeSRqCdIr762PIaqfGU1CdIr?:A\inqeSRqFADXC4m?KBa%Io&9.J%P,0*>+ +a%Io6Ht*-Us8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!o_/+Em-j0)n)iE\g"bH4eCN'tf#u:^ +daZjkbg"eabLj2'qfGU1FAD^T:A\inqfGU1CdIr762Pb!qeSRqFAD^T:A\inqfGU1CdIr?:A]-. +qfGU1FAD^T:A]-.qfGU1FAD^T:A]-.qfGU1FAD^T:A]-.qfGU1FAD^T:A]-.qfGU0Hs$8f:A]-. +qfGU1FAD^T:A]-.qeSR=9.Itl9)nqks8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W,kpA+(Hp#b&bg"bH4eCMgec-+>UbKS5Sbg">Tc,@T?bKS5_`4bqu@etISqfGU0Hs$8f:AT?? +qfGU0Hs$8f:AT??qKuEAHs$5m=SdDIqKuEAHs$5m=SdDIqKuEAHs$5m=Sm28qfGU5s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8V`bq<726kj7ckgtpK/f%A3ibKS5L`Pod7`Q#R%a]U_&FAD^T:A]-. +qfGU1FAD^T:A]-.qfGU1FAD^T:AT??qfGU0Hs$8f:A]-.qfGU0Hs$8f:AT??qfGU0Hs$6pYlFb' +s8W-!s8W-!s8W-!s8W,coC_>6n(HLQdaZjkbg")F`Pfa7`5T^-]Y2=t]!cEX[o5?.9.Kg\:AT?? +qKuEBFAD[[=SdDIqfGU0Hs$8f:A]-.qfGU1FAD^T:A]-.qfGU1FAD[[=Sm28qfGU1FADU`@fQK. +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,coC_>6n)39ig"bH4eCMgec,@T?]=bhs]XkJW[(Eua +['[3P]Y1\Z['[3I\V5:<9JFL[.`Y13a[IE<A3g$6:A]-.qfGU1FAD^T:Af/nqfGU1CdIr?:A\in +qfGU1CdIr?:A\inqfGU1FAD^T:A]-.qeSRqFAD\NXQ]$>i8j(LeCMgec,@T?]=bha['[3I['[3I +[rc)i7OQ;H,.U/ja[IDq73]iB,3N2\qfGU1FAD^T:A]-.qfGU1FAD^T:A]-.qfGU1FAD^T:A]-. +qeSRqFAD^T:A]-.qfGU0Hs$FKs8W-!s8W-!s8V`bq<[_Gi8j(ZjQG4OhTO-faK25LAP]d63k.j; +[o5>t9JEqS3k&$Ka%Ink;`a/R5l,k1qKuEAHs$5m=SdDIqKuEAHs$5m=SdDIqKuEBFAD[[=SdDI +qKuEAHs$5m=SdDIqKuEAHs$8f:AT??qfGU1FAD^T:A]-.qfGU+Lhu:fYh@ggbKS5L`PoI%]rS6: +Unsl_V50o`Unji_UnslrFCMdM-b2\oa[IDa7OP`9-cne$\OIsg73]93-cne$fi0R#FAD^T:A]-. +qfGU1CdIr?:A]-.qeSRqFAD^T:A\inqfGU1FAD^L62Pb!qfGU1FAD^T:A]-.qfGU1FAD(bICm/* +['[3@XKA:pUnji_S=Z7@St)aJQ(4G9S=Z7MFCi!P-b2\o\OIsW7OP`9-b2\o\OIsg73]93-b2\o +a[IDa7OQkg/c0?MqeSRqCdIr762Pb!qeSRqFAD^L62Pb!qfGU1FAD^L62Pb!qfGU1FAD^T:A\in +qfGU1CdIr?:A]-.q:sBts8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s7ta7fk!\,>s$_F45!n$fj-\m>s%4S.bS)hfi0Qd>UnE445!Rbfj-\m>s%4S.bS)h +fj-](A3egR45!n$fj-\m>s#Sd-b2\o\OIsW7OP`9-b2\o\OIsW7OP`9-b2\o\OIsW7OP`9-ePf- +o_/+\s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8V`bq<[_G +kj7crjQG4OhV$]@daZk3L2?*b5j;fEl"!'DA3f<_.d:J/l"!'DA3f<_.d:J/l"!'DA3fBi5j;fE +l"!'DA3fBi5j;fEl"!'DA3fBi5j;fEfi0QD9.IJA-cne$\OIse9.IJA-b2\o\OIsW7OP`9-ePf- +s8W-!s8W-!s8W-!s8W,kpA*q=n)oUKq.2_RA3fBi5j3#Xl"!'CCeX)(5j3#Xk\NrVCeX)(5j3#X +k\NrVCeX&/9^$:dl"!'VCdI;r5l5@`l"!&h9JFRW,.L<#\OIse9.IJA-b2\oa%Io7XIoOms8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s7H$\ +m.9o6m-iW_hV$]@g"bH4eCMgec-+>Ul'-VnCdIl.4o9%]qeSRoANfp,62>(TqeSRqCdI9$9`&Wl +qeSR^CeX_B62PIak\NriCdIr?:A\ink\NriCdH*7._&/+a%Inl9JEtM0ZdHZs8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s6T@Mkj7d%m-iW_hV$]@daZjreCMgec-+>UbKS5Sbg#@JO8F#o +qfGU1FAD^T:A]-.qfGU1FAD^T:A\inqfGU1FAD^T:A]-.qfGU1FAD^T:A]-.qKuEBFAD[[=SdDI +qKuEAHs$8f:AT??qfGU0Hs$5m=Sm28qKuEAHs$5m=Sm28qKuEBFAD[[=Sm28qKuEBFAB;D3ltMd +q;gN7s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s7H$\m.9o6m-iW_hU9p) +daZjkbg">Tc,@T?`5T^6`Pp$Ec,@T?kbX@;FAD[[=SdDIqKuEBFAD[[=SdDIqKuEAHs$5m=SdDI +qKuEAHs$5m=SdDIpk*&PHs$5m=SdDIqKuEAHs$5m=SKA's8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +o_/+Em-ilnkLnYIdaZjkbg")F`Pfa7`5T^:Mgabn.f4<_qKuEBFAD[[=Sm28qKuEAHs$5m=SdDI +qKuEBFAD[[=Sm28qKuEAHs$8n3;[emqKuEAHs$8f:ABHNs8W-!s8W-!s8W-!s8W-!s8V`bq<[_G +i8j(SgtpK/f#5PH`5T^-]Y1qi]u7n/]=bht>YV\+3ltMdpk*&PHs$5m=SdDIqKuEAHs$5m=SdDI +qfGU0Hs$5m=SdDIqKuEBFAD[[=Sm28qKuEAHs$5m=SdDIr3_Rbs8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!m.9o.jQG4OhU9p)daZjd`Pod7`Oidr]=bha['[HX]sP/R]=bha['[oMS[h3; +a%Inl9JFL[.`Y13qfGU1FAD^T:A]-.qfGU1FAD^T:A]-.qfGU1FAD^T:A]-.qfGU1FAD^T:A]-. +qfGU1FAD^T:A]-.q5on>jQG4OhU9p)`5T^-]Y1qi]sP/R['[3@XKB'>7EItB\4eTe7OP]>0Y'Y# +\4eURCdIr?:A]-.qfGU1FAD^T:AT??qKuEAHs$8f:A]-.qKuEBFAD^T:A]-.qfGU1FAD^T:AM#V +s8W-!s8W-!s6T@Mm.9o.jQGI^kL.l2bKS5?NJ4i?3k.j;\4eTs9.IGF0Xse1a%Inl9JFRk48X+p +qKuEAHs$5m=SdDIqKuEAHs$5m=SdDIqKuEAHs$5m=SdDIqKuEAHs$5m=SdDIqKuEAHs$5m=SdDI +qKuEAHs$5m=SdDIqKuEAHs$3HPi1Wck1nbFgtp5uc,@T?['[3@XKA:pUnji_Unsl_V50o`UpkGT +\OIsW7OP`9-b2\o\OIsW7OP`9-b2\o\OIsW7OQkg/c0WbqfGU1FAD^T:A]-.qfGU1FAD^T:A]-. +qfGU1FAD^T:A]-.qfGU1CdIr?:A\inqfGU1FAD^T:A]-.fW:^``PoI%]sP/RX/rG!V50WQS=H1@ +S=Z7@St)=BS>V$f\OIsW7OP`9-b2\o\OIsb2E86:-b2\o\OIsW7OP`9-b2\o\OItDCdIr?:A]-. +qfGU1CdIr?:A\inqfGU1FAD^T:A]-.qfGU1FAD^T:A]-.qfGU1FAD^T:A]-.qeSRqFADV\aoDD@ +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,_Z`)A[7+kj- +e6YPm?:<IP46^9@bZ%]t>s$_F45!n$fj-\m>s$_F45!n$fj-\m>s$_F45!n$fj-\m>s$_F43'uD +\OIsW7OP`9-b2\o\OIsD6n>f;-`09^\OIsD6n>f;-`09^\m7bgm-juSs8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,kpA+ILkMYFai8j(SgtpK/f%@'r +l"!'4AOkuq5h'+.l"!'DA3fBi5j;fEk\NrWA3fBi5j;fEl"!'DA3fBi5j;fEl"!'DA3fBi5j;fE +l"!'DA3egR41Is<\OIsV9JEtM0Y'Y#\4eTe7OP]>0Xse1\4eU/XIo.Yq>^Kps8W-!s8V`bq<[_G +k1nbUFB7UA9^-(Qk\NrWA3g$.60VoFk\NrVCeX)(5j3#Xk\NrVCeX&/9^$:dl"!'CCeX&/9^$:d +k\NrWA3egR41Is<\4eTd9JF"H-b)i(\4eTd9JEqS3qr"(s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8Vi[kNM:$kj7d#gt^T<hU9p) +daZk#bfeYGXQXIoqeSRqCdIr760N,Yq.2_dFAD^L60N,YqeSR^CeX_J:A\ink\NriFAD%99`&p, +qeSR^CeX_J:A]-.e6YPQ9JEtM0ZdHZ\4eTd9JH7b_#OH7s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8VHWp#tc2k1nbFgtp`>hU9p)daZjkbg"Scf%A3ibKS5qP^WFN:A]-.qfGU1FAD^T:A]-. +qfGU1FAD^T:A]-.qfGU1FAD^T:A]-.qKuEAHs$8f:AT??qfGU0Hs$8f:AT??qKuEBFAD[[=SdDI +qfGU0Hs$5m=Sm28qKuEBFAD[[=SdDIqKuEAHs$8f:<-U6\4eU?Z`*p(s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8V`bq<726k1nbFgtpK/f%A3i`5T^=bg">Tc-+>U +`5T^=bg"eQ[ebARqKuEAHs$5m=SdDIqKuEAHs$5m=SdDIqKuEAHs$5m=SdDIqKuEAHs$5m=SdDI +qKuE?K4=\)=SdDIqKuE1HsZjQs8W-!s8W-!s8W-!s8W-!s8W-!s8VHWp#tc2g"bH4eCMgec-+>U +`5T^6`Pod7`Q)I\qfGU0Hs$8f:AT??qKuEAHs$5m=Sm28qKuEAHs$5m=SdDIqKuEAHs$5m=SdDI +qKuEAHs$5m=SdDIqKuE?bJ=/Xs8W-!s8W-!s8W-!s8W-!o_/+Em-ilnkL.l2daZjd`Pod7`Q#R% +`5T^-]Y2@nZ+!Xm[o5?;?:=R@@etISqKuEAHs$5m=SdDIqKuEAHs$5m=SdDIqKuEBFAD[[=SdDI +qKuEAHs$5m=Sm28qKuEAHs$4*iW&rXs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8V`bq<[_G +i8j(SgtpK/f#u:^`5T^-]Y1qi]t:qj['[3P]Y1\Z[(Eua]=bht>YV_%0ZQg9\4eTs9.Kg\:AT?? +qfGU0Hs$5m=Sm28qKuEAHs$8f:AT??qKuEAHs$5m=SdDIqKuEAHs$8f:AT??qKuEBFADY.Mr<[Z +g"bH-bg")F`Oidr['[3I['[3I[(2Wi\4eTd9JEtM0Xse1\OIsV9JFL[.f4<_qKuEBFAD[[=SdDI +qKuEBFAD[[=Sm28qKuEAHs$8f:AT??qKuEAHs$8f:AT??qfGU/gsQ0%s7H$\m.9o.jQGI^kLnYI +daZjg[BZZA<4GUU\4eTd9JEtM0Xse1\4eTd9JEtM0\U"pqKuEAHs$5m=SdDIqKuEAHs$/r@etIS +pk*&PHs$/r@etISpk*&PHs$5m=SdDIqKuEAHs$5m=SdDIqKuEAHs$5m=SdDIqKuEAHs$3/Fnsh? +o_/+Em-ilnkL.l2bKS5L`PoI%]rS6:Unsl_V50o`Unji_UnsldFChsU0Xse1\4eTd9JF"H-b)i( +\OIsW7OP]>0Y'Y#e6YQ?FAD^T:A]-.qfGU1FAD^T:A]-.qfGU1FAD^T:A]-.qfGU1FAD^T:A]-. +qfGU1FAD^T:A]-.qfGU1FACH+]u7n/]=bha['Zm8Xe_ehUnslWSt)=BS=H1@S=Z7LN/"2t/#G]b +`&9TP6n>f;-`09^VF2rQ2E7R%/%J+sVF2rF7OP`9-g>/,k\NriCdI9$9`&p,k\NriFAD%99`&p, +k\NriFAD%A<p4?nqfGTsFB7UA9^$:dqfGTsFB7UA9`&p,q:sBts8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s43Bbe6YPm?:<:L7+>O2e6YPm?:<:L7+kj- +e6YPr>s$_F44IS)fj-\`<*7gZ44IS)bZ%]t<%ZU+7*JV4fj-\M7OP'$/#G]bVF2r36n>-&/%J+s +VF2r36n>f;-`09^VF2r36n?KDAG#Tks8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!m.9o:oC_>6n(HLQg"bH:bfeIU;qY_Pl"!'4AOkEb8(hHD +fk!\,AOkEb8(qfVfk!\;CeWMn8(qfVk\NrGAOks#9\EuIk\NrGAOkuq5hT^=fj-\L9JEtM0Xse1 +\4eTd9JEtM0Xse1\4eTd9JEtM0\EJ!s8W,kpA+@Sq=OCVo_/+IoC_4`_WYf0k\NrVCeX&/9\O>[ +k\NrHD,BG49^-(Qk\NrVCeX&/9^$:dk\NrVCeX&/9^$:dk\NrHD,BG49\O>[\4eTd9JEtM0Xse1 +W(f.Z9JEqS3k.j;aa@b$s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,coC_>6n(HLQg"bH4eCN'tf#u:^bKS5rHsZ#Q9^$:d +k\NrVCeX&/9^$:dk\NriFAD^T:?ZLfqfGTsFB7UA9`&p,k\NriFAD%A<r6u6k]BkhFB7(+8%2DX +[o5>t9JEqS3k&$KgS9u4s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!o_/+IoC_>6n)iE\ +g"bH4eCN'tf$`(!bKS5Sbg">Tc.L7`kDO?VHs$5m=SdDIqKuEAHs$5m=SdDIqKuEBFAD[[=Sm28 +qKuEAHs$8f:AT??qKuEAHs$5m=SdDIqKuEAHs$5m=SdDIqKuEAHs$5m=SdDIqKuEAHs$5m=SdDI +qKuE/FB86c=R(9?fk![_;``!XIK0?Is8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!o_/+IoC_>6n(HLQdaZjreCMgec-+>U`5T^JbfdrD`QQKM`5T^WS;6rg=SdDI +qKuEAHs$5m=SdDIqKuEAHs$5m=SdDIqKuE?K4=\)=SdDIpk*&PHs$5m=SdDIqKuE?K4=\)=SdDI +prgJQs8W-!s8W-!s8W-!s8W-!s7H$\kj7crjQG4OhU9p)fZ_OW`Pod7`Pfa7a-hq->YY'B=SdDI +qKuEAHs$5m=SdDIqKuEAHs$5m=SdDIqKuE?K4=\)=SdDIpk*&PHs$/r@etISpk*&PHs$/r@fQK. +s8W-!s8W-!s8W-!s8W-!s8VHWp#tc2g"bH;gtp5uc,@T?`5T^-]Y1qi]t:qj\?2d?;`_Bd3ne(% +pk*&NK4=V.@ebRbqKuEAHs$5m=SdDIqKuEAHs$5m=SdDIqKuEAHs$5m=SdDIqKuEAHs$/r@etIS +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,coC_>6n)39idaZjkbg")F`Oidr +]=bha['[HX]sP/R]=bha['[3I['t-d\4eTd9JEtM0XjtAk\NrhHs$5m=SdDIqKuEAHs$5m=SdDI +qKuEAHs$5m=SdDIqKuEAHs$5m=SdDIqKuEAHs$5m=SdDIq36$TgtpK/f#u:^`5T^-]Y1qi]sP/R +['[3=N/"i90W7]'\4eTd9JEtM0Xse1a]U_%Hs$5m=SdDIqKuEAHs$5m=SdDIqKuEAHs$5m=Sm28 +qKuEBFAD[[=Sm28qKuEAHs$&tD"RGso_/+Em-ilnkMYFadaZjkbg!VVKr7m7\4eTT9f9FS0W7]' +\4eTd9JEtM0XjtAk]Bl%Hs$5m=SdDIqKuEAHs$5m=SRMXqKuE?K4=V.@d8>Ipk*&NK4=\)=SRMX +pk*&NK4=\)=SRMXqKuE?K4=\)=SRMXqKuEAHs$&tD#2)Os8W-!s8V`bq<726i8j(LeCMgec,@T? +['[3I['ZX*Unji_Unsl_V50o`UoA3<W(f.Z9JED>27Z1(W(f.Z9JEtM0W7]'\4eTd9JFRk48O>, +qKuEAHs$5m=SdDIqKuEAHs$5m=SdDIqKuEBFAD%A<r.2Gk]Bl%Hs#TS<p4X+k]BkhFB7UI<p59S +daZjkbg")F`O*"ZX/rG!V50WQS=H1@S=Z7@St)=BS=,S)W(f.H6n>-&/#G]bVF2r36n>-&/#G]b +VF2r36n>f;-`09^VF2rf>s%q*:?ZLfk\NrVCeX_J:?ZLfk\NrVCeX&7<p4?nk]BkhFB7UI<p4X+ +k]BkhFB7UI<p4X+k]BkhFB84mdJs7Hs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!o_/+0E`:"`9ugL5a';?g?:;h=:!$O"a]U^T?:;n<43(T#a]U^L<*7XV7*/Rn +e6YPb=Zb;B43:Vefj-\[>YW73.],TaVF2r36n>-&/#G]bVF2r36n>-&/#G]bVF2r36n>-&/#G]b +daZkJs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8V`bq=OCVkj7crjQG4OhU9p)ert[<AOkEb8(hHDfk!\,AOkHk:tfb_g20[?D,Ar':tfb_ +k\NrGAOkHk:tfb_g20[?D,BG49\O>[g20[MCeVlZ9"7PK\4eTT9f9CY3iGb1[o5>s;`^jO27HLF +Vc5n5XInkNp%7tRo_/+QpA+(Hp#tc2kbX?oD,Ar':tfb_g20[?D,Ar':tfb_g20[?D,Ar':tfb_ +g20[>AOkHk:tfb_g20[?D,Ar';!;^hg20[>AOj7(0W.l7W(f.J9f9CY3iGb1W(f.J9f:S9[f?C- +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s7H$\kj7d%m-iW_hV$]@daZjreCMgec.f"Wk]BkhFB7UI<p4X+k]BkhFB7UI<p4?n +k]BkhFB7UA9^$S!k]BkhFB7UI<p4X+k]BkhFB7UI<p4X+k\Nqj<'Rij3k&$KVc5mi;`_@'=o\O% +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s7H$\m.9o6m-iW_hWEVKdaZjreCN'tf#u:^ +bKS5Sbg"eQ[d&6HqKuE/FB86c=Qjj-qKuE/FB89\:AT??qKuEAHs$5m=SdDIqKuEAHs$5m=SdDI +qKuE1HsZYs=SdDIl?lq7Hs$5m=R(9?qKuE1HsZ)c?M]%Ol?lq'HsZYs=R1QLpk*&2E`BMH3k'3? +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s7H$\ +kj7crjQG4OhTO-ffZ_O^bg">Tc,@T?bKS5L`Pp$Ec,RE-pk*&NK4=\)=SRMXpk*&NK4=\)=SRMX +pk*&NK4=V.@ebRbpk*&NK4=\)=SRMXpk*&NK4=V.@ebRbpk*&PHs#TeD#aP8s8W-!s8W-!s8W-! +s8W,coC_>6n(HLQdaZjreCMRW`Pfa7`5T^6`Po<.@d%o7pk*&NK4=V.@ebRbpk*&NK4=V.@ebRb +pk*&NK4=V.@ebRbpk*&NK4=V.@ebRbpk*&NK4=V.@ebRbqS]K8s8W-!s8W-!s8W-!s8W-!s8W-! +kj7d%m-iW_hU9p)bKS5N]Xl&#`Oidr`5T^-]Y2@nZ+!Xm[o5?AD,C"[@ebRbpk*&PHs$/r@ebRb +pk*&NK4=V.@etISpk*&NK4=\)=SRMXpk*&NK4=V.@ebRbpk*&KLi!+ks8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s7H$\m.9o.jQG4OhU9p)`5T^6`Poj0]">Vg['[3P]Y1\Z[(Eua +['[3LHtp/b0XjtA[o5>t9JG.28,@U8qKuEAHs$5m=SdDIqKuEAHs$5m=SRMXqKuE?K4=V.@ebRb +pk*&NK4=V.@ebRbpk*&PHs$&tCt[V#daZjd`PoI%]sP/R['[3I['[3I['t-dW(f.Z9JED>27Q=6 +W(f.J9f:U88,.^GqKuEAHs$5m=SdDIl?lq7Hs$5m=SdDIpk*&PHs$5m=SdDIqKuEAHs$5m=SdDI +q5'#9oC_>6n)39ig"bH4eCM[JZ*nIOW(f.J9f9FS0W%5gW(f.Z9JED>27Q=6a(%a<Hs#Z]?M]%O +l?lq'HsZYs=R(9?l?lq'HsZ)c?KuoEl?lq7Hs#]dAEnPKl[i[4HsZT#@d8>Il?lq5K4=+n?MK.^ +l[i[5Jn4Y/@eljYo_/+\s8W-!s8W-!o_/+Em-ilnkLnYIdaZj[]Y1qi]rS6:Unsl_V50o`Unji_ +UnsldFChsU0W7]'W(f.J9f9FS0W7]'W(f.Z9JED>25j5,a';@&FB7UI<pG'=k]BkhFB86c=Qjj- +k]BkhFB7UI<pG'=qKuE/FB7[S?KuoEk]BkjHsZ#Y<pG'=k]BkVRZQ4XhU9p)`5T^-]Y1\Z[%sOo +UnslWSt)aJQ(4G9S=Z7@St)`R25WblVF2r36n>-&/#G]bVF2r36n>-&/#G]bVF2r36n>-&/&tmh +k\NrVCeX&7<p4?nk\NrVFB7UA9^$S!k\NrVFB7UA9^$S!k\NrVFB7UI<p4X+k]BkhFB7UA9^$S! +q:sBts8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8V?6f?%/W +a]U^I=Za`.43(T#a]U^G>YW7D:!$O"a';?\=ZaZ/:!$O"a]U^I=Za`.43:Vea]U^G>YW=C43:Ve +\4eTR6n>-&/#G]bVF2r36n>-&/#G]bVF2r36n>-&/#G]bVF2rGAP_slq>^Kps8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,kpA+(Hp#tc2 +k1nbFgtp\r[b54^g20[?D,Ar':tfb_g20[?D,Ar':tfb_g20[?D,Ar':t'G`g20[?D,Ar':tfb_ +drJC@D,Ar':t'G`aDFnc;`^gU5IXQPVc5mi;`^gU5GqIF[o5>c<'Rij3nUg@m.9oBpA+(Hp$D;C +m.9o6m-iVdGhR"2g20[?D,Ar':tfb_g20[?D,Ar':tfb_g20[AE`Cb0:tfb_g20[?D,Ar':tfb_ +g20[?D,Ar':qBq$W(f.J9f9FS0W7]'W(f.J9f8kD25j5,q;gN7s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,kpA+@Sq<726 +k1nbFgtpK/f$`(!bKS5`]XHU9<7l=uk]BkXF^4-P<p4X+fQCH_FB71;<9SF)k]BkhFB7UI<p4X+ +k]BkhFB7UI<p4X+k]BkWHt);]<ju!gVc5mY<'Rij3i>qAVc5n\s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8V`bq<726kj7ckgtp`>hU9p)daZjreCN9rbKJ,SbKS5`XIng1AEnPK +qKuE1HsZYs=R(9?l?lq'HsZ)c?KuoEl?lq'HsZ)c?KuoEl?lq'HsZ)c?KuoEl?lq'HsZ)c?KuoE +l[i[5Jn42!AGCddl?lq(Jn4Y/@dAVVl[i[4HsZ#Y<k;R*\m7c#jPg.=s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,kpA+(Hp#+oog"bH;gtp5uc-+>U +bKS5L`Pp$Ec,@T?bKS5L`Ppr/L\QL2k_<pKK4=V.@dAVVon[GMJn4Y/@dAVVpk*&NK4=V.@ebRb +pk*&NK4=V.@ebRbpk*&PHs#]dAGCddl?lq5bJ=/Xs8W-!s8W-!s8V`bq<726i8j(SgtpK/f#u:^ +bKS5L`Pod7`Q4jGa(%a:K4=V.@eGOnpk*&NK4=M0D"rWlpk*&NK4=M0D"rWlpk*&NK4=V.@ebRb +pk*&NK4=V.@ebRbpk*&KLi!+ks8W-!s8W-!s8W-!s8W-!s8W,kpA+(Hp#+oog"bH4eCMRW`Oidr +]=bhq`PoI%]u7n/\?2d?;`_Bd3ll/;qKuE?K4=V.@ebRbpk*&PHs$/r@ebRbqKuE?K4=V.@ebRb +pk*&NK4=V.@ebRbpk*&NK4=V.@eGOns8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8VHWp#tc2g"bH4eCMgec,@T?]=bha['[HX]sP/R]=bha['[HX]r-6sW(f.I<'R<U27HLF +a(%a:K4=V.@ebRbpk*&NK4=V.@ebRbpk*&NK4=.uAG(appk*&AJn4Y/@dAVVpk*&AJn4Y/@dAVV +l[iZqeCMgec,@T?]=bha['[3I['[3IX/rG%AQ5U&25j5,W(f.J9f8kD27Q=6k]BkjHsZ)c?MK.^ +l?lq'HsZT#@d8>Il[i[DHs#Z]?M]%OqKuEAHs$5m=SdDIqKuEAHs#UFYi+U*i8j(SgtpK/f!pp% +Vc5mZ9f8kD25j5,W(f.J9f8kD25j5,[o5?AD,C(V=R(9?qKuE1HsZ)c?MK.^l?lq(Jn4.o?MK.^ +l[i[5Jn42!AF"hXl[i[5Jn42!AEnPKl[i[5Jn42!AF"hXl[i[5Jn42!AG(appsdFcs8W-!s8W-! +s8W-!s8VHWp#tc2i8j(LeCMgec,@T?['[3I['ZX*Unji_Unsl_V50o`UoAHIW(f.J9f8kD25j5, +W(f.J9f8kD25j5,W(f.Z9JFRk46h3"pk*&@HsZ)c?KuoEl?lq'HsZYs=R(9?k]BkhFB7UI<pG'= +k]BkhFB7UI<pG'=k]BkhFB7UI<p6B@g"bH4eCMRW`Oidr['[3@XKA:pUn"$HS=Z7@St)=BS=H1@ +VHZKd6n>-&/#G]bVF2r36n>-&/#G]bVF2r36n>-&/#G]bVF2rE9JG[H9\O>[k\NrVFB7+4;!;^h +k]BkhCeWW)<9SF)gi?BXFB71;<8;Lngi?BJD,B#.<8;Lng20[MFB7YVfDkmNs8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!fY"Z(>t)e=:!$O"\m7bH=ZaZ69"J:s +a]U^I=ZaZ69$(3ta]U^I=ZaZ/:!$O"a';?\=ZaZ/:!$O"a]U^:>t(VY/#G]bVF2r36n>-&/#G]b +VF2r36n>-&/#G]bVF2r36n>-&/'*p-o_/+\s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!o_/+Em-ilnkLnYIdaZjiHtV,D8(2KW +a(%`qD,A;j<8)1caDFo1D,A;j<7>kdaDFo1D,A]%;qc(bdrJC@D,A]%;quCmfQCHSE`C+s<2W\[ +VHZKu;`^gU5GqIFVHZKu;`^gU5GhXRVHZL1XJP:Tp$D;Cm.9oBpA*q=n)39ifQCHSE`CM.;quCm +drJCBE`Ch7<7>kdgi?BCE`:G-;qQ4tdrJC>F^3RA>hF1(g20[=F^3^B<7>kdgi?B*>t(\d25aD< +Vc5mZ9f8kD25aD<W(f.XCg$f<s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!o_/+Em-j0)n)iE\daZjreCN9rbKJ,S +fS".pF^3OG@b>g.fQCHOF^3RA>j-91fQCHOF^4-P<nMP"k]BkXF^4-P<nMP"l?lpjF^3OG@d8>I +f6h&=>t(Yj5GqIFVc5mY<'R9[5PaC!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W,kpA*q=n)39ik1nbFgtpK/f#u:^daZjkbg">Tc-+>Ujd_+kHsZ)c?KuoEl?lq'HsZ)c?KuoE +qKuE1HsZ)c?KuoEqKuE1HsZ)c?KuoEl?lq'HsZT#@dAVVpk*&AJn42!AF"hXl?lq(Jn42!AF"hX +l[i[5Jn42!AF"hXa(%`=>=IbgYlFb's8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!o_/+Em-j)lgtCK>daZjkbg">Tc-+>U`5T^=bg")F`QQKM +fX.aDL2?X;@d&P_k_<p;L2?(.D"WU#k_<p;L2?(.D!6Uil[i[5Jn42!AF"hXl[i[5Jn42!AF"hX +l[i[5Jn42!AD)ods8W-!s8W-!s8W-!o_/+Em-j)lgsX^'fZ_O^bg")F`Pfa7`5T^)Htq;V>jHuP +on[GWLhuj=@d&P_pk*&KLhuj=@eGOnpk*&KLhua?D"rWlon[GWLhua?D"WU#on[GWLhua?D"kK; +s8W-!s8W-!s8W-!s8W-!s8W-!s7H$\kj7crjQG4OhTO-f`5T^6`Pod7`Oidr`5T^-]Y2=t\u91> +[o5?/D,g1aD"rWlon[GZK4=V.@eGOnpk*&NK4=V.@eGOnpk*&KLhuj=@eGOnpk*&KLhua?D"WU# +on[G[P]d$+s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!o_/+Em-ilnkLnYI +bKS5L`PoI%]t:qj['[3P]Y1\Z[(Eua['[3LFCM.I5GqIFVc5mY<'SE59'_(>l[i[5Jn42!AF"hX +l[i[5Jn42!AF"hXpk*&AJn42!AF"hXl[i[5Jn42!AF"hXl[i[4HsZK%CsphabKS5L`PoI%]sP/R +['[3I['[?FWi&f\W(f.J9f8hJ5H%:6W(f.I<'TYq?L*2Rl[i[5Jn42!AF"hXl[i[5Jn4Y/@dAVV +pk*&AJn42!AF"hXl[i[4HsZ)c?L*2Rk01s#gtpK/f#P2'WGQ"@9f8kD25j5,W(f.J9f8kD25j5, +W(f.i@nQ$6?KuoEl?lq'HsZ)c?L*2Rl[i[4HsZ,jAF"hXl[i[5Jn4.o?L*2Rl[i[5Jn4)"D!Q[` +k_<p>Jn42!AF"hXl[i[5Jn42!AF"hXq5'#Ls8W-!s8W-!s8W-!s8W-!s8W-!o_/+Em-ilnkL.l2 +bKS5L`PoI%]rS6:Unsl_V50o`Unji_UnsldFChCF25j5,W(f.J9f8kD25j5,W(f.J9f8kD25j5, +a(%a,HsZ)c?KuoEl?lq'HsZ)c?KcK3k]BkhFB7[S?KcK3k]BkhFB7UI<nMP"k]BkXF^3RA>hF1( +fQCHO[&hs9hU9p)bKS5L`Po3k[&^:1UnslWSt)=BS=H1@S=Z7@St)0N8Z"m+VF2r36n>-&/#G]b +VF2r36n>-&/#G]bVF2r36n>-&/%8G<g20[MFB71;<8)1ck\NrJE`Cb0:u$(jgi?BLE`Ch7<8)1c +gi?BLE`Ch7<8;Lngi?BLE`Ch7<8)1cq:sBts8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W,kpA*:.ON1j'\m7b9>t)k<41\]d\m7bH=Za3#7Clbna]U^:>t)eD9$(3t +\n+[X@nOjG43(i'a(%`^@nOdO9"._[VF2r36n>-&/#G]bVF2r36n=[$4JkLsVF2r36n=[$4JkLs +R85rt]XIk?s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8V`bq<[_Gkj7ckgtp`>hU[mAaDFntD,eu);oifTg20[-D,eSn<7>kd +g20[*DI1e4;q#bcdrJC9E`:V5>hF1(aE1b@F^3RA>hF1(`GT"[<'R6a7Aj*LVHZKd>=GGh5GhXR +VHZKe<'R9[5KKq&p[%)0oC_>6n*'-,kj7d&e^rGr>hF1(fQCHOF^3RA>hF1(fQCHOF^3RA>hF1( +fQCHOF^3RA>hF1(fQCHOF^3RA>hF1(fQCHOF^3C9;l<SZVc5mY<'R9[5GqIFVc5mY<'R9[5KK%A +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8V`bq<[_Gkj7ckgtp`>hU9p)bKS5Sbg"_-OP"\\fQCHOF^43Z?J'C* +fQCHOF^3RA>j-91fQCHOF^4-P<nMP"fQCHaHsYHJ>h=@4k]BkWHt(`N>fU>HVc5mY<'R9[5GqIF +Vc5nE]WhG9s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s7H$\m.9o6m-j)lgtCK> +g"bH4eCN'tf#u:^fZ_O^bg">Tc0:I@l?lq(Jn4.o?L*2Rl[i[5Jn42!AF"hXl?lq(Jn42!AF"hX +l[i[5Jn42!AF"hXk_<p=HsZ#kD!6Uik_<p;L2?(.D!6Uik_<p>Jn42!AF"hXl[iZk@V)E@7EC[G +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8V`bq<[_Gi8j(SgtpK/f%A3ibKS5L`Pp$Ec,@T?`5T^=bg")F`T<VFk_<p;L2?(.D!-^r +k_<p:MfIp<ET`7"k_<p;L2?%2ETi-non[GJL2?1-AE\bal[i[2L2?1-AF"hXon[GLHsZ'ffDkmN +s8W,kpA+(Hp#+oog"bH4eCMgec-+>U`5T^6`Pom*Z+=LBk_<pHLhuC/AE\bak_<p:MfIs8D!-^r +k_<p:MfIs8D!6UikDO?DL2?%2ETi-nk_<p;L2?(.D!-^rkDO?[s8W-!s8W-!s8W-!s8W-!s8W-! +s8W,kpA*q=n)39ig"bH:bfdrD`Oidr`k8mp]Y1qi]u7n/]=bhcCg!W>7E8n1on[GWLhua?D"WU# +k_<pHLhua?D"WU#on[GWLhua?D!6Uion[GJL2?O=D!-^ron[GWLhu74EV5-(s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s6/h<i8j(SgtpK/f#5PH]=bhh]Y1\Z[(Eua +['[3P]Y1\Z[&.%rVc5mY<'R9[5GqIFdrJCNL2?1-AE\baon[GMJn42!AE\bal[i[2L2?(.D!Q[` +l[i[2L2?1-AE\bal[i[5Jn42!AF"hXk_<osbg")F`Oidr['[3I['[3I[&^:1W1'!L<'R9[5GqIF +Vc5mY<'R9[5It,hl[i[4HsZ,jAE\bal[i[5Jn4)"D!Q[`k_<p>Jn42!AF"hXl[i[5Jn42!AF"hX +l[i[5Jn3NXbL4nk\XJb[>=GJb2476&W(f.I<'R<U25j5,W(f.Y;``BJ;sJa:l[i[5Jn4Y/@dAVV +l[i[5Jn42!AF"hXl[i[2L2?1-AE\bak_<p;L2?(.D!6Uik_<p;L2?(.D!6Uil[i[2L2?1-AE\ba +kDO?UgsQ0%s8W-!s8W-!s8W-!s8W-!s8W-!s8V`bq<726i8j(Sgtp5uc,@T?['[3@XKA:pUnji_ +Unsl_V50o`UoAHIR85rD9f8>74K(t3W(f.J9f8kD25j5,W(f.J9f9Ln:[3=6l?lq%FB7UI<pG'= +k]BkWHt)Ag?IsR6k]BkWHt);]<nMP"fQCH_FB7%:>hF1(fQCHOF^3RA>iio@i8j(LeCMgec,@T? +['[3I['ZX*Un"$HS=Z7LR['D7S=H1@Qs!"K:HYLB/#G]bR85rB6n>-&.ssB?VF2r36n>-&/#G]b +VF2rG>t*Oh<7l=uk]Bk\E`C\6>hj@!gi?BLE`Ch7<8;LnfQCHSE`C\6>gm^lgi?BLE`Ch7<7l=u +gi?BHF^41]fDkmNs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +aFnTF>t)>17Clbn\m7b9AP^EN41\]d\n+[Z=Za3+:WHs;\n+[K>t)eD9"JS0a(%`QAP^?V9"JS0 +a(%`><'R<U2476&R85r5:HY%@4IJu-VF2r&:HY%@4IJu-VF2r&:HYOS5N(Vcs8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +o_/+QpA*q=n)39ig"bH*XJNmR?H?t_`GT#$DI1D+?H$egaE1b-DI1D+?H@4paE1b0FC)q(?H@4p +`GT#'FC*%1?H@4paE1b0FC*%*<2W\[VHZKe<'R6a7Aj*LVHZKe<'QaQ8Z,NPVHZL1XJP.In*'-, +m.9o6m-j0)n(>:]aE1b0FC*%1?J'C*aE1b?Ht(3FB@q?3f6h&KFC*RH@b>g.f6h&LHtUQKB@hN? +aa@aQHt(0=?IsR6`GT"[<'R9[5GqIFVc5mY<'R6a7Aj*LVHZLAXIoOms8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W,kpA*q=n*'-,g"bH4eCN'tf#u:^fW:^tF^3OG@b>g.f6h&[F^3OG@b>g.fQCHOF^3OG@b>g. +f6h&ZHt(`N>h=@4f6h&[F^3OG@b6!:f6h&HDI05?5GqIFVc5mY<'QdH4P6a-s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8V`bq<[_Gkj7d#gt^T<hU9p)daZjreCN'tf#u:^ +bKS5N]Xm9aES,q^k_<p>Jn3MeDX)UUfS"/.Jn4)"CtF&Dk_<p*Ht)DnACuQQl?lq%L2>Ih@d&P_ +fS"/.Jn3MeDWlgkfS"/+L2?(.CtODYk_<p;L2=qQ?D^pq[sVrjs8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,coC_>6n)iE\ +daZjreCMgec-+>UbKS5Sbg")F`QQKM`5T^9[B\nQETi-nkDO?CMfIs8D!-^rkDO?DL2?%2ET`7" +k_<p:MfIs8D!6Uik_<p;L2?(.D!6Uik_<p>Jn4)"D!6Uies_^#s8W-!s7H$\kj7crjQFt@f$`(! +bKS5L`Pod7`Pfa7VhBHHE`;1VD!6UikDO?CMfIp<ETi-nkDO?DL2?%2ET`7"kDO?CMfIp<ET`7" +kDO?CMfIp<ET`7"kDO?CMfJQpPlLd`s8W-!s8W-!s8W-!s8W-!s8W-!s7H$\kj7crjQFt@f$`(! +`5T^-]Y28&`Oidr`5T^-]Y28&`M\*&Vc5ml>t*q7ETi-nk_<p:MfJEGD!-^rkDO?CMfIs8D!-^r +k_<p:MfIp<ET`7"on[GJL2?%2ET`7"kDO?QLhu_Wq>^Kps8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!o_/+IoC_&&kLnYIdaZjd`Poj0]">Vg]=bha['[HX]sP/R\XJb[>=FrU4Jl=O +Vc5mY<'Su^@d&P_k_<p;L2?(.D!6Uik_<p;L2?(.D!6Uik_<p;L2?(.D!6Uik_<p;L2?(.D!6Ui +k_<p;L2?+=IF?WrbKS5C]Y1\Z['[3I['[3I['ZcrOI00BVc5mJ=\5Mj5GqIFVc5mlAP_NED!6Ui +k_<p;L2?(.D!6Uik_<p;L2?(.D!6Uik_<p*Ht);oD!6Uik_<p;L2?(.D!-^r`k8m^D-s2?5FG;0 +Vc5mY<'R9[5FG;0Vc5mY<'Rs*:[3=6k_<p>Jn4)"D!Q[`k_<p>Jn4P1D!6Uik_<p;L2?(.D!6Ui +k_<p;L2?(.D!6Uik_<p;L2?(.D!6Uik_<p;L2?(.D!6Uik_<pJ\YfE,s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!m.9o6m-ilnkL.l2bKS5L`PoI%]sP/RUnsl_V50o`Unji_UnslbHuPKL4K(t3 +R85rD9f8>74IJu-W(f.;:HY%@4IJu-\m7bVHt(]T@dAVVf6h&ZHt(`N>j?]CfQCHOF^3RA>hF1( +fQCHOF^3RA>hF1(fQCHOF^3RA>hF1(fQCHN`4ajZhV$]@bKS5L`Po3k['[3IUnslWSt)=BS=H1@ +S=Z7@St)0N8Z"m+MGZ^;6n=-l6Dd.$R85rB6n=[$4JkLsHoaBX:HY%@4M"fefQCH_FB7%:>hF1( +fQCHOF^3RA>hF1(fQCHOF^3RA>hF1(fQCHOF^3RA>fCSefQCHOF^3"0?J'C*q:sBts8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,coC]S?C:[\>\m7b9>t)>17Clbn +\n+[KAP^?V9"JS0\n+[KAP^?V9"JS0aDFnfAP]mK:V(+5a(%`QAP]mK:T%/VR85r5:HYLB/"'0q +R85r5:HY%@4IJu-R85r5:HY%@4IJu-Qs!#QpA+ags8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s7H$\kj7d%m-j)lgt0KX +`GT#'FC*%1?H@4paE1b0FC*%1?H@4paE1b0FC*%1?H@4paE1b1HtUNB?H@4paE1b1HtUNB?HIS- +[VT*6=\4u`8XNXPR85r4=\4u`8XW@:Qs!"J=\4u`8]\!0kj7d%m-j0)n*'-,kj7cj[&h>j?H@4p +fQCH@HtUNB?IsR6aE1b?Ht(3FB@hN?aa@aCHtV&Y@`WXtf6h&LHtV&Y@`a"1f6h&LHtTm(=f54` +VHZKd>=GDn7Aj*LVHZKd>=GGh5M*ies8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s7H$\m.9o.jQG[\gsX^' +daZjkbg"eIXOhi/f6h&ZHt(`N>h=@4fQCHNHt(]T@b6!:fQCHNHt(]T@b6!:f6h&[F^3OG@b6!: +f6h&ZHt(]T@`WXtR85rC<'QaQ8Z,NPQs!#$R>q7Hs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W,kpA+(Hp#tc2g"bH;gtpK/f$`(!bKS5Sbg"eabKJ,SfX.a4KPp".CtODY +k_<p+KPp".CtODYfS"/.Jn3MeDV0V[fS"/-HsYHYDV0V[fS".oHt);oCtF&DfS".pKPp".CtF&D +fS"/+L2>LqDV'8FVHZKfAQ8EjkPtS^s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s7H$\m.9o.jQG4OhU9p)daZjd`Pod7`Pfa7 +bKS5L`Pod7`Pfa7l'-VLN-O!.DWcptfo11=MfIp<ET`7"kDO?CMfIF/Git!)fo11>L2>P%Gj'lu +k_<p;L2?(.D!6Uik_<p;L2>Ih@d2Fpm.9o6m-ilnkLnYIdaZjkbg">Tc,@T?`5T^8]Xk[c:YLJ2 +k_<p;L2?(.D!6UikDO?CMfIp<ET`7"kDO?CMfJ!GIHQN.kDO?CMfIp<ET`7"l'-V\P^V_QETr^9 +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,kpA*q=n)39ig"bH-bg")F`Oidr`5T^-]Y28&`Oidr +]=bhdNJ3a&8Z#]\k_<p:MfIp<ETi-nkDO?DL2?(.D!-^rk_<p:MfIs8D!6Uik_<p:MfIp<ET`7" +kDO?CMfIp<ET`7"prgJQs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s6T@M +kj7ckgtpK/f#5PH]=bhh]Y1\Z[(Eua['[3P]Y14rI$e&.VHZKV=\5Mj5GhXRfo11=MfIs8CtODY +k_<p+KPp".CtODYk_<p+KPoFqDWcptfS"/*MfIC&DWcptfS"/+L2>LqDWlgkes_]Dbg")F`Oidr +['[3I['[3I['[3IW/QJ/<'QaQ8Z,NPQs!"J=\5Mj5IPB2kDO?5N-OQ@D!-^rfo11>L2>LqDWlgk +fS".pKPp".CtODYk_<p+KPoFqDV0V[fS".oHt'$c<1-NER85rC<'QdH4IJu-R85rC<'R9[5KIqQ +k_<p;L2?(.D!6Uik_<p;L2?(.D!6Uik_<p;L2?(.D!-^rkDO?CMfIp<ET`7"kDO?CMfIp<ET`7" +kDO?4KPot2ES,q^fS"/,P^WAgiUlj>s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8VHWp#tc2 +i8j(Sgtp5uc,@T?['[3@XKA:pUnji_Unsl_V50o`UmH1=R85r5:HY%@4IJu-R85r5:HY%@4IJu- +Vc5mK:HZ4":[3=6fS".oHt(]T@d8>If6h&[F^3OG@d8>If6h&[F^3OG@d8>If6h&[F^3OG@d8>I +fQCHNHt(`N>iio@i8j(Sgtp5uc,@T?]=bhXXKAP)XdkuQS=Z7@St)=BS=H1@Q=Ep_:HYLB.uI1j +VF2ql;*q-J/"'0qR85r5:HYLB/#G]bR85rS;``NX@b6!:f6h&mHsYEP@b6!:f6h&ZHt(`N>h=@4 +fQCH@HtV)S>hF1(aE1b@F^3RA>f_"nfQCH?FC+4^fDkmNs8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8V`bq=OCV[VT*XAP]mK:V(+5\n+[KAP]mK:V(+5\n+[KAP]mK:V(+5 +[VT*XAP]mK:V(+5\n+[KAP]mK:UY(B\n+[*:HY%@4IJu-R85r5:HY%@4IJu-R85r5:HY%@4IJu- +R85r5:HYP&E:il"s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,kpA+(Hp#+ooi8j(LeCM]_?FP#c[VT*UFCM_$@^gGg +[rc)gFCM_$@^gGg[rc)tH[WAF@`WXt[rc)tH[WtW?FP;saE1atHtp*+=dW>`Qs!"J=\4u`8XNXP +Qs!"J=\4u`8XNXPQs!#%Un-`9n*'-,kj7d%m-ilnkLcl.aE1b1HtUNB?HIS-aa@aBFC*(:B?>O6 +aE1b1HtV)S>fhA+aa@aCHtUQKB?>O6aE1b1HtUNB?IsR6\n+[)=\5Mj5F>SFVc5mJ=\4u`8XNXP +Qs!#CbfTnbs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8Vi[kNM:$g"bH;gtpK/f%A3i`5T^IHt(]T@`a"1 +f6h&ZHt(]T@b6!:f6h&ZHt(]T@b6!:f6h&ZHt(]T@b6!:aa@aRF^3%9B@hN?aa@aBFC(hK7@74L +Vc5mJ=\4u`8][*Ks8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +p[%),m-ilnkN:RTg"bH4eCN9rbL4nkbKS5Sbg">Tc.K+ifS".pKPoFqDV0V[fS".pKPoFqDV'8F +fS".oHt(`]DV0V[fS".oHt(`]DV0V[fS".pKPoFqDV0V[fo11.KPoFqDV0V[fS".@AQ5O27G#Jk +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W,kpA+(Hp#tc2g"bH4eCN'tf#u:^fZ_OW`Pp$Ec,@T?bKS5L`PpK:XOr2D +fo11/N-O!.DV9tnfo11.KPoJ%Gh@[efo11.KPoJ%Gh@[ekDO?4KPoJ%Gh@[efo11.KPoFqDV0V[ +k_<ooR>pFsn*'-,i8j(SgtpK/f#u:^`5T^6`Pod7`OM+i[VT+1L2?%2ES6:qkDO?5N-ONDES,q^ +fo11=MfIF/GhJ%#fo11/N-O$7GhJ%#fo11/N-O$7Gh@[efo11>V2tZVs8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s7H$\kj7crjQFt@f$`(!`5T^-]Y28&`Oidr`k8mp]Y28&`ODY9Qs!"X>=HY]BBY(d +fo11=MfIF/Git!)fo11>L2>P%Gh@[efo11=MfIC&DV9tnk_<p,N-ONDETi-nkDO?CMfIjKL]@DS +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!o_/+IoC_&&kLnYIdaZjkbg!c4]t:qj +]=bha['[HX]sP/RW+Ar*>=Fo^8Z#]\Qs!"iFCNp^Git!)fo11/N-OQ@CtXblkDO?4KPoJ%Gj'lu +fo11=MfIC&DV9tnkDO?5N-ONDES6:qfo11/N-O!^XNSi4`5T^&['[3I['[3I['[3I['ZcjL6u+8 +Qs!"J=\5Mj5F>SFQs!#%FC+-gES6:qfo11/N-O!.DV9tnfo11/N-O!.DV9tnfS".pKPoFqDV0V[ +fS"/+L2>LqDV0V[Qs!"K:HY"I8XW@:Qs!"Y<'QaQ8\/J/fS".rKOX,&ES,q^kDO?4KPp".D!-^r +fS"/+L2>P%Git!)fo11=MfIp<ES6:qkDO?5N-ONDES6:qkDO?5N-O$7GhJ%#k_<p,N-P*-VZ6\r +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!m.9o6m-ilnkL.l2bKS5L`PoI%]sP/R +Unsl_V50o`Unji_UnslRFDI:?4IB8CR85r5:HY%@4IJu-R85r5:HY%@4IJu-\n+[iKPoFqDV0V[ +fS".oHt(`]DV'8Ff6h&ZHt(]T@dAVVf6h&ZHt(]T@b6!:fS".oHt(]T@b6!:f6h&[bfer*kLnYI +daZjd`PoI%]sP/RUnsl_V50WQS=H1@S=Z7LR['7C8XW@:MGZ^;6n=-l6Dd.$R85r&;*q-J/"'0q +R85r5:HY%@4M"fefQCHNHt(`N>h=@4f6h&ZHt(]T@b6!:f6h&[KPoCh@b>g.aa@aQHt(`N>fhA+ +fQCH@HtV&Y@`WXtq:sBts8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +o_/+Em-hMs:V(+5\n+[KAP]mK:V(+5\n+[KAP]aN=h80?[VT*XAP]aN=gi-L[VT*TCg"2_=gi-L +[VT*TCg"2_=d`&JR85r5:HXM36CCV3R85r5:HXM36C:nIMGZ^-=\4KJ6C:nIVgNI`s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!m.9o6m-ilnkLnYI[sVr"FCM_$@`WXt[rc)gFCM_$@`WXt[rc)gFCM_$@^gGg +aa@a1FCM_,C:A:o[sVr"FCM_,C<1L'WGQ"0=\5#W4IB8CQs!"J=\4KJ6C:nIMGZ]t;*p.;6Fa.t +kj7d%m-ilnkNM:$i8j(UUQ`07C<1L'aa@aCHtUQKB?>O6`-ZpSHtUQKB?>O6`-ZpSHtUQKB?>O6 +aa@aQHt(3FB?>O6aa@aCHtTBh<2W\[Qs!"J=\4u`8XNXPVc5mJ=\4u`8`n7=s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!m.9o6m-ilnkLnYIdaZjkbg")F`RfKHf6h&ZHt(3FB@hN?aa@aQHt(]T@b??O +f6h&[KPoCh@`3VAfS".\H[XP"DV0V[`-ZpbKPoFqDTR9=Qs!"J=\4u`8Z#]\Qs!"jPDfJ@s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s6T@Mkj7crjQG4OhV$]@ +daZjreCMgec-+>UbKS5Sbg"_-OP#5(fS".pKPoFqDV0V[fS".\H[XP"DV0V[aFnTdKPn_TIFs3j +fS".pKPnkaEnH%_fS".qN-O!.DV9tnfo11/N-MdI=dW>`Q=EqepA+ags8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +o_/+Em-ilnkLnYIdaZk#bfe2Rc-+>U`5T^6`Pp$Ec,@T?`5T^HPC_DGGhJ%#fo11/N-O!.DV9tn +fo11/N-O!.DV9tnfS".qN-O!.DV9tnfo11>L2>P%GhJ%#k_<p,N-O!.DTR9=daZk+jQG4OhU9p) +fZ_OW`Pp$Ec,@T?`k8m^D-tqKDV9tnkDO?5N-ONDES6:ql'-VLN-O$7GhJ%#fo11.KPot2ES6:q +fo11/N-O$7GhJ%#fo11/N-O$7Gk^Rfs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,kpA*q=n)39i +g"bH-bg")F`Pfa7]=bhq`PoI%]t:qj`5T^&['Z]77@74L[rc*4N-ONDES6:qfo11.KPoJ%Gh@[e +fo11/N-O!.DV9tnfo11/N-O$7Gh@[efo11/N-O$7Git!)kDO?[s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s6T@Mkj7ckgtpK/f#5PH]=bhh]Y1\Z[(Eua['[3=P`V888XNXP +Qs!"X>=Fo^8_A]6fo11=MfIF/Git!)fo11/N-ONDES6:qfo11/N-O$7GhJ%#kDO?5N-O$7GhJ%# +kDO?5N-ONDES6:qfY"Z2`PoI%]t:qj['[3I['[3I[&^:1W/QIu=\4u`8XNXPQs!"J=\4u`8[ieN +fo11/N-O!.DV9tnfo11.KPoFqDV9tnfS".qN-O$7Gh@[efo11/N-O!.DV0V[fS".pKPm/[8XNXP +Qs!"J=\5#W4IB8CaE1bAN-O!.DV9tnfS"/*MfIF/GhJ%#kDO?4KPoJ%Git!)fS".qN-ONDES6:q +fo11/N-O$7GhJ%#fo11/N-O$7GhJ%#fS".qN-OHSL\^#is8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8V`bq<726i8j(Sgtp5uc,@T?]=bhXXKA:pUnji_Unsl_V50o`UmQOP +MGZ^.:HXM36CCV3Qs!"K:HY%@4IJu-R85r5:HYRe<7cM,f6h&[KPoCh@b??Of6h&ZHt(`]DV'8F +f6h&ZHt(`]DV0V[fS".pKPoCh@b??O`-ZpbKPoCh@bAoJi8j(SgtpK/f#5PH]=bha['Zm8XdkuQ +S=Z7@St)=BS=H1@Q=Ep_:HY%@4IJu-MGZ^.:HY%@4IJu-MGZ^.:HY%@4Gm!&R85rB>=I.k@b6!: +f6h&[KPoFb>f:u;f6h&LHtV&Y@`a"1aa@aRKPn_TIFijUaa@aQHt($@IFijUaa@aCHtVTsh#IES +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s5;u$W+Ar>AP]79<4ZX: +W+Ar:Cg"2_=gi-L[VT*TCg"2_=gi-L[VT*TCg"2_=gi-L\n+[HFCM[p=gi-L[VT*6=\4KJ6CCV3 +Qs!"<;*pXQ8W$A3Qs!"K:HXM36C:nIR85r5:HYP.I.[..s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,kpA+@Sq<726 +i8j(SgtoSqGd_Ek[rc)fCg"5h@^gGg[rc)gFCM_$@^gGg[rc)gFCM_$@^g`"[rc)gFCM_$@^g`" +[rc)gHtoWt?]%]IQs!"<;*p.;6AeW,Lg!Q2;*p(B:7,0ULg!QpUn-H)kNM:$k1nbUm-ilnkK'Hi +aa@aBFC*(:B=E8'aa@a1HtpcNB?>O6aa@aBKQ>1^B?5aHf6h&KKQ>.eEl<<Qaa@a>H[X"`B?>O6 +W+Aqq=\4u`8Z#]\Qs!"J=\4u`8XNXPQs!#4`4c3Ns8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8V`bq<726 +i8j(SgtpK/f#u:^f>PAEHtUQKB@hN?`-ZpaHt($@IFijU`-ZpSHtUQKB>f.Ff6h&KKQ>^uDV0V[ +aa@aRKPnkaEn>\JaFnTTKQ<G_8Z#]\Qs!"H@o\n!8]R6Ys8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,kpA*q=n*'-,g"bH;gtpK/f$`(!bKS5`bfe2Rc-k+m +`k8n(KQ>^uDTIKOaFnTPH[WtgEnH%_aFnTdKPn_TIFs3jaFnTdKPnkaEl`oSfS".`KQ>b)GfYPY +fo10sMga62DT$mMW+Aqo@o\n!8\'P"s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8V`bq<[_Gkj7d#gt^?-f#u:^ +bKS5Sbg")F`RrDX`5T^6`Pp$Ec,cu_fo11/N-O$7GfYekfo10sMga9;GfYekfo10sMga9;GhJ%# +fo11/N-O$7GhJ%#fo11/N-O$7GhJ%#fo11/N-NF>S`\__g"bH4eCMgec,@T?`5T^6`PoBVPdYC2 +fo11=MfIF/GhJ%#kDO?5N-O$7GhJ%#fo11.KPoJ%GhJ%#fo11/N-O$7Gh@[efo11/N-O$7GhJ%# +kbX@?s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s7H$\kj7crjQFt@f$`(!`5T^-]Y28&`Oidr +`5T^-]Y2=t]">VgVgNHN=\6&<=kSaYfo11/N-O$7GhJ%#fo11/N-O$7GhJ%#fo11.KPoJ%Gh@[e +fo11/N-O$7GhJ%#fS".nPC_DGGj)K4s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +o_/+IoC_&&kLnYIdaZjd`Pod7`Oidr['[3P]Y1\Z[&J.YQs!"H@o\n!8XNXPW+Ar]N-Np;J_?!, +fo11,PC_DGGhJ%#fo11/N-ONDES6:qkDO?5N-O$7GhJ%#kDO?5N-O$7GhJ%#fo11/N-NOic-+>U +]=bha['[3I['[3I['[3I['Z`aI$e&.Qs!"J=\4u`8XNXPQs!"iHtq>nGhJ%#fo10sMga62DTI`a +fS".`Mg`["EnQCraFnTeN-NF%IFs3jaGYK"N-NF%IFs3jQ=EpP;*pXQ8XW@:WGQ"`KQ>b)GhJ%# +fo11/N-O$7GhJ%#fS".qN-O$7GhJ%#fo11/N-O$7GhJ%#fo11/N-OTOIFaU5fo11?P^V5DGhJ%# +fo11/N-Np;Jbm<ds8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +m.9o6m-ilnkLnYIbKS5L`Po3k['[3IUnsl_V50o`Unji_UnslRFDHb26AeW,MGZ]t;*p.;6AeW, +MGZ]t;*p.;6AeW,W+ArLKQ>^uDT$mMf6h&GH[XP"DV'8F`-ZpbKPnkaEn>\J`-ZpaHt(]T@`3VA +fS".`KQ>^uDTIKOfS".pbff5:n(HLQdaZjkbg!c4]sP/RUnsl_V50WQS>_mAS=Z7@St)*V<JjX? +R85r&;*p[H4IJu-MGZ^.:HY%@4Gm!&R85r5:HY%@4K)gjfS".oHt($@IFijU`-ZpaHt(]T@`3VA +f6h&GH[XLn@`a"1fS".\H[XP"DTR9=aFnTUHtUQKB?>O6q:sBts8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!o_/+=jQEsf=fH7F[VT*FAQ6-\@]3j;[VT*GD-s8Z?`@mL +[VT*GFChFg?aacRWGQ"NCg"5h@^^)U[rc)fCg!`S?^OtfQs!"<;*pXQ8W$A3Qs!"<;*pXQ8W$A3 +Qs!"<;*p.;6C:nIQu-=4s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!o_/+IoC_>6n)iE\\V5::Cg"5h@]=H\ +[rc)YD-sbo@]=H\[rc)YFChq'@]+Tm[rc)WHuQQ:@^g`"[sVr"FCM_,C:A:oWGQ!u>#'lW:7,0U +Qs!":>#(Gf8VgPFQs!":>#(Gf8[kLgi8j(ZjQGI^kMYFai8j(BUn,VTB=E8'[rc*$HtUQKB?>O6 +[sVr/H[WtgEli]AaFnTPH[WtgEl`oSaa@aBKQ>.eEl`oSaFnTUHtTEq?^OtfQs!"J=\4u`8XNXP +Q=Ep^=\4u`8]\!0s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!o_/+IoC_&&kN:RTdaZjreCMXP]#f>4 +aFnTTKQ>.eEli]AaFnTTKQ>1^B?5aHaFnTdKPnkaEl`oSaFnTTKQ>.eEl`oSfS".`KQ>.eEl`oS +Qs!"H@o\h)<L?o\Q=Eq9XJPsss8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!o_/+Em-ilnkLnYIdaZjreCMgec-+>UbKS5Sbg"1rNQ?cn`-ZpRKQ>.eEl`oS +aFnTUHtUNREli]AaFnTTKQ>.eEl`oSaFnTTMg`["Ela/eaGYJfKQ>.lIFs3jaGYJfKQ>1^B:)gn +Qs!"H@o^UGScA`is8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,kpA*q=n(HLQg"bH4eCMgec-+>U`5T^=bg")F`QQKM +`5T^6`PpDlJ]NataGYJfMg`[)IG'R(aGYJfMga9;GfYekfo10sMg`[)IG'R(aGYK"N-NF%IG'R( +aGYJfMga9;GfYek[sVrCbfeGaf#u:^bKS5L`Pod7`Pfa7Qu-<RKQ>b)GhJ%#fo11/N-O$7GhJ%# +fo11/N-O$7GhJ%#fo11/N-O$7GfYekfo10sMga9;GfYekfo10sMgbE^iW&rXs8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W,kpA+(Hp#+oog"bH4eCMRW`Pfa7]=bhs]Xk_f]u7n/]=bhh]Y18.OI00B +Q=EqJN-Np;J_?!,fo11/N-O$7GhJ%#aGYK!KPoJ%GfYekaGYK"N-NEsEnQCraGYK!KPnkhIG'R( +fo11/N-PC&s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8V`bq<[_Gi8j(Sgtp5uc,@T? +]=bhh]Y1qi]sP/RW0EC2=\4u`8XNXPQs!"H@o^WuB@`8tfo11,PC_;KJ_$$9ert[9PC_DGGh/(0 +fo11,PC_DGGh/(0l'-VLN-O$7GhJ%#fo11/N-O$7Gh/=FdaZjd`PoI%]sP/R['[3I['[3I['[3I +R?Nhl;*p.;6AeW,Lg!Q@=\4KJ6FV&Gert[+Mga9;GfYPYaFnTeN-NEsEl`oSfS".`Mg`["Ela/e +fS".`Mg`[)IE7(^fo10sMg_O8</=^QQs!"iHtp`UEnQCraGYK"N-NF%IG'R(fo11/N-Np;J_?!, +ert[9PC_DGGh/(0ert[<N-Np;J_$$9ert[9PC_;KJ_$$9ert[<N-O$7Gh]!Wo_/+\s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8V`bq<726i8j(Sgtp5uc,@T? +]=bhXXKAP)Xe_ehUnsl_V50o`UmH1=MGZ]t;*p.;6AeW,MGZ]t;*p.;6AeW,MGZ]t;*q-a7EC.& +`-ZpRKQ>.eEl`oSaa@aBKQ>.eEli]A`-ZpRKQ>.eEl`oSaa@aBKQ>1^B?5aHaFnTTKQ>.eEotTf +i8j(SgtpK/f#5PH]=bhh]Y1AIXdkuQS=Z7@St)=BS=H1@Q=Ep_:HXM36CCV3MGZ]t;*p[H4Gm!& +MGZ^.:HXM36AeW,R85rDAQ6a(EnH%_aFnTcHt(0MEnH%_aFnTTKQ>.eEl`oSaFnTTKQ>.eEl`oS +aFnTTKQ>1^B?5aH`-ZpSHtVTsh#IESs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8V`bq<726[rc)YD-s8Z?`A-YWGQ"OFCM4kAZ9NR[rc)YD-s8aA[ZDXWGQ"NCg!`ZA[ZDX +WGQ"OFCM4d?ak,d[VT*(;*pXQ8W$A3Qs!"<;*pXQ8W$A3MGZ]t;*p.;6C:nILg!Q2;*pXQ8a,O0 +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8V`bq<[_Gi8j(SgtoMfC8l;dWGQ"OFCM_$@]=H\[rc)gFCM4kA[cbj +[rc)YFChFnA[cbjWH;^LHuQQ:@]+Tm[sVr"HtoWt?\hl\Qs!":>#'lW:5E(KLg!Q@=\4EQ:5E(K +Lg!QpXJOk9kMYFakj7crjQGI^kLcl.[sVr"FCN@>B=E8'[sVr4HtU!DGfb>G\V5:LKQ>.eEl`oS +aFnTTKQ>.eEl`oSaa@aBKQ=PLC<2'KWH;^;@o\n!8W%"[Qs!"H@o\n!8W%"[Qs!"iNJ7E4s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8V`bq<726kj7ckgtpK/f%A3i`k8n)HtUNREl<<Qaa@aBKQ>1^B?5aH +aFnTTKQ>.eEl`oSaFnTTKQ>.eEl`oSaGYJfMg`[)IE7=paFnTEKm8tf8X<jdQs!"H@o\h)<S,1& +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8V`bq<726 +i8j(`gt^?-f$`(!daZk#bfe2Rc,c]OaFnTPH[WtgEl`oS`-ZpSHtUQKB>f.FaFnTPH[WtgEli]A +aFnTdKPnkhIE7(^fS".`Mg`["EnQCraGYJfMg`[)IG'R(aGYJUFCLPG<L?o\Qs!#CbfTnbs8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s7H$\m.9o6m-iW_hU9p)bKS5`bfe2Rc,@T?bKS5L`Pod7`QQKMaJ>BJMg`[)IE7=p +aGYJfKQ>.lIE7=paFnTTMg`[)IE7(^fo10sKQ>.lIE7(^aGYJfMga62DTI`aaFnTeN-NEsEjqj; +daZjkbg">Tc,@T?`5T^)UnFYt<8!4TfS".pKPoFqDV9tnfo10sKQ>b)GfYPYfo10sKQ>b)GfYek +aFnTdKPnkhIE7(^aFnTTKQ>.lIFaU5s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s7H$\ +m.9o.jQG4OhU9p)`5T^6`Pod7`Oidr]=bhq`PoI%]u7n/\?2cg@p#+$8]ZR*aGYJtPC^f5IFaU5 +aGYK"N-NF%IFaU5aGYJfMga62DTI`aaGYJfKQ>.lIE7=paFnTTMg`["Ela/eke+/"s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!m.9o6m-ilnkL.l2daZjd`PoI%]sP/R]=bheXf@b*@Ye2_ +Qs!":>#(Gf8Z63"aHM;1N-NpBOOfVHert[9PC_;KJ_$$9es_]OPC_;KJ_$$9ert[9PC_DGGh/(0 +ert[9PC_DGGhJ%#ert[;[&hHpc-+>U]=bha['[3I[&^:1['[3I['Zd#Q&&U=Qs!":>#'rP6C:nI +Lg!Q_FCN=LIG'R(aFnTeN-NF%IE7(^aFnTTKQ>.lIE7(^fo10sMg`[)IE7(^fo10sMg`[)IE7=p +WGQ"@AQ6a(Ela/efo10sMga9;GfYekfo10sMga0?J]NataGYJtPC^f5IG'R(ert[<N-Np;J_$$9 +ert[9PC_;KJ_$$9ert[9PC_;KJ_$9OpsdFcs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!m.9o6m-ilnkLnYIbKS5L`Po3k['[3IUnsl_V50WQS><!W +UnslSI!(<D6AeW,MGZ]t;*p.;6AeW,MGZ]t;*p.;6AeW,Q=Eq9KQ>.eEl`oSaFnTPH[WtgEl`oS +aa@aBKQ>.eEli]AaFnTPH[WtgEl`oSaFnTTKQ>.eEl`oSaFnTdbff5:n(HLQdaZjkbg!c4]sP/R +X/rG!V50WQS>_mAS=Z7@St([J=GU-UMGZ]t;*p.;6AeW,MGZ^-=\4KJ6AeW,R85r&;*p[H4K)gj +aFnTTKQ>^uDTIKOaFnTTKQ>.eEl`oSaFnTdKPnkaEl`oSaFnTTKQ>1^B?5aHaFnTTKQ>.eEl`oS +k1nbls8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!m.9o:oC]YJGc>Oe +WH;^ND-s8aAZ9NRWGQ"AFChFg?`A-YWGQ"AFChFnAZ9c_WGQ"OFCM4kA[ZDXWH;^[Cg!`ZAXHUl +MGZ]r>#'rP6ASf?MGZ]r>#'lW:7,0UMGZ]r>#'rP6ASf?Lg!R+bfg%ds8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +o_/+IoC_>6n(>k-WH;^\FCM4kA[cbjWH;^NFChq'@]+Tm[rc)WHuQ',AZ9c_WH;^NFChFnA[cbj +VgNHmHtoX&A[d&%WH;^->#(Gf8VgPFQs!":>#(Gf8VgPFLg!Q@=\4EQ::RF+i8j(ZjQGI^kMYFa +i8j(A[B[2_@`a"1[sVr"HtpTHICFT=aa@a3Km:^eB=W_@aFnTEKm:[lEk-mKaFnTEKm:.^GfYPY +\V5:;Htp-<C7&-qMITbU=\4K\=GU-UQ=EpN>#(An<L@W4s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +o_/+IoC_>6n(HLQdaZjreCM^:S]HJ)aFnTTKQ=VWGfYPYaFnTTKQ>.eEl`oSaGYJWML<L'IE7=p +aGYJfMg`[)IE7(^aGYJfMg`[)ICFT=Q=Ep\@o\h)<L.,pQ=EqWgt_r0s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!o_/+QpA*q=n(HLQg"bH4eCMgec-+>U +a0i1nKQ=PLC<2'K[sVr"Htp`UEk-mK[sVr3KQ=VWGfYPYaa@aBKQ>.eEl`oSaFnTTKQ>.lIE7(^ +aGYJfKQ>.lIE7(^aGYJfKQ>.lIE7(^W+Aqq=\4u`8X<jds8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8VHWp#tc2 +k1nbFgtpK/f#u:^bKS5L`Pod7`RrDX`5T^6`Poj0]#]eXaFnTTMg`["Ela/eaFnTTMg`[)IE7=p +aFnTTMg`["El`oSaGYJfMg`["Ela/eaFnTTKQ>.eEl`oSaFnTCHtpjKc-+>U`5T^6`Pod7`Kt[^ +[rc*#KQ>.eEla/eaFnTTKQ>.eEnH%_aFnTTMg`["Ela/eaFnTTMg`[)IE7=paFnTTMg`[)IE7(^ +aGYKAeB.ajs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8VHWp#tc2g"bH4eCMgec,@T? +]=bhq`PoI%]u7n/]=bhs]Xk_f]pNYGQs!"[FCj-aGfYekert[+Mga0?J]NataGYJfKQ>.lIE7=p +aGYJfMg`["Ela/eaFnTTMg`[)IE7(^aGYJfMg`["EqK)$s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8VHWp#+oog"bH4eCMRW`Pfa7]=bhh]Y1\Z[$Z5`Lg!Q>@o\Cr=GU-UQ=Eq*Km;14J]O%. +ert[+PD%MUOOfVHes_]OPC_;KJ_$$9es_]OPC_;KJ_$$9aHM;.PC_;KJ]O%.ert[+PD%VJGhC6` +daZjd`PoI%]sP/R['[3I['[3I['[3IUnslC>#'lW:5E(KLg!Q2;*p(B:8r);aGYJfMg`[)IE7=p +aFnTTMg`[)IE7(^aFnTTKQ>.lIE7(^aGYJfMg`[)IE7=paGYJfMg`["Ela/eaGYJfMg`[1KZK(" +ert[+Mga0?J]Natfo10sMga0?J_$$9aGYJtPC^f=K[u?<ert[9PC_;KJ_$$9ert[9RZQ*aJ_$$9 +kd.5fs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8V`bq<726i8j(Sgtp5uc,@T?]=bhXXKAP)Xe_ehUnsl_V50o`UmQOPG#Cqg>#'6=8r?J4 +G#Cqi;*oG(8r?J4MGZ]t;*pRY<QKi6\V5:LKQ>.eEl`oS\V5:LKQ>.eEk-mKaFnTEKm:[lEk-mK +`-ZpCKm:[lEl<<QaFnTTKQ=VWGhC6`i8j(SgtpK/f#u:^]=bhh]Y1,;Unji_S=Z7@St)=BS=H1@ +Q=EpN>#'rP6ASf?Lg!Q2;*p(B:5Vn8MGZ]t;*p.;6AeW,MGZ^>D-tA;El`oSaFnTTKQ>.eEl`oS +aFnTTKQ>.eEl`oSaFnTTKQ>.eEl`oSaFnTTKQ>.eEl`oSaFnTTKQ?51h#IESs8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8V`bq<726\<DiMD-s8aAZ9NRWH;^NFChFg?`A-Y +WGQ"AFChFg?`@mLWGQ"AFChFnAZ9NRWH;^NFChFnAZ9c_WH;^;@o\=g:5E(KMGZ]r>#'lW:5Vn8 +Lg!Q2;*p(B:5E(KLg!Q0>#'lW:<9N5s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s7bmCkj7cV`Po<.@]=H\ +WH;^NFChFnA[cbjVgNH_FCh@tE49puVgNHmFCM.qE4:40VgNH]HuQQ:@]+Tm[sVr"HtoX&AXHUl +Lg!Q2@p#+$8VgPFMITbG@p#+$8W%"[Lg!QpXJOk9kMYFai8j(ZjQGI^kL[Yc[sVr"Htp-<C:AS* +[sVr3KQ=VWGfYPY\V5:LKQ=VWGfYPY\V5:=Km:.^GfYPY\V5:=Km:.^Ge&NQ\V59o@o\h)<JXgR +Q=Ep\@o\h)<L.,pQ=EpP@p&QfiW&rXs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s6/h<kj7d#gt^?-f$`(! +a-hptKm:.^Ge&NQ\V5:LMg`-nI(>,^\VbdUMg`'oKuf1#\VbdUMg`-nI)q4oaGYJUNJ5H3ICG2i +aGYJGFCg>>=I*GsMITbS@o\Cr=TAF$s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8V`bq=OCVi8j(ZjQFt@f$`(!fZ_OY]XkY-Ge&NQ[sVr$Km:(SC:AS* +[sVr"Htp-<C:AS*aFnTCHtp3GGe&NQ`-ZpCKm:[lEl`oSaFnTTMg`[)IE7=paGYJfMga0?J]Nat +fo10sMg`["EgC38Q=Ep^=\5N=E<#t<s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!o_/+IoC_>6n(HLQdaZjkbg">Tc-+>U +`5T^=bg")F`QQKM`5T^9R>nb2Ge&NQ\V5:LMg`-iGe&NQaFnTEKm:[sIE7(^\V5:LKQ>.eEl`oS +aGYJfKQ=VWGfYekaFnTTMg`[)ICFT=\"o\8`Pod7`Pfa7\?2cu=\6\fEl`oSaFnTTKQ>.eEla/e +aFnTTMg`["El`oSaFnTTMg`[)IE7(^aGYJfKQ>.lIE7=paFnTTMg`[1K`D)Ps8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!o_/+Em-ilnkL.l2bKS5L`Pod7`Oidr`k8mp]Y28&`Oidr +]=bhUP`V2@<L.,paHM:uMg`[)IFaU5aGYJfMg`[)IE7=paGYJfMg`[)IE7=paGYJWKm:[lEk-mK +\V5:LMg`-iGe&]ZaGYJtRZRRLs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s6T@Mkj7crjQG4OhU9p) +`5T^6`PoI%]sP/RR!a%B@o\Cr=GU-UQ=EpN>#(uCE7U5(aHM:uPD%MUON3cKert[*R>o7TNRjP[ +a-hq<RZPRXNRjP[a-hq<RZQ*hON<W=es_]OPC^f=K[u?<aJ>B[gtp5uc,@T?]=bha['[3I['[3I +X/rG1['[?FWet:gQs!":>#'lW:7,0ULg!QQD-tABIE7V*aGYJfMg`[)IE7(^aGYJfMg`[)IE7=p +aGYJfMg`[)IE7=p\VbdUMg`[)IE7=paGYJfMg`[1KZK@1ert[+PD%#@KZK@1aHM;.PC^cBNRj;E +a-hq<PC^f=K[u?<aHM;.PC^f=K[u?<a-hq<PC_;ROOfVHes_]qeB.ajs8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!m.9o6m-ilnkLnYI +bKS5L`Po3k['[3IUnsl_V50o`Unji_UnslSI!'^=</OO>Lg!Q2;*p(B:5Vn8Lg!Q0>#'6=8r-YG +Qu-<CML<L'IE7(^\VbdFKm:[sICY&V\V5:LKQ=VWGe&NQ[sVr$Km:.^Gdi'8\V5:=Km:.^Gf4rW +\V5:\bff5:n)39idaZjkbg!c4]sP/RX/rG!V50WQS=H1@S=Z7@St([J=GU-ULg!Q0>#'lW:5Vn8 +Lg!Q2;*p(B:5E(KLg!Q0>#'rP6C;V!aFnTTMg`[)IE7(^aGYJfKQ>.eEl`oSaFnTEKm:[lEk-mK +aFnTTKQ=VWGfYPY\V5:LKQ=VWGfYPYk1nbls8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!m.9o:oC]SgTW)d8Qu-<3FCghV@]=3OWH;^ND-s8Z?`@mLWH;^ND-s8Z?`A-Y +WH;^NFChFg?`A-YWH;^NFChFnAX6h+MGZ]r>#'lW:5E(KMGZ]r>#'lW:5E(KLg!Q0>#'lW:5E(K +Lg!QPN/%B4s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!o_/+IoC_>6n&V;qWH;^NFChq/C8ZGuWH;^LHuQ',AZ'op +VgNH]HuQ!2E2S)&WH;^LHuQQ:@]+TmVgNHmHtoR,E4:40QZR#!>#'rb=GU-UMITbE>#'lW:5E(K +MITbE>#'rb=LbK5q;gMmjQGI^kMYFai8j(RbfdPNGdi'8\V5:=Km:.^Gdi'8\V5:=Km:.^Ge&NQ +\V5:=Km:.^Ge&NQ\V5:=Km:.^Ge&NQaFnTEKm:.^Ga;i>Q=EpP@p#%,<Jk9gMITbG@p"Uu=GgTj +`k8n_s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!o_/+IoC_&&kLnYIdaZjkbg!\UI)pt]\V5:=Km:[lEk.'T +\VbdUMg`-nI(>,^aGYJUNJ5H3ICG2i[uH*_Mg`+!Mo^g)[uH*_Mg`'oKrK0*MITbG@p"Uu=GgTj +VgNI`s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W,_m-j0)n)iE\daZjreCMRW`Q3sc\V5:;Htp-<C:T%C[sVr$Km:(SC:AS*\V5:;Htp3GGfYPY +[sVr3KQ=VWGfYPYaGYJWKm:[lEla/eaGYJfMga9;GfYekaGYJfMg`[)IE7=paGYJfKQ;lP:6oBi +Lg!Q`PDfJ@s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s6T@Mi8j(Sgtp`>hU9p)bKS5Sbg")F`Pfa7`5T^6`Pp$Ec,[5s +\V5:=Km:.^Ge&NQ\VbdUMg`-iGe&NQ\V5:=Km:[sICY&V\V5:LMg`-iGfYPYaGYJWKm:.^GfYPY +aFnTTKQ<uDI)O"C`5T^6`Pna.I&Usi\V5:LKQ=VWGfYPYaFnTTKQ>.lIE7(^aGYJfMg`[)IE7=p +aFnTTMg`-nI)q4o[uH*_Mg`-iGfYekk01sIs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8VHWp#tc2i8j(Sgtp5uc,@T?`5T^-]Y1qi]u7n/]=bhq`PoI%]sP/RQ=Ep\@o^U'ElXT- +aHM:uPD%#8IE7V*aGYJfMg`[)ICG2iaGYJWKm:.cI(>,^\VbdFML<L'ICY&V\VbdUMg`'oKt3(g +aJ>C,s8W-!s8W-!s8W-!s8W-!s8W-!o_/+IoC_&&kLnYIdaZjkbg")F`OidrUnslSD.8B4=GgTj +MITbG@p"Uu=JpOca-hq=S:8MHNQ7HHa-hq-R>o7TNQ7HHes_]@R>o:OKZBL?es_]APD%MUON<W= +a-hq<PC^cBNRjP[aHM;.RZQ17[aN[VdaZjd`PoI%]sP/R['[3I['[3I['[3I['[3,FDH\9:5E(K +Lg!Q0>#'lW:6oBiaHM:uMg`[1KZK("aGYJfPD%#8IE7=paGYJfMg`[)ICG2iaGYJfMg`[1KXZqp +aGYJUNJ5H;KZK@1aHM:uPD%#@KZBL?aHM;.RZPUSKZBL?es_]@R>oddON<W=es_]@R>od]J]O%. +ert[*R>oddON<W=aHM;@]WhG9s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8V`bq<[_Gi8j(LeCMgec,@T?]=bhXXKA:pUnji_ +Unsl_V50o`UmQOPG#Cqg>#'6=8r-YGH!=7(>#'6=8r-YGLg!Q2;*pXe@`XIU\VbdFML;slI(>,^ +\V5:=Km:.^Ge&NQ\V5:=Km:.^Ge&NQ[sVr$Km:(SC8Z`4[sVqgKRC=aGhC6`i8j(SgtpK/f#u:^ +]=bhh]Y1AIXdkuQS=Z7@St)=BS=H1@LM^[[>#'lW:5E(KLg!Q0>#'lW:5E(KG#Cqg>#'lW:5Vn8 +Lg!Q@D.:SEICY5_\V5:=ML;sgGfYek\V5:=Km:.^GfYPY\V5:=Km:.^GfYek\V5:=Km:.^Ge&NQ +\V5:=Km;b8h#IESs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8V`bq<726 +a0i1>D.9J]?^P\>Qu-<3FCghV@]=H\Qu-<"D.9JdAXI=DWH;^ND-s8aAZ9c_WH;^NFChFnAZ9c_ +WH;^NFCghB8VgPFLg!Q0>#'lW:5E(KLg!Q0>#'lW:5E(KLg!Q0>#'lW:6oBikj7d<s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s6/h<kj7cJPDc>dE2dqjVgNH_FCh@tE2S)&VgNH]HuQ!2E2dqjVgNH]HuQ!2E2S)& +VgNHmHtoR,E2SA:[sVqgKRBb@AVsu"Lg!Q2@p"Oj:5WO`MITbG@p"Uu=GgTjLg!Q`XfC=?kNM:$ +i8j(ZjQGI^kLnYI\<Di]Km:(SC:T%C[sVr$Km:(SC:T%C\V5:=Km:.^Ge&]Z\V5:=Km:.^Ge&NQ +\V5:=ML;sgGe&]Z\V5:-FCg>>=I*GsMITbE>#(An<Jk9gQ=EpN>#(uKI/j6Hs8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8V`bq<726kj7d#gt^T<hT!4>\V5:=Km:.cI(=rU[uH*PML;sgGe&]Z\VbdDNJ4j$Kt!%q +\<DilMg`'oKt*>)aGYJUNJ4j$Kuf1#[uH*/D.8B4=GgTjQ=EpP@p$49T`>&ls8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8V`bq<726kj7ckgtp`>hUp&q +a-hptKm:(SC:T%C\V5:;Htp3GGdi'8\V5:;Htp3GGe&NQ[sVr$Km:.^Ge&NQ\V5:LMg`-iGfYek +\VbdUMg`[)IE7=paGYJfPD%#8IE7=paGYJfMg`[)IE7=p[sVqH>#'lW:5E(KfY"Zms8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W,kpA+ILkMYFag"bH4eCN9rbKJ,S`5T^JbfdrD`QQKM`5T^6`PoBVPduKm\V5:=Km:.^Ge&NQ +\V5:LMg`-nI(>,^\V5:LMg`-iGe&NQ\V5:=Km:.^Ge&NQaFnTEML;slI(=rU[sVr"UnGZF`Oidr +Lg!Q_Htp-<C:T%C\V5:=Km:[sICG2i\V5:=ML;slI)q4o\V5:;NJ5H3ICG2iaGYJUNJ5H;KZK(" +[uH*^R>q7Hs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!o_/+IoC_&&kLnYI +daZjd`Pod7`Pfa7`5T^-]Y28&`Oidr`k8n$`Pn1&MMbnGWH;^mPD%#@KZK@1a-hq.PD$uENQ@$+ +\<DilMg`'oKt!%qaGYJUNJ5H3ICG2i\VbdDNJ4j$Kt!%q[uH*_Mg`'oKug'\p[%)Cs8W-!s8W-! +s8W,kpA+(Hp#tc2g"bH;gtpK/f#u:^['[3-I!(<V=GgTjMITbG@p"Uu=GgTj\V5:LPD$uENQ7HH +a-hq-R>o7TNRjP[a-hq-R>o7TNQ7HHes_]@R>o7TNQ7HHa-hq<RZPRXNRjP[a-hq-R>o7TNQ7HH +g"bH;gtpK/f#5PH]=bha['[3I['[3I['[3I['[3I[$QGsLg!Q0>#'lW:5E(KLg!Q0>#*.sIE7V* +aGYJfPD%#@KZK("aHM:dNJ5H;KXZqpaHM:uPD%#@KXZqpaGYJfPD%#@KZK@1aGYJUNJ5H;KZK@1 +aHM:uPD$uENQ@<:a-hq-R>o:OKZBL?a-hq-R>o:OKZBL?a-hq-R>o7TNRj;Ea-hq<RZR@+iW&rX +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!m.9o6m-ilnkLnYIdaZjd`PoI%]sP/RUnsl_V50o`Unji_UnslSI!'U18r?J4 +G#CqU;G)gD6?Z7!Lg!Ps;G)aK:3KN-Qu-<CML;slI(>,^aGYJWML;sgGdiZd\V5:=Km:.^Ge&NQ +\V5:;Htp3GGc,q.\V5:=Km9MCE4L[I[sVr6bg#),kMYFadaZjkbg!c4]sP/RX/rG!V50WQS=H1@ +S=Z7@St(RQB8B_dLg!Q!>?$D^:5E(KH!=7(>#'lW:5E(KLg!Q0>#'lW:7,m-aGYJUNJ5H3ICY5_ +aGYJWML;slI(=rU\V5:=Km:.^GfYPY\V5:=Km:.^Ge&NQ\V5:HH[WGYGe&NQk1nbls8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!m.9o:oC^b[bF!-UQu-<"D.9JdAXI=D +Qu-<3FCge\CT2DeQu-<3FCghV@]=H\WH;^NFChFnAZ'opVgNH_FCh@tE2dqjMITbE>#'lW:5E(K +Q=EpN>#'lW:5E(KLg!Q0>#'lW:5E(KLg!Q0>#*)M])Vg1s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!o_/+IoC^elhPkU. +WH;^LHuQ',AZ'opVgNH]HuQ!2E2S)&VgNH]HuQ!2E4:40VgNH]HuQ!:I&D@2[sVqgKRB\FE4L[I +QZR##@p"Uu=GgTjLg!Q2@p"Oj:5E(KLg!Q!>?$Ji=LbK5i8j(ZjQGann)39ii8j(LeCM^:SYq-g +\V5:;HtoR4I(+K<VhBH.Km9MCE4L[I\V5:=Km:.^Ge&NQ\VbdFKm:.^Ge&NQVhBH.Km:.^Gc-4B +MITbG@p"Uu=GgTjLg!Q2@p"Oj:5WO`Lg!R;m-juSs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!o_/+IoC_&&kLnYI +daZjhUn,&RI(>,^\VbdFML;sgGdiZd\VbdDNJ4p#I(,)h[uH*NNJ4j$Kt!%q\<Di]ML;ptMn+^m +\<Di[NJ4osG`$!5MITbG@p"Uu=GgTjfZ_P=s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!o_/+Em-ilnkLnYIdaZjhXJNI]Ge&NQ\V5:=Km:.^Ge&NQ +\V5:=Km:.^Ge&NQ\V5:=Km:.^Ge&]Z\V5:LKQ=V\I)q4o\VbdUMg`[)IE7V*[uH*_PD%#@KZK@1 +aGYJfPD%#8ICPK!aGYJVPDdM?I@#%kMITbE>#'rb=Q\Dos8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!m.9o6m-iW_hU9p) +daZjkbg">Tc,@T?bKS5L`Pp$Ec,@T?a0i1_Km:.^GdiZd\VbdDNJ4p#I(>,^\VbdFML;slI(>,^ +[uH*_Mg`'oKuf1#\VbdFML;slI(=rU\VbdUMg`-nI&DXF`5T]oN/!^:@_%2;\V5:=Km:.^Ge&]Z +\VbdFML<L'ICG2iaGYJUNJ5H;KXZqpaHM:dNJ5H;KXZqpaHM:dNJ5H;K\+/Us8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s6T@Mkj7ckgtpK/f#u:^`5T^-]Y2=t]">Vg +]=bhq`PoI%]t:qj['[3-D.8B4=NH\Za-hq-R>o7TNQ7HH\<DilPD$H0Mo_*8\<DilMg`+!Mmn\" +[uH*NNJ5H;KXZqp[uH*_PD$E)Kt*>)\<DilMg`+!Mq>n\o_/+\s8V`bq<[_Gkj7ckgtp`>hTO-f +UnslSI!(6K:5WO`Lg!Q2@p"Oj:5WO`QZR#RML<I4NQ7HHa-hq-R>o7TNQ7HHa-hq-R>o7TNQ7HH +a-hq-R>o7TNQ7HHa-hq-R>o7TNQ@<:a-hq-R>o:OKZBL?es_]Q]XHbZkLnYIbKS5L`PoI%]sP/R +['[3@XKAk:['[3IX/rG%R[&\4:3U5VLg!Q2@p"Oj:5E(KVhBH=PD$E)KufI2[uH*_PD$E)KufI2 +aHM:uPD$E)KufI2aHM:uPD$E)KufI2[uH*_PD%#@KZBL?aHM:ePDdJLNQ@<:a-hq-R>o7TNQ7HH +a-hq-R>o7TNQ7HHa-hq.PD$uENQ@<:a-hq-R>ok+XT/>#s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8V`bq<726 +i8j(Sgtp5uc,@T?]=bhXXKAP)XdkuQUnsl_V50o`UkX8DG#CqU;G)4=</OO>G#CqU;G)gD6?Z7! +G#Cqi;*pXe@_%2;\VbdFKm:.cI(=rU\V5:=Km:.cI(>,^VhBH.Km9MKI(=rUVhBGqHuQ!:I&D@2 +\V5:+HuQ!:I+ZZdi8j(SgtpK/f#u:^]=bhh]Y1AIXe_ehS=Z7@St)44PGG%NLM^[L>?$D^:3g&C +Lg!Q!>?$D^:5WO`H!=7(>#'9P@#.u]MITbUD.:#=Mo^g)[uH*_Mg`'oKt3(gaGYJWKm:.^Ge&NQ +\V5:=Km:.^Ge&NQ\V5:=Km:.^Ge&NQVgNHoKm;b8h#IESs8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8V`bq<[_Gk1naYFDI7\@[M"AQu-<"D.8lL@[D1PWGQ"/FDI7\@]=H\ +QZR#BFCge\CSuQ!VgNH_FCh@tE2S)&WH;^LHuPHi@Ye2_Lg!Q0>#'lW:5E(KLg!Q0>#'lW:5E(K +Lg!Q!>?$D^:3g&CVhBHts8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8V`bq<726a0i1=FDI4bCR9-YR!a%CFDI4bCSuQ! +QZR#@HuQ!2E2S)&VgNH]KRB\FE2S)&VgNH]KRB\FE2SA:VgNH]KRB,.CPZ.hLg!Q!>?$Ji=F"+M +Lg!PtA71:)=F"+MLg!Q_UnHr<n*'-,i8j(bm-ilnkLnYIa0i1_Km9MCE2SA:VhBH,HtoR4I&D@2 +\V5:+KRB\NI&DXFVhBGqKRB\NI&DXFVhBGqKRC=aGe&]ZVhBH.Km8nn<JXgRLg!Q0>#'rb=F"+M +Lg!PtA713s::RF+s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8V`bq<726i8j(SgtpK/f!pp%\VbdFKm:(dKt2n^ +W/QJAKm:(dKt!%q[uH*NNJ4j$Kt!%q\<Di[NJ4j$Kt!%q[uH*OPDcu/I(5AuVgNH@@p"Uu=GgTj +MITbDD.inKs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W,kpA+@Sq<726i8j(Sgtp)ZZ)EV9\V5:+KRC=aGe&NQ\V5:=Km9MKI(=rU\V5:=Km:(dKt2n^ +\VbdFML<L'ICG2i[uH*PML<L/KXZqpaHM:dNJ5H3ICG2iaHM:dNJ4m+Mmn\"[uH*OPDdM?ICG2i +aGYJWML:e.@Z"YtMITbTFDLpVs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8V`bq<726i8j(SgtpK/f#u:^bKS5Sbg")F`QQKM +`5T^6`Pod7`Mf#_\Vbd4KRC=fI(,)hVhBH.ML;mmKt3(g\VbdDNJ4j$Kt!%q[uH*NNJ4p#I(,)h +\VbdFKm:(dKt2n^\Vbd4HuQQjTSQcHVhBH.Km:.cI(>,^\VbdDNJ4osGdiZd[uH*NNJ4j$Kt!%q +[uH*NNJ4j$Kt!%q[uH*NNJ4j$Kt!%q[uH+As8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W,kpA*q=n)39ig"bH-bg")F`Pfa7`5T^-]Y28&`Oidr`k8n$`PoI%]r7Bb +MITbTFDJpbNQ7HHa-hq-R>o7TNQ7HHa-hpsPDdJLNOY11\<Di\PDdMGKXd5([uH*OPDcr7Mmn\" +\<Di\PDco0Kt*>)\<Di[NJ5E@NQ8H3`k8mi['[?FWi2AOR!a%6@p"Oj:3g&CH!=6n>?#lP</=^Q +QZR#RML<I4NQ7HHaHM:tR>o7TNQ7HHa-hq-R>o7TNQ7HHa-hq-R>o7TNQ7HHa-hq-R>o7TNQ7HH +a-hq-R>o7TNQ7HHa-hq-R>o:`S`&Slkj7ckgtpK/f#u:^]=bha['[3I['[3I['[3I['[3I[%sOo +MITb6>?$Ji=GU-UH!=7*@p#^PA]U'g\<DilPD$H0Mo_*8\<DilPD$H0Mo_*8aHM:uPD$H0Mo_*8 +aHM:tR>o:OKZBL?\<DilPD$H0Mo_*8a-hq.PD$H0Mo_*8a-hq-R>o7TNQ7HHaHM:tR>o:OKZK@1 +a-hq-R>o:`Sb_@*s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!m.9o6m-ilnkLnYIbKS5L`Po3k['[3I +Unsl_V50o`Unji_UnslSI!'U18p4*)G#CqU;G)+18pOW?G#CqU;G)+18p4*)MITbtNJ4osGdiZd +\V5:;NJ49`I(=rUVhBH.Km9MKI(>,^\V5:+HuQWMGc,q.VgNHoKm9MCE2SA:VgNI9bfer*kMYFa +daZjkbg!c4]sP/RX/rG!V50NCPGG%NS=Z7@St(RQB6d]\Lg!Q!>?#lP</=^QH!=6n>?$D^:3g&C +Lg!Q!>?$D^:7$'<[uH*OPDcr7Mn"t/[uH*NNJ4j$Kt3(g[uH*PKm:.^Ge&NQ\V5:=Km:.^Ge&NQ +\V5:+KRC=aGc,q.k1nbls8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +o_/+IoC_>6n#22"Qu-<"D.8lL@[D1PQu-<"D.8iRCRAsJQZR#1D.8iRCSuQ!VgNH_FCgheFf0V+ +WH;^LHuQ',AZ'opQu-;g>#'?I</=^QH!=6n>?$D^:3g&CH!=6n>?#lP</=^QH!=6k;G)gV=P;Kd +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!m.9o6m-gm;OI(')WH;^<FDIe%E0kZ^VgNHMFDI7kFf0V+R!a%DI!)?7E2S)& +VgNH]KRB\FE2S)&VhBGqHuQ!:I&D@2QZR##@p!qc@#.u]H!=7*@p""\<-_\IH!=6n>?#lP<4K'1 +kj7crjQGann)39ii8j(`gt^)sc)65BVgNH]HuQ!2E2S)&VgNH]KRB\FE2S)&VgNH]KRB\FE2S)& +\V5:+HuQWMGc-4BVhBGqKRB\NI&DXFQZR#!>#'9P@#.u]H!=7*@p""\</=^QG@Y*KD.<PFs8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!m.9o6m-j)lgtCK>a0i1MKRC=aGc6RUVhBH.ML;sgGc6RU[uH*NNJ4j$Kt!%q +\<Di[NJ4j$Kt!%q\<Di[NJ4m+Mmn\"[uH*NNJ3^@CPlV(MITb4A71:)=K%15s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s7H$\kj7crjQGI^kLe#% +[uH*PKm9MKI(>,^W/QJ?NJ49`I(,)h\V5:;NJ4<iL:<.r[uH*PML;mmKt*>)[uH*OPDdMGKXZqp +aHM:dNJ4j$KufI2[uH*_PD$E)KufI2[uH*_PD$E)Kuf1#\<Di[NJ4m+Mo^g)\Vbcl@p"Uu=GU-U +VhBHts8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!o_/+IoC_>6n(HLQdaZjreCMgec-+>U`5T^6`PpKRbJ_B=bKS5PXJMhJI(>,^ +VhBH.ML;@]L:N1hW/QJ?NJ4p#I(,)h[uH*NNJ4j$KufI2[uH*PML;mmKt3(g[uH*PKm:(dKt2n^ +LM^[ZD.gD5Ge&NQVhBH,NJ4osGdiZd\VbdFML;slI(,)h[uH*PML;mmKt!%q[uH*OPDco0Kt!%q +[uH*NNJ6#t[f?C-s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s7H$\ +m.9o.jQG4OhU9p)bKS5L`PoI%]u7n/]=bhh]Y1qi]u7n/]=bhq`Pn0sJVmr>[uH*^R>n_?MoV6F +\XJbmPDdJLNObLBa-hpsPDdJLNOY11\XJbmPDcr7Mn"t/[uH*OPDcr7Mn"t/\<Di]ML;ptMmn\" +[uH*OPDdM?ICG2iQZR#1D.7cp<-_\IH!=6n>?$Ji=I<r7R!a%eML;ptMn"t/\<Di\PDcr7Mn"t/ +aHM:fRZtj\NQ7HHa-hq-R>nbGPfK2Oa-hq-R>o7TNQ7HHa-hq-R>o7TNQ7HHa-hq-R>o7TNQ7HH +k1nbapA*Y-kLnYIdaZjd`PoI%]sP/R['[3I['[3I['[3I['[3I['YU1E-YYeH!=7(>#'9P@#.u] +LM^\ER>n_?Mn"t/aHM:ePDdMGKXd5(aHM:fRZtj\NObLBa-hq-R>o7TNQ7HHa-hq-R>o7TNQ7HH +a-hq-R>n_?MoV6Fa-hptRZtmWKXd5(aHM:ePDdMGKXd5(\<Di\PDcr7MqG\Ns8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8V`bq<[_Gi8j(LeCN'tf#5PH]=bhXXKAP)Xe_ehUnsl_V50WQS;23* +G#CqU;G)+18p4*)G#CqU;G)+18p4*)G#CqU;G*<n@]+m,\V5:+KRB\NI&DXF\V5:+KRB\NI&DXF +\V5:+KRB\NI&D@2VgNH]KRB\FE2S)&VgNH]HuQ!:I+ZZdi8j(SgtpK/f#u:^]=bhh]Y1,;Unji_ +S=Z7@St)=BS=H1@LM^[I;G)4=<-_\IH!=6n>?#lP<-_\IH!=6n>?$D^:3g&CH!=77FDJFEI(5Au +\VbdEPDco0Kuf1#[uH*PKm9MKI(=rUVhBGqKRB\NI&DXFVgNH]KRB\FE2SA:VgNH]HuS6'h#IES +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8V`bq<[_Gkj7cJXf@b*@Y\f5 +Qu-;fD.f5Q@[M"AQu-<"D.8lL@[D1PQZR#0FDI4bCSuQ!QZR#BFCgheFdI2cVgNHMFDI4bCPlV( +Lg!Q!>?$D^:3KN-H!=6n>?#lP</=^QG#CqX>?#cD8pOW?G#Cr2R[*pQs8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,kpA+@Sq:XQ[ +QZR#0FDI4bCR9-YQZR#1I!(ctCSuQ!QZR#1I!(ctCSuQ!R!a%DI!)?7E0u#qVgNHNI!)?7E2SA: +VgNH]HuPEoCPZ.hH!=6n>?#lP<-_\IH!=6n>?$Ji=F"+MH!=7XXfCUOn*'-,kj7d4m-!<fkMYFa +daZjHN/"6XE0u#qVgNHNI!)?7E0u#qVhBGqHuQ!2E2S)&VgNH]HuQ!2E2S)&VhBGqHuQ!:I(+K< +VhBGqKRB\FE/J.-G@Y*;>#'9P@#.u]G@Y*;>#'9P@#.u]`5T^qs8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,kpA*q=n*'-, +g"bH;gtoT1Pc0Oq\Vbd4KRC=fI&DXFW/QJ?NJ4j$KrBrb[uH*NNJ4j$Kt!%q[uH*NNJ4j$Kt!%q +W/QJ@PDco0Kt!%qLM^[]@p!qc@#AGrMITc,`PqlWs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!o_/+QpA*q=n)39ifZ_OKPDc>lI&N!Y\Vbd5N/"g$Kr9TO +[uH*>KRC7gKrBrb\VbdDNJ4j$Kt!%q[uH*OPDcr7Mmn\"\<Di\PDcr7Mn"t/\<Di\PDcr7Mn"t/ +\<Di\PDcr7Mn"t/\<Di\PDcr7Mn"t/[uH*OPDco0Kr9TOMITbG@p""\<4AZrs8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s7H$\ +kj7d#gt^T<hU9p)bKS5Sbg">Tc,@T?`5T^6`Pod7`Pfa7\<DiKKRB_WL:N1hW/QJ?NJ4j$Kt!%q +[uH*NNJ4j$Kt*>)[uH*NNJ4j$Kt!%q[uH*NNJ4j$Kt!%q[uH*>KRB\FE2S)&W/QJAKm9PTL:N"_ +W/QJ/KRB\NI&N!YVhBH,NJ4<iL:<.r[uH*NNJ4j$Kt!%q[uH*NNJ4<iL:<.rs8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8V`bq<726i8j(LeCMgec,@T? +`5T^6`PoI%]u7n/`5T^-]Y1qi]t:qj]=bhDFDHYKB=O.`a-hptRZtj\NObLBa-hpsPDcu?PfK2O +\XJbmPDcu?Pdlp8\<Di\PDcr7Mn"t/\<Di\PDcr7Mn"t/\<Di\PDcr7Mn"t/\<Di\PDcr7Mn"t/ +\Vbd5N/"lsGc6RU\VbdEPDcr7Mn"t/\<Di\PDcr7Mn"t/\<Di\PDcr7Mn"t/a-hpsPDcu?Pe!6I +a-hptRZt@OPfK2O\XJbnRZt@OPe!6Ia-hptRZtj\NQ7HHa-hqLbfTnbs6T@Mkj7ckgtpK/f#u:^ +`5T^&['[3I['[3I['[3@XKAk:['[3IQ\9pI@p""\<-_\IH!=6n>?$Ji=LX9DaHM:ePDdMGKXd5( +\<DilPD$H0MoV6F\<DikR>o7TNQ7HH\XJc'R>nbGPfT&A\XJc'R>nbGPfK2Oa-hptRZtj\NQ7HH +\<DikR>nbGPfT&A\XJbmPDdMGKZKs[p[%)Cs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +m.9o6m-ilnkLnYIbKS5L`PoI%]sP/RUnsl_V50o`Unji_UnslAI!^$78p4*)BMV3C;G)+18p4*) +G#CqU;G)+18p4*)MITbdKRB\NI&DXF\V5:+KRB\FE2SA:VhBGqKRB\FE2SA:VgNH]KRB\FE2S)& +VhBGqHuQ!:I&DXFVgNI,bg#A<n(HLQdaZjkbg!c4]sP/RX/rFnSt)=BS=H1@R?Ni)St("8@!PsU +G#CqX>?#cD8pOW?G#CqX>?#lP<-_\IH!=6n>?#lP<1%N3[uH*NNJ4m+Mmn\"\<DiLN/"g$Kt!%q +VhBH,NJ49`I(=rUVhBH.Km9MKI&DXFVgNH]KRB\NI&DXFk1nbls8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,coC_>6n&32aQu-;fD.f5Q@Z"YtQZR"uD.f2WCRAsJ +QZR#0FDI4bCR9-YQZR#0FDI4bCR9-YQZR#0FDI4bCR9-YQZR#1D.7Zd8pOW?H!=6n>?#cD8pOW? +G#CqX>?#lP<-D/3H!=6n>?#cD8p=fRkj7d<s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s7H$\m.9nZUnF)l@[D1PQZR#0FDI4bCR9-Y +QZR#1I!(g(Ff0V+R!a%DI!)?7E0u#qR!a%SHuPI#Ff0V+R!a%DI!(g(Ff0V+LNIK\>?#lP<-_\I +H!=6n>?#lP<-_\IH!=6n>?#lP<4K'1kj7d%m-j0)n*'-,kj7ckgtp`>hRB;RR!a%SHuPI#Ff0V+ +R!a%SHuPEoCRBKlR!a%DI!)?7E0u#qR!a%SHuQ!:I&D@2VhBGqKRB\NI&DXFVhBGQD.eZ.:3U5V +H!=6n>?#fW@#.u]G@Y*,>?$r2C]FG7s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s7H$\m.9o.jQG[\grmpdW/QJAML;@]L8^&c +W/QJAML;@]L:<.rW/QJ?NJ4j$KrC5t[uH*?N/"j+Ml;Sh[uH*?N/"g$KrBrb\<Di;KRo"j=Ee:` +MITb4A71:)=TAF$s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8V`bq;C>si8j(SgtoN9TXTo7W/QJAML;@]L:N"_W/QJAML;@]L:N1hW/QJ/KRC7gKrBrb +[uH*OPDcr7Mn"t/\<Di\PDcr7Mn"t/\<Di\PDcr7Mn"t/\<Di\PDcr7Mn"t/\<Di\PDcr7Mmn\" +\<Di[NJ4m+Mn+^m[uH*NNJ3aIFa71jH!=6n>?'4m^&S-4s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,kpA+(Hp#tc2g"bH4eCN9rbKJ,S +`5T^=bg")F`QQKM`5T^=bg!Z"WjdtA[uH*?N/"g$KrBrb[uH*?N/"j+Mmn\"\<Di\PDco0Kt*>) +\<Di\PDco0Kt!%q[uH*NNJ4j$Kt!%q[uH*NNJ4j$KrBrb[uH*?N/"g$Kt!%qW/QJ?NJ4j$KrBrb +[uH*OPDcAuL:<.rW/QJ?NJ4<iL8^&c\V5:LXJPsss8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!o_/+Em-ilnkLnYIdaZjkbg")F`Pfa7]=bhs]Xk_f]t:qj +`5T^-]Y1qi]st2ELM^[jFDJFUPe!6I\XJc'R>nbGPe!6I\XJbnRZt@OPdlp8\<Di\PDcr7Mn"t/ +\<Di\PDcr7Mn"t/\<Di\PDcr7Mn"t/\<Di\PDcr7Mn"t/\<Di\PDcr7Mn"t/[uH*OPDcr7Ml;Sh +\<Di\PDcAuL:EG*\<Di\PDcr7Mn"t/\<Di\PDcr7Mn"t/a-hptRZt@OPfK2O\XJbnRZtj\NQ7HH +\XJc'R>nbGPfK2O\XJbnRZuFB^&S-4s8W,coC_>6n)39idaZjkbg")F`O*"Z['[3I['[3I['[3I +['[3@XKA:pUj60DH!=6lA713s:3g&CH!=7GKRC:nMn,:@\<Di]RZt@OPe!6I\XJc'R>nbGPfK2O +\XJbnRZtj\NObLBa-hptRZtj\NObLBa-hptRZt=GMoV6F\XJc'R>n_?Mo_*8\<Di\PDcr7Mo_*8 +f>PB&s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8V`bq<[_Gi8j(Sgtp5uc,@T? +]=bhXXKAP)XdkuQUnsl_V50o`Uka&2BMV35:J#_-8n_!lG#CqG:J#_-8p4*)G#CqU;G)gV=Lj<: +VhBGqKRB\NI&DXFVhBGqKRB\FE2S)&R!a%SHuPF*JZ!m7VhBGqKRB\NI&DXFVhBGqKRB\NI*9aY +i8j(SgtpK/f#5PH]=bha['Zm8Xe_ehS=Z7@St)=BS>_mAG@Y*);G(Uu8U4N>BMV3C;G)+18p4*) +G#CqU;G)4=<-D/3G#CqfD.ff+L8^&cW/QJ?NJ4<iL:<.rW/QJ0N/"g$Kr9TOW/QJ/KRB\NI&DXF +VhBGqHuQ!:I&DXFVgNH]KRDq;h#IESs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8V`bq=OCVkj7crjQDnXFbagHLM^[ZD.f5Q@Y\f5Qu-;fFE!RgCR9-YQZR#0FDI4bCR9-Y +QZR#0FDI4bCR9-YQZR#0FDI4bCR9-YH!=6n>?#cD8p4*)H!=6k;G)4=<-D/3BMV3F>?#938Tn!( +BMV3C;G*mPOT5@\s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W,kpA*k+gmEJ3LM^[jFDHYRE0kZ^QZR#0FDI4bCR9-YQZR#1I!(g(Ff0V+ +R!a%DI!)?7E0u#qR!a%DI!)?7E0u#qVgNHNI!(ctCO',`H!=6n>?#lP<-_\IH!=6n>?#lP<-_\I +H!=7XXfD-^kNM:$kj7d%m-j0)n)iE\g"bH(]XjJXFdI2cQZR#1I!(ctCRBKlQZR#0FDI4bCR9-Y +QZR#0FDI4bCRBKlR!a%DI!)?7E0u#qVhBGqKRB\NI$f;(H!=6lA70[e</P0fH!=6lA70[e<-Mk\ +G@Y+$]Xn.Cs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W,kpA*q=n)39ig"bGnUnFZFL8^&cVhBGqKRB_WL8^&c[uH*?N/"g$KrBrb +[uH*?N/"g$KrBrb[uH*?N/"g$KrBrb\<DiLN/"g$KpQmsG@Y*=@p!qc@#.u]Q]-h%s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s7H$\kj7crjQG4OhT2dp +VhBGqKRB_WL8T]PW/QJ0N/"9iL8^&cVhBGrN/"m#I&N!YW/QJ?NJ4<iL8^&c\<DiLN/"j+Ml;l% +\<Di\PDcr7Mn"t/\<Di\PDcr7Mn"t/\<Di\PDcr7Mn"t/[uH*OPDcAuL:<.r[uH*?N/"g$KrBrb +\V59`D.e,u<-_\IG@Y+Um-"EKs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!o_/+=jQGI^kLnYIdaZk#bfe2Rc,@T?`5T^6`Pod7`QQKM +`k8m]P`Vi&L8^&c[uH*?P`WA6KrC5t[uH*?P`WD=Mmn\"W0ECQNJ4m+Mmn\"\<Di[NJ4j$Kt!%q +W/QJ?NJ4<iL8^&c[uH*OPDco0Kt!%qW/QJ0N/"g$KrBrbW/QJ?NJ4<iL8^&c[uH*?N/"g$KrBrb +VhBGrN/"6`I.[..s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s7H$\kj7crjQFt@f#u:^bKS5L`Pod7`Pfa7]=bhq`PoI%]uI^r]=bhh]Y1hWWcr;q +VgNHoRZt@OPe!6I\XJbnRZt@OPe!6I\<Di]RZt=GMn"t/\<Di\PDcB(OLUL4\<Di\PDcr7Mn"t/ +\<Di\PDcr7Mmn\"[uH*?N/"g$Kt*>)W/QJ@PDcAuL:EG*W/QJ@PDcr7Ml;l%\<Di\PDcr7Mn"t/ +\<Di\PDcr7Mn"t/\<Di\PDcr7Mn,:@\<Di]RZt@OPe!6I\XJbnRZt@OPe!6Ia-hptRZt@OPi]j# +s8W-!s8W-!s7H$\kj7crjQG4OhTO-f`5T^-]Y1\Z['[3I['[3I['[3I['[3I['[2qD.e,u<-_\I +H!=6n>?#fW@$btN\<Di\PDcr7Mn,:@\<Di]RZt=GMn,:@a-hptRZt@OPfK2O\XJbnRZt@OPfK2O +\<Di]RZt=GMoV6F\XJc'R>n_?MoV6F\<Di]RZt=GMn,:@aJ>C!pA+ags8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!kj7bnD.eTNH`3Bu +a0i2#eCO9cq>^Kps8W-!s8W-!s8W-!m.9o6m-ilnkL.l2daZjd`PoI%]sP/RUnsl_V50o`Unji_ +UnslBFDuD$8n_!lBMV35:J#4q8Tn!(BMV35:J#4q8SCmkMITbdKRB\NI&DXFVhBGqKRB\NI$f;( +VgNHNI!)?7E2S)&R!a%SKRB\NI$f;(VhBGqKRB\NI&DXFVhBH@bg#),kLnYIdaZjkbg!c4]sP/R +X/rFnSt)=BS=H1@S=Z7@St("8?t`>-BMV35:J#h9<+o'!BMV3F>?#938SCmkG#CqF>Zu;K8r@+\ +W/QJ0N/"6`I&N!YW/QJ/KRC7gKr9TOW/QJ/KRC7gKr9TOVhBGqKRB\NI&DXFVhBGqKRB\NI&DXF +k1nbls8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,kpA+(Hp#tc2 +\XJbMD.89;B:*OFLM^[ZD.f2WCPQb>QZR"uD.f2WCPQb>QZR"uFE!RgCPR"NQu-;fFE!Ua@Y]&E +QZR"uFE!+I=D1K%H!=6]:J#4q8SCmkBMV35:J#h9<+o'!BMV3F>?#938SCmkH!=8$gtr)2s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s6T@M +\?2cdD.eW@B8:>:QZR"uFE!"WE//OSQZR#1I!(g(FdRQ!R!a%DI!(g(Ff0n?R!a%CFDI7kFdRQ! +R!a%DI!(g(FdRQ!QZR"g>?#lP<-_\IH!=6k;G)4=<-_\IH!=6]:J#h9<4K'1m.9o:oC_kEkNqg5 +kj7crjQG4OhU9p)VhBGaFDI4bCR9-YQZR#0FDI4bCR9-YQZR"uD.f2WCR9-YQZR#1I!(ctCRBKl +R!a%DI!)??I$]M;VhBGqKRAPlB8U2$G@Y*,>?#fW@!PsUG@Y*;>#'?I<-N1po_/+\s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8V`bq<[_G +kj7d#gt^)sc)?SUW/QJ/KRB_WL8^&cW/QJ0N/"9iL8^>uW/QJ0P`Vi&L8^&cW/QJ0N/"9iL:EG* +W/QJ0N/"9iL:<.rW/QIg@p""\<-Mk\H!=6lA74'6bQ%VBs8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!o_/+Em-ilnkMYFa`k8m\KRB\NI&DXFW/QJ/KRB_WL8T]P +VhBGrN/"6`I&N!YVhBGrN/"6`I&N!YW/QJ?NJ4<iL8^>u[uH*?P`WD=Ml;l%W0ECBP`Vi.OLUL4 +W0ECBN/"9qOLL4'W0ECBN/"9iL8^&cW/QJ0N/"9iL8^&cW/QJ0N/"9iL8^&cMITb6>?#lP</5R7 +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8V`bq<[_Gi8j(SgtpK/f#u:^bKS5Sbg")F`QQKM`5T^6`Pp$Ec*sLA\<DiLN/"9qOJn+m +W/QJ?NJ4<iL8^&cW/QJ0N/"g$KrBrbW/QJ0N/"9iL8^&cW/QJ?NJ4<iL:<.rW/QJ@PDcr7Ml;l% +\<DiLP`WA6KrBrb\<DiLN/"9iL8^&cW/QJ?NJ4<iL8^&cW/QJ0N/"9iL8T]PaJ>C,s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,kpA+(Hp#+oo +k1nb?eCMgec,@T?`5T^6`PoI%]uI^r]=bhh]Y28&`Oidr]=bhQV5/l`B;^E1\XJbnRZt@OPe!6I +\XJbmPDcB.Q+3$9W0ECBP`Vi.OLUL4W0ECRPDcB(OJn+mW0ECQNJ4<qOJn+mW0ECBN/"9iL:<.r +W/QJ0N/"9iL:<.rW0ECRPDcB(OLUL4W0ECRPDcB(OLUL4W1'!]PDcB.Q+3$9\<DiLP`WD=Ml;l% +\<DiLP`WD=Mn"t/\XJbnRZt@OPe!6I\XJbnRZt=GMn,:@f>PB&s8W-!s8W-!s8W,kpA+(Hp#+oo +daZjreCMRW`Oidr['[3I['[3I['[3IX/rG1['[3I[$Q`/H!=6lA70[e<-Mk\H!=7*@p#[oOL^gE +\XJbnRZt=GMn,:@\XJbnRZt@OPe!6I\XJbnRZt=GMoV6F\XJbnRZtj\NObLBa-hptRZt@OPe!6I +\XJbmPDcu?Pdlp8a-hqOe^sj$s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,]gt[*a@!PsUBMV3F>?#6?>'<e9H!=6n>?$u;Ff:ao +['[4(m-jT?q<[_Gi8j(Sgtp5uc,@T?]=bhXXKAP)Xe_ehUnsl_V50o`Uka&2BMV35:J#4q8SCmk +BMV35:J#4q8SCmkG#CqG:J$FR=Jph"VhBGbI!)?7E0u#qVgNHNI!)?7E0u#qVhBGbI!)?7E0u#q +VhBGqKRB\NI$f;(VhBGqKRB\NI*9aYi8j(SgtpK/f#5PH]=bha['Zm8XdkuQS=Z7@St)=BS=H1@ +G@Y)p:J#_-8n_!lBMV35:J#4q8SCmkBMV3F>?#938Tn!(BMV3TD.ff+L8T]PVhBGqKRB_WL8T]P +W/QJ/KRB\NI&DXFW/QJ/KRB\NI&DXFR!a%SKRB\NI&DXFVhBGbI!+,thZ*WUs8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s7H$\m.9o6m-hm3`J8PSLM^[ZD.eW@B8:>: +QZR"uFE!"WE0tKOLM^[ZD.eWGE//:CQu-;fD.eW@B8:>:LM^[kD.89;B8:>:LM^[L>?#938SCmk +H!=6]:J#h9<+o'!BMV3F>?#938SCmkB3\VR:J#4q8V_D,o_/+\s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!o_/+=jQDkOCPQb>Qu-;fD.eW@B8:>: +QZR#0FDHYRE0u#qR!a%DI!(g(FdRQ!R!a%DI!(g(FdRQ!R!a%DI!(ctCRBKlR!a%DI!(3dE->,O +H!=6n>?#cD8nVC4H!=6]:J#2(>'X=OBMV4,[']2kp$D;Cm.9oBpA*q=n)39ig"bH4eCM+)TSIAs +LNIL%FDHYKB:!^ULM^[jFDHYKB8:SJLNIL%FDHYRE0kZ^R!a%DI!(g(FdRQ!R!a%CKRp%SI&DXF +R!a%#A70Ul@!PsUH!=6lA70[e<-Mk\G@Y*,>?$rBJcGcMs8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!o_/+Em-ilnkLnYI\XJb]N/"6`I&DXF +W/QJ/KRB_WL8^&cW/QJ?NJ4<iL8^&cW/QJ?NJ4<iL:EG*W/QJ0N/"9iL:N1hW/QJ0N/!^IFa%A( +MITb4A71:)=GM!;s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W,kpA*q=n*'-,i8j(>`Pnd7L8T]PQ\9pfKRB\NI&N!YVhBGqKRB\NI&DXFVhBGaKRp%SI&N!Y +VhBGrN/"9iL8^&cW/QJ0N/"9iL8^>uW0ECBP`WD=Ml;l%\<DiLP`WD=Ml;l%[uH*?P`Vi&L8^&c +W/QJ0N/"6`I&DXFVhBGqKRB_WL8^&cW/QJ0N/![PJU(I!H!=6lA71a_MZ<_Vs8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,kpA*q=n(HLQ +g"bH4eCMgec-+>U`5T^6`Pod7`QQKM`5T^8]Xk&+OJnD*W/QJ0N/"9iL8^&cW/QJ0N/"9iL8^&c +W/QJ0N/"9iL8^&cW/QJ0N/"9iL8^&cW0ECBP`WD=Ml;l%W0ECRPDcB(OLUL4W0ECRPDcB(OJn+m +W/QJ@PDcAuL8^&cW/QJ0N/"9iL8^&cVhBGrN/%)nkPtS^s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!o_/+Em-ilnkLnYIdaZjkbg")F`Pfa7 +`5T^-]Y28&`Oidr]=bhq`PoI%]uI^rW1&uqD/6)/L:Nb;\XJb]P`WGEPc0h.\<DiLP`Vi.OLUL4 +W/QJ0N/"9iL8^&cW0ECQNJ4<iL8^&cW0ECQNJ4<iL:<.rW/QJ0N/"9iL8^&cW/QJ0N/"9iL8^&c +\<DiLN/"9qOLUL4W0ECBP`Vi.OLUL4W0ECRPDcB(OLUL4W0ECBN/"9iL:EG*W0ECRPDcB(OLUL4 +\XJbmPDcu?Pe!6I\<Dj8e^sj$s8W-!s8W-!s8W-!s7H$\m.9o6m-iW_hTO-fbKS5C]Y1qi]sP/R +X/rG1['[3I['[3I['[39V5/B@<-_\IH!=6n>?#lP<-_\IW/QJ@PDcu?Pe!6I\XJbnRZt@OPe!6I +\XJbnRZtj\NObLB\XJbnRZt@OPdlp8\XJbmPDcu?Pe!6I\<DikR>nbGPdlp8\XJc(XJPsss8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8U$V`FiFZBMV35:J#4q8SCmkBMV3F>?#938S;:3B3\V`;G)^dE5oQ%m.9o6m-ilnkLnYI +daZjd`PoI%]sP/RUnsl_V50o`Unji_UnslBFDtnh8QA2FBMV3I3]q(O8SCmkBMV35:J#4q8SCmk +G@Y*JKRp%SI$f;(VhBGqKRB/7Ff0n?R!a%CKRp%KE0u#qR!a%SKRB/7Ff0n?Q\9pfKRB\NI$]M; +VhBH@bg#),kLnYIdaZjd`PoI%]sP/RX/rFnSt)=BS=H1@S=Z7@St("8?t`>-BMV35:J#4q8SCmk +BMV35:J#4q8SCmkBMV35:J#4q8W%"[VhBGaKRp%SI&DXFVhBGqKRB\NI&DXFW/QJ/KRB\NI&DXF +Q\9pfKRB,>JZ"0KQ\9pfKRB,>JZ"0Kk1nbls8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W,kpA+@Sq<726i8j'gI!(3]B8:>:LM^[ZD.eW@B8:>:LM^[ZD.eWGE0tKO +LM^[ZD.eW@B8U2$LM^[ZD.eW@B8:>:LNIL%FDHYKB8:>:BMV34>Ztf:8SCmkB3\VR:J#4q8SCmk +BMV35:J#4q8SCmkBMV35:J$t<PQ1[_s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8VHWor+=ELNIKjD.eW@B8:>:LM^[jFDHYRE//OSQZR"uFE!RgCPR"N +QZR"uFE!RgCPR"NQZR#0FDHYRE0u#qQZR#1I!(ctCRBKlLM^[I;G(S,>%g]'B3\V`;G(Uu8S;:3 +BMV35:J#4q8[Pk3o_/+QpA+@Sq<[_Gm.9o6m-ilnkLnYI`5T]^FDHYKB8:>:LM^[ZFE!RgCPQb> +LNIL&D.89BE//OSQZR#1I!(ctCRBKlR!a%DI!(d/JX;%@VhBGaN/FNdI$f;(H!=6lA70Ul@!PsU +G@Y*,>?#fW@!?-hG@Y*[R[*pQs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W,kpA+@Sq<726i8j(A[BZ'WMPl,TQ]-g"KRB_WL8^&cW/QJ0N/"9iL8^&c +W/QJ0N/"9iL8^&cW/QJ0N/"9iL8^&cW/QJ0N/"9iL8^&cQZR"eA70[e<-Mk\G@Y*kXfDF$s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s6T@Mkj7d#gt^?-eu4gp +VhBGaKRoJCJZ"0KQ\9pVKRoJCJZ"0KQ]-fgKRp%SI$]M;Q\9pVKRoJCJZ"0KQ]-g"KRB_WL8^&c +W/QJ0N/"9iL8^&cW/QJ0N/"9iL8^&cW/QJ0N/"9iL8^&cW/QJ0N/"6`I$]eLW/QItKRp(\L8^&c +W/QJ0N/"9qOJn+mW0EC2I!'XD@!PsUH!=7XXfDF$s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s7H$\kj7crjQG4OhU9p)fZ_O^bg")F`RrDX +`5T^6`Pp$Ec,@T?\"o[qP`Vi&L8^&cW/QJ0N/"9iL8^&cW/QJ0N/"9iL8^&cW/QJ0N/"9iL8^&c +W/QJ@PDcAuL:<.rW0ECBN/"9iL8^&cW/QJ0N/"9iL8^&cW/QJ0N/"9iL8^&cW/QJ0N/"9iL8T]P +W/QJ/KRB_WL:Nb;s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s6T@Mkj7ckgtp`>hU9p)bKS5L`Pod7`Oidr`5T^-]Y28&`Oidr +]=bhh]Y1qi]qhL#G@Y*[N/"9qOJnD*W0ECBP`Vi.OJn+mW/QJ0N/"9iL8^&cW/QJ0N/"9iL8^&c +W/QJ0N/"9iL8^&cW/QJ0N/"9iL8^&cW/QJ0N/"9iL8^>uW/QJ0P`Vi.OJnD*\<DiLN/"9qOLUL4 +W0ECBP`WGEPc0h.\<DiLP`WD=Ml<)0\<DiLP`WD=Ml<)0\XJbnRZsb8OL^gE\XJbnRZuakkPtS^ +s8W-!s8W-!s8W-!s8W-!s8VHWp#+ooi8j(LeCMgec,@T?]=bha['[3I['[3IX/rG1['[3I[(*6< +LNIKZA70[e<-_\IG@Y*,>?$B"E4D*i\<Di]RZt@OPe!6I\XJbmPDcu?Pdlp8\XJbnRZt=GMn,:@ +\XJbnRZt@OPe!6I\XJbnRZt@OPdlp8\XJbnRZusih#IESs8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s7H$\o_/+IoC_JAp%7tRo_/+\s8V`bq4+%HBMV35:J#4q8SCmk +BMV35:J#4q8SCmkBMV35:J#4q8V_D,W/QJ0P`XhakNqg5i8j(Sgtp5uc,@T?]=bhXXKAP)Xe_eh +Unsl_V50o`Uj$p&BMV3"76tT_8Q\YWBMV3"76tT_8SCmkBMV35:J$@G:7$WbVgNHMKRoJCJXCh- +VhBGaKRp%KE0l6/VhBGaKRp%SI$]M;VhBGaKRp%SI&DXFQ]-g"KRB_WL<Ifci8j(SgtpK/f#5PH +]=bha['ZX*Unji_S=Z7@St)aJQ(4G9G@Y)p:J#4q8SCmkBMV35:J#4q8SCmkBMV35:J#4q8SCmk +BMV3DA72<gI$f;(Q\9pVKRoJCJX;%@VhBGaKRp%SI$]M;VhBGaKRp%SI$]M;Q\9pVKRp%SI$]M; +VhBGaN/HcQh#IESs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +o_/+Em-j0)n$f*cLM^[ZD.e`9=GLa+LM^[ZD.eW@B8:>:LM^[ZD.eW@B8:>:LM^[JD/5#==GLa+ +LM^[ZD.eW@B8:>:LM^[ZD.e''?t`>-BMV35:J#4q8SCmkBMV35:J#4q8SCmkBMV35:J"Y^88(dj +BMV3uR[*pQs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s7H$\ +fZ_NoD.eW@B8:>:LM^[ZD.eW@B8:>:LM^[ZFE!RgCPR"NLNIL&I!(3dE0kZ^L4"?7FDHVYH^Ahi +L4"?7FDHVYH\Z]^LNIL%FDHYKB4kIQBMV35:J#4q8S;:3BMV35:J#4q8SCmkBMV40XfD$eq=OCV +o_/+QpA+@Sq<726i8j(SgtpK/esV_cQu-;fD.eW@B8:>:LM^[ZD.eW@B8:>:LM^[jFDHYRE//OS +R!a%2I!_6.FdIc4R!a%CKRoJCJZ"0KQ\9pVKRnnqB6d]\G@Y**A70Ul@!?-hG@Y)o>ZuDW<-Mk\ +Q]-h%s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s7H$\ +kj7crjQF_1c'OBHVhBGaKRoJCJZ+N^Q]-g"KRB,FMPuJgW/QJ0P`Vi&L8^&cW0ECBN/"9iL8^&c +W/QJ0N/"9iL8^&cW/QJ/KR@uS@!?-hG@Y**A70Ul@/p9,s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!kj7d%m-ilnkLnYIW1'!<KRoJCJX;%@Q\9pVKRoJCJZ"0K +Q\9pVKRoJCJX;%@Q\9pVKRoJCJZ"0KQ\9pVKRp%SI$]M;Q]-g#N/![XMO8d6G@Y*[N/"9iL8^>u +W/QJ0N/"9iL8^&cW/QJ0N/"9iL8^&cW/QJ/KRB,>JZ+N^Q\9pgN/"9iL8^&cW/QJ0N/"9iL8^>u +LNIKZA70%T>'X=Og"bHas8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W,kpA+@Sq<726i8j(LeCN'tf#u:^bKS5L`Pp$Ec,@T?`5T^6`Poj0\u:jT +W/QJ0N/"9iL8^&cVhBGaN/FNdI&N!YW/QJ0N/"9iL8^&cW/QJ0N/"9iL8^&cW/QJ0P`Vi&L8^&c +W0ECBP`Vi&L8^>uW/QJ0N/"9iL8^&cW/QJ0N/"9iL8^&cQ]-g#N/![PJZ+N^Q\9qRm-juSs8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W,kpA+@Sq;C>sg"bH4eCMgec-+>U`5T^6`Pod7`Oidr]=bhs]Xk_f]u7n/]=bhs]Xjo8Uk`f" +Q]-g3PDcAuL8^>uW/QJ0N/"9qOJn+mW/QJ0N/"9iL6mjVW/QJ0N/"9iL8^&cW/QJ0N/"9iL8^&c +W/QJ0N/"9iL8^>uW/QJ0N/"9iL8^&cW/QJ0P`Vi.OJnD*W0ECBP`Vi4Q+3$9W0ECBP`Vi4Q+<?J +W1'!]PDcB.Q+<?JW1'!^RZt@OPc1%9\XJbnRZt:WT`>&ls8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +o_/+IoC_&&kLnYIbKS5L`PoI%]sP/R['[3I['[3I['[3I['[3@XK@nSPBgA3G@Y)o>ZuDW<-_\I +G@Y*[P`WGEPdlp8\XJbmPDcu?Pe!6I\XJbnRZt=GMn,:@\XJbnRZt@OPdlp8\<Di]RZt=GMn"t/ +\XJbmPDdJhZ2ak(s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +m.9o:oC_>6n*'-,kj7d%m-j<4p#+ooL4">J76spB5ug?><CK2U9Lr8Z86APVBMV3%9Lrhm8SCmk +QZR#AN/![PJZ"0K]=bi@m-ilnkL.l2daZjd`Po3k['[3IUnsl_V50o`Unji_UnslBFDt5K6"j%c +<CK2e:J"Y^8:3H\BMV3"76spB6"j%cH!=7GHuPF*JXCh-VhBGbI!(d/JZ"0KQ\9pWI!(d/JXCh- +Q\9pfKRB,>JX;%@VhBGaKRp(\L8^&cQ]-gFbg#),kLnYIdaZjd`PoI%]sP/RX/rFnSt)44PFS57 +S=Z7@St'Fu>#e!W<CK2R76spB5ug?>BMV35:J#4q8SCmkBMV35:J#4q8W%"[Q\9pWI!(g(FdRQ! +VgNHMKRp%SI$]eLVhBGaKRoJCJX;%@Q\9pWI!)??I$]M;Q\9pVKRoJCJZ"0Kg"bHas8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8V`bq<[_Gkj7c]bfto[B8:>: +GAV,Q@p"M'B8:>:LM^[ZD.eW@B8:>:G@Y*=@p!qlCNj;sGAV,Q@p!qlCPQb>LM^[ZD.eWGE//:C +LM^[;:J#4q8SCmkBMV35:J"Y^88(dj=A28!:J"Y^88(djBMV3%9Lr8Z88(djL4"@3m-juSs8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,Pgtmg.E//:CLM^[ZD.eW@B6S3. +LM^[ZD.eW@B8:>:LNIKjFE!"WE//OSLNIL%FDHYRE/&aeLNIKjFE!RgCPR"NLNIKjFE!RgCPI4` +LM^[;:J#4q8SCmkBMV35:J#4q8SCmkBMV3%9Lrhm8[Pk3o_/+\s8V`bq=OCVo_/+Em-ilnkN:RT +daZjT['YU*B8:SJLM^[ZD.eW@B8:>:LM^[ZD.eW@B8:SJLNIL%FDHVYH^AhiL4"?8I!(d/JX;%@ +VhBGaKRoJCJZ+N^Q\9p6D/4?+@!PsUB3\Vc>?#fW@!PsUB3\VaA70[e</5R7daZkJs8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!o_/+IoC_&&kLe#%W/QItKRoJCJX;%@ +Q\9pVKRoJCJX;%@W/QItN/FQmL8^&cW/QJ0P`Vi&L8^&cW0ECBN/"9iL8^&cW0ECBN/"9iL5()& +G@Y*,>?#fW@!PsUUnsmes8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W,kpA*q=n)39ik1nb%Xf@_@JXCh-Q\9pWI!(d/JX;%@Q\9pVKRoJCJXCh-Q\9pWI!(d/JX;%@ +R!a%CKRoJCJX;%@Q]-g"KRB,>JZ+N^Q\9p6A70%T>*k2*W/QItN/FQmL6mjVQ]-g#N/![XMO09Z +W/QItN/Es\MPuJgQ]-g"KRB,FMPuJgQ]-g#N/"9iL8^>uW0ECBN/"9iL3IKMH!=6\>Zu>^@/p9, +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +o_/+Em-ilnkLnYIdaZjkbg")F`QQKM`5T^6`Pp$Ec,@T?`5T]oR['h1L6mjVVhBGaN/EsTJZ+N^ +Q\9pgN/![XMPl,TQ]-fgKRp(\L6mjVW/QItN/FQmL8^&cW/QJ0N/"9iL8^&cW/QJ0N/"9iL8^&c +Q]-g#N/![PJX;=QVhBGaN/FNdI$]M;Q]-fgKRp(dOT5@\s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!o_/+Em-j0)n(HLQ +daZjreCMgec,@T?`5T^-]Y28&`Oidr]=bhs]Xk_f]t:qj]=bhQV5/lgE0l6/W0ECBN/"9iL8^&c +W/QItN/Es\MPuJgQ\9pfKRB,FMO0!IQ]-g#N/![XMPuJgQ]-g#N/![XMPuJgQ]-g#N/"9iL8^&c +W0ECBN/"9qOLUL4W0ECRPDcB(OJnD*\<DiLP`Vi4Q+<?JW0ECBP`Vi4Q+<?JW1'!^RZsb>Q+<?J +W1'!^RZsb>Q,LY\s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8V`bq<[_Gi8j(SgtpK/f#5PH +]=bhh]Y1\Z['[3I['[3@XKAk:['[3IX/rFIA70%T>'X=OB3\VaA70[e<2bb1W1'!^RZsb>Q+<?J +\XJb]P`WGEPe!6IW0ECSRZt=GMn,:@W0ECSRZt@OPc1%9\XJb]R[(FPPe!6IfZ_P=s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!o_/+IoC_&&kMYFai8j(SgtpuMkMYFa +['[2Q>Zt,r5ug?><CK2R76spB5ug?><CK2R76spB5ug?>BMV3SI!_35JX;%@Q\9pVKRp(dOPo3_ +i8j(Sgtp5uc,@T?]=bha['ZX*Unji_Unsl_V50o`Uka&2BMV3%9Lr/P6"j%c<CK2U9Lrhm8QA2F +BMV3"76u3'<0r8hR!a%CKRoM<FdIc4R!a%CKRoJCJX;%@Q\9pVKRoJCJX;%@VhBGaN/EsTJZ+N^ +Q\9pgN/![PJ^W'!i8j(LeCN'tf#5PH]=bha['ZX*Unji_S=Z7@St)=BS=H1@B3\V?76spB5ug?> +BMV3"76spB5ug?><CK2R76spB6"j%c<CK2tA71dPFdRQ!R!a%CKRoM<FdRQ!Q\9pVKRoJCJX;%@ +Q\9pWI!(d/JXCh-Q\9pWI!(d/JZ"0KQ\9pVKRr:@h#IESs8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!o_/+IoC_>6n)39iQ]-fGA7110B6RloGAV,>A70Ul@!?I' +G@Y**D/4?+@!?I'MITb4A70Ul@!?I'G@Y**A70Ul@!?I'LM^[JA70Ul@#&T3B3\VB9Lrhm8Q\YW +BMV3%9Lrhm8Q\YWBMV3%9Lr8Z86APVBMV3%9Lr8Z89\TP]=biWs8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8Ud-hM-E)LM^[ZD.e'0CPQb>GAV,ND.eW@B6S3.LM^[ZFE!"PB8:SJ +LNIKjFE!"WE//OSLNIL%FDHYRE//OSLNIKjFE!"PB8:>:LNIKjFDuG7?t`>-BMV35:J"Y^88(dj +=A27f9Lr8Z86APV=A28m[']l5s8W-!s8W-!s8V`bq=OCVi8j(ZjQG4OhUp&qQ\9pFD.eW@B8:>: +LM^[ZD.eW@B8:>:LM^[ZFE!"WE//OSLNIKjFDut^H^K2'R!a%DI!(g(FdIc4Q\9pVKRoJCJX;%@ +LM^[:>ZuDW<-Mk\B3\VaA70%T>'FLbB3\VQ>ZuDW<1/r6o_/+\s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W,kpA+@Sq<726`5T]^KRoJCJXCh-Q\9pWI!(d/JX;%@Q\9pfKRB,>JX;%@ +W/QItN/FQmL6mjVW/QItN/FQmL8^&cR?Ni5N/"9iL7+6hW/QITA70Ul@!?-hG@Y**A75''q>^Kp +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8V`bq<726i8j(Sgtp&`\sJ)$ +Q\9pVKRoJCJX;%@Q\9pVKRoJCJX;%@L4"?8I!(0kH^K2'L4"?8I!(d/JXCh-Q\9pVKRp%SI$]eL +Q]-g#N.uOnCN`TJL4"?d`PndEQ'[/TQ]-fgKRp(\L6mjVW/QItN/FQmL6mjVW/QItN/FQmL6mjV +W/QItKRoJKMO09ZW/QJ!PEVr(L8^>uW/QItN/Dgi?t`>-B3\VpI!bnns8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s6/h<kj7ckgtpK/f$`(! +fZ_OW`Pp$Ec,@T?`5T^6`Pod7`OidrQ\9pgN/![PJX;%@W/QItKRp(\L6mjVW/QItKRp(\L6mRE +VhBGaKRoJKMPl,TQ]-fgKRoJKMO09ZQ]-fgN/FQmL6mjVW/QItKRoJKMO0!IQ\9pfKRB,FMO0!I +Q]-fgN/FNdI$]eLl.+Dcs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s7H$\kj7crjQG4OhU9p)bKS5Sbg")F`Pfa7 +`5T^-]Y28&`Oidr]=bhq`PoI%]uI^r\?2cTD/5JkJZ+fpW0ECBN/![XMPuJgQ]-g"KRB,>JX;%@ +Q\9pfKRB,>JX;%@Q\9pgN/![XMPuJgQ]-g#N/"9iL6mjVW/QItN/FQmL8^>uW/QJ0P`Vi.OJnV5 +\XJb]R['h?Q+<?JW1'!MP`Vi.OJnV5\<DiLR[(FPPc0h.\XJb]R[(FPPc1%9f>PB&s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,coC_>6n(HLQdaZjd`Pod7`Oidr['[3I['[3I['[3I +['[3@XKAk:["sBgH!=6\>Zu>^@!PsUB3\VqD.ff3OJnD*\XJb]R['h9OL^gEW0ECBR[(FPPe!6I +W1'!MP`WGEPc1%9\XJb]P`WGEPe!6IW0ECBR[(FPPigcVs8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W,coC_JAp#+ooi8j(SgtpK/f$`(!bKS4iMi:Y)5ug?><CK2R76spB5ug?> +<CK2R76spB5ug?><CK2e:J$=`E0u#qR!a%DI!(d/JXCh-LkLH"`PpcrkLnYIdaZjd`PoI%]sP/R +Unsl_V50o`Unji_UnslBFDt5K6"j%c<CK2e:J"Y^88(dj<CK2e:J"PT6!-fOH!=78I!(d/JX;%@ +R!a%CKRoM<FdIc4R!a%DI!(d/JX;%@Q\9pVKRoJCJZ+N^Q\9pVN/Es\MPuJgQ]-gFbg#),kLnYI +daZjd`PoI%]rS6:X/rFnSt)=BS=H1@S=Z7@St't%8l\;G<CK2R76spB5ug?><CK2R76spB5ug?> +<CK2R76spB6$Z[6L4"?8I!(0kH^K2'R!a%CKRoM<FdRQ!R!a%CKRoM<FdIc4R!a%DI!(d/JX;%@ +R!a%CKRoJCJX;%@g"bHas8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s7H$\kj7d%m-hs,\p&",G@Y**A70Ul@#AGrGAV,Q@p!qc@!?-hG@Y**A70Ul@!?-h +G@Y*,>?#fW@!?-hG@Y**A70Ul@!?I'G@Y**A70Ul@!PsU=A28!:J"Y^88(dj=A27f9Lrhm8Q\YW +BMV3"76t$L86&)E=A27c76spB6&0Q$bKS62s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s2;mq +LNIKjD.e''@#&T3GAV,>A7110B6S3.LM^[ZD.e'7FGF^GLNIKjD.eWGE//OSLNIKjFDut^H\Z]^ +LNIKjFE!"WE//:CGB@q^D.eW@B8:SJG@Y)`9Lr8Z86APV=A27f9Lrhm8Q\YW=A28!:J"Y^8@5b2 +s8W-!s8W-!s8W-!o_/+IoC_>6n)39ig"bH4eCM.3Wcqu]LM^[JD/4oDB6S3.LM^[ZD.e'0CPQb> +LNIKjFE!"WE//OSR!a%3FDut^H\d?.R!a%4KS5_?FdRQ!Q\9pVKRoJKMO8d6G@Y)o>ZuDW<+fH> +H!=6\>Zu>^@!?-hB3\VaA70%T>+D1Sp[%)Cs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8V`bq=OCV +i8j(1UnF'-JX;%@L4"?7KRoJCJX;%@Q\9pWI!(d7MO0!IQ]-g#N/![XMPuJgQ]-g#N/"9qOI(o` +W/QItN/FQmL7+6hQ]-g#N/!+0E-Gi#G@Y)o>Zu>^@&TNZs8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s7H$\kj7d%m-ilnkKD)oQ]-fgKRoJCJX;%@Q\9pVKRoJCJX;%@ +Q\9pWI!(0kH^K2'L4"?8I!(0kH^BD:Q\9pGKS5_?FdIc4Q\9pVKRp%SI"uf_BMV34>[#(b`RrDX +`k8m]N/![XMO0!IQ]-fgKRp(\L6mjVQ]-g#N/![XMPuJgQ]-fgN/FQmL6mjVW/QJ0N/![XMPuJg +W0EC3PEVr(L6mjVQ\9p&>Ztf:8SCmkR?Nj7s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,kpA*q=n)39ig"bH4eCMgec-+>U`5T^=bg")F`Pfa7 +f>PA@`Pnd?OI(WOQ\9pVKRoJCJX;%@Q]-g"KRB,FMO09ZQ\9pVKRoJKMPl,TQ\9pVN/EsTJX;%@ +Q\9pVKRp%SI$]eLQ]-g#N/![XMO0!IQ\9pVKRoJCJX;%@Q\9pVKRp%SI$]M;Q\9pgP`YqFs8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8V`bq<726i8j(Sgtp`>hTO-fbKS5L`Pod7`Oidr]=bhq`PoI%]t:qj +]=bhh]Y1\ZZtN6,BMV3TFE!S*MO09ZVhBGaN/EsTJX;%@Q]-fgKRoJCJX;%@Q\9pfKRB,FMO09Z +W/QItN/FQmL6mjVW/QItN/FQmL8^>uW0EC3PEVr0OJnD*W0ECBP`Vi4Q)Kq/W1'!MP`Vi4Q+<?J +W1'!MR['h?Q)L.:W1'!^RZsb>Q)L.:W1'!MR['h9OQP?Rs8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s6T@Mkj7crjQG4OhTO-f`5T^-]Y1\Z['[3IX/rG1['[3I['[3I['[39V5.a/>%_)D +BMV34>ZuDW<+fH>W/QJ0P`Vi.OJnD*W0ECBP`WGEPc0h.W1'!MP`WGEPc1%9W0ECBR['h9OJnV5 +\XJb]R['h9OL^gEW0ECBR[)glkPtS^s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,coC_JAp#tc2 +i8j(SgtpK/f$`(!bKS53XK>uCAQ;/b<CK2R76spB5ug?><CK2R76spB5ug?><CK2R76u-.@$l=a +L4"?&I!_6.FbY9jR!a%DI!(d/JXM^ci8j(Sgtp5uc,@T?]=bha['ZX*Unji_Unsl_V50o`Uj$p& +=A27c76tT_8QA2FBMV3"76tT_8QA2FBMV35:J#2(>*jnnR!a%DI!(d/JVJQ!Q\9pWI!(6uKU7@C +R!a%CKRoJCJX;%@Q\9pVKRoJCJX;%@Q]-fgKRoJKMTa5gi8j(Sgtp5uc,@T?]=bha['ZX*Un"$H +S=Z7@St)=BS=,S)B3\V?76spB5ug?><CK2R76spB5ug?><CK2R76spB5ug?><CK2s;G)^dE0u#q +LNIL&I!(0kH\Z]^L4"?8I!(0kH^K2'R!a%2I!^TqH\QopR!a%4KS5_?FdIc4R!a%CN/HcQh#IES +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,kpA+(Hp#tc2 +k1naHI!^'J@!?-hG@Y**A70Ul?tW_JG@Y*,>?#fW@!?-hG@Y*,>?#fW@!?-hG@Y**A70Ul@!?-h +G@Y**A70Ul@!?-hG@Y**A70Ul?t`>-=A27f9Lr8Z86APV=A27c76spB6!-fO<CK2R76spB6!-fO +<CK2R76spB6$IEm]=biWs8W-!s8W-!s8W-!s8W-!s5;u$W1&uqA7110B6S3.GAV,>A7110B6S3. +G@Y**D/4?4CPQb>GAV,ND.e'0CPR"NLM^[ZFE!"WE//OSLNIKjFE!"WE//OSLNIKjFE!"WE-HDG +LNIKZD/4?+?t`>-=A27f9Lrhm8Q\YW=A27f9Lr8Z86APV=A28m[']l5s8W-!s8W-!s8W-!s7H$\ +kj7crjQGI^kL.l2bKS4cI!^WcB6RloLM^[ZD.e'0CPQb>LM^[JD/4oKE//:CLNIKjD.eWGE/&ae +LNIKiI!_6.FbY9jL4"?(KS5\FJX;%@Q\9pGKS5_?Fbb'XB3\VaA70%T>'FLbB3\VQ>ZtcF>%_)D +H!=6\>ZtcF>*k2*`5T^qs8W-!s8W-!s8W-!s8W-!s7H$\m.9ni]XjGgMMQq=R!a%4KS5\FJVJQ! +Q\9pEI!_35JX;%@Q\9pVKRoJCJX;=QQ]-fgN/FQmL6mjVQ]-g#N/![XMOBZlW/QItN/FQmL6mjV +G@Y)o>Zu>^?tW_JG@Y+RpA+ags8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W,_m-j0)n)iE\daZjHP`V5jMO0!IQ\9pVKRoJCJX;=QQ\9pVKRoJKMO0!ILkLGKI!(6uKSFl$ +R!a%2I!_6.FdIc4Q\9pGKS5_?FdIc4L4">]:J"Mb<Of02bKS5Sbg")F`ON%MQ\9pgN/![PJZ+N^ +Q]-fgN/FQmL6mjVW/QJ!PEVr(L6mjVW/QItN/FQmL6mjVW/QJ!PEV>lMPuJgQ]-fgN/Es\MMH:m +BMV3!<)mU-8\;XKs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s7H$\o_/+=jQG4OhU9p)bKS5Sbg"eabJ_B=`5T^=bg")F`Pfa7\?2ctKRoJCJX;=Q +Q\9pVKRoJCJX;=QQ\9pVKRp(\L6mREQ\9pVKRoJCJXCh-Q\9pVKRoM<FdIc4Q\9pVKRoJCJV\u4 +R!a%CKRoJCJXCh-LkLGKI!(d/JX;%@Q\9pVKRoJCJ_82is8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W,kpA*q=n)iE\g"bH4eCMgec,@T?`5T^6`Pod7`Oidr`k8mp]Y28&`OidrS=Z6Q9Lrhm8Q\YW +LNIL5KRB,FMO0!IW/QItN/FNdI$]M;R!a%CKRoJCJX;=QQ]-g#N/"9iL7+6hW/QJ!PEVr(L7+6h +W/QJ!PEVr0OJnD*W1'!MR['h?Q)L.:W1'!MR['h?Q+<?JW1'!MR['h9OL^gEW1'!^RZsb>Q)L.: +W1'!MR['h9OL^gEW1'!MR[*$jh#IESs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8VHWp#+oo +g"bH-bg">Tc+CX%]=bha['[3I['[3I['[3@XKAk:['[3IL4">]:J#2(>%_)DB3\VQ>Zuo)E2]"_ +W0ECBP`Vi.OJnV5W1'!MP`Vi4Q)Kq/W0ECBP`Vi.OJnD*\XJb]P`Vi4Q)Kq/W1'!MP`Vi.OJnD* +W0ECleCO["s8W-!s8W-!s8W-!s8W-!s8W,coC_JAp$D;Ci8j(ZjQG4OhU9p)bKS53XK?5RDHKS' +<CK2R76spB5ug?><CK2R76sC+4B4g9<CK2R76tT_8V_.qR!a%2I!_6.FbY9jL4"?&I!^TqH\Qop +L4"?&I!`fN`S'&'daZjd`PoI%]sP/RUnsl_V50o`Unji_UnslBFDt5K6!-fO<CK2R76spB5ug?> +<CK2e:J"PT6!-fOB3\W,KRoJCJVJQ!R!a%2I!_35JVJQ!R!a%2I!_6.Fbk^(R!a%4KS5\FJX;%@ +Q\9pVN/EsTJX;=QQ]-gFbg#),kLnYIdaZjd`PoI%]sP/RX/rFnSt)=BS=H1@S=Z7LR[%Mj>#e!W +<CK2R76spB5ug?>HoaAi76spB5ug?><CK2R76spB6"aG+L4"?'FE!"WE//OSL4"?'FE!"WE/&ae +LNIKiI!^WjE/&aeR!a%2I!_6.FbY9jQ\9pVKRoJCJX;=Qg"bHas8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!o_/+Em-ilnkI@XoG@Y**A70%T>'X=O +B3\VaA70[e<+BHMG@Y)o>Zu>^?t3_YG@Y**A70Ul@!?-hG@Y**A70Ul@!?-hG@Y**A70Ul@!?-h +G@Y**A70%T>$+Hh<CK2R76spB5ug?><CK2R76t$L86&)E<CK2R76spB6!-fO779RE76spB6"j%c +R?NiXbg#MGp#tc2['[2qFDuG7@!?I'G@Y**D/4?+@!?I'G@Y**A70UuCNjW2LM^[JD/4oDB6SH> +LNIKjFDuGGFGFsWGB@q^FE!"WE/&aeLNIKZFEE:[E-HDGLNIKjD.e'7FGFsWG@Y)`9Lr8Z86APV +=A28!:J"Y^88(dj=A28!:J"Y^8@uOJs8W-!s8W-!s8W-!s8W,kpA+@Sq<726k1nbFgtpK/f!qi^ +LM^[JD/4oDB6S3.LM^[JD/4oDB6S3.LM^[JD/4oKE-HDGLM^[ZFE!"WE/&aeLNIKiI!_6.FdRQ! +LkLGKI!(d/JX;%@Q\9pVKRnr4KSODWB3\Vc>?#6?>'X=OB3\VaA70%T>'X=OB3\VQ>ZtcF>'FLb +LkLGkXfB=Y`S'&'daZjd`Pnd7L5:M9L4"?8I!(0kH^BD:L4"?7KRoJCJX;%@LkLGKI!(6uKU7@C +Q]-fgN/FQmL6mjVQ]-g#P`V5jMO09ZW/QItN/Es\MO09ZW/QIcI!^'J?tW_JG@Y)o>["MA[/^1+ +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8VHWp#tc2i8j(Sgtnj'Uo96, +Q]-fgN/EsTJX;=QQ\9pVKRoJKMO0!IQ\9pVKRoJCJV\u4R!a%2I!^TqH^BD:LkLGJKRoJCJX;%@ +LkLG9I!]L2>%g]'Q\9q<eCMgec-+>UbKS5Sbg!)TQ'[/TQ]-fgKRoJKMPuJgQ]-fgN/FQmL6mjV +W0EC3PEV>lMPuc$R?Ni5N/!aaPF%5cW/QItN/Es\MO09ZQ\9pVKRn>aCM6L8=A27b<)r)9h#IES +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8VHWp#tc2 +i8j(SgtpK/f#u:^`5T^=bg")F`Pfa7bKS5L`Pod7`Ku7/Q\9pWI!(d/JX;=QQ\9pVKRoJCJX;%@ +Q\9pVKRoJCJV\u4L4"?8I!(0kH\QopL4"?8I!(6uKU@.0LkLGKI!(0kH\QopL4"?&I!_6.FbY9j +L4"?&I!_35JV\u4Q\9qis8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s7H$\m.9o6m-iW_hV$]@ +daZjkbg")F`Pfa7]=bhh]Y1qi]t:qj`k8mp]Y0&IHWWs4=A27f9Lsq\E0lN@Q\9pgN/![XMO0!I +Q\9pVKRoJCJX;%@Q]-g#N/![XMPuJgR?Ni5N/!aaPGjFpR?Ni5P`V;sPGj_-W0EC3PEVr0OJnV5 +W0ECBR['h?Q)L.:W1'!MR['h9OJnV5W1'!MR['h?Q)Kq/W1'!MP`Vi4Q)L.:W1'!MR['h?Q)Kq/ +W1'"0jQHRCs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!m.9o6m-ilnkL.l2bKS5L`PoI%]sP/R +['[3I['[3I['[3I['[3I['ZX*Uh<q9B3\VR:J#2(>%g]'B3\W=P`Vi.OJnD*W0ECBP`Vi4Q)L.: +W1'!MP`Vi4Q)Kq/W0ECBR['h9OJnD*W0ECBR['h9OJnD*W0ECBP`Vi.OJnD*`k8nTpA+ags8W-! +o_/+IoC_JAp#tc2i8j(ZjQG4OhU9p)['[3!Mi;:R>"(hJ=A27c76spB5ug?><CK2R76spB5ug?> +<CK2R76spB6$Z[6L4"?&I!^TqH\QopLNIKiI!_6.FbY9jR!a%2I!_6.FbY9jUnsm?gtp5uc,@T? +]=bha['ZX*Unji_Unsl_V50o`Uj$p&=A27f9Lr8Z86APV=A28!:J"PT5ug?><CK2e:J#2(>*s\[ +L4"?&I!_6.FbY9jL4"?8I!(0kH\d?.R!a%2I!^TqH^BD:LkLGJKRoJCJX;%@Q\9pVKRoJCJ]l9^ +i8j(LeCN'tf#5PH]=bha['ZX*Un"$HS=Z7@St)=BS=H1@B3\V04Zl_55t4""<CK2C4Zl_55ug?> +<CK2R76spB5ug?><CK2s;G)[kH^K2'LNIKiI!^WjE//OSL4"?'FE!"WE/&aeLNIKjFDut^H\Qop +Q\9pEI!_35JX;%@Q]-fgN/HcQh#IESs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8V`bq<[_Gkj7ckgtm6sFE_8'B3\VaA70%T>'FLbB3\VQ>Zu>^?tW_J +G@Y**A70Ul@!?-hB3\VaA70%T>'X=O@q9.pA70Ul@!?-hGAV,>A70UuCNjW2G@Y**A70%T>$+Hh +=A27c76t$L86&)E<CK2R76spB5t+11<CK2B6q(*E5ug?>779RE76s@179E5SGAV,MI!^WjE-Gi# +GAV,>A70UuCNj;sLM^[JD/4?4CNjW2G@Y*:D.e'0CNjW2GAV,>D/4oDB6SH>LNIKjFE!"WE-HDG +LNIKjFDut^H\QopLNIKiI!^WjE-HDGLNIKjFDuG7?s$)n=A27f9Lrhm8Q\YW<)ck2:J"Y^85rPg +BMV4,[']l5s8W-!s8W-!s8W-!s8W-!o_/+Em-ilnkMYFadaZjkbftliH\Z]^LNIKjD.e'7FGF^G +GAV,NFDuG@CPR"NGB@q^FE!"WE//OSLNIKiI!^TqH^K2'LkLG;KS5_?Fbk^(N/NX]KRo)?N0f3K +Q\9pVKRo)?N/)LoG@Y)kA7]CY>%_)DB3\VQ>ZtcF>%_)DB3\VQ>ZtcF>%_)D@q9/+D.eTNH^BD: +L4"?(KS5_?Fbk^(L4"?(KS5_?Fbk^(Q\9pGKS5\FJV\u4Q\9pVKRoJCJX;=QQ]-g#N/![XMO09Z +Q]-fgN/Es\MPuJgQ]-fiPEV>dJTkX4G@Y)o>ZtcF>).3=s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s7H$\kj7crjQG4OhRK\fQ\9pVN/FNdI$]eLQ]-fgKRoJKMO0!I +Q]-fgKRoJKMO0!IQ\9pGKS5\FJVJQ!Q\9pGKS5\FJX;%@Q\9pGKS5_?Fa%A(=A280D/7>=c-+>U +bKS5Sbg">Tc-+>U`5T]^KRoJCJX;=QQ\9pVN/Es\MO09ZQ]-fgN/Es\MO09ZQ]-fgN/Es\MO09Z +Q]-fgN/Es\MO09ZQ]-fgKRoJCJX;%@L4">\>Zt6'86APVB3\X?s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!o_/+QpA*Y-kLnYIdaZk#bfe2Rc,@T? +bKS5L`Pod7`Pfa7`5T]kV5/inH^BD:LkLGJKRoJCJX;%@Q]-fgKRoJKMO0!IQ\9pEI!_35JVJQ! +L4"?8I!(0kH\QopR!a%2I!^TqH\QopL4"?&I!^TqH\QopL4"?&I!^TqH\QopL4"?&I!`lG])Vg1 +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8V`bq<726i8j(SgtpK/f#u:^`5T^6`PoI%]t:qj +`5T^-]Y1qi]t:qjB3\VB9Lr8Z88(djL4"?7KRoJKMO09ZQ]-g#N/![XMO09ZQ]-fgN/EsTJX;=Q +W/QItN/FQuOI(o`W0EC3PEVr0OI;;rW0ECBP`V;sPGj_-W1'!MP`Vi4Q)Kq/W1'!MP`Vi4Q)Kq/ +W1'!MR['h?Q)L.:W0ECBR['h?Q)L.:W1'!MR['h?Q)L.:W1'!MR['h?Q)L.:o_/+\s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8V`bq<[_Gi8j(Sgtp5uc,@T?]=bhh]Y1\Z['[3IX/rG1['[3I[&^:1 +['[2pI!]L2>%_)DBMV34>ZtcF>).3=R?Ni&PEVr0OJnD*W1'!MR['h9OJnV5W0ECBR['h9OJnV5 +W0ECBR['h9OJnD*W1'!MP`Vi4Q'mi"W0EC1N/F$ePIR`pi8j(foC_JAp#tc2i8j(LeCM7E]pt[a +H[C0C>[CE!5t+11<CK2U9Lr/P6!-fO<CK2U9Lr/P6!-fO<CK2R76t$L89nE=LNIKiI!^TqH\Qop +L4"?'FDut^H\QopLNIKiI!^WjE/&aeLNIKiI!^[&KZhTadaZjd`PoI%]rS6:X/rG!V50o`Unji_ +UnslBFDt>U86&)E<CK2U9Lr/P6!-fO=A27f9Lr8Z86APVB3\W,KRnr4KU7@CL4"?7KRnl*H\d?. +R!a%2I!^TqH^K2'LkLGJKRoJCJX;%@Q]-fgN/ERPN0f3KQ]-g?`PpcrkLnYIdaZjd`PoI%]sP/R +Unsl_V50WQS=H1@S=Z7@St'Ii8Obj*7Qik676sC+4B4g9<CK2C4Zl1s4B4g9<CK2R76spB6"j%c +L4"?&I!^TqH^AhiL4"?&I!^WjE//OSLNIKjFE!"WE/&aeLNIKiI!_6.Fbk^(Q\9pVKRoJCJX;=Q +g"bHas8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +o_/+IoC_>6n)39i\?2cD>Zu>^?t3_YG@Y)o>Zu>^?t3_YG@Y)o>Zu>^?t3_YG@Y)kA7]sq?t3_Y +G@Y)kA7]sq@!?-h@q9.pA7/nXATqZmC2@d3A7/nXATqZmG@Y**A70%T>$+Hh=A27S6q(*E5t+11 +<CK2R76spB5ug?><CK2R76t$L87u12G@Y*:FDuGGFGFsWGAV,>FEE:TB6S3.GAV,>D/4?+@!?I' +LM^[JD/4?4CNjW2LM^[JD/4oKE-H/7GB@q^FDuGGFGFsWGB@q^FDuGGFGFsWH[C0rFDut^H\Z]^ +L4"?&I!^WjE-lq[GAV+t9Lrhm8Q8Yh=A28!:J"Mb<EMpcB3\VB9Lr,^<Q;\_s8W-!s8W-!s8W-! +s8W-!s8V`bq<[_Gkj7ckgtp`>hU9p)['[2aD/4oKE-HDGLNIKjFDuGGFGF^GGB@q^FE!"WE//OS +H[C0qI!^TqH\Z]^L4"?&I!^TqH^K2'LkLG;KS5_?FdIc4Q\9pVN/EsTJX;%@Q\9pVN/EsTJV\u4 +LNIKZD/4?+?tW_JG@Y)o>Zu>^@!?I'LNIKiI!_35JV\u4Q\9pEI!_35JV\u4L4"?&I!_6.FbY9j +LkLG9I!^[&KU@.0LkLGJKRo)?N/3.?Q]-fgN/Es\MO09ZQ]-fgN/Es\MO09ZQ]-fgN/Es\MO09Z +LNIKJ>ZtcF>%_)DB3\WgeCO["s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +o_/+Em-ilnkN:RT`k8mLN/Es\MO09ZQ\9pVN/EsTJX;=QQ\9pVN/EsTJX;%@LkLGJKRnr4KSY;7 +R!a%4KS5_?Fbk^(Q\9pGKS5\FJX;%@GAV+t9Lrhm8\;XKdaZjreCN'tf#u:^bKS5Sbg">Tc+'mU +LkLGJKRoJCJX;%@Q]-fgN/Es\MO09ZQ]-fgN/Es\MO09ZQ]-fgN/Es\MO09ZQ]-fgN/EsTJX;=Q +LkLGJKRnr4KSOYg=A27c76t$L89]/ts8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s6T@Mkj7crjQG4OhU9p)bKS5Sbg")F`Pfa7bKS5L`Pp$Ec,RE- +Q]-fXKS5\FJX;%@Q]-fgN/EsTJW,MGQ]-fgKRnr4KU7@CLkLG9I!^[&KSFl$L4"?(KS5)-H\d?. +R!a%2I!^TqH\Z]^LNIKjFE!"WE/&aeLNIKiI!^TqH^K2's8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W,coC_>6n(HLQg"bH-bg">Tc,@T?`k8mp]Y1qi]t:qj]=bhQV5.*[5ug?> +=A28!:J$n3MO0!IQ]-fgKRoJKMO09ZQ]-fgN/EsTJX;=QQ]-fgN/Es\MOBZlQ]-g#P`V5jMPuc$ +Q]-g#P`V;sPF7VuW0EC3PEVr0OIVo4W0EC6St)aDOJnV5W0ECBR['h?Q)Kq/W1'!MR['h?Q)L.: +W1'!MR['h?Q)Kq/W1'!MR['h?Q)L.:W1'!MP`V];V#UJps8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W,coC_&&kLnYIdaZjkbg")F`Oidr['[3I['[3I['[3IX/rG1['[3I[%sOoB3\VB9Lrf$>#\I$ +B3\VQ>[!JQMPuc$R?Ni5R['h9OJnV5W0ECBR[';)PGj_-R?Ni5R[';)PGjq8R?Ni5R['D7S>_[6 +R?Ni5P`V;sPGj_-Q]-fgN/FR&Q(4G9LkLG*FED86DHKS'=A27f9Lr8Z86&)E=A27c76spB5t+11 +<CK2R76s@179)cB<CK2U9Lrf$>'FLbL4"?&I!^[&KU@.0L4"?'FE!"WE/&aeLNIKjFDut^H\Z]^ +LNIKiI!^WjE/&aeQ\9pjXKBq#f#5PH]=bha['ZX*Unji_Unsl_V50o`Uj$p&=A27f9Lr8Z86&)E +=A27c76spB5ug?>=A27c76tQk>*jnnL4"?7KRnr4KSFl$Q\9pEI!^[&KU7@CL4"?(KS5\FJW,MG +Q\9pKMi=!]MO0!IQ\9pKMi=!UJ]l9^i8j(Sgtp5uc,@T?]=bha['ZX*Un"$HS=Z7@St)44PFS57 +<)cje4Zl1s4@VIr7Qik'4Zl1s4B4g97Qik676sC+4B4g9<CK2e:J$:gH\QopLNIKiI!^TqH\Z]^ +L4"?&I!^TqH\QopLNIKiI!^TqH\QopLkLG9I!_35JX;%@Q]-fgKRr(BkPtS^s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s7H$\m.9o.jQG4OhKsTt +G@Y**A7/nXATqZmB3\VaA70%T>'FLb@q9.r>?#*CAS57OG@Y)o>ZtcF>'FLbB3\VaA7/nXATqZm +@q9.pA7/nXATqZmG@Y**A7/nXATr!,B3\VaA70%T>%_)DB3\VR:J"Mb<G50"<)ck">[D&J>'FLb +GAV,>FED_KFG>0iLNIKZFEE:[E//:CGAV,>D/4?4CNjW2GAV,NFDuG@CNjlBLM^[JD/4?4CNjW2 +GAV,>D/4?4CNjW2LNIKZFED_KFGFsWH[C0rFDuGGFG>0iL4"?&I!^TqH\QopL4"?&I!^'SCM6L8 +<)ck2:J"Mb<G50"<)ck2:J"Mb<G50"<)cl0]Y4@Fs8W-!s8W-!s8W-!s8W-!s8W,kpA*q=n*'-, +g"bH4eCN9rbEn0FGAV,NFDuGGFGFsWGB@q^FDuGGFGFsWGB@q]I!^TqH\QopL4"?(KS5)-H\d?. +R!a%4KS5/7KU@.0LkLG?Mi=!UJW,MGQ\9pKMi<IFKT(hJQ\9pVKRnr4KU7@CLkLGJKRnr4KSY;7 +Q\9pEI!^TqH\d?.R!a%4KS5)-H^BD:LkLG;KS5\FJV\u4L4"?&I!^TqH\QopL4"?(KS5/7KSY;7 +LkLGJKRnr4KU7@CQ]-fgN/Es\MO09ZQ]-fgN/Es\MO09ZQ]-fgKRmWDAS57OB3\VQ>["(pQ2gma +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,kpA*q=n*'-,g"bH-bfuQ>PF%5c +Q\9pVN/Es\MO0!IQ]-fgN/EsTJX;%@Q]-fgKRoJKMO0!IQ\9pGKS5\FJV\u4Q\9pGKS5\FJVJQ! +LkLG9I!]O&8Q\YWS=Z8(gtp`>hU9p)daZk#bfe2Rc-+>UbKS5L`PndEQ&(*HLkLG;KS5\FJX;=Q +Q\9pVN/Es\MO09ZQ]-fgN/Es\MO0!IQ]-fgKRoJKMMQq=Q]-fgKRnr4KU7@CLkLG9I!^'SCKO8$ +<CK2R77!H8SH&Whs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8V<Ln)39ig"bH4eCN9rbJ_B=fZ_OW`Pod7`Pfa7`5T^6`PnXLUmHacQ]-fgN/Es\MO09Z +Q]-fgN/Es\MO09ZQ]-fgKRnl*H^BD:L4"?7KRnl*H\QopL4"?&I!^TqH\QopL4">pH[UZkE-lq[ +GB@q^FDuGGFGFsWLNILFXfDF$s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s6T@M +kj7crjQFt@f$`(!bKS5L`PoI%]t:qj`5T^-]Y2=t\ql#m<CK2B6q(*E6"=G:L4"?(KS5\FJX;%@ +Q]-fgN/Es\MO09ZQ]-fgN/Es\MO09ZQ]-fgN/FQuOI;;rR?Ni&PEVDuPF%5cW0EC3PEVr0OI;;r +Q]-fiPEVN.S>_[6W0EC6St)aDOIVo4W1'!>PEVr6Q'mi"W1'!>PEVr6Q'mi"W1'!MR[';)PGjq8 +W1'!>PEVr6Q)L.:W0ECRXfDF$s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s6T@Mkj7crjQG4OhTO-f +`5T^-]Y1\Z['[3IX/rG1['[3I['[3I['[3@XK@G>N+c!Y<)ck2:J"Y^87u12LNIL%N/Es\MOBZl +R?Ni&PEVDuPF7VuR?Ni&PEVDuPF7VuW0EC3PEVr6Q'mi"W0EC6St)aJQ)Kq/R?Ni&PEVDuPF%5c +R?Ni$N/Es\MM?M*G@Y)o>Zt6'86APV=A27f9Lr8Z86APV=A27f9Lr8Z86&)EB3\VQ>Zu>gCPR"N +L4"?&I!^[&KSFl$L4"?&I!^TqH\QopL4"?'FDut^H\Z]^L4"?'FDut^H\Z]^L4"?&I!^[&KT(hJ +bKS5L`PoI%]sP/RX/rG!V50o`Unji_Unsl2FECVY86&)E=A27f9Lr8Z86APV=A27c76t$L86APV +B3\W,KRnr4KSFl$Q\9pVKRnr4KU7@CQ\9pGKS5\FJV\u4N/NX]KRoJKMO09ZQ]-fgN/EsTJW,MG +LkLH"`PpcrkLnYIdaZjd`PoI%]sP/RX/rFnSt)=BS=H1@S=Z7LR[%Mj>"1Y;7Qik'4Zl1s4@VIr +7Qik'4Zl1s4@VIr7Qik'4Zl1s4B,9[LNIKZFEE:[E-HDGLNIKjFDut^H\Z]^LNIKjFDut^H\Qop +L4"?(KS5_?FbY9jLkLG;KS5/7KU7XTg"bHas8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,kpA+(Hp#tc2i8j(.['X=RATqZm@q9.pA7/nXAS57O +B3\VQ>ZtcF>%_)DB3\VQ>ZtcF>%_)DB3\VQ>ZtcF>%;)SG@Y)o>Zu>^?tW_JG@Y)kA7]CY>%;)S +G@Y)o>Zu>gCM-mUGAV,.>Zu>^?tsLqG@Y)rCi4H-@!?I'GAV,>D/4?;FGFsWGB@q^FDuSRI>3,r +GB@qNFED_KFGF^GGB@qND/4oKE-HDGGB@q^FDuG@CNjW2GAV,>D/4?4CPR"NGAV,>FED_DCPR"N +GB@qNFED_KFGFsWL4"?&I!^'ZFG>0iL4"?&I!^WjE/&aeGAV+p<)mU-8Q]5(BMV3!<)mU-8Q]5( +BMV3!<)mU-8\;XKs8W-!s8W-!s8W-!s8W-!s8W-!s7H$\m.9o.jQGI^kLnYIdaZj[]Y0)BE-HDG +LNIKZFEE:[E-HDGLNIKZFEE7bH\Z]^H[C0qI!^TqH\QopR!a%4KS5/7KSY;7R!a%4KS5/7KU7@C +LkLGJKRo)?N0f3KLkLGJKRnr4KSY;7LkLGJKRnr4KSY;7LkLG;KS5)-H\d?.L4"?(KS5)-H\d?. +Q\9pGKS5)-H\d?.L4"?&I!^TqH\QopL4"?&I!^TqH^BD:LkLGJKRnr4KSY;7Q\9pVN/Es\MO09Z +Q]-fgN/Es\MO09ZQ]-fgN/Es\MK`oQB3\VQ>ZtcF>'kUEs8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8V`bq<[_Gi8j(ZjQFt@eu4gpQ]-fgKRoJCJX;=QQ]-fgN/Es\MO09Z +Q\9pKMi=!UJW,MGQ\9pGKS5\FJV\u4Q\9pGKS5\FJV\u4LkLG9I!^TqHY6Se=A284H[Xi5kMYFa +g"bH;gtpK/f$`(!bKS5Sbg">Tc-+>U`5T]^N/EFEKSY;7Q\9pKMi=!]MO09ZQ]-fgN/Es\MO09Z +Q]-fgN/EFEKU7@CN/NX]KRoJKMMQq=LkLG;KS5/7KSFl$L4">\>Zt6'84>p8<CK3l`PqlWs8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!m.9o6m-iW_hV$]@ +daZjkbg")F`Pfa7fZ_OW`Pp$Ec,@T?`k8mLN/EFEKU7XTQ]-f\Mi=!]MO09ZQ]-fgN/ERPN/3.? +LkLG9I!^TqH\QopL4"?&I!^TqH\Z]^H[C0qI!^WjE/&aeGB@q^FDuGGFGFsWGB@q^FDuGGFT;C@ +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,kpA+(Hp#+oog"bH4eCMRW`Pfa7 +`5T^-]Y1qi]u7n/]=bgeA7\4n4B4g9<CK2tD/4r\KSFl$Q\9pGKS5\FJX;%@Q]-fgN/Es\MPuJg +Q]-fgN/Es\MPuJgR?Ni$N/FQmL7+6hW0EC3PEVr0OI;;rR?Ni&PEVr0OI;;rW0EC3PEVN.S>_[6 +R?Ni5P`V;sPGjq8S=Z7LR['h?Q'mi"W1'!MR[';)PGjq8W1'!>PEVr6Q'mi"W1'!>PEVr6Q(4G9 +`5T^qs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8VHWp#+oog"bH4eCMgec,@T?]=bha['[3I['[3I +X/rG1['[3I['[3IX/rF<Ci3o^8Q]5(BMV3!<)mR9>)7ibR?Ni$N/Es\MOBZlW0EC3PEVDuPGj_- +R?Ni&PEVDuPF7VuR?Ni5R[';)PGjq8R?Ni&PEVDuPGj_-Q]-fiPEV>lMOBZlQ]-fgN/Es\MO09Z +LkLG9I!^'SCMI['@q9.pA70.gDKfr5GB@q]I!^TqH\QopL4"?&I!^TqH\QopL4"?&I!^TqH\Qop +L4"?'FDut^H\Z]^GB@q^FDuGGFG>0iGB@q]I!^TqH\d?.L4"?7KRpM;[)Br&]=bha['ZX*Unji_ +Unsl_V50o`Uj$p&=A27f9Lr8Z86APV8k_r]9Lr8Z86APV=A27c76tQk>)7ibL4"?7KRnr4KU7@C +Q]-f\Mi<IFKU7@CLkLGJKRoJCJW,MGQ]-fgN/Es\MN!IPN/NXNKS5/7KZ(jKi8j(SgtpK/f#5PH +]=bha['ZX*Un"$HS=Z7@St)=BS=H1@<)cje4Zl1s4B4g97Qik'4Zl1s4@VIr7Qik'4Zl1s4@VIr +7QikI:J#bPFGFsWGB@q^FDuGGFE_hKLNIKZFEE7bH\QopH[C0qI!^TqH\QopLkLG9I!_35JV\u4 +LkLGJKRqh3hZ*WUs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!o_/+Em-j0)n)39iN/NX=A7/nXAS57OB3\VQ>ZtWJAS57OB3\VQ>ZtcF>%;)S +B3\VQ>ZtcF>%;)SG@Y)kA7]CY>%_)D@q9.\A7]CY>%_)DB3\VQ>ZtcF>%;)SB3\VMA7]7]ATqZm +@q9.pA7/nXATqZmC2@d3A70UuCNjW2GAV,>FED_KFF/@_LNIK^H[UZkE-HDGLNIKZFED_KFE_hK +GB@qND/4?4CNjlBGAV,>D/4?4CNjlBGAV,>D/4?;FE_hKGAV,>FED_DCNjW2LNIKZFED_KFGFsW +L4"?&I!^TqH\QopL4">pH[U*TCM6L8<)cjs<)mU-8Q8Yh<)ck2:J"Yn?>*,+<)cl0]Y4@Fs8W-! +s8W-!s8W-!s8W-!s8W-!s8VHWp%Rh9i8j(Sgtp`>hU9p)Unsl2D/4?;FE_hKLNIKZD/4?;FG>0i +LNIK^H[UWrH\Z]^L4"?&I!^TqH\QopL4"?&I!^[&KSY;7LkLG;KS5\FJV\u4LkLG;KS5/7KSY;7 +LkLG;KS5/7KSY;7LkLG;KS5\FJVJQ!LkLG;KS5\FJVJQ!LkLG;KS5)-H\d?.L4"?(KS5)-H\Qop +L4"?&I!^TqH\QopL4"?&I!^TqH\d?.R!a%4KS5/7KT(hJLkLGJN/ERPN0f3KQ]-fgN/EsTJX;=Q +LNIKJ>ZtcF>%_)D@q907m-juSs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +kj7d%m-j0)n']_:UnslRN/Es\MN!IPQ\9pVN/Es\MO0!IQ]-fgKRo)?N0fK\Q\9pGKS5\NMMQq= +Q\9pGKS5\FJV\u4LkLGJKRnl*H\QopGAV+t9Lrf$>1q]fkj7d%m-ilnkN:RTg"bH4eCMgec.L7` +bKS5Sbg">Tc*XjbQ\9pGKS5/7KU7XTQ]-fgN/Es\MO09ZQ]-fgN/Es\MO0!IN/NX]N/EFEKT(hJ +Q\9pGKS5/7KU@.0LkLG9I!^TqHZsRRB3\VB9Lr/P5u^f`kj7d<s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8V`bq<726i8j(SgtpK/f#u:^bKS5Sbg")F`Pfa7 +`5T^6`Pod7`MB?+Q\9pKMi=!]MO09ZN/NX]N/ERPN/W[RQ\9pGKS5)-H\QopL4"?&I!^TqHZsRR +L4">pH[UZkE/&aeGB@q^FDuGGFE_hKGB@qNFEE:[E-HDGS=Z8Ns8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!kj7d%m-iW_hU9p)bKS5L`Poj0]#;S,`5T^6`Po3kZrKO\ +7Qik'4Zl_56&'c6L4"?(KS5/7KU7@CN/NX]KRoJKMO09ZQ]-fgN/Es\MOBZlQ]-fiPEV>lMOBZl +R?Ni5R[';)PGjq8R?Ni&PEVr0OI;;rR?Ni&PEVDuPGjq8R?Ni5R[';)PFS57W1'!>PEVr6Q'mi" +R?Ni5R[';)PGj_-R?Ni&PEVDuPGjq8R?Ni5R[';)PGjq8R?Ni&PEVr0OQc'"s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!m.9o:oC_&&kL.l2bKS5L`PoI%]sP/R['[3I['[3I['[3I['[3@XKB"7WgoZN +B3\V><)lms<G50"<)ckAD/5JsMPuc$Q]-fiPEVDuPF7VuR?Ni&PEVDuPF7VuR?Ni&PEVDuPF7Vu +R?Ni&PEVr0OI;;rR?Ni$N/F$ePF%5cQ]-fgN/Es\MO09ZN/NXRMi=!]MN!IPQ\9pGKS5\FJV\u4 +LkLGJKRnr4KSY;7L4"?(KS5)-H\QopL4"?&I!^TqH\QopL4"?&I!^TqH\QopL4"?&I!^TqHZsRR +GB@q]I!^TqH\QopL4"?&I!^[&KT(hJS=Z7h`PoI%]sP/RUnsl_V50o`Unji_Unsl2FECVY86APV +8k_r]9Lr8Z86APV=A27S6q(3O86APVB3\W,KRnr4KU7@CLkLG;KS5/7KSY;7Q\9pGKS5/7KSY;7 +N/NX]N/Es\MN!IPQ]-fgN/Es\MMQq=LkLH"`PpcrkLnYIdaZjd`PoI%]sP/RUnsl_V50WQS=H1@ +S=Z7@St'Ii8Obj*7Qik'4Zl1s4@VIr7Qik'4Zl1s4@VIr7Qik'4Zl_55u^f`LNIKZFED_DCNjlB +GB@q^FDuGGFE_hKGB@qRH[UZkE/&aeL4"?&I!^TqH\d?.L4"?(KS5/7KSY;7g"bHas8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s7H$\ +kj7crjQF_1c!t9qB3\VQ>ZtcF>%_)DB3\VQ>ZtcF>%_)DB3\VQ>ZtWJAS57OB3\VQ>ZtcF>%_)D +B3\VMA7]sq?tW_JB3\VMA7]sq?tW_J@q9.pA70%T>'FLbB3\VTCi3`nATr!,G@Y)rCi4H6CMI[' +GAV,>D/4?;FE_hKLNIKZFED_KFGFsWGB@qNFED_KFE_hKLNIKZD/4?;FE_S;GB@qND/4?4CNjW2 +GB@qND/4?4CNjlBGAV,NFDuGGFE_S;GAV,>FED_DCNjlBGB@qNFEE7bHZsRRL4"?&I!^TqH\Qop +GAV+p<)mU-8S;:3<)ck1>Ztf:8Q]5(=A27f>[D)>8\;XKs8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W,coC_>6n)39ig"bH4eCN9rbD:h)GB@qND/4?;FE_hKLNIKZFED_KFG>0iGB@q]I!^3eI>;o` +L4"?&I!^TqH\QopL4"?(KS5)-H\d?.LkLG;KS5/7KSY;7L4"?(KS5)-H^BD:L4"?(KS5)-H\d?. +LkLG;KS5)-H\d?.L4"?&I!^TqH\QopL4"?&I!^[&KSFl$L4"?(KS5/7KSFl$L4"?&I!^[&KSFl$ +LkLG;KS5)-H\d?.LkLGJKRoJKMMQq=Q]-f\Mi<UQN0fK\N/NXLI!]L2>%_)DB3\VQ>[#S*f)PdM +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,kpA*q=n)39ig"bGoXf@_HMO09Z +Q]-fgN/Es\MO09ZQ]-fgN/ERPN0fK\Q\9pKMi<UQN0f3KN/NX]N/ERPN0f3KN/NX]KRnr4KSFl$ +LkLG:FDt>U85rPg]=biLpA*q=n*'-,kj7crjQG4OhV$]@daZjreCMgec-+>UbKS5Sbfur[Ukj\W +LkLG;KS5\NMN!IPQ]-fgN/Es\MO09ZN/NX]N/ERPN0f3KN/NXNKS5/7KSY;7LkLG;KS5)-H\d?. +L4"?&I!^'ZFBD4-=A27c76tEoAcMf1s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W,coC_>6n(HLQdaZjreCMgec,@T?`5T^=bg")F`Pfa7`5T^-]Y0,SKT(hJ +Q]-f\Mi=!]MN!IPQ]-fXKS5/7KSY;7LkLG9I!^TqH[C*fL4"?&I!^TqHZsRRH[C0bFEE:[E-HDG +GB@q^FDuG@CNjlBGB@q^FE$I1n,NFfs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8VHWp#tc2g"bH;gtp5uc,@T?`5T^6`Pp$Ec-+>US=Z6?4Zl1s4@VIrBMV3HH[UZkE/&ae +LkLG;KS5/7KU7@CN/NX]N/Es\MO09ZR?Ni5P`V];UoUT!\?2d<['[3I[(Eua]=bhh]Y1\Z['[3I +X/rG!V51&SOJnV5R?Ni)St)44PFS57R?Ni5R[';)PF7VuR?Ni5R[';)PF7VuR?Ni&PEVDuPGj_- +R?Ni&PEVDuPF7VuR?Ni&PEVDuPF7VuR?Ni5R[*pQs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s6T@M +i8j(SgtpK/f#u:^`5T^-]Y1\Z['[3I['[3@XKAk:['[3IX/rG1['YXBKNLo==A27b<)mU-8Q]5( +LkLGJN/F$ePF7VuR?Ni$N/F$ePF%5cR?Ni$N/F$ePF7VuR?Ni&PEVDuPF7VuQ]-fiPEVDuPF%5c +Q]-fgN/ERPN0fK\N/NXRMi=!]MMQq=Q]-fXKS5;BN/3.?LkLG;KS5)-H\d?.L4"?&I!^[&KSY;7 +L4"?&I!^TqH\QopL4"?&I!^TqH\QopL4"?&I!^3eI>;o`H[C0rFDut^HZsRRL4"?&I!^TqH\d?. +LkLGJKRo)?N3ot!]=bha['Zm8Xe_ehUnsl_V50o`Uj$p&=A27X9MJV_86&)E=A27f9Lr8Z86APV +=A27f9Lrf$>)7ibLkLG9I!^[&KSY;7Q\9pGKS5\FJW,MGQ\9pKMi=!UJW,MGQ]-fgN/Es\MN!IP +Q\9pKMi<IFKZ(jKi8j(Sgtp5uc,@T?]=bha['ZX*Un"$HS=Z7@St)aJQ(4G9<)cje4Zl1s4@VIr +7Qik'4Zl1s4@VIr7Qik'4Zl_55t4""7QikI:J#bPFE_hKGB@qND/4?;FE_S;GB@qNFED_KFGFsW +GB@qRH[UZkE/&aeL4"?&I!^TqH\QopLkLG;KS8%6hZ*WUs8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,kpA+@Sq;C>si8j'sV5.a/>%_)D +B3\VB>[D&J>$,$9B3\VB>[D&J>%_)D@q9.`>ZtcF>%_)DB3\VQ>ZtcF>%_)DB3\VQ>ZtWJAS57O +@q9.`>ZtcF>%_)DB3\VMA7]7]AS57OG@Y)kA7]t%CL^mdGAV,>A70.gDKfr5GAV,>FED_KFGFsW +GB@qRH[UWrHZsRRLNIKZFED_KFGFsWGB@qNFED_DCNjW2C2@d3D/4?4CNjlBGB@qND/4?;FE_hK +GAV,>FED_KFE_S;GAV,>FED_KFGFsWGB@q]I!^TqH\QopL4"?&I!^'SCK+85B3\V><)m$o85rPg +<)ck2:J"Mb<EMpc<)cl0]Y4@Fs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s7H$\kj7crjQG[\gtCK> +daZjd`PmUSE-H/7GAV,>FEE:[E-HDGL4"?&I!^TqH\Z]^H[C0qI!^3eI>3,rH[C0qI!^TqH\d?. +L4"?(KS5)-H\d?.L4"?&I!^[&KSY;7LkLG;KS5/7KSY;7Q\9pGKS5)-H\d?.L4"?(KS5)-H\Qop +L4"?&I!^3eI>3,rL4"?&I!^TqH\QopL4"?(KS5/7KSFl$L4"?&I!^TqH\QopL4"?&I!^[&KSY;7 +LkLG?Mi=!UJV\u4Q]-fXKS5;BN-Af?=Bo0F>ZtcF>11pOs8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8V`bq<726i8j(Sgtp&`\sJA5Q]-fgN/Es\MO09ZN/NX]N/ERPN0fK\ +N/NXNKS5\NMMQq=Q]-fXKS5/7KT(hJQ\9pGKS5/7KSY;7LkLG;KS5)-HY6Se<)ckaN/IZ8s8W-! +s8W,kpA*q=n*'-,i8j(SgtpK/f$`(!bKS5Sbg">Tc-+>U`5T]^N/EFEKU7@CLkLG?Mi=!]MOBZl +N/NX]N/EFEKU7XTLkLG?Mi=!]MO0!ILkLGJKRnr4KSFl$LkLG9I!^TqH\QopL4">lD/36I86&)E +779S!I!bnns8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s7H$\ +kj7crjQG4OhU9p)bKS5Sbg")F`Pfa7bKS5L`Pod7`Pfa7S=Z7,KS5;BN1#lnQ]-fgN/EFEKU7XT +LkLG;KS5)-H\QopL4"?(KS5/7KSFl$H[C0qI!^TqHZsRRGB@qNFED_KFE_S;GB@qND/4?;FIA>V +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!m.9o6m-ilnkLnYI +daZjreCN'tf#u:^daZjreCKA%HU^.\7Qik'4Zm4bATr6<L4"?&I!^TqH\d?.LkLG;KS5\NMOBZl +X/rG8]Y28&`QQKM`5T^6`Pod7`Oidr`5T^-]Y1\Z[(Eua['[3P]Y1\Z[(Eua['[3@XK@nSPF7Vu +W0EC3PEVr6Q'mi"R?Ni&PEVDuPF7VuQ]-fgN/Es\MO09ZQ]-fgN/Es\MO09ZQ]-fgN/Es\MOBZl +R?Ni&PEVDuPF7Vu`5T^qs8W-!s8W-!s8W-!s8W-!s8W-!s8W,coC_JAp#+oodaZjkbg")F`Oidr +]=bha['[3I[&^:1['[3I['Zm8XgGIBX/rFIFECVY86APV<)ck"9Lrf$>*k2*Q]-fgN/F$ePF7Vu +R?Ni&PEVDuPF7VuR?Ni&PEV>lMOBZlQ]-fgN/F$ePF7VuQ]-f\Mi=!]MN!IPN/NXRMi=!]MN!IP +N/NX]N/ERPN0fK\N/NX]KRnr4KSY;7LkLG;KS5)-H\QopL4"?(KS5)-H[C*fL4">pH[UWrH\Qop +L4"?&I!^TqH\QopL4"?&I!^'ZFE_hKH[C0qI!^3eI>3,rL4"?&I!^[&KSY;7N/NXjV51`9]sP/R +Unsl_V50o`Unji_Unsl2FECVY86APV=A27X9MJV_84lQM=A27X9MJV_86APVB3\VrKS5)-H\d?. +Q\9pEI!^[&KT(hJN/NXRMi=!UJW,MGN/NX]N/Es\MN!IPQ]-f\Mi<UQN/3.?LkLH"`PpcrkLnYI +daZjd`PoI%]sP/RX/rFnSt)=BS=H1@S=Z7@St&nV84Ga)7Qijk1c.Zb4@VIr7Qik'4Zl1s4@VIr +2)I-Z4Zl1s4B,9[GB@qND/4?;FE_S;GAV,>FED_DCNjW2GAV,>FED_DCNjlBGAV,>FED_KFE_hK +L4"?&I!^TqH\d?.g"bHas8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!m.9o6m-j0)n(HLQLkLF\<)mR9>#\I$B3\VQ>Zt*+<G,Q? +B3\VQ>ZtcF>$,$9=Bo0F>Zt*+<G,Q?=Bo0F>ZtcF>%_)DB3\VQ>ZtWJATqZm@q9.`>ZtWJATqZm +@q9.pA70.gDI[3gG@Y)kA7]t%CL^mdGAV,1Ci4H6CNjW2GB@qNFED_KFG>0iGB@qNFEE7bHZsRR +GB@qNFED_KFE_hKGAV,>FED_DCNjW2C2@d3D/4?;FE_hKLNIKZFEE:[E-HDGGAV,>FED_DCPR"N +GB@q]I!^TqH[C*fL4"?&I!^3eI>3,rGAV+p<)m$o88(dj=Bo079Lr,^<E)pt<)ck"9Lr,^<P,oW +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8V`bq<726i8j(Sgtp`>hU9p)['[2aD/4?4CNjlB +GB@q]I!^'ZFF/@_H[C0qI!^3eI>;o`H[C0bFEE7bHZsRRL4"?&I!^TqH\QopL4"?&I!^[&KSFl$ +L4"?&I!^[&KSFl$LkLG;KS5)-H\d?.L4"?&I!^3eI<TdTL4">pH[U*[FF/@_GB@q]I!^3eI=$<h +L4">pH[UWrH\QopLkLG.H[U^'KR8&oLkLG;KS5/7KSFl$LkLG;KS5/7KSY;7N/NXRMi<IFKU7XT +GAV+t>[D&J>&%kkdaZkJs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s7H$\ +kj7d%m-j)lgrmpdR?NhnMi<UQN/W[RN/NX]N/ERPN0fK\N/NX]N/ERPN0fK\N/NXNKS5\NMMQq= +Q\9pKMi<IFKSY;7LkLG;KS5)-H\d?.GAV+t9Lro7DY3Yus8W-!s8W-!s8W-!o_/+Em-j0)n)iE\ +g"bH4eCN'tf%A3ibKS5Sbg">Tc+CX%LkLG;KS5\NMN!IPQ]-f\Mi=!]MN!IPN/NXNKS5\FJV\u4 +LkLG;KS5/7KSFl$L4"?(KS5)-H\QopL4">lFEE7bHZsRRC2@cV6q'O477KF&S=Z8Ns8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,kpA+@Sq;C>sk1nb?eCN9rbKJ,S +`5T^6`Pod7`Pfa7f>PA@`Po3k[$Q`/N/NXRMi<UQN/W[RQ]-f\Mi<IFKSY;7LkLG;KS5/7KSFl$ +LkLG;KS5)-H[C*fLNIKZFEE:[E-HDGGB@qNFED_KFE_S;GB@r[gtr)2s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8VHWp#tc2i8j(Sgtp`>hU9p)daZjreCN=.hV$]@ +<)cje4Zl1s4B4g9GAV,MI!^TqH\QopLkLG;KS5/7KW(?)]=bi1gtp`>hV$]@daZjreCMgec-+>U +`5T^6`Pod7`Oidr]=bhh]Y1qi]t:qj['[3I['[HX]sP/R['[2pI!^[&KUJ$fR?Ni&PEVr6Q'mi" +R?Ni&PEVDuPF%5cR?Ni$N/ERPN/W[RQ]-fiPEV>lMO09ZQ]-fgN/Es\MOBZlR?Ni&PEVDuPP"SE +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!m.9o.jQG4OhU9p)bKS5L`PoI%]sP/R['[3I['[3I['[3I +X/rG1['[3I[&^:1C2@c[9MJV_84lQM=A27qA7^^XN0fK\Q]-fgN/Es\MOBZlR?Ni$N/F$ePF%5c +Q]-fgN/F$ePF%5cN/NX]N/Es\MO09ZN/NXRMi=!UJW,MGLkLGJN/ERPN/W[RQ\9pKMi<IFKSY;7 +LkLG9I!^TqH[C*fL4"?&I!^3eI>3,rH[C0qI!^3eI>3,rL4">pH[UWrH[C*fL4">pH[UWrH\Qop +L4"?&I!^[&KSY;7LkLG;KS5/7KSY;7LkLGJN/ERPN0fK\['[3I['ZX*Unji_Unsl_V50o`Uj$p& +<)ck"9Lr8Z86APV8k_r]9Lr8Z86APV8k_r]9LrZ(AVc"mLkLG;KS5/7KSY;7Q\9pKMi=!UJW,MG +N/NX]KRo)?N0fK\N/NX]N/ERPN/3.?Q\9pGKS5)-HcsXXi8j(SgtpK/f#5PH]=bha['ZX*Un"$H +S=Z7@St)=BS=H1@<)cje4Zl1s4@VIr2)I-Z4Zl1s4>erP7Qik'4Zl1s4@VIr7Qik99LsALFE_hK +GAV,>FED_KFE_S;GAV,>FED_DCNjlBGB@qND/4?;FE_hKGB@qNFEDkVI=$<hL4"?&I!aQ%hZ*WU +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8V`bq=OCVkj7crjQFt@eou4XB3\VQ>ZtcF>$,$9B3\VQ>ZtWJAS57O=Bo0F>ZtcF>#\I$ +B3\V><)mR9>#\I$B3\VMA7]CY>%;)S@q9.`>ZtWJARf7^B3\VQ>ZtWJARf7^G@Y)kA7]7]ATqZm +@q9.\A7]7]ARf7^GAV,>FED_DCNjlBGB@qNFEDkVI>3,rH[C0bFED_KFGFsWGB@qNFED_KFE_S; +GB@qNFED_KFE_S;GAV,>FED_KFE_hKGB@qND/4?;FE_hKGB@qNFEE7bHZsRRH[C0bFEE7bH[C*f +L4">pH[U*TCK+85<)cjs<)m$o85rPg<)ck2:J"Mb<E)pt=A28t]Y4@Fs8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!o_/+QpA*q=n)39ig"bH4eCN'tetf.<C2@d3D/4?;FE_hKGB@q^FDuGGFF/@_ +GB@qRH[U6fI>;o`H[C0qI!^3eI>3,rH[C0sKS4]!I>3,rL4"?&I!^TqH\QopL4"?&I!^[&KSFl$ +L4"?&I!^3eI=$<hGB@q^FDuGGFE_hKGB@qNFED_KFE_hKL4">lFEDkVI>3,rH[C0fH[UWrH[C*f +L4">pH[UWrH\QopL4"?(KS5/7KSY;7LkLG;KS5/7KU7XTLkLG*D/36Y?>!MHLkLHFm-juSs8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!o_/+QpA*Y-kMYFadaZj9PEUfUKU7XT +Q]-fXKS5\NMN!IPQ\9pKMi=!]MMQq=N/NX]N/EFEKT(hJLkLG?Mi<IFKSY;7LkLG;KS5)-H\Qop +LkLG*D/36I86APVg"bHas8W-!s8W-!s8W-!s8W-!s7H$\kj7crjQG4OhV$]@daZjkbg">Tc-+>U +`5T^=bg!Z"Wec=]N/NXNKS5;BN0fK\LkLG?Mi=!UJW,MGLkLG;KS5/7KSY;7L4"?(KS5)-H\Qop +L4"?&I!^'ZFF/@_GB@q^FDuGGFD"i^7Qik'4ZkSY1t'n)s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!o_/+Em-ilnkLnYIdaZk#bfdrD`RrDX`5T^6`Pp$Ec,@T? +`5T]`PEV>lMO09ZN/NX]N/ERPN/W[RLkLG;KS5/7KR8&oLkLG.H[UWrH\d?.LkLG9I!^3eI>3,r +H[C0bFED_KFGFsWGB@qNFEEk.MZ<_Vs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!o_/+IoC_>6n)39ig"bH;gtp`>hVdJXi8j(5]Y.<65t+11<CK2U9LsMWI=$<h +H[C0qI!^[&KW(?)bKS5pm-j<4p#tc2kj7crjQGI^kLnYIdaZjreCN'tf#5PH`5T^6`PoI%]uI^r +['[3P]Y1qi]t:qj['[3P]Y1\Z[&^:1B3\VTCi52iN1#lnR?Ni&PEVDuPF7VuR?Ni&PEUr`N0fK\ +Q]-fgN/ERPN0fK\N/NX_PEV>lMN!IPR?Ni&PEVDuPF7VuR?NiH]Y4@Fs8W-!s8W-!s8W-!s8W-! +s8W-!s8V`bq<[_Gi8j(SgtpK/f#5PH]=bhh]Y1\Z['[3I['[3I['[3I['[3IX/rG1['Zm8X`nl/ +<CK2B6q'^A9it([GAV,SMi<UQN/W[RQ]-fgN/Es\MN!IPQ]-f\Mi='fPDkEYQ]-f\Mi<UQN0fK\ +N/NXRMi<UQN/W[RN/NX]N/EFEKT(hJLkLG;KS5;BN/3.?LkLG;KS5)-H\QopH[C0bFEDkVI=$<h +L4">pH[UWrH[C*fL4"?&I!^3eI>3,rH[C0qI!^3eI>3,rLkLG.H[U^'KSFl$L4"?(KS5/7KT(hJ +Q]-fXKS5;BN/W[RN/NXNKS6D-XgGIBUnsl_V50o`Unji_Unsl2FECVY86APV8k_r]9Lr,^<EMpc +8k_r]9Lr8Z86APVB3\VrKS5/7KSY;7LkLG;KS5/7KT(hJN/NX]KRo)?N/W[RQ]-f\Mi=!]MN!IP +N/NXRMi<IFKSY;7H[C1Z`PpcrkLnYIdaZjd`PoI%]sP/RX/rFnSt)aJQ(4G9S=Z7LR[$iO<CT,6 +7Qik'4Zl1s4@VIr7Qik'4Zl1s4>erP7Qik'4Zl1s4BP9JGB@qNFED_KFE_hKGAV,>D/4?;FE_hK +GB@qNFED_KFE_hKGB@qNFED_KFE_hKGB@qRH[UWrH[C*fg"bHas8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,kpA+(Hp#+oo +i8j(Ebft?RFD"i^@q9.`>ZtWJARf7^B3\VMA7]CY>%_)D<)ck1>Zt*+<G,Q?<)ck1>ZtcF>$,$9 +B3\VMA7]CY>%;)S@q9.pA7/nXARf7^B3\VMA7]7]ARf7^@q9.\A7]CY>%;)SG@Y)kA7]t%CMI[' +GAV,>FED_KFG>0iL4">pH[U*[FG>0iH[C0fH[U*[FGFsWGB@qNFED_KFE_hKGB@qNFED_KFE_hK +LNIKZFED_KFE_hKGAV,NFDuGGFE_hKGB@qNFED_KFE_hKGB@qNFEDkVI<TdTGAV+t9Lr,^<G50" +<)cjs<)m$o85rPg=A27f9Lr,^<P,oWs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s7H$\ +m.9o6m-ilnkLnYIg"bH4eCLFlUj$ZkC2@d3D/4?;FE_hKGB@qNFED_KFG>0iGB@qRH[U*[FE_hK +H[C0fH[UWrH[C*fL4">pH[U6fI>EQ0H[C0qI!^3eI>3,rL4">pH[U6fI<TODGB@qND/4?;FE_hK +H[C0bFEE:[E-HDGL4">lFEDkVI<TdTLNIK^H[UWrH[C*fL4">pH[U6fI>3,rH[C0fH[U6fI>3,r +L4"?&I!^[&KSY;7N/NXNKS4PdCK+85B3\W9V54.ks8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W,kpA+(Hp#tc2i8j(LeCLFlUl:4jQ]-fXKS5;BN/W[RN/NXNKS5;BN/W[R +N/NXRMi<IFKU7XTN/NX]N/ERPN0fK\LkLG;KS5)-H\QopL4"?&I!^3eI99`\<CK3SXKDO&s8W-! +s8W-!s8W-!s8W-!s8W-!s8V`bq<726i8j(SgtpK/f$`(!fZ_O^bg">Tc-+>U`5T]`PEV>lMO09Z +N/NX]N/ERPN/3.?LkLG;KS5/7KSY;7L4">pH[UWrH[C*fH[C0qI!^3eI<TdTL4">lFED_KFE_hK +GB@qND/2R.75ZnY7Qik&6q..Us8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8V`bq<726i8j(SgtpK/f#u:^bKS5Sbg")F`Pfa7`5T^6`Pod7`ON%MN/NXRMi<UQN0fK\ +N/NXRMi<IFKSY;7LkLG9I!^[&KSY;7LkLG;KS5/7KSY;7LkLG;KS5)-H\QopL4">pH[UWrH[C*f +daZkJs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s6T@M +m.9o6m-ilnkNM:$i8j(bm-j<4ophVD7Qik676sC+4C_o5L4"?&I!^TqH^U(]bKS6'pA+ags7H$\ +o_/+IoC_JAp#tc2kj7crjQG4OhV$]@daZjkbg">Tc,@T?`5T^-]Y1qi]t:qj]=bhh]Y1qi]sP/R +]=bhh]Y0_sP>kL]B3\VeH[V<GPF7VuR?Ni&PEVDuPF7VuQ]-fiPEUr`N/W[RN/NX_PEUr`N1#ln +R?Ni&PEUr`N1#lnR?Ni&PEVDuPF7Vus8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,coC_>6n(HLQ +daZjkbg")F`Oidr]=bha['[3I[&^:1['[3I['Zm8XgGIBX/rG5Xf@21KM"p4<CK2B6q(3O89]/t +LkLG;KS5;BN/W[RN/NX]N/ERPN/W[RN/NXRMi<UQN/W[RN/NXRMi<UQN/3.?LkLG;KS5;BN/W[R +N/NXNKS5/7KSY;7LkLG;KS5)-H[C*fH[C0bFED_KFE_hKL4">lFEDkVI>3,rH[C0fH[UWrH[C*f +L4">pH[UWrH[C*fLkLG;KS5/7KSY;7LkLG;KS5/7KSY;7N/NXNKS5;BN/W[RQ]-f\Mi<UQN1#ln +['[3I['Zm8Xe_ehUnsl_V50o`Uj$p&8k_r]9LqcL9it([8k_r]9Lr8Z84lQM=A27f9LrZ(AXA@5 +LkLG?Mi<IFKU7XTLkLG?Mi=!]MN!IPN/NX]N/ERPN1#lnN/NXRMi=!UJW,MGL4"?(KS4]!IDj+D +i8j(SgtpK/f#5PH]=bha['ZX*Unji_S=Z7@St)=BS=H1@=Bo0$6q'O477KF&7Qik'4Zl1s4@VIr +7Qik'4Zl1s4@VIr7Qik99LsALFF/@_GB@qRH[U6fI<TdTGB@qNFED_KFE_hKGB@qNFED_KFE_hK +L4">pH[UWrH\QopL4"?(KS8%6hZ*WUs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!o_/+QpA*Y-kMYFabKS4cI!]@6ARf7^ +B3\VMA7]7]ARf7^B3\VQ>ZtcF>$,$9B3\VB>[D&J>$,$9B3\VQ>ZtWJAS57O@q9.`>ZtcF>%;)S +B3\VQ>ZtcF>%_)DB3\VQ>ZtcF>%_)DB3\VQ>ZtcF>%;)S@q9.cCi4H6CNjW2GB@qRH[UWrHZsRR +L4">lFED_KFE_hKGB@qNFED_DCNjlBGAV,>FED_KFE_S;GB@qNFED_KFE_hKGAV,>FED_KFE_hK +GB@q^FDuGGFE_hKGB@qND/4?4CNjlBGB@qNFED_DCK+85=A27b<)m$o86APV=A27b<)m$o85rPg +=A28m[']l5s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8V`bq=j7=kj7crjQG4OhV$]@ +daZjT['Y%!FD>W0GAV,>FED_DCNjlBGAV,>FED_KFF/@_GB@qNFED_KFE_hKH[C0bFEDkVI=$<h +H[C0fH[U6fI=$<hH[C0fH[U6fI<TdTGB@qNFED_KFE_S;GB@qNFED_DCNjlBGB@qNFED_KFE_hK +GB@qRH[U*[FE_hKGB@qRH[U6fI=$<hH[C0fH[U6fI>3,rL4">pH[U6fI>EQ0LkLG;KS5/7KO\P( +<)ckPI!af4kPtS^s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s7H$\ +kj7crjQG4OhRK\fLkLG?Mi<IFKT(hJQ]-fXKS5\NMMQq=N/NXRMi<IFKU7XTN/NXNKS5;BN/W[R +LkLG?Mi<IFKSY;7H[C0fH[U6fI=$<hB3\V04Zmq1FT;C@s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +o_/+Em-j0)n)iE\g"bH4eCN'tf#u:^bKS5Sbg">Tc+CX%R?NhnMi=!]MN!IPN/NXNKS5;BN.u_, +LkLG9I!^[&KR8&oGB@qNFEDkVI=$<hL4">pH[U*[FE_hKGB@qNFED86DKfr5B3\V04ZkSY1c7*H +@q90Ns8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,kpA*q=n)39i +g"bH4eCMgec,@T?`5T^=bg")F`Pfa7`5T^6`Pn7/PDkEYN/NXRMi<UQN/W[RN/NXLI!^[&KSY;7 +H[C0sKS5/7KT(hJLkLG;KS5/7KSY;7LkLG;KS4]!I=$<hL4"?(KS9C*s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,kpA+@Sq=OCVkj7d%m-j<4p%7tR +o_/*NSt&5;77BU5779RgD/4KFI>EQ0]=biWs8W-!s8W-!s8W-!s8W-!s8W-!s8W,kpA+(Hp#tc2 +i8j(Sgtp`>hV$]@bKS5Sbg")F`Pfa7]=bhs]XkJW[(Eua['[3P]Y1\Z[(Eua['[2aFECJ]<E)pt +H[C1/PEUr`N1#lnR?NhnMi='fPDkEYN/NXRMi<UQN/W[RN/NX_PEUr`N1#lnR?Ni&PEVDuPDkEY +R?Ni&PEXGEf)PdMs8W-!s8W-!s8W-!s8W-!s8W-!s7H$\m.9o6m-iW_hU9p)daZjd`PoI%]t:qj +['[3I['[3I[&^:1['[3@XKAk:[&^:1X/rFkPESsF<D#qZ779R:9MK_QFGPU'N/NXRMi<UQN/3.? +N/NXRMi=!]MN!IPN/NXRMi<UQN/W[RLkLG?Mi<IFKSY;7LkLG;KS5/7KSY;7LkLG;KS5/7KR8&o +L4">pH[U6fI<TdTGB@qNFED_KFF/@_H[C0fH[UWrH\QopH[C0fH[U6fI>3,rH[C0qI!^[&KSY;7 +LkLG;KS5;BN/3.?N/NXNKS5;BN/W[RN/NXRMi<UQN/3.?S=Z7h`PoI%]sP/RUnsl_V50o`Unji_ +Unsl2FEC,K9it([8k_rO9MJV_84lQM8k_r]9LqcL9it([@q9/,KS5;BN/3.?LkLG;KS5;BN/3.? +N/NXRMi<UQN/W[RQ]-f\Mi=!]MN!IPLkLG;KS5)-H[C*fH[C1Z`PpcrkLnYIdaZjd`PoI%]sP/R +X/rFnSt)=BS=H1@S=Z7@St'Fu>"(hJ=A27T4Zl>19gqH=<CK2C4Zl_55t4""7Qik'4Zl/$79!5d +GB@qRH[UZkE-lq[GB@qRH[U6fI=$<hH[C0bFED_KFE_hKGB@qNFEE7bHZsRRH[C0fH[U^'KR8&o +g"bHas8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s6T@Mkj7d%m-ilnkL.l2Q]-f3A7]7]ATqZm@q9.\A7]7]ARf7^ +@q9.`>ZtcF>%_)DB3\VB>[CoNAS57O@q9.`>ZtWJAS57O@q9.`>Zt67?>!MH=Bo07>[D&J>#\I$ +=Bo03<)m%*?<CH=B3\VQ>ZtWJATqZmC2@d&Ci4H6CNjlBGB@qNFED_KFE_hKGB@qND/4?4CNjlB +GAV,>FED_DCL^mdGAV,>FED_DCNjlBGB@qNFED_KFE_hKGB@qNFED_KFE_hKGB@qND/4?4CNjW2 +GB@qND/4KFI<TdTC2@ci9Lr,^<EMpc=A27b<)m$o84lQM=A27X9MJ,Q9tS'Os8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,kpA+(Hp#tc2i8j(`gt^T<hU9p)`5T]OKS3iGATr!, +GAV,>D/4?4CNjlBGAV,>FED_DCNjlBGB@qNFED_KFE_hKGB@qNFED_KFGFsWGB@qND/4?;FE_S; +GB@qNFED_KFE_S;GB@qND/4?;FE_S;GB@qND/4?4CNjlBGB@qNFED_DCNjlBGB@qRH[U*[FG>0i +GB@qNFEE7bH\QopLkLG.H[U^'KR8&oLkLG.H[U^'KQhN[B3\VMA7`]u`W,u<s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!o_/+Em-ilnkN:RT]=bh9Mi<IFKT(hJ +LkLG?Mi<IFKT(hJLkLG?Mi<IFKSY;7N/NXNKS5;BN/W[RLkLG?Mi<UQN/3.?LkLG.H[U6fI<TOD +GB@q:A7\4n4B,9[o_/+\s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s7H$\kj7d%m-iW_hV$]@ +daZk#bfe2Rc-+>UbKS5Sbg!N%[#Bp%N/NXRMi<UQN/3.?LkLG;KS4]!I=$<hH[C0fH[U*[FE_hK +H[C0bFEDkVI<TdTGB@qND/4?4CNjW2C2@d&Ci4!(DJ*3X2)I-I1c1PXMZ<_Vs8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s7H$\kj7crjQG4OhU9p)bKS5Sbg")F`Pfa7 +`5T^=bg")F`Pfa7X/rFZKS5/7KSY;7N/NXNKS5;BN/3.?LkLG;KS5/7KSY;7LkLG;KS5;BN/W[R +N/NXRMi<IFKSY;7LkLG.H[UWrHd^Eps8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!o_/+QpA+@Sq=OCVs8W-!s8W-!s8W-!UnskZ9MJ,Q9m_58 +UnsmZpA+ags8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,kpA+(Hp#tc2i8j(SgtpK/f$`(! +bKS5L`Pod7`Oidr]=bhh]Y1qi]sP/R['[3P]Y1\Z[&BFY<)ck2:J"Yn?AO8fN/NX_PEVDuPF7Vu +N/NX_PEUr`N0fK\N/NXRMi='fPDkEYR?Ni&PEVDuPF7VuR?Ni&PEUr`N1#lnX/rH's8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8V`bq<[_Gi8j(SgtpK/f#u:^`5T^-]Y1qi]sP/R['[3I['[3I[(*6< +X/rG1['[3I['[3IUnsl2FECVY84>p8=A28#Ci5&^KSY;7LkLG;KS5/7KSY;7LkLG;KS5/7KSY;7 +LkLG;KS5/7KSY;7LkLG;KS5/7KSY;7L4"?&I!^TqH[C*fL4">pH[U6fI<TdTGB@qNFED_DCNjW2 +GB@qNFEE7bH[C*fL4">pH[UWrH[C*fL4">pH[U^'KSY;7LkLG;KS5;BN/3.?N/NXRMi<UQN/W[R +LkLG;KS5;BN/3.?Q]-g&XKB[ic,@T?]=bha['ZX*Unji_Unsl_V50o`Uj$Zk779R:9MIrD79E5S +8k_r]9LqcL9it([8k_rO9MK/)>)7ibLkLG;KS5/7KSY;7LkLG;KS5/7KSY;7LkLG;KS5;BN/W[R +LkLG;KS5/7KR8&oH[C0fH[U*[FMu/;i8j(SgtpK/f#5PH]=bha['ZX*Unji_S=Z7@St)44PGG%N +<)cjd6q'O477BU5<CK2R76s@177BU5779R:9MJMU5t4""779RH>[E/4H[C*fH[C0fH[U6fI=$<h +GB@q]I!^TqH\QopLkLG.H[UWrH[C*fH[C0fH[UWrH[C*fH[C0qI!aQ%hZ*WUs8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8V`bq<726i8j(Sgtp`>hQ*`[GAV,*A7]sq?tsLqG@Y)rCi3lj>%;)S=Bo0BA7]CY>%;)S +B3\VQ>Zt67?>!MHB3\VQ>Zt67?>!MH=Bo0F>Zt*+<E)pt<)cjs<)mR9>#\I$<)cjs<)m%*?=RMW +@q9.\A7]7]ARf7^C2@d&Ci4H=FE_S;GAV,>FED_DCNjW2C2@d3D/3m&DKfr5=Bo03<)n-ZCNjlB +GAV,>FEDkVI<TdTL4">lFED_KFE_hKC2@d3D/3m&DJF!*C2@d&Ci4H6CNjlBGB@qNFED86DHKS' +=A27f9LqcL9hJ)R8k_rO9MJ,Q9hJ)R779SO[']l5s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!o_/+Em-j0)n)39ii8j(SgtpK/f$`(!Unsl2D/3m&DJF!*C2@d3D/4?4CNjlB +GB@qNFED_KFE_S;GB@qND/4?;FE_S;H[C0bFED_DCO:DVGB@qNFED_KFE_S;GB@qND/4?;FE_hK +GB@qND/3m&DKg2EC2@d3D/4?4CNjlBGB@qNFED_KFE_hKGB@qNFEDkVI=$<hH[C0fH[U6fI>EQ0 +H[C0qI!^3eI<TdT@q9.cCi6Ve[/^1+s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W,kpA*q=n)39ii8j(>`PmdoN/3.?LkLG;KS5/7KSY;7LkLG;KS5;BN/3.? +LkLG;KS5/7KT(hJLkLG?Mi<IFKSY;7LkLG;KS4]!I=$<hGB@qNFED_DCJ%8p779S_`PqlWs8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8V`bq<726k1nbFgtpK/f$`(!bKS5Sbg">Tc-+>U +`5T]cSt(atN/W[RN/NXNKS5)-H\d?.H[C0qI!^TqHZsRRH[C0bFED_KFE_hKGB@qNFED_KFE_hK +GAV,1Ci4H6CL^md@q9.\A7\_><EMpcs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W,kpA+(Hp#tc2g"bH4eCN9rbKJ,SbKS5L`Pod7`Pfa7`5T^6`PmRZH[C*f +LkLG;KS5/7KSY;7N/NXNKS5/7KSY;7N/NXNKS5/7KSY;7LkLG?Mi<UQN/W[RN/NXRMi<IFKR8&o +N/NYps8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s2;mqGAV-Kgtr)2s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!o_/+IoC_&&kMYFag"bH4eCN'tf#5PH`5T^-]Y2=t]!SiO +]=bha['[HX]sP/R]=bha['XRaDH'S8<)ck-A7^^XN1#lnN/NX_PEVDuPF7VuN/NX_PEUr`N1#ln +N/NX_PEVDuPDkEYN/NXRMi='fPDkEYN/NXRMi<UQN;rqXs8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W,kpA+(Hp#+oog"bH4eCMgec,@T?`5T^-]Y1qi]sP/R['[3@XKAk:[&^:1['[3@XKAk:[&^:1 +S=Z6`>ZsQa77BU5@q9.tH[U6fI>EQ0H[C0sKS5/7KSY;7LkLG;KS4]!I>EQ0LkLG;KS5/7KSY;7 +LkLG.H[U^'KR8&oH[C0fH[U6fI=$<hGB@qRH[U*[FE_hKGAV,>D/4?;FF/@_H[C0qI!^3eI>3,r +H[C0qI!^3eI>EQ0LkLG;KS5/7KSY;7N/NXRMi<UQN/W[RN/NXNKS5;BN/W[RN/NX_PEWr(`S'&' +bKS5L`PoI%]rS6:X/rG!V50o`Unji_Unsl2FEBr>77BU5779RE76s@177BU5779R:9MJV_84lQM +@q9/,KS5)-H\d?.LkLG;KS5/7KR8&oLkLG;KS5/7KSY;7LkLG;KS5/7KSY;7H[C0fH[U6fI<TdT +GB@rF`PpcrkLnYIdaZjkbg!c4]sP/RX/rFnSt)=BS=H1@S=Z7@St'Fu>"(hJ<CK2B6q'R.4@MY, +779R56q(*E5t+11779R:9MIrD7;#k/H[C0fH[UWrH[C*fH[C0fH[UWrH[C*fLkLG.H[UWrH[C*f +L4">pH[U6fI=$<hH[C0qI!^3eI=$<hdaZkJs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!o_/+QpA+(Hp#tc2 +i8j(Sgtoug`JB2#@q9.\A7]7]ARf7^C2@d#>ZtWJARf7^=Bo0F>Zt67?<CH==Bo07>[CB/<ENL4 +=Bo03<)lms<E)pt<)cjs<)lms<E)pt<)cjs<)lms<E)ptB3\VB>[D&J>%;)SGAV,*A7]sq?tsLq +C2@d&Ci3`nASQ%!GAV,1Ci4!(DJF!*C2@ce<)l@T79!5dGAV,1Ci4!(DKg2EGB@qNFED_DCNjW2 +GAV,1Ci4!(DI[3gC2@d#>ZtlYDJF!*C2@d3D/4?4CNjW2@q9.C9MJ,Q9hJ)R8k_rZ76sO>9iXVJ +<CK2R76sO>9sh:7s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +o_/+Em-ilnkMYFag"bH;gtpK/f#5PHN/NX0Ci4!(DJF!*GAV,1Ci4H6CNjW2GB@qNFED_DCNjW2 +GAV,>FED_KFE_hKGB@qNFED_DCNjW2GB@qND/4?;FD>W0GB@qND/4?;FD>W0GB@qND/3m&DKg2E +C2@d3FED_DCNjlBGAV,>FED_KFF/@_GB@qRH[U6fI=$<hLkLG.H[U6fI=$<hC2@d3FEFms[/^1+ +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s7H$\ +m.9o.jQFt@esV_cLkLG.H[U^'KSY;7LkLG;KS5/7KSY;7H[C0sKS4]!I>EQ0H[C0sKS5/7KSY;7 +LkLG;KS5/7KR8&oLkLG*FED_KFD>W0<)cjt76uljN;rqXs8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!o_/+IoC_>6n(HLQg"bH4eCN'tf%A3ibKS5Sbg">Tc,@T?Q]-fXKS5/7KR8&o +H[C0fH[U6fI=$<hH[C0fH[U*[FE_hKH[C0bFEE7bH[C*fGB@qNFED86DKg2EC2@d&Ci3`nATqZm +N/NYYm-juSs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +m.9o6m-j)lgtCK>bKS5Sbg")F`Pfa7bKS5L`Pod7`O*"Z=Bo0eI!^[&KSY;7LkLG;KS5;BN/3.? +LkLG;KS5/7KSY;7LkLG;KS5;BN/W[RN/NXRMi<UQN/W[RLkLG;KS7:_`W,u<s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s7H$\o_/+Em-ilnkLnYIdaZjkbg">Tc,@T?]=bhh]Y1qi]sP/R]=bha['[3I[(Eua +Q]-f(9Lr,^<E)ptGB@qcMi='fPDkEYN/NX_PEUr`N/W[RN/NXRMi<UQN/W[RN/NXRMi<UQN/W[R +N/NXRMi<UQN/W[RN/NYQjQHRCs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!o_/+Em-ilnkLnYI +daZjkbg")F`Oidr]=bhh]Y1\Z['[3I['[3@XKAk:[&^:1['[3@XKAP)XfJP*N/NWo<)l@T79!5d +H[C0fH[U^'KSY;7LkLG;KS4]!I=$<hLkLG.H[U^'KR8&oLkLG.H[U6fI>EQ0H[C0fH[U6fI=$<h +GB@qRH[U*[FE_hKGB@qND/4?;FD>W0GB@qRH[U6fI=$<hH[C0sKS4]!I>EQ0LkLG;KS5/7KT(hJ +LkLG;KS5;BN0fK\N/NXRMi<UQN/W[RN/NXNKS6.tUtOP[i8j(LeCN'tf#5PH]=bha['ZX*Unji_ +Unsl_V50o`Uj$Zk4$5Yq4Zkeg4[qRs779RE76spB5t4""779R56q(`n>'kUELkLG.H[U6fI=$<h +H[C0sKS4]!I>EQ0LkLG.H[U6fI=$<hH[C0fH[U6fI=$<hH[C0bFED_KFM#3!i8j(SgtpK/f#5PH +]=bha['Zm8XdkuQS=Z7@St)=BS=H1@=Bo0$6q'^A9gqH=<CK2B6q'O477BU5779R64Zl/$79)cB +779RH>[Dc(I=$<hH[C0fH[UWrH[C*fH[C0sKS4]!I=$<hH[C0fH[U6fI=$<hH[C0bFEDkVI=$<h +H[C0fH[XT&hZ*WUs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s7H$\o_/+Em-j0)n)39ig"bH;gto*5X`nl/ +@q9.\A7]CY>%;)S@q9.Q>[D&J>$,$9<)cjs<)lms<E)pt<)cjs<)lms<EMpc<)ck"9Lr,^<EMpc +<)ck"9Lr,^<E)pt=A27b<)lms<G,Q?@q9.\A7]7]ARf7^@q9.\A7]7]ARf7^@q9.cCi4!(DKfr5 +C2@d#>ZsQa77BU5779RH9Lro7DJF!*C2@d&Ci4H6CMI['C2@d&Ci4!(DJF!*B3\VMA7]CY>%;)S +@q9.`>ZtWJASQ%!C2@d&Ci3`nAP,Wj8k_rO9MJMU5tXgF779R64Zl/$76<Up7QilG]Y4@Fs8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8V`bq=OCVp[%),m-ilnkMYFa +g"bH;gtpK/f!MfkL4">_Ci4!(DJF!*C2@d&Ci4H=FD>W0GB@qNFED_KFE_hKGB@qNFED_KFE_hK +GB@qNFED86DKg2EC2@d3FED86DKg2EGB@qNFED86DKg2EGB@qACi4H=FE_hKC2@d3FED_KFE_hK +GB@qND/4?;FE_hKGB@qRH[U6fI=$<hGB@qpPEX26c2[hDs8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,kpA*q=n)39idaZjKXK@G>N/3.? +H[C0fH[U^'KR8&oLkLG.H[U^'KR8&oH[C0fH[U6fI<TdTH[C0fH[U6fI=$<hH[C0fH[U6fI=$<h +GB@q:A7\1t7:Tk>s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s7H$\ +kj7d%m-iW_hV$]@daZjkbg">Tc,@T?bKS5Sbg!2iXc/0sH[C0sKS4]!I>EQ0H[C0fH[U6fI<TdT +GB@qNFED_KFE_hKGB@qNFED_KFE_hKC2@d3D/3m&DKfr5UnsmNm-juSs8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8V`bq<726g"bH;gtp5uc-+>U +`5T^6`Pod7`Pfa7`5T]BH[TXFDL6_YLkLG.H[U^'KSY;7LkLG;KS5/7KSY;7N/NXAH[U^'KSY;7 +N/NXRMi<UQN/W[RN/NXRMi<IFKT(hJs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s6/h< +kj7crjQG4OhU9p)bKS5L`Poj0]">Vg]=bhh]Y1\Z[(Eua]=bha['Zm8X]Sh7=A27f9Lr8j?Asf$ +N/NXRMi<UQN/W[RN/NXNKS5;BN/W[RLkLG?Mi<UQN/W[RN/NXRMi<UQN/W[RN/NXRMi<UQN4Za9 +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8V`bq=OCVm.9o.jQG4OhU9p)bKS5Sbg")F`Oidr +]=bhh]Y1\Z['[3IX/rG5XfAG'XgGIBX/rG1['[?FWiN5'LkLF\<)lOa9k.^FH[C0sKS4]!I>EQ0 +LkLG;KS4]!I>EQ0H[C0sKS4]!I>EQ0H[C0fH[U*[FF/@_GB@qRH[U*[FE_hKGB@qNFED_KFD>W0 +C2@d&Ci4H6CNjlBGB@qRH[U6fI=$<hH[C0fH[U^'KSY;7LkLG;KS5;BN/W[RN/NX_PEUr`N/W[R +N/NXNKS5bWPJkGZm.9o6m-ilnkLnYIbKS5L`PoI%]rS6:Unsl_V50o`Unji_Unsl2D/2!c1c7*H +4$5Yq4Zkeg4Zbbh4$5Yp6q(*E5t+11=Bo0ZH[U6fI=$<hLkLG.H[U6fI=$<hLkLG.H[U6fI=$<h +H[C0fH[U6fI<TdTH[C0fH[U6fI<TdTC2@e+`PpcrkLnYIdaZjd`PoI%]sP/RX/rFnSt)=BS>_mA +S=Z7@St'Fu>"(hJ<CK2G9MIrD77BU5<CK2G9MJ,Q9gqH=779R56q(*E5u^f`H[C0fH[U6fI=$<h +H[C0fH[U6fI=$<hH[C0fH[U6fI=$<hH[C0fH[U6fI>3,rGB@qRH[U6fI=$<hdaZkJs8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s7H$\m.9o6m-ilnkMYFag"bH4eCL.]S9K's@q9.\A7]CY>#\I$ +=Bo03<)lms<E)pt<)ck"9Lr8Z86APV=A27b<)lms<EMpc<)cjs<)lms<EMpc<)cjs<)lms<E)pt +<)cjs<)m%*?>!MHB3\VB>[CoNARf7^@q9.`>ZtWJARf7^@q9.\A7\_><CK;E7Qik'4Zkeg4[hb- +@q9.\A7]7]ASQ%!C2@ctA7]7]ARf7^@q9.\A7]CY>%;)S@q9.Q>[D&J>$,$9@q9.\A7]7]ATr!, +B3\V?76s@177KF&779R64Zl1s4@MY,4$5Yq4Zm4bA^])Zs8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8V`bq<[_Gkj7d%m-ilnkN:RTg"bH;gtpK/f!qi^ +H[C0UCi4H6CMI['GAV,>FED_KFD>W0GB@qACi4H=FD>W0C2@d3D/3m&DJF!*GB@qACi4H=FE_S; +GB@qNFEDkVI<TdTGB@qNFED86DKfr5C2@d&Ci4H=FD>W0GB@qACi4!(DKg2EGB@qNFED_KFE_hK +LkLG^XKCFAkPtS^s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s7H$\m.9o6m-iW_hV$]@daZj[]Y0i,S;`AbH[C0sKS5/7KR8&o +H[C0fH[U6fI<TdTGB@qNFED_KFE_hKH[C0fH[U6fI=$<hH[C0bFED86DG!Ss8k_t-eCO["s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8VHWp#tc2k1nbFgtpK/f$`(! +daZk#bfe2Rc-+>UbKS5$St(UiKR8&oH[C0bFEDkVI=$<hGB@qNFED_KFD>W0GB@qNFED_KFE_hK +GB@qACi4!(DMWt!]=biWs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!m.9o6m-ilnkLnYIbKS5Sbg")F`RrDX`5T^6`Po3kZrC") +LkLG;KS5/7KSY;7H[C0sKS4]!I>EQ0LkLG;KS4]!I>EQ0LkLG;KS5;BN/W[RN/NXRMi<UQN/W[R +LkLGn]Y4@Fs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,kpA+(Hp#+oog"bH4eCN'tf#5PH +`5T^-]Y1qi]sP/R]=bha['[3I[(Eua['[2aD/3*M<E)pt<)ckAFEEJ"N/3.?LkLG;KS5/7KSY;7 +H[C0sKS4]!I>EQ0LkLG?Mi<UQN/W[RN/NXRMi<UQN/W[RN/NXbSt,i\s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8V`bq<[_Gi8j(ZjQG4OhU9p)bKS5L`Pod7`Oidr]=bhh]Y1\Z['[3I +['[3@XKAk:[&^:1X/rG(XKB"7WiN5'N/NX)A7\_><GH>fH[C0fH[U^'KSY;7LkLG.H[U^'KR8&o +LkLG.H[U6fI=$<hGB@qNFED_KFE_hKGB@qNFED86DKg2EC2@d3FED86DJF!*C2@d3D/4?;FE_hK +H[C0fH[U^'KT(hJH[C1"Mi<IFKT(hJN/NXRMi<UQN/W[RN/NX_PEUr`N2s%^m.9oMs8VHWp#tc2 +i8j(LeCN'tf"8T.]=bha['ZX*Unji_Unsl_V50o`UgmqH2)I-I1c.'H1c7*H4$5Yq4Zkeg4Zbbh +4$5Yq4Zl\C<I9(@H[C0fH[U6fI=$<hH[C0fH[U6fI=$<hH[C0fH[U6fI<TdTGB@qNFED_KFE_hK +GB@qNFED86DS*Qpkj7ckgtpK/f#5PH]=bha['Zm8Xe_ehS=Z7@St)=BS=H1@<)cjd6q'O477KF& +779R:9MIrD77BU5<CK2B6q'^A9gqH=779RH>[E/4H[C*fH[C0fH[U^'KR8&oLkLG.H[U6fI=$<h +H[C0fH[U6fI=$<hH[C0fH[U6fI=$<hH[C0bFEGs\f)PdMs8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8V`bq=OCVkj7d%m-ilnkMYFag"bH-bfuZLS8)kX=Bo0F>Zt*+<E)pt<)cjs<)m$o85rPg +8k_rY<)lOa9iP(l8k_rO9MJJc<EMpc8k_rY<)lOa9it([=A27b<)lms<E)pt<)cjs<)lms<ENL4 +B3\V><)m%*?<CH=@q9.`>Zt67?:@7N7Qijk1c.'H1cmf_<)ckAD/36Y?>!MHB3\VQ>ZtcF>%;)S +@q9.`>ZtWJAS57O@q9.Q>[D&J>#\I$=Bo03<)lms<G,Q?@q9.\A7\_><CK;E7Qik&6q'R.4?GYg +<)ckEH[VrrXm#-?s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W,kpA+@Sq=j7=kj7d%m-ilnkMYFag"bH;gtpK/f!MfkN/NX0Ci4H=FD>W0 +GB@qACi4H=FE_S;C2@d&Ci4H=FD>W0C2@d3D/3m&DKg2EC2@d3FED_KFF/@_GB@qRH[U*[FE_hK +GB@qNFED_KFD>W0GB@qACi4!(DJF!*GB@qNFED_KFF/@_R?NiXbg$1fs8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8V`bq<726i8j(ZjQG4OhV$]@g"bH-bg!N%[$d,ALkLG;KS4]!I=$<hGB@qNFED_KFD>W0 +C2@d&Ci4!(DKg2EGB@qNFED_KFE_hK<)cje4ZoO:V#UJps8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,coC_>6n)iE\g"bH4eCN'tf#u:^bKS5Sbg"Scf#u:^ +N/NXAH[U6fI<TdTH[C0bFED_KFE_hKC2@d3FED_KFD>W0GB@qNFEDkVI@Qn!g"bHas8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8V`bq<726i8j(Sgtp]-bKJ,S`5T^6`Pp$Ec,@T?L4">XA7^+7I=$<hH[C0fH[U6fI=$<h +H[C0sKS4]!I>EQ0LkLG?Mi<"0I>j)CH[C1"Mi<UQN/W[RN/NXRMi<UQN;rqXs8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!o_/+IoC_>6n(HLQdaZjkbg")F`Oidr]=bhh]Y1\Z['[3I +]=bha['[HX]nh>p<)ck"9Lr,^<F]QNN/NXAH[Uj2N-fo"N/NXAH[U6fI=$<hH[C0sKS4]!I=$<h +N/NXAH[U^'KSY;7N/NXRMi<UQN/W[Rs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +o_/+QpA+(Hp#tc2g"bH;gtpK/f$`(!bKS5L`PoI%]t:qj]=bhh]Y1\Z['[3I['[3@XKAk:['[3I +X/rG(XKAP)XfJP*S=Z6pFED#'AUAcPH[C0fH[U6fI>EQ0H[C0sKS4]!I=$<hH[C0fH[U6fI=$<h +GB@qACi4THI;3S9GB@qACi4!(DI[3gC2@ctA7]LlDJF!*C2@d&Ci4H=FF/@_H[C0fH[U^'KR8&o +LkLG?Mi<UQN/W[RN/NX_PEUr`N1?K0i8j)$s8W-!s8W-!m.9o6m-ilnkLnYIbKS5L`PoI%]rS6: +Unsl_V50o`Unji_Unsl%Ci2*e1c7*H2)I-B/1i_91bL=22)I-O4?YPY1cmf_8k_s'FED86DKg2E +C2@d3FED_KFF/@_GB@qNFED_KFD>W0GB@qACi4H=FD>W0GB@qACi4!(DJF!*C2@e"]Y37akLnYI +daZjd`PoI%]sP/RX/rFnSt)=BS=H1@S=Z7@St'Fu>"(hJ8k_rJ6q'^A9gqH=8k_rJ6q'O477BU5 +8k_rJ6q(*E6"=G:H[C0fH[U6fI=$<hH[C0fH[U^'KR8&oH[C0bFEDkVI<TdTH[C0bFEDkVI=$<h +H[C0bFED_KFF/@_daZkJs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,kpA+@Sq<[_G +kj7crjQGI^kMYFag"bH:bfcNJS8)kX<)cjs<)m$o84lQM8k_rO9MJV_84lQM8k_rO9MJV_85rPg +8k_rO9MJJc<EMpc<)cji9MJJc<E)pt<)cjs<)m%*?;sm(=Bo03<)lms<E)pt<)cjs<)lms<CK;E +2)I-O4?ZYC<JGmJUnsm*`Pp9Tf!qi^=Bo07>[CN;?<CH==Bo0F>Zt67?<CH==Bo0F>Zt67?>!MH +=Bo03<)lms<E)pt<)cjs<)m%*?>!MH<)cjZ4?Z;19k.^FR?NiQ`PqKCq>^Kps8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W,kpA+(Hp%7tRkj7d%m-ilnkMYFag"bH;gtp`>hSdCPS=Z6tH[TXFDKg2EGB@qACi4H=FD>W0 +C2@d3FED_DCNjlBGB@qNFED_KFE_hKGB@qRH[U6fI<TdTH[C0bFED_KFE_hKC2@d&Ci4!(DJF!* +GB@qACi4H=FF/@_X/rG]jQHRCs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!o_/+QpA*q=n)39i +i8j(Sgtp`>hV$]@daZjreCMRW`MB?+N/NXAH[U*[FE_hKC2@d&Ci3`nARf7^C2@d&Ci4H=FE_hK +GB@q/>[Bl_4C_o5s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s7H$\m.9o6m-iW_hV$]@daZk$gtpK/f$`(!daZk$gtoug`Hur[H[C0fH[U6fI<TdT +H[C0bFED_KFD>W0C2@d3FEE=lKXA+nm.9oMs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!m.9o6m-iW_hV$]@ +bKS5Sbg")F`Pfa7`5T^&['WG!9m:]$H[C0fH[U6fI=$<hH[C0fH[U6fI=$<hH[C0sKS4]!I>EQ0 +LkLG;KS5/7KSY;7H[C1"Mi<UQN/3.?['[4?s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s6T@Mkj7crjQG4OhTO-f`5T^6`PoI%]sP/R]=bhh]Y1\Z[(Eua['[31St&DH9iP(l +8k_rY<)na-KT(hJN/NXNKS5;BN-fo"H[C0fH[U6fI=$<hH[C1"Mi<"0I>j)CLkLG.H[Uj2N-fo" +N/NXRMi@#op&G'ls8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!o_/+IoC_JAp#+oo +g"bH;gtpK/f$`(!bKS5L`PoI%]t:qj]=bha['[3I['[3I['[3@XKAk:[&^:1['[3@XKAP)XfJP* +X/rF^Mi<"0I=$<hN/NXAH[U6fI=$<hH[C0fH[U6fI=$<hH[C0bFED_KFE_hKH[C0UCi4H=FD>W0 +@q9.\A7]7]ASQ%!@q9.cCi4H=FD>W0GB@qRH[U6fI=$<hLkLG.H[Uj2N-fo"N/NXRMi<UQN1?K0 +`5T^qs8W-!s8W-!s8W-!s8V`bq<726i8j(LeCMgec,@T?['[3I['ZX*Unji_Unsl_V50o`Uj$Zk +2)I-I1c.'H1c7*H2)I-B/1iJ*/N#@A2)I-I1c.fu9knK^C2@d&Ci4!(DKg2EC2@d&Ci4!(DJF!* +C2@d&Ci4!(DJF!*C2@d&Ci4!(DJF!*C2@d&Ci4!(DS*Qpkj7ckgtpK/f#5PH]=bha['Zm8XdkuQ +S=Z7@St)=BS=H1@B3\V/6q'^A9iXVJ779RE76s@177BU5779R:9MIu>4@MY,779RH>[Dc(I>EQ0 +H[C0sKS5/7KSY;7LkLG.H[U6fI=$<hH[C0fH[U*[FF/@_GB@qNFED_KFE_hKGB@qNFEGs\f)PdM +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,kpA+@Sq=OCVkj7d%m-ilnkMYFa +g"bH;gto*5XbM4M<)cjs<)lOa9hJ)R8k_r]9LqcL9hJ)R8k_rO9MJ,Q9iP(l8k_rY<)lms<E)pt +=A27b<)lms<E)pt<)cjs<)m$o85rPg=A27b<)lms<E)pt@q9/,KS6k;Wm]DJi8j(ZjQG4OhVdJX +g"bGk['We3<E)pt<)cjs<)lms<E)pt<)cjs<)m$o85rPg<)cjs<)lms<E)pt<)ck"9Lr8j??^7% +H[C1"Mi<UQN2s%^g"bHNoC`.`s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,kpA+@Sq=j7= +kj7d%m-j0)n)39ii8j(Sgtp`>hU9p)['[3!Mi;k%FE_hKC2@d3FED86DKg2EGB@qNFED_KFD>W0 +GB@qNFED_KFF/@_H[C0fH[U6fI<TdTGB@qACi4!(DJF!*C2@d&Ci4THI@Qn!bKS62s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s7H$\o_/+Em-j0)n*'-,i8j(ZjQG4OhV$]@ +g"bH;gtpK/f"8T.R?NhYFED86DI[3g=Bo07>[CN;?>=:o@q9.cCi3`nAO\gF=Bo2!oC`.`s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8V`bq<726 +kj7crjQG4OhWEVKg"bH;gtq2KgtCK>i8j(.['YXBKR8&oGB@qRH[U*[FD>W0C2@d&Ci52iN6BGi +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,kpA+@Sq<726g"bH;gtp5uc-+>U`5T^6`Pp$Ec%^Um +=Bo0VFED_KFE_hKGB@qNFED_KFE_hKGB@qRH[U6fI=$<hH[C0sKS5/7KT(hJN/NXRMi<UQN/W[R +H[C1"Mi@]9s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8VHWp#+oo +g"bH4eCMRW`Pfa7]=bhh]Y1\Z['[3I['[3P]Y1\Z[%sOo8k_rY<)lOa9iP(lH[C0sKS5/7KSY;7 +LkLG;KS5/7KSY;7H[C0fH[U6fI=$<hH[C0sKS4]!I>EQ0LkLG?Mi<IFKT(hJdaZkJs8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!m.9o:oC_>6n)39ig"bH;gtpK/f$`(! +bKS5L`Pod7`Oidr]=bhh]Y1\Z['[3I['[3I['Zm8XgGIBX/rG(XKAP)XfJP*X/rG!V50'.N/W[R +N/NXRMi<"0I=$<hH[C0fH[U6fI<TdTC2@d3FED_KFD>W0GB@qACi4!(DI[3g@q9.\A7]7]ASQ%! +C2@d3FED_KFE_hKH[C0fH[U6fI>EQ0H[C0sKS5;BN1#ln`5T^qs8W-!s8W-!s8W-!s8W-!s8W-! +m.9o6m-iW_hU9p)bKS5L`PoI%]rS6:X/rG!V51/nXe_ehUnsl6H[S=N77KF&2)I-Z4ZkSY1c7*H +2)I-I1c.'H1bL=2779RZCi4!(DJF!*C2@d&Ci3`nASQ%!@q9.\A7]7]ASQ%!@q9.\A7]7]ARf7^ +@q9.\A7]7]ASQ%!C2@e"]Y37akLnYIdaZjkbg!c4]sP/RX/rFnSt)UQUn"$HUnslWSt'P3DFHr^ +779R56q'O477BU5779R:9MJ,Q9gqH=8k_rO9MIrD79Ef$H[C0sKS5/7KR8&oLkLG.H[U^'KT(hJ +H[C0sKS4]!I=$<hGB@qNFED86DJF!*C2@d3FED_KFE_hKdaZkJs8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!o_/+QpA+(Hp#tc2kj7d%m-ilnkMYFag"bHBjQFJ#`LNNi +GAV+p<)lOa9hJ)R8k_rO9MJ,Q9hJ)R8k_rO9MJ,Q9iP(l<)cjs<)lms<E)pt<)cjs<)lms<E)pt +8k_rY<)n-aFIA>V]=bi1gtq8]n*'-,kj7d%m-j0)n*'-,kj7crjQGI^kI\C?=Bo07>[CB/<E)pt +<)ck-A7]LlDKg2EH[C1"Mi=0tS><!W['[3[]Xl;1c.Un/i8j(bm-j<4p$D;Co_/+QpA+@Sq>^Kp +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,kpA+@Sq=OCVkj7d%m-j0)n*'-, +i8j(ZjQGI^kLnYIdaZjT['Z6bPC%Y)GB@qACi4H=FD>W0H[C0bFEDkVI<TdTH[C0fH[U6fI=$<h +H[C0bFED86DKg2EC2@d7H[V<GPJkGZm.9oMs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8V`bq>^Kpo_/+Em-j0)n*'-,i8j(ZjQGI^kLnYIi8j(ZjQGI^kL.l2 +['[2rKS3H4?<CH=@q9.\A7]7]ASQ%!779S'Mi@]9s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,kpA+(Hp#tc2kj7crjQGann)39i +kj7d%m-j<4p#tc2R?Nh]H[U6fI<TdTGB@qRH[V]dV!.16s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s7H$\m.9o.jQG[\gsX^'bKS5Sbg")F`Pfa7['[249MK8<DJF!*GB@qNFED_KFE_hK +GB@qACi4THI;3S9H[C0fH[U6fI>j)CLkLG;KS5;BN/3.?N/NXNKS5/7KWD2Vs8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!m.9o6m-ilnkLnYIbKS5L`PoI%]t:qj +['[3[]Xk_f]sP/R]=bhQV5-^W9it([8k_r]9LrZ(AVc"mLkLG;KS4]!I>j)CH[C0fH[U6fI=$<h +H[C0fH[U6fI=$<hH[C0fH[U6fI>j)CH[C0fH[WN=^&S-4s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s7H$\m.9o6m-ilnkMYFag"bH;gtpK/f$`(!bKS5Sbg")F`Pfa7 +]=bhh]Y1qi]sP/R]=bha['[3I['[3I['[3I['[3I['[3I['[3I['Zm8XdkuQLkLG.H[U6fI=$<h +H[C0UCi4H=FD>W0C2@d3FED86DJF!*@q9.\A7]7]ARf7^@q9.\A7]LlDJF!*C2@d7H[U6fI=$<h +H[C0fH[Uj2N3ot!g"bHVpA+ags8W-!s8W-!s8W-!s8W-!s8W-!s8V`bq<726i8j(SgtpK/f#u:^ +]=bhh]Y1AIXgGIB['[3I['[3I['[3IUnslGMi;jsCJ%8p7Qik'4Zkeg4Z,&Q2)I-I1c.Wh7;?XV +C2@d&Ci4!(DJF!*@q9.cCi3`nASQ%!@q9.\A7]LlDI[3g@q9.\A7]7]ARf7^@q9.\A7]LlDS*Qp +kj7ckgtp`>hTO-f`5T^-]Y1\Z[&^:1UnslfXKAP)XfJP*X/rG!V50'.N-BAc=Bo0)9MJ,Q9gqH= +<CK2B6q'^A9gqH=8k_r]>[Dc(I>EQ0LkLG;KS5/7KR8&oLkLG.H[U^'KR8&oH[C0fH[U6fI;3S9 +GB@qNFED_KFD>W0GB@qACi7\Nf)PdMs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W,kpA+@Sq<726kj7d%m-j0)n)39ii8j(ZjQG4OhTO-fUnsl6H[TC7AP,Wj +8k_rO9MJ,Q9iP(l8k_rY<)lms<E)pt<)cjs<)m%*?>=:oLkLGOSt*F*^#7u7kj7d%m-j<4p%7tR +o_/+QpA+@Sq=OCVm.9o:oC_kEkNM:$kj7ckgto*5Xh26Z`5T^=bg"hrhVdJXi8j(bm-j0)n*'-, +kj7d%m-j0)n*'-,m.9o:oC_bLq=OCVo_/+QpA+ags8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8V`bq=OCVp[%)0oC_>6n*'-,kj7d%m-ilnkMYFa +i8j(Sgtoug`MB?+S=Z7,KS4]!I<TdTGB@qNFEDkVI<TdTGB@qACi4THI>j)CS=Z7X['\92f(A\3 +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s7H$\o_/+IoC_JAp#tc2kj7d%m-j0)n*'-,i8j(foC_>6n*KZ=g"bG[V5/<WFD>W0 +@q9.cCi7G?c2[hDs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!o_/+QpA+ILkNqg5kj7d)oC_JAp%7tRo_/+QpA*Y-kBhQ( +H[C1"Mi>Tn`Urm"s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,kpA*q=n)39i +g"bH4eCMgec-+>U`5T^6`PmXdKN(oNGB@qNFEDkVI=$<hGB@qRH[U6fI=$<hH[C0bFED86DL6_Y +H[C0fH[U6fI=$<hLkLG;KS5/7KT(hJLkLHJoC`.`s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!o_/+\s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8V`bq<726i8j(SgtpK/f#5PH`k8mp]Y1qi]sP/R]=bha['[3I[%*_X +8k_rO9MJ,Q9hJ)R=Bo0gKS5;BN-fo"N/NXAH[U6fI=$<hH[C0fH[TXFDKg2EH[C0fH[U6fI=$<h +H[C0fH[U^'KR8&oX/rH's8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8V`bq=OCVm.9o:oC_&&kMYFag"bH;gtpK/f$`(!bKS5Sbg">Tc,@T?`5T^6`PoI%]t:qj +]=bhh]Y1qi]t:qj]=bhh]Y1qi]u7n/]=bhq`PoI%]sP/RS=Z7,KS4]!I=$<hC2@d&Ci4!(DJF!* +C2@ctA7]7]ARf7^=Bo0BA7]7]ARf7^C2@d&Ci4!(DJF!*LkLGOSt*a<`TZ[Ws8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!o_/+IoC_>6n)39ig"bH4eCMRW`Pfa7]=bha['[HX]t:qj +]=bhh]Y1qi]t:qj`5T^-]Y1,;Ul:4j@q9.>6q'R.4@VIr8k_s'FED_KFD>W0C2@d3FED86DJF!* +C2@d&Ci4THI=$<hN/NXbSt)UQUpRM9]=bi#bg"Scf&5WPkj7d%m-j0)n)39ig"bH4eCN'tf#5PH +]=bha['[3I['[3I['[3I['[3I[(Eua['[3I['[HX]sP/RS=Z70Mi;CeDH'S87Qik&6q(*E6!.Au +H[C0sKS5/7KSY;7N/NXAH[U^'KR8&oH[C1"Mi<UQN1?K0UnslfXKB+I]t:qjbKS5agtq8]n*KZ= +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +o_/+\s8V`bq<726kj7d%m-j0)n)39ii8j(ZjQGI^kMYFag"bH-bg!N%[%*_XQ]-fXKS5/7KT(hJ +N/NXbSt*0p[)Br&daZk+jQGann*'-,kj7d)oC_JAp%7tRo_/+QpA+ags8W-!o_/+\s8V`bq=OCV +o_/+QpA+@Sq=OCVkj7d%m-j0)n*'-,kj7d%m-j<4p#tc2o_/+Em-jT?q=OCVm.9oBpA+@Sq=OCV +o_/+\s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s7H$\o_/+IoC_JAp#tc2kj7d%m-j0)n*'-,kj7d%m-j0)n*'-, +g"bH4eCMRW`Oidr`5T^-]Y2M4c.Un/kj7d)oC`.`s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s7H$\ +o_/+QpA+(Hp$D;Cm.9o:oC_JAp$D;Co_/+QpA+ags8W-!s8W,PgtoEF[/^1+s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W,kpA+@Sq=OCVs8W-!s8W-!s8W-!s8W,Pgtp`>hXpO;s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s7H$\kj7ckgtpK/f$`(!bKS5L`Pod7`Q#R% +8k_roCi4!(DKg2EH[C0UCi4THI=$<hGB@qNFED86DJF!*C2@d7H[TXFDL6_YH[C1"Mi<"0I>j)C +H[C1"Mi=0tSH&Whs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,+['WG!:"e=Y +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W,coC_&&kLnYIdaZjd`Pod7`Oidr['[3I['[3I[(Eua]=bhDN/C5$9gqH=8k_rO9MJJc<JZ<] +H[C1"Mi<"0I>j)CH[C0fH[U6fI=$<hH[C0UCi4THI;3S9H[C0fH[U6fI=$<hH[C0fH[VEUSH&Wh +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8V`bq=OCV +m.9o6m-ilnkMYFag"bH;gtp`>hU9p)daZjkbg">Tc-+>UbKS5Sbg")F`QQKM`5T^6`Pod7`Pfa7 +`5T^6`Pp$Ec,@T?daZjkbg"Scf#u:^]=bhXXKA"aS9oU2GB@qACi4!(DI[3g@q9.\A7]7]ARf7^ +@q9.pFEEJ"N2s%^bKS5toC_bLq>^Kps8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8V`bq<[_Gkj7crjQG4OhV$]@bKS5Sbg")F`Pfa7`5T^6`Pod7`QQKMbKS5Sbg")F`QQKM +bKS5ZeCN'tf$`(!X/rF^Mi;CeDN'L4S=Z7OXKB+I]u7n/daZk+jQGann+?>Ls8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8VHWp$D;Cm.9o6m-ilnkLnYIdaZjd`Pod7`Oidr]=bhh]Y1qi]t:qj +`5T^-]Y28&`Oidr`5T^6`Pp$Ec-k+mdaZk$gtoug`MB?+LkLG.H[VEUS?&`n['[3Y`Pp$Ec.Un/ +i8j(bm-j<4p%7tRs8W-!s8W-!s8W-!o_/+\s8W-!s7H$\s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,kpA+@Sq=OCV +m.9o:oC_>6n*'-,kj7d%m-ilnkNM:$i8j(ZjQGI^kMYFai8j(ZjQGann*'-,kj7d%m-j0)n*'-, +m.9o:oC_bLq=OCVo_/+\s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,kpA+@Sq=OCV +o_/+QpA+@Sq=OCVo_/+QpA+@Sq=OCVs8W,kpA+ags8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!o_/+IoC`.`s6T@Mm.9o:oC_JAp$D;Cm.9o:oC_JAp$D;Cm.9o:oC_JAp%7tR +o_/+QpA+ags8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s7H$\ +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!o_/+Em-ilnkLnYIdaZjkbg">Tc-+>U`5T]SMi:8%9m:]$C2@d3FED_KFE_hK +C2@d&Ci4THI;3S9H[C0UCi4!(DJF!*H[C0UCi4THI=$<hH[C0fH[U6fI=$<hi8j)$s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8UNsejVtq779R:9MNsbf)PdMs8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8V`bq<[_Gkj7crjQFt@f#u:^ +]=bhh]Y1qi]t:qj['[3P]Y1\Z[!-V6779R:9MJ,Q9hJ)R8k_s<Mi<"0I>j)CH[C0fH[U6fI=$<h +H[C0fH[U6fI<TdTH[C0fH[TXFDL6_YC2@d7H[U6fI=$<hR?Nj7s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8V`bq=OCVm.9o:oC_>6n)39i +i8j(Sgtp`>hV$]@g"bH4eCN'tf#u:^daZjkbg">Tc-k+mbKS5ZeCN'tf$`(!daZjreCN'tf$`(! +g"bH;gtpuMkMYFai8j(bm-iW_hTO-f`5T^-]Y28&`OidrdaZk+jQGn$p&G'ls8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,coC_JAp$D;C +i8j(Sgtp`>hU9p)bKS5Sbg">Tc-k+mdaZjkbg">Tc-+>UdaZjreCN'tf%Jj8i8j(ZjQGann*KZ= +o_/+\s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W,coC_JAp#tc2i8j(Sgtp`>hU9p)daZjd`Pod7`Pfa7`5T^=bg")F`Pfa7bKS5Sbg">Tc-+>U +daZk$gtpuMkMYFai8j(foC_JAp$D;Co_/+QpA+@Sq=OCVo_/+QpA+@Sq>^Kps8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8V`bq=OCVm.9oBpA*q=n*KZ= +kj7d%m-j0)n*'-,kj7d)oC_>6n*KZ=kj7d)oC_>6n+?>Lo_/+QpA+@Sq=OCVs8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s7H$\s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W,kpA+ags8W-!s8W,kpA+ags8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8VHWp#tc2 +g"bH;gtpK/f#u:^`5T^6`PoI%]h1sm@q9.cCi4!(DKg2EC2@d&Ci4!(DKg2EC2@d7H[TXFDJF!* +C2@d&Ci4!(DJF!*C2@d7H[U6fI=$<hH[C1"Mi@]9s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s5;u$779R+4?Z.s4@MY,8k_t-eCO["s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,coC_>6n(HLQdaZjkbg")F`Oidr['[3I['[HX]sP/R +['[2><)l@T77p6J779R:9MJ,Q9m_58H[C1"Mi<"0I=$<hH[C0fH[U6fI=$<hH[C0fH[TXFDL6_Y +C2@d7H[U*[FE_hKC2@d7H[Uj2N;rqXs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8V`bq=OCVm.9o:oC_JAp#+ooi8j(ZjQG4OhV$]@ +g"bH;gtp`>hV$]@g"bH;gtp`>hV$]@g"bH;gtp`>hV$]@i8j(ZjQGI^kMYFai8j(bm-j0)n*KZ= +m.9o:oC_bLq=OCVs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!m.9o:oC_>6n*'-,g"bH;gtpK/f%Jj8 +g"bH;gtpK/f%Jj8g"bH;gtp`>hV$]@i8j(ZjQGI^kNqg5m.9oBpA+@Sq=OCVs8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s7H$\m.9o:oC_JAp#+oo +i8j(SgtpK/f$`(!daZjkbg"Scf$`(!daZjreCN'tf$`(!daZjreCN=.hV$]@i8j(bm-j<4p$D;C +m.9oBpA+ags8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s7H$\o_/+QpA+@Sq=OCVo_/+QpA+@Sq=OCV +m.9oBpA+@Sq=OCVo_/+QpA+ags8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s7H$\kj7crjQG4OhU9p)bKS5Sbg")F`QQKM +N/NWe9MK8<DJF!*C2@d&Ci4!(DJF!*C2@d&Ci4!(DJF!*C2@d&Ci4!(DKg2EC2@d&Ci4!(DJF!* +C2@d7H[TXFDUR%cs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!o_/+QpA+@Sq>^Kpkj7b;<)l"B4Zbbh +4$5Yf4?Z;19o+IUs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s6T@Mkj7crjQFt@f#u:^`5T^-]Y1qi]sP/R]=bha['Z6bP=7l.779R56q'^A9gqH= +=Bo0kMi<"0I=$<hH[C0fH[U6fI=$<hH[C0fH[TXFDL6_YH[C0UCi4THI;3S9C2@d7H[TXFDKg2E +N/NYps8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W,kpA+@Sq<[_Gm.9o:oC_>6n*'-,i8j(ZjQGI^kLnYIi8j(Sgtp`>hV$]@ +g"bHBjQG4OhVdJXi8j(ZjQGI^kMYFakj7d%m-j<4p$D;Cm.9o:oC_bLq>^Kps8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W,kpA+(Hp$D;Cm.9o6m-ilnkMYFag"bH;gtp`>hV$]@g"bHBjQG4OhVdJX +i8j(ZjQGI^kMYFakj7d)oC_JAp$D;Co_/+\s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,kpA+(Hp$D;Ckj7d%m-ilnkMYFag"bH4eCN'tf$`(! +daZjreCN'tf$`(!daZk$gtp`>hV$]@i8j(ZjQGann*KZ=m.9o:oC_bLq=OCVs8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W,kpA+ags7H$\o_/+QpA+@Sq=OCVm.9oBpA+ags7H$\o_/+\s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W,kpA*q=n)39idaZk#bfe2Rc,@T?bKS5N]Xg^/9knK^C2@d&Ci4!(DJF!* +C2@d&Ci4!(DJF!*C2@d&Ci4!(DJF!*H[C0UCi4!(DJF!*C2@d&Ci4!(DJF!*H[C2@s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!m.9o:oC_>6n*KZ=m.9o6m-eFpAMl;$2)I-O4?Ybg4[hb-@q9.tH[WiO`W,u< +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,coC_>6n(HLQ +g"bH-bg")F`O*"Z]=bha['[HX]sP/R@q9.>6q'O479)cB779R56q(TrAUAcPH[C0fH[U6fI=$<h +H[C0fH[U6fI;3S9H[C0UCi4!(DL6_YC2@d7H[TXFDL6_YC2@d&Ci6&FV#UJps8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s7H$\ +o_/+IoC_JAp#tc2i8j(bm-ilnkMYFai8j(SgtpuMkLnYIi8j(Sgtp`>hV$]@i8j(ZjQGI^kMYFa +i8j(bm-j0)n*'-,kj7d)oC_JAp$D;Co_/+QpA+ags8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8V`bq=OCV +m.9o:oC_>6n*'-,i8j(ZjQG4OhV$]@g"bHBjQG4OhV$]@i8j(ZjQG4OhVdJXi8j(ZjQGann*'-, +m.9o:oC_bLq=OCVo_/+\s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8VHWp$D;Cm.9o6m-j0)n)39ii8j(Sgtp`>hU9p)daZk$gtpK/f%Jj8daZk$gtp`>hU9p) +g"bH;gtpuMkMYFam.9o6m-j<4p$D;Co_/+\s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,kpA+ags7H$\ +o_/+\s8V`bq=OCVo_/+QpA+@Sq=OCVo_/+QpA+@Sq=OCVo_/+QpA+ags8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8V`bq<726 +i8j(SgtpK/f#u:^bKS5Sbg")F`Jf_68k_rhA7]LlDJF!*C2@d&Ci4!(DJF!*C2@d&Ci4!(DJF!* +C2@d&Ci4!(DJF!*C2@d&Ci4!(DJF!*C2@d&Ci721`W,u<s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,coC_>6n*'-, +i8j(ZjQGI^kBhQ(/hAS31c.'H1cmf_4$5Z.>[Dc(I=$<hH[C2@s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s6T@Mkj7ckgtpK/f#u:^]=bhh]Y1\Z[(Eua +['[31St&5;77KF&779R56q'O477BU5C2@d7H[U6fI=$<hH[C0fH[TXFDL6_YC2@d&Ci4!(DJF!* +C2@d&Ci4!(DJF!*H[C0UCi4!(DJF!*['[4?s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,kpA+@Sq=OCVm.9o6m-j0)n)39i +i8j(ZjQG4OhVdJXg"bH;gtp`>hVdJXg"bHBjQG4OhVdJXi8j(ZjQGann)39ikj7d%m-j0)n*KZ= +m.9oBpA+@Sq=OCVs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8V`bq=OCVm.9o:oC_JAp#tc2kj7crjQGI^kLnYI +g"bH;gtpuMkLnYIi8j(ZjQG4OhVdJXi8j(ZjQGI^kMYFakj7d%m-j0)n*KZ=m.9o:oC_JAp$D;C +o_/+QpA+@Sq=OCVo_/+QpA+@Sq=OCVo_/+QpA+@Sq=OCVo_/+QpA+(Hp$D;Cm.9o6m-j0)n*'-, +i8j(ZjQG4OhV$]@g"bH4eCN'tf$`(!g"bH4eCN=.hU9p)daZk$gtp`>hVdJXi8j(ZjQGI^kNqg5 +m.9o:oC_bLq=OCVs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!o_/+QpA+@Sq=OCVo_/+QpA+@Sq=OCV +o_/+QpA+@Sq=OCVo_/+QpA+@Sq>^Kpo_/+\s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!o_/+Em-ilnkL.l2daZjkbg")F`Pfa7 +`5T\p<)mF=ARf7^@q9.\A7]LlDJF!*C2@d&Ci4!(DJF!*C2@d&Ci4!(DJF!*C2@d&Ci4!(DJF!* +C2@d&Ci4!(DJF!*o_/+\s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,kpA+(Hp#tc2i8j(Sgtp`>hV$]@R?Ngl1c-g9/N#@A +/hAS31c.fu9m:]$GB@qRH[U6fI@Qn!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W,coC_>6n(HLQdaZjkbg")F`Oidr['[3I['[3IZrgR>4$5Yf4?Z,$77BU5 +779R:9MKk\I=$<hH[C0fH[U6fI=$<hC2@d&Ci4!(DJF!*C2@d&Ci4!(DJF!*C2@d&Ci4!(DL6_Y +C2@d&Ci7\Nf)PdMs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8V`bq=OCVm.9o:oC_JAp#tc2kj7crjQGI^kMYFai8j(SgtpuMkLnYI +g"bH;gtpuMkLnYIi8j(ZjQGI^kMYFai8j(bm-j0)n*'-,m.9o:oC_JAp$D;Cm.9oBpA+(Hp%7tR +o_/+\s8V`bq>^Kpo_/+\s8V`bq=OCVs8W,kpA+@Sq=OCVo_/+QpA+@Sq=OCVo_/+IoC_bLq<[_G +o_/+IoC_bLq<[_Gm.9o:oC_>6n*'-,i8j(bm-ilnkMYFai8j(SgtpuMkLnYIg"bH;gtp`>hVdJX +g"bHBjQG4OhVdJXi8j(ZjQGann)39ikj7d%m-j0)n*KZ=m.9o6m-j<4p$D;Cm.9o6m-j<4p#tc2 +kj7d%m-j0)n*'-,kj7d%m-j<4p#tc2kj7d%m-j0)n)39ii8j(ZjQG4OhV$]@g"bH;gtpK/f$`(! +daZjreCN'tf%Jj8g"bH;gtpK/f%Jj8daZk$gtpuMkMYFakj7d)oC_JAp$D;Co_/+QpA+ags8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!o_/+QpA+@Sq=OCVo_/+QpA+@Sq=OCVo_/+QpA+@Sq=OCVo_/+QpA+@Sq=OCV +o_/+QpA+ags8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W,kpA*q=n)39ig"bH4eCMgec-+>UbKS5L`Pn7/P<1li@q9.\A7]7]ARf7^ +@q9.\A7]LlDI[3gC2@d&Ci4!(DJF!*@q9.\A7]7]ASQ%!C2@d&Ci4!(DJF!*@q9/OXKDO&s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s6T@Mkj7ckgtp`>hU9p)daZjDV5-184Z,&Q/hAS,/1i_91cmf_C2@d&Ci4!(DKg2E +H[C0fH[WiO`W,u<s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8V`bq<726 +i8j(SgtpK/f#5PH]=bhh]Y1qi]sP/RLkLFC4?Ybg4Zbbh4$5Yf4?Z,$7:Tk>H[C0fH[U6fI=$<h +H[C0UCi4THI;3S9C2@d&Ci3`nARf7^@q9.\A7]7]ARf7^C2@d&Ci4!(DJF!*i8j)$s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s7H$\s8W,kpA+ags7H$\s8W,kpA+@Sq>^Kpo_/+QpA+(Hp#tc2 +kj7d%m-j0)n)39ii8j(ZjQGI^kLnYIg"bH;gtpK/f$`(!bKS5ZeCN'tf$`(!bKS5ZeCN'tf$`(! +daZjreCN'tf$`(!daZjreCN=.hV$]@g"bH;gtpuMkLnYIg"bH;gtp`>hV$]@g"bH;gtp`>hU9p) +g"bH4eCN'tf$`(!daZjreCN'tf$`(!daZjreCMgec-k+mbKS5Sbg">Tc-+>UbKS5Sbg">Tc,@T? +`5T^6`Pod7`Pfa7]=bhh]Y1qi]t:qj]=bhh]Y1qi]t:qj]=bhh]Y1qi]t:qj['[3P]Y1qi]t:qj +]=bhh]Y1qi]t:qj]=bhh]Y1qi]sP/R]=bha['[3I[(Eua['[3I['[3I[(Eua['[3@XKAk:[&^:1 +['[3@XKAk:[&^:1X/rG(XKA:pUoUT!Unsl_V50WQS><!WS=Z7@St)=BS><!WS=Z7@St)=BS=H1@ +S=Z7@St)=BS=H1@Unsl_V50o`UoUT!X/rG(XKAk:['[3I['[3P]Y1qi^!"XEs8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!kj7cF['Z?pS=H1@S=Z7@St)=BS=,S)S=Z7@St)44PFS57S=Z7=PEVN.S=H1@ +S=Z70Mi=0tS=H1@N/NXbSt)44PF7VuS=Z7=PEVDuPF7VuR?Ni&PEVDuPF7VuN/NX_PEVDuPF7Vu +R?Ni&PEUr`N/W[RN/NX_PEUr`N/W[RR?NhnMi<UQN1#lnN/NXRMi<UQN/W[RN/NXRMi<UQN/W[R +N/NXRMi<UQN/W[RLkLG;KS5/7KSY;7LkLG?Mi<IFKSY;7N/NXNKS5;BN/3.?LkLG;KS5/7KSY;7 +H[C1"Mi<IFKSY;7H[C0sKS4]!I>3,rH[C0fH[U^'KR8&oH[C0qI!^3eI=$<hH[C0fH[U6fI=$<h +H[C0fH[U6fI=$<hH[C0bFEDkVI<TdTGB@qNFED_KFE_hKGB@qNFED_KFE_hKGB@qNFED86DKg2E +C2@d3FED86DKg2EC2@d3FED86DKg2EC2@d&Ci4!(DJF!*C2@d&Ci4!(DJF!*C2@d&Ci4!(DJF!* +C2@ctA7]LlDI[3gC2@ctA7]LlDI[3gC2@ctA7]LlDJ*3X@q9.\A7]7]AS57O@q9.\A7]7]ARf7^ +@q9.\A7\kJ?>!MH=Bo0F>Zt67?=RMW=Bo0F>Zt67?>!MH=Bo07>[CB/<ENL4<)ck">[CB/<ENL4 +<)ck">[CB/<ENL4<)cjs<)lms<E)pt<)cjs<)lms<E)pt<)cjs<)lOa9it([8k_r]9LqcL9it([ +8k_rO9MJV_84lQM=A27X9MIrD77p6J779R:9MJ,Q9gqH==A27X9MIrD77p6J779R56q'O477BU5 +779R56q'O477BU5779R56q'O477KF&4$5Yp6q'1"4[qRs4$5Yq4Zkeg4[qRs4$5Yq4Zkeg4Z,&Q +4$5Y`1c.9V4Z,&Q4$5Y`1c.9V4Z,&Q4$5Y`1c.'H1c7*H2)I-I1c.'H1c7*H2)I-I1c.'H1c7*H +/hAS31c-g9/M8S+/hAS,/1i_91bL=22)I-I1c.'H1bL=22)I-B/1iJ*/M8S+/hASe>[%1-s6T@M +kj7crjQG4OhU9p)bKS5L`Pod7`Pfa7<)cjs<)mF=ARf7^=Bo0BA7]7]AQW2D@q9.Q>[CoNAQW2D +@q9.\A7]7]AQW2D@q9.cCi3`nARf7^@q9.\A7]7]AaK$]s8W-!s8W-!s8W-!s8W-!s8W-!s+YoJ +'b1Zk)]BG$%2B?^)B0S0%Lj-_%2B?^'b1Zf%Lj-_%2B?^'b1Zf%Lj-_%2B?^$k!IP$OdFO$l'6] +$k!IY%Lj-_%2B?^'b1Zf%Lj-_%H-=1s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!m.9o6m-iW_hV$]@ +daZjkbg!N%ZpdAO2)I-I1c.'H1bL=24$5Z9A7]7]ASQ%!C2@d3FEDkVI<TdTH[C1ogtr)2s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!m.9o6m-iW_hV$]@bKS5L`Pod7`Oidr +['[3!Mi9_[4Z,&Q4$5Yf4?Ybg4[hb-779RZCi4THI=$<hH[C0UCi4THI;3S9C2@d&Ci4!(DJF!* +@q9.\A7]7]AQW2D=Bo07>[CoNARf7^C2@d7H[Xi5k7nI9"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/ +"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/ +"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/ +"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/ +"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/ +"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/ +"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/ +"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/ +"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-">25WH[C1abg$1fs8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8V<Ln$KI/C2@c+)]Ah\"9\c/ +"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/ +"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/ +"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/ +"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/ +"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/ +"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/ +"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/ +"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/ +"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/ +"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/ +"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/ +"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/ +"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/ +"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"B\o8o_/+Em-ilnkLnYIdaZjkbg">Tc,@T? +`5T]cSt%Yp1h1'-@q9.Q>[CoNARf7^@q9.\A7\kJ?=RMW=Bo07>[CoNAQW2D@q9.\A7]7]ARf7^ +@q9.\A7]7]AQW2DS=Z8Ns8W-!s8W-!s8W-!s8W-!s7H$\i8j&(!X&W-"9\c/"9J]/!X&W-"9\c/ +"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/ +"9J]O,:*<hs8W-!s8W-!s8W-!s8W-!s8W,coC_>6n(HLQg"bH4eCMgec+CX%<)cjZ4?YPY1c7*H +2)I-O4?ZeO?>=:o@q9.cCi4!(DJF!*C2@d3FEDkVI>j)CdaZkJs8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W,coC_>6n)39ig"bH4eCN'tf#5PH]=bha['Y1,I5Ni<2)I-I1c.9V4Z,&Q +4$5Yf4?ZeO?@.$IC2@d7H[TXFDL6_YC2@d7H[TXFDJF!*C2@ctA7]7]ARf7^=Bo0BA7\kJ?<CH= +@q9.\A7]LlDOd;gS=Z5R!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/ +"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/ +"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/ +"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/ +"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/ +"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/ +"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/ +"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/ +"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]`1c0Q+IF?Wrs8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!o_/*m]Y/&rDBpGP"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/ +"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/ +"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/ +"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/ +"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/ +"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/ +"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/ +"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/ +"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/ +"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/ +"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/ +"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/ +"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/ +"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/ +"9J]/!X&W-"9\c/"9J_<]Y3\'p#tc2i8j(Sgtp]-bKJ,SbKS5L`Pod7`E6AO8k_rhA7\kJ?>=:o +@q9.\A7]7]ARf7^@q9.Q>[CoNARf7^@q9.\A7]7]ASQ%!@q9.Q>[CoNAQW2D@q9.Q>[H+=hZ*WU +s8W-!s8V`bq=OCVm.9o:oC[<LF9DXJ"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/ +"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/Unsmes8W-!s8W-! +s8W-!s8V`bq<726i8j(SgtpK/f#u:^`5T]1Ci2<s4Zbbh2)I-I1c.'H1fRFSC2@d&Ci4!(DJF!* +C2@d7H[U6fI=$<hGB@qRH[TXFDN'L4daZkJs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8VHWp#tc2 +i8j(ZjQFt@f#u:^`5T^6`Pn@=S4ZIL/hAS,/1iJ*/M8S+2)I-I1c.9V4[hb-C2@d&Ci4H=FD>W0 +H[C0UCi4!(DJF!*C2@ctA7]7]AQW2D@q9.\A7]7]ARf7^=Bo0BA7]7]ASQ%!C2@dp['VG:/Hc+X +"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/ +"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/ +"9J]/!X&W-"9\c/"9J]/!X&W-"9\c/(BO^B!X&W-"9\c/(BO^B!X&W-"9\c/(BO^B!X';@"9\c/ +(BO^B!X';@"9\c/(BO^B!X';@"9\c/(BO^U!X&W-";_+B(BO^U!X&W-";_+B(BO^U!X&W-";_+B +(BO^U!X';@";_+B(BO^U!X';@";_+B(BO^U!X';@";_+B(BO^U!X';@";_+B(BO^U!X';@";_+B +(BO^U!X';@";_+B(BO^U!X';@";_+B(BO^U!X';@";_+B(BO^e!X';@"=F6R(BO^e!X';@"=F6R +(BO^U!X'kP";_+B-NXDe!X'kP";_+B-NXDe!X'kP";_+B-NXDe!X'kP"=F6R-NXDu!X'kP"=F6R +-NXDu!X'kP"=F6R-NXDu!X'kP"=F6R-NXDu!X'kP"=F6R-NXDu!X'kP"=F6R-NXDu!X'kP"=F6R +-NXDu!X'kP"=F6R-NXDu!X)U,"K"R;ke+/"s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W+r>=DWq"?HSe +3W]FF!X(Oc"?HSe3W]FF!X)$q"?HSe3W]FF!X(Oc"@rRs3W]FF!X)$q"?HSe3W]FT!X)$q"?HSe +8-/ob!X(Oc"@rRs8-/oT!X)$q"@rRs8-/ob!X)$q"@rRs8-/ob!X)$q"@rRs8-/ob!X)$q"@rRs +8-/ob!X)$q"@rRs8-/ob!X)$q"@rRs8-/or!X)$q"BY^.8-/ob!X)U,"@rRs=98Ur!X)U,"@rRs +=98V-!X)$q"BY^.=98V-!X)U,"BY^.=98V-!X)U,"BY^.=98V-!X)U,"BY^.=98V-!X)U,"BY^. +=98V-!X)U,"BY^.=98V=!X)U,"BY^.=98V-!X*0<"BY^.=98V=!X)U,"D@i>=98V=!X)U,"D@i> +=98V=!X)U,"D@i>BEA<M!X*0<"D@i>BEA<M!X*0<"D@i>BEA<M!X*0<"D@i>BEA<M!X*0<"D@i> +BEA<M!X*0<"D@i>BEA<M!X*0<"F1%OBEA<M!X*cM"D@i>BEA<M!X*cM"D@i>Gle+^!X*cM"D@i> +Gle+o!X*0<"F1%OGle+^!X*cM"F1%OGle+o!X*cM"F1%OGle+o!X*cM"F1%OGle+o!X*cM"F1%O +Gle+o!X*cM"F1%OGle+o!X*cM"F1%OGle,)!X*cM"Gd*^Gle,)!X*cM"Gd*^Gle,)!X*cM"Gd*^ +L]R^8!X+;\"F1%OL]R^8!X+;\"Gd*^L]R^8!X+;\"Gd*^L]R^8!X+;\"Gd*^L]R^8!X+;\"Gd*^ +L]R^8!X+;\"Gd*^L]R^8!X+;\"Gd*^L]R^8!X+;\"Gd*^L]R^D!X+_h"Gd*^PQCuP!X+;\"I&rj +PQCuD!X+_h"I&rjPQCuP!X+_h"I&rjPQCuP!X+_h"I&rjPQCuP!X+_h"J>f!PQCu\!X+_h"J>f! +PQCu\!X+_h"J>f!PQCu\!X,.t"J>f!PQCu\!X,.t"J>f!TE57h!X,.t"J>f!TE57h!X,.t"J>f! +TE57h!X,.t"J>f!TE57h!X,.t"J>f!TE57h!X,.t"J>f!TE57h!X,.t"J>f!TE57h!X-G"3:-80 +p[%)$jQG4OhU9p)bKS5Sbg")F`Pfa7UnskK4?ZeO?<CH==Bo0ICi4!(DI[3gC2@ctA7]7]ARf7^ +=Bo0BA7]7]ARf7^@q9.cCi4!(DI[3g@q9.Q>[CN;?Asf$s8W-!s8W-!s7H$\m.9o6m-j0)n(HLQ +"9J]/!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4 +ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X-7T)#sX9s8W-!s8W-!s6T@Mkj7crjQFt@f$`(! +bKS5SbftK]I76Om779R+4?Ybg4Z,&Q<)ck4Ci3`nASQ%!C2@d&Ci4!(DJF!*C2@d&Ci4THI;3S9 +H[C0NA7[hb4_['[4,oC`.`s8W-!s8W-!s8W-!s6T@Mm.9o.jQGI^kL.l2daZjd`PmdoN(Qc< +/hAS",:"lm/M8S+/hAS,/1iJ*/N#@A4$5Z.>[D/]DJF!*C2@d&Ci4!(DJF!*C2@d&Ci3`nARf7^ +@q9.\A7\kJ?=RMW=Bo0ICi4!(DJF!*C2@d&Ci4THIB0HO"9J]/!X&W-"9\c/"9J]/!X,h2"J>f! +ZN:9&!X,h2"J>f!ZN:9&!X,h2"J>f!ZN:9&!X,h2"J>f!ZN:9&!X,h2"J>f!ZN:9&!X,h2"J>f! +ZN:99!X,.t"LA.4ZN:9&!X,h2"J>f!ZN:9&!X,h2"J>f!ZN:99!X,.t"LA.4ZN:99!X,.t"LA.4 +ZN:9&!X,h2"J>f!ZN:99!X,.t"LA.4TE58&!X,.t"LA.4TE57h!X,h2"J>f!TE58&!X,.t"J>f! +ZN:9&!X,.t"J>f!ZN:9&!X,.t"J>f!ZN:9&!X,.t"J>f!ZN:9&!X,.t"J>f!TE57h!X,.t"J>f! +TE57h!X,.t"J>f!TE57h!X,.t"J>f!TE57h!X,.t"J>f!TE57h!X,.t"J>f!TE57h!X,.t"J>f! +TE57h!X,.t"J>f!TE57h!X,.t"J>f!TE57h!X,.t"J>f!TE57h!X,.t"J>f!TE57h!X,.t"J>f! +TE57h!X,.t"J>f!TE57h!X,.t"J>f!TE57h!X+_h"J>f!PQCu\!X+_h"J>f!PQCu\!X+_h"J>f! +PQCu\!X,.t"J>f!PQCu\!X,.t"I&rjTE57h!X+_h"J>f!TE57h!X,.t"J>f!TE57h!X,.t"J>f! +TE57h!X,.t"O(=ds8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s7ta7`&9TJ!X,h2"J>f!ZN:9&!X,.t"LA.4 +TE57h!X,h2"J>f!ZN:9&!X,h2"J>f!TE58&!X,.t"LA.4TE58&!X,.t"J>f!ZN:9&!X,h2"J>f! +ZN:9&!X,.t"LA.4TE58&!X,.t"LA.4TE58&!X,.t"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4 +ZN:99!X,.t"LA.4ZN:99!X,h2"LA.4TE58&!X,h2"LA.4ZN:99!X,.t"LA.4ZN:99!X,.t"LA.4 +ZN:9&!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4 +ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4 +ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4 +ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4 +ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4 +ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4 +ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"M>*PZN:9B$P'fW%^Q3> +]F,4^$P'KE"M>*P]F,4U!X-.D%^Q3>ZN:99!X,h2"LA.4]F,4U!X,h2"LA.4ZN:99!X-.D%^Q3> +ZN:99!X,h2"LA.4]F,4U!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4 +ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4 +ZN:9B$P'fW%^Q3>ZN:9B$P'KE"M>*PZN:99!X,h2"LA.4kbX@(m-j0)n)39ig"bH4eCMgec-+>U +`5T^6`Pkqa?:mmc@q9.\A7]7]ARf7^C2@ci>[CoNARf7^=Bo07>[CN;?=RMW=Bo0BA7]7]ASQ%! +@q9.Q>[CoNARf7^=Bo1\eCO9cq=OCVm.9o6m-ilnkMYFag"bG.FE@We"?HSeZN:99!X,h2"LA.4 +ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4 +ZN:99!X,h2"LA.4ZN:9pHsZjQs8W-!o_/+IoC_&&kLnYIdaZjkbg">Tc'acZ4$5Yf4?Z,$77BU5 +4$5Yu9MK8<DJF!*C2@d&Ci4!(DJF!*C2@d&Ci4!(DL6_YC2@d&Ci4H=FD>W0C2@cL4?YPY1cmf_ +@q9/=PEWr(`S'&'m.9o6m-ilnkLnYI]=bh9Mi;.VAM,Mc,U4Q[,:"NZ,VCW"/hAS,/1iJ*/M8S+ +/hAS31c/02<GH>fC2@d&Ci4!(DJF!*C2@d&Ci4!(DJF!*@q9.Q>[CoNAQW2D=Bo07>[D/]DJF!* +C2@d&Ci4THI;3S9N/NWe9MGWk"9\c/"9J]/!X&W-"BY^.TE58&!X,h2"J>f!ZN:99!X,.t"LA.4 +TE58&!X,h2"J>f!ZN:9&!X,h2"J>f!ZN:9&!X,h2"J>f!ZN:9&!X,h2"J>f!ZN:9&!X,.t"LA.4 +TE58&!X,.t"LA.4TE58&!X,.t"J>f!ZN:9&!X,.t"J>f!ZN:9&!X,.t"LA.4TE57h!X,h2"J>f! +TE57h!X,h2"J>f!TE57h!X,.t"LA.4TE57h!X,h2"J>f!TE58&!X,.t"J>f!TE57h!X,.t"J>f! +TE57h!X,.t"J>f!TE57h!X,.t"J>f!TE57h!X,.t"J>f!TE57h!X,.t"J>f!TE57h!X,.t"J>f! +TE57h!X,.t"J>f!TE57h!X,.t"J>f!TE57h!X,.t"J>f!TE57h!X,.t"J>f!TE57h!X,.t"J>f! +TE57h!X,.t"J>f!TE57h!X,.t"J>f!TE57h!X,.t"J>f!TE57h!X,.t"J>f!TE57h!X,.t"J>f! +PQCu\!X,.t"I&rjTE57h!X,.t"I&rjTE57h!X+_h"J>f!TE57\!X,.t"I&rjTE57\!X,.t"I&rj +TE57\!X,.t"I&rjTE57\!X+_h"J>f!PQCu\!X+_h"I&rjPQCuP!X+_h"I&rjTE57\!X,eG)X5f( +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8V`bq:L@<ZN:9&!X,.t"LA.4TE57h!X,h2"J>f!ZN:9&!X,.t"LA.4 +TE57h!X,h2"J>f!ZN:9&!X,h2"J>f!TE58&!X,.t"LA.4TE57h!X,h2"J>f!ZN:9&!X,h2"J>f! +TE58&!X,.t"LA.4TE58&!X,.t"J>f!ZN:9&!X,.t"LA.4TE57h!X,h2"J>f!ZN:9&!X,h2"J>f! +TE58&!X,h2"J>f!ZN:9&!X,h2"J>f!ZN:99!X,h2"J>f!ZN:99!X,.t"LA.4ZN:99!X,.t"LA.4 +TE58&!X,h2"J>f!ZN:99!X,.t"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4 +ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4 +ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4 +ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4 +ZN:99!X,h2"LA.4ZN:99!X-.D%^Q3>]F,4U!X-.D%^Q3>]F,4U!X-.D%^Q3>]F,4U!X,h2"LA.4 +ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"M>*PZN:99!X,h2"LA.4ZN:99!X-.D%^Q3> +]F,4U!X-.D%^Q3>]F,4^$P'KE"M>*PZN:9B$P'KE"M>*PZN:9B$P'KE"M>*PZN:9B$P'KE"M>*P +]F,4U!X-.D%_N/Z]F,4U!X-.D%_N/Z]F,4^$P'fW%^Q3>]F,4^$P'fW%_N/Z]F,4^$P'KE"M>*P +]F,4^$P'fW%_N/Z]F,4^$P'fW%^Q3>]F,4^$P'KE"M>*P]F,4^$P'KE"M>*P]F,4^$P'KE"M>*P +ZN:99!X,h2"M>*P]F,4^$P'fW%_N/Z]F,4^$P'KE"M>*P]F,4^$P'KE"M>*PZN:9B$P'KE"M>*P +ZN:9B$P'KE"M>*P]F,4f,:)L>n*'-,i8j(SgtpK/f%A3ibKS5L`Pod7`MB?+4$5Z.>[CoNAQW2D +@q9.\A7]7]ARf7^@q9.Q>[CN;?<CH==Bo07>[CoNAQW2D=Bo0BA7]LlDI[3g@q9.\A7^RMK^A=' +o_/+IoC_&&kMYFag"bH;gtp]-b6.kL"9J_!!X,h2"LA.4ZN:9B$P'KE"LA.4]F,4U!X-.D%^Q3> +ZN:9B$P'KE"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4 +ji#%.pA*q=n)39ig"bH;gtp5uc-+>UUnskK4?YPY1cmf_779R+4?Z;19m_58C2@d7H[TXFDJF!* +C2@d&Ci3`nARf7^C2@d&Ci4!(DL6_YC2@d&Ci4!(DI[3g8k_r:1c.'H1aF:k/hAS",:#?54Zbbh +779Qs/1hbZ)B'P5)B0S5)]BtH,U=T[,U4Q[,:"NZ,VCW"/hAS",:#-'1fRFS@q9.\A7]7]ARf7^ +@q9.cCi3`nASQ%!@q9.\A7]7]AQW2D=Bo0BA7]7]ARf7^C2@d&Ci4!(DJF!*C2@d&Ci5c7S-/lr +"9J]/!X&W-"9\c/"9J_!!X,h2"J>f!ZN:9&!X,h2"J>f!ZN:9&!X,h2"LA.4TE58&!X,.t"LA.4 +TE58&!X,.t"LA.4TE58&!X,.t"LA.4TE58&!X,.t"LA.4TE58&!X,.t"LA.4TE58&!X,.t"LA.4 +TE58&!X,.t"LA.4TE58&!X,.t"LA.4TE57h!X,h2"J>f!TE58&!X,.t"LA.4TE57h!X,.t"LA.4 +TE57h!X,.t"J>f!TE57h!X,.t"J>f!TE57h!X,h2"J>f!ZN:9&!X,h2"J>f!ZN:9&!X,.t"LA.4 +TE57h!X,h2"J>f!TE58&!X,.t"J>f!ZN:9&!X,.t"J>f!TE57h!X,.t"J>f!TE57h!X,.t"J>f! +TE57h!X,.t"J>f!TE57h!X,.t"J>f!TE57h!X,.t"J>f!TE57h!X,.t"J>f!TE57h!X,.t"J>f! +TE57\!X,.t"J>f!TE57h!X+_h"J>f!PQCu\!X+_h"J>f!PQCu\!X,.t"I&rjTE57h!X+_h"J>f! +PQCu\!X,.t"I&rjTE57h!X+_h"J>f!TE57h!X+_h"J>f!TE57\!X,.t"J>f!PQCu\!X+_h"J>f! +PQCu\!X+_h"I&rjTE57\!X,.t"J>f!PQCu\!X+_h"I&rjTE57h!X.28GlRgDs8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8U]h]tYC$TE57h!X,h2"J>f!TE58&!X,.t"J>f!ZN:9&!X,h2"J>f!ZN:9&!X,.t"LA.4 +TE58&!X,.t"LA.4TE57h!X,h2"J>f!ZN:9&!X,h2"J>f!ZN:9&!X,h2"J>f!ZN:9&!X,h2"J>f! +ZN:99!X,.t"LA.4ZN:9&!X,h2"LA.4TE58&!X,h2"J>f!ZN:99!X,h2"J>f!ZN:99!X,.t"LA.4 +TE58&!X,h2"J>f!ZN:99!X,.t"LA.4ZN:9&!X,h2"J>f!ZN:99!X,h2"LA.4TE58&!X,h2"LA.4 +ZN:99!X,.t"LA.4TE58&!X,.t"LA.4ZN:9&!X,h2"LA.4TE58&!X,h2"LA.4ZN:99!X,h2"LA.4 +ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4 +ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4 +ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:9B$P'KE"M>*PZN:9B$P'KE"LA.4 +ZN:99!X,h2"M>*PZN:99!X-.D%^Q3>]F,4U!X-.D%^Q3>]F,4^$P'fW%_N/Z]F,4^$P'fW%_N/Z +ZN:9B$P'fW%^Q3>]F,4U!X-.D%^Q3>]F,4^$P'KE"M>*PZN:9B$P'KE"M>*PZN:9B$P'KE"M>*P +ZN:9B$P'fW%^Q3>]F,4U!X-.D%^Q3>]F,4^$P'KE"M>*P]F,4U!X-.D%^Q3>]F,4U!X-.D%^Q3> +]F,4U!X-.D%^Q3>]F,4^$P'KE"M>*PZN:9B$P'KE"M>*PZN:9B$P'KE"M>*P]F,4U!X-.D%^Q3> +]F,4^$P'fW%^Q3>]F,4U!X-.D%^Q3>]F,4^$P'KE"M>*P]F,4U!X-.D%_N/Z]F,4U!X-.D%^Q3> +]F,4U!X,h2"M>*PZN:9B$P'KE"M>*P]F,4U!X-.D%_N/Z]F,4U!X-.D%^Q3>]F,4U!X,h2"Qc// +kj7d%m-ilnkLnYIdaZjkbg">Tc,@T?bKS4@A7\A,9k.^F@q9.\A7]7]AQW2D=Bo07>[CN;?<CH= +=Bo07>[CN;?<CH==Bo07>[CN;?<CH==Bo0BA7]7]ARf7^`5T^^oC_JAp#+oog"bH;gtpK/f#u:^ +H[C/D!X'kP"LA.4ZN:9B$P'KE"M>*PZN:9B$P'KE"LA.4ZN:9B$P'KE"LA.4]F,4U!X-.D%^Q3> +]F,4U!X-.D%^Q3>]F,4U!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,_S.,!D4kj7ckgtp`>hTO-f +bKS5L`Pl=tAM,Mc/hAS31c.9V4[hb-GB@qRH[U6fI<TdTC2@d&Ci4!(DI[3g@q9.Q>[D/]DJF!* +C2@d&Ci4!(DJF!*C2@d&Ci3`nAQW2D779R%1c-I&,VCW")B0S5)]BV6)B'P5)B0S?,:"0H)B'P5 +,U4QQ)]BV6)C-OQ,U4Q[,:#-'1eLG9=Bo07>[CN;?<CH==Bo0BA7]7]ARf7^=Bo0BA7]7]ARf7^ +=Bo0BA7\kJ?=RMW@q9.\A7]LlDI[3gC2@d&Ci4THI=$<h8k_q^!X&W-"9\c/"9J]/!X'kP"LA.4 +TE58&!X,h2"LA.4TE58&!X,h2"J>f!ZN:9&!X,h2"J>f!ZN:9&!X,h2"J>f!ZN:99!X,.t"LA.4 +TE57h!X,h2"J>f!ZN:9&!X,h2"J>f!TE58&!X,.t"J>f!ZN:9&!X,.t"LA.4TE58&!X,.t"LA.4 +TE57h!X,h2"J>f!TE58&!X,.t"J>f!TE57h!X,h2"J>f!ZN:9&!X,.t"LA.4TE58&!X,.t"LA.4 +TE58&!X,.t"J>f!TE57h!X,.t"J>f!TE57h!X,.t"J>f!TE57h!X,.t"J>f!TE57h!X,.t"J>f! +TE57h!X,.t"J>f!TE57h!X,.t"LA.4TE57h!X,.t"J>f!TE57h!X,.t"J>f!TE57h!X,.t"J>f! +TE57h!X,.t"J>f!TE57h!X,.t"J>f!TE57h!X,.t"J>f!TE57h!X,.t"J>f!TE57h!X+_h"J>f! +TE57h!X,.t"J>f!TE57h!X,.t"I&rjTE57h!X,.t"I&rjTE57h!X,.t"I&rjTE57h!X+_h"J>f! +PQCu\!X+_h"J>f!TE57\!X,.t"I&rjTE57\!X,.t"J>f!PQCu\!X,.t"I&rjTE57\!X,.t"I&rj +PQCuP!X,.t"I&rjTE57\!X,.t"I&rjTE58#-7J]NiW&rXs8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +o_/+\s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!o_/+=jQFQg9sXm( +TE58&!X,.t"J>f!ZN:9&!X,h2"J>f!TE58&!X,.t"J>f!ZN:9&!X,.t"LA.4TE58&!X,.t"LA.4 +TE58&!X,.t"LA.4TE58&!X,.t"LA.4TE58&!X,.t"LA.4TE58&!X,.t"LA.4TE58&!X,.t"LA.4 +ZN:9&!X,h2"J>f!ZN:99!X,.t"LA.4TE58&!X,h2"J>f!ZN:99!X,h2"LA.4ZN:9&!X,h2"J>f! +ZN:99!X,.t"LA.4ZN:99!X,h2"LA.4TE58&!X,h2"LA.4ZN:99!X,.t"LA.4ZN:99!X,h2"LA.4 +ZN:9&!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"J>f!ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4 +ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4 +ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:9B$P'KE"LA.4]F,4U!X,h2"LA.4 +]F,4U!X-.D%^Q3>]F,4U!X-.D%^Q3>ZN:99!X,h2"LA.4]F,4^$P'KE"M>*PZN:9B$P'KE"M>*P +ZN:9B$P'KE"LA.4]F,4U!X-.D%^Q3>ZN:99!X,h2"LA.4ZN:99!X-.D%^Q3>]F,4U!X-.D%_N/Z +ZN:9B$P'KE"M>*PZN:9B$P'KE"M>*PZN:9B$P'KE"M>*P]F,4U!X-.D%^Q3>ZN:9B$P'KE"M>*P +ZN:9B$P'KE"M>*PZN:9B$P'KE"M>*PZN:9B$P'KE"M>*PZN:9B$P'fW%_N/ZZN:9B$P'KE"M>*P +]F,4U!X-.D%^Q3>]F,4^$P'fW%^Q3>]F,4U!X-.D%_N/Z]F,4^$P'KE"LA.4]F,4U!X-.D%_N/Z +ZN:9B$P'fW%^Q3>]F,4U!X-.D%_N/Z]F,4U!X-.D%^Q3>]F,4U!X-.D%^Q3>]F,4^$P'fW%^Q3> +]F,4U!X-.D%^Q3>]F,4U!X,h2"M>*P]F,4U!X-.D%_N/Z^DIgGjQGann)39ig"bH4eCMgec-+>U +bKS5L`PnXLUcU\%=Bo0BA7]7]ARf7^@q9.\A7\kJ?=RMW=Bo07>[CN;?<CH=<)ck">[CN;?<CH= +=Bo0BA7\kJ?=RMW@q9.tH[Y8Pp$D;Ci8j(ZjQFt@f#u:^bKS5Sbfpq*"9\c/PQD!#$P'KE"LA.4 +]F,4U!X,h2"LA.4ZN:9B$P'KE"LA.4]F,4U!X,h2"M>*PZN:99!X-.D%^Q3>ZN:99!X,h2"M>*P +ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:9.AQ7@<hV$]@daZjkbg")F`Pfa7UnskE1c-g9/M8S+ +4$5Z9A7]t,FD>W0C2@d3FED86DJF!*@q9.\A7]7]AQW2D@q9.cCi4!(DJF!*C2@d&Ci4!(DHL.M +@q9.\A7]7]AQW2D8k_r:1c-g9/L2Pd)B0S5)]BV6)B'P5)B0S5)]BV6)C-OQ)B0S?,:"lm/P8]2 +<)ck">[CN;?<CH==Bo07>[CN;?<CH==Bo07>[CN;?<CH==Bo07>[CN;?<CH==Bo07>[CoNARf7^ +@q9.cCi4!(DJF!*C2@dHMi7c?"9\c/"9J]/!X&W-"9\c/L]R^c!X,h2"J>f!ZN:9&!X,h2"LA.4 +TE58&!X,.t"LA.4TE58&!X,.t"LA.4TE58&!X,.t"J>f!ZN:9&!X,h2"LA.4TE57h!X,h2"J>f! +TE58&!X,.t"LA.4TE58&!X,.t"J>f!ZN:9&!X,h2"J>f!TE57h!X,h2"J>f!ZN:9&!X,h2"J>f! +TE58&!X,.t"LA.4TE57h!X,.t"J>f!ZN:9&!X,.t"J>f!TE57h!X,.t"J>f!TE57h!X,h2"J>f! +TE58&!X,.t"J>f!TE58&!X,.t"J>f!ZN:9&!X,.t"LA.4TE57h!X,.t"J>f!TE57h!X,.t"J>f! +TE57h!X,.t"J>f!TE57h!X,.t"J>f!TE57h!X,.t"J>f!TE57h!X,.t"J>f!TE57h!X,.t"J>f! +TE57h!X,.t"J>f!TE57h!X,.t"I&rjTE57h!X+_h"J>f!TE57h!X+_h"J>f!TE57\!X,.t"I&rj +TE57h!X,.t"I&rjTE57h!X,.t"I&rjTE57h!X,.t"I&rjTE57h!X+_h"J>f!TE57\!X,.t"I&rj +TE57\!X,.t"J>f!PQCu\!X+_h"J>f!PQCu\!X+_h"J>f!PQCu\!X,.t"I&rjTE57\!X,.t"I&rj +TE57\!X+_h"J>f!TE58NUQb`Xs8W-!s8W-!s8W-!s7H$\s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8V`bq<[_Gkj7cZUn+gn"J>f!ZN:9&!X,.t"LA.4 +TE57h!X,h2"J>f!TE58&!X,.t"LA.4TE57h!X,h2"J>f!ZN:9&!X,h2"J>f!ZN:9&!X,h2"J>f! +ZN:9&!X,h2"J>f!ZN:9&!X,h2"LA.4TE58&!X,h2"J>f!ZN:9&!X,h2"J>f!ZN:99!X,.t"LA.4 +TE58&!X,h2"J>f!ZN:99!X,.t"LA.4TE58&!X,.t"LA.4ZN:99!X,h2"J>f!ZN:99!X,.t"LA.4 +TE58&!X,h2"J>f!ZN:9&!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,.t"LA.4 +ZN:9&!X,h2"LA.4ZN:99!X,h2"LA.4TE58&!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4 +ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4 +ZN:99!X,h2"LA.4]F,4U!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"M>*PZN:99!X-.D%^Q3> +ZN:9B$P'KE"M>*PZN:9B$P'KE"LA.4]F,4U!X,h2"LA.4]F,4U!X,h2"M>*PZN:9B$P'KE"LA.4 +]F,4U!X-.D%_N/Z]F,4^$P'fW%^Q3>]F,4U!X-.D%^Q3>]F,4U!X-.D%^Q3>]F,4U!X-.D%^Q3> +]F,4U!X-.D%^Q3>]F,4U!X,h2"M>*P]F,4U!X-.D%^Q3>]F,4U!X-.D%_N/ZZN:9B$P'fW%^Q3> +]F,4U!X-.D%^Q3>]F,4U!X-.D%^Q3>]F,4^$P'KE"M>*PZN:9B$P'KE"M>*P]F,4^$P'KE"M>*P +ZN:9B$P'fW%_N/ZZN:99!X-.D%_N/Z]F,4^$P'KE"M>*PZN:9B$P'KE"M>*PZN:9B$P'fW%^Q3> +]F,4U!X-.D%^Q3>]F,4U!X-.D%_N/Z]F,4U!X-.D%^Q3>]F,4^$P'fW%^Q3>]F,4U!X-.D%_N/Z +]F,4U!X-.D%^Q3>]F,4U!X.\EETlcXi8j(`gt^T<hU9p)bKS5Sbg")F`Pfa7@q9.C9MJVo?<CH= +=Bo07>[CoNAQW2D=Bo07>[CoNAQW2D=Bo07>[CN;?<CH==Bo07>[CN;?<CH=@q9.Q>[CoNA[JhO +m.9o6m-iW_hU9p)daZjkbg")F`JB2#"9J]B!X,h2"LA.4]F,4U!X,h2"M>*PZN:9B$P'KE"M>*P +ZN:9B$P'KE"LA.4]F,4U!X,h2"M>*PZN:99!X-.D%^Q3>ZN:99!X,h2"M>*PZN:99!X-.D%^Q3> +ZN:99!X,h2"J>f!\"o\FeCMgec,@T?`5T^6`PoI%]o7l./hAS31c/02<GH>fC2@d&Ci4!(DJF!* +@q9.\A7]7]ARf7^@q9.\A7]7]ARf7^@q9.\A7]7]ARf7^=Bo0BA7\kJ?=RMW@q9.\A7]7]AQW2D +=Bo0)9MIT24YA9;)B0S5)]BtH,U=T[,U4Qe/1iqG4\ACB<)cji9MJ,Q9iP(l8k_rO9MJ,Q9iP(l +8k_rO9MJ,Q9hJ)R=Bo07>[CN;?<CH==Bo07>[CN;?<CH==Bo0BA7]7]ASQ%!C2@d7H[U6fI76Om +"9J]/!X&W-"9\c/"9J]B!X,h2"J>f!ZN:99!X,.t"LA.4TE58&!X,.t"LA.4ZN:9&!X,h2"J>f! +ZN:99!X,.t"LA.4TE58&!X,.t"LA.4TE57h!X,h2"J>f!ZN:9&!X,h2"J>f!ZN:9&!X,h2"J>f! +ZN:9&!X,h2"J>f!TE58&!X,.t"LA.4TE57h!X,.t"LA.4TE57h!X,h2"J>f!ZN:9&!X,.t"LA.4 +TE57h!X,.t"J>f!ZN:9&!X,h2"J>f!ZN:9&!X,h2"J>f!TE57h!X,.t"J>f!TE58&!X,.t"J>f! +TE57h!X,.t"J>f!TE57h!X,.t"J>f!ZN:9&!X,.t"J>f!TE57h!X,.t"J>f!TE57h!X,.t"J>f! +TE57h!X,.t"J>f!TE57h!X,.t"J>f!TE57h!X,.t"J>f!TE57h!X,.t"J>f!TE57h!X,.t"J>f! +TE57h!X,.t"J>f!TE57h!X,.t"J>f!TE57h!X+_h"J>f!TE57\!X,.t"I&rjTE57h!X+_h"J>f! +PQCu\!X,.t"I&rjTE57h!X+_h"J>f!PQCu\!X+_h"J>f!PQCu\!X,.t"I&rjTE57\!X,.t"I&rj +TE57h!X+_h"J>f!PQCu\!X+_h"I&rjTE57\!X+_h"J>f!PQCuP!X+_h"J>f!PQCu\!X+_h"J>f! +cV74!m-juSs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!o_/+QpA*q=n)39ifZ_OL7OOi1"J>f!ZN:9&!X,h2"J>f!ZN:9&!X,h2"J>f! +TE58&!X,.t"LA.4TE57h!X,h2"J>f!ZN:9&!X,h2"J>f!TE58&!X,.t"LA.4TE58&!X,.t"LA.4 +TE58&!X,.t"LA.4TE58&!X,.t"LA.4TE58&!X,h2"J>f!ZN:9&!X,h2"LA.4TE58&!X,.t"LA.4 +TE58&!X,h2"J>f!ZN:99!X,.t"LA.4TE58&!X,h2"J>f!ZN:99!X,h2"LA.4TE58&!X,h2"LA.4 +ZN:99!X,.t"LA.4ZN:9&!X,h2"J>f!ZN:99!X,.t"LA.4ZN:99!X,h2"LA.4ZN:99!X,.t"LA.4 +ZN:99!X,h2"LA.4TE58&!X,h2"LA.4TE58&!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4 +ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4 +ZN:99!X,h2"LA.4ZN:9B$P'KE"M>*PZN:99!X,h2"LA.4ZN:9B$P'KE"LA.4ZN:9B$P'KE"LA.4 +]F,4U!X,h2"LA.4]F,4^$P'KE"LA.4]F,4U!X,h2"M>*PZN:9B$P'KE"LA.4]F,4U!X,h2"LA.4 +ZN:9B$P'KE"M>*PZN:9B$P'KE"M>*PZN:9B$P'KE"M>*PZN:9B$P'KE"M>*PZN:9B$P'KE"M>*P +]F,4U!X-.D%^Q3>]F,4U!X-.D%_N/ZZN:9B$P'KE"M>*PZN:9B$P'KE"M>*P]F,4U!X-.D%_N/Z +ZN:9B$P'KE"M>*P]F,4U!X-.D%_N/ZZN:9B$P'KE"M>*PZN:9B$P'fW%_N/ZZN:9B$P'fW%_N/Z +ZN:9B$P'KE"M>*PZN:9B$P'fW%^Q3>]F,4U!X-.D%^Q3>]F,4U!X-.D%^Q3>]F,4^$P'fW%^Q3> +]F,4U!X-.D%_N/ZZN:9B$P'KE"M>*PZN:9B$P'fW%^Q3>]F,4U!X,h2"M>*PZN:9B$P'KE"MYcj +k1nbUm-ilnkLnYIdaZk#bfe2Rc,@T?`5T]rXK=*+/Qc7a=Bo07>[CN;?<CH=@q9.\A7]7]AQW2D +=Bo07>[D/]DHL.M=Bo0BA7]LlDI[3g=Bo0BA7]7]ARf7^C2@eOm-j0)n)39ig"bH;gtp5uc,@T? +`5T\6)]Ah\"Gd*^ZN:99!X-.D%^Q3>]F,4U!X-.D%^Q3>]F,4U!X,h2"LA.4ZN:9B$P'KE"LA.4 +]F,4U!X,h2"LA.4ZN:99!X,h2"M>*PZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X+;\"N89u +`5T^6`Pod7`Oidr]=bhh]Y.EP?:@7N=Bo0BA7]7]ARf7^@q9.\A7\kJ?=RMW=Bo07>[CoNARf7^ +@q9.\A7]7]ARf7^@q9.Q>[CN;?<CH=@q9.Q>[CoNAQW2D=Bo07>[CN;?<CH==Bo03<)lms<D#qZ +8k_rY<)lms<E)pt<)cji9MJ,Q9hJ)R8k_rO9MJ,Q9hJ)R8k_rJ6q'O477BU58k_rO9MJ,Q9hJ)R +8k_rY<)lms<E)pt8k_rO9MJVo?<CH==Bo0BA7]7]ASQ%!H[C/D!X&W-"9\c/"9J]/!X&W-"F1%O +ZN:9&!X,h2"J>f!ZN:99!X,.t"LA.4ZN:9&!X,h2"J>f!ZN:99!X,.t"LA.4TE58&!X,.t"LA.4 +TE58&!X,.t"LA.4TE58&!X,.t"LA.4TE58&!X,.t"J>f!ZN:9&!X,.t"LA.4TE57h!X,h2"J>f! +ZN:9&!X,h2"J>f!ZN:9&!X,.t"LA.4TE57h!X,.t"LA.4TE57h!X,.t"LA.4TE58&!X,.t"J>f! +TE57h!X,.t"J>f!TE57h!X,.t"LA.4TE58&!X,.t"J>f!TE57h!X,h2"J>f!TE57h!X,h2"J>f! +TE57h!X,.t"J>f!TE57h!X,h2"J>f!TE57h!X,.t"J>f!TE57h!X,.t"LA.4TE57h!X,.t"J>f! +TE57h!X,.t"J>f!TE57h!X,.t"J>f!TE57h!X,.t"I&rjTE57h!X,.t"J>f!PQCu\!X,.t"J>f! +TE57\!X,.t"J>f!TE57\!X,.t"J>f!TE57h!X,.t"I&rjTE57h!X,.t"J>f!PQCu\!X+_h"J>f! +PQCu\!X,.t"I&rjTE57h!X,.t"J>f!PQCu\!X,.t"I&rjTE57\!X,.t"I&rjTE57\!X,.t"I&rj +TE57\!X,.t"I&rjTE57\!X,.t"I&rjTE57\!X,.t"I&rjTE57\!X,.t"J>f!ke+/"s8W-!s8W-! +s8W,kpA+ags8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s7H$\ +m.9o6m-j0)n)39iaGYJQ!X,.t"J>f!TE58&!X,.t"J>f!ZN:9&!X,h2"J>f!ZN:9&!X,h2"J>f! +TE58&!X,.t"LA.4TE58&!X,.t"LA.4TE58&!X,.t"LA.4ZN:9&!X,h2"J>f!ZN:9&!X,h2"J>f! +ZN:99!X,.t"LA.4TE58&!X,h2"LA.4TE58&!X,h2"J>f!ZN:99!X,h2"J>f!ZN:99!X,.t"LA.4 +ZN:99!X,h2"J>f!ZN:99!X,.t"LA.4TE58&!X,h2"LA.4TE58&!X,.t"LA.4ZN:99!X,h2"LA.4 +ZN:99!X,h2"LA.4ZN:99!X,h2"J>f!ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4 +ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4 +ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"M>*PZN:99!X-.D%^Q3> +ZN:99!X,h2"LA.4]F,4U!X,h2"LA.4]F,4U!X-.D%^Q3>]F,4U!X,h2"M>*PZN:9B$P'KE"LA.4 +]F,4U!X-.D%^Q3>]F,4U!X,h2"M>*PZN:9B$P'KE"M>*P]F,4U!X-.D%^Q3>]F,4U!X-.D%^Q3> +]F,4U!X-.D%^Q3>]F,4U!X-.D%^Q3>]F,4U!X-.D%^Q3>]F,4U!X,h2"M>*PZN:9B$P'fW%^Q3> +]F,4U!X-.D%^Q3>]F,4U!X-.D%^Q3>]F,4U!X-.D%^Q3>]F,4U!X-.D%^Q3>]F,4U!X-.D%^Q3> +]F,4^$P'KE"M>*PZN:9B$P'fW%^Q3>]F,4U!X-.D%^Q3>]F,4U!X-.D%^Q3>]F,4U!X-.D%_N/Z +ZN:9B$P'fW%_N/ZZN:9B$P'KE"M>*PZN:9B$P'KE"M>*PZN:9B$P'KE"M>*PZN:9B$P'fW%^Q3> +]F,4^$P'KE"M>*PZN:9B$P'KE"M>*P]F,4U!X-.D%_N/ZZN:9^KPp#?n)39ii8j(SgtpK/f#u:^ +`5T^6`Pp$Ec!t9q4$5Z.>[CN;?<CH==Bo07>[CN;?=RMW@q9.\A7]7]ARf7^C2@ctA7]LlDI[3g +@q9.\A7]7]AQW2D=Bo07>[FeE[-[DWm.9o6m-iW_hV$]@daZjreCM"6ZigF5(BO`G!X,h2"M>*P +ZN:99!X-.D%^Q3>ZN:99!X,h2"M>*PZN:9B$P'KE"LA.4]F,4U!X,h2"M>*PZN:9B$P'KE"LA.4 +ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:8W3]t@"`Pfa7]=bhh]Y1qi]t:qj +X/rF<Ci3`nAQW2D@q9.Q>[CN;?<CH==Bo07>[CN;?<CH==Bo0BA7\kJ?=RMW=Bo0BA7\kJ?<CH= +=Bo07>[CN;?=RMW@q9.\A7]7]AQW2D=Bo07>[CB/<E)pt<)cjs<)lms<D#qZ8k_rO9MJ,Q9hJ)R +8k_rO9MIrD77BU5779R56q'O477BU5779R:9MIrD77BU58k_rO9MJ,Q9hJ)R8k_rO9MJ,Q9itY, +=Bo07>[CN;?=RMW@q9.tH[Uj2N!'1b"9J]/!X&W-"9\c/(BO`G!X,.t"LA.4ZN:9&!X,h2"J>f! +ZN:9&!X,h2"J>f!ZN:9&!X,h2"J>f!ZN:9&!X,h2"J>f!ZN:9&!X,h2"J>f!ZN:9&!X,h2"J>f! +ZN:9&!X,h2"J>f!ZN:9&!X,.t"LA.4TE58&!X,.t"LA.4TE57h!X,.t"LA.4TE58&!X,.t"LA.4 +TE57h!X,.t"LA.4TE57h!X,h2"J>f!TE57h!X,.t"J>f!TE58&!X,.t"LA.4TE57h!X,h2"J>f! +TE57h!X,.t"J>f!TE57h!X,.t"J>f!TE57h!X,h2"J>f!TE57h!X,h2"J>f!TE57h!X,.t"J>f! +TE57h!X,.t"J>f!TE57h!X,.t"J>f!TE57h!X,.t"J>f!TE57h!X,.t"J>f!TE57h!X,.t"J>f! +TE57h!X,.t"J>f!TE57h!X,.t"J>f!TE57h!X,.t"J>f!PQCu\!X,.t"J>f!TE57\!X,.t"J>f! +TE57\!X,.t"I&rjTE57h!X+_h"J>f!PQCu\!X,.t"I&rjTE57h!X+_h"J>f!PQCu\!X+_h"I&rj +TE57\!X,.t"I&rjTE57h!X+_h"J>f!PQCu\!X+_h"I&rjTE57\!X+_h"J>f!PQCu\!X+_h"I&rj +TE57\!X+_h"I&rjTE57\!X+_h"I&rjPQCu\!X+_h"O(=ds8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8V`bq=OCVkj7d%m-ilnkLdGU +`%3U8!X,h2"J>f!TE58&!X,.t"LA.4TE57h!X,h2"J>f!TE58&!X,.t"LA.4TE57h!X,h2"J>f! +ZN:9&!X,h2"J>f!ZN:9&!X,h2"J>f!ZN:99!X,.t"LA.4TE58&!X,h2"J>f!ZN:9&!X,h2"LA.4 +TE58&!X,.t"LA.4TE58&!X,h2"J>f!ZN:99!X,.t"LA.4ZN:9&!X,h2"J>f!ZN:99!X,.t"LA.4 +ZN:9&!X,h2"LA.4TE58&!X,h2"LA.4ZN:99!X,h2"LA.4TE58&!X,h2"J>f!ZN:99!X,.t"LA.4 +ZN:99!X,h2"LA.4TE58&!X,h2"LA.4TE58&!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4 +ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4 +ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"M>*PZN:99!X,h2"M>*P +ZN:9B$P'KE"LA.4ZN:99!X,h2"M>*PZN:99!X-.D%^Q3>]F,4U!X,h2"M>*PZN:9B$P'KE"LA.4 +]F,4U!X-.D%^Q3>]F,4U!X,h2"M>*PZN:9B$P'KE"M>*PZN:9B$P'KE"LA.4]F,4U!X-.D%^Q3> +]F,4U!X-.D%^Q3>]F,4U!X-.D%_N/ZZN:9B$P'KE"M>*PZN:9B$P'fW%^Q3>]F,4U!X-.D%_N/Z +ZN:9B$P'fW%^Q3>]F,4U!X-.D%^Q3>]F,4^$P'KE"M>*PZN:9B$P'fW%^Q3>]F,4^$P'KE"M>*P +ZN:9B$P'fW%^Q3>]F,4U!X-.D%_N/Z]F,4U!X-.D%_N/ZZN:9B$P'KE"M>*PZN:9B$P'fW%^Q3> +]F,4^$P'KE"M>*P]F,4^$P'KE"M>*PZN:9B$P'fW%^Q3>ZN:9B$P'fW%^Q3>]F,4U!X-.D%^Q3> +]F,4^$P'KE"M>*PZN:9B$P'fW%d)R%kj7d%m-iW_hU9p)bKS5Sbg">Tc,@T?['[1m/1jIf9iP(l +<)cji9MJJc<ENL4=Bo07>[CN;?<CH=@q9.\A7]LlDJF!*@q9.cCi4!(DI[3g@q9.Q>[CN;?>=:o +m.9oBpA+@Sq<[_Gkj7ckgtp`>hV$]@`5T[u!X*cM"LA.4ZN:99!X-.D%^Q3>ZN:9B$P'KE"M>*P +ZN:99!X-.D%^Q3>]F,4U!X,h2"M>*PZN:99!X,h2"LA.4]F,4U!X,h2"M>*PZN:99!X-.D%^Q3> +ZN:99!X,h2"LA.4ZN:99!X,h2"J>f!Q]-g?`PoI%]u7n/]=bhh]Y1qi]qhL#@q9.Q>[CN;?<CH= +=Bo07>[CN;?;sm(<)ck">[CN;?<CH==Bo07>[CoNAQW2D@q9.\A7\kJ?=RMW=Bo0BA7]7]ARf7^ +@q9.\A7\kJ?<CH==Bo07>[CN;?;sm(<)cji9MJ,Q9hJ)R779R56q'1"4[hb-779R56q'O477BU5 +779R56q'O477BU5779R56q'O476<Up779R:9MJ,Q9hJ)R8k_rO9MJ,Q9itY,@q9.\A7]7]AXo?^ +bKS5<['V(s(^'mC"9J]/!X*cM"J>f!ZN:99!X,.t"LA.4TE58&!X,h2"J>f!ZN:99!X,.t"LA.4 +TE58&!X,.t"LA.4TE58&!X,.t"LA.4TE58&!X,.t"J>f!ZN:9&!X,h2"J>f!TE58&!X,.t"LA.4 +TE58&!X,.t"J>f!ZN:9&!X,h2"J>f!ZN:9&!X,.t"J>f!TE57h!X,h2"J>f!ZN:9&!X,h2"J>f! +TE57h!X,h2"J>f!ZN:9&!X,h2"J>f!TE57h!X,.t"J>f!TE57h!X,.t"LA.4TE57h!X,.t"LA.4 +TE58&!X,.t"J>f!TE57h!X,.t"J>f!TE57h!X,.t"J>f!ZN:9&!X,.t"J>f!TE57h!X,h2"J>f! +TE57h!X,.t"J>f!TE57h!X,.t"J>f!TE57h!X,.t"J>f!TE57h!X,.t"J>f!TE57h!X,.t"J>f! +TE57\!X,.t"J>f!TE57h!X,.t"J>f!TE57\!X,.t"J>f!TE57h!X+_h"J>f!TE57h!X+_h"J>f! +TE57\!X,.t"J>f!PQCu\!X,.t"I&rjTE57h!X+_h"J>f!TE57h!X+_h"J>f!PQCu\!X+_h"I&rj +TE57\!X,.t"I&rjPQCu\!X+_h"J>f!PQCu\!X+_h"I&rjTE57\!X+_h"J>f!PQCu\!X+_h"I&rj +PQCu\!X+_h"J>f!PQCuP!X,eG)Ud-ds8W,kpA+ags8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8VHWp$D;Ckj7d%m-iW_hT0eFZN:9&!X,h2"J>f! +TE58&!X,.t"LA.4TE58&!X,.t"LA.4TE58&!X,.t"LA.4TE58&!X,.t"LA.4TE58&!X,.t"LA.4 +TE58&!X,.t"LA.4TE58&!X,h2"J>f!ZN:9&!X,h2"LA.4TE58&!X,.t"LA.4ZN:9&!X,h2"J>f! +ZN:9&!X,h2"J>f!ZN:99!X,.t"LA.4ZN:9&!X,h2"LA.4ZN:9&!X,h2"LA.4ZN:9&!X,h2"LA.4 +TE58&!X,.t"LA.4TE58&!X,h2"LA.4TE58&!X,h2"LA.4ZN:99!X,.t"LA.4ZN:99!X,h2"LA.4 +ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:9&!X,h2"LA.4ZN:99!X,h2"LA.4 +ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4 +]F,4U!X,h2"LA.4]F,4U!X,h2"M>*PZN:99!X,h2"M>*PZN:99!X-.D%^Q3>ZN:9B$P'KE"M>*P +ZN:99!X-.D%^Q3>ZN:99!X,h2"M>*PZN:99!X,h2"LA.4]F,4U!X-.D%^Q3>ZN:9B$P'KE"M>*P +ZN:9B$P'KE"LA.4]F,4U!X-.D%^Q3>]F,4U!X-.D%^Q3>]F,4U!X-.D%^Q3>]F,4U!X-.D%^Q3> +]F,4U!X-.D%^Q3>]F,4U!X-.D%^Q3>]F,4U!X-.D%^Q3>]F,4U!X-.D%^Q3>ZN:9B$P'KE"M>*P +ZN:9B$P'KE"M>*P]F,4U!X-.D%^Q3>]F,4U!X-.D%^Q3>]F,4U!X-.D%^Q3>]F,4U!X-.D%^Q3> +]F,4U!X-.D%_N/Z]F,4U!X-.D%_N/ZZN:9B$P'KE"M>*P]F,4^$P'fW%^Q3>]F,4U!X-.D%^Q3> +]F,4U!X-.D%^Q3>]F,4^$P'KE"M>*PZN:9B$P'fW%^Q3>]F,4^$P'KE"M>*PZN:9B$P'KE"M>*P +fQCHnm-!<fkN:RTg"bH4eCMgec-+>U`5T^6`PlS.DD!Il<)cji9MJJc<E)pt=Bo0)9MJVo?<CH= +=Bo0BA7\kJ?=RMWC2@ctA7]7]ASQ%!C2@ctA7\kJ?<CH==Bo1.V53bWq>^Kpo_/+IoC_>6n*'-, +i8j(SgtpuMk;iYIZN:99!X,h2"M>*PZN:99!X-.D%^Q3>ZN:9B$P'KE"M>*PZN:99!X,h2"M>*P +ZN:99!X-.D%^Q3>ZN:9B$P'KE"LA.4]F,4U!X,h2"M>*PZN:99!X,h2"LA.4ZN:99!X,h2"LA.4 +ZN:99!X,#/'ZRes]=bhh]Y1qi]t:qj]=bhh]Y0_sP?;'r<)cjs<)lms<D#qZ8k_rY<)lms<E)pt +=Bo07>[CN;?<CH==Bo0BA7\kJ?=RMW=Bo07>[CN;?=RMW@q9.cCi3`nAQW2D=Bo07>[CN;?<CH= +=Bo07>[CB/<D#qZ<)cji9MIrD77BU5779R56q'O477BU5779R56q'O477BU5779R56q'O477BU5 +779R56q'^A9gqH=8k_rO9MJ,Q9hJ)R<)ck">[CN;?=RMWH[C1abg"Scf$`(!g"bG2H[Q"u";_+B +ZN:99!X,.t"LA.4ZN:9&!X,h2"J>f!ZN:9&!X,h2"J>f!ZN:99!X,.t"LA.4TE58&!X,.t"LA.4 +TE58&!X,.t"LA.4TE58&!X,.t"LA.4TE58&!X,.t"LA.4TE58&!X,.t"J>f!ZN:9&!X,.t"LA.4 +TE58&!X,.t"LA.4TE58&!X,.t"J>f!TE58&!X,.t"J>f!TE58&!X,.t"LA.4TE57h!X,.t"J>f! +TE57h!X,h2"J>f!ZN:9&!X,h2"J>f!TE57h!X,.t"LA.4TE57h!X,.t"J>f!TE57h!X,.t"J>f! +TE58&!X,.t"J>f!TE57h!X,.t"J>f!TE57h!X,.t"J>f!TE57h!X,.t"J>f!TE57h!X,.t"J>f! +TE57h!X,.t"J>f!TE57h!X,.t"J>f!TE57h!X,.t"J>f!TE57h!X,.t"J>f!TE57h!X+_h"J>f! +TE57h!X+_h"J>f!TE57\!X,.t"J>f!TE57\!X,.t"I&rjTE57h!X+_h"J>f!TE57\!X,.t"I&rj +TE57h!X+_h"J>f!TE57\!X,.t"I&rjTE57h!X+_h"J>f!PQCu\!X+_h"J>f!PQCu\!X+_h"J>f! +PQCu\!X+_h"I&rjTE57\!X+_h"J>f!PQCuP!X,.t"I&rjTE57\!X,.t"I&rjPQCuP!X,.t"I&rj +TE57h!X-GgIK0?Is8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W,kpA+@Sq<726kj7crjQG1&XKiZ]TE57h!X,h2"J>f!TE57h!X,h2"J>f! +TE58&!X,.t"LA.4TE58&!X,.t"LA.4TE57h!X,h2"J>f!ZN:9&!X,h2"J>f!ZN:9&!X,h2"LA.4 +TE58&!X,.t"LA.4ZN:9&!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4 +ZN:99!X,h2"LA.4ZN:9&!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4 +ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4ZN:99!X,h2"LA.4 +ZN:99!X,h2"LA.4ZN:99!X-.D%^Q3>ZN:99!X,h2"LA.4ZN:9B$P'KE"LA.4ZN:9B$P'KE"LA.4 +]F,4U!X-.D%_N/Z]F,4^$P'fW%_N/Z]F,4^$P'fW%_N/Z]F,4^$P'fW%_iht]F,4^$P'fW%_N/Z +]F,4^$P'fW%_iht]F,4a(`9mn%_iht]F,4a(`:")(q^4d^DIg#$P'og(r$n)^DIg&(`:")(r$n) +^DIg&(`:")(r$n)^DIg&(`:")(r$n)^DIg+,:(#@(r$n)`$6PB(`:")(r$n)^DIg+,:(2P,fCoQ +^DIg+,:(2P,fCoQ^DIg+,:(2P,fCoQ`$6PG/25!e,fD5f`$6PG,:(2Y0Z51]`%3U\,:(2Y0Z5Lr +`%3U\/25!n0Z5Lr`%3U\/25!n0Z5Lr`%3U\2E8W535d@%`&9Tn/25"#35d@%`&9Tn/25"#35d@% +`&9Tn2E8W535d^7`&9Tn2E8W535d^7`&9Tn2E8W536XKL`&9U!4?pbB36XKL`&9Tn2E8W536XKL +`&9Tn2E8oC5Kl5SbWJ,64?q%P5Kl5SbWJ,64?q%P5Kl5SbWJ,66q#6]5KlM`bWJ,66q#6]5KlM` +bWJ,66q#6]5KlM`bX=kF9i&u$7*eS'cV73]9i')0:X;a2cV73]9i($(fBDSii8j(SgtpK/f%A3i +bKS5L`Pod7`O*"Z/hASC6q'^A9hJ)R<)ck">[CB/<ENL4<)ck">[CN;?<CH==Bo0BA7\kJ?=RMW +=Bo0BA7\kJ?=RMW@q9.Q>[CoNAaK$]s8W-!s8W-!s7H$\m.9o6m-j0)n*'-,kj7cVH[Wq>:!?R= +bZ%]g<*7@D=Nj`HbZ%]g<*7@D=Nj`HbZ%]g<*7XV7*K+ObZ%]g<*7@RA^"+Ue6YPe<*7@RA^"+U +b[P/-@V*bmA^"Upb[P/-@V+5(8'GFRb[P/-@V*b_=Nk5cb[P/-<*6_;7Ee_5[o5>sUnG?4]u7n/ +]=bhh]Y1qi]t:qj]=bh(H[Sjm<ENL4<)cjs<)m%*?:mmc<)cjs<)lms<ENL4=Bo07>[CN;?<CH= +=Bo07>[CN;?<CH=@q9.\A7]7]ASQ%!C2@ctA7]7]AQW2D=Bo07>[CN;?<CH==Bo07>[CB/<D#qZ +8k_rJ6q'O476<Up779R+4?Z,$77BU5779R+4?Z,$76<Up779R56q'1"4[hb-779R:9MJ,Q9hJ)R +8k_rY<)lms<ENL4@q9.\A7`-T[+X6ki8j(Sgtp`>hV$]@]=bhdHtpTHIE6M:`-ZpRFC)n4IDgJ\ +aa@a>H[WhZIDgJ\`-ZpNH[WhZIDgJ\`-ZpNH[WhZIDgJ\`-ZpNH[WhZIDgJ\`-ZpNH[WhZIDgJ\ +`-ZpNH[WhZIDgJ\`-ZpNH[WhZIDgJ\`-ZpNH[WhZIDgJ\`-ZpNH[WhZIDgJ\`-ZpNH[WhZIDgJ\ +`-ZpNH[WhZIDgJ\`-ZpNH[WhZIDgJ\`-ZpNH[WhZIDgJ\aFnTPH[WtgEl<<Q\V5:HH[WGYGf4rW +\V5:HH[WtgEl<<QaGYJbH[WGYGfYek`-ZpRMg`NjIE7=p`-ZpRMg`'oKuf1#\VbdUMg`[)IE7=p +\VbdUMg`-nI)q4o\VbdUMg`'oKuf1#[uH*_Mg`[)ICG2iaGYJUNJ5H3ICY5_aHM:dNJ5H;KXZqp +aHM:dNJ5H;KXZqp[uH*NNJ4j$Kt!%q\<Di\PDcr7Mn"t/aHM:dNJ4m+Mn"t/aHM:dNJ4m+Mn"t/ +\<Di\PDcr7Mn"t/[uH*OPDco0Kt*>)[uH*OPDcu?Pdlp8\<Di\PDcu?Pdlp8\<Di\PDcr7Mn,:@ +\XJbnRZt@OPe!6I\XJbnRZt@OPe!6I\XJbnRZtmhS[YDfaK25ZXJO">V:`/VfY"ZF]XHG1^#d2L +k01s3e^s'9fD*k;l.+DMe^s'9fBLi;l.+DMe^s'9fBLi;l.+DJgt_/EfD44Ll.+DXpA+ags8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +o_/+QpA+@Sq<[_Gm.9o6m-j)\al^ghf>PATbff.mak4h\fZ_P$bfSM]bLk%^fZ_OkbfeY_bLk%^ +fZ_Okbff8$f@\<jdaZk4e^rHtbL4nkl.+D6eCNm7f@&1"l.+D=gtq;GfB1lDl.+D=gtq;Gf@es9 +k1nbFgtq;Gf@es9k1nbSgt_&IgtCK>i8j(`gt_&IgudDIg"bHHgt^iKkMYFai8j(ZjQG[\h!"+n +k1nbMjQGI^kN:RTi8j(bm-ilnkNM:$i8j(bm-j0)n*'-,kj7d%m-j0)n*'-,kj7d%m-j0)n*'-, +m.9o6m-j<4p#tc2m.9o6m-j<4p#tc2o_/+Em-jT?q<726o_/+Em-jT?q<726o_/+Em-j<4p#tc2 +m.9oEm-!a,p$D;Ckj7d1pA*q=n*'-,o_/+Tm-"$7q<726o_/+Tm-"$7q=j7=o_/+Tm-"$7q=j7= +o_/+Tm-"$7q=OCVo_/+Tm-"$7q=OCVp[%)8pA+@Sq=OCVo_/+QpA+@Sq=OCVo_/+QpA+@Sq=j7= +o_/+QpA+@Sq=j7=o_/+QpA+ILkOeKDp[%)8pA+@Sq=OCVo_/+QpA+ILkOeKDo_/+QpA+@Sq=OCV +o_/+QpA+@Sq=OCVo_/+QpA+@Sq=OCVo_/+\s8W-!s7H$\o_/+QpA+@Sq=OCVo_/+QpA+ags7H$\ +o_/+QpA+@Sq=OCVo_/+QpA+@Sq=OCVo_/+QpA+@Sq=OCVo_/+QpA+@Sq=OCVo_/+QpA+@Sq=OCV +o_/+QpA+@Sq=OCVo_/+QpA+@Sq=OCVo_/+\s8V`bq=OCVo_/+\s8V`bq=OCVo_/+QpA+ags7H$\ +o_/+\s8V`bq=OCVo_/+QpA+@Sq=OCVo_/+QpA+@Sq=OCVo_/+QpA+@Sq=OCVo_/+QpA+@Sq=OCV +o_/+QpA+@Sq=OCVo_/+QpA+@Sq=OCVo_/+\s8V`bq=OCVo_/+QpA+ags7H$\s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8V`bq=OCVkj7d%m-ilnkLnYIdaZjkbg">Tc,@T?`5T]>FEB,d/P8]2 +8k_rO9MJJc<ENL4<)ck">[CN;?<CH==Bo07>[CN;?<CH==Bo07>[CN;?<CH==Bo07>[CN;?<CH= +S=Z8CpA+ags8W-!s8W-!s8W-!s7H$\m.9o:oC_JAp$D;Ckj7d1pA+@Sq=OCVm.9oBpA+(Hp%7tR +m.9oBpA+(Hp%7tRkj7d1pA+@Sq=OCVp[%)0oC_JAp%7tRp[%)0oC_bLq=OCVo_/+QpA+@Sq=OCV +o_/+QpA+ILkNM:$kj7crjQG4OhV$]@daZjkbg")F`Pfa7`k8mp]Y1qi]t:qj]=bhh]Y1qi]t:qj +H[C059MJJc<E)pt<)cjs<)lms<E)pt<)ck">[CN;?<CH==Bo07>[CN;?<CH==Bo07>[CN;?<CH= +C2@d&Ci3`nAQW2D=Bo07>[CN;?<CH=<)cji9MJJc<E)pt8k_rY<)lOa9hJ)R8k_rO9MIrD77p6J +8k_rO9MJ,Q9hJ)R779R56q'O477p6J8k_rO9MJ,Q9hJ)R8k_rO9MJVo?:mmc=Bo07>[CN;?Asf$ +kj7d%m-ilnkNM:$kj7crjQGann)39ii8j(ZjQGI^kMYFai8j(ZjQGI^kN:RTi8j(SgtpuMkLnYI +i8j(SgtpuMkLnYIi8j(ZjQGI^kLnYIi8j(ZjQG4OhVdJXg"bHBjQGI^kLnYIi8j(SgtpuMkLnYI +i8j(SgtpuMkLnYIi8j(ZjQGI^kMYFai8j(SgtpuMkLnYIi8j(SgtpuMkLnYIi8j(Sgtp`>hV$]@ +g"bH;gtp`>hV$]@g"bH;gtp`>hV$]@g"bH;gtp`>hV$]@g"bH;gtp`>hV$]@g"bH;gtp`>hVdJX +g"bH;gtp`>hV$]@g"bH;gtp`>hV$]@g"bH;gtp`>hV$]@daZk$gtpK/f%Jj8daZjreCN'tf$`(! +daZjreCN'tf$`(!daZjreCN'tf$`(!daZjreCN'tf$`(!daZjreCN'tf$`(!daZjreCN'tf%Jj8 +daZk$gtpK/f%Jj8daZjreCN'tf$`(!daZjreCN'tf$`(!daZjreCN'tf#u:^daZjreCN'tf#u:^ +daZjkbg"Scf#u:^daZjkbg"Scf#u:^bKS5ZeCMgec-k+mbKS5Sbg">Tc-+>UdaZjkbg">Tc-+>U +bKS5ZeCMgec-k+mbKS5ZeCN'tf&5WPi8j(bm-j0)n*KZ=m.9oMs8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,kpA+@Sq=OCV +kj7d)oC_>6n*'-,kj7d%m-j0)n*'-,kj7d%m-j0)n*'-,kj7d%m-j0)n*'-,kj7d%m-j0)n*'-, +m.9oEm-!U!n*'-,kj7d1pA*q=n*KZ=kj7d)oC_JAp#tc2m.9oBpA*q=n*KZ=m.9o:oC_JAp$D;C +m.9oBpA+@Sq=OCVm.9o:oC_bLq=OCVm.9oBpA+@Sq=OCVo_/+IoC_JAp%Rh9m.9oBpA+(Hp%7tR +o_/+QpA+@Sq=OCVp[%)8pA+(Hp%Rh9o_/+QpA+@Sq=OCVo_/+QpA+@Sq=OCVo_/+QpA+@Sq=OCV +s8W,kpA+@Sq=OCVo_/+QpA+@Sq>^Kpo_/+QpA+@Sq>^Kpo_/+QpA+@Sq=OCVo_/+QpA+@Sq=OCV +o_/+QpA+@Sq=OCVo_/+QpA+@Sq=OCVo_/+QpA+@Sq=OCVo_/+\s8V`bq>^Kpo_/+\s8V`bq>^Kp +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s7H$\ +s8W-!s8V`bq>^Kps8W,kpA+ags8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +o_/+QpA*q=n)39ig"bH4eCMgec-+>U`5T^6`PoI%]eqW'779R:9MJ,Q9hJ)R8k_rO9MJVo?:mmc +=Bo0)9MJJc<E)pt<)ck">[C#r9hJ)R8k_rO9MJ,Q9iP(l<)ck">[Hdgp&G'ls8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W,kpA+ags8W-!o_/+QpA+ags7H$\o_/+QpA+@Sq=OCVo_/+QpA+ags7H$\ +o_/+\s8V`bq>^Kps8W,kpA+ags8W-!o_/+\s8W-!s8W-!s8W-!s8W-!s8W-!o_/+QpA+(Hp#tc2 +i8j(SgtpK/f$`(!bKS5L`Pod7`Pfa7]=bhq`PoI%]t:qj`5T^-]Y1\Z[!-V6=Bo03<)m%*?;sm( +<)cji9MJJc<E)pt<)ck">[C#r9iP(l<)cjs<)lms<E)pt=Bo07>[CN;?=RMW@q9.\A7\kJ?<CH= +=Bo07>[CN;?<CH=<)cjs<)m%*?;sm(<)cji9MJ,Q9hJ)R8k_rO9MJJc<D#qZ8k_rO9MJ,Q9hJ)R +8k_rO9MJ,Q9iP(l8k_r]>[CB/<E)pt<)ck">[CN;?<CH=C2@eGjQGn$p$D;Cm.9o:oC_JAp$D;C +m.9o:oC_JAp$D;Cm.9o:oC_JAp#tc2kj7d%m-j0)n*'-,kj7d%m-j0)n*'-,kj7d%m-j0)n*'-, +kj7d%m-j0)n*'-,kj7d%m-j0)n*'-,kj7d%m-j0)n*'-,kj7d%m-j0)n*'-,kj7d%m-j0)n*'-, +kj7d%m-j0)n*'-,kj7crjQGann)39ikj7crjQGI^kMYFakj7crjQGI^kMYFakj7crjQGI^kMYFa +i8j(bm-j0)n)39ikj7crjQGI^kNM:$i8j(bm-ilnkNM:$kj7crjQGI^kNM:$i8j(ZjQGann)39i +kj7crjQGI^kMYFai8j(ZjQGI^kMYFai8j(SgtpuMkMYFag"bHBjQGI^kMYFag"bHBjQGI^kLnYI +i8j(ZjQG4OhVdJXi8j(SgtpuMkLnYIi8j(SgtpuMkMYFai8j(Sgtp`>hVdJXg"bH;gtp`>hV$]@ +i8j(SgtpuMkLnYIg"bH;gtp`>hV$]@g"bH;gtp`>hV$]@g"bH;gtp`>hV$]@daZk$gtp`>hV$]@ +g"bH;gtp`>hV$]@g"bH;gtp`>hV$]@g"bH;gtpK/f%Jj8g"bH;gtp`>hU9p)g"bH;gtp`>hV$]@ +i8j(ZjQGI^kNM:$m.9oBpA+@Sq=OCVs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,kpA+@Sq=OCVo_/+QpA+@Sq=OCV +o_/+QpA+@Sq=OCVo_/+QpA+@Sq=OCVo_/+QpA+@Sq=OCVo_/+QpA+@Sq<[_Go_/+QpA+@Sq=OCV +o_/+QpA+@Sq=OCVo_/+QpA+@Sq=OCVs8W,kpA+@Sq>^Kpo_/+\s8W-!s7H$\s8W-!s8W-!s8W-! +o_/+\s8V`bq=OCVo_/+QpA+ags7H$\s8W-!s8V`bq=OCVs8W,kpA+@Sq=OCVs8W,kpA+ags8W-! +o_/+\s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8V`bq<[_Gkj7crjQG4OhU9p) +fZ_O^bg")F`Pfa7H[C/n/1jIf9hJ)R8k_rO9MJ,Q9hJ)R<)cji9MJVo?<CH=8k_rO9MJ,Q9hJ)R +8k_rO9MJ,Q9hJ)R8k_rO9MJ,Q9oP!hs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!o_/+IoC_>6n)39ig"bH4eCN'tf#u:^ +`5T^6`PoI%]t:qj]=bhh]Y1qi]t:qj]=bha['Y1,I99`\<)cjs<)lms<E)pt<)ck">[C#r9iP(l +8k_rY<)lOa9itY,8k_r]>[CN;?<CH==Bo0BA7\kJ?<CH=@q9.Q>[CN;?<CH=<)cji9MJJc<ENL4 +<)ck">[CB/<E)pt<)cjs<)lms<E)pt<)cjs<)lms<E)pt<)cji9MJJc<D#qZ=Bo03<)m%*?<CH= +=Bo03<)m%*?<CH==Bo0BA7a3=f'N#$m.9oBpA+@Sq=OCVs8W-!s8W-!s7H$\o_/+QpA+@Sq=OCV +o_/+QpA+ags7H$\o_/+QpA+@Sq=OCVo_/+QpA+@Sq=OCVo_/+QpA+@Sq=OCVo_/+QpA+@Sq=OCV +o_/+QpA+(Hp%7tRo_/+IoC_bLq=OCVo_/+QpA+@Sq=OCVo_/+QpA+@Sq=OCVm.9o:oC_bLq<[_G +m.9o:oC_JAp$D;Cm.9o:oC_JAp$D;Cm.9o:oC_JAp$D;Cm.9o:oC_JAp#tc2m.9o:oC_>6n*KZ= +m.9o6m-j<4p$D;Ckj7d)oC_>6n*KZ=kj7d)oC_JAp#tc2m.9o6m-j<4p$D;Ckj7d%m-j<4p#tc2 +kj7d%m-j0)n*'-,kj7d%m-j0)n*'-,i8j(bm-j0)n*'-,kj7d%m-j0)n*'-,kj7d%m-ilnkNM:$ +kj7d%m-j0)n*'-,kj7crjQGann*'-,kj7crjQGann*'-,kj7d%m-ilnkNM:$kj7d%m-j0)n*'-, +i8j(bm-ilnkMYFai8j(ZjQGI^kLnYIi8j(ZjQGI^kMYFai8j(SgtpuMkMYFai8j(SgtpuMkMYFa +i8j(ZjQGI^kMYFai8j(ZjQGI^kMYFai8j(ZjQGI^kMYFai8j(ZjQGann*'-,kj7d%m-j<4p$D;C +o_/+QpA+ags8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +o_/+\s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,kpA+ags8W-!o_/+\s8V`bq>^Kp +o_/+\s8W-!s7H$\s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!o_/+QpA*Y-kN:RTdaZjreCMgec-+>U`5T^-]Y-0Z1eLG9 +<)cji9MJ,Q9hJ)R8k_rO9MIrD77p6J779R:9MJ,Q9gqH=8k_r@4?Ybg4Zbbh4$5Yf4?Ybg4Zbbh +779T.m-juSs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!o_/+Em-j0)n(HLQdaZjreCMgec,@T?`5T^6`Pod7`Oidr +]=bhh]Y1qi]t:qj['[2eH[SL[9itY,<)ck">[CB/<ENL4<)cjs<)lOa9hJ)R8k_rY<)lOa9hJ)R +=Bo07>[CN;?<CH==Bo07>[CN;?<CH==Bo03<)lms<E)pt<)cjs<)lOa9iP(l<)cjs<)m%*?<CH= +<)ck">[CB/<E)pt=Bo07>[CN;?;sm(<)cjs<)m%*?<CH==Bo07>[CN;?<CH==Bo07>[CoNA\5Ug +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8V`bq>^Kps8W-!s8W-!s8W-!o_/+\s8V`bq>^Kpo_/+\s8V`bq>^Kpo_/+\s8V`bq=OCV +o_/+QpA+@Sq<[_Go_/+QpA+@Sq=OCVo_/+QpA+(Hp%7tRo_/+QpA+@Sq=OCVo_/+QpA+@Sq<[_G +o_/+QpA+(Hp%7tRo_/+IoC_bLq=OCVm.9oBpA+@Sq=OCVo_/+IoC_bLq<[_Gm.9o:oC_JAp$D;C +m.9o:oC_JAp$D;Cm.9o:oC_JAp#tc2m.9o:oC_JAp$D;Cm.9o:oC_JAp$D;Cm.9o:oC_JAp$D;C +m.9o:oC_JAp$D;Cm.9o:oC_JAp$D;Cm.9o:oC_>6n*'-,kj7d%m-j0)n*KZ=kj7d%m-j0)n*'-, +kj7d%m-j0)n*'-,kj7d%m-j0)n*'-,kj7d%m-j0)n*'-,kj7d%m-j0)n)39ikj7d%m-ilnkNM:$ +kj7d%m-j0)n*'-,kj7crjQGann*'-,kj7d)oC_JAp$D;Co_/+QpA+@Sq=OCVs8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!o_/+\s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8VHWp#tc2i8j(SgtpK/f#u:^bKS5L`Pod7`Hur[/hASH9MJ,Q9hJ)R8k_rJ6q'O476<Up +8k_rJ6q'O477BU5779R+4?Ybg4Zbbh4$5Yf4?Ybg4Zbbh4$5Yf4?\%<IJ!7/s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s7H$\kj7crjQGI^kL.l2daZjkbg")F`Pfa7]=bhh]Y28&`Oidr]=bhh]Y1qi]sP/R +H[C0C>[CN;?;sm(<)cjs<)lms<D#qZ<)cji9MJ,Q9hJ)R8k_r]>[CB/<ENL4=Bo07>[CN;?<CH= +=Bo03<)lOa9iP(l8k_rO9MJ,Q9iP(l<)cjs<)lms<ENL4<)ck">[CB/<ENL4<)ck">[CB/<ENL4 +=Bo07>[CB/<ENL4=Bo07>[CN;?=RMW=Bo07>[CN;?=RMW]=biLpA+ags8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W,kpA+ags8W-!o_/+\s8W-!s8W-!o_/+\s8V`bq=OCVo_/+QpA+@Sq=OCV +o_/+QpA+@Sq=OCVo_/+QpA+@Sq=OCVo_/+QpA+@Sq=OCVo_/+QpA+@Sq=OCVo_/+QpA+ags7H$\ +o_/+QpA+@Sq=OCVo_/+QpA+@Sq=OCVo_/+IoC_bLq=OCVm.9o:oC_JAp$D;Cm.9o:oC_JAp$D;C +m.9o:oC_JAp$D;Cm.9o:oC_JAp$D;Cm.9o:oC_JAp$D;Cm.9o:oC_JAp$D;Cm.9o:oC_JAp$D;C +m.9o:oC_JAp$D;Co_/+QpA+@Sq=OCVs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s7H$\m.9o6m-ilnkL.l2 +daZjkbg">Tc,@T?]=bg71c.9V4\ACB8k_rJ6q'^A9gqH=779R56q'O476<Up8k_rJ6q'^A9fkI# +4$5Yf4?Ybg4Zbbh4$5Yf4?Ybg4Zbbhg"bHas8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8V`bq<[_G +i8j(Sgtp`>hU9p)bKS5Sbg")F`Pfa7`5T^-]Y1qi]t:qj]=bhh]Y1qi]o7l.<)ck">[CB/<ENL4 +<)cjs<)lOa9iP(l8k_rO9MJJc<D#qZ<)cjs<)lms<ENL4=Bo07>[CN;?<CH==Bo03<)lms<E)pt +8k_rY<)lOa9iP(l<)ck">[CB/<E)pt=Bo0)9MJJc<E)pt<)ck">[CN;?<CH==Bo07>[CN;?<CH= +@q9.Q>[CN;?<CH=C2@e@gtr)2s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W,kpA+ags8W-!s8W,kpA+@Sq>^Kpo_/+QpA+@Sq=OCVo_/+QpA+@Sq=OCV +o_/+QpA+@Sq=OCVo_/+QpA+@Sq=OCVo_/+QpA+@Sq=OCVo_/+QpA+@Sq=OCVs8W,kpA+ags8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8V`bq>^Kp +o_/+\s8V`bq>^Kps8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,kpA+(Hp#+oog"bH4eCMgec-+>U`5T^6`Pm1NI3^$_ +8k_r@4?Ybg4Zbbh4$5Yf4?Ybg4Zbbh779R56q'O477BU5779R56q'O477BU5779R56q'^A9gqH= +779RZCi8n=q>^Kps8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,kpA+(Hp#tc2g"bH;gtpK/f#u:^ +`5T^6`Pod7`Oidr`5T^-]Y1qi]t:qj]=bhh]Y0i,S60$&<)ck">[CB/<E)pt<)cjs<)m%*?<CH= +<)ck">[CB/<E)pt<)cjs<)lms<ENL4=Bo07>[CB/<E)pt8k_rY<)lms<E)pt=Bo07>[CB/<E)pt +<)cji9MJ,Q9iP(l<)ck">[CN;?<CH==Bo07>[CoNARf7^=Bo0BA7\kJ?=RMW=Bo0kMi@#op&G'l +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,kpA+ags8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s6T@Mkj7d#gt^?-f$`(!bKS5L`Pod7`Pfa78k_r@4?Ybg4Zbbh4$5Yf4?Z,$76<Up +4$5Yf4?Ybg4Zbbh779R56q'^A9fkI#779R56q'O477BU5779R56q'O47G6JQs8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!o_/+Em-j0)n)39ig"bH;gtpK/f#u:^bKS5L`Pod7`Oidr +`5T^-]Y1qi]t:qj]=bhQV5.jBDH'S8=Bo03<)lms<ENL4=Bo07>[CN;?<CH==Bo03<)lms<D#qZ +=Bo07>[CN;?<CH=<)ck">[CB/<E)pt<)cjs<)lms<ENL4=Bo03<)m%*?;sm(8k_rO9MJJc<ENL4 +=Bo07>[CoNARf7^@q9.\A7]7]ARf7^@q9.tH[X>lf)PdMs8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W,kpA+ags8W-!s8W,kpA+ags8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,coC_>6n)39i +g"bH4eCMgec-+>UbKS5C]Y,pK/NZ'X4$5YY/1i_91c7*H4$5Yf4?Z,$77p6J8k_rJ6q'^A9gqH= +4$5Yu9MIrD77p6J8k_rO9MJ,Q9hJ)RC2@e[pA+ags8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!m.9o6m-ilnkMYFag"bH4eCN'tf#u:^bKS5L`Pod7`Pfa7]=bhq`PoI%]t:qj +['[2rKS3H4?<CH=@q9.Q>[CN;?<CH==Bo07>[CN;?<CH==Bo07>[CN;?<CH==Bo07>[CN;?<CH= +<)cjs<)lms<E)pt<)ck">[CB/<ENL4=Bo03<)m%*?<CH==Bo07>[CN;?<CH=@q9.\A7]LlDJF!* +C2@d&Ci6kt^%D$oo_/+\s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8V`bq>^Kp +s8W,kpA+ags8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s7H$\kj7crjQG4OhU9p)daZjreCMgec(q23 +/hAS31c.'H1bL=22)I-B/1iqG4Zbbh779R56q'1"4[hb-779R+4?Z;19gqH=779R:9MJ,Q9gqH= +8k_rO9MN^Sc2[hDs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s6T@M +m.9o.jQGI^kLnYIg"bH4eCN'tf#u:^bKS5Sbg")F`Pfa7`5T^6`PoI%]t:qjUnsl6H[TC7ARf7^ +=Bo07>[CN;?<CH==Bo07>[CN;?<CH==Bo07>[CN;?<CH==Bo07>[CB/<E)pt=Bo03<)lms<ENL4 +8k_r]>[CB/<E)pt<)ck">[CN;?<CH=@q9.\A7]LlDI[3gC2@d7H[W9.[/^1+s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!o_/+\s8V`bq>^Kp +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8VHWp#tc2i8j(ZjQG4OhU9p)daZj(KS23>1bL=2/hAS31c-g9/N#@A +2)I-O4?Z,$77p6J8k_rO9MJ,Q9hJ)R8k_rO9MJ,Q9hJ)R8k_rO9MJ,Q9knK^o_/+\s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8V`bq<[_Gm.9o.jQGI^kLnYI +g"bH;gtpK/f$`(!bKS5Sbg">Tc,@T?bKS5L`Pod7`OidrS=Z6tH[TC7AQW2D=Bo07>[CN;?<CH= +@q9.Q>[CN;?<CH=8k_r]>[C#r9iP(l<)ck">[C#r9itY,<)cjs<)m%*?:mmc<)ck">[CB/<ENL4 +=Bo07>[CoNARf7^@q9/0Mi>j'c1L`*o_/+\s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s7H$\s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +o_/+QpA*q=n)39ii8j(ZjQGI^kG4rMC2@ci>[BKS4YA9;2)I-B/1iqG4Zbbh4$5Yp6q'^A9gqH= +8k_rO9MJ,Q9iP(l<)cjs<)lms<D#qZ8k_sk]Y4@Fs8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8V`bq<[_Gkj7d)oC_&&kMYFag"bH;gtp`>hU9p) +daZjreCN'tf#u:^daZjkbg">Tc-+>U['[3!Mi;CeDHL.M=Bo07>[CN;?<CH==Bo0)9MJVo?;sm( +=Bo07>[C#r9iP(l<)cjs<)lms<E)pt<)ck">[C#r9iP(l8k_rO9MJVo?<CH=@q9/HV53>An+?>L +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +o_/+\s8W-!s7H$\s8W,kpA+ags8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s7H$\o_/+Em-j0)n*'-, +kj7crjQGI^kMYFai8j(>`Po3k[%*_XN/NXAH[TC7AP,Wj4$5Yu9MJ,Q9iP(l<)cjs<)lms<E)pt +8k_rY<)m%*?N:'*s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8V`bq<[_Gm.9o6m-j0)n)39ii8j(ZjQG4OhV$]@g"bH;gtpK/f$`(! +g"bH4eCN=.hU9p)daZj[]Y0i,S9K's=Bo0)9MJ,Q9itY,=Bo0)9MJVo?:mmc8k_rO9MJ,Q9hJ)R +8k_rO9MJ,Q9hJ)R8k_rO9MJ,Q9itY,S=Z8!eCO9cq=OCVs8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!o_/+\s8W-!s8W-! +o_/+\s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s7H$\o_/+IoC_JAp$D;Cm.9o:oC_>6n*KZ= +kj7d)oC_>6n*KZ=m.9o:oC_&&kKD)o]=bhXXK@G>N-fo"=Bo03<)lms<E)pt['[4?s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W,kpA+@Sq<[_Gm.9o:oC_>6n*'-,i8j(ZjQGI^kLnYIi8j(ZjQG4OhVdJXg"bH;gtpuMkLnYI +g"bHBjQG4OhSdCPUnslGMi<"0I99`\<)cjs<)lOa9hJ)R8k_rO9MJ,Q9hJ)R8k_r]>[EAIN3ot! +i8j)$s8V`bq>^Kps8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,kpA+ags8W-!o_/+\s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,kpA+@Sq=OCVm.9o:oC_JAp$D;Cm.9oBpA+@Sq=OCV +o_/+\s8V`bq=OCVo_/+\s8V`bq>^Kpm.9o.jQH1/q>^Kps8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8V`bq<[_G +o_/+IoC_JAp$D;Ckj7d%m-j0)n)39ikj7crjQGann*'-,i8j(bm-j0)n*'-,kj7d)oC_JAp$D;C +m.9o:oC_&&kL.l2daZjd`Pp$Ec-k+mg"bHBjQGn$p&G'lo_/+QpA+ags8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +o_/+\s8W-!s8W-!s8W,kpA+ags8W-!o_/+\s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s7H$\o_/+IoC_bLq<[_G +m.9o:oC_JAp$D;Cm.9o:oC_JAp$D;Cm.9o:oC_JAp$D;Co_/+QpA+ags7H$\s8W,kpA+ags7H$\ +s8W,kpA+ags8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!o_/+\s8V`bq>^Kp +s8W,kpA+ags8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W,kpA+ags7H$\o_/+QpA+(Hp%7tR +o_/+QpA+ags8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-! +s8W-!s8W-!s8W-!s8W-!s8W-!s7H$\s8W-!s8W-!s8W-!s8W,kpA+ags8W-!o_/+\s8N~> +Q +cleartomark end end pagesave restore showpage +%%PageTrailer +%%Trailer +%%Pages: 1 diff --git a/trunk/doc/doxygen_logo.gif b/trunk/doc/doxygen_logo.gif new file mode 100644 index 0000000..6b45597 Binary files /dev/null and b/trunk/doc/doxygen_logo.gif differ diff --git a/trunk/doc/doxygen_logo_low.gif b/trunk/doc/doxygen_logo_low.gif new file mode 100644 index 0000000..02e3c9a Binary files /dev/null and b/trunk/doc/doxygen_logo_low.gif differ diff --git a/trunk/doc/doxygen_manual.css b/trunk/doc/doxygen_manual.css new file mode 100644 index 0000000..1f22b59 --- /dev/null +++ b/trunk/doc/doxygen_manual.css @@ -0,0 +1,1029 @@ +/* The standard CSS for doxygen */ + +body, table, div, p, dl { + font-family: Lucida Grande, Verdana, Geneva, Arial, sans-serif; + font-size: 13px; + line-height: 1.3; +} + +/* @group Heading Levels */ + +h1 { + font-size: 150%; +} + +.title { + font-size: 150%; + font-weight: bold; + margin: 10px 2px; +} + +h2 { + font-size: 120%; +} + +h3 { + font-size: 100%; +} + +dt { + font-weight: bold; +} + +div.multicol { + -moz-column-gap: 1em; + -webkit-column-gap: 1em; + -moz-column-count: 3; + -webkit-column-count: 3; +} + +p.startli, p.startdd, p.starttd { + margin-top: 2px; +} + +p.endli { + margin-bottom: 0px; +} + +p.enddd { + margin-bottom: 4px; +} + +p.endtd { + margin-bottom: 2px; +} + +/* @end */ + +caption { + font-weight: bold; +} + +span.legend { + font-size: 70%; + text-align: center; +} + +h3.version { + font-size: 90%; + text-align: center; +} + +div.qindex, div.navtab{ + background-color: #F1F1F1; + border: 1px solid #BDBDBD; + text-align: center; +} + +div.qindex, div.navpath { + width: 100%; + line-height: 140%; +} + +div.navtab { + margin-right: 15px; +} + +/* @group Link Styling */ + +a { + color: #646494; + font-weight: normal; + text-decoration: none; +} + +.contents a:visited { + color: #7474A4; +} + +a:hover { + text-decoration: underline; +} + +a.qindex { + font-weight: bold; +} + +a.qindexHL { + font-weight: bold; + background-color: #B8B8B8; + color: #ffffff; + border: 1px double #A8A8A8; +} + +.contents a.qindexHL:visited { + color: #ffffff; +} + +a.el { + font-weight: bold; +} + +a.elRef { +} + +a.code, a.code:visited { + color: #4665A2; +} + +a.codeRef, a.codeRef:visited { + color: #4665A2; +} + +/* @end */ + +dl.el { + margin-left: -1cm; +} + +.fragment { + font-family: monospace, fixed; + font-size: 105%; +} + +pre.fragment { + border: 1px solid #D5D5D5; + background-color: #FCFCFC; + padding: 4px 6px; + margin: 4px 8px 4px 2px; + overflow: auto; + word-wrap: break-word; + font-size: 9pt; + line-height: 125%; +} + +div.ah { + background-color: black; + font-weight: bold; + color: #ffffff; + margin-bottom: 3px; + margin-top: 3px; + padding: 0.2em; + border: solid thin #333; + border-radius: 0.5em; + -webkit-border-radius: .5em; + -moz-border-radius: .5em; + box-shadow: 2px 2px 3px #999; + -webkit-box-shadow: 2px 2px 3px #999; + -moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px; + background-image: -webkit-gradient(linear, left top, left bottom, from(#eee), to(#000),color-stop(0.3, #444)); + background-image: -moz-linear-gradient(center top, #eee 0%, #444 40%, #000); +} + +div.groupHeader { + margin-left: 16px; + margin-top: 12px; + font-weight: bold; +} + +div.groupText { + margin-left: 16px; + font-style: italic; +} + +body { + background-color: #CCCCCC; + color: black; + margin: 0; +} + +div.contents { + margin-bottom: 10px; + padding: 8px; + margin-left: auto; + margin-right: auto; + width: 800px; + background-color: white; + -moz-border-radius-bottomleft: 8px; + -moz-border-radius-bottomright: 8px; + /* firefox specific markup */ + -moz-box-shadow: rgba(0, 0, 0, 0.15) 0px 0px 5px; + /* webkit specific markup */ + -webkit-box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.15); +} + +td.indexkey { + background-color: #F1F1F1; + font-weight: bold; + border: 1px solid #D5D5D5; + margin: 2px 0px 2px 0; + padding: 2px 10px; + white-space: nowrap; + vertical-align: top; +} + +td.indexvalue { + background-color: #F1F1F1; + border: 1px solid #D5D5D5; + padding: 2px 10px; + margin: 2px 0px; +} + +tr.memlist { + background-color: #F2F2F2; +} + +p.formulaDsp { + text-align: center; +} + +img.formulaDsp { + +} + +img.formulaInl { + vertical-align: middle; +} + +div.center { + text-align: center; + margin-top: 0px; + margin-bottom: 0px; + padding: 0px; +} + +div.center img { + border: 0px; +} + +address.footer { + text-align: right; + padding-right: 12px; + background-color: #8080A0; + color: white; +} + +img.footer { + border: 0px; + vertical-align: middle; +} + +/* @group Code Colorization */ + +span.keyword { + color: #008000 +} + +span.keywordtype { + color: #604020 +} + +span.keywordflow { + color: #e08000 +} + +span.comment { + color: #800000 +} + +span.preprocessor { + color: #806020 +} + +span.stringliteral { + color: #002080 +} + +span.charliteral { + color: #008080 +} + +span.vhdldigit { + color: #ff00ff +} + +span.vhdlchar { + color: #000000 +} + +span.vhdlkeyword { + color: #700070 +} + +span.vhdllogic { + color: #ff0000 +} + +blockquote { + background-color: #F9F9F9; + border-left: 2px solid #B8B8B8; + margin: 0 24px 0 4px; + padding: 0 12px 0 16px; +} + +/* @end */ + +/* +.search { + color: #003399; + font-weight: bold; +} + +form.search { + margin-bottom: 0px; + margin-top: 0px; +} + +input.search { + font-size: 75%; + color: #000080; + font-weight: normal; + background-color: #e8eef2; +} +*/ + +td.tiny { + font-size: 75%; +} + +.dirtab { + padding: 4px; + border-collapse: collapse; + border: 1px solid #BDBDBD; +} + +th.dirtab { + background: #F1F1F1; + font-weight: bold; +} + +hr { + height: 0px; + border: none; + border-top: 1px solid #7A7A7A; +} + +hr.footer { + display: none; +} + +/* @group Member Descriptions */ + +table.memberdecls { + border-spacing: 0px; + padding: 0px; +} + +.mdescLeft, .mdescRight, +.memItemLeft, .memItemRight, +.memTemplItemLeft, .memTemplItemRight, .memTemplParams { + background-color: #FAFAFA; + border: none; + margin: 4px; + padding: 1px 0 0 8px; +} + +.mdescLeft, .mdescRight { + padding: 0px 8px 4px 8px; + color: #555; +} + +.memItemLeft, .memItemRight, .memTemplParams { + border-top: 1px solid #D5D5D5; +} + +.memItemLeft, .memTemplItemLeft { + white-space: nowrap; +} + +.memItemRight { + width: 100%; +} + +.memTemplParams { + color: #747474; + white-space: nowrap; +} + +/* @end */ + +/* @group Member Details */ + +/* Styles for detailed member documentation */ + +.memtemplate { + font-size: 80%; + color: #747474; + font-weight: normal; + margin-left: 9px; +} + +.memnav { + background-color: #F1F1F1; + border: 1px solid #BDBDBD; + text-align: center; + margin: 2px; + margin-right: 15px; + padding: 2px; +} + +.mempage { + width: 100%; +} + +.memitem { + padding: 0; + margin-bottom: 10px; + margin-right: 5px; +} + +.memname { + white-space: nowrap; + font-weight: bold; + margin-left: 6px; +} + +.memproto, dl.reflist dt { + border-top: 1px solid #C0C0C0; + border-left: 1px solid #C0C0C0; + border-right: 1px solid #C0C0C0; + padding: 6px 0px 6px 0px; + color: #3D3D3D; + font-weight: bold; + text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.9); + /* opera specific markup */ + box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); + border-top-right-radius: 8px; + border-top-left-radius: 8px; + /* firefox specific markup */ + -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px; + -moz-border-radius-topright: 8px; + -moz-border-radius-topleft: 8px; + /* webkit specific markup */ + -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); + -webkit-border-top-right-radius: 8px; + -webkit-border-top-left-radius: 8px; + background-image:url('nav_f.png'); + background-repeat:repeat-x; + background-color: #EAEAEA; + +} + +.memdoc, dl.reflist dd { + border-bottom: 1px solid #C0C0C0; + border-left: 1px solid #C0C0C0; + border-right: 1px solid #C0C0C0; + padding: 2px 5px; + background-color: #FCFCFC; + border-top-width: 0; + /* opera specific markup */ + border-bottom-left-radius: 8px; + border-bottom-right-radius: 8px; + box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); + /* firefox specific markup */ + -moz-border-radius-bottomleft: 8px; + -moz-border-radius-bottomright: 8px; + -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px; + background-image: -moz-linear-gradient(center top, #FFFFFF 0%, #FFFFFF 60%, #F9F9F9 95%, #F2F2F2); + /* webkit specific markup */ + -webkit-border-bottom-left-radius: 8px; + -webkit-border-bottom-right-radius: 8px; + -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); + background-image: -webkit-gradient(linear,center top,center bottom,from(#FFFFFF), color-stop(0.6,#FFFFFF), color-stop(0.60,#FFFFFF), color-stop(0.95,#F9F9F9), to(#F2F2F2)); +} + +dl.reflist dt { + padding: 5px; +} + +dl.reflist dd { + margin: 0px 0px 10px 0px; + padding: 5px; +} + +.paramkey { + text-align: right; +} + +.paramtype { + white-space: nowrap; +} + +.paramname { + color: #602020; + white-space: nowrap; +} +.paramname em { + font-style: normal; +} + +.params, .retval, .exception, .tparams { + border-spacing: 6px 2px; +} + +.params .paramname, .retval .paramname { + font-weight: bold; + vertical-align: top; +} + +.params .paramtype { + font-style: italic; + vertical-align: top; +} + +.params .paramdir { + font-family: "courier new",courier,monospace; + vertical-align: top; +} + + + + +/* @end */ + +/* @group Directory (tree) */ + +/* for the tree view */ + +.ftvtree { + font-family: sans-serif; + margin: 0px; +} + +/* these are for tree view when used as main index */ + +.directory { + font-size: 9pt; + font-weight: bold; + margin: 5px; +} + +.directory h3 { + margin: 0px; + margin-top: 1em; + font-size: 11pt; +} + +/* +The following two styles can be used to replace the root node title +with an image of your choice. Simply uncomment the next two styles, +specify the name of your image and be sure to set 'height' to the +proper pixel height of your image. +*/ + +/* +.directory h3.swap { + height: 61px; + background-repeat: no-repeat; + background-image: url("yourimage.gif"); +} +.directory h3.swap span { + display: none; +} +*/ + +.directory > h3 { + margin-top: 0; +} + +.directory p { + margin: 0px; + white-space: nowrap; +} + +.directory div { + display: none; + margin: 0px; +} + +.directory img { + vertical-align: -30%; +} + +/* these are for tree view when not used as main index */ + +.directory-alt { + font-size: 100%; + font-weight: bold; +} + +.directory-alt h3 { + margin: 0px; + margin-top: 1em; + font-size: 11pt; +} + +.directory-alt > h3 { + margin-top: 0; +} + +.directory-alt p { + margin: 0px; + white-space: nowrap; +} + +.directory-alt div { + display: none; + margin: 0px; +} + +.directory-alt img { + vertical-align: -30%; +} + +/* @end */ + +div.dynheader { + margin-top: 8px; +} + +address { + font-style: normal; + color: #464646; +} + +table.doxtable { + border-collapse:collapse; + margin-top: 4px; + margin-bottom: 4px; +} + +table.doxtable td, table.doxtable th { + border: 1px solid #4A4A4A; + padding: 3px 7px 2px; +} + +table.doxtable th { + background-color: #5B5B5B; + color: #FFFFFF; + font-size: 110%; + padding-bottom: 4px; + padding-top: 5px; + text-align:left; +} + +table.fieldtable { + width: 100%; + margin-bottom: 10px; + border: 1px solid #C0C0C0; + border-spacing: 0px; + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + border-radius: 4px; + -moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px; + -webkit-box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.15); + box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.15); +} + +.fieldtable td, .fieldtable th { + padding: 3px 7px 2px; +} + +.fieldtable td.fieldtype, .fieldtable td.fieldname { + white-space: nowrap; + border-right: 1px solid #C0C0C0; + border-bottom: 1px solid #C0C0C0; + vertical-align: top; +} + +.fieldtable td.fielddoc { + border-bottom: 1px solid #C0C0C0; + width: 100%; +} + +.fieldtable tr:last-child td { + border-bottom: none; +} + +.fieldtable th { + background-image:url('nav_f.png'); + background-repeat:repeat-x; + background-color: #EAEAEA; + font-size: 90%; + color: #3D3D3D; + padding-bottom: 4px; + padding-top: 5px; + text-align:left; + -moz-border-radius-topleft: 4px; + -moz-border-radius-topright: 4px; + -webkit-border-top-left-radius: 4px; + -webkit-border-top-right-radius: 4px; + border-top-left-radius: 4px; + border-top-right-radius: 4px; + border-bottom: 1px solid #C0C0C0; +} + + +.tabsearch { + top: 0px; + left: 10px; + height: 36px; + background-image: url('tab_b.png'); + z-index: 101; + overflow: hidden; + font-size: 13px; +} + +.navpath ul +{ + font-size: 11px; + background-image:url('tab_b.png'); + background-repeat:repeat-x; + height:30px; + line-height:30px; + color:#ABABAB; + border:solid 1px #D3D3D3; + overflow:hidden; + margin:0px; + padding:0px; +} + +.navpath li +{ + list-style-type:none; + float:left; + padding-left:10px; + padding-right:15px; + background-image:url('bc_s.png'); + background-repeat:no-repeat; + background-position:right; + color:#595959; +} + +.navpath li.navelem a +{ + height:32px; + display:block; + text-decoration: none; + outline: none; +} + +.navpath li.navelem a:hover +{ + color:#929292; +} + +.navpath li.footer +{ + list-style-type:none; + float:right; + padding-left:10px; + padding-right:15px; + background-image:none; + background-repeat:no-repeat; + background-position:right; + color:#595959; + font-size: 8pt; +} + + +div.summary +{ + float: right; + font-size: 8pt; + padding-right: 5px; + width: 50%; + text-align: right; +} + +div.summary a +{ + white-space: nowrap; +} + +div.ingroups +{ + margin-left: 5px; + font-size: 8pt; + padding-left: 5px; + width: 50%; + text-align: left; +} + +div.ingroups a +{ + white-space: nowrap; +} + +div.header +{ + background-image:url('nav_h.png'); + background-repeat:repeat-x; + background-color: #FAFAFA; + border-bottom: 1px solid #D5D5D5; + margin-left: auto; + margin-right: auto; + width: 800px; + padding-left: 8px; + padding-right: 8px; + /* firefox specific markup */ + -moz-box-shadow: rgba(0, 0, 0, 0.15) 0px 0px 5px; + /* webkit specific markup */ + -webkit-box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.15); +} + +div.headertitle +{ + padding: 5px 5px 5px 7px; +} + +dl +{ + padding: 0 0 0 10px; +} + +dl.section +{ + border-left:4px solid; + padding: 0 0 0 6px; +} + +dl.note +{ + border-color: #D0C000; +} + +dl.warning, dl.attention +{ + border-color: #FF0000; +} + +dl.pre, dl.post, dl.invariant +{ + border-color: #00D000; +} + +dl.deprecated +{ + border-color: #505050; +} + +dl.todo +{ + border-color: #00C0E0; +} + +dl.test +{ + border-color: #3030E0; +} + +dl.bug +{ + border-color: #C08050; +} + +dl.section dd { + margin-bottom: 1em; +} + +#projectlogo +{ + text-align: center; + vertical-align: bottom; + border-collapse: separate; +} + +#projectlogo img +{ + border: 0px none; +} + +#projectname +{ + font: 300% Tahoma, Arial,sans-serif; + margin: 0px; + padding: 2px 0px; +} + +#projectbrief +{ + font: 120% Tahoma, Arial,sans-serif; + margin: 0px; + padding: 0px; +} + +#projectnumber +{ + font: 50% Tahoma, Arial,sans-serif; + margin: 0px; + padding: 0px; +} + +#titlearea +{ + padding: 0px; + margin: 0px; + width: 100%; + border-bottom: 1px solid #848484; +} + +.image +{ + text-align: center; +} + +.dotgraph +{ + text-align: center; +} + +.mscgraph +{ + text-align: center; +} + +.caption +{ + font-weight: bold; +} + +div.zoom +{ + border: 1px solid #AFAFAF; +} + +dl.citelist { + margin-bottom:50px; +} + +dl.citelist dt { + color:#545454; + float:left; + font-weight:bold; + margin-right:10px; + padding:5px; +} + +dl.citelist dd { + margin:2px 0; + padding:5px 0; +} + +div.toc { + padding: 14px 25px; + background-color: #F6F6F6; + border: 1px solid #DDDDDD; + border-radius: 7px 7px 7px 7px; + float: right; + height: auto; + margin: 0 20px 10px 10px; + width: 200px; +} + +div.toc li { + background: url("bdwn.png") no-repeat scroll 0 5px transparent; + font: 10px/1.2 Verdana,DejaVu Sans,Geneva,sans-serif; + margin-top: 5px; + padding-left: 10px; + padding-top: 2px; +} + +div.toc h3 { + font: bold 12px/1.2 Arial,FreeSans,sans-serif; + border-bottom: 0 none; + color: #606060; + margin: 0; +} + +div.toc ul { + list-style: none outside none; + border: medium none; + padding: 0px; +} + +div.toc li.level1 { + margin-left: 0px; +} + +div.toc li.level2 { + margin-left: 15px; +} + +div.toc li.level3 { + margin-left: 30px; +} + +div.toc li.level4 { + margin-left: 45px; +} + +@media print +{ + #top { display: none; } + #side-nav { display: none; } + #nav-path { display: none; } + body { overflow:visible; } + h1, h2, h3, h4, h5, h6 { page-break-after: avoid; } + .summary { display: none; } + .memitem { page-break-inside: avoid; } + #doc-content + { + margin-left:0 !important; + height:auto !important; + width:auto !important; + overflow:inherit; + display:inline; + } + pre.fragment + { + overflow: visible; + text-wrap: unrestricted; + white-space: -moz-pre-wrap; /* Moz */ + white-space: -pre-wrap; /* Opera 4-6 */ + white-space: -o-pre-wrap; /* Opera 7 */ + white-space: pre-wrap; /* CSS3 */ + word-wrap: break-word; /* IE 5.5+ */ + } +} + diff --git a/trunk/doc/doxygen_manual.tex b/trunk/doc/doxygen_manual.tex new file mode 100644 index 0000000..8e47015 --- /dev/null +++ b/trunk/doc/doxygen_manual.tex @@ -0,0 +1,110 @@ +% +% +% +% Copyright (C) 1997-2011 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. + +\documentclass{book} +\usepackage[a4paper,left=2.5cm,right=2.5cm,top=2.5cm,bottom=2.5cm]{geometry} +\usepackage{makeidx} +\usepackage{natbib} +\usepackage{graphicx} +\usepackage{multicol} +\usepackage{float} +\usepackage{geometry} +\usepackage{listings} +\usepackage{color} +\usepackage{ifthen} +\usepackage[table]{xcolor} +\usepackage{textcomp} +\usepackage{alltt} +\usepackage{ifpdf} +\ifpdf +\usepackage[pdftex, + pagebackref=true, + colorlinks=true, + linkcolor=blue, + unicode + ]{hyperref} +\else +\usepackage[ps2pdf, + pagebackref=true, + colorlinks=true, + linkcolor=blue, + unicode + ]{hyperref} +\usepackage{pspicture} +\fi +\usepackage[utf8]{inputenc} +\usepackage{mathptmx} +\usepackage[scaled=.90]{helvet} +\usepackage{courier} +\usepackage{sectsty} +\usepackage[titles]{tocloft} +\usepackage{doxygen} +\lstset{language=C++,inputencoding=utf8,basicstyle=\footnotesize,breaklines=true,breakatwhitespace=true,tabsize=8,numbers=left } +\makeindex +\setcounter{tocdepth}{3} +\renewcommand{\footrulewidth}{0.4pt} +\renewcommand{\familydefault}{\sfdefault} +\renewcommand{\cftsecindent}{0 em} +\renewcommand{\cftsecnumwidth}{3.2 em} +\renewcommand{\cftsubsecindent}{3.2 em} +\newcommand{\thisyear}{\the\year} +\hfuzz=15pt +\setlength{\emergencystretch}{15pt} +\hbadness=750 +\tolerance=750 +\begin{document} +\begin{titlepage} +\includegraphics[width=\textwidth]{doxygen_logo} +\begin{center} +Manual for version $VERSION\\[2ex] +Written by Dimitri van Heesch\\[2ex] +\copyright 1997-\thisyear +\end{center} +\end{titlepage} +\clearemptydoublepage +\tableofcontents +\clearemptydoublepage +\pagenumbering{arabic} +\include{index} +\part{User Manual} +\chapter{Installation}\label{install}\hypertarget{install}{}\input{install} +\chapter{Getting Started}\label{starting}\hypertarget{starting}{}\input{starting} +\chapter{Documenting the code}\label{docblocks}\hypertarget{docblocks}{}\input{docblocks} +\chapter{Markdown}\label{markdown}\hypertarget{markdown}{}\input{markdown} +\chapter{Grouping}\label{grouping}\hypertarget{grouping}{}\input{grouping} +\chapter{Including Formulas}\label{formulas}\hypertarget{formulas}{}\input{formulas} +\chapter{Graphs and diagrams}\label{diagrams}\hypertarget{diagrams}{}\input{diagrams} +\chapter{Preprocessing}\label{preprocessing}\hypertarget{preprocessing}{}\input{preprocessing} +\chapter{Automatic link generation}\label{autolink}\hypertarget{autolink}{}\input{autolink} +\chapter{Output Formats}\label{output}\hypertarget{output}{}\input{output} +\chapter{Searching}\label{searching}\hypertarget{searching}{}\input{searching} +\chapter{Customizing the Output}\label{customize}\hypertarget{customize}{}\input{customize} +\chapter{Custom Commands}\label{custcmd}\hypertarget{custcmd}{}\input{custcmd} +\chapter{Link to external documentation}\label{external}\hypertarget{external}{}\input{external} +\chapter{Frequently Asked Questions}\label{faq}\hypertarget{faq}{}\input{faq} +\chapter{Troubleshooting}\label{trouble}\hypertarget{trouble}{}\input{trouble} +\part{Reference Manual} +\chapter{Features}\label{features}\hypertarget{features}{}\input{features} +\chapter{Doxygen usage}\label{doxygen_usage}\hypertarget{doxygen_usage}{}\input{doxygen_usage} +\chapter{Doxywizard usage}\label{doxywizard_usage}\hypertarget{doxywizard_usage}{}\input{doxywizard_usage} +\chapter{Configuration}\label{config}\hypertarget{config}{}\input{config} +\chapter{Special Commands}\label{commands}\hypertarget{commands}{}\input{commands} +\chapter{HTML commands}\label{htmlcmds}\hypertarget{htmlcmds}{}\input{htmlcmds} +\chapter{XML commands}\label{xmlcmds}\hypertarget{xmlcmds}{}\input{xmlcmds} +\part{Developers Manual} +\chapter{Doxygen's internals}\label{arch}\hypertarget{arch}{}\input{arch} +\chapter{Perl Module Output format}\label{perlmod}\hypertarget{perlmod}{}\input{perlmod} +\chapter{Internationalization}\label{langhowto}\hypertarget{langhowto}{}\input{langhowto} +\printindex +\end{document} diff --git a/trunk/doc/doxygen_usage.doc b/trunk/doc/doxygen_usage.doc new file mode 100644 index 0000000..40e5163 --- /dev/null +++ b/trunk/doc/doxygen_usage.doc @@ -0,0 +1,106 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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 doxygen_usage Doxygen usage + +Doxygen is a command line based utility. Calling \c doxygen with the +\c --help option at the command line will give you a brief description of the +usage of the program. + +All options consist of a leading character <tt>-</tt>, +followed by one character and one or more arguments depending on the option. + +To generate a manual for your project you typically +need to follow these steps: +<ol> +<li> You document your source code with + special documentation blocks (see section \ref specialblock). +<li> You generate a configuration file (see section \ref config) by + calling doxygen with the \c -g option: +\verbatim +doxygen -g <config_file> +\endverbatim +<li> You edit the configuration file so it matches your project. + In the configuration file you can specify the input files and + a lot of optional information. +<li> You let doxygen generate the documentation, based on the settings in the + configuration file: +\verbatim +doxygen <config_file> +\endverbatim +</ol> + +If you have a configuration file generated with an older version of +doxygen, you can upgrade it to the current version by running doxygen +with the -u option. +\verbatim +doxygen -u <config_file> +\endverbatim +All configuration settings in the original configuration file will be copied +to the new configuration file. Any new options will have their default value. +Note that comments that you may have added in the original configuration file +will be lost. + +\section doxygen_finetune Fine-tuning the output +If you want to fine-tune the way the output looks, doxygen allows you +generate default style sheet, header, and footer files that you can edit +afterwards: +<ul> +<li>For HTML output, you can generate the default header file + (see \ref cfg_html_header "HTML_HEADER"), the default footer + (see \ref cfg_html_footer "HTML_FOOTER"), and the default style + sheet (see \ref cfg_html_stylesheet "HTML_STYLESHEET"), using the + following command: +\verbatim +doxygen -w html header.html footer.html stylesheet.css <config_file> +\endverbatim + The config_file is optional. When omitted doxygen will search for + a file named Doxyfile and process that. When this is also not found it + will used the default settings. + +<li>For LaTeX output, you can generate the first part of \c refman.tex + (see \ref cfg_latex_header "LATEX_HEADER") and the style sheet included + by that header (normally <code>doxygen.sty</code>), using: +\verbatim +doxygen -w latex header.tex doxygen.sty +\endverbatim +If you need non-default options (for instance to use pdflatex) you need +to make a config file with those options set correctly and then specify +that config file as the third argument. +<li>For RTF output, you can generate the default style sheet file (see + \ref cfg_rtf_stylesheet_file "RTF_STYLESHEET_FILE") using: +\verbatim +doxygen -w rtf rtfstyle.cfg +\endverbatim +</ul> +\warning When using a custom header you are responsible + for the proper inclusion of any scripts and style sheets that doxygen + needs, which is dependent on the configuration options and may changes + when upgrading to a new doxygen release. + +\note +<ul> +<li> If you do not want documentation for each item inside the configuration + file then you can use the optional \c -s option. This can use be + used in combination with the \c -u option, to add or strip the + documentation from an existing configuration file. + Please use the \c -s option if you send me a configuration file + as part of a bug report! +<li> To make doxygen read/write to standard input/output instead of from/to + a file, use \c - for the file name. +</ul> + +*/ diff --git a/trunk/doc/doxywizard.1 b/trunk/doc/doxywizard.1 new file mode 100644 index 0000000..a209f21 --- /dev/null +++ b/trunk/doc/doxywizard.1 @@ -0,0 +1,10 @@ +.TH DOXYWIZARD "1" "DATE" "doxywizard VERSION" "User Commands" +.SH NAME +doxywizard \- a tool to configure and run doxygen on your source files +.SH SYNOPSIS +.B doxywizard +.SH DESCRIPTION +Doxywizard is an interactive frontend to the doxygen tool to configure +and run doxygen on your source files. +.SH SEE ALSO +doxygen(1) diff --git a/trunk/doc/doxywizard.gif b/trunk/doc/doxywizard.gif new file mode 100644 index 0000000..80bb636 Binary files /dev/null and b/trunk/doc/doxywizard.gif differ diff --git a/trunk/doc/doxywizard_expert.png b/trunk/doc/doxywizard_expert.png new file mode 100644 index 0000000..93fd4ee Binary files /dev/null and b/trunk/doc/doxywizard_expert.png differ diff --git a/trunk/doc/doxywizard_main.png b/trunk/doc/doxywizard_main.png new file mode 100644 index 0000000..e57c144 Binary files /dev/null and b/trunk/doc/doxywizard_main.png differ diff --git a/trunk/doc/doxywizard_menu.png b/trunk/doc/doxywizard_menu.png new file mode 100644 index 0000000..37adc46 Binary files /dev/null and b/trunk/doc/doxywizard_menu.png differ diff --git a/trunk/doc/doxywizard_page1.png b/trunk/doc/doxywizard_page1.png new file mode 100644 index 0000000..ee3181d Binary files /dev/null and b/trunk/doc/doxywizard_page1.png differ diff --git a/trunk/doc/doxywizard_page2.png b/trunk/doc/doxywizard_page2.png new file mode 100644 index 0000000..dc9b5a8 Binary files /dev/null and b/trunk/doc/doxywizard_page2.png differ diff --git a/trunk/doc/doxywizard_page3.png b/trunk/doc/doxywizard_page3.png new file mode 100644 index 0000000..f75e63f Binary files /dev/null and b/trunk/doc/doxywizard_page3.png differ diff --git a/trunk/doc/doxywizard_page4.png b/trunk/doc/doxywizard_page4.png new file mode 100644 index 0000000..e4f4361 Binary files /dev/null and b/trunk/doc/doxywizard_page4.png differ diff --git a/trunk/doc/doxywizard_usage.doc b/trunk/doc/doxywizard_usage.doc new file mode 100644 index 0000000..435661b --- /dev/null +++ b/trunk/doc/doxywizard_usage.doc @@ -0,0 +1,138 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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 doxywizard_usage Doxywizard usage + +Doxywizard is a GUI front-end for configuring and running doxygen. + +When you start doxywizard it will display the main window +(the actual look depends on the OS used). + +\image html doxywizard_main.png "Main window" + +The windows shows the steps to take to configure and run doxygen. +The first step is to choose one of the ways to configure doxygen. +<dl> +<dt>Wizard<dd>Click this button to quickly configure the most important + settings and leave the rest of the options to their defaults. +<dt>Expert<dd>Click this button to gain access to the + \ref config "full range of configuration options". +<dt>Load<dd>Click this button to load an existing configuration file + from disk. +</dl> +Note that you can select multiple buttons in a row, for instance to first +configure doxygen using the Wizard and then fine tune the settings via +the Expert. + +After doxygen is configured you need to save the configuration as a file +to disk. This second step allows doxygen to use the configuration +and has the additional advantage that the configuration can be reused +to run doxygen with the same settings at a later point in time. + +Since some configuration options may use relative paths, the next step is +to select a directory from which to run doxygen. This is typically the root +of the source tree and will most of the time already be filled in correctly. + +Once the configuration file is saved and the working directory is set, you +can run doxygen based on the selected settings. Do this by pressing the +"Start" button. Once doxygen runs you can cancel it by clicking the same +button again. The output produced by doxygen is captured and shown in a log +window. Once doxygen finishes, the log can be saved as a text file. + +<h3>The Wizard Dialog</h3> + +If you select the Wizard button in step 1, then a dialog with +a number of tabs will appear. + +\image html doxywizard_page1.png "Wizard dialog: Project settings" + +The fields in the project tab speak for themselves. Once doxygen has finished +the Destination directory is where to look for the results. Doxygen will +put each output format in a separate sub-directory. + +\image html doxywizard_page2.png "Wizard dialog: Mode of operating" + +The mode tab allows you to select how doxygen will look at your sources. +The default is to only look for things that have been documented. + +You can also select how doxygen should present the results. +The latter does not affect the way doxygen parses your source code. + +\image html doxywizard_page3.png "Wizard dialog: Output to produce" + +You can select one or more of the output formats that doxygen should +produce. For HTML and LaTeX there are additional options. + +\image html doxywizard_page4.png "Wizard dialog: Diagrams to generate" + +Doxygen can produce a number of diagrams. Using the diagrams tab you +can select which ones to generate. For most diagrams the +dot tool of the <a href="http://www.graphviz.org">GraphViz</a> package +is needed (if you use the binary packages for MacOSX this +tool is already included). + +<h3>Expert dialog</h3> + +The Expert dialog has a number of tab fields, one +for each section in the configuration file. Each tab-field +contains a number of lines, one for each configuration option in +that section. + +The kind of input widget depends on the type of the configuration option. +<ul> +<li>For each boolean option (those options that are answered with YES or + NO in the configuration file) there is a check-box. +<li>For items taking one of a fixed set of values (like + \ref cfg_output_language "OUTPUT_LANGUAGE") a combo box is used. +<li>For items taking an integer value from a range, a spinbox is used. +<li>For free form string-type options there is a one line edit field +<li>For options taking a lists of strings, a one line edit field is + available, with a `+' button to add this string to the list and + a `-' button to remove the selected string from the list. There + is also a `*' button that, when pressed, + replaces the selected item in the list with the string entered in the + edit field. +<li>For file and folder entries, there are special buttons + that start a file selection dialog. +</ul> + +\image html doxywizard_expert.png "Some options from the Expert dialog" + +The get additional information about the meaning of an option, click +on the "Help" button at the bottom right of the dialog and then on the +item. A tooltip with additional information will appear. + +<h3>Menu options</h3> + +The GUI front-end has a menu with a couple of useful items + +\image html doxywizard_menu.png "File menu" + +<dl> +<dt>Open...<dd>This is the same as the "Load" button in the main window + and allows to open a configuration file from disk. +<dt>Save as..<dd>This is the same as the "Save" button in the main window + and can be used to save the current configuration settings to disk. +<dt>Recent configurations<dd>Allow to quickly load a recently saved + configuration. +<dt>Set as default...<dd>Stores the current configuration settings as the + default to use next time the GUI is started. You will be asked to + confirm the action. +<dt>Reset...<dd>Restores the factory defaults as the default settings to use. + You will be asked to confirm the action. +</dl> + +*/ diff --git a/trunk/doc/external.doc b/trunk/doc/external.doc new file mode 100644 index 0000000..013b7c2 --- /dev/null +++ b/trunk/doc/external.doc @@ -0,0 +1,120 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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 external Linking to external documentation + +If your project depends on external libraries or tools, there are several +reasons to not include all sources for these with every run of doxygen: + +<dl> +<dt>Disk space:<dd> Some documentation may be available outside of the output + directory of doxygen already, for instance somewhere on the web. + You may want to link to these pages instead of generating the documentation + in your local output directory. +<dt>Compilation speed:<dd> External projects typically have a different update + frequency from your own project. It does not make much sense to let doxygen + parse the sources for these external project over and over again, even if + nothing has changed. +<dt>Memory:<dd> For very large source trees, letting doxygen parse all sources + may simply take too much of your system's memory. By dividing the sources + into several "packages", the sources of one package can be parsed by + doxygen, while all other packages that this package depends on, are + linked in externally. This saves a lot of memory. +<dt>Availability:<dd> For some projects that are documented with doxygen, + the sources may just not be available. +<dt>Copyright issues:<dd>If the external + package and its documentation are copyright someone else, it may be + better - or even necessary - to reference it rather than include a + copy of it with your project's documentation. When the author forbids + redistribution, this is necessary. If the author requires compliance + with some license condition as a precondition of redistribution, and + you do not want to be bound by those conditions, referring to their + copy of their documentation is preferable to including a copy. + +</dl> + +If any of the above apply, you can use doxygen's tag file mechanism. +A tag file is basically a compact representation of the entities found in the +external sources. Doxygen can both generate and read tag files. + +To generate a tag file for your project, simply put the name of the +tag file after the \ref cfg_generate_tagfile "GENERATE_TAGFILE" option in +the configuration file. + +To combine the output of one or more external projects with your own project +you should specify the name of the tag files after +the \ref cfg_tagfiles "TAGFILES" option in the configuration file. + +A tag file typically only contains a relative location of the documentation from the +point where doxygen was run. So when you include a tag file in other project +you have to specify where the external documentation is located in relation this project. +You can do this in the configuration file by assigning the (relative) location to the +tag files specified after the \ref cfg_tagfiles "TAGFILES" configuration +option. If you use a relative path it should be relative with respect to +the directory where the HTML output of your project is generated; so a relative path +from the HTML output directory of a project to the HTML output of the other project that +is linked to. + +\par Example: +Suppose you have a project \c proj that uses two external +projects called \c ext1 and \c ext2. +The directory structure looks as follows: + +\par +\verbatim +<root> + +- proj + | +- html HTML output directory for proj + | +- src sources for proj + | |- proj.cpp + +- ext1 + | +- html HTML output directory for ext1 + | |- ext1.tag tag file for ext1 + +- ext2 + | +- html HTML output directory for ext2 + | |- ext2.tag tag file for ext2 + |- proj.cfg doxygen configuration file for proj + |- ext1.cfg doxygen configuration file for ext1 + |- ext2.cfg doxygen configuration file for ext2 +\endverbatim + +\par +Then the relevant parts of the configuration files look as follows: +\par +proj.cfg: +\verbatim +OUTPUT_DIRECTORY = proj +INPUT = proj/src +TAGFILES = ext1/ext1.tag=../../ext1/html \ + ext2/ext2.tag=../../ext2/html +\endverbatim +ext1.cfg: +\verbatim +OUTPUT_DIRECTORY = ext1 +GENERATE_TAGFILE = ext1/ext1.tag +\endverbatim +ext2.cfg: +\verbatim +OUTPUT_DIRECTORY = ext2 +GENERATE_TAGFILE = ext2/ext2.tag +\endverbatim + +\htmlonly +Go to the <a href="faq.html">next</a> section or return to the + <a href="index.html">index</a>. +\endhtmlonly + +*/ diff --git a/trunk/doc/faq.doc b/trunk/doc/faq.doc new file mode 100644 index 0000000..0475aa7 --- /dev/null +++ b/trunk/doc/faq.doc @@ -0,0 +1,299 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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 faq Frequently Asked Questions + +<ol> +<li><b>How to get information on the index page in HTML?</b> +<p> +You should use the \\mainpage command inside a comment block like this: +\verbatim +/*! \mainpage My Personal Index Page + * + * \section intro_sec Introduction + * + * This is the introduction. + * + * \section install_sec Installation + * + * \subsection step1 Step 1: Opening the box + * + * etc... + */ +\endverbatim + +<li><b>Help, some/all of the members of my class / file / namespace + are not documented?</b> + + Check the following: + <ol> + <li>Is your class / file / namespace documented? If not, it will not + be extracted from the sources unless \c EXTRACT_ALL is set to \c YES + in the config file. + <li>Are the members private? If so, you must set \c EXTRACT_PRIVATE to \c YES + to make them appear in the documentation. + <li>Is there a function macro in your class that does not end with a + semicolon (e.g. MY_MACRO())? If so then you have to instruct + doxygen's preprocessor to remove it. + + This typically boils down to the following settings in the config file: + + \verbatim +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = YES +EXPAND_ONLY_PREDEF = YES +PREDEFINED = MY_MACRO()= + \endverbatim + + Please read the \ref preprocessing "preprocessing" section of the + manual for more information. + </ol> + +<li><b>When I set EXTRACT_ALL to NO none of my functions are shown in the + documentation.</b> + +In order for global functions, variables, enums, typedefs, and defines +to be documented you should document the file in which these commands are +located using a comment block containing a \\file (or \@file) +command. + +Alternatively, you can put all members in a group (or module) +using the \\ingroup command and then document the group using a comment +block containing the \\defgroup command. + +For member functions or functions that are part of a namespace you should +document either the class or namespace. + +<li><b>How can I make doxygen ignore some code fragment?</b> + +The new and easiest way is to add one comment block +with a \ref cmdcond "\\cond" command at the start and one comment block +with a \ref cmdendcond "\\endcond" command at the end of the piece of +code that should be ignored. This should be within the same file of course. + +But you can also use Doxygen's preprocessor for this: +If you put +\verbatim +#ifndef DOXYGEN_SHOULD_SKIP_THIS + + /* code that must be skipped by Doxygen */ + +#endif /* DOXYGEN_SHOULD_SKIP_THIS */ +\endverbatim +around the blocks that should be hidden and put: +\verbatim + PREDEFINED = DOXYGEN_SHOULD_SKIP_THIS +\endverbatim +in the config file then all blocks should be skipped by Doxygen as long +as <code>PREPROCESSING = YES</code>. + +<li><b>How can I change what is after the <code>\#include</code> in the class documentation?</b> + +In most cases you can use STRIP_FROM_INC_PATH to strip a user defined +part of a path. + +You can also document your class as follows + +\verbatim +/*! \class MyClassName include.h path/include.h + * + * Docs for MyClassName + */ +\endverbatim + +To make doxygen put <br><br> +<code> +\#include \<path/include.h\> +</code> + +in the documentation of the class MyClassName regardless of the name of the actual +header file in which the definition of MyClassName is contained. + +If you want doxygen to show that the include file should be included using +quotes instead of angle brackets you should type: +\verbatim +/*! \class MyClassName myhdr.h "path/myhdr.h" + * + * Docs for MyClassName + */ +\endverbatim + +<li><b>How can I use tag files in combination with compressed HTML?</b> + +If you want to refer from one compressed HTML file +\c a.chm to another compressed HTML file +called \c b.chm, the +link in \c a.chm must have the following format: +\verbatim +<a href="b.chm::/file.html"> +\endverbatim +Unfortunately this only works if both compressed HTML files are in the same +directory. + +As a result you must rename the generated \c index.chm files for all projects +into something unique and put all <code>.chm</code> files in one directory. + +Suppose you have a project \e a referring to a project \e b using tag file +\c b.tag, then you could rename the \c index.chm for project \e a into +\c a.chm and the \c index.chm for project \e b into \c b.chm. In the +configuration file for project \e a you write: +\verbatim +TAGFILES = b.tag=b.chm:: +\endverbatim +or you can use \c installdox to set the links as follows: +\verbatim +installdox -lb.tag@b.chm:: +\endverbatim + +<li><b>I don't like the quick index that is put above each HTML page, what do I do?</b> + +You can disable the index by setting DISABLE_INDEX to YES. Then you can +put in your own header file by writing your own header and feed that to +HTML_HEADER. + +<li><b>The overall HTML output looks different, while I only wanted to + use my own html header file</b> + +You probably forgot to include the stylesheet <code>doxygen.css</code> that +doxygen generates. You can include this by putting +\verbatim +<LINK HREF="doxygen.css" REL="stylesheet" TYPE="text/css"> +\endverbatim +in the HEAD section of the HTML page. + +<li><b>Why does doxygen use Qt?</b> + +The most important reason is to have a platform abstraction for most +Unices and Windows by means of the QFile, QFileInfo, QDir, QDate, +QTime and QIODevice classes. +Another reason is for the nice and bug free utility classes, like QList, +QDict, QString, QArray, QTextStream, QRegExp, QXML etc. + +The GUI front-end doxywizard uses Qt for... well... the GUI! + +<li><b>How can I exclude all test directories from my directory tree?</b> + +Simply put an exclude pattern like this in the configuration file: + +\verbatim +EXCLUDE_PATTERNS = */test/* +\endverbatim + +<li><b>Doxygen automatically generates a link to the + class MyClass somewhere in the running text. + How do I prevent that at a certain place?</b> + +Put a \% in front of the class name. Like this: \%MyClass. Doxygen will then +remove the % and keep the word unlinked. + +<li><b>My favorite programming language is X. Can I still use doxygen?</b> + +No, not as such; doxygen needs to understand the structure of what it reads. +If you don't mind spending some time on it, there are several options: +- If the grammar of X is close to C or C++, then it is probably not too hard to + tweak src/scanner.l a bit so the language is supported. This is done + for all other languages directly supported by doxygen + (i.e. Java, IDL, C#, PHP). +- If the grammar of X is somewhat different than you can write an input + filter that translates X into something similar enough to C/C++ for + doxygen to understand (this approach is taken for VB, Object Pascal, and + Javascript, see http://www.stack.nl/~dimitri/doxygen/download.html#helpers). +- If the grammar is completely different one could write a parser for X and + write a backend that produces a similar syntax tree as is done by + src/scanner.l (and also by src/tagreader.cpp while reading tag files). + +<li><b>Help! I get the cryptic message + "input buffer overflow, can't enlarge buffer because scanner uses REJECT"</b> + +This error happens when doxygen's lexical scanner has a rule that matches +more than 256K of input characters in one go. I've seen this happening +on a very large generated file (\>256K lines), where the built-in preprocessor +converted it into an empty file (with \>256K of newlines). Another case +where this might happen is if you have lines in your code with more than +256K characters. + +If you have run into such a case and want me to fix it, you +should send me a code fragment that triggers the message. To work around +the problem, put some line-breaks into your file, split it up into smaller +parts, or exclude it from the input using EXCLUDE. + +<li><b>When running make in the latex dir I get "TeX capacity exceeded". Now what?</b> + +You can edit the texmf.cfg file to increase the default values of the +various buffers and then run "texconfig init". + +<li><b>Why are dependencies via STL classes not shown in the dot graphs?</b> + +Doxygen is unaware of the STL classes, unless the option BUILTIN_STL_SUPPORT is +turned on. + +<li><b>I have problems getting the search engine to work with PHP5 and/or windows</b> + +Please read <a href="searchengine.html">this</a> for hints on where to look. + +<li><b>Can I configure doxygen from the command line?</b> + +Not via command line options, but doxygen can read from <code>stdin</code>, +so you can pipe things through it. Here's an example how to override an option +in a configuration file from the command line (assuming a UNIX environment): + +\verbatim +( cat Doxyfile ; echo "PROJECT_NUMBER=1.0" ) | doxygen - +\endverbatim + +For Windows the following would do the same: + +\verbatim +( type Doxyfile & echo PROJECT_NUMBER=1.0 ) | doxygen.exe - +\endverbatim + +If multiple options with the same name are specified then doxygen will use +the last one. To append to an existing option you can use the += operator. + +<li><b>How did doxygen get its 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 pronounceable +(the proper pronouncement is Docs-ee-gen, so with a long "e"). + +<li><b>What was the reason to develop doxygen?</b> + +I once wrote a GUI widget based on the Qt library (it is still available at +http://qdbttabular.sourceforge.net/ and maintained by Sven Meyer). +Qt had nicely generated documentation (using an internal tool which +they didn't want to release) and I wrote similar docs by hand. +This was a nightmare to maintain, so I wanted a similar tool. I looked at +Doc++ but that just wasn't good enough (it didn't support signals and +slots and did not have the Qt look and feel I had grown to like), +so I started to write my own tool... + +</ol> + +\htmlonly +Go to the <a href="trouble.html">next</a> section or return to the + <a href="index.html">index</a>. +\endhtmlonly + +*/ + diff --git a/trunk/doc/features.doc b/trunk/doc/features.doc new file mode 100644 index 0000000..46a6219 --- /dev/null +++ b/trunk/doc/features.doc @@ -0,0 +1,116 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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 features Features + +\addindex features +<UL> +<li>Requires very little overhead from the writer of the documentation. + Plain text will do, Markdown is support, and for more fancy or + structured output HTML tags and/or some of doxygen's special commands + can be used. +<li>Cross platform: works on Windows and many Unix flavors (including Linux and + MacOSX). +<li>Indexes, organizes and generates browsable and cross-referenced + output even from undocumented code. +<li>Generates structured XML output for parsed sources, which can be + used by external tools. +<li>Supports C/C++, Java, (Corba and Microsoft) Java, Python, VHDL, PHP + IDL, C#, Fortran, TCL, Objective-C 2.0, and to some extent D sources. +<li>Supports documentation of files, namespaces, packages, classes, + structs, unions, templates, variables, functions, typedefs, enums and + defines. +<li>JavaDoc (1.1), qdoc3 (partially), and ECMA-334 (C# spec.) compatible. +<li>Comes with a GUI frontend (Doxywizard) to ease editing the options and + run doxygen. The GUI is available on Windows, Linux, and MacOSX. +<li>Automatically generates class and collaboration diagrams in HTML (as clickable + image maps) and \f$\mbox{\LaTeX}\f$ (as Encapsulated PostScript images). +<li>Uses the `dot` tool of the Graphviz tool kit to generate + include dependency graphs, collaboration diagrams, call graphs, directory structure + graphs, and graphical class hierarchy graphs. +<li>Allows grouping of entities in modules and creating a hierarchy of modules. +<li>Flexible comment placement: Allows you to put documentation in the + header file (before the + declaration of an entity), source file (before the definition of an entity) + or in a separate file. +<li>Generates a list of all members of a class (including any inherited + members) along with their protection level. +<li>Outputs documentation in on-line format (XHTML and UNIX man page) and + off-line format (\f$\mbox{\LaTeX}\f$ and RTF) simultaneously + (any of these can be disabled if desired). All formats are optimized for + ease of reading. <br> + Furthermore, compressed HTML can be generated from HTML output using + Microsoft's HTML Help Workshop (Windows only) and PDF can be generated + from the \f$\mbox{\LaTeX}\f$ output. +<li>Support for various third party help formats including HTML Help, + docsets, Qt-Help, and eclipse help. +<li>Includes a full C preprocessor to allow proper parsing of conditional + code fragments and to allow expansion of all or part of macros definitions. +<li>Automatically detects public, protected and private sections, as well as + the Qt specific signal and slots sections. Extraction of private class + members is optional. +<li>Automatically generates references to documented classes, files, namespaces + and members. Documentation of global functions, global variables, + typedefs, defines and enumerations is also supported. +<li>References to base/super classes and inherited/overridden members are + generated automatically. +<li>Includes a fast, rank based search engine to search for strings or words + in the class and member documentation (PHP based). +<li>Includes an Javascript based live search feature to search for symbols + as you type (for small to medium sized projects). +<li>You can type normal HTML tags in your documentation. Doxygen will convert + them to their equivalent \f$\mbox{\LaTeX}\f$, RTF, and man-page + counterparts automatically. +<li>Allows references to documentation generated for other (doxygen documented) + projects (or another part of the same project) in a location independent way. +<li>Allows inclusion of source code examples that are automatically + cross-referenced with the documentation. +<li>Inclusion of undocumented classes is also supported, allowing to quickly + learn the structure and interfaces of a (large) piece of code without + looking into the implementation details. +<li>Allows automatic cross-referencing of (documented) entities with their + definition in the source code. +<li>All source code fragments are syntax highlighted for ease of reading. +<li>Allows inclusion of function/member/class definitions in the documentation. +<li>All options are read from an easy to edit and (optionally) annotated + configuration file. +<li>Documentation and search engine can be transferred to another + location or machine without regenerating the documentation. +<li>Supports many different character encodings and uses UTF-8 internally and + for the generated output. +<li>Doxygen can generate a layout which you can use and edit to change the + layout of each page. +<li>There more than a 100 configurable options to fine-tune the output. +<li>Can cope with large projects easily. +</UL> + +Although doxygen can now be used in any project written in a language that is +supported by doxygen, initially it was specifically designed to be used for projects +that make use of Qt Software's +<A HREF="http://www.trolltech.com/products/qt.html">Qt toolkit</A>. I have tried to +make doxygen `Qt-compatible'. That is: Doxygen can read the documentation contained in +the Qt source code and create a class browser that looks quite similar to the +one that is generated by Qt Software. Doxygen understands the C++ extensions +used by Qt such as signals and slots and many of the markup commands used in the Qt sources. + +Doxygen can also automatically generate links to existing documentation +that was generated with Doxygen or with Qt's non-public class browser +generator. For a Qt based project this means that whenever you refer to +members or classes belonging to the Qt toolkit, a link will be generated to +the Qt documentation. This is done independent of where this documentation +is located! + +*/ diff --git a/trunk/doc/formulas.doc b/trunk/doc/formulas.doc new file mode 100644 index 0000000..bc23a11 --- /dev/null +++ b/trunk/doc/formulas.doc @@ -0,0 +1,112 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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 formulas Including formulas + +Doxygen allows you to put \f$\mbox{\LaTeX}\f$ formulas in the +output (this works only for the HTML and \f$\mbox{\LaTeX}\f$ output, +not for the RTF nor for the man page output). To be able to include +formulas (as images) in the HTML documentation, you will also need to +have the following tools installed +<ul> +<li>\c latex: the \f$\mbox{\LaTeX}\f$ compiler, needed to parse the formulas. + To test I have used the teTeX 1.0 distribution. +<li>\c dvips: a tool to convert DVI files to PostScript files + I have used version 5.92b from Radical Eye software for testing. +<li>\c gs: the GhostScript interpreter for converting PostScript files + to bitmaps. I have used Aladdin GhostScript 8.0 for testing. +</ul> +For the HTML output there is also an alternative solution using +<a href="http://www.mathjax.org">MathJax</a> which does not +require the above tools. If you enable \ref cfg_use_mathjax "USE_MATHJAX" in +the config then the latex formulas will be copied to the HTML "as is" and a +client side javascript will parse them and turn them into (interactive) images. + +There are three ways to include formulas in the documentation. +<ol> +<li>Using in-text formulas that appear in the running text. + These formulas should be put between a pair of \\f\$ + commands, so +\verbatim + The distance between \f$(x_1,y_1)\f$ and \f$(x_2,y_2)\f$ is + \f$\sqrt{(x_2-x_1)^2+(y_2-y_1)^2}\f$. +\endverbatim results in: + + The distance between \f$(x_1,y_1)\f$ and \f$(x_2,y_2)\f$ is + \f$\sqrt{(x_2-x_1)^2+(y_2-y_1)^2}\f$. +<br> +<li>Unnumbered displayed formulas that are centered on a separate line. + These formulas should be put between \\f[ and \\f] commands. + An example: +\verbatim + \f[ + |I_2|=\left| \int_{0}^T \psi(t) + \left\{ + u(a,t)- + \int_{\gamma(t)}^a + \frac{d\theta}{k(\theta,t)} + \int_{a}^\theta c(\xi)u_t(\xi,t)\,d\xi + \right\} dt + \right| + \f] +\endverbatim + results in: + \f[ + |I_2|=\left| \int_{0}^T \psi(t) + \left\{ + u(a,t)- + \int_{\gamma(t)}^a + \frac{d\theta}{k(\theta,t)} + \int_{a}^\theta c(\xi)u_t(\xi,t)\,d\xi + \right\} dt + \right| + \f] +<li>Formulas or other latex elements that are not in a math + environment can be specified using \\f{environment}, where + \c environment is the name of the \f$\mbox{\LaTeX}\f$ environment, + the corresponding end command is \\f}. Here is an example for an + equation array +\verbatim + \f{eqnarray*}{ + g &=& \frac{Gm_2}{r^2} \\ + &=& \frac{(6.673 \times 10^{-11}\,\mbox{m}^3\,\mbox{kg}^{-1}\, + \mbox{s}^{-2})(5.9736 \times 10^{24}\,\mbox{kg})}{(6371.01\,\mbox{km})^2} \\ + &=& 9.82066032\,\mbox{m/s}^2 + \f} +\endverbatim + which results in: + \f{eqnarray*} + g &=& \frac{Gm_2}{r^2} \\ + &=& \frac{(6.673 \times 10^{-11}\,\mbox{m}^3\,\mbox{kg}^{-1}\, + \mbox{s}^{-2})(5.9736 \times 10^{24}\,\mbox{kg})}{(6371.01\,\mbox{km})^2} \\ + &=& 9.82066032\,\mbox{m/s}^2 + \f} +</ol> +For the first two commands one should make sure formulas contain +valid commands in \f$\mbox{\LaTeX}\f$'s math-mode. For the third command +the section should contain valid command for the specific environment. + +\warning Currently, doxygen is not very fault tolerant in recovering +from typos in formulas. It may be necessary to remove the +file <code>formula.repository</code> that is written to the html directory to +get rid of an incorrect formula. + +\htmlonly +Go to the <a href="diagrams.html">next</a> section or return to the + <a href="index.html">index</a>. +\endhtmlonly + +*/ diff --git a/trunk/doc/grouping.doc b/trunk/doc/grouping.doc new file mode 100644 index 0000000..56f19f7 --- /dev/null +++ b/trunk/doc/grouping.doc @@ -0,0 +1,228 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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 grouping Grouping + +Doxygen has three mechanisms to group things together. +One mechanism works at a global level, creating a new page +for each group. These groups are called \ref modules "'modules'" in the documentation. +The second mechanism works within a member list of some compound entity, +and is referred to as a \ref memgroup "'member groups'". +For \ref cmdpage "pages" there is a third grouping mechanism referred to +as \ref subpaging "subpaging". + +\section modules Modules + +Modules are a way to group things together on a separate page. You +can document a group as a whole, as well as all individual members. +Members of a group can be files, namespaces, classes, functions, +variables, enums, typedefs, and defines, but also other groups. + +To define a group, you should put the \ref cmddefgroup "\\defgroup" +command in a special comment block. The first argument of the command +is a label that should uniquely identify the group. +The second argument is the name or title of the group as it should appear +in the documentation. + +You can make an entity a member of a specific group by putting +a \ref cmdingroup "\\ingroup" command inside its documentation block. + +To avoid putting \ref cmdingroup "\\ingroup" commands in the documentation +for each member you can also group members together by the +open marker <code>\@{</code> before the group and the +closing marker <code>\@}</code> after the group. The markers can +be put in the documentation of the group definition or in a separate +documentation block. + +Groups themselves can also be nested using these grouping markers. + +You will get an error message when you use the same group label more than once. +If you don't want doxygen to enforce unique labels, then you can +use \ref cmdaddtogroup "\\addtogroup" instead of +\ref cmddefgroup "\\defgroup". +It can be used exactly like \ref cmddefgroup "\\defgroup", +but when the group has been defined already, then it silently merges the +existing documentation with the new one. +The title of the group is optional for this command, so you can use +\verbatim +/** \addtogroup <label> + * @{ + */ +... + +/** @}*/ +\endverbatim +to add additional members to a group that is defined in more detail elsewhere. + +Note that compound entities (like classes, files and namespaces) can +be put into multiple groups, but members (like variable, functions, typedefs +and enums) can only be a member of one group +(this restriction is in place to avoid ambiguous linking targets in case +a member is not documented in the context of its class, namespace +or file, but only visible as part of a group). + +Doxygen will put members into the group whose definition has +the highest "priority": e.g. An explicit \ref cmdingroup "\\ingroup" overrides +an implicit grouping definition via <code>\@{</code> <code>\@}</code>. +Conflicting grouping definitions with the same priority trigger a warning, +unless one definition was for a member without any explicit documentation. + +The following example puts VarInA into group A and silently resolves +the conflict for IntegerVariable by putting it into group IntVariables, +because the second instance of IntegerVariable +is undocumented: + +\verbatim + +/** + * \ingroup A + */ +extern int VarInA; + +/** + * \defgroup IntVariables Global integer variables + * @{ + */ + +/** an integer variable */ +extern int IntegerVariable; + +/**@}*/ + +.... + +/** + * \defgroup Variables Global variables + */ +/**@{*/ + +/** a variable in group A */ +int VarInA; + +int IntegerVariable; + +/**@}*/ +\endverbatim + +The \ref cmdref "\\ref" command can be used to refer to a group. +The first argument of the \\ref command should be group's label. +To use a custom link name, you can put the name of the links in +double quotes after the label, as shown by the following example +\verbatim +This is the \ref group_label "link" to this group. +\endverbatim + +The priorities of grouping definitions are (from highest to lowest): +\ref cmdingroup "\\ingroup", \ref cmddefgroup "\\defgroup", +\ref cmdaddtogroup "\\addtogroup", \ref cmdweakgroup "\\weakgroup". +The last command is exactly like \ref cmdaddtogroup "\\addtogroup" +with a lower priority. It was added to allow "lazy" grouping +definitions: you can use commands with a higher priority in your .h +files to define the hierarchy and \ref cmdweakgroup "\\weakgroup" +in .c files without having to duplicate the hierarchy exactly. + +\par Example: +\verbinclude group.cpp + +\htmlonly +Click <a href="$(DOXYGEN_DOCDIR)/examples/group/html/modules.html">here</a> +for the corresponding HTML documentation that is generated by Doxygen. +\endhtmlonly + +\section memgroup Member Groups + +If a compound (e.g. a class or file) has many members, it is often +desired to group them together. Doxygen already automatically groups +things together on type and protection level, but maybe you feel that +this is not enough or that that default grouping is wrong. +For instance, because you feel that members of different (syntactic) +types belong to the same (semantic) group. + +A member group is defined by +a +\verbatim +///@{ + ... +///@} +\endverbatim +block or a +\verbatim +/**@{*/ + ... +/**@}*/ +\endverbatim +block if you prefer C style +comments. Note that the members of the group should be +physically inside the member group's body. + +Before the opening marker of a block a separate comment block may be +placed. This block should contain the \ref cmdname "@@name" +(or \ref cmdname "\\name") command and is used to specify the header +of the group. Optionally, the comment block may also contain more +detailed information about the group. + +Nesting of member groups is not allowed. + +If all members of a member group inside a class have the same type +and protection level (for instance all are static public members), +then the whole member group is displayed as a subgroup of +the type/protection level group (the group is displayed as a +subsection of the "Static Public Members" section for instance). +If two or more members have different types, then the group is put +at the same level as the automatically generated groups. +If you want to force all member-groups of a class to be at the top level, +you should put a \ref cmdnosubgrouping "\\nosubgrouping" command inside the +documentation of the class. + +\par Example: +\verbinclude memgrp.cpp + +\htmlonly +Click <a href="$(DOXYGEN_DOCDIR)/examples/memgrp/html/class_test.html">here</a> +for the corresponding HTML documentation that is generated by Doxygen. +\endhtmlonly + +Here Group1 is displayed as a subsection of the "Public Members". And +Group2 is a separate section because it contains members with +different protection levels (i.e. public and protected). + +\htmlonly +Go to the <a href="formulas.html">next</a> section or return to the + <a href="index.html">index</a>. +\endhtmlonly + +\section subpaging Subpaging + +Information can be grouped into pages using the \ref cmdpage "\\page" and +\ref cmdsubpage "\\mainpage" commands. Normally, this results in a +flat list of pages, where the "main" page is the first in the list. + +Instead of adding structure using the approach described in section +\ref modules "modules" it is often more natural and convenient to add +additional structure to the pages using the \ref cmdsubpage "\\subpage" +command. + +For a page A the \\subpage command adds a link to another page B and at +the same time makes page B a subpage of A. This has the effect of making +two groups GA and GB, where GB is part of GA, page A is put in group GA, +and page B is put in group GB. + +\htmlonly +Go to the <a href="formulas.html">next</a> section or return to the + <a href="index.html">index</a>. +\endhtmlonly + +*/ diff --git a/trunk/doc/htmlcmds.doc b/trunk/doc/htmlcmds.doc new file mode 100644 index 0000000..7b3ff71 --- /dev/null +++ b/trunk/doc/htmlcmds.doc @@ -0,0 +1,153 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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 htmlcmds HTML Commands + +Here is a list of all HTML commands that may be used inside the +documentation. Note that although these HTML tags are translated to the +proper commands for output formats other than HTML, all attributes +of a HTML tag are passed on to the HTML output only +(the HREF and NAME attributes for the A tag are the only exception). + +<ul> +<li><tt>\<A HREF="..."\></tt> Starts a hyperlink + (if supported by the output format). +<li><tt>\<A NAME="..."\></tt> Starts an named anchor + (if supported by the output format). +<li><tt>\</A\></tt> Ends a link or anchor +<li><tt>\<B\></tt> Starts a piece of text displayed in a bold font. +<li><tt>\</B\></tt> Ends a <tt>\<B\></tt> section. +<li><tt>\<BLOCKQUOTE\></tt> Starts a quotation block. +<li><tt>\</BLOCKQUOTE\></tt> Ends the quotation block. +<li><tt>\<BODY\></tt> Does not generate any output. +<li><tt>\</BODY\></tt> Does not generate any output. +<li><tt>\<BR\></tt> Forces a line break. +<li><tt>\<CENTER\></tt> starts a section of centered text. +<li><tt>\</CENTER\></tt> ends a section of centered text. +<li><tt>\<CAPTION\></tt> Starts a caption. Use within a table only. +<li><tt>\</CAPTION\></tt> Ends a caption. Use within a table only. +<li><tt>\<CODE\></tt> Starts a piece of text displayed in a typewriter font. + Note that for C# code, this command is equivalent to + \ref cmdcode "\\code". +<li><tt>\</CODE\></tt> Ends a <tt>\<CODE\></tt> section. + Note that for C# code, this command is equivalent to + \ref cmdendcode "\\endcode". +<li><tt>\<DD\></tt> Starts an item description. +<li><tt>\<DFN\></tt> Starts a piece of text displayed in a typewriter font. +<li><tt>\</DFN\></tt> Ends a <tt>\<DFN\></tt> section. +<li><tt>\<DIV></tt> Starts a section with a specific style (HTML only) +<li><tt>\</DIV></tt> Ends a section with a specific style (HTML only) +<li><tt>\<DL\></tt> Starts a description list. +<li><tt>\</DL\></tt> Ends a description list. +<li><tt>\<DT\></tt> Starts an item title. +<li><tt>\</DT\></tt> Ends an item title. +<li><tt>\<EM\></tt> Starts a piece of text displayed in an italic font. +<li><tt>\</EM\></tt> Ends a <tt>\<EM\></tt> section. +<li><tt>\<FORM\></tt> Does not generate any output. +<li><tt>\</FORM\></tt> Does not generate any output. +<li><tt>\<HR\></tt> Writes a horizontal ruler. +<li><tt>\<H1\></tt> Starts an unnumbered section. +<li><tt>\</H1\></tt> Ends an unnumbered section. +<li><tt>\<H2\></tt> Starts an unnumbered subsection. +<li><tt>\</H2\></tt> Ends an unnumbered subsection. +<li><tt>\<H3\></tt> Starts an unnumbered subsubsection. +<li><tt>\</H3\></tt> Ends an unnumbered subsubsection. +<li><tt>\<I\></tt> Starts a piece of text displayed in an italic font. +<li><tt>\<INPUT\></tt> Does not generate any output. +<li><tt>\</I\></tt> Ends a <tt>\<I\></tt> section. +<li><tt>\<IMG\></tt> This command is written with attributes to the HTML output only. +<li><tt>\<LI\></tt> Starts a new list item. +<li><tt>\</LI\></tt> Ends a list item. +<li><tt>\<META\></tt> Does not generate any output. +<li><tt>\<MULTICOL\></tt> ignored by doxygen. +<li><tt>\</MUTLICOL\></tt> ignored by doxygen. +<li><tt>\<OL\></tt> Starts a numbered item list. +<li><tt>\</OL\></tt> Ends a numbered item list. +<li><tt>\<P\></tt> Starts a new paragraph. +<li><tt>\</P\></tt> Ends a paragraph. +<li><tt>\<PRE\></tt> Starts a preformatted fragment. +<li><tt>\</PRE\></tt> Ends a preformatted fragment. +<li><tt>\<SMALL\></tt> Starts a section of text displayed in a smaller font. +<li><tt>\</SMALL\></tt> Ends a <tt>\<SMALL\></tt> section. +<li><tt>\<SPAN></tt> Starts an inline text fragment with a specific style (HTML only) +<li><tt>\</SPAN></tt> Ends an inline text fragment with a specific style (HTML only) +<li><tt>\<STRONG\></tt> Starts a section of bold text. +<li><tt>\</STRONG\></tt> Ends a section of bold text. +<li><tt>\<SUB\></tt> Starts a piece of text displayed in subscript. +<li><tt>\</SUB\></tt> Ends a <tt>\<SUB\></tt> section. +<li><tt>\<SUP\></tt> Starts a piece of text displayed in superscript. +<li><tt>\</SUP\></tt> Ends a <tt>\</SUP\></tt> section. +<li><tt>\<TABLE\></tt> starts a table. +<li><tt>\</TABLE\></tt> ends a table. +<li><tt>\<TD\></tt> Starts a new table data element. +<li><tt>\</TD\></tt> Ends a table data element. +<li><tt>\<TH\></tt> Starts a new table header. +<li><tt>\</TH\></tt> Ends a table header. +<li><tt>\<TR\></tt> Starts a new table row. +<li><tt>\</TR\></tt> Ends a table row. +<li><tt>\<TT\></tt> Starts a piece of text displayed in a typewriter font. +<li><tt>\</TT\></tt> Ends a <tt>\<TT\></tt> section. +<li><tt>\<KBD\></tt> Starts a piece of text displayed in a typewriter font. +<li><tt>\</KBD\></tt> Ends a <tt>\<KBD\></tt> section. +<li><tt>\<UL\></tt> Starts an unnumbered item list. +<li><tt>\</UL\></tt> Ends an unnumbered item list. +<li><tt>\<VAR\></tt> Starts a piece of text displayed in an italic font. +<li><tt>\</VAR\></tt> Ends a <tt>\<VAR\></tt> section. +</ul> + +The special HTML character entities that are recognized by Doxygen: + +<ul> +<li><tt>\©</tt> the copyright symbol +<li><tt>\&tm;</tt> the trade mark symbol +<li><tt>\®</tt> the registered trade mark symbol +<li><tt>\<</tt> less-than symbol +<li><tt>\></tt> greater-than symbol +<li><tt>\&</tt> ampersand +<li><tt>\'</tt> single quotation mark (straight) +<li><tt>\"</tt> double quotation mark (straight) +<li><tt>\‘</tt> left single quotation mark +<li><tt>\’</tt> right single quotation mark +<li><tt>\“</tt> left double quotation mark +<li><tt>\”</tt> right double quotation mark +<li><tt>\–</tt> n-dash (for numeric ranges, e.g. 2–8) +<li><tt>\—</tt> m-dash (for parenthetical punctuation — like this) +<li><tt>\&?uml;</tt> where ? is one of {A,E,I,O,U,Y,a,e,i,o,u,y}, + writes a character with a diaeresis accent (like ä). +<li><tt>\&?acute;</tt> where ? is one of {A,E,I,O,U,Y,a,e,i,o,u,y}, + writes a character with a acute accent (like á). +<li><tt>\&?grave;</tt> where ? is one of {A,E,I,O,U,a,e,i,o,u,y}, + writes a character with a grave accent (like à). +<li><tt>\&?circ;</tt> where ? is one of {A,E,I,O,U,a,e,i,o,u,y}, + writes a character with a circumflex accent (like â). +<li><tt>\&?tilde;</tt> where ? is one of {A,N,O,a,n,o}, + writes a character with a tilde accent (like ã). +<li><tt>\ß</tt> write a sharp s (i.e. ß) to the output. +<li><tt>\&?cedil;</tt> where ? is one of {c,C}, + writes a c-cedille (like ç). +<li><tt>\&?ring;</tt> where ? is one of {a,A}, + writes an <tt>a</tt> with a ring (like å). +<li><tt>\ </tt> a non breakable space. +</ul> + +Finally, to put invisible comments inside comment blocks, HTML style +comments can be used: +\verbatim +/*! <!-- This is a comment with a comment block --> Visible text */ +\endverbatim + +*/ + diff --git a/trunk/doc/index.doc b/trunk/doc/index.doc new file mode 100644 index 0000000..e604ee5 --- /dev/null +++ b/trunk/doc/index.doc @@ -0,0 +1,208 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ +/*! \mainpage Doxygen Manual +\if logo_on +<center> +\htmlonly +<img src="doxygen_logo.gif" width="634" height="197" alt="doxygen"/><br/> +Version: $(VERSION) +\endhtmlonly +</center> +\endif + +<h2>Introduction</h2> +Doxygen is a documentation system for C++, C, Java, Objective-C, Python, IDL +(Corba and Microsoft flavors), Fortran, VHDL, PHP, C#, and to some extent D. + +It can help you in three ways: +<ol> +<li> It can generate an on-line documentation browser (in HTML) and/or an + off-line reference manual (in \f$\mbox{\LaTeX}\f$) from a set + of documented source files. + There is also support for generating output in RTF (MS-Word), + PostScript, hyperlinked PDF, compressed HTML, and Unix man pages. + The documentation is extracted directly from the sources, which + makes it much easier to keep the documentation consistent with the + source code. +<li> You can \ref extract_all "configure" doxygen to extract the code structure + from undocumented source files. This is very useful to quickly + find your way in large source distributions. + You can also visualize the relations between the various elements + by means of include dependency graphs, inheritance diagrams, + and collaboration diagrams, which are all generated automatically. +<li> You can also use doxygen for creating normal documentation (as I did + for this manual). +</ol> + +Doxygen is developed under <a href="http://www.linux.org">Linux</a> +and Mac OS X, but is set-up to be highly portable. As a result, it +runs on most other Unix flavors as well. Furthermore, executables for +Windows are available. + +\n This manual is divided into three parts, each of which is divided into several +sections. + +The first part forms a user manual: +<ul> +<li>Section \ref install discusses how to + <a href="http://www.doxygen.org/download.html">download</a>, compile and install + doxygen for your platform. +<li>Section \ref starting tells you how to generate your first piece of + documentation quickly. +<li>Section \ref docblocks demonstrates the various ways that code can + be documented. +<li>Section \ref markdown show the Markdown formatting supported by doxygen. +<li>Section \ref grouping shows how to group things together. +<li>Section \ref formulas shows how to insert formulas in the documentation. +<li>Section \ref diagrams describes the diagrams and graphs that doxygen can generate. +<li>Section \ref preprocessing explains how doxygen deals with macro definitions. +<li>Section \ref autolink shows how to put links to files, classes, + and members in the documentation. +<li>Section \ref output shows how to generate the various output formats + supported by doxygen. +<li>Section \ref searching shows various ways to search in the HTML documentation. +<li>Section \ref customize explains how you can customize the output generated + by doxygen. +<li>Section \ref custcmd show how to define and use custom commands in your comments. +<li>Section \ref external explains how to let doxygen create links to externally generated documentation. +<li>Section \ref faq gives answers to frequently asked questions. +<li>Section \ref trouble tells you what to do when you have problems. +</ul> + +The second part forms a reference manual: + +<ul> +<li>Section \ref features presents an overview of what doxygen can do. +<li>Section \ref doxygen_usage shows how to use the \c doxygen program. +<li>Section \ref doxywizard_usage shows how to use the \c doxywizard program. +<li>Section \ref config shows how to fine-tune doxygen, so it + generates the documentation you want. +<li>Section \ref commands shows an overview of the special commands that can be + used within the documentation. +<li>Section \ref htmlcmds shows an overview of the HTML commands that + can be used within the documentation. +<li>Section \ref xmlcmds shows an overview of the C# style XML 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 perlmod shows how to use the PerlMod output. +<li>Section \ref langhowto explains how to add support for new + output languages. +</ul> + +\n<h2>Doxygen license</h2> +\addindex license +\addindex GPL + +Copyright © 1997-2012 by +<a href="mailto:dimitri@stack.nl">Dimitri van Heesch</a>.<p> + +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 +<a href="http://www.gnu.org/licenses/old-licenses/gpl-2.0.html"> +GNU General Public License</a> +for more details. +<p> +Documents produced by doxygen are derivative works derived from the +input used in their production; they are not affected by this license. + +<h2>User examples</h2> + +Doxygen supports a number of \ref output "output formats" where HTML is the +most popular one. I've gathered +\htmlonly +<a href="http://www.doxygen.org/results.html">some nice examples</a> +\endhtmlonly +\latexonly +some nice examples (see {\tt http://www.doxygen.org/results.html}) +\endlatexonly +of real-life projects using doxygen. + +These are part of a larger +\htmlonly +<a href="http://www.doxygen.org/projects.html">list of projects</a> +that use doxygen. +\endhtmlonly +\latexonly +list of projects that use doxygen (see {\tt http://www.doxygen.org/projects.html}). +\endlatexonly +If you know other projects, let <a href="mailto:dimitri@stack.nl?subject=New%20project%20using%20Doxygen">me</a> +know and I'll add them. + +<h2>Commercial Support</h2> + +I'm currently investigating the possibilities of providing +commercial support for doxygen. The forms of support I'm thinking of +are: +<ul> +<li>implementing features, +<li>fixing bugs, +<li>providing priority help in answering questions. +</ul> +To get a better understanding of the feasibility, +please let <a href="mailto:dimitri@stack.nl?subject=Doxygen%20Commercial%20Support">me</a> know if you +have a need for this type (or another type) +of doxygen related commercial support. + +<h2>Future work</h2> +Although doxygen is successfully used by large number of companies and +open source projects already, there is always room for improvement. +<p> +You can submit enhancement requests in +<a href="https://bugzilla.gnome.org/buglist.cgi?product=doxygen&bug_status=UNCONFIRMED&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&bug_severity=enhancement">the bug tracker</a>. +Make sure the severity of the bug report is set to "enhancement". + +<h2>Acknowledgements</h2> +\addindex acknowledgements +Thanks go to: +<ul> +<li>\addindex Doc++ + Malte Zöckler and Roland Wunderling, authors of DOC++. + The first version of doxygen borrowed some code of an old version of DOC++. + Although I have rewritten practically all code since then, DOC++ has still + given me a good start in writing doxygen. +<li>All people at Qt Software, for creating a beautiful GUI Toolkit + (which is very useful as a Windows/Unix platform abstraction layer :-) +<li>My brother Frank + for rendering the logos. +<li>Harm van der Heijden for adding HTML help support. +<li>Wouter Slegers of + <a href="http://www.yourcreativesolutions.nl">Your Creative Solutions</a> + for registering the www.doxygen.org domain. +<li>Parker Waechter for adding the RTF output generator. +<li>Joerg Baumann, for adding conditional documentation blocks, + PDF links, and the configuration generator. +<li>Tim Mensch for adding the todo command. +<li>Christian Hammond for redesigning the web-site. +<li>Ken Wong for providing the HTML tree view code. +<li>Talin for adding support for C# style comments with XML markup. +<li>Petr Prikryl for coordinating the internationalization support. + All language maintainers for providing translations into many languages. +<li>The band <a href="http://www.porcupinetree.com">Porcupine Tree</a> for + providing hours of great music to listen to while coding. +<li>many, many others for suggestions, patches and bug reports. +</ul> +*/ + diff --git a/trunk/doc/index.hhp.txt b/trunk/doc/index.hhp.txt new file mode 100644 index 0000000..b676d83 --- /dev/null +++ b/trunk/doc/index.hhp.txt @@ -0,0 +1,108 @@ +examples/afterdoc/html/tab_a.png +examples/afterdoc/html/tab_b.png +examples/afterdoc/html/tab_h.png +examples/afterdoc/html/tab_s.png +examples/author/html/tab_a.png +examples/author/html/tab_b.png +examples/author/html/tab_h.png +examples/author/html/tab_s.png +examples/autolink/html/tab_a.png +examples/autolink/html/tab_b.png +examples/autolink/html/tab_h.png +examples/autolink/html/tab_s.png +examples/class/html/tab_a.png +examples/class/html/tab_b.png +examples/class/html/tab_h.png +examples/class/html/tab_s.png +examples/define/html/tab_a.png +examples/define/html/tab_b.png +examples/define/html/tab_h.png +examples/define/html/tab_s.png +examples/diagrams/html/tab_a.png +examples/diagrams/html/tab_b.png +examples/diagrams/html/tab_h.png +examples/diagrams/html/tab_s.png +examples/docstring/html/tab_a.png +examples/docstring/html/tab_b.png +examples/docstring/html/tab_h.png +examples/docstring/html/tab_s.png +examples/enum/html/tab_a.png +examples/enum/html/tab_b.png +examples/enum/html/tab_h.png +examples/enum/html/tab_s.png +examples/example/html/tab_a.png +examples/example/html/tab_b.png +examples/example/html/tab_h.png +examples/example/html/tab_s.png +examples/file/html/tab_a.png +examples/file/html/tab_b.png +examples/file/html/tab_h.png +examples/file/html/tab_s.png +examples/func/html/tab_a.png +examples/func/html/tab_b.png +examples/func/html/tab_h.png +examples/func/html/tab_s.png +examples/group/html/tab_a.png +examples/group/html/tab_b.png +examples/group/html/tab_h.png +examples/group/html/tab_s.png +examples/include/html/tab_a.png +examples/include/html/tab_b.png +examples/include/html/tab_h.png +examples/include/html/tab_s.png +examples/jdstyle/html/tab_a.png +examples/jdstyle/html/tab_b.png +examples/jdstyle/html/tab_h.png +examples/jdstyle/html/tab_s.png +examples/manual/html/tab_a.png +examples/manual/html/tab_b.png +examples/manual/html/tab_h.png +examples/manual/html/tab_s.png +examples/memgrp/html/tab_a.png +examples/memgrp/html/tab_b.png +examples/memgrp/html/tab_h.png +examples/memgrp/html/tab_s.png +examples/mux/html/tab_a.png +examples/mux/html/tab_b.png +examples/mux/html/tab_h.png +examples/mux/html/tab_s.png +examples/overload/html/tab_a.png +examples/overload/html/tab_b.png +examples/overload/html/tab_h.png +examples/overload/html/tab_s.png +examples/page/html/tab_a.png +examples/page/html/tab_b.png +examples/page/html/tab_h.png +examples/page/html/tab_s.png +examples/par/html/tab_a.png +examples/par/html/tab_b.png +examples/par/html/tab_h.png +examples/par/html/tab_s.png +examples/pyexample/html/tab_a.png +examples/pyexample/html/tab_b.png +examples/pyexample/html/tab_h.png +examples/pyexample/html/tab_s.png +examples/qtstyle/html/tab_a.png +examples/qtstyle/html/tab_b.png +examples/qtstyle/html/tab_h.png +examples/qtstyle/html/tab_s.png +examples/relates/html/tab_a.png +examples/relates/html/tab_b.png +examples/relates/html/tab_h.png +examples/relates/html/tab_s.png +examples/restypedef/html/tab_a.png +examples/restypedef/html/tab_b.png +examples/restypedef/html/tab_h.png +examples/restypedef/html/tab_s.png +examples/structcmd/html/tab_a.png +examples/structcmd/html/tab_b.png +examples/structcmd/html/tab_h.png +examples/structcmd/html/tab_s.png +examples/tag/html/tab_a.png +examples/tag/html/tab_b.png +examples/tag/html/tab_h.png +examples/tag/html/tab_s.png +examples/template/html/tab_a.png +examples/template/html/tab_b.png +examples/template/html/tab_h.png +examples/template/html/tab_s.png diff --git a/trunk/doc/infoflow.eps b/trunk/doc/infoflow.eps new file mode 100644 index 0000000..f11b1fc --- /dev/null +++ b/trunk/doc/infoflow.eps @@ -0,0 +1,624 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%Title: infoflow.fig +%%Creator: fig2dev Version 3.2 Patchlevel 5d +%%CreationDate: Thu Dec 29 10:46:41 2011 +%%For: dimitri@macbookpro (Dimitri van Heesch) +%%BoundingBox: 0 0 661 582 +%Magnification: 1.0000 +%%EndComments +%%BeginProlog +/$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 +/col32 {0.878 0.878 0.878 srgb} bind def +/col33 {0.000 0.000 0.000 srgb} bind def + +end + +/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 +/reencdict 12 dict def /ReEncode { reencdict begin +/newcodesandnames exch def /newfontname exch def /basefontname exch def +/basefontdict basefontname findfont def /newfont basefontdict maxlength dict def +basefontdict { exch dup /FID ne { dup /Encoding eq +{ exch dup length array copy newfont 3 1 roll put } +{ exch newfont 3 1 roll put } ifelse } { pop pop } ifelse } forall +newfont /FontName newfontname put newcodesandnames aload pop +128 1 255 { newfont /Encoding get exch /.notdef put } for +newcodesandnames length 2 idiv { newfont /Encoding get 3 1 roll put } repeat +newfontname newfont definefont pop end } def +/isovec [ +8#055 /minus 8#200 /grave 8#201 /acute 8#202 /circumflex 8#203 /tilde +8#204 /macron 8#205 /breve 8#206 /dotaccent 8#207 /dieresis +8#210 /ring 8#211 /cedilla 8#212 /hungarumlaut 8#213 /ogonek 8#214 /caron +8#220 /dotlessi 8#230 /oe 8#231 /OE +8#240 /space 8#241 /exclamdown 8#242 /cent 8#243 /sterling +8#244 /currency 8#245 /yen 8#246 /brokenbar 8#247 /section 8#250 /dieresis +8#251 /copyright 8#252 /ordfeminine 8#253 /guillemotleft 8#254 /logicalnot +8#255 /hyphen 8#256 /registered 8#257 /macron 8#260 /degree 8#261 /plusminus +8#262 /twosuperior 8#263 /threesuperior 8#264 /acute 8#265 /mu 8#266 /paragraph +8#267 /periodcentered 8#270 /cedilla 8#271 /onesuperior 8#272 /ordmasculine +8#273 /guillemotright 8#274 /onequarter 8#275 /onehalf +8#276 /threequarters 8#277 /questiondown 8#300 /Agrave 8#301 /Aacute +8#302 /Acircumflex 8#303 /Atilde 8#304 /Adieresis 8#305 /Aring +8#306 /AE 8#307 /Ccedilla 8#310 /Egrave 8#311 /Eacute +8#312 /Ecircumflex 8#313 /Edieresis 8#314 /Igrave 8#315 /Iacute +8#316 /Icircumflex 8#317 /Idieresis 8#320 /Eth 8#321 /Ntilde 8#322 /Ograve +8#323 /Oacute 8#324 /Ocircumflex 8#325 /Otilde 8#326 /Odieresis 8#327 /multiply +8#330 /Oslash 8#331 /Ugrave 8#332 /Uacute 8#333 /Ucircumflex +8#334 /Udieresis 8#335 /Yacute 8#336 /Thorn 8#337 /germandbls 8#340 /agrave +8#341 /aacute 8#342 /acircumflex 8#343 /atilde 8#344 /adieresis 8#345 /aring +8#346 /ae 8#347 /ccedilla 8#350 /egrave 8#351 /eacute +8#352 /ecircumflex 8#353 /edieresis 8#354 /igrave 8#355 /iacute +8#356 /icircumflex 8#357 /idieresis 8#360 /eth 8#361 /ntilde 8#362 /ograve +8#363 /oacute 8#364 /ocircumflex 8#365 /otilde 8#366 /odieresis 8#367 /divide +8#370 /oslash 8#371 /ugrave 8#372 /uacute 8#373 /ucircumflex +8#374 /udieresis 8#375 /yacute 8#376 /thorn 8#377 /ydieresis] def +/Times-Roman /Times-Roman-iso isovec ReEncode +/$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def +/$F2psEnd {$F2psEnteredState restore end} def + +/pageheader { +save +newpath 0 582 moveto 0 0 lineto 661 0 lineto 661 582 lineto closepath clip newpath +-53.3 599.2 translate +1 -1 scale +$F2psBegin +10 setmiterlimit +0 slj 0 slc + 0.06000 0.06000 sc +} bind def +/pagefooter { +$F2psEnd +restore +} bind def +%%EndProlog +pageheader +% +% Fig objects follow +% +% +% here starts figure with depth 50 +/Times-Roman-iso ff 200.00 scf sf +8100 7200 m +gs 1 -1 sc (import) col0 sh gr +% Polyline +0 slj +0 slc +7.500 slw +n 975 3600 m 975 3300 l 2175 3300 l 2175 4800 l + 2100 4800 l gs col0 s gr +% Polyline +n 1050 3300 m 1050 3225 l 2250 3225 l 2250 4725 l + 2175 4725 l gs col0 s gr +% Polyline +n 1125 3225 m 1125 3150 l 2325 3150 l 2325 4650 l + 2250 4650 l gs col0 s gr +% Polyline +n 900 5700 m 1200 5400 l 2100 5400 l 2100 6900 l 900 6900 l 900 5700 l + 1200 5700 l + 1200 5400 l gs col0 s gr +% Polyline +n 975 5625 m 975 5325 l 2175 5325 l 2175 6825 l + 2100 6825 l gs col0 s gr +% Polyline +n 1050 5325 m 1050 5250 l 2250 5250 l 2250 6750 l + 2175 6750 l gs col0 s gr +% Polyline +n 1125 5250 m 1125 5175 l 2325 5175 l 2325 6675 l + 2250 6675 l gs col0 s gr +/Times-Roman-iso ff 200.00 scf sf +1275 6075 m +gs 1 -1 sc (- headers) col0 sh gr +/Times-Roman-iso ff 200.00 scf sf +1275 6675 m +gs 1 -1 sc (- images) col0 sh gr +/Times-Roman-iso ff 200.00 scf sf +1275 6375 m +gs 1 -1 sc (- footers) col0 sh gr +% Polyline +n 6675 8775 m 6975 8475 l 7875 8475 l 7875 9975 l 6675 9975 l 6675 8775 l + 6975 8775 l + 6975 8475 l gs col0 s gr +% Polyline +n 6750 8700 m 6750 8400 l 7950 8400 l 7950 9900 l + 7875 9900 l gs col0 s gr +% Polyline +n 6825 8400 m 6825 8325 l 8025 8325 l 8025 9825 l + 7950 9825 l gs col0 s gr +% Polyline +n 6900 8325 m 6900 8250 l 8100 8250 l 8100 9750 l + 8025 9750 l gs col0 s gr +% Polyline +n 6600 4950 m 6900 4650 l 7800 4650 l 7800 6150 l 6600 6150 l 6600 4950 l + 6900 4950 l + 6900 4650 l gs col0 s gr +% Polyline +n 6675 4875 m 6675 4575 l 7875 4575 l 7875 6075 l + 7800 6075 l gs col0 s gr +% Polyline +n 6750 4575 m 6750 4500 l 7950 4500 l 7950 6000 l + 7875 6000 l gs col0 s gr +% Polyline +n 6825 4500 m 6825 4425 l 8025 4425 l 8025 5925 l + 7950 5925 l gs col0 s gr +% Polyline +n 6600 2925 m 6900 2625 l 7800 2625 l 7800 4125 l 6600 4125 l 6600 2925 l + 6900 2925 l + 6900 2625 l gs col0 s gr +% Polyline +n 6675 2850 m 6675 2550 l 7875 2550 l 7875 4050 l + 7800 4050 l gs col0 s gr +% Polyline +n 6750 2550 m 6750 2475 l 7950 2475 l 7950 3975 l + 7875 3975 l gs col0 s gr +% Polyline +n 6825 2475 m 6825 2400 l 8025 2400 l 8025 3900 l + 7950 3900 l gs col0 s gr +% Polyline +n 6600 900 m 6900 600 l 7800 600 l 7800 2100 l 6600 2100 l 6600 900 l + 6900 900 l + 6900 600 l gs col0 s gr +% Polyline +n 6675 825 m 6675 525 l 7875 525 l 7875 2025 l + 7800 2025 l gs col0 s gr +% Polyline +n 6750 525 m 6750 450 l 7950 450 l 7950 1950 l + 7875 1950 l gs col0 s gr +% Polyline +n 6825 450 m 6825 375 l 8025 375 l 8025 1875 l + 7950 1875 l gs col0 s gr +% Polyline +n 4350 1950 m 4650 1650 l 5550 1650 l 5550 3150 l 4350 3150 l 4350 1950 l + 4650 1950 l + 4650 1650 l gs col0 s gr +/Times-Roman-iso ff 200.00 scf sf +4575 2250 m +gs 1 -1 sc (Config file) col0 sh gr +/Times-Roman-iso ff 200.00 scf sf +4575 2550 m +gs 1 -1 sc (Doxyfile) col0 sh gr +% Polyline +n 2850 1950 m 3150 1650 l 4050 1650 l 4050 3150 l 2850 3150 l 2850 1950 l + 3150 1950 l + 3150 1650 l gs col0 s gr +/Times-Roman-iso ff 200.00 scf sf +3000 2475 m +gs 1 -1 sc (Layout file) col0 sh gr +% Polyline +gs clippath +3164 4155 m 3315 4155 l 3315 4095 l 3164 4095 l 3164 4095 l 3284 4125 l 3164 4155 l cp +eoclip +n 2100 4125 m + 3300 4125 l gs col0 s gr gr + +% arrowhead +n 3164 4155 m 3284 4125 l 3164 4095 l 3164 4155 l cp gs 0.00 setgray ef gr col0 s +% Polyline +gs clippath +3164 4380 m 3315 4380 l 3315 4320 l 3164 4320 l 3164 4320 l 3284 4350 l 3164 4380 l cp +eoclip +n 2100 6225 m 2700 6225 l 2700 4350 l + 3300 4350 l gs col0 s gr gr + +% arrowhead +n 3164 4380 m 3284 4350 l 3164 4320 l 3164 4380 l cp gs 0.00 setgray ef gr col0 s +% Polyline +n 3675 5925 m 3975 5625 l 4875 5625 l 4875 7125 l 3675 7125 l 3675 5925 l + 3975 5925 l + 3975 5625 l gs col0 s gr +% Polyline +gs clippath +4155 4786 m 4155 4635 l 4095 4635 l 4095 4786 l 4095 4786 l 4125 4666 l 4155 4786 l cp +eoclip +n 4125 5625 m + 4125 4650 l gs col0 s gr gr + +% arrowhead +n 4155 4786 m 4125 4666 l 4095 4786 l 4155 4786 l cp gs 0.00 setgray ef gr col0 s +% Polyline +gs clippath +4320 5489 m 4320 5640 l 4380 5640 l 4380 5489 l 4380 5489 l 4350 5609 l 4320 5489 l cp +eoclip +n 4350 5625 m + 4350 4650 l gs col0 s gr gr + +% arrowhead +n 4320 5489 m 4350 5609 l 4380 5489 l 4320 5489 l cp gs 0.00 setgray ef gr col0 s +% Polyline +gs clippath +6464 1455 m 6615 1455 l 6615 1395 l 6464 1395 l 6464 1395 l 6584 1425 l 6464 1455 l cp +eoclip +n 5100 3900 m 6000 3900 l 6000 1425 l + 6600 1425 l gs col0 s gr gr + +% arrowhead +n 6464 1455 m 6584 1425 l 6464 1395 l 6464 1455 l cp gs 0.00 setgray ef gr col0 s +% Polyline +gs clippath +6464 3480 m 6615 3480 l 6615 3420 l 6464 3420 l 6464 3420 l 6584 3450 l 6464 3480 l cp +eoclip +n 5100 4050 m 6300 4050 l 6300 3450 l + 6600 3450 l gs col0 s gr gr + +% arrowhead +n 6464 3480 m 6584 3450 l 6464 3420 l 6464 3480 l cp gs 0.00 setgray ef gr col0 s +% Polyline +gs clippath +6464 5580 m 6615 5580 l 6615 5520 l 6464 5520 l 6464 5520 l 6584 5550 l 6464 5580 l cp +eoclip +n 5100 4200 m 6300 4200 l 6300 5550 l + 6600 5550 l gs col0 s gr gr + +% arrowhead +n 6464 5580 m 6584 5550 l 6464 5520 l 6464 5580 l cp gs 0.00 setgray ef gr col0 s +% Polyline +gs clippath +6539 7380 m 6690 7380 l 6690 7320 l 6539 7320 l 6539 7320 l 6659 7350 l 6539 7380 l cp +eoclip +n 5100 4350 m 6000 4350 l 6000 7350 l + 6675 7350 l gs col0 s gr gr + +% arrowhead +n 6539 7380 m 6659 7350 l 6539 7320 l 6539 7380 l cp gs 0.00 setgray ef gr col0 s +% Polyline +gs clippath +6539 9180 m 6690 9180 l 6690 9120 l 6539 9120 l 6539 9120 l 6659 9150 l 6539 9180 l cp +eoclip +n 5100 4500 m 5700 4500 l 5700 9150 l + 6675 9150 l gs col0 s gr gr + +% arrowhead +n 6539 9180 m 6659 9150 l 6539 9120 l 6539 9180 l cp gs 0.00 setgray ef gr col0 s +% Polyline +n 6675 6675 m 6975 6375 l 7875 6375 l 7875 7875 l 6675 7875 l 6675 6675 l + 6975 6675 l + 6975 6375 l gs col0 s gr +% Polyline +n 3300 3750 m 5100 3750 l 5100 4650 l 3300 4650 l + cp gs col32 1.00 shd ef gr gs col0 s gr +% Polyline +n 8775 450 m 10800 450 l 10800 1575 l 8775 1575 l + cp gs col32 1.00 shd ef gr gs col0 s gr +% Polyline +n 9075 900 m 10650 900 l 10650 1425 l 9075 1425 l + cp gs col0 s gr +% Polyline +gs clippath +8639 1380 m 8790 1380 l 8790 1320 l 8639 1320 l 8639 1320 l 8759 1350 l 8639 1380 l cp +eoclip +n 7800 1350 m + 8775 1350 l gs col0 s gr gr + +% arrowhead +n 8639 1380 m 8759 1350 l 8639 1320 l 8639 1380 l cp gs 0.00 setgray ef gr col0 s +% Polyline +gs clippath +11339 1380 m 11490 1380 l 11490 1320 l 11339 1320 l 11339 1320 l 11459 1350 l 11339 1380 l cp +eoclip +n 10800 1350 m + 11475 1350 l gs col0 s gr gr + +% arrowhead +n 11339 1380 m 11459 1350 l 11339 1320 l 11339 1380 l cp gs 0.00 setgray ef gr col0 s +% Polyline +gs clippath +8864 3180 m 9015 3180 l 9015 3120 l 8864 3120 l 8864 3120 l 8984 3150 l 8864 3180 l cp +eoclip +n 7800 3150 m + 9000 3150 l gs col0 s gr gr + +% arrowhead +n 8864 3180 m 8984 3150 l 8864 3120 l 8864 3180 l cp gs 0.00 setgray ef gr col0 s +% Polyline +gs clippath +8864 3555 m 9015 3555 l 9015 3495 l 8864 3495 l 8864 3495 l 8984 3525 l 8864 3555 l cp +eoclip +n 7800 3525 m + 9000 3525 l gs col0 s gr gr + +% arrowhead +n 8864 3555 m 8984 3525 l 8864 3495 l 8864 3555 l cp gs 0.00 setgray ef gr col0 s +% Polyline +n 9000 2925 m 10800 2925 l 10800 3675 l 9000 3675 l + cp gs col32 1.00 shd ef gr gs col0 s gr +% Polyline +gs clippath +11339 3180 m 11490 3180 l 11490 3120 l 11339 3120 l 11339 3120 l 11459 3150 l 11339 3180 l cp +eoclip +n 10800 3150 m + 11475 3150 l gs col0 s gr gr + +% arrowhead +n 11339 3180 m 11459 3150 l 11339 3120 l 11339 3180 l cp gs 0.00 setgray ef gr col0 s +% Polyline +gs clippath +11339 3555 m 11490 3555 l 11490 3495 l 11339 3495 l 11339 3495 l 11459 3525 l 11339 3555 l cp +eoclip +n 10800 3525 m + 11475 3525 l gs col0 s gr gr + +% arrowhead +n 11339 3555 m 11459 3525 l 11339 3495 l 11339 3555 l cp gs 0.00 setgray ef gr col0 s +% Polyline +gs clippath +8864 7305 m 9015 7305 l 9015 7245 l 8864 7245 l 8864 7245 l 8984 7275 l 8864 7305 l cp +eoclip +n 7875 7275 m + 9000 7275 l gs col0 s gr gr + +% arrowhead +n 8864 7305 m 8984 7275 l 8864 7245 l 8864 7305 l cp gs 0.00 setgray ef gr col0 s +% Polyline +gs clippath +8864 9180 m 9015 9180 l 9015 9120 l 8864 9120 l 8864 9120 l 8984 9150 l 8864 9180 l cp +eoclip +n 7875 9150 m + 9000 9150 l gs col0 s gr gr + +% arrowhead +n 8864 9180 m 8984 9150 l 8864 9120 l 8864 9180 l cp gs 0.00 setgray ef gr col0 s +% Polyline + [60] 0 sd +n 8700 6450 m 11850 6450 l 11850 9975 l 8700 9975 l + cp gs col0 s gr [] 0 sd +% Polyline +gs clippath +4845 1514 m 4845 1665 l 4905 1665 l 4905 1514 l 4905 1514 l 4875 1634 l 4845 1514 l cp +4905 1186 m 4905 1035 l 4845 1035 l 4845 1186 l 4845 1186 l 4875 1066 l 4905 1186 l cp +eoclip +n 4875 1050 m + 4875 1650 l gs col0 s gr gr + +% arrowhead +n 4905 1186 m 4875 1066 l 4845 1186 l 4905 1186 l cp gs 0.00 setgray ef gr col0 s +% arrowhead +n 4845 1514 m 4875 1634 l 4905 1514 l 4845 1514 l cp gs 0.00 setgray ef gr col0 s +% Polyline +n 4125 300 m 5925 300 l 5925 1050 l 4125 1050 l + cp gs col32 1.00 shd ef gr gs col0 s gr +% Polyline +gs clippath +4905 3286 m 4905 3135 l 4845 3135 l 4845 3286 l 4845 3286 l 4875 3166 l 4905 3286 l cp +eoclip +n 4875 3150 m + 4875 3750 l gs col0 s gr gr + +% arrowhead +n 4905 3286 m 4875 3166 l 4845 3286 l 4905 3286 l cp gs 0.00 setgray ef gr col0 s +% Polyline +gs clippath +4620 3614 m 4620 3765 l 4680 3765 l 4680 3614 l 4680 3614 l 4650 3734 l 4620 3614 l cp +eoclip +n 4650 3150 m + 4650 3750 l gs col0 s gr gr + +% arrowhead +n 4620 3614 m 4650 3734 l 4680 3614 l 4620 3614 l cp gs 0.00 setgray ef gr col0 s +% Polyline +gs clippath +3720 3614 m 3720 3765 l 3780 3765 l 3780 3614 l 3780 3614 l 3750 3734 l 3720 3614 l cp +eoclip +n 3750 3150 m + 3750 3750 l gs col0 s gr gr + +% arrowhead +n 3720 3614 m 3750 3734 l 3780 3614 l 3720 3614 l cp gs 0.00 setgray ef gr col0 s +% Polyline +gs clippath +3555 3286 m 3555 3135 l 3495 3135 l 3495 3286 l 3495 3286 l 3525 3166 l 3555 3286 l cp +eoclip +n 3525 3150 m + 3525 3750 l gs col0 s gr gr + +% arrowhead +n 3555 3286 m 3525 3166 l 3495 3286 l 3555 3286 l cp gs 0.00 setgray ef gr col0 s +% Polyline +n 9000 8775 m 11175 8775 l 11175 9525 l 9000 9525 l + cp gs col32 1.00 shd ef gr gs col0 s gr +% Polyline +gs clippath +11639 7305 m 11790 7305 l 11790 7245 l 11639 7245 l 11639 7245 l 11759 7275 l 11639 7305 l cp +eoclip +n 11250 7275 m + 11775 7275 l gs col0 s gr gr + +% arrowhead +n 11639 7305 m 11759 7275 l 11639 7245 l 11639 7305 l cp gs 0.00 setgray ef gr col0 s +% Polyline +n 9000 6900 m 11250 6900 l 11250 7650 l 9000 7650 l + cp gs col32 1.00 shd ef gr gs col0 s gr +% Polyline +gs clippath +11564 9180 m 11715 9180 l 11715 9120 l 11564 9120 l 11564 9120 l 11684 9150 l 11564 9180 l cp +eoclip +n 11175 9150 m + 11700 9150 l gs col0 s gr gr + +% arrowhead +n 11564 9180 m 11684 9150 l 11564 9120 l 11564 9180 l cp gs 0.00 setgray ef gr col0 s +/Times-Roman-iso ff 200.00 scf sf +2850 3975 m +gs 1 -1 sc (read) col0 sh gr +/Times-Roman-iso ff 200.00 scf sf +2850 4650 m +gs 1 -1 sc (read) col0 sh gr +/Times-Roman-iso ff 200.00 scf sf +4425 5175 m +gs 1 -1 sc (generate) col0 sh gr +/Times-Roman-iso ff 200.00 scf sf +3675 5175 m +gs 1 -1 sc (read) col0 sh gr +/Times-Roman-iso ff 200.00 scf sf +3900 4275 m +gs 1 -1 sc (Doxygen) col0 sh gr +/Times-Roman-iso ff 200.00 scf sf +8175 3000 m +gs 1 -1 sc (make ps) col0 sh gr +/Times-Roman-iso ff 200.00 scf sf +9675 3375 m +gs 1 -1 sc (latex) col0 sh gr +/Times-Roman-iso ff 200.00 scf sf +11025 825 m +gs 1 -1 sc (custom) col0 sh gr +/Times-Roman-iso ff 200.00 scf sf +11025 1050 m +gs 1 -1 sc (output) col0 sh gr +/Times-Roman-iso ff 200.00 scf sf +11025 3000 m +gs 1 -1 sc (postscript) col0 sh gr +/Times-Roman-iso ff 200.00 scf sf +11025 3825 m +gs 1 -1 sc (PDF) col0 sh gr +/Times-Roman-iso ff 200.00 scf sf +6975 9075 m +gs 1 -1 sc (HTML) col0 sh gr +/Times-Roman-iso ff 200.00 scf sf +6975 9300 m +gs 1 -1 sc (pages) col0 sh gr +/Times-Roman-iso ff 200.00 scf sf +8775 6675 m +gs 1 -1 sc (Windows only) col0 sh gr +/Times-Roman-iso ff 200.00 scf sf +8250 1200 m +gs 1 -1 sc (read) col0 sh gr +/Times-Roman-iso ff 200.00 scf sf +1200 4200 m +gs 1 -1 sc (Sources) col0 sh gr +/Times-Roman-iso ff 200.00 scf sf +1275 5775 m +gs 1 -1 sc (Custom) col0 sh gr +/Times-Roman-iso ff 200.00 scf sf +3675 1350 m +gs 1 -1 sc (generate/edit) col0 sh gr +/Times-Roman-iso ff 200.00 scf sf +4425 750 m +gs 1 -1 sc (Doxywizard) col0 sh gr +/Times-Roman-iso ff 200.00 scf sf +4050 3525 m +gs 1 -1 sc (read) col0 sh gr +/Times-Roman-iso ff 200.00 scf sf +5025 3375 m +gs 1 -1 sc (generate) col0 sh gr +/Times-Roman-iso ff 200.00 scf sf +5025 3600 m +gs 1 -1 sc (update) col0 sh gr +/Times-Roman-iso ff 200.00 scf sf +2625 3375 m +gs 1 -1 sc (generate) col0 sh gr +/Times-Roman-iso ff 200.00 scf sf +6825 1350 m +gs 1 -1 sc (XML files) col0 sh gr +/Times-Roman-iso ff 200.00 scf sf +6750 3300 m +gs 1 -1 sc (Latex files) col0 sh gr +/Times-Roman-iso ff 200.00 scf sf +6750 3750 m +gs 1 -1 sc (Makefile) col0 sh gr +/Times-Roman-iso ff 200.00 scf sf +7125 3525 m +gs 1 -1 sc (+) col0 sh gr +/Times-Roman-iso ff 200.00 scf sf +6750 5625 m +gs 1 -1 sc (Man pages) col0 sh gr +/Times-Roman-iso ff 200.00 scf sf +6900 7350 m +gs 1 -1 sc (refman.rtf) col0 sh gr +/Times-Roman-iso ff 200.00 scf sf +9075 9225 m +gs 1 -1 sc (HTML Help Workshop) col0 sh gr +/Times-Roman-iso ff 200.00 scf sf +8100 3750 m +gs 1 -1 sc (make pdf) col0 sh gr +/Times-Roman-iso ff 200.00 scf sf +9225 1275 m +gs 1 -1 sc (doxmlparser lib) col0 sh gr +/Times-Roman-iso ff 200.00 scf sf +9150 750 m +gs 1 -1 sc (Your application) col0 sh gr +/Times-Roman-iso ff 200.00 scf sf +3900 6450 m +gs 1 -1 sc (Tag file\(s\)) col0 sh gr +/Times-Roman-iso ff 200.00 scf sf +11325 7125 m +gs 1 -1 sc (doc) col0 sh gr +/Times-Roman-iso ff 200.00 scf sf +9750 7350 m +gs 1 -1 sc (MS-Word) col0 sh gr +/Times-Roman-iso ff 200.00 scf sf +11325 9000 m +gs 1 -1 sc (chm) col0 sh gr +/Times-Roman-iso ff 200.00 scf sf +8250 9075 m +gs 1 -1 sc (read) col0 sh gr +% Polyline +n 900 3675 m 1200 3375 l 2100 3375 l 2100 4875 l 900 4875 l 900 3675 l + 1200 3675 l + 1200 3375 l gs col0 s gr +% here ends figure; +pagefooter +showpage +%%Trailer +%EOF diff --git a/trunk/doc/infoflow.fig b/trunk/doc/infoflow.fig new file mode 100644 index 0000000..9db91af --- /dev/null +++ b/trunk/doc/infoflow.fig @@ -0,0 +1,229 @@ +#FIG 3.2 Produced by xfig version 3.2.5b +Landscape +Center +Inches +Letter +100.00 +Single +-2 +1200 2 +0 32 #e0e0e0 +0 33 #000000 +6 900 3150 2325 4875 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 8 + 900 3675 1200 3375 2100 3375 2100 4875 900 4875 900 3675 + 1200 3675 1200 3375 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 + 975 3600 975 3300 2175 3300 2175 4800 2100 4800 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 + 1050 3300 1050 3225 2250 3225 2250 4725 2175 4725 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 + 1125 3225 1125 3150 2325 3150 2325 4650 2250 4650 +-6 +6 900 5175 2325 6900 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 8 + 900 5700 1200 5400 2100 5400 2100 6900 900 6900 900 5700 + 1200 5700 1200 5400 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 + 975 5625 975 5325 2175 5325 2175 6825 2100 6825 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 + 1050 5325 1050 5250 2250 5250 2250 6750 2175 6750 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 + 1125 5250 1125 5175 2325 5175 2325 6675 2250 6675 +-6 +6 1275 5925 2025 6750 +4 0 0 50 0 0 12 0.0000 4 150 795 1275 6075 - headers\001 +4 0 0 50 0 0 12 0.0000 4 195 720 1275 6675 - images\001 +4 0 0 50 0 0 12 0.0000 4 150 705 1275 6375 - footers\001 +-6 +6 6675 8250 8100 9975 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 8 + 6675 8775 6975 8475 7875 8475 7875 9975 6675 9975 6675 8775 + 6975 8775 6975 8475 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 + 6750 8700 6750 8400 7950 8400 7950 9900 7875 9900 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 + 6825 8400 6825 8325 8025 8325 8025 9825 7950 9825 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 + 6900 8325 6900 8250 8100 8250 8100 9750 8025 9750 +-6 +6 6600 4425 8025 6150 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 8 + 6600 4950 6900 4650 7800 4650 7800 6150 6600 6150 6600 4950 + 6900 4950 6900 4650 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 + 6675 4875 6675 4575 7875 4575 7875 6075 7800 6075 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 + 6750 4575 6750 4500 7950 4500 7950 6000 7875 6000 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 + 6825 4500 6825 4425 8025 4425 8025 5925 7950 5925 +-6 +6 6600 2400 8025 4125 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 8 + 6600 2925 6900 2625 7800 2625 7800 4125 6600 4125 6600 2925 + 6900 2925 6900 2625 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 + 6675 2850 6675 2550 7875 2550 7875 4050 7800 4050 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 + 6750 2550 6750 2475 7950 2475 7950 3975 7875 3975 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 + 6825 2475 6825 2400 8025 2400 8025 3900 7950 3900 +-6 +6 6600 375 8025 2100 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 8 + 6600 900 6900 600 7800 600 7800 2100 6600 2100 6600 900 + 6900 900 6900 600 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 + 6675 825 6675 525 7875 525 7875 2025 7800 2025 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 + 6750 525 6750 450 7950 450 7950 1950 7875 1950 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 + 6825 450 6825 375 8025 375 8025 1875 7950 1875 +-6 +6 4350 1650 5550 3150 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 8 + 4350 1950 4650 1650 5550 1650 5550 3150 4350 3150 4350 1950 + 4650 1950 4650 1650 +4 0 0 50 0 0 12 0.0000 4 195 870 4575 2250 Config file\001 +4 0 0 50 0 0 12 0.0000 4 195 720 4575 2550 Doxyfile\001 +-6 +6 2850 1650 4050 3150 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 8 + 2850 1950 3150 1650 4050 1650 4050 3150 2850 3150 2850 1950 + 3150 1950 3150 1650 +4 0 0 50 -1 0 12 0.0000 4 195 915 3000 2475 Layout file\001 +-6 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2 + 1 1 1.00 60.00 120.00 + 2100 4125 3300 4125 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 4 + 1 1 1.00 60.00 120.00 + 2100 6225 2700 6225 2700 4350 3300 4350 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 8 + 3675 5925 3975 5625 4875 5625 4875 7125 3675 7125 3675 5925 + 3975 5925 3975 5625 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2 + 1 1 1.00 60.00 120.00 + 4125 5625 4125 4650 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 1 2 + 1 1 1.00 60.00 120.00 + 4350 5625 4350 4650 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 4 + 1 1 1.00 60.00 120.00 + 5100 3900 6000 3900 6000 1425 6600 1425 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 4 + 1 1 1.00 60.00 120.00 + 5100 4050 6300 4050 6300 3450 6600 3450 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 4 + 1 1 1.00 60.00 120.00 + 5100 4200 6300 4200 6300 5550 6600 5550 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 4 + 1 1 1.00 60.00 120.00 + 5100 4350 6000 4350 6000 7350 6675 7350 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 4 + 1 1 1.00 60.00 120.00 + 5100 4500 5700 4500 5700 9150 6675 9150 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 8 + 6675 6675 6975 6375 7875 6375 7875 7875 6675 7875 6675 6675 + 6975 6675 6975 6375 +2 2 0 1 0 32 50 0 20 0.000 0 0 -1 0 0 5 + 3300 3750 5100 3750 5100 4650 3300 4650 3300 3750 +2 2 0 1 0 32 50 0 20 0.000 0 0 -1 0 0 5 + 8775 450 10800 450 10800 1575 8775 1575 8775 450 +2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 + 9075 900 10650 900 10650 1425 9075 1425 9075 900 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2 + 1 1 1.00 60.00 120.00 + 7800 1350 8775 1350 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2 + 1 1 1.00 60.00 120.00 + 10800 1350 11475 1350 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2 + 1 1 1.00 60.00 120.00 + 7800 3150 9000 3150 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2 + 1 1 1.00 60.00 120.00 + 7800 3525 9000 3525 +2 2 0 1 0 32 50 0 20 0.000 0 0 -1 0 0 5 + 9000 2925 10800 2925 10800 3675 9000 3675 9000 2925 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2 + 1 1 1.00 60.00 120.00 + 10800 3150 11475 3150 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2 + 1 1 1.00 60.00 120.00 + 10800 3525 11475 3525 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2 + 1 1 1.00 60.00 120.00 + 7875 7275 9000 7275 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2 + 1 1 1.00 60.00 120.00 + 7875 9150 9000 9150 +2 2 1 1 0 7 50 0 -1 4.000 0 0 -1 0 0 5 + 8700 6450 11850 6450 11850 9975 8700 9975 8700 6450 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 1 2 + 1 1 1.00 60.00 120.00 + 1 1 1.00 60.00 120.00 + 4875 1050 4875 1650 +2 2 0 1 0 32 50 0 20 0.000 0 0 -1 0 0 5 + 4125 300 5925 300 5925 1050 4125 1050 4125 300 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 1 2 + 1 1 1.00 60.00 120.00 + 4875 3150 4875 3750 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2 + 1 1 1.00 60.00 120.00 + 4650 3150 4650 3750 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2 + 1 1 1.00 60.00 120.00 + 3750 3150 3750 3750 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 1 2 + 1 1 1.00 60.00 120.00 + 3525 3150 3525 3750 +2 2 0 1 0 32 50 0 20 0.000 0 0 -1 0 0 5 + 9000 8775 11175 8775 11175 9525 9000 9525 9000 8775 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2 + 1 1 1.00 60.00 120.00 + 11250 7275 11775 7275 +2 2 0 1 0 32 50 0 20 0.000 0 0 -1 0 0 5 + 9000 6900 11250 6900 11250 7650 9000 7650 9000 6900 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2 + 1 1 1.00 60.00 120.00 + 11175 9150 11700 9150 +4 0 0 50 0 0 12 0.0000 4 150 390 2850 3975 read\001 +4 0 0 50 0 0 12 0.0000 4 150 390 2850 4650 read\001 +4 0 0 50 0 0 12 0.0000 4 165 765 4425 5175 generate\001 +4 0 0 50 0 0 12 0.0000 4 150 390 3675 5175 read\001 +4 0 0 50 0 0 12 0.0000 4 195 780 3900 4275 Doxygen\001 +4 0 0 50 0 0 12 0.0000 4 195 720 8175 3000 make ps\001 +4 0 0 50 0 0 12 0.0000 4 150 420 9675 3375 latex\001 +4 0 0 50 0 0 12 0.0000 4 120 630 11025 825 custom\001 +4 0 0 50 0 0 12 0.0000 4 165 540 11025 1050 output\001 +4 0 0 50 0 0 12 0.0000 4 195 840 11025 3000 postscript\001 +4 0 0 50 0 0 12 0.0000 4 150 390 11025 3825 PDF\001 +4 0 0 50 0 0 12 0.0000 4 150 615 6975 9075 HTML\001 +4 0 0 50 0 0 12 0.0000 4 150 510 6975 9300 pages\001 +4 0 0 50 0 0 12 0.0000 4 195 1215 8775 6675 Windows only\001 +4 0 0 50 0 0 12 0.0000 4 150 390 8250 1200 read\001 +4 0 0 50 0 0 12 0.0000 4 150 705 1200 4200 Sources\001 +4 0 0 50 0 0 12 0.0000 4 150 675 1275 5775 Custom\001 +4 0 0 50 0 0 12 0.0000 4 195 1140 3675 1350 generate/edit\001 +4 0 0 50 0 0 12 0.0000 4 195 1050 4425 750 Doxywizard\001 +4 0 0 50 0 0 12 0.0000 4 150 390 4050 3525 read\001 +4 0 0 50 0 0 12 0.0000 4 165 765 5025 3375 generate\001 +4 0 0 50 -1 0 12 0.0000 4 195 585 5025 3600 update\001 +4 0 0 50 0 0 12 0.0000 4 165 765 2625 3375 generate\001 +4 0 0 50 0 0 12 0.0000 4 150 870 6825 1350 XML files\001 +4 0 0 50 0 0 12 0.0000 4 150 900 6750 3300 Latex files\001 +4 0 0 50 0 0 12 0.0000 4 150 765 6750 3750 Makefile\001 +4 0 0 50 0 0 12 0.0000 4 105 120 7125 3525 +\001 +4 0 0 50 0 0 12 0.0000 4 195 960 6750 5625 Man pages\001 +4 0 0 50 0 0 12 0.0000 4 150 870 6900 7350 refman.rtf\001 +4 0 0 50 0 0 12 0.0000 4 195 1995 9075 9225 HTML Help Workshop\001 +4 0 0 50 0 0 12 0.0000 4 195 795 8100 3750 make pdf\001 +4 0 0 50 0 0 12 0.0000 4 195 1320 9225 1275 doxmlparser lib\001 +4 0 0 50 0 0 12 0.0000 4 195 1395 9150 750 Your application\001 +4 0 0 50 0 0 12 0.0000 4 195 885 3900 6450 Tag file(s)\001 +4 0 0 50 0 0 12 0.0000 4 150 315 11325 7125 doc\001 +4 0 0 50 0 0 12 0.0000 4 150 855 9750 7350 MS-Word\001 +4 0 0 50 0 0 12 0.0000 4 150 375 11325 9000 chm\001 +4 0 0 50 0 0 12 0.0000 4 150 390 8250 9075 read\001 +4 0 0 50 0 0 12 0.0000 4 195 555 8100 7200 import\001 diff --git a/trunk/doc/infoflow.png b/trunk/doc/infoflow.png new file mode 100644 index 0000000..d975be1 Binary files /dev/null and b/trunk/doc/infoflow.png differ diff --git a/trunk/doc/install.doc b/trunk/doc/install.doc new file mode 100644 index 0000000..d076cf3 --- /dev/null +++ b/trunk/doc/install.doc @@ -0,0 +1,643 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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 install Installation + +\addindex installation +\tableofcontents + +First go to the +<a href="http://www.doxygen.org/download.html">download</a> page +to get the latest distribution, if you did not downloaded doxygen already. + +\section install_src_unix Compiling from source on UNIX + +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 + flex, bison and GNU make, and strip + \addindex flex + \addindex bison + \addindex make + \addindex strip +<li>In order to generate a Makefile for your platform, you need + <a href="http://www.perl.com/">perl</a> + \addindex perl +<li>The configure script assume the availability of standard UNIX tools such + as sed, date, find, uname, mv, cp, cat, echo, tr, cd, and rm. +</ul> + +To take full advantage of doxygen's features the following additional +tools should be installed. + +<ul> +<li>Qt Software's GUI toolkit + <a href="http://qt.nokia.com/">Qt</A> + \addindex Qt + version 4.3 or higher. + This is needed to build the GUI front-end doxywizard. +<li>A \f$\mbox{\LaTeX}\f$ distribution: for instance + <a href="http://www.tug.org/interest.html#free">teTeX 1.0</a> + This is needed for generating LaTeX, Postscript, and PDF output. +<li><a href="http://www.graphviz.org/"> + the Graph visualization toolkit version 1.8.10 or higher</a> + Needed for the include dependency graphs, + the graphical inheritance graphs, and the collaboration graphs. + If you compile graphviz yourself, make sure you do include + freetype support (which requires the freetype library and header files), + otherwise the graphs will not render proper text labels. +<li>For formulas or if you do not wish to use pdflatex, the ghostscript interpreter + is needed. You can find it at + <a href="http://www.ghostscript.com/">www.ghostscript.com</a>. +<li>In order to generate doxygen's own documentation, Python is needed, you + can find it at <a href="http://www.python.org">www.python.org</a>. +</ul> + +Compilation is now done by performing the following steps: + +<ol> +<li>Unpack the archive, unless you already have done that: + + gunzip doxygen-$VERSION.src.tar.gz # uncompress the archive + tar xf doxygen-$VERSION.src.tar # unpack it + +<li>Run the configure script: + + sh ./configure + + The script tries to determine the platform you use, the make tool + (which \e must be GNU make) and the perl + interpreter. It will report what it finds. + + To override the auto detected platform and compiler you can run + configure as follows: + + configure --platform platform-type + + See the <code>PLATFORMS</code> file for a list of possible platform + options. + + If you have Qt-4.3 or higher installed and want to build the GUI + front-end, you should run the configure script with + the <code>--with-doxywizard</code> option: + + configure --with-doxywizard + + For an overview of other configuration options use + + configure --help + +<li>Compile the program by running make: + + make + + The program should compile without problems and the binaries + (<code>doxygen</code> and optionally <code>doxywizard</code>) + should be available in the bin directory of the distribution. + +<li>Optional: Generate the user manual. + + make docs + + To let doxygen generate the HTML documentation. + + The HTML directory of the distribution will now contain the html + documentation (just point a HTML browser to the file + <code>index.html</code> in the + html directory). You will need the <code>python</code> interpreter + for this. + +<li>Optional: Generate a PDF version of the manual + (you will need <code>pdflatex</code>, <code>makeindex</code>, and + <code>egrep</code> for this). + + make pdf + + The PDF manual <code>doxygen_manual.pdf</code> will be located + in the latex directory of the distribution. Just + view and print it via the acrobat reader. + +</ol> + +\section install_bin_unix Installing the binaries on UNIX + + After the compilation of the source code do a <code>make install</code> + to install doxygen. If you downloaded the binary distribution for UNIX, + type: + + ./configure + make install + + Binaries are installed into the directory <code>\<prefix\>/bin</code>. + Use <code>make install_docs</code> to install the + documentation and examples into <code>\<docdir\>/doxygen</code>. + + <code>\<prefix\></code> defaults to <code>/usr/local</code> but can be changed with + the <code>--prefix</code> option of the configure script. + The default <code>\<docdir\></code> directory is + <code>\<prefix\>/share/doc/packages</code> and can be changed with + the <code>--docdir</code> option of the configure script. + + Alternatively, you can also copy the binaries from the <code>bin</code> + directory manually to some <code>bin</code> directory in your search path. + This is sufficient to use doxygen. + + \note You need the GNU install tool for this to work (it is part of + the coreutils package). Other install tools may put the binaries in + the wrong directory! + + If you have a RPM or DEP package, then please follow the + standard installation procedure that is required for these packages. + +\section unix_problems Known compilation problems for UNIX + +<b>Qt problems</b> + +The Qt include files and libraries are not a subdirectory of the +directory pointed to by QTDIR on some systems +(for instance on Red Hat 6.0 includes are in /usr/include/qt and +libs are in /usr/lib). + +The solution: go to the root of the doxygen distribution and do: + + mkdir qt + cd qt + ln -s your-qt-include-dir-here include + ln -s your-qt-lib-dir-here lib + ln -s your-qt-bin-dir-here bin + export QTDIR=$PWD + +If you have a csh-like shell you should use <code>setenv QTDIR \$PWD</code> +instead of the <code>export</code> command above. + +Now install doxygen as described above. + +<b>Bison problems</b> + +Versions 1.31 to 1.34 of bison contain a "bug" that results in a +compiler errors like this: + +ce_parse.cpp:348: member `class CPPValue yyalloc::yyvs' with +constructor not allowed in union + +This problem has been solved in version 1.35 (versions before 1.31 +will also work). + +<b>Latex problems</b> + +The file <code>a4wide.sty</code> is not available for all distributions. If +your distribution does not have it please select another paper type +in the config file (see the \ref cfg_paper_type "PAPER_TYPE" tag in the +config file). + +<b>HP-UX \& Digital UNIX problems</b> + +If you are compiling for HP-UX with aCC and you get this error: + + /opt/aCC/lbin/ld: Unsatisfied symbols: + alloca (code) + +then you should (according to Anke Selig) edit <code>ce_parse.cpp</code> +and replace + + extern "C" { + void *alloca (unsigned int); + }; + +with + + #include <alloca.h> + +If that does not help, try removing <code>ce_parse.cpp</code> and let +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 +ce_parse.cpp: + +\verbatim + #else /* not GNU C. */ + #if (!defined (__STDC__) && defined (sparc)) || defined (__sparc__) \ + || defined (__sparc) || defined (__sgi) + #include <alloca.h> +\endverbatim + + with + +\verbatim + #else /* not GNU C. */ + #if (!defined (__STDC__) && defined (sparc)) || defined (__sparc__) \ + || defined (__sparc) || defined (__sgi) || defined (__osf__) + #include <alloca.h> +\endverbatim + + Alternatively, one could fix the problem at the bison side. + Here is patch for bison.simple (provided by Andre Johansen): + +\verbatim +--- bison.simple~ Tue Nov 18 11:45:53 1997 ++++ bison.simple Mon Jan 26 15:10:26 1998 +@@ -27,7 +27,7 @@ + #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) + #include <alloca.h> + #else /* not sparc */ + #if defined (MSDOS) && !defined (__TURBOC__) +\endverbatim + + The generated scanner.cpp that comes with doxygen is build with this + patch applied. + +<b>Sun compiler problems</b> + +It appears that doxygen doesn't work properly if it is compiled +with Sun's C++ WorkShop 6 Compiler. I cannot verify this myself as I do +not have access to a Solaris machine with this compiler. With GNU compiler +it does work and installing Sun patch 111679-13 has also been reported +as a way to fix the problem. + +when configuring with `--static` I got: + +\verbatim +Undefined first referenced + symbol in file +dlclose /usr/lib/libc.a(nss_deffinder.o) +dlsym /usr/lib/libc.a(nss_deffinder.o) +dlopen /usr/lib/libc.a(nss_deffinder.o) +\endverbatim + +Manually adding `-Bdynamic` after the target rule in +`Makefile.doxygen` will fix this: + + $(TARGET): $(OBJECTS) $(OBJMOC) + $(LINK) $(LFLAGS) -o $(TARGET) $(OBJECTS) $(OBJMOC) $(LIBS) -Bdynamic + +<b>GCC compiler problems</b> + +Older versions of the GNU compiler have problems with constant strings +containing characters with character codes larger than 127. Therefore +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. + +Gcc versions before 2.95 may produce broken binaries due to bugs in +these compilers. + +<b>Dot problems</b> + +Due to a change in the way image maps are generated, older versions +of doxygen (\<=1.2.17) will not work correctly with newer versions of +graphviz (\>=1.8.8). The effect of this incompatibility is that +generated graphs in HTML are not properly clickable. For doxygen 1.3 +it is recommended to use at least graphviz 1.8.10 or higher. +For doxygen 1.4.7 or higher it is recommended to +use GraphViz 2.8 or higher to avoid font issues. + +<b>Red Hat 9.0 problems</b> + +If you get the following error after running make +\verbatim +tmake error: qtools.pro:70: Syntax error +\endverbatim +then first type +\verbatim +export LANG= +\endverbatim +before running make. + +\section install_src_windows Compiling from source on Windows + +From version 1.7.0 onwards, build files are provided for Visual Studio 2008. +Also the free (as in beer) "Express" version of Developer Studio can be used to +compile doxygen. Alternatively, you can compile doxygen +\ref install_src_unix "the UNIX way" using +<a href="http://en.wikipedia.org/wiki/Cygwin">Cygwin</a> +or <a href="http://www.mingw.org/">MinGW</a>. + +The next step is to install unxutils (see http://sourceforge.net/projects/unxutils). +This packages contains the tools \c flex and \c bison which are needed during the +compilation process if you use a CVS snapshot of doxygen (the official source releases +come with pre-generated sources). +Download the zip extract it to e.g. <code>c:\\tools\\unxutils</code>. + +Now you need to add/adjust the following environment variables +(via Control Panel/System/Advanced/Environment Variables): +- add <code>c:\\tools\\unxutils\\usr\\local\\wbin;</code> to the start of <code>PATH</code> +- set <code>BISON_SIMPLE</code> to <code>c:\\tools\\unxutils\\usr\\local\\share\\bison.simple</code> + +Download doxygen's source tarball and put it somewhere (e.g. use <code>c:\\tools</code>) + +Now start a new command shell and type +\verbatim +cd c:\tools +gunzip doxygen-x.y.z.src.tar.gz +tar xvf doxygen-x.y.z.src.tar +\endverbatim +to unpack the sources. + +Now your environment is setup to build \c doxygen. + +Inside the \c doxygen-x.y.z directory you will find a \c winbuild directory +containing a \c Doxygen.sln file. Open this file in Visual Studio. +You can now build the Release or Debug flavor of Doxygen by right-clicking +the project in the solutions explorer, and selecting Build. + +Note that compiling Doxywizard currently requires Qt version 4 +(see http://qt.nokia.com/products/platform/qt-for-windows). + +Also read the next section for additional tools you may need to install to run +doxygen with certain features enabled. + +<!-- + +Currently, I have only compiled doxygen for Windows using Microsoft's +Visual C++ (). For other compilers you may need to edit the +perl script in <code>wintools/make.pl</code> a bit. +Let me know what you had to change if you got Doxygen working with another +compiler. If you have Visual Studio you can also use the .dsw file found in +the <code>wintools</code> directory. Note that this file is not maintained +by me, so it might be outdated a little. + +If you have Visual C++ 6.0, and the source distribution, you can easily +build doxygen using the project files in the \c wintools directory. If +you want to build the CVS sources, or want to build from the command line, +or with another compiler, you have to follow the steps below. + +Thomas Baust reported that if you have Visual Studio.NET (2003) then +you should be aware that there is a problem with the _popen() and _pclose() +implementation, which currently leaks handles, so if you build doxygen with +it and use the INPUT_FILTER, you will run to risk of crashing Windows! +The problem is reported to and confirmed by Microsoft so maybe it will +fixed in the next service pack. + +Since Windows comes without all the nice tools that UNIX users are +used to, you'll need to install a number of these tools before you can compile +doxygen for Windows from the command-line. + +Here is what is required: +<ul> +<li>An unzip/untar tool like WinZip to unpack the tar source distribution. + This can be found at http://www.winzip.com/ + + The good, tested, and free alternative is the <code>tar</code> utility + supplied with <a href="http://sourceware.cygnus.com/cygwin/">cygwin + tools</a>. Anyway, the cygwin's flex, bison, and sed are also + recommended below. + +<li>Microsoft Visual C++ (I only tested with version 6.0). + Use the <code>vcvars32.bat</code> batch file to set the environment + variables (if you did not select to do this automatically during + installation). + + 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/ + +<li>The GNU tools flex, bison, and sed. + To get these working on Windows you should install the + <a href="http://sources.redhat.com/cygwin/">cygwin tools</a> + + Alternatively, you can also choose to + download only a <a href="http://www.doxygen.org/dl/cygwin_tools.zip">small subset</a> + of the cygwin tools that I put together just to compile doxygen. + + As a third alternative one could use the GNUWin32 tools that can be + found at http://gnuwin32.sourceforge.net/ + + Make sure the <code>BISON_SIMPLE</code> environment variable points to the + location where the files <code>bison.simple</code> and + is located. For instance if these file is in + <code>c:\\tools\\cygwin\\usr\\share</code> then BISON_SIMPLE should + be set to <code>c:/tools/cygwin/usr/share/bison.simple</code> + + Also make sure the tools are available from a dos box, by adding + the directory they are in to the search path. + + For those of you who are very new to cygwin (if you are going to + install it from scratch), you should notice that there is an + archive file <code>bootstrap.zip</code> which also contains the + <code>tar</code> utility (<code>tar.exe</code>), <code>gzip</code> + utilities, and the <code>cygwin1.dll</code> core. This also means + that you have the <code>tar</code> in hands from the start. It + can be used to unpack the tar source distribution instead of + using WinZip -- as mentioned at the beginning of this list of + steps. + +<li>From Doxygen-1.2.2-20001015 onwards, the distribution includes the part + of Qt that is needed for to compile doxygen. + The Windows specific part were also created. + As a result doxygen (without the wizard) can be compiled on systems + without X11 or (the commerical version of) Qt. + +<li>If you used WinZip to extract the tar archive it will (apparently) not + create empty folders, so you have to add the folders + <code>objects</code> and <code>bin</code> manually in the root of the + distribution before compiling. + +</ul> + + +Compilation is now done by performing the following steps: + +<ol> +<li>Open a dos box. + Make sure all tools (i.e. <code>nmake</code>, <code>latex</code>, + <code>gswin32</code>, <code>dvips</code>, <code>sed</code>, + <code>flex</code>, <code>bison</code>, <code>cl</code>, + <code>rm</code>, and <code>perl</code>), are accessible from + the command-line (add them to the PATH environment variable if + needed). + + Notice: The use of LaTeX is optional and only needed for compilation + of the documentation into PostScript or PDF. + It is \e not needed for compiling the doxygen's binaries. + +<li>Go to the doxygen root dir and type: + +\verbatim + make.bat msvc +\endverbatim + + This should build the executable + <code>doxygen.exe</code> using Microsoft's Visual C++ compiler + (The compiler should not produce any serious warnings or errors). + + You can use also the <code>bcc</code> argument to build + executables using the Borland C++ compiler, or + <code>mingw</code> argument to compile using GNU gcc. + +<li>To build the examples, go to the <code>examples</code> subdirectory + and type: + +\verbatim + nmake +\endverbatim + +<li>To generate the doxygen documentation, go to the <code>doc</code> + subdirectory and type: + +\verbatim + nmake +\endverbatim + + The generated HTML docs are located in the <code>..\\html</code> + subdirectory. + + The sources for LaTeX documentation are located in the <code>..\\latex</code> + subdirectory. From those sources, the DVI, PostScript, and PDF + documentation can be generated. +</ol> + +--> + +\section install_bin_windows Installing the binaries on Windows + +Doxygen comes as a self-installing archive, so installation is extremely simple. +Just follow the dialogs. + +After installation it is recommended to also download and install GraphViz +(version 2.20 or better is highly recommended). Doxygen can use the \c dot tool +of the GraphViz package to render nicer diagrams, see the +\ref cfg_have_dot "HAVE_DOT" option in the configuration file. + +If you want to produce compressed HTML files (see \ref +cfg_generate_htmlhelp "GENERATE_HTMLHELP") in the config file, then +you need the Microsoft HTML help workshop. +You can download it from +<a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/htmlhelp/html/vsconHH1Start.asp">Microsoft</a>. + +If you want to produce Qt Compressed Help files (see \ref +cfg_qhg_location "QHG_LOCATION") in the config file, then +you need qhelpgenerator which is part of Qt. +You can download Qt from <a href="http://trolltech.com/downloads/">Qt Software Downloads</a>. + +In order to generate PDF output or use scientific formulas you will also need to +install <a href="http://en.wikipedia.org/wiki/LaTeX">LaTeX</a> and +<a href="http://en.wikipedia.org/wiki/Ghostscript">Ghostscript</a>. + +For LaTeX a number of distributions exists. Popular ones that should work with +doxygen are <a href="http://www.miktex.org">MikTex</a> +and <a href="http://www.xemtex.org">XemTex</a>. + +Ghostscript can be <a href="http://sourceforge.net/projects/ghostscript/">downloaded</a> +from Sourceforge. + +After installing LaTeX and Ghostscript you'll need to make sure the tools +latex.exe, pdflatex.exe, and gswin32c.exe are present in the search path of a +command box. Follow <a href="http://www.computerhope.com/issues/ch000549.htm">these</a> +instructions if you are unsure and run the commands from a command box to verify it works. + +<!-- +There is no fancy installation procedure at the moment (if anyone can +add it in a location independent way please let me know). + +To install doxygen, just copy the binaries from the <code>bin</code> directory +to a location somewhere in the path. Alternatively, you can include +the <code>bin</code> directory of the distribution to the path. + +There are a couple of tools you may want to install to use all of doxygen's +features: + +<ul> +<li>To generate LaTeX documentation or formulas in HTML you need the tools: + <code>latex</code>, <code>dvips</code> and <code>gswin32</code>. + To get these working under Windows + install the fpTeX distribution. You can find more info at: + http://www.fptex.org/ and download it from CTAN or one of its mirrors. + In the Netherlands for example this would be: + ftp://ftp.easynet.nl/mirror/CTAN/systems/win32/fptex/ + + Make sure the tools are available from a dos box, by adding the + directory they are in to the search path. + + For your information, the LaTeX is freely available set of so + called macros and styles on the top of the famous TeX program + (by famous Donald Knuth) and the accompanied utilities (all + available for free). It is used for high quality + typesetting. The result -- in the form of so called + <code>DVI</code> (DeVice Independent) file -- can be printed or + displayed on various devices preserving exactly the same look up + to the capability of the device. The <code>dvips</code> allows you + to convert the <code>dvi</code> to the high quality PostScript + (i.e. PostScript that can be processed by utilities like + <code>psnup</code>, <code>psbook</code>, <code>psselect</code>, + and others). The derived version of TeX (the pdfTeX) can be used + to produce PDF output instead of DVI, or the PDF can be produced + from PostScript using the utility <code>ps2pdf</code>. + + If you want to use MikTeX then you need to select at least the + medium size installation. For really old versions of MikTex or minimal + installations, you may need to download the fancyhdr package separately. + You can find it in the + <a href="ftp://ftp.tex.ac.uk/tex-archive/macros/latex/contrib/supported/fancyhdr/"> + contrib/supported</a> directory of the tex archives. + +<li>If you want to generate compressed HTML help + (see \ref cfg_generate_htmlhelp "GENERATE_HTMLHELP") in the + config file, then you need the Microsoft HTML help workshop. + You can download it from + <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/htmlhelp/html/vsconHH1Start.asp">Microsoft</a>. + +<li>If you want to produce Qt Compressed Help files (see \ref + cfg_qhelgenerator_loc "QHG_LOCATION") in the config file, + then you need qhelpgenerator which is part of Qt. + You can download Qt from + <a href="http://trolltech.com/downloads/">Qt Software Downloads</a>. + +<li><a href="http://www.graphviz.org/"> + the Graph visualization toolkit version 1.8.10</a><br> + Needed for the include dependency graphs, the graphical inheritance graphs, + and the collaboration graphs. +</ul> + +--> + +\section build_tools Tools used to develop doxygen + +Doxygen was developed and tested under Linux & MacOSX using the following +open-source tools: +<ul> +<li>GCC version 3.3.6 (Linux) and 4.0.1 (MacOSX) +<li>GNU flex version 2.5.33 (Linux) and 2.5.4 (MacOSX) +<li>GNU bison version 1.75 +<li>GNU make version 3.80 +<li>Perl version 5.8.1 +<li>VIM version 6.2 +<li>Firefox 1.5 +<li>Trolltech's tmake version 1.3 (included in the distribution) +<li>teTeX version 2.0.2 +<li>CVS 1.12.12 +</ul> + +\htmlonly +Go to the <a href="starting.html">next</a> section or return to the + <a href="index.html">index</a>. +\endhtmlonly + +*/ + diff --git a/trunk/doc/install_prefix b/trunk/doc/install_prefix new file mode 100644 index 0000000..681eca9 --- /dev/null +++ b/trunk/doc/install_prefix @@ -0,0 +1,2 @@ +VERSION = $(VERSION) + diff --git a/trunk/doc/language.doc b/trunk/doc/language.doc new file mode 100644 index 0000000..7fa38e4 --- /dev/null +++ b/trunk/doc/language.doc @@ -0,0 +1,747 @@ +/****************************************************************************** + * Do not edit this file. It was generated by the translator.py script. + * + * Copyright (C) 1997-2011 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. + * + * $Id$ + */ +/*! \page langhowto Internationalization + +<h3>Support for multiple languages</h3> + +Doxygen has built-in support for multiple languages. This means that the +text fragments, generated by doxygen, can be produced in languages other +than English (the default). The output language is chosen through the +configuration file (with default name and known as Doxyfile). + +Currently (version 1.7.6.1), 39 languages +are supported (sorted alphabetically): +Afrikaans, Arabic, Armenian, Brazilian Portuguese, Catalan, Chinese, +Chinese Traditional, Croatian, Czech, Danish, Dutch, English, +Esperanto, Finnish, French, German, Greek, Hungarian, Indonesian, +Italian, Japanese (+En), Korean (+En), Lithuanian, Macedonian, +Norwegian, Persian, Polish, Portuguese, Romanian, Russian, Serbian, +SerbianCyrilic, Slovak, Slovene, Spanish, Swedish, Turkish, Ukrainian, +and Vietnamese.. + +The table of information related to the supported languages follows. +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. + +\htmlonly +<table align="center" cellspacing="0" cellpadding="0" border="0"> +<tr bgcolor="#000000"> +<td> + <table cellspacing="1" cellpadding="2" border="0"> + <tr bgcolor="#4040c0"> + <td ><b><font size="+1" color="#ffffff"> Language </font></b></td> + <td ><b><font size="+1" color="#ffffff"> Maintainer </font></b></td> + <td ><b><font size="+1" color="#ffffff"> Contact address </font> + <font size="-2" color="#ffffff">(replace the at and dot)</font></b></td> + <td ><b><font size="+1" color="#ffffff"> Status </font></b></td> + </tr> + <!-- table content begin --> + + <tr bgcolor="#ffffff"> + <td>Afrikaans</td> + <td>Johan Prinsloo</td> + <td>johan at zippysnoek dot com</td> + <td>1.6.0</td> + </tr> + <tr bgcolor="#ffffff"> + <td>Arabic</td> + <td>Moaz Reyad<br/><span style="color: red; background-color: yellow">-- searching for the maintainer --</span></td> + <td><span style="color: brown">[resigned]</span><br/><span style="color: brown">[Please, try to help to find someone.]</span></td> + <td>1.4.6</td> + </tr> + <tr bgcolor="#ffffff"> + <td>Armenian</td> + <td>Armen Tangamyan</td> + <td>armen dot tangamyan at anu dot edu dot au</td> + <td>up-to-date</td> + </tr> + <tr bgcolor="#ffffff"> + <td>Brazilian Portuguese</td> + <td>Fabio "FJTC" Jun Takada Chino</td> + <td>jun-chino at uol dot com dot br</td> + <td>up-to-date</td> + </tr> + <tr bgcolor="#ffffff"> + <td>Catalan</td> + <td>Maximiliano Pin<br/>Albert Mora</td> + <td>max dot pin at bitroit dot com<br/><span style="color: brown">[unreachable]</span></td> + <td>up-to-date</td> + </tr> + <tr bgcolor="#ffffff"> + <td>Chinese</td> + <td>Lian Yang<br/>Li Daobing<br/>Wei Liu</td> + <td>lian dot yang dot cn at gmail dot com<br/>lidaobing at gmail dot com<br/>liuwei at asiainfo dot com</td> + <td>up-to-date</td> + </tr> + <tr bgcolor="#ffffff"> + <td>Chinese Traditional</td> + <td>Daniel YC Lin<br/>Gary Lee</td> + <td>dlin dot tw at gmail dot com<br/>garywlee at gmail dot com</td> + <td>up-to-date</td> + </tr> + <tr bgcolor="#ffffff"> + <td>Croatian</td> + <td>Boris Bralo</td> + <td>boris dot bralo at gmail dot com</td> + <td>up-to-date</td> + </tr> + <tr bgcolor="#ffffff"> + <td>Czech</td> + <td>Petr Přikryl</td> + <td>prikrylp at skil dot cz</td> + <td>up-to-date</td> + </tr> + <tr bgcolor="#ffffff"> + <td>Danish</td> + <td>Poul-Erik Hansen<br/>Erik Søe Sørensen</td> + <td>pouhan at gnotometrics dot dk<br/>eriksoe+doxygen at daimi dot au dot dk</td> + <td>up-to-date</td> + </tr> + <tr bgcolor="#ffffff"> + <td>Dutch</td> + <td>Dimitri van Heesch</td> + <td>dimitri at stack dot nl</td> + <td>up-to-date</td> + </tr> + <tr bgcolor="#ffffff"> + <td>English</td> + <td>Dimitri van Heesch</td> + <td>dimitri at stack dot nl</td> + <td>up-to-date</td> + </tr> + <tr bgcolor="#ffffff"> + <td>Esperanto</td> + <td>Ander Martinez</td> + <td>dwarfnauko at gmail dot com</td> + <td>1.7.5</td> + </tr> + <tr bgcolor="#ffffff"> + <td>Finnish</td> + <td>Antti Laine</td> + <td>antti dot a dot laine at tut dot fi</td> + <td>1.6.0</td> + </tr> + <tr bgcolor="#ffffff"> + <td>French</td> + <td>David Martinet<br/>Xavier Outhier</td> + <td>contact at e-concept-applications dot fr<br/>xouthier at yahoo dot fr</td> + <td>up-to-date</td> + </tr> + <tr bgcolor="#ffffff"> + <td>German</td> + <td>Peter Grotrian<br/>Jens Seidel</td> + <td>Peter dot Grotrian at pdv-FS dot de<br/>jensseidel at users dot sf dot net</td> + <td>up-to-date</td> + </tr> + <tr bgcolor="#ffffff"> + <td>Greek</td> + <td>Paul Gessos</td> + <td>gessos dot paul at yahoo dot gr</td> + <td>up-to-date</td> + </tr> + <tr bgcolor="#ffffff"> + <td>Hungarian</td> + <td>Ákos Kiss<br/>Földvári György</td> + <td>akiss at users dot sourceforge dot net<br/><span style="color: brown">[unreachable]</span></td> + <td>1.4.6</td> + </tr> + <tr bgcolor="#ffffff"> + <td>Indonesian</td> + <td>Hendy Irawan</td> + <td>ceefour at gauldong dot net</td> + <td>up-to-date</td> + </tr> + <tr bgcolor="#ffffff"> + <td>Italian</td> + <td>Alessandro Falappa<br/>Ahmed Aldo Faisal</td> + <td>alessandro at falappa dot net<br/>aaf23 at cam dot ac dot uk</td> + <td>1.7.5</td> + </tr> + <tr bgcolor="#ffffff"> + <td>Japanese</td> + <td>Hiroki Iseri<br/>Ryunosuke Satoh<br/>Kenji Nagamatsu<br/>Iwasa Kazmi</td> + <td>goyoki at gmail dot com<br/>sun594 at hotmail dot com<br/>naga at joyful dot club dot ne dot jp<br/><span style="color: brown">[unreachable]</span></td> + <td>1.6.0</td> + </tr> + <tr bgcolor="#ffffff"> + <td>JapaneseEn</td> + <td>see the Japanese language</td> + <td> </td> + <td>English based</td> + </tr> + <tr bgcolor="#ffffff"> + <td>Korean</td> + <td>Kim Taedong<br/>SooYoung Jung<br/>Richard Kim</td> + <td>fly1004 at gmail dot com<br/>jung5000 at gmail dot com<br/><span style="color: brown">[unreachable]</span></td> + <td>1.7.5</td> + </tr> + <tr bgcolor="#ffffff"> + <td>KoreanEn</td> + <td>see the Korean language</td> + <td> </td> + <td>English based</td> + </tr> + <tr bgcolor="#ffffff"> + <td>Lithuanian</td> + <td>Tomas Simonaitis<br/>Mindaugas Radzius<br/>Aidas Berukstis<br/><span style="color: red; background-color: yellow">-- searching for the maintainer --</span></td> + <td><span style="color: brown">[unreachable]</span><br/><span style="color: brown">[unreachable]</span><br/><span style="color: brown">[unreachable]</span><br/><span style="color: brown">[Please, try to help to find someone.]</span></td> + <td>1.4.6</td> + </tr> + <tr bgcolor="#ffffff"> + <td>Macedonian</td> + <td>Slave Jovanovski</td> + <td>slavejovanovski at yahoo dot com</td> + <td>1.6.0</td> + </tr> + <tr bgcolor="#ffffff"> + <td>Norwegian</td> + <td>Lars Erik Jordet</td> + <td>lejordet at gmail dot com</td> + <td>1.4.6</td> + </tr> + <tr bgcolor="#ffffff"> + <td>Persian</td> + <td>Ali Nadalizadeh</td> + <td>nadalizadeh at gmail dot com</td> + <td>1.7.5</td> + </tr> + <tr bgcolor="#ffffff"> + <td>Polish</td> + <td>Piotr Kaminski<br/>Grzegorz Kowal<br/>Krzysztof Kral</td> + <td><span style="color: brown">[unreachable]</span><br/><span style="color: brown">[unreachable]</span><br/>krzysztof dot kral at gmail dot com</td> + <td>1.6.3</td> + </tr> + <tr bgcolor="#ffffff"> + <td>Portuguese</td> + <td>Rui Godinho Lopes<br/><span style="color: red; background-color: yellow">-- searching for the maintainer --</span></td> + <td><span style="color: brown">[resigned]</span><br/><span style="color: brown">[Please, try to help to find someone.]</span></td> + <td>up-to-date</td> + </tr> + <tr bgcolor="#ffffff"> + <td>Romanian</td> + <td>Ionut Dumitrascu<br/>Alexandru Iosup</td> + <td>reddumy at yahoo dot com<br/>aiosup at yahoo dot com</td> + <td>1.6.0</td> + </tr> + <tr bgcolor="#ffffff"> + <td>Russian</td> + <td>Alexandr Chelpanov</td> + <td>cav at cryptopro dot ru</td> + <td>1.7.5</td> + </tr> + <tr bgcolor="#ffffff"> + <td>Serbian</td> + <td>Dejan Milosavljevic</td> + <td><span style="color: brown">[unreachable]</span></td> + <td>1.6.0</td> + </tr> + <tr bgcolor="#ffffff"> + <td>SerbianCyrilic</td> + <td>Nedeljko Stefanovic</td> + <td>stenedjo at yahoo dot com</td> + <td>1.6.0</td> + </tr> + <tr bgcolor="#ffffff"> + <td>Slovak</td> + <td>Kali+Laco Švec<br/>Petr Přikryl</td> + <td>the Slovak language advisors<br/>prikrylp at skil dot cz</td> + <td>up-to-date</td> + </tr> + <tr bgcolor="#ffffff"> + <td>Slovene</td> + <td>Matjaž Ostroveršnik</td> + <td>matjaz dot ostroversnik at ostri dot org</td> + <td>1.4.6</td> + </tr> + <tr bgcolor="#ffffff"> + <td>Spanish</td> + <td>Bartomeu<br/>Francisco Oltra Thennet<br/>David Vaquero</td> + <td>bartomeu at loteria3cornella dot com<br/><span style="color: brown">[unreachable]</span><br/>david at grupoikusnet dot com</td> + <td>1.7.5</td> + </tr> + <tr bgcolor="#ffffff"> + <td>Swedish</td> + <td>Mikael Hallin</td> + <td>mikaelhallin at yahoo dot se</td> + <td>1.6.0</td> + </tr> + <tr bgcolor="#ffffff"> + <td>Turkish</td> + <td>Emin Ilker Cetinbas</td> + <td>niw3 at yahoo dot com</td> + <td>1.7.5</td> + </tr> + <tr bgcolor="#ffffff"> + <td>Ukrainian</td> + <td>Olexij Tkatchenko<br/><span style="color: red; background-color: yellow">-- searching for the maintainer --</span></td> + <td><span style="color: brown">[resigned]</span><br/><span style="color: brown">[Please, try to help to find someone.]</span></td> + <td>1.4.1</td> + </tr> + <tr bgcolor="#ffffff"> + <td>Vietnamese</td> + <td>Dang Minh Tuan</td> + <td>tuanvietkey at gmail dot com</td> + <td>1.6.0</td> + </tr> + <!-- table content end --> + </table> +</td> +</tr> +</table> +\endhtmlonly + + +\latexonly +\footnotesize +\begin{longtable}{|l|l|l|l|} + \hline + {\bf Language} & {\bf Maintainer} & {\bf Contact address} & {\bf Status} \\ + \hline + + \hline + Afrikaans & Johan Prinsloo & {\tt\tiny johan at zippysnoek dot com} & 1.6.0 \\ + \hline + Arabic & Moaz Reyad & {\tt\tiny [resigned] moazreyad at yahoo dot com} & 1.4.6 \\ + ~ & -- searching for the maintainer -- & {\tt\tiny [Please, try to help to find someone.]} & ~ \\ + \hline + Armenian & Armen Tangamyan & {\tt\tiny armen dot tangamyan at anu dot edu dot au} & up-to-date \\ + \hline + Brazilian Portuguese & Fabio "FJTC" Jun Takada Chino & {\tt\tiny jun-chino at uol dot com dot br} & up-to-date \\ + \hline + Catalan & Maximiliano Pin & {\tt\tiny max dot pin at bitroit dot com} & up-to-date \\ + ~ & Albert Mora & {\tt\tiny [unreachable] amora at iua dot upf dot es} & ~ \\ + \hline + Chinese & Lian Yang & {\tt\tiny lian dot yang dot cn at gmail dot com} & up-to-date \\ + ~ & Li Daobing & {\tt\tiny lidaobing at gmail dot com} & ~ \\ + ~ & Wei Liu & {\tt\tiny liuwei at asiainfo dot com} & ~ \\ + \hline + Chinese Traditional & Daniel YC Lin & {\tt\tiny dlin dot tw at gmail dot com} & up-to-date \\ + ~ & Gary Lee & {\tt\tiny garywlee at gmail dot com} & ~ \\ + \hline + Croatian & Boris Bralo & {\tt\tiny boris dot bralo at gmail dot com} & up-to-date \\ + \hline + Czech & Petr Přikryl & {\tt\tiny prikrylp at skil dot cz} & up-to-date \\ + \hline + Danish & Poul-Erik Hansen & {\tt\tiny pouhan at gnotometrics dot dk} & up-to-date \\ + ~ & Erik Søe Sørensen & {\tt\tiny eriksoe+doxygen at daimi dot au dot dk} & ~ \\ + \hline + Dutch & Dimitri van Heesch & {\tt\tiny dimitri at stack dot nl} & up-to-date \\ + \hline + English & Dimitri van Heesch & {\tt\tiny dimitri at stack dot nl} & up-to-date \\ + \hline + Esperanto & Ander Martinez & {\tt\tiny dwarfnauko at gmail dot com} & 1.7.5 \\ + \hline + Finnish & Antti Laine & {\tt\tiny antti dot a dot laine at tut dot fi} & 1.6.0 \\ + \hline + French & David Martinet & {\tt\tiny contact at e-concept-applications dot fr} & up-to-date \\ + ~ & Xavier Outhier & {\tt\tiny xouthier at yahoo dot fr} & ~ \\ + \hline + German & Peter Grotrian & {\tt\tiny Peter dot Grotrian at pdv-FS dot de} & up-to-date \\ + ~ & Jens Seidel & {\tt\tiny jensseidel at users dot sf dot net} & ~ \\ + \hline + Greek & Paul Gessos & {\tt\tiny gessos dot paul at yahoo dot gr} & up-to-date \\ + \hline + Hungarian & Ákos Kiss & {\tt\tiny akiss at users dot sourceforge dot net} & 1.4.6 \\ + ~ & Földvári György & {\tt\tiny [unreachable] foldvari lost at cyberspace} & ~ \\ + \hline + Indonesian & Hendy Irawan & {\tt\tiny ceefour at gauldong dot net} & up-to-date \\ + \hline + Italian & Alessandro Falappa & {\tt\tiny alessandro at falappa dot net} & 1.7.5 \\ + ~ & Ahmed Aldo Faisal & {\tt\tiny aaf23 at cam dot ac dot uk} & ~ \\ + \hline + Japanese & Hiroki Iseri & {\tt\tiny goyoki at gmail dot com} & 1.6.0 \\ + ~ & Ryunosuke Satoh & {\tt\tiny sun594 at hotmail dot com} & ~ \\ + ~ & Kenji Nagamatsu & {\tt\tiny naga at joyful dot club dot ne dot jp} & ~ \\ + ~ & Iwasa Kazmi & {\tt\tiny [unreachable] iwasa at cosmo-system dot jp} & ~ \\ + \hline + JapaneseEn & see the Japanese language & {\tt\tiny ~} & English based \\ + \hline + Korean & Kim Taedong & {\tt\tiny fly1004 at gmail dot com} & 1.7.5 \\ + ~ & SooYoung Jung & {\tt\tiny jung5000 at gmail dot com} & ~ \\ + ~ & Richard Kim & {\tt\tiny [unreachable] ryk at dspwiz dot com} & ~ \\ + \hline + KoreanEn & see the Korean language & {\tt\tiny ~} & English based \\ + \hline + Lithuanian & Tomas Simonaitis & {\tt\tiny [unreachable] haden at homelan dot lt} & 1.4.6 \\ + ~ & Mindaugas Radzius & {\tt\tiny [unreachable] mindaugasradzius at takas dot lt} & ~ \\ + ~ & Aidas Berukstis & {\tt\tiny [unreachable] aidasber at takas dot lt} & ~ \\ + ~ & -- searching for the maintainer -- & {\tt\tiny [Please, try to help to find someone.]} & ~ \\ + \hline + Macedonian & Slave Jovanovski & {\tt\tiny slavejovanovski at yahoo dot com} & 1.6.0 \\ + \hline + Norwegian & Lars Erik Jordet & {\tt\tiny lejordet at gmail dot com} & 1.4.6 \\ + \hline + Persian & Ali Nadalizadeh & {\tt\tiny nadalizadeh at gmail dot com} & 1.7.5 \\ + \hline + Polish & Piotr Kaminski & {\tt\tiny [unreachable] Piotr dot Kaminski at ctm dot gdynia dot pl} & 1.6.3 \\ + ~ & Grzegorz Kowal & {\tt\tiny [unreachable] g\_kowal at poczta dot onet dot pl} & ~ \\ + ~ & Krzysztof Kral & {\tt\tiny krzysztof dot kral at gmail dot com} & ~ \\ + \hline + Portuguese & Rui Godinho Lopes & {\tt\tiny [resigned] rgl at ruilopes dot com} & up-to-date \\ + ~ & -- searching for the maintainer -- & {\tt\tiny [Please, try to help to find someone.]} & ~ \\ + \hline + Romanian & Ionut Dumitrascu & {\tt\tiny reddumy at yahoo dot com} & 1.6.0 \\ + ~ & Alexandru Iosup & {\tt\tiny aiosup at yahoo dot com} & ~ \\ + \hline + Russian & Alexandr Chelpanov & {\tt\tiny cav at cryptopro dot ru} & 1.7.5 \\ + \hline + Serbian & Dejan Milosavljevic & {\tt\tiny [unreachable] dmilos at email dot com} & 1.6.0 \\ + \hline + SerbianCyrilic & Nedeljko Stefanovic & {\tt\tiny stenedjo at yahoo dot com} & 1.6.0 \\ + \hline + Slovak & Kali+Laco Švec & {\tt\tiny the Slovak language advisors} & up-to-date \\ + ~ & Petr Přikryl & {\tt\tiny prikrylp at skil dot cz} & ~ \\ + \hline + Slovene & Matjaž Ostroveršnik & {\tt\tiny matjaz dot ostroversnik at ostri dot org} & 1.4.6 \\ + \hline + Spanish & Bartomeu & {\tt\tiny bartomeu at loteria3cornella dot com} & 1.7.5 \\ + ~ & Francisco Oltra Thennet & {\tt\tiny [unreachable] foltra at puc dot cl} & ~ \\ + ~ & David Vaquero & {\tt\tiny david at grupoikusnet dot com} & ~ \\ + \hline + Swedish & Mikael Hallin & {\tt\tiny mikaelhallin at yahoo dot se} & 1.6.0 \\ + \hline + Turkish & Emin Ilker Cetinbas & {\tt\tiny niw3 at yahoo dot com} & 1.7.5 \\ + \hline + Ukrainian & Olexij Tkatchenko & {\tt\tiny [resigned] olexij at tkatchenko dot com} & 1.4.1 \\ + ~ & -- searching for the maintainer -- & {\tt\tiny [Please, try to help to find someone.]} & ~ \\ + \hline + Vietnamese & Dang Minh Tuan & {\tt\tiny tuanvietkey at gmail dot com} & 1.6.0 \\ + \hline +\end{longtable} +\normalsize +\endlatexonly + + +Most people on the list have indicated that they were also busy +doing other things, so if you want to help to speed things up please +let them (or me) know. + +If you want to add support for a language that is not yet listed +please read the next section. + + +<h3>Adding a new language to doxygen</h3> + +This short HOWTO explains how to add support for the new language to Doxygen: + +Just follow these steps: +<ol> +<li>Tell me for which language you want to add support. If no one else + 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_country_code\>.h + I'll use xx in the rest of this document. +<li>Add definition of the symbol for your language in the configure +at two places in the script: + <ol> + <li>After the <code>f_langs=</code> is statement, in lower case. + <li>In the string that following <code>\@allowed=</code> in upper case. + </ol> +The rerun the configure script such that is generates src/lang_cfg.h. +This file should now contain a \#define for your language code. +<li>Edit language.cpp: + Add a +\verbatim +#ifdef LANG_xx +#include<translator_xx.h> +#endif +\endverbatim + Remember to use the same symbol LANG_xx that you added to \c lang_cfg.h. + I.e., the \c xx should be capital letters that identify your language. + On the other hand, the \c xx inside your \c translator_xx.h should use + lower case. + <p>Now, in <code>setTranslator()</code> add +\verbatim +#ifdef LANG_xx + else if (L_EQUAL("your_language_name")) + { + theTranslator = new TranslatorYourLanguage; + } +#endif +\endverbatim + after the <code>if { ... }</code>. I.e., it must be placed after the code + for creating the English translator at the beginning, and before the + <code>else { ... }</code> part that creates the translator for the + default language (English again). +<li>Edit libdoxygen.pro.in and add \c translator_xx.h to + the \c HEADERS line. +<li>Edit <code>translator_xx.h</code>: + <ul> + <li>Rename <code>TRANSLATOR_EN_H</code> to <code>TRANSLATOR_XX_H</code> + twice (i.e. in the \c \#ifndef and \c \#define preprocessor commands at + the beginning of the file). + <li>Rename TranslatorEnglish to TranslatorYourLanguage + <li>In the member <code>idLanguage()</code> change "english" into the + name of your language (use lower case characters only). Depending + on the language you may also wish to change the member functions + 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! + To enter special characters (with accents) you can: + <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 \f$\mbox{\LaTeX}\f$ 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. ä). + See the HTML specification for the codes. + </ul> + </ul> +<li>Run configure and make again from the root of the distribution, + in order to regenerated the Makefiles. +<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> + +New versions of doxygen may use new translated sentences. In such +situation, the \c Translator class requires implementation of new +methods -- its interface changes. Of course, the English +sentences need to be translated to the other languages. At least, +new methods have to be implemented by the language-related +translator class; 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 official 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 name of the adapter class is +chosen so that its suffix is derived from the previous official +version of doxygen that did not need the adapter. This way, one can +say approximately, when the language translator class was last +updated -- see details below. + +The newest translator adapter derives from the abstract \c +TranslatorAdapterBase class that derives directly from the abstract +\c Translator class. It adds only the private English-translator +member for easy implementation of the default translation inside the +adapter classes, and it also enforces implementation of one method +for noticing the user that the language translation is not up-to-date +(because of that some sentences in the generated files may appear in +English). + +Once the oldest adapter class is not used by any of the language +translators, it can be removed from the doxygen project. 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.py Python +script was developed (located in \c doxygen/doc directory). +It extracts the important information about obsolete and +new methods from the source files for each of the languages. +The information is stored in the <em>translator report</em> ASCII file +(translator_report.txt). + +\htmlonly If you compiled this documentation +from sources and if you have also doxygen sources available the +link <a href="../doc/translator_report.txt" +><code>doxygen/doc/translator_report.txt</code></a> should be valid.\endhtmlonly + +Looking at the base class of the language translator, the script +guesses also the status of the translator -- see the last column of +the table with languages above. The \c translator.py is called +automatically when the doxygen documentation is generated. You can +also run the script manually 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). + +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>). + +If everything compiles fine, try to run \c translator.py, 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 source 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.py again). Also, you will be informed when you forgot to +change the base class of your translator class to some newer adapter +class or directly to the Translator class. + +<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. + +<b>If you prefer to update your translator gradually</b>, have a look +at \c TranslatorEnglish (the \c translator_en.h file). Inside, you +will find the comments like <code>new since 1.2.4</code> that separate +always a number of methods that were implemented in the stated +version. Do implement the group of methods that are placed below the +comment that uses the same version numbers as your translator adapter +class. (For example, your translator class have to use the \c +TranslatorAdapter_1_2_4, if it does not implement the methods below +the comment <code>new since 1.2.4</code>. When you implement them, +your class should use newer translator adapter. + +Run the \c translator.py script occasionally and give it your \c xx +identification (from \c translator_xx.h) to create the translator +report shorter (also produced faster) -- it will contain only the +information related to your translator. Once you reach the state when +the base class should be changed to some newer adapter, you will see +the note in the translator report. + +Warning: Don't forget to compile Doxygen to discover, whether it is +compilable. The \c translator.py does not check if everything is +correct with respect to the compiler. Because of that, it may lie +sometimes about the necessary base class. + +<b>The most obsolete language translators</b> would lead to +implementation of too complicated adapters. Because of that, doxygen +developers may decide to derive such translators from the \c +TranslatorEnglish class, which is by definition always up-to-date. + +When doing so, all the missing methods will be replaced by the +English translation. This means that not-implemented methods will +always return the English result. Such translators are marked using +word \c obsolete. You should read it <b>really obsolete</b>. No +guess about the last update can be done. + +Often, it is possible to construct better result from the obsolete +methods. Because of that, the translator adapter classes should be +used if possible. On the other hand, implementation of adapters for +really obsolete translators brings too much maintenance and +run-time overhead. + +*/ + diff --git a/trunk/doc/language.tpl b/trunk/doc/language.tpl new file mode 100644 index 0000000..cba8b8a --- /dev/null +++ b/trunk/doc/language.tpl @@ -0,0 +1,357 @@ + +ATTENTION! This is the template for generating language.doc. If you want to +change the language.doc, make the changes here and inside maintainers.txt. + +/****************************************************************************** + * %(editnote)s + * + * Copyright (C) 1997-2011 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. + * + * $Id$ + */ +/*! \page langhowto Internationalization + +<h3>Support for multiple languages</h3> + +Doxygen has built-in support for multiple languages. This means that the +text fragments, generated by doxygen, can be produced in languages other +than English (the default). The output language is chosen through the +configuration file (with default name and known as Doxyfile). + +Currently (version %(doxVersion)s), %(numLangStr)s languages +are supported (sorted alphabetically): +%(supportedLangReadableStr)s. + +The table of information related to the supported languages follows. +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. + +%(informationTable)s + +Most people on the list have indicated that they were also busy +doing other things, so if you want to help to speed things up please +let them (or me) know. + +If you want to add support for a language that is not yet listed +please read the next section. + + +<h3>Adding a new language to doxygen</h3> + +This short HOWTO explains how to add support for the new language to Doxygen: + +Just follow these steps: +<ol> +<li>Tell me for which language you want to add support. If no one else + 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_country_code\>.h + I'll use xx in the rest of this document. +<li>Add definition of the symbol for your language in the configure +at two places in the script: + <ol> + <li>After the <code>f_langs=</code> is statement, in lower case. + <li>In the string that following <code>\@allowed=</code> in upper case. + </ol> +The rerun the configure script such that is generates src/lang_cfg.h. +This file should now contain a \#define for your language code. +<li>Edit language.cpp: + Add a +\verbatim +#ifdef LANG_xx +#include<translator_xx.h> +#endif +\endverbatim + Remember to use the same symbol LANG_xx that you added to \c lang_cfg.h. + I.e., the \c xx should be capital letters that identify your language. + On the other hand, the \c xx inside your \c translator_xx.h should use + lower case. + <p>Now, in <code>setTranslator()</code> add +\verbatim +#ifdef LANG_xx + else if (L_EQUAL("your_language_name")) + { + theTranslator = new TranslatorYourLanguage; + } +#endif +\endverbatim + after the <code>if { ... }</code>. I.e., it must be placed after the code + for creating the English translator at the beginning, and before the + <code>else { ... }</code> part that creates the translator for the + default language (English again). +<li>Edit libdoxygen.pro.in and add \c translator_xx.h to + the \c HEADERS line. +<li>Edit <code>translator_xx.h</code>: + <ul> + <li>Rename <code>TRANSLATOR_EN_H</code> to <code>TRANSLATOR_XX_H</code> + twice (i.e. in the \c \#ifndef and \c \#define preprocessor commands at + the beginning of the file). + <li>Rename TranslatorEnglish to TranslatorYourLanguage + <li>In the member <code>idLanguage()</code> change "english" into the + name of your language (use lower case characters only). Depending + on the language you may also wish to change the member functions + 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! + To enter special characters (with accents) you can: + <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 \f$\mbox{\LaTeX}\f$ 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. ä). + See the HTML specification for the codes. + </ul> + </ul> +<li>Run configure and make again from the root of the distribution, + in order to regenerated the Makefiles. +<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> + +New versions of doxygen may use new translated sentences. In such +situation, the \c Translator class requires implementation of new +methods -- its interface changes. Of course, the English +sentences need to be translated to the other languages. At least, +new methods have to be implemented by the language-related +translator class; 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 official 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 name of the adapter class is +chosen so that its suffix is derived from the previous official +version of doxygen that did not need the adapter. This way, one can +say approximately, when the language translator class was last +updated -- see details below. + +The newest translator adapter derives from the abstract \c +TranslatorAdapterBase class that derives directly from the abstract +\c Translator class. It adds only the private English-translator +member for easy implementation of the default translation inside the +adapter classes, and it also enforces implementation of one method +for noticing the user that the language translation is not up-to-date +(because of that some sentences in the generated files may appear in +English). + +Once the oldest adapter class is not used by any of the language +translators, it can be removed from the doxygen project. 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.py Python +script was developed (located in \c doxygen/doc directory). +It extracts the important information about obsolete and +new methods from the source files for each of the languages. +The information is stored in the <em>translator report</em> ASCII file +(%(translatorReportFileName)s). + +\htmlonly If you compiled this documentation +from sources and if you have also doxygen sources available the +link %(translatorReportLink)s should be valid.\endhtmlonly + +Looking at the base class of the language translator, the script +guesses also the status of the translator -- see the last column of +the table with languages above. The \c translator.py is called +automatically when the doxygen documentation is generated. You can +also run the script manually 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). + +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>). + +If everything compiles fine, try to run \c translator.py, 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 source 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.py again). Also, you will be informed when you forgot to +change the base class of your translator class to some newer adapter +class or directly to the Translator class. + +<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. + +<b>If you prefer to update your translator gradually</b>, have a look +at \c TranslatorEnglish (the \c translator_en.h file). Inside, you +will find the comments like <code>new since 1.2.4</code> that separate +always a number of methods that were implemented in the stated +version. Do implement the group of methods that are placed below the +comment that uses the same version numbers as your translator adapter +class. (For example, your translator class have to use the \c +TranslatorAdapter_1_2_4, if it does not implement the methods below +the comment <code>new since 1.2.4</code>. When you implement them, +your class should use newer translator adapter. + +Run the \c translator.py script occasionally and give it your \c xx +identification (from \c translator_xx.h) to create the translator +report shorter (also produced faster) -- it will contain only the +information related to your translator. Once you reach the state when +the base class should be changed to some newer adapter, you will see +the note in the translator report. + +Warning: Don't forget to compile Doxygen to discover, whether it is +compilable. The \c translator.py does not check if everything is +correct with respect to the compiler. Because of that, it may lie +sometimes about the necessary base class. + +<b>The most obsolete language translators</b> would lead to +implementation of too complicated adapters. Because of that, doxygen +developers may decide to derive such translators from the \c +TranslatorEnglish class, which is by definition always up-to-date. + +When doing so, all the missing methods will be replaced by the +English translation. This means that not-implemented methods will +always return the English result. Such translators are marked using +word \c obsolete. You should read it <b>really obsolete</b>. No +guess about the last update can be done. + +Often, it is possible to construct better result from the obsolete +methods. Because of that, the translator adapter classes should be +used if possible. On the other hand, implementation of adapters for +really obsolete translators brings too much maintenance and +run-time overhead. + +*/ + diff --git a/trunk/doc/lists.doc b/trunk/doc/lists.doc new file mode 100644 index 0000000..89b21e8 --- /dev/null +++ b/trunk/doc/lists.doc @@ -0,0 +1,125 @@ +/*! \page lists Lists + +Doxygen provides a number of ways to create lists of items. + +<b>Using dashes</b> + +By putting a number of column-aligned minus (-) signs at the start of a +line, a bullet list will automatically be generated. Instead of the minus +sign also plus (+) or asterix (\*) can be used. + +Numbered lists can also be generated by using a minus followed by a hash +or by using a number followed by a dot. + +Nesting of lists is allowed and is based on indentation of the items.<p> +Here is an example: + +\verbatim + /*! + * A list of events: + * - mouse events + * -# mouse move event + * -# mouse click event\n + * More info about the click event. + * -# mouse double click event + * - keyboard events + * 1. key down event + * 2. key up event + * + * More text here. + */ +\endverbatim + The result will be: + + A list of events: + - mouse events + -# mouse move event + -# mouse click event\n + More info about the click event. + -# mouse double click event + - keyboard events + 1. key down event + 2. key up event + + More text here. + +If you use tabs for indentation within lists, please make sure +that \ref cfg_tab_size "TAB_SIZE" in the configuration file is set to +the correct tab size. + +You can end a list by starting a new paragraph or +by putting a dot (.) on an empty line at the same indentation level as the +list you would like to end. + +Here is an example that speaks for itself: + +\verbatim +/** + * Text before the list + * - list item 1 + * - sub item 1 + * - sub sub item 1 + * - sub sub item 2 + * . + * The dot above ends the sub sub item list. + * + * More text for the first sub item + * . + * The dot above ends the first sub item. + * + * More text for the first list item + * - sub item 2 + * - sub item 3 + * - list item 2 + * . + * More text in the same paragraph. + * + * More text in a new paragraph. + */ +\endverbatim + +<b>Using HTML commands</b> + +If you like you can also use HTML commands inside the documentation +blocks. + +Here is the above example with HTML commands: +\verbatim + /*! + * A list of events: + * <ul> + * <li> mouse events + * <ol> + * <li>mouse move event + * <li>mouse click event<br> + * More info about the click event. + * <li>mouse double click event + * </ol> + * <li> keyboard events + * <ol> + * <li>key down event + * <li>key up event + * </ol> + * </ul> + * More text here. + */ +\endverbatim + +\note In this case the indentation is not important. + +<b>Using \\arg or \\li</b> + +For compatibility with the Qt Software's internal documentation tool qdoc and +with KDoc, doxygen has two commands that can be used to create simple +unnested lists. + +See \ref cmdarg "\\arg" and \ref cmdli "\\li" for more info. + +\htmlonly +Go to the <a href="grouping.html">next</a> section or return to the + <a href="index.html">index</a>. +\endhtmlonly + +*/ + + diff --git a/trunk/doc/maintainers.txt b/trunk/doc/maintainers.txt new file mode 100644 index 0000000..c3fa112 --- /dev/null +++ b/trunk/doc/maintainers.txt @@ -0,0 +1,161 @@ +% $Id$ +% +% The text is in UTF-8. Comments start with % sign at the beginning. +% There is one record for each language. The records are separated +% by the empty line and they do not contain empty lines. +% First line of the record identifies the translator class for the language. +% The following one or more lines contain information about +% the maintainer(s) for the language (one line, one maintainer) +% in the form: <readable name><colon><e-mail> +% If the readable name name starts with '--' it will be displayed in HTML +% output as a highlighted text notice related to the langluage (usually +% '-- searching for the maintainer --'). +% If the <e-mail> is prefixed [some_text] it is not displayed in the table +% of maintainers in the Doxygen documentation, nor it is used when building +% the mailto.txt by translator.py. The mark is displayed in the documentation +% instead. + +TranslatorAfrikaans +Johan Prinsloo: johan at zippysnoek dot com + +TranslatorArabic +Moaz Reyad: [resigned] moazreyad at yahoo dot com +-- searching for the maintainer --: [Please, try to help to find someone.] + +TranslatorArmenian +Armen Tangamyan: armen dot tangamyan at anu dot edu dot au + +TranslatorBrazilian +Fabio "FJTC" Jun Takada Chino: jun-chino at uol dot com dot br + +TranslatorCatalan +Maximiliano Pin: max dot pin at bitroit dot com +Albert Mora: [unreachable] amora at iua dot upf dot es + +TranslatorChinese +Lian Yang: lian dot yang dot cn at gmail dot com +Li Daobing: lidaobing at gmail dot com +Wei Liu: liuwei at asiainfo dot com + +TranslatorChinesetraditional +Daniel YC Lin: dlin dot tw at gmail dot com +Gary Lee: garywlee at gmail dot com + +TranslatorCroatian +Boris Bralo: boris dot bralo at gmail dot com + +TranslatorCzech +Petr Přikryl: prikrylp at skil dot cz + +TranslatorDanish +Poul-Erik Hansen: pouhan at gnotometrics dot dk +Erik Søe Sørensen: eriksoe+doxygen at daimi dot au dot dk + +TranslatorDutch +Dimitri van Heesch: dimitri at stack dot nl + +TranslatorEnglish +Dimitri van Heesch: dimitri at stack dot nl + +TranslatorEsperanto +Ander Martinez: dwarfnauko at gmail dot com + +TranslatorFinnish +Antti Laine: antti dot a dot laine at tut dot fi + +TranslatorFrench +David Martinet: contact at e-concept-applications dot fr +Xavier Outhier: xouthier at yahoo dot fr + +TranslatorGerman +Peter Grotrian: Peter dot Grotrian at pdv-FS dot de +Jens Seidel: jensseidel at users dot sf dot net + +TranslatorGreek +Paul Gessos: gessos dot paul at yahoo dot gr + +TranslatorHungarian +Ákos Kiss: akiss at users dot sourceforge dot net +Földvári György: [unreachable] foldvari lost at cyberspace + +TranslatorIndonesian +Hendy Irawan: ceefour at gauldong dot net + +TranslatorItalian +Alessandro Falappa: alessandro at falappa dot net +Ahmed Aldo Faisal: aaf23 at cam dot ac dot uk + +TranslatorJapanese +Hiroki Iseri: goyoki at gmail dot com +Ryunosuke Satoh: sun594 at hotmail dot com +Kenji Nagamatsu: naga at joyful dot club dot ne dot jp +Iwasa Kazmi: [unreachable] iwasa at cosmo-system dot jp + +TranslatorKorean +Kim Taedong: fly1004 at gmail dot com +SooYoung Jung: jung5000 at gmail dot com +Richard Kim: [unreachable] ryk at dspwiz dot com + +TranslatorLithuanian +Tomas Simonaitis: [unreachable] haden at homelan dot lt +Mindaugas Radzius: [unreachable] mindaugasradzius at takas dot lt +Aidas Berukstis: [unreachable] aidasber at takas dot lt +-- searching for the maintainer --: [Please, try to help to find someone.] + +TranslatorNorwegian +Lars Erik Jordet: lejordet at gmail dot com + +TranslatorMacedonian +Slave Jovanovski: slavejovanovski at yahoo dot com + +TranslatorPersian +Ali Nadalizadeh: nadalizadeh at gmail dot com + +TranslatorPolish +Piotr Kaminski: [unreachable] Piotr dot Kaminski at ctm dot gdynia dot pl +Grzegorz Kowal: [unreachable] g_kowal at poczta dot onet dot pl +Krzysztof Kral: krzysztof dot kral at gmail dot com + +TranslatorPortuguese +Rui Godinho Lopes: [resigned] rgl at ruilopes dot com +-- searching for the maintainer --: [Please, try to help to find someone.] + +TranslatorRomanian +Ionut Dumitrascu: reddumy at yahoo dot com +Alexandru Iosup: aiosup at yahoo dot com + +TranslatorRussian +Alexandr Chelpanov: cav at cryptopro dot ru + +TranslatorSerbian +Dejan Milosavljevic: [unreachable] dmilos at email dot com + +TranslatorSerbianCyrilic +Nedeljko Stefanovic: stenedjo at yahoo dot com + +TranslatorSlovak +% Stanislav Kudláč: [resigned] skudlac at pobox dot sk +Kali+Laco Švec: the Slovak language advisors +Petr Přikryl: prikrylp at skil dot cz + +TranslatorSlovene +Matjaž Ostroveršnik: matjaz dot ostroversnik at ostri dot org + +TranslatorSpanish +Bartomeu: bartomeu at loteria3cornella dot com +Francisco Oltra Thennet: [unreachable] foltra at puc dot cl +David Vaquero: david at grupoikusnet dot com + +TranslatorSwedish +Mikael Hallin: mikaelhallin at yahoo dot se + +TranslatorTurkish +Emin Ilker Cetinbas: niw3 at yahoo dot com + +TranslatorUkrainian +Olexij Tkatchenko: [resigned] olexij at tkatchenko dot com +-- searching for the maintainer --: [Please, try to help to find someone.] + +TranslatorVietnamese +Dang Minh Tuan: tuanvietkey at gmail dot com + diff --git a/trunk/doc/markdown.doc b/trunk/doc/markdown.doc new file mode 100644 index 0000000..d571eef --- /dev/null +++ b/trunk/doc/markdown.doc @@ -0,0 +1,605 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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 markdown Markdown support + +[TOC] + +[Markdown] support +was introduced in doxygen version 1.8.0. It is a plain text formatting +syntax written by John Gruber, with the following underlying design goal: + +> The design goal for Markdown's formatting syntax is to +> make it as readable as possible. The idea is that a Markdown-formatted +> document should be publishable as-is, as plain text, without +> looking like it's been marked up with tags or formatting instructions. +> While Markdown's syntax has been influenced by several existing +> text-to-HTML filters, the single biggest source of inspiration +> for Markdown's syntax is the format of plain text email. + +In the \ref markdown_std "next section" the standard Markdown features +are briefly discussed. The reader is referred to the [Markdown site][markdown] +for more details. + +Some enhancements were made, for instance [PHP Markdown Extra][mdextra], and +[GitHub flavored Markdown][github]. The section \ref markdown_extra discusses +the extensions that doxygen supports. + +Finally section \ref markdown_dox discusses some specifics for doxygen's +implementation of the Markdown standard. + +[markdown]: http://daringfireball.net/projects/markdown +[mdextra]: http://michelf.com/projects/php-markdown/extra/ +[github]: http://github.github.com/github-flavored-markdown/ + +\section markdown_std Standard Markdown + +\subsection md_para Paragraphs + +Even before doxygen had Markdown support it supported the same way +of paragraph handling as Markdown: to make a paragraph you just separate +consecutive lines of text by one or more blank lines. + +An example: + + Here is text for one paragraph. + + We continue with more text in another paragraph. + +\subsection md_headers Headers + +Just like Markdown, doxygen supports two types of headers + +Level 1 or 2 headers can be made as the follows + + This is an level 1 header + ========================= + + This is an level 2 header + ------------------------- + +A header is followed by a line containing only ='s or -'s. +Note that the exact amount of ='s or -'s is not important. + +Alternatively, you can use #'s at the start of a line to make a header. +The number of #'s at the start of the line determines the level (up to 6 levels are supported). +You can end a header by any number of #'s. + +Here is an example: + + # This is a level 1 header + + ### This is level 3 header ####### + +\subsection md_blockquotes Block quotes + +Block quotes can be created by starting each line with one or more >'s, +similar to what is used in text-only emails. + + > This is a block quote + > spanning multiple lines + +Lists and code blocks (see below) can appear inside a quote block. +Quote blocks can also be nested. + +Note that doxygen requires that you put a space after the (last) > character +to avoid false positives, i.e. when writing + + 0 if OK\n + >1 if NOK + +the second line will not be seen as a block quote. + +\subsection md_lists Lists + +Simple bullet lists can be made by starting a line with -, +, or *. + + - Item 1 + + More text for this item. + + - Item 2 + + nested list item. + + another nested item. + - Item 3 + +List items can span multiple paragraphs (if each paragraph starts with +the proper indentation) and lists can be nested. +You can also make a numbered list like so + + 1. First item. + 2. Second item. + +\subsection md_codeblock Code Blocks + +Preformatted verbatim blocks can be created by indenting +each line in a block of text by at least 4 extra spaces + + This a normal paragraph + + This is a code block + + We continue with a normal paragraph again. + +Doxygen will remove the mandatory indentation from the code block. +Note that you cannot start a code block in the middle of a paragraph +(i.e. the line preceding the code block must be empty). + +See section \ref mddox_code_blocks for more info how doxygen handles +indentation as this is slightly different than standard Markdown. + +\subsection md_rulers Horizontal Rulers + +A horizontal ruler will be produced for lines containing at least three or more +hyphens, asterisks, or underscores. The line may also include any amount of whitespace. + +Examples: + + - - - + ______ + +Note that using asterisks in comment blocks does not work. See +\ref mddox_stars for details. + +\subsection md_emphasis Emphasis + +To emphasize a text fragment you start and end the fragment with an underscore or star. +Using two stars or underscores will produce strong emphasis. + +Examples: + + *single asterisks* + + _single underscores_ + + **double asterisks** + + __double underscores__ + +See section \ref mddox_emph_spans for more info how doxygen handles +emphasis spans slightly different than standard Markdown. + +\subsection md_codespan code spans + +To indicate a span of code, you should wrap it in backticks (`). Unlike code blocks, +code spans appear inline in a paragraph. An example: + + Use the `printf()` function. + +To show a literal backtick inside a code span use double backticks, i.e. + + To assign the output of command `ls` to `var` use ``var=`ls```. + +See section \ref mddox_code_spans for more info how doxygen handles +code spans slightly different than standard Markdown. + +\subsection md_links Links + +Doxygen supports both styles of make links defined by Markdown: *inline* and *reference*. + +For both styles the link definition starts with the link text delimited by [square +brackets]. + +\subsubsection md_inlinelinks Inline Links + +For an inline link the link text is followed by a URL and an optional link title which +together are enclosed in a set of regular parenthesis. +The link title itself is surrounded by quotes. + +Examples: + + [The link text](http://example.net/) + [The link text](http://example.net/ "Link title") + [The link text](/relative/path/to/index.html "Link title") + [The link text](somefile.html) + +In addition doxygen provides a similar way to link a documented entity: + + [The link text](@ref MyClass) + +\subsubsection md_reflinks Reference Links + +Instead of putting the URL inline, you can also define the link separately +and then refer to it from within the text. + +The link definition looks as follows: + + [link name]: http://www.example.com "Optional title" + +Instead of double quotes also single quotes or parenthesis can +be used for the title part. + +Once defined, the link looks as follows + + [link text][link name] + +If the link text and name are the same, also + + [link name][] + +or even + + [link name] + +can be used to refer to the link. +Note that the link name matching is not case sensitive +as is shown in the following example: + + I get 10 times more traffic from [Google] than from + [Yahoo] or [MSN]. + + [google]: http://google.com/ "Google" + [yahoo]: http://search.yahoo.com/ "Yahoo Search" + [msn]: http://search.msn.com/ "MSN Search" + +Link definitions will not be visible in the output. + +Like for inline links doxygen also supports \@ref inside a link definition: + + [myclass]: @ref MyClass "My class" + +\subsection md_images Images + +Markdown syntax for images is similar to that for links. +The only difference is an additional ! before the link text. + +Examples: + + ![Caption text](/path/to/img.jpg) + ![Caption text](/path/to/img.jpg "Image title") + ![Caption text][img def] + ![img def] + + [img def]: /path/to/img.jpg "Optional Title" + +Also here you can use \@ref to link to an image: + + ![Caption text](@ref image.png) + ![img def] + + [img def]: @ref image.png "Caption text" + +The caption text is optional. + +\subsection md_autolink Automatic Linking + +To create a link to an URL or e-mail address Markdown supports the following +syntax: + + <http://www.example.com> + <address@example.com> + +Note that doxygen will also produce the links without the angle brackets. + +\section markdown_extra Markdown Extensions + +\subsection md_toc Table of Contents + +Doxygen supports a special link marker `[TOC]` which can be placed in a page +to produce a table of contents at the start of the page, listing all sections. + +Note that using `[TOC]` is the same as using a +\ref cmdtableofcontents "\\tableofcontents" command. + +\subsection md_tables Tables + +Of the features defined by "Markdown Extra" is support for +<a href="http://michelf.com/projects/php-markdown/extra/#table">simple tables</a>: + +A table consists of a header line, a separator line, and at least one +row line. Table columns are separated by the pipe (|) character. + +Here is an example: + + First Header | Second Header + ------------- | ------------- + Content Cell | Content Cell + Content Cell | Content Cell + +which will produce the following table: + +First Header | Second Header +------------- | ------------- +Content Cell | Content Cell +Content Cell | Content Cell + +Column alignment can be controlled via one or two colons +at the header separator line: + + | Right | Center | Left | + | ----: | :----: | :---- | + | 10 | 10 | 10 | + | 1000 | 1000 | 1000 | + +which will look as follows: + +| Right | Center | Left | +| ----: | :----: | :---- | +| 10 | 10 | 10 | +| 1000 | 1000 | 1000 | + +\subsection md_fenced Fenced Code Blocks + +Another feature defined by "Markdown Extra" is support for +<a href="http://michelf.com/projects/php-markdown/extra/#fenced-code-blocks"> +fenced code blocks</a>: + +A fenced code block does not require indentation, and is +defined by a pair of "fence lines". Such a line consists of 3 or +more tilde (~) characters on a line. The end of the block should have the +same number of tildes. Here is an example: + + + This is a paragraph introducing: + + ~~~~~~~~~~~~~~~~~~~~~ + a one-line code block + ~~~~~~~~~~~~~~~~~~~~~ + +By default the output is the same as for a normal code block. + +For languages supported by doxygen you can also make the code block +appear with syntax highlighting. To do so you need to +indicate the typical file extension that corresponds to the +programming language after the opening fence. For highlighting according +to the Python language for instance, you would need to write the following: + + ~~~~~~~~~~~~~{.py} + # A class + class Dummy: + pass + ~~~~~~~~~~~~~ + +which will produce: +~~~~~~~~~~~~~{.py} +# A class +class Dummy: + pass +~~~~~~~~~~~~~ + +and for C you would write: + + ~~~~~~~~~~~~~~~{.c} + int func(int a,int b) { return a*b; } + ~~~~~~~~~~~~~~~ + +which will produce: + +~~~~~~~~~~~~~~~{.c} +int func(int a,int b) { return a*b; } +~~~~~~~~~~~~~~~ + +The curly braces and dot are optional by the way. + +\subsection md_header_id Header Id Attributes + +Standard Markdown has no support for labeling headers, which +is a problem if you want to link to a section. + +PHP Markdown Extra allows you to label a header by adding +the following to the header + + Header 1 {#labelid} + ======== + + ## Header 2 ## {#labelid2} + +To link to a section in the same comment block you can use + + [Link text](#labelid) + +to link to a section in general, doxygen allows you to use \@ref + + [Link text](@ref labelid) + +Note this only works for the headers of level 1 to 4. + +\section markdown_dox Doxygen specifics + +Even though doxygen tries to following the Markdown standard as closely as +possible, there are couple of deviation and doxygen specifics additions. + +\subsection md_page_header Including Markdown files as pages + +Doxygen can process files with Markdown formatting. +For this to work the extension for such a file should +be `.md` or `.markdown` (see +\ref cfg_extension_mapping "EXTENSION_MAPPING" if your Markdown files have +a different extension, and use `md` as the name of the parser). +Each file is converted to a page (see the \ref cmdpage "page" command for +details). + +By default the name and title of the page are derived from the file name. +If the file starts with a level 1 header however, it is used as the title +of the page. If you specify a label for the +header (as shown \ref md_header_id "here") doxygen will use that as the +page name. + +If the label is called `index` or `mainpage` doxygen will put the +documentation on the front page (`index.html`). + +Here is an example of a file `README.md` that will appear as the main page +when processed by doxygen: + + My Main Page {#mainpage} + ============ + + Documentation that will appear on the main page + +\subsection md_html_blocks Treatment of HTML blocks + +Markdown is quite strict in the way it processes block-level HTML: + +> block-level HTML elements — e.g. +> `<div>`, `<table>`, `<pre>`, `<p>`, etc. — +> must be separated from surrounding content by blank lines, +> and the start and end tags of the block should not be indented +> with tabs or spaces. + +Doxygen does not have this requirement, and will also process +Markdown formatting inside such HTML blocks. The only exception is +`<pre>` blocks, which are passed untouched (handy for ASCII art). + +Doxygen will not process Markdown formatting inside verbatim or code blocks, +and in other sections that need to be processed without changes +(for instance formulas or inline dot graphs). + +\subsection mddox_code_blocks Code Block Indentation + +With Markdown any block that is indented by 4 spaces (and 8 spaces +inside lists) is treated as a code block. This indentation amount +is absolute, i.e. counting from the start of the line. + +Since doxygen comments can appear at any indentation level +that is required by the programming language, it +uses a relative indentation instead. The amount of +indentation is counted relative to the preceding paragraph. +In case there is no preceding paragraph (i.e. you want to start with a +code block), the minimal amount of indentation of the whole comment block +is used as a reference. + +In most cases this difference does not result in different output. +Only if you play with the indentation of paragraphs the difference +is noticeable: + + text + + text + + text + + code + +In this case Markdown will put the word code in a code block, +whereas Doxygen will treat it as normal text, since although the absolute +indentation is 4, the indentation with respect to the previous paragraph +is only 1. + +Note that list markers are not counted when determining the +relative indent: + + 1. Item1 + + More text for item1 + + 2. Item2 + + Code block for item2 + +For Item1 the indentation is 4 (when treating the list marker as whitespace), +so the next paragraph "More text..." starts at the same indentation level +and is therefore not seen as a code block. + +\subsection mddox_emph_spans Emphasis limits + +Unlike standard Markdown, doxygen will not touch internal underscores or +stars, so the following will appear as-is: + + a_nice_identifier + +Futhermore, a `*` or `_` only starts an emphasis if +- it is followed by an alphanumberical character, and +- it is preceded by a space, newline, or one the following characters `<{([,:;` + +An emphasis ends if +- it is not following by an alphanumerical character, and +- it is not preceded by a space, newline, or one the following characters `({[<=+-\@` + +Lastly, the span of the emphasis is limited to a single paragraph. + + +\subsection mddox_code_spans Code Spans Limits + +Note that unlike standard Markdown, doxygen leaves the following untouched. + + A `cool' word in a `nice' sentence. + +In other words; a single quote cancels the special treatment of a code span +wrapped in a pair of backtick characters. This extra restriction was +added for backward compatibility reasons. + +\subsection mddox_lists Lists Extensions + +With Markdown two lists separated by an empty line are joined together into +a single list which can be rather unexpected and many people consider it to +be a bug. Doxygen, however, will make two separate lists as you would expect. + +Example: + + - Item1 of list 1 + - Item2 of list 1 + + 1. Item1 of list 2 + 2. Item2 of list 2 + +Historically doxygen has an additional way to create numbered +lists by using `-#` markers: + + -# item1 + -# item2 + +\subsection mddox_stars Use of asterisks + +Special care has to be taken when using *'s in a comment block +to start a list or make a ruler. + +Doxygen will strip off any leading *'s from the comment before doing +Markdown processing. So although the following works fine + +@verbatim + /** A list: + * * item1 + * * item2 + */ +@endverbatim + +When you remove the leading *'s doxygen will strip the other stars +as well, making the list disappear! + +Rulers created with *'s will not be visible at all. They only work +in Markdown files. + +\subsection mddox_limits Limits on markup scope + +To avoid that a stray * or _ matches something many paragraphs later, +and shows everything in between with emphasis, doxygen limits the scope +of a * and _ to a single paragraph. + +For a code span, between the starting and ending backtick only two +new lines are allowed. + +Also for links there are limits; the link text, and link title each can +contain only one new line, the URL may not contain any newlines. + +\section markdown_debug Debugging of problems + +When doxygen parses the source code it first extracts the comments blocks, +then passes these through the Markdown preprocessor. The output of the +Markdown preprocessing consists of text with \ref cmd_intro "special commands" +and \ref htmlcmds "HTML commands". +A second pass takes the output of the Markdown preprocessor and +converts it into the various output formats. + +During Markdown preprocessing no errors are produced. Anything that +does not fit the Markdown syntax is simply passed on as-is. In the subsequent +parsing phase this could lead to errors, which may not always be obvious +as they are based on the intermediate format. + +To see the result after Markdown processing you can run doxygen with the +`-d Markdown` option. It will then print each comment block before and +after Markdown processing. + +*/ diff --git a/trunk/doc/output.doc b/trunk/doc/output.doc new file mode 100644 index 0000000..d34e057 --- /dev/null +++ b/trunk/doc/output.doc @@ -0,0 +1,64 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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 output Output Formats + +\addindex output formats + +The following output formats are \e directly supported by doxygen: +<dl> +<dt><b>HTML</b> +<dd>Generated if \c GENERATE_HTML is set to \c YES in the configuration file. +<dt>\f$\mbox{\LaTeX}\f$ +<dd>Generated if \c GENERATE_LATEX is set to \c YES in the configuration file. +<dt><b>Man pages</b> +<dd>Generated if \c GENERATE_MAN is set to \c YES in the configuration file. +<dt><b>RTF</b> +<dd>Generated if \c GENERATE_RTF is set to \c YES in the configuration file.<p> + Note that the RTF output probably only looks nice with Microsoft's + Word. If you have success with other programs, please let me know. +<dt><b>XML</b> +<dd>Generated if \c GENERATE_XML is set to \c YES in the configuration file.<p> +</dl> + +The following output formats are \e indirectly supported by doxygen: +<dl> +<dt><b>Compiled HTML Help</b> (a.k.a. Windows 98 help) +<dd>Generated by Microsoft's HTML Help workshop from the HTML output if + \c GENERATE_HTMLHELP is set to \c YES. +<dt><b>Qt Compressed Help (.qch)</b> +<dd>Generated by Qt's qhelpgenerator tool from the HTML output if + \c GENERATE_QHP is set to \c YES. +<dt><b>Eclipse Help</b> +<dd>Generated from HTML with a special index file that is generated when + \c GENERATE_ECLIPSEHELP is set to \c YES. +<dt><b>XCode DocSets</b> +<dd>Compiled from HTML with a special index file that is generated when + \c GENERATE_DOCSET is set to \c YES. +<dt><b>PostScript</b> +<dd>Generated from the \f$\mbox{\LaTeX}\f$ output by + running <code>make ps</code> in the output directory. + For the best results \c PDF_HYPERLINKS should be set to \c NO. +<dt><b>PDF</b>\htmlonly    \endhtmlonly +<dd>Generated from the \f$\mbox{\LaTeX}\f$ output by + running <code>make pdf</code> in the output directory. + To improve the PDF output, you typically would want to enable the use + of \c pdflatex by setting \ref cfg_use_pdflatex "USE_PDFLATEX" to \c YES in the + configuration file. In order to get hyperlinks in the PDF file you also need to enable + \ref cfg_pdf_hyperlinks "PDF_HYPERLINKS". +</dl> + +*/ diff --git a/trunk/doc/perlmod.doc b/trunk/doc/perlmod.doc new file mode 100644 index 0000000..b375e15 --- /dev/null +++ b/trunk/doc/perlmod.doc @@ -0,0 +1,193 @@ +/*! \page perlmod Perl Module Output + +\addindex perlmod + +<p>Since version 1.2.18, Doxygen can generate a new output format we +have called the "Perl Module output format". It has been +designed as an intermediate format that can be used to generate new +and customized output without having to modify the Doxygen source. +Therefore, its purpose is similar to the XML output format that can be +also generated by Doxygen. The XML output format is more standard, +but the Perl Module output format is possibly simpler and easier to +use. + +<p>The Perl Module output format is still experimental at the moment +and could be changed in incompatible ways in future versions, although +this should not be very probable. It is also lacking some features of +other Doxygen backends. However, it can be already used to generate +useful output, as shown by the Perl Module-based LaTeX generator. + +<p>Please report any bugs or problems you find in the Perl Module +backend or the Perl Module-based LaTeX generator to the +doxygen-develop mailing list. Suggestions are welcome as well. + +\section using_perlmod_fmt Usage + +<p>When the <b>GENERATE_PERLMOD</b> tag is enabled in the Doxyfile, +running Doxygen generates a number of files in the <b>perlmod/</b> +subdirectory of your output directory. These files are the following: + +<ul> + +<li><b>DoxyDocs.pm</b>. This is the Perl module that actually +contains the documentation, in the Perl Module format described +\ref doxydocs_format "below". + +<li><b>DoxyModel.pm</b>. This Perl module describes the structure of +<b>DoxyDocs.pm</b>, independently of the actual documentation. See +\ref doxymodel_format "below" for details. + +<li><b>doxyrules.make</b>. This file contains the make rules to build +and clean the files that are generated from the Doxyfile. Also +contains the paths to those files and other relevant information. This +file is intended to be included by your own Makefile. + +<li><b>Makefile</b>. This is a simple Makefile including +<b>doxyrules.make</b>. + +</ul> + +<p>To make use of the documentation stored in DoxyDocs.pm you can use +one of the default Perl Module-based generators provided by Doxygen +(at the moment this includes the Perl Module-based LaTeX generator, +see \ref perlmod_latex "below") or write your own customized +generator. This should not be too hard if you have some knowledge of +Perl and it's the main purpose of including the Perl Module backend in +Doxygen. See \ref doxydocs_format "below" for details on how +to do this. + +\section perlmod_latex Using the LaTeX generator. + +<p>The Perl Module-based LaTeX generator is pretty experimental and +incomplete at the moment, but you could find it useful nevertheless. +It can generate documentation for functions, typedefs and variables +within files and classes and can be customized quite a lot by +redefining TeX macros. However, there is still no documentation on +how to do this. + +<p>Setting the <b>PERLMOD_LATEX</b> tag to <b>YES</b> in the Doxyfile +enables the creation of some additional files in the <b>perlmod/</b> +subdirectory of your output directory. These files contain the Perl +scripts and LaTeX code necessary to generate PDF and DVI output from +the Perl Module output, using PDFLaTeX and LaTeX respectively. Rules +to automate the use of these files are also added to +<b>doxyrules.make</b> and the <b>Makefile</b>. + +<p>The additional generated files are the following: + +<ul> + +<li><b>doxylatex.pl</b>. This Perl script uses DoxyDocs.pm and +DoxyModel.pm to generate <b>doxydocs.tex</b>, a TeX file containing +the documentation in a format that can be accessed by LaTeX code. This +file is not directly LaTeXable. + +<li><b>doxyformat.tex</b>. This file contains the LaTeX code that +transforms the documentation from doxydocs.tex into LaTeX text +suitable to be LaTeX'ed and presented to the user. + +<li><b>doxylatex-template.pl</b>. This Perl script uses DoxyModel.pm +to generate <b>doxytemplate.tex</b>, a TeX file defining default +values for some macros. doxytemplate.tex is included by +doxyformat.tex to avoid the need of explicitly defining some macros. + +<li><b>doxylatex.tex</b>. This is a very simple LaTeX document that +loads some packages and includes doxyformat.tex and doxydocs.tex. This +document is LaTeX'ed to produce the PDF and DVI documentation by the +rules added to <b>doxyrules.make</b>. + +</ul> + +\subsection pm_pdf_gen Creation of PDF and DVI output + +<p>To try this you need to have installed LaTeX, PDFLaTeX and the +packages used by <b>doxylatex.tex</b>. + +<ol> + +<li>Update your Doxyfile to the latest version using: + +<pre>doxygen -u Doxyfile</pre> + +<li>Set both <b>GENERATE_PERLMOD</b> and <b>PERLMOD_LATEX</b> tags to +YES in your Doxyfile. + +<li>Run Doxygen on your Doxyfile: + +<pre>doxygen Doxyfile</pre> + +<li>A <b>perlmod/</b> subdirectory should have appeared in your output +directory. Enter the <b>perlmod/</b> subdirectory and run: + +<pre>make pdf</pre> + +<p>This should generate a <b>doxylatex.pdf</b> with the documentation +in PDF format. + +<li>Run: + +<pre>make dvi</pre> + +<p>This should generate a <b>doxylatex.dvi</b> with the documentation +in DVI format. + +</ol> + +\section doxydocs_format Documentation format. + +<p>The Perl Module documentation generated by Doxygen is stored in +<b>DoxyDocs.pm</b>. This is a very simple Perl module that contains +only two statements: an assignment to the variable <b>$doxydocs</b> and +the customary <b>1;</b> statement which usually ends Perl modules. +The documentation is stored in the variable <b>$doxydocs</b>, which +can then be accessed by a Perl script using <b>DoxyDocs.pm</b>. + +<p><b>$doxydocs</b> contains a tree-like structure composed of three +types of nodes: strings, hashes and lists. + +<ul> + +<li><b>Strings</b>. These are normal Perl strings. They can be of +any length can contain any character. Their semantics depends on +their location within the tree. This type of node has no children. + +<li><b>Hashes</b>. These are references to anonymous Perl hashes. A +hash can have multiple fields, each with a different key. The value +of a hash field can be a string, a hash or a list, and its semantics +depends on the key of the hash field and the location of the hash +within the tree. The values of the hash fields are the children of +the node. + +<li><b>Lists</b>. These are references to anonymous Perl lists. A +list has an undefined number of elements, which are the children of +the node. Each element has the same type (string, hash or list) and +the same semantics, depending on the location of the list within the +tree. + +</ul> + +<p>As you can see, the documentation contained in <b>$doxydocs</b> +does not present any special impediment to be processed by a simple +Perl script. +<!-- +To be able to generate meaningful output using the +documentation contained in <b>$doxydocs</b> you'll probably need to +know the semantics of the nodes of the documentation tree, which we +present in \ref perlmod_tree "this page". +--> + +\section doxymodel_format Data structure + +<p>You might be interested in processing the documentation contained +in <b>DoxyDocs.pm</b> without needing to take into account the +semantics of each node of the documentation tree. For this purpose, +Doxygen generates a <b>DoxyModel.pm</b> file which contains a data +structure describing the type and children of each node in the +documentation tree. + +<p>The rest of this section is to be written yet, but in the meantime +you can look at the Perl scripts generated by Doxygen (such as +<b>doxylatex.pl</b> or <b>doxytemplate-latex.pl</b>) to get an idea on +how to use <b>DoxyModel.pm</b>. + +*/ diff --git a/trunk/doc/perlmod_tree.doc b/trunk/doc/perlmod_tree.doc new file mode 100644 index 0000000..be71315 --- /dev/null +++ b/trunk/doc/perlmod_tree.doc @@ -0,0 +1,377 @@ +/*! \page perlmod_tree Perl Module Tree Nodes + +<h2>Nodes in the documentation tree of the Perl Module output +format.</h2> + +This is a description of the structure of the documentation tree in +<b>DoxyDocs.pm</b>. Each item in the list below describes a node in +the tree, and the format of the description is as follows: + +<ul> +<li>[ key => ] <b>Name</b> <i>(type)</i>. Explanation of the content. +</ul> + +Where + +<ul> + +<li>The "key =>" part only appears if the parent node is a hash. +"key" is the key for this node. + +<li><b>"Name"</b> is a unique name for the node, defined in +DoxyModel.pm. + +<li><i>"(type)"</i> is the type of the node: "string" for string +nodes, "hash" for hash nodes, "list" for list nodes, and "doc" for +documentation subtrees. The structure of documentation subtrees is +not described anywhere yet, but you can look for example at +<b>doxylatex.pl</b> to see how to process it. + +</ul> + +The meaning of each node in the documentation tree is as follows: +<ul> +<li> <b>Root</b> <i>(hash)</i>. Root node. +<ul> +<li>classes => <b>Classes</b> <i>(list)</i>. Documented classes. +<ul> +<li> <b>Class</b> <i>(hash)</i>. A documented class. +<ul> +<li>protected_members => <b>ClassProtectedMembers</b> <i>(hash)</i>. Information about the protected members in the class. +<ul> +<li>members => <b>ClassProtectedMemberList</b> <i>(list)</i>. protected member list. +<ul> +<li> <b>ClassProtectedMember</b> <i>(hash)</i>. A protected member. +<ul> +<li>protection => <b>ClassProtectedMemberProtection</b> <i>(string)</i>. Protection of the protected member. +<li>detailed => <b>ClassProtectedMemberDetailed</b> <i>(hash)</i>. Detailed information about the protected member. +<ul> +<li>doc => <b>ClassProtectedMemberDetailedDoc</b> <i>(doc)</i>. Detailed documentation for the protected member. +<li>see => <b>ClassProtectedMemberSee</b> <i>(doc)</i>. "See also" documentation for the protected member. +</ul> +<li>kind => <b>ClassProtectedMemberKind</b> <i>(string)</i>. Kind of protected member (usually "variable"). +<li>name => <b>ClassProtectedMemberName</b> <i>(string)</i>. Name of the protected member. +<li>type => <b>ClassProtectedMemberType</b> <i>(string)</i>. Data type of the protected member. +</ul> +</ul> +</ul> +<li>detailed => <b>ClassDetailed</b> <i>(hash)</i>. Detailed information about the class. +<ul> +<li>doc => <b>ClassDetailedDoc</b> <i>(doc)</i>. Detailed documentation block for the class. +</ul> +<li>protected_typedefs => <b>ClassProtectedTypedefs</b> <i>(hash)</i>. Information about the protected typedefs in the class. +<ul> +<li>members => <b>ClassProtectedTypedefList</b> <i>(list)</i>. protected typedef list. +<ul> +<li> <b>ClassProtectedTypedef</b> <i>(hash)</i>. A protected typedef. +<ul> +<li>protection => <b>ClassProtectedTypedefProtection</b> <i>(string)</i>. Protection of the protected typedef. +<li>detailed => <b>ClassProtectedTypedefDetailed</b> <i>(hash)</i>. Detailed information about the protected typedef. +<ul> +<li>doc => <b>ClassProtectedTypedefDetailedDoc</b> <i>(doc)</i>. Detailed documentation for the protected typedef. +<li>see => <b>ClassProtectedTypedefSee</b> <i>(doc)</i>. "See also" documentation for the protected typedef. +</ul> +<li>kind => <b>ClassProtectedTypedefKind</b> <i>(string)</i>. Kind of protected typedef (usually "typedef"). +<li>name => <b>ClassProtectedTypedefName</b> <i>(string)</i>. Name of the protected typedef. +<li>type => <b>ClassProtectedTypedefType</b> <i>(string)</i>. Data type of the protected typedef. +</ul> +</ul> +</ul> +<li>name => <b>ClassName</b> <i>(string)</i>. Name of the class. +<li>private_members => <b>ClassPrivateMembers</b> <i>(hash)</i>. Information about the private members in the class. +<ul> +<li>members => <b>ClassPrivateMemberList</b> <i>(list)</i>. private member list. +<ul> +<li> <b>ClassPrivateMember</b> <i>(hash)</i>. A private member. +<ul> +<li>protection => <b>ClassPrivateMemberProtection</b> <i>(string)</i>. Protection of the private member. +<li>detailed => <b>ClassPrivateMemberDetailed</b> <i>(hash)</i>. Detailed information about the private member. +<ul> +<li>doc => <b>ClassPrivateMemberDetailedDoc</b> <i>(doc)</i>. Detailed documentation for the private member. +<li>see => <b>ClassPrivateMemberSee</b> <i>(doc)</i>. "See also" documentation for the private member. +</ul> +<li>kind => <b>ClassPrivateMemberKind</b> <i>(string)</i>. Kind of private member (usually "variable"). +<li>name => <b>ClassPrivateMemberName</b> <i>(string)</i>. Name of the private member. +<li>type => <b>ClassPrivateMemberType</b> <i>(string)</i>. Data type of the private member. +</ul> +</ul> +</ul> +<li>private_typedefs => <b>ClassPrivateTypedefs</b> <i>(hash)</i>. Information about the private typedefs in the class. +<ul> +<li>members => <b>ClassPrivateTypedefList</b> <i>(list)</i>. private typedef list. +<ul> +<li> <b>ClassPrivateTypedef</b> <i>(hash)</i>. A private typedef. +<ul> +<li>protection => <b>ClassPrivateTypedefProtection</b> <i>(string)</i>. Protection of the private typedef. +<li>detailed => <b>ClassPrivateTypedefDetailed</b> <i>(hash)</i>. Detailed information about the private typedef. +<ul> +<li>doc => <b>ClassPrivateTypedefDetailedDoc</b> <i>(doc)</i>. Detailed documentation for the private typedef. +<li>see => <b>ClassPrivateTypedefSee</b> <i>(doc)</i>. "See also" documentation for the private typedef. +</ul> +<li>kind => <b>ClassPrivateTypedefKind</b> <i>(string)</i>. Kind of private typedef (usually "typedef"). +<li>name => <b>ClassPrivateTypedefName</b> <i>(string)</i>. Name of the private typedef. +<li>type => <b>ClassPrivateTypedefType</b> <i>(string)</i>. Data type of the private typedef. +</ul> +</ul> +</ul> +<li>protected_methods => <b>ClassProtectedMethods</b> <i>(hash)</i>. Information about the protected methods in the class. +<ul> +<li>members => <b>ClassProtectedMethodList</b> <i>(list)</i>. protected method list. +<ul> +<li> <b>ClassProtectedMethod</b> <i>(hash)</i>. A protected method. +<ul> +<li>parameters => <b>ClassProtectedMethodParams</b> <i>(list)</i>. List of the parameters of the protected method. +<ul> +<li> <b>ClassProtectedMethodParam</b> <i>(hash)</i>. A parameter of the protected method. +<ul> +<li>declaration_name => <b>ClassProtectedMethodParamName</b> <i>(string)</i>. The name of the parameter. +<li>type => <b>ClassProtectedMethodParamType</b> <i>(string)</i>. The data type of the parameter. +</ul> +</ul> +<li>protection => <b>ClassProtectedMethodProtection</b> <i>(string)</i>. Protection of the protected method. +<li>virtualness => <b>ClassProtectedMethodVirtualness</b> <i>(string)</i>. Virtualness of the protected method. +<li>detailed => <b>ClassProtectedMethodDetailed</b> <i>(hash)</i>. Detailed information about the protected method. +<ul> +<li>params => <b>ClassProtectedMethodPDBlocks</b> <i>(list)</i>. List of parameter documentation blocks for the protected method. +<ul> +<li> <b>ClassProtectedMethodPDBlock</b> <i>(hash)</i>. A parameter documentation block for the protected method. +<ul> +<li>parameters => <b>ClassProtectedMethodPDParams</b> <i>(list)</i>. Parameter list for this parameter documentation block. +<ul> +<li> <b>ClassProtectedMethodPDParam</b> <i>(hash)</i>. A parameter documented by this documentation block. +<ul> +<li>name => <b>ClassProtectedMethodPDParamName</b> <i>(string)</i>. Name of the parameter. +</ul> +</ul> +<li>doc => <b>ClassProtectedMethodPDDoc</b> <i>(doc)</i>. Documentation for this parameter documentation block. +</ul> +</ul> +<li>doc => <b>ClassProtectedMethodDetailedDoc</b> <i>(doc)</i>. Detailed documentation for the protected method. +<li>see => <b>ClassProtectedMethodSee</b> <i>(doc)</i>. "See also" documentation for the protected method. +<li>return => <b>ClassProtectedMethodReturn</b> <i>(doc)</i>. Documentation about the return value of the protected method. +</ul> +<li>kind => <b>ClassProtectedMethodKind</b> <i>(string)</i>. Kind of protected method (usually "function"). +<li>name => <b>ClassProtectedMethodName</b> <i>(string)</i>. Name of the protected method. +<li>type => <b>ClassProtectedMethodType</b> <i>(string)</i>. Data type returned by the protected method. +<li>static => <b>ClassProtectedMethodStatic</b> <i>(string)</i>. Whether the protected method is static. +</ul> +</ul> +</ul> +<li>public_typedefs => <b>ClassPublicTypedefs</b> <i>(hash)</i>. Information about the public typedefs in the class. +<ul> +<li>members => <b>ClassPublicTypedefList</b> <i>(list)</i>. public typedef list. +<ul> +<li> <b>ClassPublicTypedef</b> <i>(hash)</i>. A public typedef. +<ul> +<li>protection => <b>ClassPublicTypedefProtection</b> <i>(string)</i>. Protection of the public typedef. +<li>detailed => <b>ClassPublicTypedefDetailed</b> <i>(hash)</i>. Detailed information about the public typedef. +<ul> +<li>doc => <b>ClassPublicTypedefDetailedDoc</b> <i>(doc)</i>. Detailed documentation for the public typedef. +<li>see => <b>ClassPublicTypedefSee</b> <i>(doc)</i>. "See also" documentation for the public typedef. +</ul> +<li>kind => <b>ClassPublicTypedefKind</b> <i>(string)</i>. Kind of public typedef (usually "typedef"). +<li>name => <b>ClassPublicTypedefName</b> <i>(string)</i>. Name of the public typedef. +<li>type => <b>ClassPublicTypedefType</b> <i>(string)</i>. Data type of the public typedef. +</ul> +</ul> +</ul> +<li>public_members => <b>ClassPublicMembers</b> <i>(hash)</i>. Information about the public members in the class. +<ul> +<li>members => <b>ClassPublicMemberList</b> <i>(list)</i>. public member list. +<ul> +<li> <b>ClassPublicMember</b> <i>(hash)</i>. A public member. +<ul> +<li>protection => <b>ClassPublicMemberProtection</b> <i>(string)</i>. Protection of the public member. +<li>detailed => <b>ClassPublicMemberDetailed</b> <i>(hash)</i>. Detailed information about the public member. +<ul> +<li>doc => <b>ClassPublicMemberDetailedDoc</b> <i>(doc)</i>. Detailed documentation for the public member. +<li>see => <b>ClassPublicMemberSee</b> <i>(doc)</i>. "See also" documentation for the public member. +</ul> +<li>kind => <b>ClassPublicMemberKind</b> <i>(string)</i>. Kind of public member (usually "variable"). +<li>name => <b>ClassPublicMemberName</b> <i>(string)</i>. Name of the public member. +<li>type => <b>ClassPublicMemberType</b> <i>(string)</i>. Data type of the public member. +</ul> +</ul> +</ul> +<li>private_methods => <b>ClassPrivateMethods</b> <i>(hash)</i>. Information about the private methods in the class. +<ul> +<li>members => <b>ClassPrivateMethodList</b> <i>(list)</i>. private method list. +<ul> +<li> <b>ClassPrivateMethod</b> <i>(hash)</i>. A private method. +<ul> +<li>parameters => <b>ClassPrivateMethodParams</b> <i>(list)</i>. List of the parameters of the private method. +<ul> +<li> <b>ClassPrivateMethodParam</b> <i>(hash)</i>. A parameter of the private method. +<ul> +<li>declaration_name => <b>ClassPrivateMethodParamName</b> <i>(string)</i>. The name of the parameter. +<li>type => <b>ClassPrivateMethodParamType</b> <i>(string)</i>. The data type of the parameter. +</ul> +</ul> +<li>protection => <b>ClassPrivateMethodProtection</b> <i>(string)</i>. Protection of the private method. +<li>virtualness => <b>ClassPrivateMethodVirtualness</b> <i>(string)</i>. Virtualness of the private method. +<li>detailed => <b>ClassPrivateMethodDetailed</b> <i>(hash)</i>. Detailed information about the private method. +<ul> +<li>params => <b>ClassPrivateMethodPDBlocks</b> <i>(list)</i>. List of parameter documentation blocks for the private method. +<ul> +<li> <b>ClassPrivateMethodPDBlock</b> <i>(hash)</i>. A parameter documentation block for the private method. +<ul> +<li>parameters => <b>ClassPrivateMethodPDParams</b> <i>(list)</i>. Parameter list for this parameter documentation block. +<ul> +<li> <b>ClassPrivateMethodPDParam</b> <i>(hash)</i>. A parameter documented by this documentation block. +<ul> +<li>name => <b>ClassPrivateMethodPDParamName</b> <i>(string)</i>. Name of the parameter. +</ul> +</ul> +<li>doc => <b>ClassPrivateMethodPDDoc</b> <i>(doc)</i>. Documentation for this parameter documentation block. +</ul> +</ul> +<li>doc => <b>ClassPrivateMethodDetailedDoc</b> <i>(doc)</i>. Detailed documentation for the private method. +<li>see => <b>ClassPrivateMethodSee</b> <i>(doc)</i>. "See also" documentation for the private method. +<li>return => <b>ClassPrivateMethodReturn</b> <i>(doc)</i>. Documentation about the return value of the private method. +</ul> +<li>kind => <b>ClassPrivateMethodKind</b> <i>(string)</i>. Kind of private method (usually "function"). +<li>name => <b>ClassPrivateMethodName</b> <i>(string)</i>. Name of the private method. +<li>type => <b>ClassPrivateMethodType</b> <i>(string)</i>. Data type returned by the private method. +<li>static => <b>ClassPrivateMethodStatic</b> <i>(string)</i>. Whether the private method is static. +</ul> +</ul> +</ul> +<li>public_methods => <b>ClassPublicMethods</b> <i>(hash)</i>. Information about the public methods in the class. +<ul> +<li>members => <b>ClassPublicMethodList</b> <i>(list)</i>. public method list. +<ul> +<li> <b>ClassPublicMethod</b> <i>(hash)</i>. A public method. +<ul> +<li>parameters => <b>ClassPublicMethodParams</b> <i>(list)</i>. List of the parameters of the public method. +<ul> +<li> <b>ClassPublicMethodParam</b> <i>(hash)</i>. A parameter of the public method. +<ul> +<li>declaration_name => <b>ClassPublicMethodParamName</b> <i>(string)</i>. The name of the parameter. +<li>type => <b>ClassPublicMethodParamType</b> <i>(string)</i>. The data type of the parameter. +</ul> +</ul> +<li>protection => <b>ClassPublicMethodProtection</b> <i>(string)</i>. Protection of the public method. +<li>virtualness => <b>ClassPublicMethodVirtualness</b> <i>(string)</i>. Virtualness of the public method. +<li>detailed => <b>ClassPublicMethodDetailed</b> <i>(hash)</i>. Detailed information about the public method. +<ul> +<li>params => <b>ClassPublicMethodPDBlocks</b> <i>(list)</i>. List of parameter documentation blocks for the public method. +<ul> +<li> <b>ClassPublicMethodPDBlock</b> <i>(hash)</i>. A parameter documentation block for the public method. +<ul> +<li>parameters => <b>ClassPublicMethodPDParams</b> <i>(list)</i>. Parameter list for this parameter documentation block. +<ul> +<li> <b>ClassPublicMethodPDParam</b> <i>(hash)</i>. A parameter documented by this documentation block. +<ul> +<li>name => <b>ClassPublicMethodPDParamName</b> <i>(string)</i>. Name of the parameter. +</ul> +</ul> +<li>doc => <b>ClassPublicMethodPDDoc</b> <i>(doc)</i>. Documentation for this parameter documentation block. +</ul> +</ul> +<li>doc => <b>ClassPublicMethodDetailedDoc</b> <i>(doc)</i>. Detailed documentation for the public method. +<li>see => <b>ClassPublicMethodSee</b> <i>(doc)</i>. "See also" documentation for the public method. +<li>return => <b>ClassPublicMethodReturn</b> <i>(doc)</i>. Documentation about the return value of the public method. +</ul> +<li>kind => <b>ClassPublicMethodKind</b> <i>(string)</i>. Kind of public method (usually "function"). +<li>name => <b>ClassPublicMethodName</b> <i>(string)</i>. Name of the public method. +<li>type => <b>ClassPublicMethodType</b> <i>(string)</i>. Data type returned by the public method. +<li>static => <b>ClassPublicMethodStatic</b> <i>(string)</i>. Whether the public method is static. +</ul> +</ul> +</ul> +</ul> +</ul> +<li>files => <b>Files</b> <i>(list)</i>. Documented files. +<ul> +<li> <b>File</b> <i>(hash)</i>. A documented file. +<ul> +<li>detailed => <b>FileDetailed</b> <i>(hash)</i>. Detailed information about the file. +<ul> +<li>doc => <b>FileDetailedDoc</b> <i>(doc)</i>. Detailed documentation block for the file. +</ul> +<li>functions => <b>FileFunctions</b> <i>(hash)</i>. Information about the functions in the file. +<ul> +<li>members => <b>FileFunctionList</b> <i>(list)</i>. function list. +<ul> +<li> <b>FileFunction</b> <i>(hash)</i>. A function. +<ul> +<li>parameters => <b>FileFunctionParams</b> <i>(list)</i>. List of the parameters of the function. +<ul> +<li> <b>FileFunctionParam</b> <i>(hash)</i>. A parameter of the function. +<ul> +<li>declaration_name => <b>FileFunctionParamName</b> <i>(string)</i>. The name of the parameter. +<li>type => <b>FileFunctionParamType</b> <i>(string)</i>. The data type of the parameter. +</ul> +</ul> +<li>protection => <b>FileFunctionProtection</b> <i>(string)</i>. Protection of the function. +<li>virtualness => <b>FileFunctionVirtualness</b> <i>(string)</i>. Virtualness of the function. +<li>detailed => <b>FileFunctionDetailed</b> <i>(hash)</i>. Detailed information about the function. +<ul> +<li>params => <b>FileFunctionPDBlocks</b> <i>(list)</i>. List of parameter documentation blocks for the function. +<ul> +<li> <b>FileFunctionPDBlock</b> <i>(hash)</i>. A parameter documentation block for the function. +<ul> +<li>parameters => <b>FileFunctionPDParams</b> <i>(list)</i>. Parameter list for this parameter documentation block. +<ul> +<li> <b>FileFunctionPDParam</b> <i>(hash)</i>. A parameter documented by this documentation block. +<ul> +<li>name => <b>FileFunctionPDParamName</b> <i>(string)</i>. Name of the parameter. +</ul> +</ul> +<li>doc => <b>FileFunctionPDDoc</b> <i>(doc)</i>. Documentation for this parameter documentation block. +</ul> +</ul> +<li>doc => <b>FileFunctionDetailedDoc</b> <i>(doc)</i>. Detailed documentation for the function. +<li>see => <b>FileFunctionSee</b> <i>(doc)</i>. "See also" documentation for the function. +<li>return => <b>FileFunctionReturn</b> <i>(doc)</i>. Documentation about the return value of the function. +</ul> +<li>kind => <b>FileFunctionKind</b> <i>(string)</i>. Kind of function (usually "function"). +<li>name => <b>FileFunctionName</b> <i>(string)</i>. Name of the function. +<li>type => <b>FileFunctionType</b> <i>(string)</i>. Data type returned by the function. +<li>static => <b>FileFunctionStatic</b> <i>(string)</i>. Whether the function is static. +</ul> +</ul> +</ul> +<li>name => <b>FileName</b> <i>(string)</i>. Name of the file. +<li>variables => <b>FileVariables</b> <i>(hash)</i>. Information about the variables in the file. +<ul> +<li>members => <b>FileVariableList</b> <i>(list)</i>. variable list. +<ul> +<li> <b>FileVariable</b> <i>(hash)</i>. A variable. +<ul> +<li>protection => <b>FileVariableProtection</b> <i>(string)</i>. Protection of the variable. +<li>detailed => <b>FileVariableDetailed</b> <i>(hash)</i>. Detailed information about the variable. +<ul> +<li>doc => <b>FileVariableDetailedDoc</b> <i>(doc)</i>. Detailed documentation for the variable. +<li>see => <b>FileVariableSee</b> <i>(doc)</i>. "See also" documentation for the variable. +</ul> +<li>kind => <b>FileVariableKind</b> <i>(string)</i>. Kind of variable (usually "variable"). +<li>name => <b>FileVariableName</b> <i>(string)</i>. Name of the variable. +<li>type => <b>FileVariableType</b> <i>(string)</i>. Data type of the variable. +</ul> +</ul> +</ul> +<li>typedefs => <b>FileTypedefs</b> <i>(hash)</i>. Information about the typedefs in the file. +<ul> +<li>members => <b>FileTypedefList</b> <i>(list)</i>. typedef list. +<ul> +<li> <b>FileTypedef</b> <i>(hash)</i>. A typedef. +<ul> +<li>protection => <b>FileTypedefProtection</b> <i>(string)</i>. Protection of the typedef. +<li>detailed => <b>FileTypedefDetailed</b> <i>(hash)</i>. Detailed information about the typedef. +<ul> +<li>doc => <b>FileTypedefDetailedDoc</b> <i>(doc)</i>. Detailed documentation for the typedef. +<li>see => <b>FileTypedefSee</b> <i>(doc)</i>. "See also" documentation for the typedef. +</ul> +<li>kind => <b>FileTypedefKind</b> <i>(string)</i>. Kind of typedef (usually "typedef"). +<li>name => <b>FileTypedefName</b> <i>(string)</i>. Name of the typedef. +<li>type => <b>FileTypedefType</b> <i>(string)</i>. Data type of the typedef. +</ul> +</ul> +</ul> +</ul> +</ul> +</ul> +</ul> + +*/ diff --git a/trunk/doc/preprocessing.doc b/trunk/doc/preprocessing.doc new file mode 100644 index 0000000..49dd0f1 --- /dev/null +++ b/trunk/doc/preprocessing.doc @@ -0,0 +1,263 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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 preprocessing Preprocessing + +Source files that are used as input to doxygen can be parsed by doxygen's +built-in C-preprocessor. + +By default doxygen does only partial preprocessing. That is, it +evaluates conditional compilation statements (like \#if) and +evaluates macro definitions, but it does not perform macro expansion. + +So if you have the following code fragment +\verbatim +#define VERSION 200 +#define CONST_STRING const char * + +#if VERSION >= 200 + static CONST_STRING version = "2.xx"; +#else + static CONST_STRING version = "1.xx"; +#endif +\endverbatim + +Then by default doxygen will feed the following to its parser: + +\verbatim +#define VERSION +#define CONST_STRING + + static CONST_STRING version = "2.xx"; +\endverbatim + +You can disable all preprocessing by setting +\ref cfg_enable_preprocessing "ENABLE_PREPROCESSING" to \c +NO in the configuration file. In the case above doxygen will then read +both statements, i.e.: + +\verbatim + static CONST_STRING version = "2.xx"; + static CONST_STRING version = "1.xx"; +\endverbatim + +In case you want to expand the \c CONST_STRING macro, you should set the +\ref cfg_macro_expansion "MACRO_EXPANSION" tag in the config file +to \c YES. Then the result after preprocessing becomes: + +\verbatim +#define VERSION +#define CONST_STRING + + static const char * version = "1.xx"; +\endverbatim + +Note that doxygen will now expand \e all macro definitions +(recursively if needed). This is often too much. Therefore, doxygen also +allows you to expand only those defines that you explicitly +specify. For this you have to set the +\ref cfg_expand_only_predef "EXPAND_ONLY_PREDEF" tag to \c YES +and specify the macro definitions after +the \ref cfg_predefined "PREDEFINED" or +\ref cfg_expand_as_defined "EXPAND_AS_DEFINED" tag. + +A typically example where some help from the preprocessor is needed is +when dealing with Microsoft's __declspec language extension. Here is an +example function. + +\verbatim +extern "C" void __declspec(dllexport) ErrorMsg( String aMessage,...); +\endverbatim + +When nothing is done, doxygen will be confused and see __declspec as +some sort of function. To help doxygen one typically uses the following +preprocessor settings: + +\verbatim +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = YES +EXPAND_ONLY_PREDEF = YES +PREDEFINED = __declspec(x)= +\endverbatim + +This will make sure the __declspec(dllexport) is removed before doxygen +parses the source code. + +For a more complex example, suppose you have the following obfuscated +code fragment of an abstract base class called \c IUnknown: + +\verbatim +/*! A reference to an IID */ +#ifdef __cplusplus +#define REFIID const IID & +#else +#define REFIID const IID * +#endif + + +/*! The IUnknown interface */ +DECLARE_INTERFACE(IUnknown) +{ + STDMETHOD(HRESULT,QueryInterface) (THIS_ REFIID iid, void **ppv) PURE; + STDMETHOD(ULONG,AddRef) (THIS) PURE; + STDMETHOD(ULONG,Release) (THIS) PURE; +}; +\endverbatim + +without macro expansion doxygen will get confused, but we may not want to +expand the REFIID macro, because it is documented and the user that reads +the documentation should use it when implementing the interface. + +By setting the following in the config file: + +\verbatim +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = YES +EXPAND_ONLY_PREDEF = YES +PREDEFINED = "DECLARE_INTERFACE(name)=class name" \ + "STDMETHOD(result,name)=virtual result name" \ + "PURE= = 0" \ + THIS_= \ + THIS= \ + __cplusplus +\endverbatim + +we can make sure that the proper result is fed to doxygen's parser: +\verbatim +/*! A reference to an IID */ +#define REFIID + +/*! The IUnknown interface */ +class IUnknown +{ + virtual HRESULT QueryInterface ( REFIID iid, void **ppv) = 0; + virtual ULONG AddRef () = 0; + virtual ULONG Release () = 0; +}; +\endverbatim + +Note that the \ref cfg_predefined "PREDEFINED" tag accepts function +like macro definitions +(like \c DECLARE_INTERFACE ), normal macro +substitutions (like \c PURE and \c THIS) and plain +defines (like \c __cplusplus). + +Note also that preprocessor definitions that are normally defined +automatically by the preprocessor (like \c __cplusplus), have to be defined +by hand with doxygen's parser (this is done because these defines +are often platform/compiler specific). + +In some cases you may want to substitute a macro name or function by +something else without exposing the result to further macro substitution. +You can do this but using the <code>:=</code> operator instead of +<code>=</code> + +As an example suppose we have the following piece of code: +\verbatim +#define QList QListT +class QListT +{ +}; +\endverbatim + +Then the only way to get doxygen interpret this as a class definition +for class QList is to define: +\verbatim +PREDEFINED = QListT:=QList +\endverbatim + +Here is an example provided by Valter Minute and Reyes Ponce that helps +doxygen to wade through the boilerplate code in Microsoft's ATL \& MFC +libraries: + +\verbatim +PREDEFINED = "DECLARE_INTERFACE(name)=class name" \ + "STDMETHOD(result,name)=virtual result name" \ + "PURE= = 0" \ + THIS_= \ + THIS= \ + DECLARE_REGISTRY_RESOURCEID=// \ + DECLARE_PROTECT_FINAL_CONSTRUCT=// \ + "DECLARE_AGGREGATABLE(Class)= " \ + "DECLARE_REGISTRY_RESOURCEID(Id)= " \ + DECLARE_MESSAGE_MAP= \ + BEGIN_MESSAGE_MAP=/* \ + END_MESSAGE_MAP=*/// \ + BEGIN_COM_MAP=/* \ + END_COM_MAP=*/// \ + BEGIN_PROP_MAP=/* \ + END_PROP_MAP=*/// \ + BEGIN_MSG_MAP=/* \ + END_MSG_MAP=*/// \ + BEGIN_PROPERTY_MAP=/* \ + END_PROPERTY_MAP=*/// \ + BEGIN_OBJECT_MAP=/* \ + END_OBJECT_MAP()=*/// \ + DECLARE_VIEW_STATUS=// \ + "STDMETHOD(a)=HRESULT a" \ + "ATL_NO_VTABLE= " \ + "__declspec(a)= " \ + BEGIN_CONNECTION_POINT_MAP=/* \ + END_CONNECTION_POINT_MAP=*/// \ + "DECLARE_DYNAMIC(class)= " \ + "IMPLEMENT_DYNAMIC(class1, class2)= " \ + "DECLARE_DYNCREATE(class)= " \ + "IMPLEMENT_DYNCREATE(class1, class2)= " \ + "IMPLEMENT_SERIAL(class1, class2, class3)= " \ + "DECLARE_MESSAGE_MAP()= " \ + TRY=try \ + "CATCH_ALL(e)= catch(...)" \ + END_CATCH_ALL= \ + "THROW_LAST()= throw"\ + "RUNTIME_CLASS(class)=class" \ + "MAKEINTRESOURCE(nId)=nId" \ + "IMPLEMENT_REGISTER(v, w, x, y, z)= " \ + "ASSERT(x)=assert(x)" \ + "ASSERT_VALID(x)=assert(x)" \ + "TRACE0(x)=printf(x)" \ + "OS_ERR(A,B)={ #A, B }" \ + __cplusplus \ + "DECLARE_OLECREATE(class)= " \ + "BEGIN_DISPATCH_MAP(class1, class2)= " \ + "BEGIN_INTERFACE_MAP(class1, class2)= " \ + "INTERFACE_PART(class, id, name)= " \ + "END_INTERFACE_MAP()=" \ + "DISP_FUNCTION(class, name, function, result, id)=" \ + "END_DISPATCH_MAP()=" \ + "IMPLEMENT_OLECREATE2(class, name, id1, id2, id3, id4,\ + id5, id6, id7, id8, id9, id10, id11)=" +\endverbatim + +As you can see doxygen's preprocessor is quite powerful, but if you want +even more flexibility you can always write an input filter and specify it +after the \ref cfg_input_filter "INPUT_FILTER" tag. + +If you are unsure what the effect of doxygen's preprocessing will be +you can run doxygen as follows: +\verbatim + doxygen -d Preprocessor +\endverbatim +This will instruct doxygen to dump the input sources to standard output after +preprocessing has been done (Hint: set <code>QUIET = YES</code> and +<code>WARNINGS = NO</code> in the configuration file to disable any other +output). + +\htmlonly +Go to the <a href="external.html">next</a> section or return to the + <a href="index.html">index</a>. +\endhtmlonly + +*/ diff --git a/trunk/doc/searching.doc b/trunk/doc/searching.doc new file mode 100644 index 0000000..b3e4fd9 --- /dev/null +++ b/trunk/doc/searching.doc @@ -0,0 +1,158 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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 searching Searching + +Doxygen indexes your source code in various ways to make it easier +to navigate and find what you are looking for. +There are also situations however where you want to +search for something by keyword rather than browse for it. + +HTML browsers by default have no search capabilities that work across multiple +pages, so either doxygen or external tools need to help to facilitate +this feature. + +Doxygen has 6 different ways to add searching to the HTML output, each of which +has its own advantages and disadvantages: + +<h2>1. Client side searching</h2> + The easiest way to enable searching is to enable the built-in client + side search engine. This engine is implemented using Javascript and DHTML + only and runs entirely on the clients browser. So no additional tooling is + required to make it work. + + To enable it set + \ref cfg_searchengine "SEARCHENGINE" to \c YES in the config file + and make sure \ref cfg_server_based_search "SERVER_BASED_SEARCH" is set + to \c NO. + + An additional advantage of this method is that it provides live + searching, i.e. the search results are presented and adapted as you type. + + This method also has its drawbacks: it is limited to searching for symbols + only. It does not provide full text search capabilities, and it does not + scale well to very large projects (then searching becomes very slow). + +<h2>2. Server side searching</h2> + If you plan to put the HTML documentation on a web server, and that + web server has the capability to process PHP code, then you can also use + doxygen's built-in server side search engine. + + To enable this set both + \ref cfg_searchengine "SEARCHENGINE" and + \ref cfg_server_based_search "SERVER_BASED_SEARCH" to \c YES in the config + file. + + Advantages over the client side search engine are that it provides full + text search and it scales well to large projects. + + Disadvantages are that it does not work locally (i.e. using a file:// URL) + and that it does not provide live search capabilities. + +<h2>3. Windows Compiled HTML Help</h2> + If you are running doxygen on Windows, then you can make a + compiled HTML Help file (.chm) out of the HTML files produced by doxygen. + This is a single file containing all HTML files and it also includes a + search index. There are viewers for this format on many platforms, + and Windows even supports it natively. + + To enable this set \ref cfg_generate_htmlhelp "GENERATE_HTMLHELP" to \c YES + in the config file. To let doxygen compile the HTML Help file for you, + you also need to specify the path to the HTML compiler (hhc.exe) using the + \ref cfg_hhc_location "HHC_LOCATION" config option and the name of the + resulting CHM file using \ref cfg_chm_file "CHM_FILE". + + An advantage of this method is that the result is a single file that can + easily be distributed. It also provides full text search. + + Disadvantages are that compiling the CHM file only works on Windows + and requires Microsoft's HTML compiler, which is not very actively supported + by Microsoft. Although the tool works fine for most people, it can + sometimes crash for no apparent reason (how typical). + +<h2>4. Mac OS X Doc Sets</h2> + If you are running doxygen on Mac OS X 10.5 or higher, + then you can make a "doc set" out of the HTML files produced by doxygen. + A doc set consists of a single directory with a special structure + containing the HTML files along with a precompiled search index. + A doc set can be embedded in Xcode (the integrated development environment + provided by Apple). + + To enable the creation of doc sets set \ref cfg_generate_docset "GENERATE_DOCSET" + to \c YES in the config file. There are a couple of other doc set related + options you may want to set. After doxygen has finished you will find + a Makefile in the HTML output directory. Running "make install" on this + Makefile will compile and install the doc set. + See <a href="http://developer.apple.com/tools/creatingdocsetswithdoxygen.html">this + article</a> for more info. + + Advantage of this method is that it nicely integrates with the Xcode + development environment, allowing for instance to click on an identifier + in the editor and jump to the corresponding section in the doxygen + documentation. + + Disadvantage is that it only works in combination with Xcode on MacOSX. + +<h2>5. Qt Compressed Help</h2> + If you develop for or want to install the Qt application framework, + you will get an application + called <a href="http://doc.trolltech.com/4.6/assistant-manual.html">Qt assistant</a>. + This is a help viewer for Qt Compressed Help files (.qch). + + To enable this feature set \ref cfg_generate_qhp "GENERATE_QHP" to \c YES. + You also need to fill in the other Qt help related options, such as + \ref cfg_qhp_namespace "QHP_NAMESPACE", + \ref cfg_qhg_location "QHG_LOCATION", + \ref cfg_qhp_virtual_folder "QHP_VIRTUAL_FOLDER". + See <a href="http://doc.trolltech.com/qq/qq28-qthelp.html#htmlfilesandhelpprojects">this article</a> + for more info. + + Feature wise the Qt compressed help feature is comparable with the CHM + output, with the additional advantage that compiling the QCH file is + not limited to Windows. + + Disadvantage is that it requires setting up a Qt 4.5 (or better) for + each user, or distributing the Qt help assistant along with + the documentation, which is complicated by the fact that it is not + available as a separate package at this moment. + +<h2>6. Eclipse Help Plugin</h2> + If you use eclipse, you can embed the documentation generated by + doxygen as a help plugin. It will then appear as a topic in the help + browser that can be started from "Help contents" in the Help menu. + Eclipse will generate a search index for the documentation when you + first search for an keyword. + + To enable the help plugin set + \ref cfg_generate_eclipsehelp "GENERATE_ECLIPSEHELP" to \c YES, + and define a unique identifier for your project via + \ref cfg_eclipse_doc_id "ECLIPSE_DOC_ID", i.e.: +\verbatim + GENERATE_ECLIPSEHELP = YES + ECLIPSE_DOC_ID = com.yourcompany.yourproject +\endverbatim + then create the \c com.yourcompany.yourproject directory (so with + the same name as the value of \c ECLIPSE_DOC_ID) in the + \c plugin directory of eclipse and after doxygen completes copy + to contents of the help output directory to + the \c com.yourcompany.yourproject directory. + Then restart eclipse to make let it find the new plugin. + + The eclipse help plugin provides similar functionality as the + Qt compressed help or CHM output, but it does require that Eclipse is + installed and running. + +*/ diff --git a/trunk/doc/starting.doc b/trunk/doc/starting.doc new file mode 100644 index 0000000..4e5481e --- /dev/null +++ b/trunk/doc/starting.doc @@ -0,0 +1,328 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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 starting Getting started +\tableofcontents + +The executable \c doxygen is the main program that parses the sources and +generates the documentation. See section \ref doxygen_usage for more +detailed usage information. + +Optionally, the executable \c doxywizard can be used, which is a +\ref doxywizard_usage "graphical front-end" for editing the configuration file +that is used by doxygen and for running doxygen in a graphical environment. +For Mac OS X doxywizard will be started by clicking on the Doxygen application +icon. + +The following figure shows the relation between the tools and the flow +of information between them (it looks complex but that's only because it +tries to be complete): + +\image html infoflow.png "Doxygen information flow" +\image latex infoflow.eps "Doxygen information flow" width=14cm + +\section step0 Step 0: Check if doxygen supports your programming language + +First, assure that your programming language has a reasonable chance of being +recognized by Doxygen. These languages are supported by default: C, C++, C#, +Objective-C, IDL, Java, VHDL, PHP, Python, Tcl, Fortran, and D. It +is possible to configure certain file type extensions to use certain parsers: +see the \ref cfg_extension_mapping "Configuration/ExtensionMappings" for details. +Also, completely different languages can be supported by using preprocessor +programs: see the <a href="http://www.doxygen.org/helpers.html">Helpers page</a> +for details. + +\section step1 Step 1: Creating a configuration file + +Doxygen uses a configuration file to determine all of its settings. +Each project should get its own configuration file. A project can consist +of a single source file, but can also be an entire source tree that is +recursively scanned. + +To simplify the creation of a configuration file, doxygen can create a +template configuration file for you. To do this call \c doxygen +from the command line with the \c -g option: +\verbatim +doxygen -g <config-file> +\endverbatim + +where \<config-file\> is the name of the configuration file. If you omit +the file name, a file named \c Doxyfile will be created. If a file with the +name \<config-file\> already exists, doxygen will rename it to +\<config-file\>.bak before generating the configuration template. +If you use <code>-</code> (i.e. the minus sign) as the file name then +doxygen will try to read the configuration file from standard +input (<code>stdin</code>), which can be useful for scripting. + +The configuration file has a format that is similar to that of a (simple) +Makefile. It consists of a number of assignments (tags) of the form: + +<tt>TAGNAME = VALUE</tt> or <br> +<tt>TAGNAME = VALUE1 VALUE2 ... </tt><br> + +You can probably leave the values of most tags in a generated template +configuration file to their default value. See section \ref config for +more details about the configuration file. + +If you do not wish to edit the config file with a text editor, you should +have a look at \ref doxywizard_usage "doxywizard", which is a GUI +front-end that can create, read and write doxygen configuration files, +and allows setting configuration options by entering them via dialogs. + +For a small project consisting of a few C and/or C++ source +and header files, you can leave +\ref cfg_input "INPUT" tag empty and doxygen will search for sources in +the current directory. + +If you have a larger project consisting of a source directory or tree +you should assign the root directory or +directories to the \ref cfg_input "INPUT" tag, and add one or more file +patterns to the \ref cfg_file_patterns "FILE_PATTERNS" tag +(for instance `*.cpp *.h`). Only files that match one of the +patterns will be parsed (if the patterns are omitted a list of +typical patterns is used for the types of files doxygen supports). +For recursive parsing of a source tree you must set +the \ref cfg_recursive "RECURSIVE" tag to \c YES. To further fine-tune the +list of files that is parsed the \ref cfg_exclude "EXCLUDE" and +\ref cfg_exclude_patterns "EXCLUDE_PATTERNS" tags can be used. +To omit all \c test directories from a source tree for instance, one could use: + +\verbatim EXCLUDE_PATTERNS = */test/* +\endverbatim + +Doxygen looks at the file's extension to determine how to parse a file, +using the following table: + +Extension | Language +---------:|--------- +.idl |IDL +.ddl |IDL +.odl |IDL +.java |Java +.cs |C# +.d |D +.php |PHP +.php4 |PHP +.php5 |PHP +.inc |PHP +.phtml |PHP +.m |Objective-C +.M |Objective-C +.mm |Objective-C +.py |Python +.f |Fortran +.for |Fortran +.f90 |Fortran +.vhd |VHDL +.vhdl |VHDL +.tcl |TCL +.ucf |VHDL +.qsf |VHDL +.md |Markdown +.markdown |Markdown + +Any other extension is parsed as if it is a C/C++ file. + +\anchor extract_all +If you start using doxygen for an existing project (thus without any +documentation that doxygen is aware of), you can still get an idea of +what the structure is and how the documented result would look like. +To do so, you must set +the \ref cfg_extract_all "EXTRACT_ALL" tag in the configuration file +to \c YES. Then, doxygen will pretend everything in your sources is documented. +Please note that as a consequence warnings about undocumented members +will not be generated as long as \ref cfg_extract_all "EXTRACT_ALL" is +set to \c YES. + +To analyze an existing piece of software it is useful to cross-reference +a (documented) entity with its definition in the source files. Doxygen will +generate such cross-references if you set +the \ref cfg_source_browser "SOURCE_BROWSER" tag to \c YES. +It can also include the sources directly into the documentation by setting +\ref cfg_inline_sources "INLINE_SOURCES" to \c YES (this can be handy for +code reviews for instance). + +\section step2 Step 2: Running doxygen + +To generate the documentation you can now enter: +\verbatim +doxygen <config-file> +\endverbatim + +Depending on your settings doxygen will create \c html, \c rtf, +\c latex, \c xml and/or \c man directories inside the output directory. +As the names suggest these directories contain the +generated documentation in HTML, RTF, \f$\mbox{\LaTeX}\f$, XML and +Unix-Man page format. + +The default output directory is the directory in which \c doxygen +is started. The root directory to which the output is written can be changed +using the \ref cfg_output_directory "OUTPUT_DIRECTORY". The format specific +directory within the output directory can be selected using the +\ref cfg_html_output "HTML_OUTPUT", \ref cfg_rtf_output "RTF_OUTPUT", +\ref cfg_latex_output "LATEX_OUTPUT", \ref cfg_xml_output "XML_OUTPUT", +and \ref cfg_man_output "MAN_OUTPUT" +tags of the configuration file. If the output directory does not exist, +\c doxygen will try to create it for you (but it will \e not try to create +a whole path recursively, like <code>mkdir -p</code> does). + +\subsection html_out HTML output +\addindex browser +The generated HTML documentation can be viewed by pointing a HTML browser +to the \c index.html file in the \c html directory. For the best results +a browser that supports cascading style sheets (CSS) should be used +(I'm using Mozilla Firefox, Google Chrome, Safari, and sometimes +IE8, IE9, and Opera to test the generated output). + +Some of the features the HTML section (such as +\ref cfg_generate_treeview "GENERATE_TREEVIEW" or the search engine) +require a browser that supports Dynamic HTML and Javascript enabled. + +\subsection latex_out LaTeX output +\addindex LaTeX +The generated \f$\mbox{\LaTeX}\f$ documentation must first be compiled by +a \f$\mbox{\LaTeX}\f$ compiler (I use a recent teTeX distribution for Linux +and MacOSX and MikTex for Windows). +To simplify the process of compiling the generated +documentation, \c doxygen writes a \c Makefile into the \c latex directory +(on the Windows platform also a \c make.bat batch file is generated). + +The contents and targets in the \c Makefile depend on the setting of +\ref cfg_use_pdflatex "USE_PDFLATEX". If it is disabled (set to \c NO), then +typing \c make in the \c latex directory a \c dvi file called \c refman.dvi +will be generated. This file can then be viewed using \c xdvi or +converted into a PostScript file \c refman.ps by +typing `make ps` (this requires `dvips`). + +To put 2 pages on one physical page use `make ps_2on1` instead. +The resulting PostScript file can be send to a PostScript +printer. If you do not have a PostScript printer, you can try to use +ghostscript to convert PostScript into something your printer understands. + +Conversion to PDF is also possible if you have installed the ghostscript +interpreter; just type `make pdf` (or `make pdf_2on1`). + +To get the best results for PDF output you should set +the \ref cfg_pdf_hyperlinks "PDF_HYPERLINKS" +and \ref cfg_use_pdflatex "USE_PDFLATEX" tags to \c YES. +In this case the \c Makefile will only contain a target to build +\c refman.pdf directly. + +\subsection rtf_out RTF output +\addindex RTF +Doxygen combines the RTF output to a single file called refman.rtf. This +file is optimized for importing into the Microsoft Word. Certain information +is encoded using so called fields. To show the actual value you need to +select all (Edit - select all) and then toggle fields (right click and select +the option from the drop down menu). + +\subsection xml_out XML output +\addindex XML +The XML output consists of a structured "dump" of the information gathered +by doxygen. Each compound (class/namespace/file/...) has its own XML file +and there is also an index file called `index.xml`. + +A file called `combine.xslt` +XSLT script is also generated and can be used to combine all XML files +into a single file. + +Doxygen also generates two XML schema files `index.xsd` +(for the index file) and `compound.xsd` (for the compound files). +This schema file describes the possible elements, their attributes and +how they are structured, i.e. it the describes the grammar of the XML +files and can be used for validation or to steer XSLT scripts. + +In the `addon/doxmlparser` directory you can find a parser library for reading +the XML output produced by doxygen in an incremental way +(see `addon/doxmlparser/include/doxmlintf.h` for the interface of the library) + +\subsection man_out Man page output +The generated man pages can be viewed using the \c man program. You do need +to make sure the man directory is in the man path (see the \c MANPATH +environment variable). Note that there are some limitations to the +capabilities of the man page format, so some information +(like class diagrams, cross references and formulas) will be lost. + +\section step3 Step 3: Documenting the sources + +Although documenting the sources is presented as step 3, in a new project +this should of course be step 1. Here I assume +you already have some code and you want doxygen to generate a nice document +describing the API and maybe the internals and some related design +documentation as well. + +If the \ref cfg_extract_all "EXTRACT_ALL" option is set to \c NO in the +configuration file (the default), then doxygen will only generate +documentation for \e documented entities. So +how do you document these? For members, classes and namespaces there are +basically two options: +1. Place a \e special documentation block in front of the declaration or + definition of the member, class or namespace. For file, class and namespace + members it is also allowed to place the documentation directly after the + member. + + See section \ref specialblock to learn more about special + documentation blocks. +2. Place a special documentation block somewhere else (another file or + another location) \e and put a <em>structural command</em> in the + documentation block. A structural command links a documentation block + to a certain entity that can be documented (e.g. a member, class, + namespace or file). + + See section \ref structuralcommands to learn more + about structural commands. + +The advantage of the first option is that you do not have to repeat the +name of the entity. + +Files can only be documented using the second option, since there is +no way to put a documentation block before a file. Of course, file members +(functions, variables, typedefs, defines) do not need an explicit +structural command; just putting a special documentation block in front or +behind them will work fine. + +The text inside a special documentation block is parsed +before it is written to the HTML and/or \f$\mbox{\LaTeX}\f$ output files. + +\addindex parsing +During parsing the following steps take place: +- Markdown formatting is replaced by corresponding HTML or special + commands. +- The special commands inside the documentation are executed. See + section \ref commands for an overview of all commands. +- If a line starts with some whitespace followed by one or more asterisks + (`*`) and then optionally more whitespace, + then all whitespace and asterisks are removed. +- All resulting blank lines are treated as a paragraph separators. + This saves you from placing new-paragraph commands yourself + in order to make the generated documentation readable. +- Links are created for words corresponding to documented classes + (unless the word is preceded by a \%; then the word will not be linked and + the \% sign is removed). +- Links to members are created when certain patterns are found in the + text. See section \ref autolink + for more information on how the automatic link generation works. +- HTML tags that are in the documentation are interpreted and converted + to \f$\mbox{\LaTeX}\f$ equivalents for the \f$\mbox{\LaTeX}\f$ output. + See section \ref htmlcmds for an overview of all supported HTML tags. + +\htmlonly +Go to the <a href="docblocks.html">next</a> section or return to the + <a href="index.html">index</a>. +\endhtmlonly + +*/ + diff --git a/trunk/doc/translator.py b/trunk/doc/translator.py new file mode 100644 index 0000000..5a78ee2 --- /dev/null +++ b/trunk/doc/translator.py @@ -0,0 +1,2012 @@ +"""Script to generate reports on translator classes from Doxygen sources. + + The main purpose of the script is to extract the information from sources + related to internationalization (the translator classes). It uses the + information to generate documentation (language.doc, + translator_report.txt) from templates (language.tpl, maintainers.txt). + + Simply run the script without parameters to get the reports and + documentation for all supported languages. If you want to generate the + translator report only for some languages, pass their codes as arguments + to the script. In that case, the language.doc will not be generated. + Example: + + python translator.py en nl cz + + Originally, the script was written in Perl and was known as translator.pl. + The last Perl version was dated 2002/05/21 (plus some later corrections) + + $Id$ + + Petr Prikryl (prikrylp@skil.cz) + + History: + -------- + 2002/05/21 - This was the last Perl version. + 2003/05/16 - List of language marks can be passed as arguments. + 2004/01/24 - Total reimplementation started: classes TrManager, and Transl. + 2004/02/05 - First version that produces translator report. No language.doc yet. + 2004/02/10 - First fully functional version that generates both the translator + report and the documentation. It is a bit slower than the + Perl version, but is much less tricky and much more flexible. + It also solves some problems that were not solved by the Perl + version. The translator report content should be more useful + for developers. + 2004/02/11 - Some tuning-up to provide more useful information. + 2004/04/16 - Added new tokens to the tokenizer (to remove some warnings). + 2004/05/25 - Added from __future__ import generators not to force Python 2.3. + 2004/06/03 - Removed dependency on textwrap module. + 2004/07/07 - Fixed the bug in the fill() function. + 2004/07/21 - Better e-mail mangling for HTML part of language.doc. + - Plural not used for reporting a single missing method. + - Removal of not used translator adapters is suggested only + when the report is not restricted to selected languages + explicitly via script arguments. + 2004/07/26 - Better reporting of not-needed adapters. + 2004/10/04 - Reporting of not called translator methods added. + 2004/10/05 - Modified to check only doxygen/src sources for the previous report. + 2005/02/28 - Slight modification to generate "mailto.txt" auxiliary file. + 2005/08/15 - Doxygen's root directory determined primarily from DOXYGEN + environment variable. When not found, then relatively to the script. + 2007/03/20 - The "translate me!" searched in comments and reported if found. + 2008/06/09 - Warning when the MAX_DOT_GRAPH_HEIGHT is still part of trLegendDocs(). + 2009/05/09 - Changed HTML output to fit it with XHTML DTD + 2009/09/02 - Added percentage info to the report (implemented / to be implemented). + 2010/02/09 - Added checking/suggestion 'Reimplementation using UTF-8 suggested. + 2010/03/03 - Added [unreachable] prefix used in maintainers.txt. + 2010/05/28 - BOM skipped; minor code cleaning. + 2010/05/31 - e-mail mangled already in maintainers.txt + 2010/08/20 - maintainers.txt to UTF-8, related processin of unicode strings + - [any mark] introduced instead of [unreachable] only + - marks hihglighted in HTML + 2010/08/30 - Highlighting in what will be the table in langhowto.html modified. + 2010/09/27 - The underscore in \latexonly part of the generated language.doc + was prefixed by backslash (was LaTeX related error). + """ + +from __future__ import generators +import codecs +import os +import re +import sys + + +def fill(s): + """Returns string formated to the wrapped paragraph multiline string. + + Replaces whitespaces by one space and then uses he textwrap.fill().""" + + # Replace all whitespace by spaces, remove whitespaces that are not + # necessary, strip the left and right whitespaces, and break the string + # to list of words. + rexWS = re.compile(r'\s+') + lst = rexWS.sub(' ', s).strip().split() + + # If the list is not empty, put the words together and form the lines + # of maximum 70 characters. Build the list of lines. + lines = [] + if lst: + line = lst.pop(0) # no separation space in front of the first word + for word in lst: + if len(line) + len(word) < 70: + line += ' ' + word + else: + lines.append(line) # another full line formed + line = word # next line started + lines.append(line) # the last line + return '\n'.join(lines) + + +# The following function dedent() is the verbatim copy from the textwrap.py +# module. The textwrap.py was introduced in Python 2.3. To make this script +# working also in older Python versions, I have decided to copy it. +# Notice that the textwrap.py is copyrighted: +# +# Copyright (C) 1999-2001 Gregory P. Ward. +# Copyright (C) 2002, 2003 Python Software Foundation. +# Written by Greg Ward <gward@python.net> +# +# The explicit permission to use the code here was sent by Guido van Rossum +# (4th June, 2004). +# +def dedent(text): + """dedent(text : string) -> string + + Remove any whitespace than can be uniformly removed from the left + of every line in `text`. + + This can be used e.g. to make triple-quoted strings line up with + the left edge of screen/whatever, while still presenting it in the + source code in indented form. + + For example: + + def test(): + # end first line with \ to avoid the empty line! + s = '''\ + hello + world + ''' + print repr(s) # prints ' hello\n world\n ' + print repr(dedent(s)) # prints 'hello\n world\n' + """ + lines = text.expandtabs().split('\n') + margin = None + for line in lines: + content = line.lstrip() + if not content: + continue + indent = len(line) - len(content) + if margin is None: + margin = indent + else: + margin = min(margin, indent) + + if margin is not None and margin > 0: + for i in range(len(lines)): + lines[i] = lines[i][margin:] + + return '\n'.join(lines) + + +class Transl: + """One instance is build for each translator. + + The abbreviation of the source file--part after 'translator_'--is used as + the identification of the object. The empty string is used for the + abstract Translator class from translator.h. The other information is + extracted from inside the source file.""" + + def __init__(self, fname, manager): + """Bind to the manager and initialize.""" + + # Store the filename and the reference to the manager object. + self.fname = fname + self.manager = manager + + # The instance is responsible for loading the source file, so it checks + # for its existence and quits if something goes wrong. + if not os.path.isfile(fname): + sys.stderr.write("\a\nFile '%s' not found!\n" % fname) + sys.exit(1) + + # Initialize the other collected information. + self.classId = None + self.baseClassId = None + self.readableStatus = None # 'up-to-date', '1.2.3', '1.3', etc. + self.status = None # '', '1.2.03', '1.3.00', etc. + self.lang = None # like 'Brasilian' + self.langReadable = None # like 'Brasilian Portuguese' + self.note = None # like 'should be cleaned up' + self.prototypeDic = {} # uniPrototype -> prototype + self.translateMeText = 'translate me!' + self.translateMeFlag = False # comments with "translate me!" found + self.txtMAX_DOT_GRAPH_HEIGHT_flag = False # found in string in trLegendDocs() + self.obsoleteMethods = None # list of prototypes to be removed + self.missingMethods = None # list of prototypes to be implemented + self.implementedMethods = None # list of implemented required methods + self.adaptMinClass = None # The newest adapter class that can be used + self.isDecodedTranslator = None # Flag related to internal usage of UTF-8 + + def __tokenGenerator(self): + """Generator that reads the file and yields tokens as 4-tuples. + + The tokens have the form (tokenId, tokenString, lineNo). The + last returned token has the form ('eof', None, None). When trying + to access next token afer that, the exception would be raised.""" + + # Set the dictionary for recognizing tokenId for keywords, separators + # and the similar categories. The key is the string to be recognized, + # the value says its token identification. + tokenDic = { 'class': 'class', + 'const': 'const', + 'public': 'public', + 'protected': 'protected', + 'private': 'private', + 'static': 'static', + 'virtual': 'virtual', + ':': 'colon', + ';': 'semic', + ',': 'comma', + '[': 'lsqbra', + ']': 'rsqbra', + '(': 'lpar', + ')': 'rpar', + '{': 'lcurly', + '}': 'rcurly', + '=': 'assign', + '*': 'star', + '&': 'amp', + '+': 'plus', + '-': 'minus', + '!': 'excl', + '?': 'qmark', + '<': 'lt', + '>': 'gt', + "'": 'quot', + '"': 'dquot', + '.': 'dot', + '%': 'perc', + '~': 'tilde', + '^': 'caret', + } + + # Regular expression for recognizing identifiers. + rexId = re.compile(r'^[a-zA-Z]\w*$') + + # Open the file for reading and extracting tokens until the eof. + # Initialize the finite automaton. + f = open(self.fname) + lineNo = 0 + line = '' # init -- see the pos initialization below + linelen = 0 # init + pos = 100 # init -- pos after the end of line + status = 0 + + tokenId = None # init + tokenStr = '' # init -- the characters will be appended. + tokenLineNo = 0 + + while status != 777: + + # Get the next character. Read next line first, if necessary. + if pos < linelen: + c = line[pos] + else: + lineNo += 1 + line = f.readline() + if line.startswith('\xef\xbb\xbf'): + line = line[3:] # skip the BOM + linelen = len(line) + pos = 0 + if line == '': # eof + status = 777 + else: + c = line[pos] + + # Consume the character based on the status + + if status == 0: # basic status + + # This is the initial status. If tokenId is set, yield the + # token here and only here (except when eof is found). + # Initialize the token variables after the yield. + if tokenId: + # If it is an unknown item, it can still be recognized + # here. Keywords and separators are the example. + if tokenId == 'unknown': + if tokenDic.has_key(tokenStr): + tokenId = tokenDic[tokenStr] + elif tokenStr.isdigit(): + tokenId = 'num' + elif rexId.match(tokenStr): + tokenId = 'id' + else: + msg = '\aWarning: unknown token "' + tokenStr + '"' + msg += '\tfound on line %d' % tokenLineNo + msg += ' in "' + self.fname + '".\n' + sys.stderr.write(msg) + + yield (tokenId, tokenStr, tokenLineNo) + + # If it is a comment that contains the self.translateMeText + # string, set the flag -- the situation will be reported. + if tokenId == 'comment' and tokenStr.find(self.translateMeText) >= 0: + self.translateMeFlag = True + + tokenId = None + tokenStr = '' + tokenLineNo = 0 + + # Now process the character. When we just skip it (spaces), + # stay in this status. All characters that will be part of + # some token cause moving to the specific status. And only + # when moving to the status == 0 (or the final state 777), + # the token is yielded. With respect to that the automaton + # behaves as Moore's one (output bound to status). When + # collecting tokens, the automaton is the Mealy's one + # (actions bound to transitions). + if c.isspace(): + pass # just skip whitespace characters + elif c == '/': # Possibly comment starts here, but + tokenId = 'unknown' # it could be only a slash in code. + tokenStr = c + tokenLineNo = lineNo + status = 1 + elif c == '#': + tokenId = 'preproc' # preprocessor directive + tokenStr = c + tokenLineNo = lineNo + status = 5 + elif c == '"': # string starts here + tokenId = 'string' + tokenStr = c + tokenLineNo = lineNo + status = 6 + elif c == "'": # char literal starts here + tokenId = 'charlit' + tokenStr = c + tokenLineNo = lineNo + status = 8 + elif tokenDic.has_key(c): # known one-char token + tokenId = tokenDic[c] + tokenStr = c + tokenLineNo = lineNo + # stay in this state to yield token immediately + else: + tokenId = 'unknown' # totally unknown + tokenStr = c + tokenLineNo = lineNo + status = 333 + + pos += 1 # move position in any case + + elif status == 1: # possibly a comment + if c == '/': # ... definitely the C++ comment + tokenId = 'comment' + tokenStr += c + pos += 1 + status = 2 + elif c == '*': # ... definitely the C comment + tokenId = 'comment' + tokenStr += c + pos += 1 + status = 3 + else: + status = 0 # unrecognized, don't move pos + + elif status == 2: # inside the C++ comment + if c == '\n': # the end of C++ comment + status = 0 # yield the token + else: + tokenStr += c # collect the C++ comment + pos += 1 + + elif status == 3: # inside the C comment + if c == '*': # possibly the end of the C comment + tokenStr += c + status = 4 + else: + tokenStr += c # collect the C comment + pos += 1 + + elif status == 4: # possibly the end of the C comment + if c == '/': # definitely the end of the C comment + tokenStr += c + status = 0 # yield the token + elif c == '*': # more stars inside the comment + tokenStr += c + else: + tokenStr += c # this cannot be the end of comment + status = 3 + pos += 1 + + elif status == 5: # inside the preprocessor directive + if c == '\n': # the end of the preproc. command + status = 0 # yield the token + else: + tokenStr += c # collect the preproc + pos += 1 + + elif status == 6: # inside the string + if c == '\\': # escaped char inside the string + tokenStr += c + status = 7 + elif c == '"': # end of the string + tokenStr += c + status = 0 + else: + tokenStr += c # collect the chars of the string + pos += 1 + + elif status == 7: # escaped char inside the string + tokenStr += c # collect the char of the string + status = 6 + pos += 1 + + elif status == 8: # inside the char literal + tokenStr += c # collect the char of the literal + status = 9 + pos += 1 + + elif status == 9: # end of char literal expected + if c == "'": # ... and found + tokenStr += c + status = 0 + pos += 1 + else: + tokenId = 'error' # end of literal was expected + tokenStr += c + status = 0 + + elif status == 333: # start of the unknown token + if c.isspace(): + pos += 1 + status = 0 # tokenId may be determined later + elif tokenDic.has_key(c): # separator, don't move pos + status = 0 + else: + tokenStr += c # collect + pos += 1 + + # We should have finished in the final status. If some token + # have been extracted, yield it first. + assert(status == 777) + if tokenId: + yield (tokenId, tokenStr, tokenLineNo) + tokenId = None + tokenStr = '' + tokenLineNo = 0 + + # The file content is processed. Close the file. Then always yield + # the eof token. + f.close() + yield ('eof', None, None) + + + def __collectClassInfo(self, tokenIterator): + """Collect the information about the class and base class. + + The tokens including the opening left curly brace of the class are + consumed.""" + + status = 0 # initial state + + while status != 777: # final state + + # Always assume that the previous tokens were processed. Get + # the next one. + tokenId, tokenStr, tokenLineNo = tokenIterator.next() + + # Process the token and never return back. + if status == 0: # waiting for the 'class' keyword. + if tokenId == 'class': + status = 1 + + elif status == 1: # expecting the class identification + if tokenId == 'id': + self.classId = tokenStr + status = 2 + else: + self.__unexpectedToken(status, tokenId, tokenLineNo) + + elif status == 2: # expecting the curly brace or base class info + if tokenId == 'lcurly': + status = 777 # correctly finished + elif tokenId == 'colon': + status = 3 + else: + self.__unexpectedToken(status, tokenId, tokenLineNo) + + elif status == 3: # expecting the 'public' in front of base class id + if tokenId == 'public': + status = 4 + else: + self.__unexpectedToken(status, tokenId, tokenLineNo) + + elif status == 4: # expecting the base class id + if tokenId == 'id': + self.baseClassId = tokenStr + status = 5 + else: + self.__unexpectedToken(status, tokenId, tokenLineNo) + + elif status == 5: # expecting the curly brace and quitting + if tokenId == 'lcurly': + status = 777 # correctly finished + elif tokenId == 'comment': + pass + else: + self.__unexpectedToken(status, tokenId, tokenLineNo) + + # Extract the status of the TranslatorXxxx class. The readable form + # will be used in reports the status form is a string that can be + # compared lexically (unified length, padding with zeros, etc.). + if self.baseClassId: + lst = self.baseClassId.split('_') + if lst[0] == 'Translator': + self.readableStatus = 'up-to-date' + self.status = '' + elif lst[0] == 'TranslatorAdapter': + self.status = lst[1] + '.' + lst[2] + self.readableStatus = self.status + if len(lst) > 3: # add the last part of the number + self.status += '.' + ('%02d' % int(lst[3])) + self.readableStatus += '.' + lst[3] + else: + self.status += '.00' + elif lst[0] == 'TranslatorEnglish': + # Obsolete or Based on English. + if self.classId[-2:] == 'En': + self.readableStatus = 'English based' + self.status = 'En' + else: + self.readableStatus = 'obsolete' + self.status = '0.0.00' + + # Check whether status was set, or set 'strange'. + if self.status == None: + self.status = 'strange' + if not self.readableStatus: + self.readableStatus = 'strange' + + # Extract the name of the language and the readable form. + self.lang = self.classId[10:] # without 'Translator' + if self.lang == 'Brazilian': + self.langReadable = 'Brazilian Portuguese' + elif self.lang == 'Chinesetraditional': + self.langReadable = 'Chinese Traditional' + else: + self.langReadable = self.lang + + + def __unexpectedToken(self, status, tokenId, tokenLineNo): + """Reports unexpected token and quits with exit code 1.""" + + import inspect + calledFrom = inspect.stack()[1][3] + msg = "\a\nUnexpected token '%s' on the line %d in '%s'.\n" + msg = msg % (tokenId, tokenLineNo, self.fname) + msg += 'status = %d in %s()\n' % (status, calledFrom) + sys.stderr.write(msg) + sys.exit(1) + + + def collectPureVirtualPrototypes(self): + """Returns dictionary 'unified prototype' -> 'full prototype'. + + The method is expected to be called only for the translator.h. It + extracts only the pure virtual method and build the dictionary where + key is the unified prototype without argument identifiers.""" + + # Prepare empty dictionary that will be returned. + resultDic = {} + + # Start the token generator which parses the class source file. + tokenIterator = self.__tokenGenerator() + + # Collect the class and the base class identifiers. + self.__collectClassInfo(tokenIterator) + assert(self.classId == 'Translator') + + # Let's collect readable form of the public virtual pure method + # prototypes in the readable form -- as defined in translator.h. + # Let's collect also unified form of the same prototype that omits + # everything that can be omitted, namely 'virtual' and argument + # identifiers. + prototype = '' # readable prototype (with everything) + uniPrototype = '' # unified prototype (without arg. identifiers) + + # Collect the pure virtual method prototypes. Stop on the closing + # curly brace followed by the semicolon (end of class). + status = 0 + curlyCnt = 0 # counter for the level of curly braces + + # Loop until the final state 777 is reached. The errors are processed + # immediately. In this implementation, it always quits the application. + while status != 777: + + # Get the next token. + tokenId, tokenStr, tokenLineNo = tokenIterator.next() + + if status == 0: # waiting for 'public:' + if tokenId == 'public': + status = 1 + + elif status == 1: # colon after the 'public' + if tokenId == 'colon': + status = 2 + else: + self.__unexpectedToken(status, tokenId, tokenLineNo) + + elif status == 2: # waiting for 'virtual' + if tokenId == 'virtual': + prototype = tokenStr # but not to unified prototype + status = 3 + elif tokenId == 'comment': + pass + elif tokenId == 'rcurly': + status = 11 # expected end of class + else: + self.__unexpectedToken(status, tokenId, tokenLineNo) + + elif status == 3: # return type of the method expected + if tokenId == 'id': + prototype += ' ' + tokenStr + uniPrototype = tokenStr # start collecting the unified prototype + status = 4 + elif tokenId == 'tilde': + status = 4 + else: + self.__unexpectedToken(status, tokenId, tokenLineNo) + + elif status == 4: # method identifier expected + if tokenId == 'id': + prototype += ' ' + tokenStr + uniPrototype += ' ' + tokenStr + status = 5 + else: + self.__unexpectedToken(status, tokenId, tokenLineNo) + + elif status == 5: # left bracket of the argument list expected + if tokenId == 'lpar': + prototype += tokenStr + uniPrototype += tokenStr + status = 6 + else: + self.__unexpectedToken(status, tokenId, tokenLineNo) + + elif status == 6: # collecting arguments of the method + if tokenId == 'rpar': + prototype += tokenStr + uniPrototype += tokenStr + status = 7 + elif tokenId == 'const': + prototype += tokenStr + uniPrototype += tokenStr + status = 12 + elif tokenId == 'id': # type identifier + prototype += tokenStr + uniPrototype += tokenStr + status = 13 + else: + self.__unexpectedToken(status, tokenId, tokenLineNo) + + elif status == 7: # assignment expected or left curly brace + if tokenId == 'assign': + status = 8 + elif tokenId == 'lcurly': + curlyCnt = 1 # method body entered + status = 10 + else: + self.__unexpectedToken(status, tokenId, tokenLineNo) + + elif status == 8: # zero expected + if tokenId == 'num' and tokenStr == '0': + status = 9 + else: + self.__unexpectedToken(status, tokenId, tokenLineNo) + + elif status == 9: # after semicolon, produce the dic item + if tokenId == 'semic': + assert(not resultDic.has_key(uniPrototype)) + resultDic[uniPrototype] = prototype + status = 2 + else: + self.__unexpectedToken(status, tokenId, tokenLineNo) + + elif status == 10: # consuming the body of the method + if tokenId == 'rcurly': + curlyCnt -= 1 + if curlyCnt == 0: + status = 2 # body consumed + elif tokenId == 'lcurly': + curlyCnt += 1 + + elif status == 11: # probably the end of class + if tokenId == 'semic': + status = 777 + else: + self.__unexpectedToken(status, tokenId, tokenLineNo) + + elif status == 12: # type id for argument expected + if tokenId == 'id': + prototype += ' ' + tokenStr + uniPrototype += ' ' + tokenStr + status = 13 + else: + self.__unexpectedToken(status, tokenId, tokenLineNo) + + elif status == 13: # namespace qualification or * or & expected + if tokenId == 'colon': # was namespace id + prototype += tokenStr + uniPrototype += tokenStr + status = 14 + elif tokenId == 'star' or tokenId == 'amp': # pointer or reference + prototype += ' ' + tokenStr + uniPrototype += ' ' + tokenStr + status = 16 + elif tokenId == 'id': # argument identifier + prototype += ' ' + tokenStr + # don't put this into unified prototype + status = 17 + else: + self.__unexpectedToken(status, tokenId, tokenLineNo) + + elif status == 14: # second colon for namespace:: expected + if tokenId == 'colon': + prototype += tokenStr + uniPrototype += tokenStr + status = 15 + else: + self.__unexpectedToken(status, tokenId, tokenLineNo) + + elif status == 15: # type after namespace:: expected + if tokenId == 'id': + prototype += tokenStr + uniPrototype += tokenStr + status = 13 + else: + self.__unexpectedToken(status, tokenId, tokenLineNo) + + elif status == 16: # argument identifier expected + if tokenId == 'id': + prototype += ' ' + tokenStr + # don't put this into unified prototype + status = 17 + else: + self.__unexpectedToken(status, tokenId, tokenLineNo) + + elif status == 17: # comma or ')' after argument identifier expected + if tokenId == 'comma': + prototype += ', ' + uniPrototype += ', ' + status = 6 + elif tokenId == 'rpar': + prototype += tokenStr + uniPrototype += tokenStr + status = 7 + else: + self.__unexpectedToken(status, tokenId, tokenLineNo) + + # Eat the rest of the source to cause closing the file. + while tokenId != 'eof': + tokenId, tokenStr, tokenLineNo = tokenIterator.next() + + # Return the resulting dictionary with 'uniPrototype -> prototype'. + return resultDic + + + def __collectPublicMethodPrototypes(self, tokenIterator): + """Collects prototypes of public methods and fills self.prototypeDic. + + The dictionary is filled by items: uniPrototype -> prototype. + The method is expected to be called only for TranslatorXxxx classes, + i.e. for the classes that implement translation to some language. + It assumes that the openning curly brace of the class was already + consumed. The source is consumed until the end of the class. + The caller should consume the source until the eof to cause closing + the source file.""" + + assert(self.classId != 'Translator') + assert(self.baseClassId != None) + + # The following finite automaton slightly differs from the one + # inside self.collectPureVirtualPrototypes(). It produces the + # dictionary item just after consuming the body of the method + # (transition from from state 10 to state 2). It also does not allow + # definitions of public pure virtual methods, except for + # TranslatorAdapterBase (states 8 and 9). Argument identifier inside + # method argument lists can be omitted or commented. + # + # Let's collect readable form of all public method prototypes in + # the readable form -- as defined in the source file. + # Let's collect also unified form of the same prototype that omits + # everything that can be omitted, namely 'virtual' and argument + # identifiers. + prototype = '' # readable prototype (with everything) + uniPrototype = '' # unified prototype (without arg. identifiers) + warning = '' # warning message -- if something special detected + methodId = None # processed method id + + # Collect the method prototypes. Stop on the closing + # curly brace followed by the semicolon (end of class). + status = 0 + curlyCnt = 0 # counter for the level of curly braces + + # Loop until the final state 777 is reached. The errors are processed + # immediately. In this implementation, it always quits the application. + while status != 777: + + # Get the next token. + tokenId, tokenStr, tokenLineNo = tokenIterator.next() + + if status == 0: # waiting for 'public:' + if tokenId == 'public': + status = 1 + elif tokenId == 'eof': # non-public things until the eof + status = 777 + + elif status == 1: # colon after the 'public' + if tokenId == 'colon': + status = 2 + else: + self.__unexpectedToken(status, tokenId, tokenLineNo) + + elif status == 2: # waiting for 'virtual' (can be omitted) + if tokenId == 'virtual': + prototype = tokenStr # but not to unified prototype + status = 3 + elif tokenId == 'id': # 'virtual' was omitted + prototype = tokenStr + uniPrototype = tokenStr # start collecting the unified prototype + status = 4 + elif tokenId == 'comment': + pass + elif tokenId == 'protected' or tokenId == 'private': + status = 0 + elif tokenId == 'rcurly': + status = 11 # expected end of class + else: + self.__unexpectedToken(status, tokenId, tokenLineNo) + + elif status == 3: # return type of the method expected + if tokenId == 'id': + prototype += ' ' + tokenStr + uniPrototype = tokenStr # start collecting the unified prototype + status = 4 + else: + self.__unexpectedToken(status, tokenId, tokenLineNo) + + elif status == 4: # method identifier expected + if tokenId == 'id': + prototype += ' ' + tokenStr + uniPrototype += ' ' + tokenStr + methodId = tokenStr # for reporting + status = 5 + else: + self.__unexpectedToken(status, tokenId, tokenLineNo) + + elif status == 5: # left bracket of the argument list expected + if tokenId == 'lpar': + prototype += tokenStr + uniPrototype += tokenStr + status = 6 + else: + self.__unexpectedToken(status, tokenId, tokenLineNo) + + elif status == 6: # collecting arguments of the method + if tokenId == 'rpar': + prototype += tokenStr + uniPrototype += tokenStr + status = 7 + elif tokenId == 'const': + prototype += tokenStr + uniPrototype += tokenStr + status = 12 + elif tokenId == 'id': # type identifier + prototype += tokenStr + uniPrototype += tokenStr + status = 13 + else: + self.__unexpectedToken(status, tokenId, tokenLineNo) + + elif status == 7: # left curly brace expected + if tokenId == 'lcurly': + curlyCnt = 1 # method body entered + status = 10 + elif tokenId == 'comment': + pass + elif tokenId == 'assign': # allowed only for TranslatorAdapterBase + assert(self.classId == 'TranslatorAdapterBase') + status = 8 + else: + self.__unexpectedToken(status, tokenId, tokenLineNo) + + elif status == 8: # zero expected (TranslatorAdapterBase) + assert(self.classId == 'TranslatorAdapterBase') + if tokenId == 'num' and tokenStr == '0': + status = 9 + else: + self.__unexpectedToken(status, tokenId, tokenLineNo) + + elif status == 9: # after semicolon (TranslatorAdapterBase) + assert(self.classId == 'TranslatorAdapterBase') + if tokenId == 'semic': + status = 2 + else: + self.__unexpectedToken(status, tokenId, tokenLineNo) + + elif status == 10: # consuming the body of the method, then dic item + if tokenId == 'rcurly': + curlyCnt -= 1 + if curlyCnt == 0: + # Insert new dictionary item. + assert(not self.prototypeDic.has_key(uniPrototype)) + self.prototypeDic[uniPrototype] = prototype + status = 2 # body consumed + methodId = None # outside of any method + elif tokenId == 'lcurly': + curlyCnt += 1 + + # Warn in special case. + elif methodId == 'trLegendDocs' and tokenId == 'string' \ + and tokenStr.find('MAX_DOT_GRAPH_HEIGHT') >= 0: + self.txtMAX_DOT_GRAPH_HEIGHT_flag = True + + + elif status == 11: # probably the end of class + if tokenId == 'semic': + status = 777 + else: + self.__unexpectedToken(status, tokenId, tokenLineNo) + + elif status == 12: # type id for argument expected + if tokenId == 'id': + prototype += ' ' + tokenStr + uniPrototype += ' ' + tokenStr + status = 13 + else: + self.__unexpectedToken(status, tokenId, tokenLineNo) + + elif status == 13: # :: or * or & or id or ) expected + if tokenId == 'colon': # was namespace id + prototype += tokenStr + uniPrototype += tokenStr + status = 14 + elif tokenId == 'star' or tokenId == 'amp': # pointer or reference + prototype += ' ' + tokenStr + uniPrototype += ' ' + tokenStr + status = 16 + elif tokenId == 'id': # argument identifier + prototype += ' ' + tokenStr + # don't put this into unified prototype + status = 17 + elif tokenId == 'comment': # probably commented-out identifier + prototype += tokenStr + elif tokenId == 'rpar': + prototype += tokenStr + uniPrototype += tokenStr + status = 7 + elif tokenId == 'comma': + prototype += ', ' + uniPrototype += ', ' + status = 6 + else: + self.__unexpectedToken(status, tokenId, tokenLineNo) + + elif status == 14: # second colon for namespace:: expected + if tokenId == 'colon': + prototype += tokenStr + uniPrototype += tokenStr + status = 15 + else: + self.__unexpectedToken(status, tokenId, tokenLineNo) + + elif status == 15: # type after namespace:: expected + if tokenId == 'id': + prototype += tokenStr + uniPrototype += tokenStr + status = 13 + else: + self.__unexpectedToken(status, tokenId, tokenLineNo) + + elif status == 16: # argument identifier or ) expected + if tokenId == 'id': + prototype += ' ' + tokenStr + # don't put this into unified prototype + status = 17 + elif tokenId == 'rpar': + prototype += tokenStr + uniPrototype += tokenStr + status = 7 + elif tokenId == 'comment': + prototype += tokenStr + else: + self.__unexpectedToken(status, tokenId, tokenLineNo) + + elif status == 17: # comma or ')' after argument identifier expected + if tokenId == 'comma': + prototype += ', ' + uniPrototype += ', ' + status = 6 + elif tokenId == 'rpar': + prototype += tokenStr + uniPrototype += tokenStr + status = 7 + else: + self.__unexpectedToken(status, tokenId, tokenLineNo) + + + + def collectAdapterPrototypes(self): + """Returns the dictionary of prototypes implemented by adapters. + + It is created to process the translator_adapter.h. The returned + dictionary has the form: unifiedPrototype -> (version, classId) + thus by looking for the prototype, we get the information what is + the newest (least adapting) adapter that is sufficient for + implementing the method.""" + + # Start the token generator which parses the class source file. + assert(os.path.split(self.fname)[1] == 'translator_adapter.h') + tokenIterator = self.__tokenGenerator() + + # Get the references to the involved dictionaries. + reqDic = self.manager.requiredMethodsDic + + # Create the empty dictionary that will be returned. + adaptDic = {} + + + # Loop through the source of the adapter file until no other adapter + # class is found. + while True: + try: + # Collect the class and the base class identifiers. + self.__collectClassInfo(tokenIterator) + + # Extract the comparable version of the adapter class. + # Note: The self.status as set by self.__collectClassInfo() + # contains similar version, but is related to the base class, + # not to the class itself. + lst = self.classId.split('_') + version = '' + if lst[0] == 'TranslatorAdapter': # TranslatorAdapterBase otherwise + version = lst[1] + '.' + lst[2] + if len(lst) > 3: # add the last part of the number + version += '.' + ('%02d' % int(lst[3])) + else: + version += '.00' + + # Collect the prototypes of implemented public methods. + self.__collectPublicMethodPrototypes(tokenIterator) + + # For the required methods, update the dictionary of methods + # implemented by the adapter. + for protoUni in self.prototypeDic: + if reqDic.has_key(protoUni): + # This required method will be marked as implemented + # by this adapter class. This implementation assumes + # that newer adapters do not reimplement any required + # methods already implemented by older adapters. + assert(not adaptDic.has_key(protoUni)) + adaptDic[protoUni] = (version, self.classId) + + # Clear the dictionary object and the information related + # to the class as the next adapter class is to be processed. + self.prototypeDic.clear() + self.classId = None + self.baseClassId = None + + except StopIteration: + break + + # Return the result dictionary. + return adaptDic + + + def processing(self): + """Processing of the source file -- only for TranslatorXxxx classes.""" + + # Start the token generator which parses the class source file. + tokenIterator = self.__tokenGenerator() + + # Collect the class and the base class identifiers. + self.__collectClassInfo(tokenIterator) + assert(self.classId != 'Translator') + assert(self.classId[:17] != 'TranslatorAdapter') + + # Collect the prototypes of implemented public methods. + self.__collectPublicMethodPrototypes(tokenIterator) + + # Eat the rest of the source to cause closing the file. + while True: + try: + t = tokenIterator.next() + except StopIteration: + break + + # Shorthands for the used dictionaries. + reqDic = self.manager.requiredMethodsDic + adaptDic = self.manager.adaptMethodsDic + myDic = self.prototypeDic + + # Build the list of obsolete methods. + self.obsoleteMethods = [] + for p in myDic: + if not reqDic.has_key(p): + self.obsoleteMethods.append(p) + + # Build the list of missing methods and the list of implemented + # required methods. + self.missingMethods = [] + self.implementedMethods = [] + for p in reqDic: + if myDic.has_key(p): + self.implementedMethods.append(p) + else: + self.missingMethods.append(p) + + # Set the least important note first if the translator is decoded. + # If yes, then it means that the implementation should be switched + # to UTF-8 later (suggestion). + self.isDecodedTranslator = self.classId in self.manager.decodedTranslators + if self.isDecodedTranslator: + self.note = 'Reimplementation using UTF-8 suggested.' + + # Check whether adapter must be used or suggest the newest one. + # Change the status and set the note accordingly. + if self.baseClassId != 'Translator': + if not self.missingMethods: + self.note = 'Change the base class to Translator.' + self.status = '' + self.readableStatus = 'up-to-date' + elif self.baseClassId != 'TranslatorEnglish': + # The translator uses some of the adapters. + # Look at the missing methods and check what adapter + # implements them. Remember the one with the lowest version. + adaptMinVersion = '9.9.99' + adaptMinClass = 'TranslatorAdapter_9_9_99' + for uniProto in self.missingMethods: + if adaptDic.has_key(uniProto): + version, cls = adaptDic[uniProto] + if version < adaptMinVersion: + adaptMinVersion = version + adaptMinClass = cls + + # Test against the current status -- preserve the self.status. + # Possibly, the translator implements enough methods to + # use some newer adapter. + status = self.status + + # If the version of the used adapter is smaller than + # the required, set the note and update the status as if + # the newer adapter was used. + if adaptMinVersion > status: + self.note = 'Change the base class to %s.' % adaptMinClass + self.status = adaptMinVersion + self.adaptMinClass = adaptMinClass + self.readableStatus = adaptMinVersion # simplified + + # If everything seems OK, some explicit warning flags still could + # be set. + if not self.note and self.status == '' and \ + (self.translateMeFlag or self.txtMAX_DOT_GRAPH_HEIGHT_flag): + self.note = '' + if self.translateMeFlag: + self.note += 'The "%s" found in a comment.' % self.translateMeText + if self.note != '': + self.note += '\n\t\t' + if self.txtMAX_DOT_GRAPH_HEIGHT_flag: + self.note += 'The MAX_DOT_GRAPH_HEIGHT found in trLegendDocs()' + + # If everything seems OK, but there are obsolete methods, set + # the note to clean-up source. This note will be used only when + # the previous code did not set another note (priority). + if not self.note and self.status == '' and self.obsoleteMethods: + self.note = 'Remove the obsolete methods (never used).' + + + def report(self, fout): + """Returns the report part for the source as a multiline string. + + No output for up-to-date translators without problem.""" + + # If there is nothing to report, return immediately. + if self.status == '' and not self.note: + return + + # Report the number of not implemented methods. + fout.write('\n\n\n') + fout.write(self.classId + ' (' + self.baseClassId + ')') + percentImplemented = 100 # init + allNum = len(self.manager.requiredMethodsDic) + if self.missingMethods: + num = len(self.missingMethods) + percentImplemented = 100 * (allNum - num) / allNum + fout.write(' %d' % num) + fout.write(' method') + if num > 1: + fout.write('s') + fout.write(' to implement (%d %%)' % (100 * num / allNum)) + fout.write('\n' + '-' * len(self.classId)) + + # Write the info about the implemented required methods. + fout.write('\n\n Implements %d' % len(self.implementedMethods)) + fout.write(' of the required methods (%d %%).' % percentImplemented) + + # Report the missing method, but only when it is not English-based + # translator. + if self.missingMethods and self.status != 'En': + fout.write('\n\n Missing methods (should be implemented):\n') + reqDic = self.manager.requiredMethodsDic + for p in self.missingMethods: + fout.write('\n ' + reqDic[p]) + + # Always report obsolete methods. + if self.obsoleteMethods: + fout.write('\n\n Obsolete methods (should be removed, never used):\n') + myDic = self.prototypeDic + for p in self.obsoleteMethods: + fout.write('\n ' + myDic[p]) + + # For English-based translator, report the implemented methods. + if self.status == 'En' and self.implementedMethods: + fout.write('\n\n This English-based translator implements ') + fout.write('the following methods:\n') + reqDic = self.manager.requiredMethodsDic + for p in self.implementedMethods: + fout.write('\n ' + reqDic[p]) + + + def getmtime(self): + """Returns the last modification time of the source file.""" + assert(os.path.isfile(self.fname)) + return os.path.getmtime(self.fname) + + +class TrManager: + """Collects basic info and builds subordinate Transl objects.""" + + def __init__(self): + """Determines paths, creates and initializes structures. + + The arguments of the script may explicitly say what languages should + be processed. Write the two letter identifications that are used + for composing the source filenames, so... + + python translator.py cz + + this will process only translator_cz.h source. + """ + + # Determine the path to the script and its name. + self.script = os.path.abspath(sys.argv[0]) + self.script_path, self.script_name = os.path.split(self.script) + self.script_path = os.path.abspath(self.script_path) + + # Determine the absolute path to the Doxygen's root subdirectory. + # If DOXYGEN environment variable is not found, the directory is + # determined from the path of the script. + doxy_default = os.path.join(self.script_path, '..') + self.doxy_path = os.path.abspath(os.getenv('DOXYGEN', doxy_default)) + + # Get the explicit arguments of the script. + self.script_argLst = sys.argv[1:] + + # Build the path names based on the Doxygen's root knowledge. + self.doc_path = os.path.join(self.doxy_path, 'doc') + self.src_path = os.path.join(self.doxy_path, 'src') + + # Create the empty dictionary for Transl object identitied by the + # class identifier of the translator. + self.__translDic = {} + + # Create the None dictionary of required methods. The key is the + # unified prototype, the value is the full prototype. Set inside + # the self.__build(). + self.requiredMethodsDic = None + + # Create the empty dictionary that says what method is implemented + # by what adapter. + self.adaptMethodsDic = {} + + # The last modification time will capture the modification of this + # script, of the translator.h, of the translator_adapter.h (see the + # self.__build() for the last two) of all the translator_xx.h files + # and of the template for generating the documentation. So, this + # time can be compared with modification time of the generated + # documentation to decide, whether the doc should be re-generated. + self.lastModificationTime = os.path.getmtime(self.script) + + # Set the names of the translator report text file, of the template + # for generating "Internationalization" document, for the generated + # file itself, and for the maintainers list. + self.translatorReportFileName = 'translator_report.txt' + self.maintainersFileName = 'maintainers.txt' + self.languageTplFileName = 'language.tpl' + self.languageDocFileName = 'language.doc' + + # The information about the maintainers will be stored + # in the dictionary with the following name. + self.__maintainersDic = None + + # Define the other used structures and variables for information. + self.langLst = None # including English based + self.supportedLangReadableStr = None # coupled En-based as a note + self.numLang = None # excluding coupled En-based + self.doxVersion = None # Doxygen version + + # Capture the knowledge about translators that are not implemented + # to use UTF-8 internally. + self.decodedTranslators = self.getDecodedTranslators() + + # Build objects where each one is responsible for one translator. + self.__build() + + + def getDecodedTranslators(self): + """Parses language.cpp to find what translators do not use UTF-8 yet""" + decodedTranslators = [] + + # Regular expression to detect the lines like + # theTranslator=new TranslatorDecoder(new TranslatorSwedish); + rex = re.compile(r'^\s*theTranslator\s*=\s*new\s+.*$') + + # Regular expression to get the (optional) TranslatorDecoder and TranslatorXXX + rex2 = re.compile(r'\bTranslator\w+') + + # Parse the lines in the specific source code. + f = open(os.path.join(self.src_path, 'language.cpp'), 'rU') + for line in f: + if rex.match(line): + lst = rex2.findall(line) + if lst[0] == 'TranslatorDecoder': + decodedTranslators.append(lst[1]) + f.close() + + # Display warning when all translator implementations were converted + # to UTF-8. + if len(decodedTranslators) == 0: + print 'This script should be updated. All translators do use UTF-8' + print 'internally. The TranslatorDecoder adapter should be removed' + print 'from the code and its usage should not be checked any more.' + + return decodedTranslators + + + def __build(self): + """Find the translator files and build the objects for translators.""" + + # The translator.h must exist (the Transl object will check it), + # create the object for it and let it build the dictionary of + # required methods. + tr = Transl(os.path.join(self.src_path, 'translator.h'), self) + self.requiredMethodsDic = tr.collectPureVirtualPrototypes() + tim = tr.getmtime() + if tim > self.lastModificationTime: + self.lastModificationTime = tim + + # The translator_adapter.h must exist (the Transl object will check it), + # create the object for it and store the reference in the dictionary. + tr = Transl(os.path.join(self.src_path, 'translator_adapter.h'), self) + self.adaptMethodsDic = tr.collectAdapterPrototypes() + tim = tr.getmtime() + if tim > self.lastModificationTime: + self.lastModificationTime = tim + + # Create the list of the filenames with language translator sources. + # If the explicit arguments of the script were typed, process only + # those files. + if self.script_argLst: + lst = ['translator_' + x + '.h' for x in self.script_argLst] + for fname in lst: + if not os.path.isfile(os.path.join(self.src_path, fname)): + sys.stderr.write("\a\nFile '%s' not found!\n" % fname) + sys.exit(1) + else: + lst = os.listdir(self.src_path) + lst = filter(lambda x: x[:11] == 'translator_' + and x[-2:] == '.h' + and x != 'translator_adapter.h', lst) + + # Build the object for the translator_xx.h files, and process the + # content of the file. Then insert the object to the dictionary + # accessed via classId. + for fname in lst: + fullname = os.path.join(self.src_path, fname) + tr = Transl(fullname, self) + tr.processing() + assert(tr.classId != 'Translator') + self.__translDic[tr.classId] = tr + + # Extract the global information of the processed info. + self.__extractProcessedInfo() + + + def __extractProcessedInfo(self): + """Build lists and strings of the processed info.""" + + # Build the auxiliary list with strings compound of the status, + # readable form of the language, and classId. + statLst = [] + for obj in self.__translDic.values(): + assert(obj.classId != 'Translator') + s = obj.status + '|' + obj.langReadable + '|' + obj.classId + statLst.append(s) + + # Sort the list and extract the object identifiers (classId's) for + # the up-to-date translators and English-based translators. + statLst.sort() + self.upToDateIdLst = [x.split('|')[2] for x in statLst if x[0] == '|'] + self.EnBasedIdLst = [x.split('|')[2] for x in statLst if x[:2] == 'En'] + + # Reverse the list and extract the TranslatorAdapter based translators. + statLst.reverse() + self.adaptIdLst = [x.split('|')[2] for x in statLst if x[0].isdigit()] + + # Build the list of tuples that contain (langReadable, obj). + # Sort it by readable name. + self.langLst = [] + for obj in self.__translDic.values(): + self.langLst.append((obj.langReadable, obj)) + self.langLst.sort(lambda a, b: cmp(a[0], b[0])) + + # Create the list with readable language names. If the language has + # also the English-based version, modify the item by appending + # the note. Number of the supported languages is equal to the length + # of the list. + langReadableLst = [] + for name, obj in self.langLst: + if obj.status == 'En': continue + + # Append the 'En' to the classId to possibly obtain the classId + # of the English-based object. If the object exists, modify the + # name for the readable list of supported languages. + classIdEn = obj.classId + 'En' + if self.__translDic.has_key(classIdEn): + name += ' (+En)' + + # Append the result name of the language, possibly with note. + langReadableLst.append(name) + + # Create the multiline string of readable language names, + # with punctuation, wrapped to paragraph. + if len(langReadableLst) == 1: + s = langReadableLst[0] + elif len(langReadableLst) == 2: + s = ' and '.join(langReadableLst) + else: + s = ', '.join(langReadableLst[:-1]) + ', and ' + s += langReadableLst[-1] + + self.supportedLangReadableStr = fill(s + '.') + + # Find the number of the supported languages. The English based + # languages are not counted if the non-English based also exists. + self.numLang = len(self.langLst) + for name, obj in self.langLst: + if obj.status == 'En': + classId = obj.classId[:-2] + if self.__translDic.has_key(classId): + self.numLang -= 1 # the couple will be counted as one + + # Extract the version of Doxygen. + f = open(os.path.join(self.doxy_path, 'VERSION')) + self.doxVersion = f.readline().strip() + f.close() + + # Update the last modification time. + for tr in self.__translDic.values(): + tim = tr.getmtime() + if tim > self.lastModificationTime: + self.lastModificationTime = tim + + + def __getNoTrSourceFilesLst(self): + """Returns the list of sources to be checked. + + All .cpp files and also .h files that do not declare or define + the translator methods are included in the list. The file names + are searched in doxygen/src directory. + """ + files = [] + for item in os.listdir(self.src_path): + # Split the bare name to get the extension. + name, ext = os.path.splitext(item) + ext = ext.lower() + + # Include only .cpp and .h files (case independent) and exclude + # the files where the checked identifiers are defined. + if ext == '.cpp' or (ext == '.h' and name.find('translator') == -1): + fname = os.path.join(self.src_path, item) + assert os.path.isfile(fname) # assumes no directory with the ext + files.append(fname) # full name + return files + + + def __removeUsedInFiles(self, fname, dic): + """Removes items for method identifiers that are found in fname. + + The method reads the content of the file as one string and searches + for all identifiers from dic. The identifiers that were found in + the file are removed from the dictionary. + + Note: If more files is to be checked, the files where most items are + probably used should be checked first and the resulting reduced + dictionary should be used for checking the next files (speed up). + """ + lst_in = dic.keys() # identifiers to be searched for + + # Read content of the file as one string. + assert os.path.isfile(fname) + f = open(fname) + cont = f.read() + f.close() + + # Remove the items for identifiers that were found in the file. + while lst_in: + item = lst_in.pop(0) + if cont.find(item) != -1: + del dic[item] + + + def __checkForNotUsedTrMethods(self): + """Returns the dictionary of not used translator methods. + + The method can be called only after self.requiredMethodsDic has been + built. The stripped prototypes are the values, the method identifiers + are the keys. + """ + # Build the dictionary of the required method prototypes with + # method identifiers used as keys. + trdic = {} + for prototype in self.requiredMethodsDic.keys(): + ri = prototype.split('(')[0] + identifier = ri.split()[1].strip() + trdic[identifier] = prototype + + # Build the list of source files where translator method identifiers + # can be used. + files = self.__getNoTrSourceFilesLst() + + # Loop through the files and reduce the dictionary of id -> proto. + for fname in files: + self.__removeUsedInFiles(fname, trdic) + + # Return the dictionary of not used translator methods. + return trdic + + + def __emails(self, classId): + """Returns the list of maintainer emails. + + The method returns the list of e-mail adresses for the translator + class, but only the addresses that were not marked as [xxx].""" + lst = [] + for m in self.__maintainersDic[classId]: + if not m[1].startswith('['): + email = m[1] + email = email.replace(' at ', '@') # Unmangle the mangled e-mail + email = email.replace(' dot ', '.') + lst.append(email) + return lst + + + def generateTranslatorReport(self): + """Generates the translator report.""" + + output = os.path.join(self.doc_path, self.translatorReportFileName) + + # Open the textual report file for the output. + f = open(output, 'w') + + # Output the information about the version. + f.write('(' + self.doxVersion + ')\n\n') + + # Output the information about the number of the supported languages + # and the list of the languages, or only the note about the explicitly + # given languages to process. + if self.script_argLst: + f.write('The report was generated for the following, explicitly') + f.write(' identified languages:\n\n') + f.write(self.supportedLangReadableStr + '\n\n') + else: + f.write('Doxygen supports the following ') + f.write(str(self.numLang)) + f.write(' languages (sorted alphabetically):\n\n') + f.write(self.supportedLangReadableStr + '\n\n') + + # Write the summary about the status of language translators (how + # many translators) are up-to-date, etc. + s = 'Of them, %d translators are up-to-date, ' % len(self.upToDateIdLst) + s += '%d translators are based on some adapter class, ' % len(self.adaptIdLst) + s += 'and %d are English based.' % len(self.EnBasedIdLst) + f.write(fill(s) + '\n\n') + + # The e-mail addresses of the maintainers will be collected to + # the auxiliary file in the order of translator classes listed + # in the translator report. + fmail = open('mailto.txt', 'w') + + # Write the list of up-to-date translator classes. + if self.upToDateIdLst: + s = '''The following translator classes are up-to-date (sorted + alphabetically). This means that they derive from the + Translator class and they implement all %d of the required + methods. Anyway, there still may be some details listed even + for them:''' + s = s % len(self.requiredMethodsDic) + f.write('-' * 70 + '\n') + f.write(fill(s) + '\n\n') + + mailtoLst = [] + for x in self.upToDateIdLst: + obj = self.__translDic[x] + f.write(' ' + obj.classId) + if obj.note: + f.write(' -- ' + obj.note) + f.write('\n') + mailtoLst.extend(self.__emails(obj.classId)) + + fmail.write('up-to-date\n') + fmail.write('; '.join(mailtoLst)) + + # Write the list of the adapter based classes. The very obsolete + # translators that derive from TranslatorEnglish are included. + if self.adaptIdLst: + s = '''The following translator classes need some maintenance + (the most obsolete at the end). The other info shows the + estimation of Doxygen version when the class was last + updated and number of methods that must be implemented to + become up-to-date:''' + f.write('\n' + '-' * 70 + '\n') + f.write(fill(s) + '\n\n') + + # Find also whether some adapter classes may be removed. + adaptMinVersion = '9.9.99' + + mailtoLst = [] + numRequired = len(self.requiredMethodsDic) + for x in self.adaptIdLst: + obj = self.__translDic[x] + f.write(' %-30s' % obj.classId) + f.write(' %-6s' % obj.readableStatus) + numimpl = len(obj.missingMethods) + pluralS = '' + if numimpl > 1: pluralS = 's' + percent = 100 * numimpl / numRequired + f.write('\t%2d method%s to implement (%d %%)' % ( + numimpl, pluralS, percent)) + if obj.note: + f.write('\n\tNote: ' + obj.note + '\n') + f.write('\n') + mailtoLst.extend(self.__emails(obj.classId)) # to maintainer + + # Check the level of required adapter classes. + if obj.status != '0.0.00' and obj.status < adaptMinVersion: + adaptMinVersion = obj.status + + fmail.write('\n\ntranslator based\n') + fmail.write('; '.join(mailtoLst)) + + # Set the note if some old translator adapters are not needed + # any more. Do it only when the script is called without arguments, + # i.e. all languages were checked against the needed translator + # adapters. + if not self.script_argLst: + to_remove = {} + for version, adaptClassId in self.adaptMethodsDic.values(): + if version < adaptMinVersion: + to_remove[adaptClassId] = True + + if to_remove: + lst = to_remove.keys() + lst.sort() + plural = len(lst) > 1 + note = 'Note: The adapter class' + if plural: note += 'es' + note += ' ' + ', '.join(lst) + if not plural: + note += ' is' + else: + note += ' are' + note += ' not used and can be removed.' + f.write('\n' + fill(note) + '\n') + + # Write the list of the English-based classes. + if self.EnBasedIdLst: + s = '''The following translator classes derive directly from the + TranslatorEnglish. The class identifier has the suffix 'En' + that says that this is intentional. Usually, there is also + a non-English based version of the translator for + the language:''' + f.write('\n' + '-' * 70 + '\n') + f.write(fill(s) + '\n\n') + + for x in self.EnBasedIdLst: + obj = self.__translDic[x] + f.write(' ' + obj.classId) + f.write('\timplements %d methods' % len(obj.implementedMethods)) + if obj.note: + f.write(' -- ' + obj.note) + f.write('\n') + + # Check for not used translator methods and generate warning if found. + # The check is rather time consuming, so it is not done when report + # is restricted to explicitly given language identifiers. + if not self.script_argLst: + dic = self.__checkForNotUsedTrMethods() + if dic: + s = '''WARNING: The following translator methods are declared + in the Translator class but their identifiers do not appear + in source files. The situation should be checked. The .cpp + files and .h files excluding the '*translator*' files + in doxygen/src directory were simply searched for occurence + of the method identifiers:''' + f.write('\n' + '=' * 70 + '\n') + f.write(fill(s) + '\n\n') + + keys = dic.keys() + keys.sort() + for key in keys: + f.write(' ' + dic[key] + '\n') + f.write('\n') + + # Write the details for the translators. + f.write('\n' + '=' * 70) + f.write('\nDetails for translators (classes sorted alphabetically):\n') + + cls = self.__translDic.keys() + cls.sort() + + for c in cls: + obj = self.__translDic[c] + assert(obj.classId != 'Translator') + obj.report(f) + + # Close the report file and the auxiliary file with e-mails. + f.close() + fmail.close() + + + def __loadMaintainers(self): + """Load and process the file with the maintainers. + + Fills the dictionary classId -> [(name, e-mail), ...].""" + + fname = os.path.join(self.doc_path, self.maintainersFileName) + + # Include the maintainers file to the group of files checked with + # respect to the modification time. + tim = os.path.getmtime(fname) + if tim > self.lastModificationTime: + self.lastModificationTime = tim + + # Process the content of the maintainers file. + f = codecs.open(fname, 'r', 'utf-8') + inside = False # inside the record for the language + lineReady = True + classId = None + maintainersLst = None + self.__maintainersDic = {} + while lineReady: + line = f.readline() # next line + lineReady = line != '' # when eof, then line == '' + + line = line.strip() # eof should also behave as separator + if line != u'' and line[0] == u'%': # skip the comment line + continue + + if not inside: # if outside of the record + if line != u'': # should be language identifier + classId = line + maintainersLst = [] + inside = True + # Otherwise skip empty line that do not act as separator. + + else: # if inside the record + if line == u'': # separator found + inside = False + else: + # If it is the first maintainer, create the empty list. + if not self.__maintainersDic.has_key(classId): + self.__maintainersDic[classId] = [] + + # Split the information about the maintainer and append + # the tuple. The address may be prefixed '[unreachable]' + # or whatever '[xxx]'. This will be processed later. + lst = line.split(u':', 1) + assert(len(lst) == 2) + t = (lst[0].strip(), lst[1].strip()) + self.__maintainersDic[classId].append(t) + f.close() + + + def generateLanguageDoc(self): + """Checks the modtime of files and generates language.doc.""" + self.__loadMaintainers() + + # Check the last modification time of the template file. It is the + # last file from the group that decide whether the documentation + # should or should not be generated. + fTplName = os.path.join(self.doc_path, self.languageTplFileName) + tim = os.path.getmtime(fTplName) + if tim > self.lastModificationTime: + self.lastModificationTime = tim + + # If the generated documentation exists and is newer than any of + # the source files from the group, do not generate it and quit + # quietly. + fDocName = os.path.join(self.doc_path, self.languageDocFileName) + if os.path.isfile(fDocName): + if os.path.getmtime(fDocName) > self.lastModificationTime: + return + + # The document or does not exist or is older than some of the + # sources. It must be generated again. + # + # Read the template of the documentation, and remove the first + # attention lines. + f = codecs.open(fTplName, 'r', 'utf-8') + doctpl = f.read() + f.close() + + pos = doctpl.find(u'/***') + assert pos != -1 + doctpl = doctpl[pos:] + + # Fill the tplDic by symbols that will be inserted into the + # document template. + tplDic = {} + + s = u'Do not edit this file. It was generated by the %s script.' % self.script_name + tplDic['editnote'] = s + + tplDic['doxVersion'] = self.doxVersion + tplDic['supportedLangReadableStr'] = self.supportedLangReadableStr + tplDic['translatorReportFileName'] = self.translatorReportFileName + + ahref = u'<a href="../doc/' + self.translatorReportFileName + ahref += u'"\n><code>doxygen/doc/' + self.translatorReportFileName + ahref += u'</code></a>' + tplDic['translatorReportLink'] = ahref + tplDic['numLangStr'] = str(self.numLang) + + # Define templates for HTML table parts of the documentation. + htmlTableTpl = u'''\ + \\htmlonly + <table align="center" cellspacing="0" cellpadding="0" border="0"> + <tr bgcolor="#000000"> + <td> + <table cellspacing="1" cellpadding="2" border="0"> + <tr bgcolor="#4040c0"> + <td ><b><font size="+1" color="#ffffff"> Language </font></b></td> + <td ><b><font size="+1" color="#ffffff"> Maintainer </font></b></td> + <td ><b><font size="+1" color="#ffffff"> Contact address </font> + <font size="-2" color="#ffffff">(replace the at and dot)</font></b></td> + <td ><b><font size="+1" color="#ffffff"> Status </font></b></td> + </tr> + <!-- table content begin --> + %s + <!-- table content end --> + </table> + </td> + </tr> + </table> + \\endhtmlonly + ''' + htmlTableTpl = dedent(htmlTableTpl) + htmlTrTpl = u'\n <tr bgcolor="#ffffff">%s\n </tr>' + htmlTdTpl = u'\n <td>%s</td>' + + # Loop through transl objects in the order of sorted readable names + # and add generate the content of the HTML table. + trlst = [] + for name, obj in self.langLst: + # Fill the table data elements for one row. The first element + # contains the readable name of the language. + lst = [ htmlTdTpl % obj.langReadable ] + + # The next two elements contain the list of maintainers + # and the list of their mangled e-mails. For English-based + # translators that are coupled with the non-English based, + # insert the 'see' note. + mm = None # init -- maintainer + ee = None # init -- e-mail address + if obj.status == 'En': + # Check whether there is the coupled non-English. + classId = obj.classId[:-2] + if classId in self.__translDic: + lang = self.__translDic[classId].langReadable + mm = u'see the %s language' % lang + ee = u' ' + + if not mm and obj.classId in self.__maintainersDic: + # Build a string of names separated by the HTML break element. + # Special notes used instead of names are highlighted. + lm = [] + for maintainer in self.__maintainersDic[obj.classId]: + name = maintainer[0] + if name.startswith(u'--'): + name = u'<span style="color: red; background-color: yellow">'\ + + name + u'</span>' + lm.append(name) + mm = u'<br/>'.join(lm) + + # The marked adresses (they start with the mark '[unreachable]', + # '[resigned]', whatever '[xxx]') will not be displayed at all. + # Only the mark will be used instead. + rexMark = re.compile(ur'(?P<mark>\[.*?\])') + le = [] + for maintainer in self.__maintainersDic[obj.classId]: + address = maintainer[1] + m = rexMark.search(address) + if m is not None: + address = u'<span style="color: brown">'\ + + m.group(u'mark') + u'</span>' + le.append(address) + ee = u'<br/>'.join(le) + + # Append the maintainer and e-mail elements. + lst.append(htmlTdTpl % mm) + lst.append(htmlTdTpl % ee) + + # The last element contains the readable form of the status. + lst.append(htmlTdTpl % obj.readableStatus) + + # Join the table data to one table row. + trlst.append(htmlTrTpl % (''.join(lst))) + + # Join the table rows and insert into the template. + htmlTable = htmlTableTpl % (''.join(trlst)) + + # Define templates for LaTeX table parts of the documentation. + latexTableTpl = ur''' + \latexonly + \footnotesize + \begin{longtable}{|l|l|l|l|} + \hline + {\bf Language} & {\bf Maintainer} & {\bf Contact address} & {\bf Status} \\ + \hline + %s + \hline + \end{longtable} + \normalsize + \endlatexonly + ''' + latexTableTpl = dedent(latexTableTpl) + latexLineTpl = u'\n' + r' %s & %s & {\tt\tiny %s} & %s \\' + + # Loop through transl objects in the order of sorted readable names + # and add generate the content of the LaTeX table. + trlst = [] + for name, obj in self.langLst: + # For LaTeX, more maintainers for the same language are + # placed on separate rows in the table. The line separator + # in the table is placed explicitly above the first + # maintainer. Prepare the arguments for the LaTeX row template. + maintainers = [] + if self.__maintainersDic.has_key(obj.classId): + maintainers = self.__maintainersDic[obj.classId] + + lang = obj.langReadable + maintainer = None # init + email = None # init + if obj.status == 'En': + # Check whether there is the coupled non-English. + classId = obj.classId[:-2] + if classId in self.__translDic: + langNE = self.__translDic[classId].langReadable + maintainer = u'see the %s language' % langNE + email = u'~' + + if not maintainer and (obj.classId in self.__maintainersDic): + lm = [ m[0] for m in self.__maintainersDic[obj.classId] ] + maintainer = maintainers[0][0] + email = maintainers[0][1] + + status = obj.readableStatus + + # Use the template to produce the line of the table and insert + # the hline plus the constructed line into the table content. + # The underscore character must be escaped. + trlst.append(u'\n \\hline') + s = latexLineTpl % (lang, maintainer, email, status) + s = s.replace(u'_', u'\\_') + trlst.append(s) + + # List the other maintainers for the language. Do not set + # lang and status for them. + lang = u'~' + status = u'~' + for m in maintainers[1:]: + maintainer = m[0] + email = m[1] + s = latexLineTpl % (lang, maintainer, email, status) + s = s.replace(u'_', u'\\_') + trlst.append(s) + + # Join the table lines and insert into the template. + latexTable = latexTableTpl % (u''.join(trlst)) + + # Put the HTML and LaTeX parts together and define the dic item. + tplDic['informationTable'] = htmlTable + u'\n' + latexTable + + # Insert the symbols into the document template and write it down. + f = codecs.open(fDocName, 'w', 'utf-8') + f.write(doctpl % tplDic) + f.close() + +if __name__ == '__main__': + + # Create the manager, build the transl objects, and parse the related + # sources. + trMan = TrManager() + + # Generate the language.doc. + trMan.generateLanguageDoc() + + # Generate the translator report. + trMan.generateTranslatorReport() diff --git a/trunk/doc/translator_report.txt b/trunk/doc/translator_report.txt new file mode 100644 index 0000000..382c066 --- /dev/null +++ b/trunk/doc/translator_report.txt @@ -0,0 +1,792 @@ +(1.7.6.1) + +Doxygen supports the following 39 languages (sorted alphabetically): + +Afrikaans, Arabic, Armenian, Brazilian Portuguese, Catalan, Chinese, +Chinese Traditional, Croatian, Czech, Danish, Dutch, English, +Esperanto, Finnish, French, German, Greek, Hungarian, Indonesian, +Italian, Japanese (+En), Korean (+En), Lithuanian, Macedonian, +Norwegian, Persian, Polish, Portuguese, Romanian, Russian, Serbian, +SerbianCyrilic, Slovak, Slovene, Spanish, Swedish, Turkish, Ukrainian, +and Vietnamese. + +Of them, 16 translators are up-to-date, 23 translators are based on +some adapter class, and 2 are English based. + +---------------------------------------------------------------------- +The following translator classes are up-to-date (sorted +alphabetically). This means that they derive from the Translator class +and they implement all 228 of the required methods. Anyway, there +still may be some details listed even for them: + + TranslatorArmenian + TranslatorBrazilian + TranslatorCatalan + TranslatorChinesetraditional -- Reimplementation using UTF-8 suggested. + TranslatorChinese + TranslatorCroatian + TranslatorCzech + TranslatorDanish -- Reimplementation using UTF-8 suggested. + TranslatorDutch + TranslatorEnglish + TranslatorFrench -- Reimplementation using UTF-8 suggested. + TranslatorGerman + TranslatorGreek + TranslatorIndonesian -- Reimplementation using UTF-8 suggested. + TranslatorPortuguese + TranslatorSlovak + +---------------------------------------------------------------------- +The following translator classes need some maintenance (the most +obsolete at the end). The other info shows the estimation of Doxygen +version when the class was last updated and number of methods that +must be implemented to become up-to-date: + + TranslatorTurkish 1.7.5 3 methods to implement (1 %) + TranslatorSpanish 1.7.5 3 methods to implement (1 %) + TranslatorRussian 1.7.5 3 methods to implement (1 %) + Note: Reimplementation using UTF-8 suggested. + + TranslatorPersian 1.7.5 3 methods to implement (1 %) + TranslatorKorean 1.7.5 3 methods to implement (1 %) + Note: Reimplementation using UTF-8 suggested. + + TranslatorItalian 1.7.5 3 methods to implement (1 %) + TranslatorEsperanto 1.7.5 3 methods to implement (1 %) + TranslatorPolish 1.6.3 7 methods to implement (3 %) + TranslatorVietnamese 1.6.0 12 methods to implement (5 %) + TranslatorSwedish 1.6.0 12 methods to implement (5 %) + Note: Reimplementation using UTF-8 suggested. + + TranslatorSerbian 1.6.0 12 methods to implement (5 %) + Note: Reimplementation using UTF-8 suggested. + + TranslatorSerbianCyrilic 1.6.0 12 methods to implement (5 %) + TranslatorRomanian 1.6.0 12 methods to implement (5 %) + Note: Reimplementation using UTF-8 suggested. + + TranslatorMacedonian 1.6.0 12 methods to implement (5 %) + TranslatorJapanese 1.6.0 12 methods to implement (5 %) + Note: Reimplementation using UTF-8 suggested. + + TranslatorFinnish 1.6.0 12 methods to implement (5 %) + TranslatorAfrikaans 1.6.0 12 methods to implement (5 %) + Note: Reimplementation using UTF-8 suggested. + + TranslatorSlovene 1.4.6 36 methods to implement (15 %) + Note: Reimplementation using UTF-8 suggested. + + TranslatorNorwegian 1.4.6 35 methods to implement (15 %) + Note: Reimplementation using UTF-8 suggested. + + TranslatorLithuanian 1.4.6 36 methods to implement (15 %) + Note: Reimplementation using UTF-8 suggested. + + TranslatorHungarian 1.4.6 36 methods to implement (15 %) + Note: Reimplementation using UTF-8 suggested. + + TranslatorArabic 1.4.6 35 methods to implement (15 %) + Note: Reimplementation using UTF-8 suggested. + + TranslatorUkrainian 1.4.1 36 methods to implement (15 %) + Note: Reimplementation using UTF-8 suggested. + + +---------------------------------------------------------------------- +The following translator classes derive directly from the +TranslatorEnglish. The class identifier has the suffix 'En' that says +that this is intentional. Usually, there is also a non-English based +version of the translator for the language: + + TranslatorJapaneseEn implements 5 methods -- Reimplementation using UTF-8 suggested. + TranslatorKoreanEn implements 5 methods -- Reimplementation using UTF-8 suggested. + +====================================================================== +WARNING: The following translator methods are declared in the +Translator class but their identifiers do not appear in source files. +The situation should be checked. The .cpp files and .h files excluding +the '*translator*' files in doxygen/src directory were simply searched +for occurence of the method identifiers: + + QCString idLanguageCharset() + QCString trAlphabeticalList() + QCString trDCOPMethods() + QCString trDirDependency(const char *) + QCString trFuncProtos() + QCString trFunctionPrototypeDocumentation() + QCString trGraphicalHierarchy() + QCString trSearchForIndex() + + +====================================================================== +Details for translators (classes sorted alphabetically): + + + +TranslatorAfrikaans (TranslatorAdapter_1_6_0) 12 methods to implement (5 %) +------------------- + + Implements 216 of the required methods (94 %). + + Missing methods (should be implemented): + + virtual QCString trSearching() + virtual QCString trNoMatches() + virtual QCString trLoading() + virtual QCString trDateTime(int year, int month, int day, int dayOfWeek, int hour, int minutes, int seconds, bool includeTime) + virtual QCString trFileIn(const char * name) + virtual QCString trGlobalNamespace() + virtual QCString trDirDepGraph(const char * name) + virtual QCString trDirRelation(const char * name) + virtual QCString trCiteReferences() + virtual QCString trDirDependency(const char * name) + virtual QCString trCopyright() + virtual QCString trIncludesFileIn(const char * name) + + +TranslatorArabic (TranslatorAdapter_1_4_6) 35 methods to implement (15 %) +---------------- + + Implements 193 of the required methods (84 %). + + Missing methods (should be implemented): + + virtual QCString trCompoundMembersDescriptionFortran(bool extractAll) + virtual QCString trSearching() + virtual QCString trNoMatches() + virtual QCString trGeneratedFromFilesFortran(ClassDef::CompoundType compType, bool single) + virtual QCString trLoading() + virtual QCString trSubprograms() + virtual QCString trDateTime(int year, int month, int day, int dayOfWeek, int hour, int minutes, int seconds, bool includeTime) + virtual QCString trModulesListDescription(bool extractAll) + virtual QCString trModulesList() + virtual QCString trTypeConstraints() + virtual QCString trFileIn(const char * name) + virtual QCString trGlobalNamespace() + virtual QCString trMemberFunctionDocumentationFortran() + virtual QCString trCompoundListDescriptionFortran() + virtual QCString trTypeDocumentation() + virtual QCString trModuleReference(const char * namespaceName) + virtual QCString trModulesMemberDescription(bool extractAll) + virtual QCString trModulesMembers() + virtual QCString trDirDepGraph(const char * name) + virtual QCString trModulesIndex() + virtual QCString trDirRelation(const char * name) + virtual QCString trCompoundListFortran() + virtual QCString trDataTypes() + virtual QCString trCiteReferences() + virtual QCString trDirDependency(const char * name) + virtual QCString trCopyright() + virtual QCString trIncludesFileIn(const char * name) + virtual QCString trCompoundIndexFortran() + virtual QCString trSubprogram(bool first_capital, bool singular) + virtual QCString trCallerGraph() + virtual QCString trCompoundReferenceFortran(const char * clName, ClassDef::CompoundType compType, bool isTemplate) + virtual QCString trType(bool first_capital, bool singular) + virtual QCString trModule(bool first_capital, bool singular) + virtual QCString trCompoundMembersFortran() + virtual QCString trSubprogramDocumentation() + + Obsolete methods (should be removed, never used): + + virtual QCString trHeaderFilesDescription() + virtual QCString trField(bool/*first_capital*/, bool singular) + virtual QCString trPackageDocumentation() + virtual QCString trSources() + virtual QCString trReimplementedForInternalReasons() + virtual QCString trInterfaces() + virtual QCString trHeaderFiles() + virtual QCString trBugsAndLimitations() + virtual QCString trNoDescriptionAvailable() + + +TranslatorChinesetraditional (Translator) +---------------------------- + + Implements 228 of the required methods (100 %). + + +TranslatorDanish (Translator) +---------------- + + Implements 228 of the required methods (100 %). + + +TranslatorEsperanto (TranslatorAdapter_1_7_5) 3 methods to implement (1 %) +------------------- + + Implements 225 of the required methods (98 %). + + Missing methods (should be implemented): + + virtual QCString trDirDepGraph(const char * name) + virtual QCString trCiteReferences() + virtual QCString trCopyright() + + +TranslatorFinnish (TranslatorAdapter_1_6_0) 12 methods to implement (5 %) +----------------- + + Implements 216 of the required methods (94 %). + + Missing methods (should be implemented): + + virtual QCString trSearching() + virtual QCString trNoMatches() + virtual QCString trLoading() + virtual QCString trDateTime(int year, int month, int day, int dayOfWeek, int hour, int minutes, int seconds, bool includeTime) + virtual QCString trFileIn(const char * name) + virtual QCString trGlobalNamespace() + virtual QCString trDirDepGraph(const char * name) + virtual QCString trDirRelation(const char * name) + virtual QCString trCiteReferences() + virtual QCString trDirDependency(const char * name) + virtual QCString trCopyright() + virtual QCString trIncludesFileIn(const char * name) + + +TranslatorFrench (Translator) +---------------- + + Implements 228 of the required methods (100 %). + + +TranslatorHungarian (TranslatorAdapter_1_4_6) 36 methods to implement (15 %) +------------------- + + Implements 192 of the required methods (84 %). + + Missing methods (should be implemented): + + virtual QCString trCompoundMembersDescriptionFortran(bool extractAll) + virtual QCString trSearching() + virtual QCString trNoMatches() + virtual QCString trGeneratedFromFilesFortran(ClassDef::CompoundType compType, bool single) + virtual QCString trLoading() + virtual QCString trSubprograms() + virtual QCString trDateTime(int year, int month, int day, int dayOfWeek, int hour, int minutes, int seconds, bool includeTime) + virtual QCString trModulesListDescription(bool extractAll) + virtual QCString trModulesList() + virtual QCString trTypeConstraints() + virtual QCString trFileIn(const char * name) + virtual QCString trGlobalNamespace() + virtual QCString trMemberFunctionDocumentationFortran() + virtual QCString trCompoundListDescriptionFortran() + virtual QCString trTypeDocumentation() + virtual QCString trModuleReference(const char * namespaceName) + virtual QCString trModulesMemberDescription(bool extractAll) + virtual QCString trModulesMembers() + virtual QCString trDirDepGraph(const char * name) + virtual QCString trModulesIndex() + virtual QCString trDirRelation(const char * name) + virtual QCString trCompoundListFortran() + virtual QCString trDataTypes() + virtual QCString trCiteReferences() + virtual QCString trDirDependency(const char * name) + virtual QCString trCopyright() + virtual QCString trIncludesFileIn(const char * name) + virtual QCString trCompoundIndexFortran() + virtual QCString trSubprogram(bool first_capital, bool singular) + virtual QCString trCallerGraph() + virtual QCString trEnumerationValueDocumentation() + virtual QCString trCompoundReferenceFortran(const char * clName, ClassDef::CompoundType compType, bool isTemplate) + virtual QCString trType(bool first_capital, bool singular) + virtual QCString trModule(bool first_capital, bool singular) + virtual QCString trCompoundMembersFortran() + virtual QCString trSubprogramDocumentation() + + +TranslatorIndonesian (Translator) +-------------------- + + Implements 228 of the required methods (100 %). + + +TranslatorItalian (TranslatorAdapter_1_7_5) 3 methods to implement (1 %) +----------------- + + Implements 225 of the required methods (98 %). + + Missing methods (should be implemented): + + virtual QCString trDirDepGraph(const char * name) + virtual QCString trCiteReferences() + virtual QCString trCopyright() + + +TranslatorJapanese (TranslatorAdapter_1_6_0) 12 methods to implement (5 %) +------------------ + + Implements 216 of the required methods (94 %). + + Missing methods (should be implemented): + + virtual QCString trSearching() + virtual QCString trNoMatches() + virtual QCString trLoading() + virtual QCString trDateTime(int year, int month, int day, int dayOfWeek, int hour, int minutes, int seconds, bool includeTime) + virtual QCString trFileIn(const char * name) + virtual QCString trGlobalNamespace() + virtual QCString trDirDepGraph(const char * name) + virtual QCString trDirRelation(const char * name) + virtual QCString trCiteReferences() + virtual QCString trDirDependency(const char * name) + virtual QCString trCopyright() + virtual QCString trIncludesFileIn(const char * name) + + Obsolete methods (should be removed, never used): + + virtual QCString trHeaderFilesDescription() + virtual QCString trField(bool first_capital, bool singular) + virtual QCString trPackageDocumentation() + virtual QCString trSources() + virtual QCString trReimplementedForInternalReasons() + virtual QCString trInterfaces() + virtual QCString trHeaderFiles() + virtual QCString trBugsAndLimitations() + virtual QCString trNoDescriptionAvailable() + + +TranslatorJapaneseEn (TranslatorEnglish) 223 methods to implement (97 %) +-------------------- + + Implements 5 of the required methods (2 %). + + This English-based translator implements the following methods: + + virtual QCString trRTFansicp() + virtual QCString idLanguage() + virtual QCString trRTFCharSet() + virtual QCString idLanguageCharset() + virtual QCString latexLanguageSupportCommand() + + +TranslatorKorean (TranslatorAdapter_1_7_5) 3 methods to implement (1 %) +---------------- + + Implements 225 of the required methods (98 %). + + Missing methods (should be implemented): + + virtual QCString trDirDepGraph(const char * name) + virtual QCString trCiteReferences() + virtual QCString trCopyright() + + +TranslatorKoreanEn (TranslatorEnglish) 223 methods to implement (97 %) +------------------ + + Implements 5 of the required methods (2 %). + + This English-based translator implements the following methods: + + virtual QCString trRTFansicp() + virtual QCString idLanguage() + virtual QCString trRTFCharSet() + virtual QCString idLanguageCharset() + virtual QCString latexLanguageSupportCommand() + + +TranslatorLithuanian (TranslatorAdapter_1_4_6) 36 methods to implement (15 %) +-------------------- + + Implements 192 of the required methods (84 %). + + Missing methods (should be implemented): + + virtual QCString trCompoundMembersDescriptionFortran(bool extractAll) + virtual QCString trSearching() + virtual QCString trNoMatches() + virtual QCString trGeneratedFromFilesFortran(ClassDef::CompoundType compType, bool single) + virtual QCString trLoading() + virtual QCString trSubprograms() + virtual QCString trDateTime(int year, int month, int day, int dayOfWeek, int hour, int minutes, int seconds, bool includeTime) + virtual QCString trModulesListDescription(bool extractAll) + virtual QCString trModulesList() + virtual QCString trTypeConstraints() + virtual QCString trFileIn(const char * name) + virtual QCString trGlobalNamespace() + virtual QCString trMemberFunctionDocumentationFortran() + virtual QCString trCompoundListDescriptionFortran() + virtual QCString trTypeDocumentation() + virtual QCString trModuleReference(const char * namespaceName) + virtual QCString trModulesMemberDescription(bool extractAll) + virtual QCString trModulesMembers() + virtual QCString trDirDepGraph(const char * name) + virtual QCString trModulesIndex() + virtual QCString trDirRelation(const char * name) + virtual QCString trCompoundListFortran() + virtual QCString trDataTypes() + virtual QCString trCiteReferences() + virtual QCString trDirDependency(const char * name) + virtual QCString trCopyright() + virtual QCString trIncludesFileIn(const char * name) + virtual QCString trCompoundIndexFortran() + virtual QCString trSubprogram(bool first_capital, bool singular) + virtual QCString trCallerGraph() + virtual QCString trEnumerationValueDocumentation() + virtual QCString trCompoundReferenceFortran(const char * clName, ClassDef::CompoundType compType, bool isTemplate) + virtual QCString trType(bool first_capital, bool singular) + virtual QCString trModule(bool first_capital, bool singular) + virtual QCString trCompoundMembersFortran() + virtual QCString trSubprogramDocumentation() + + +TranslatorMacedonian (TranslatorAdapter_1_6_0) 12 methods to implement (5 %) +-------------------- + + Implements 216 of the required methods (94 %). + + Missing methods (should be implemented): + + virtual QCString trSearching() + virtual QCString trNoMatches() + virtual QCString trLoading() + virtual QCString trDateTime(int year, int month, int day, int dayOfWeek, int hour, int minutes, int seconds, bool includeTime) + virtual QCString trFileIn(const char * name) + virtual QCString trGlobalNamespace() + virtual QCString trDirDepGraph(const char * name) + virtual QCString trDirRelation(const char * name) + virtual QCString trCiteReferences() + virtual QCString trDirDependency(const char * name) + virtual QCString trCopyright() + virtual QCString trIncludesFileIn(const char * name) + + +TranslatorNorwegian (TranslatorAdapter_1_4_6) 35 methods to implement (15 %) +------------------- + + Implements 193 of the required methods (84 %). + + Missing methods (should be implemented): + + virtual QCString trCompoundMembersDescriptionFortran(bool extractAll) + virtual QCString trSearching() + virtual QCString trNoMatches() + virtual QCString trGeneratedFromFilesFortran(ClassDef::CompoundType compType, bool single) + virtual QCString trLoading() + virtual QCString trSubprograms() + virtual QCString trDateTime(int year, int month, int day, int dayOfWeek, int hour, int minutes, int seconds, bool includeTime) + virtual QCString trModulesListDescription(bool extractAll) + virtual QCString trModulesList() + virtual QCString trTypeConstraints() + virtual QCString trFileIn(const char * name) + virtual QCString trGlobalNamespace() + virtual QCString trMemberFunctionDocumentationFortran() + virtual QCString trCompoundListDescriptionFortran() + virtual QCString trTypeDocumentation() + virtual QCString trModuleReference(const char * namespaceName) + virtual QCString trModulesMemberDescription(bool extractAll) + virtual QCString trModulesMembers() + virtual QCString trDirDepGraph(const char * name) + virtual QCString trModulesIndex() + virtual QCString trDirRelation(const char * name) + virtual QCString trCompoundListFortran() + virtual QCString trDataTypes() + virtual QCString trCiteReferences() + virtual QCString trDirDependency(const char * name) + virtual QCString trCopyright() + virtual QCString trIncludesFileIn(const char * name) + virtual QCString trCompoundIndexFortran() + virtual QCString trSubprogram(bool first_capital, bool singular) + virtual QCString trCallerGraph() + virtual QCString trCompoundReferenceFortran(const char * clName, ClassDef::CompoundType compType, bool isTemplate) + virtual QCString trType(bool first_capital, bool singular) + virtual QCString trModule(bool first_capital, bool singular) + virtual QCString trCompoundMembersFortran() + virtual QCString trSubprogramDocumentation() + + Obsolete methods (should be removed, never used): + + virtual QCString trHeaderFilesDescription() + virtual QCString trField(bool first_capital, bool singular) + virtual QCString trPackageDocumentation() + virtual QCString trSources() + virtual QCString trReimplementedForInternalReasons() + virtual QCString trInterfaces() + virtual QCString trHeaderFiles() + virtual QCString trBugsAndLimitations() + virtual QCString trNoDescriptionAvailable() + + +TranslatorPersian (TranslatorAdapter_1_7_5) 3 methods to implement (1 %) +----------------- + + Implements 225 of the required methods (98 %). + + Missing methods (should be implemented): + + virtual QCString trDirDepGraph(const char * name) + virtual QCString trCiteReferences() + virtual QCString trCopyright() + + +TranslatorPolish (TranslatorAdapter_1_6_3) 7 methods to implement (3 %) +---------------- + + Implements 221 of the required methods (96 %). + + Missing methods (should be implemented): + + virtual QCString trDateTime(int year, int month, int day, int dayOfWeek, int hour, int minutes, int seconds, bool includeTime) + virtual QCString trFileIn(const char * name) + virtual QCString trDirDepGraph(const char * name) + virtual QCString trCiteReferences() + virtual QCString trDirDependency(const char * name) + virtual QCString trCopyright() + virtual QCString trIncludesFileIn(const char * name) + + Obsolete methods (should be removed, never used): + + QCString trHeaderFilesDescription() + virtual QCString trField(bool first_capital, bool singular) + virtual QCString trPackageDocumentation() + QCString trSources() + QCString trReimplementedForInternalReasons() + virtual QCString trInterfaces() + QCString trHeaderFiles() + QCString trBugsAndLimitations() + QCString trNoDescriptionAvailable() + + +TranslatorRomanian (TranslatorAdapter_1_6_0) 12 methods to implement (5 %) +------------------ + + Implements 216 of the required methods (94 %). + + Missing methods (should be implemented): + + virtual QCString trSearching() + virtual QCString trNoMatches() + virtual QCString trLoading() + virtual QCString trDateTime(int year, int month, int day, int dayOfWeek, int hour, int minutes, int seconds, bool includeTime) + virtual QCString trFileIn(const char * name) + virtual QCString trGlobalNamespace() + virtual QCString trDirDepGraph(const char * name) + virtual QCString trDirRelation(const char * name) + virtual QCString trCiteReferences() + virtual QCString trDirDependency(const char * name) + virtual QCString trCopyright() + virtual QCString trIncludesFileIn(const char * name) + + +TranslatorRussian (TranslatorAdapter_1_7_5) 3 methods to implement (1 %) +----------------- + + Implements 225 of the required methods (98 %). + + Missing methods (should be implemented): + + virtual QCString trDirDepGraph(const char * name) + virtual QCString trCiteReferences() + virtual QCString trCopyright() + + +TranslatorSerbian (TranslatorAdapter_1_6_0) 12 methods to implement (5 %) +----------------- + + Implements 216 of the required methods (94 %). + + Missing methods (should be implemented): + + virtual QCString trSearching() + virtual QCString trNoMatches() + virtual QCString trLoading() + virtual QCString trDateTime(int year, int month, int day, int dayOfWeek, int hour, int minutes, int seconds, bool includeTime) + virtual QCString trFileIn(const char * name) + virtual QCString trGlobalNamespace() + virtual QCString trDirDepGraph(const char * name) + virtual QCString trDirRelation(const char * name) + virtual QCString trCiteReferences() + virtual QCString trDirDependency(const char * name) + virtual QCString trCopyright() + virtual QCString trIncludesFileIn(const char * name) + + +TranslatorSerbianCyrilic (TranslatorAdapter_1_6_0) 12 methods to implement (5 %) +------------------------ + + Implements 216 of the required methods (94 %). + + Missing methods (should be implemented): + + virtual QCString trSearching() + virtual QCString trNoMatches() + virtual QCString trLoading() + virtual QCString trDateTime(int year, int month, int day, int dayOfWeek, int hour, int minutes, int seconds, bool includeTime) + virtual QCString trFileIn(const char * name) + virtual QCString trGlobalNamespace() + virtual QCString trDirDepGraph(const char * name) + virtual QCString trDirRelation(const char * name) + virtual QCString trCiteReferences() + virtual QCString trDirDependency(const char * name) + virtual QCString trCopyright() + virtual QCString trIncludesFileIn(const char * name) + + +TranslatorSlovene (TranslatorAdapter_1_4_6) 36 methods to implement (15 %) +----------------- + + Implements 192 of the required methods (84 %). + + Missing methods (should be implemented): + + virtual QCString trCompoundMembersDescriptionFortran(bool extractAll) + virtual QCString trSearching() + virtual QCString trNoMatches() + virtual QCString trGeneratedFromFilesFortran(ClassDef::CompoundType compType, bool single) + virtual QCString trLoading() + virtual QCString trSubprograms() + virtual QCString trDateTime(int year, int month, int day, int dayOfWeek, int hour, int minutes, int seconds, bool includeTime) + virtual QCString trModulesListDescription(bool extractAll) + virtual QCString trModulesList() + virtual QCString trTypeConstraints() + virtual QCString trFileIn(const char * name) + virtual QCString trGlobalNamespace() + virtual QCString trMemberFunctionDocumentationFortran() + virtual QCString trCompoundListDescriptionFortran() + virtual QCString trTypeDocumentation() + virtual QCString trModuleReference(const char * namespaceName) + virtual QCString trModulesMemberDescription(bool extractAll) + virtual QCString trModulesMembers() + virtual QCString trDirDepGraph(const char * name) + virtual QCString trModulesIndex() + virtual QCString trDirRelation(const char * name) + virtual QCString trCompoundListFortran() + virtual QCString trDataTypes() + virtual QCString trCiteReferences() + virtual QCString trDirDependency(const char * name) + virtual QCString trCopyright() + virtual QCString trIncludesFileIn(const char * name) + virtual QCString trCompoundIndexFortran() + virtual QCString trSubprogram(bool first_capital, bool singular) + virtual QCString trCallerGraph() + virtual QCString trEnumerationValueDocumentation() + virtual QCString trCompoundReferenceFortran(const char * clName, ClassDef::CompoundType compType, bool isTemplate) + virtual QCString trType(bool first_capital, bool singular) + virtual QCString trModule(bool first_capital, bool singular) + virtual QCString trCompoundMembersFortran() + virtual QCString trSubprogramDocumentation() + + +TranslatorSpanish (TranslatorAdapter_1_7_5) 3 methods to implement (1 %) +----------------- + + Implements 225 of the required methods (98 %). + + Missing methods (should be implemented): + + virtual QCString trDirDepGraph(const char * name) + virtual QCString trCiteReferences() + virtual QCString trCopyright() + + +TranslatorSwedish (TranslatorAdapter_1_6_0) 12 methods to implement (5 %) +----------------- + + Implements 216 of the required methods (94 %). + + Missing methods (should be implemented): + + virtual QCString trSearching() + virtual QCString trNoMatches() + virtual QCString trLoading() + virtual QCString trDateTime(int year, int month, int day, int dayOfWeek, int hour, int minutes, int seconds, bool includeTime) + virtual QCString trFileIn(const char * name) + virtual QCString trGlobalNamespace() + virtual QCString trDirDepGraph(const char * name) + virtual QCString trDirRelation(const char * name) + virtual QCString trCiteReferences() + virtual QCString trDirDependency(const char * name) + virtual QCString trCopyright() + virtual QCString trIncludesFileIn(const char * name) + + +TranslatorTurkish (TranslatorAdapter_1_7_5) 3 methods to implement (1 %) +----------------- + + Implements 225 of the required methods (98 %). + + Missing methods (should be implemented): + + virtual QCString trDirDepGraph(const char * name) + virtual QCString trCiteReferences() + virtual QCString trCopyright() + + +TranslatorUkrainian (TranslatorAdapter_1_4_1) 36 methods to implement (15 %) +------------------- + + Implements 192 of the required methods (84 %). + + Missing methods (should be implemented): + + virtual QCString trCompoundMembersDescriptionFortran(bool extractAll) + virtual QCString trSearching() + virtual QCString trOverloadText() + virtual QCString trNoMatches() + virtual QCString trGeneratedFromFilesFortran(ClassDef::CompoundType compType, bool single) + virtual QCString trLoading() + virtual QCString trSubprograms() + virtual QCString trDateTime(int year, int month, int day, int dayOfWeek, int hour, int minutes, int seconds, bool includeTime) + virtual QCString trModulesListDescription(bool extractAll) + virtual QCString trModulesList() + virtual QCString trTypeConstraints() + virtual QCString trFileIn(const char * name) + virtual QCString trGlobalNamespace() + virtual QCString trMemberFunctionDocumentationFortran() + virtual QCString trCompoundListDescriptionFortran() + virtual QCString trTypeDocumentation() + virtual QCString trModuleReference(const char * namespaceName) + virtual QCString trModulesMemberDescription(bool extractAll) + virtual QCString trModulesMembers() + virtual QCString trDirDepGraph(const char * name) + virtual QCString trModulesIndex() + virtual QCString trDirRelation(const char * name) + virtual QCString trCompoundListFortran() + virtual QCString trDataTypes() + virtual QCString trCiteReferences() + virtual QCString trDirDependency(const char * name) + virtual QCString trCopyright() + virtual QCString trIncludesFileIn(const char * name) + virtual QCString trCompoundIndexFortran() + virtual QCString trSubprogram(bool first_capital, bool singular) + virtual QCString trCallerGraph() + virtual QCString trCompoundReferenceFortran(const char * clName, ClassDef::CompoundType compType, bool isTemplate) + virtual QCString trType(bool first_capital, bool singular) + virtual QCString trModule(bool first_capital, bool singular) + virtual QCString trCompoundMembersFortran() + virtual QCString trSubprogramDocumentation() + + Obsolete methods (should be removed, never used): + + virtual QCString trHeaderFilesDescription() + virtual QCString trField(bool first_capital, bool singular) + virtual QCString trPackageDocumentation() + virtual QCString trSources() + virtual QCString trReimplementedForInternalReasons() + virtual QCString trInterfaces() + virtual QCString trHeaderFiles() + virtual QCString trBugsAndLimitations() + virtual QCString trNoDescriptionAvailable() + + +TranslatorVietnamese (TranslatorAdapter_1_6_0) 12 methods to implement (5 %) +-------------------- + + Implements 216 of the required methods (94 %). + + Missing methods (should be implemented): + + virtual QCString trSearching() + virtual QCString trNoMatches() + virtual QCString trLoading() + virtual QCString trDateTime(int year, int month, int day, int dayOfWeek, int hour, int minutes, int seconds, bool includeTime) + virtual QCString trFileIn(const char * name) + virtual QCString trGlobalNamespace() + virtual QCString trDirDepGraph(const char * name) + virtual QCString trDirRelation(const char * name) + virtual QCString trCiteReferences() + virtual QCString trDirDependency(const char * name) + virtual QCString trCopyright() + virtual QCString trIncludesFileIn(const char * name) \ No newline at end of file diff --git a/trunk/doc/trouble.doc b/trunk/doc/trouble.doc new file mode 100644 index 0000000..c795b0f --- /dev/null +++ b/trunk/doc/trouble.doc @@ -0,0 +1,142 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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 trouble Troubleshooting + +<h2>Known problems:</h2> +<ul> +<li>If you have problems building doxygen from sources, please + read \ref unix_problems "this section" first. +<li>Doxygen is <em>not</em> a real compiler, it is only a lexical scanner. + This means that it can and will not detect errors in your source code. +<li>Since it is impossible to test all possible code fragments, it is + very well possible, that some valid piece of C/C++ code is not handled + properly. If you find such a piece, please send it to me, so I can + improve doxygen's parsing capabilities. Try to make the piece of code + you send as small as possible, to help me narrow down the search. +<li>Doxygen does not work properly if there are multiple classes, structs + or unions with the same name in your code. It should not crash however, + rather it should ignore all of the classes with the same name except one. +<li>Some commands do not work inside the arguments of other commands. + Inside a HTML link (i.e. \<a href="..."\>...\<a\>) for instance + other commands (including other HTML commands) do not work! + The sectioning commands are an important exception. +<li>Redundant braces can confuse doxygen in some cases. + For example: +\verbatim + void f (int); +\endverbatim + is properly parsed as a function declaration, but +\verbatim + const int (a); +\endverbatim + is also seen as a function declaration with name + <code>int</code>, because only the syntax is analyzed, + not the semantics. If the redundant braces can be detected, as in +\verbatim + int *(a[20]); +\endverbatim + then doxygen will remove the braces and correctly parse the result. +<li>Not all names in code fragments that are included in the documentation + are replaced by links (for instance when using \c SOURCE_BROWSER = \c YES) + and links to overloaded members may point to the wrong member. + This also holds for the "Referenced by" list that is generated for + each function. + + For a part this is because the code parser isn't smart enough at the + moment. I'll try to improve this in the future. But even with these + improvements not everything can be properly linked to the corresponding + documentation, because of possible ambiguities or lack of + information about the context in which the code fragment is found. +<li>It is not possible to insert a non-member function f in a class A + using the \\relates or \\relatesalso command, if class A already + has a member with name f and the same argument list. +<li>There is only very limited support for member specialization at the + moment. It only works if there is a specialized template class as + well. +<li>Not all special commands are properly translated to RTF. +<li>Version 1.8.6 of dot (and maybe earlier versions too) do not + generate proper map files, causing the graphs that doxygen generates + not to be properly clickable. +<li>PHP only: Doxygen requires that all PHP statements (i.e. code) is + wrapped in a functions/methods, otherwise you may run into parse problems. +</ul> + + +<h2>How to help</h2> +The development of Doxygen highly depends on your input! + +If you are trying Doxygen let me know what you think of it (do you +miss certain features?). Even if you decide not to use it, please let me +know why. + +\anchor bug_reports +<h2>How to report a bug</h2> + +Bugs are tracked in GNOME's <a href="http://bugzilla.gnome.org">bugzilla</a> database. +Before submitting a +<a href="http://bugzilla.gnome.org/enter_bug.cgi?product=doxygen">new bug</a>, +first <a href="http://bugzilla.gnome.org/query.cgi?format=advanced&product=doxygen">search</a> +through the database if the same bug has already been submitted by others (the doxygen +product will be preselected). +If you believe you have found a new bug, +please <a href="http://bugzilla.gnome.org/enter_bug.cgi?product=doxygen">report it</a>. + +If you are unsure whether or not something is a bug, please ask help +on the <a href="http://sourceforge.net/mail/?group_id=5971">users mailing list</a> +first (subscription is required). + +If you send only a (vague) description of a bug, you are usually not very +helpful and it will cost me much more time to figure out what you mean. +In the worst-case your bug report may even be completely ignored by me, so +always try to include the following information in your bug report: +- The version of doxygen you are using (for instance 1.5.3, use + <code>doxygen --version</code> if you are not sure). +- The name and version number of your operating system (for instance + SuSE Linux 6.4) +- It is usually a good idea to send along the configuration file as well, + but please use doxygen with the <code>-s</code> flag while generating it + to keep it small (use <code>doxygen -s -u [configName]</code> to strip + the comments from an existing config file). +- The easiest (and often the only) way for me to fix bugs is if you can + attach a small example demonstrating the problem you have to the bug report, so I can + reproduce it on my machine. Please make sure the example is valid + source code (could potentially compile) and that the problem is really + captured by the example (I often get examples that do not trigger the + actual bug!). If you intend to send more than one file please zip or tar + the files together into a single file for easier processing. + Note that when reporting a new bug you'll get a chance to attach a file to it + only \e after submitting the initial bug description. + +You can (and are encouraged to) add a patch for a bug. If you do so +please use PATCH as a keyword in the bug entry form. + +If you have ideas how to fix existing bugs and limitations please discuss them on +the <a href="http://sourceforge.net/mail/?group_id=5971">developers mailing list</a> +(subscription required). Patches can also be sent directly to dimitri@stack.nl if +you prefer not to send them via the bug tracker or mailing list. + +For patches please use +"diff -uN" or include the files you modified. If you send more than +one file please tar or zip everything, so I only have to save and download +one file. + +\htmlonly +Return to the <a href="index.html">index</a>. +\endhtmlonly + +*/ + diff --git a/trunk/doc/xmlcmds.doc b/trunk/doc/xmlcmds.doc new file mode 100644 index 0000000..2d6cbab --- /dev/null +++ b/trunk/doc/xmlcmds.doc @@ -0,0 +1,103 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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 xmlcmds XML Commands + +Doxygen supports most of the XML commands that are typically used in C# +code comments. The XML tags are defined in Appendix E of the +<a href="http://www.ecma-international.org/publications/standards/Ecma-334.htm">ECMA-334</a> +standard, which defines the C# language. Unfortunately, the specification is +not very precise and a number of the examples given are of poor quality. + +Here is the list of tags supported by doxygen: + +<ul> +<li><tt>\<c\></tt> Identifies inline text that should be rendered as a + piece of code. Similar to using <tt>\<tt\></tt>text<tt>\</tt\></tt>. +<li><tt>\<code\></tt> Set one or more lines of source code or program output. + Note that this command behaves like <tt>\\code ... \\endcode</tt> + for C# code, but it behaves like the HTML equivalent + <tt>\<code\>...\</code\></tt> for other languages. +<li><tt>\<description\></tt> Part of a <tt>\<list\></tt> command, describes an item. +<li><tt>\<example\></tt> Marks a block of text as an example, ignored by doxygen. +<li><tt>\<exception cref="member"\></tt> Identifies the exception a + method can throw. +<li><tt>\<include\></tt> Can be used to import a piece of XML from an external + file. Ignored by doxygen at the moment. +<li><tt>\<inheritdoc\></tt> Can be used to insert the documentation of a + member of a base class into the documentation of a + member of a derived class that reimplements it. +<li><tt>\<item\></tt> List item. Can only be used inside a <tt>\<list\></tt> context. +<li><tt>\<list type="type"\></tt> Starts a list, supported types are <tt>bullet</tt> + or <tt>number</tt> and <tt>table</tt>. + A list consists of a number of <tt>\<item\></tt> tags. + A list of type table, is a two column table which can have + a header. +<li><tt>\<listheader\></tt> Starts the header of a list of type "table". +<li><tt>\<para\></tt> Identifies a paragraph of text. +<li><tt>\<param name="paramName"\></tt> Marks a piece of text as the documentation + for parameter "paramName". Similar to + using \ref cmdparam "\\param". +<li><tt>\<paramref name="paramName"\></tt> Refers to a parameter with name + "paramName". Similar to using \ref cmda "\\a". +<li><tt>\<permission\></tt> Identifies the security accessibility of a member. + Ignored by doxygen. +<li><tt>\<remarks\></tt> Identifies the detailed description. +<li><tt>\<returns\></tt> Marks a piece of text as the return value of a + function or method. Similar to using \ref cmdreturn "\\return". +<li><tt>\<see cref="member"\></tt> Refers to a member. Similar to \ref cmdref "\\ref". +<li><tt>\<seealso cref="member"\></tt> Starts a "See also" section referring + to "member". Similar to using \ref cmdsa "\\sa" member. +<li><tt>\<summary\></tt> Identifies the brief description. + Similar to using \ref cmdbrief "\\brief". +<li><tt>\<term\></tt> Part of a <tt>\<list\></tt> command. +<li><tt>\<typeparam name="paramName"\></tt> Marks a piece of text as the documentation + for type parameter "paramName". Similar to + using \ref cmdparam "\\param". +<li><tt>\<typeparamref name="paramName"\></tt> Refers to a parameter with name + "paramName". Similar to using \ref cmda "\\a". +<li><tt>\<value\></tt> Identifies a property. Ignored by doxygen. +</ul> + +Here is an example of a typical piece of code using some of the above commands: + +\code +/// <summary> +/// A search engine. +/// </summary> +class Engine +{ + /// <summary> + /// The Search method takes a series of parameters to specify the search criterion + /// and returns a dataset containing the result set. + /// </summary> + /// <param name="connectionString">the connection string to connect to the + /// database holding the content to search</param> + /// <param name="maxRows">The maximum number of rows to + /// return in the result set</param> + /// <param name="searchString">The text that we are searching for</param> + /// <returns>A DataSet instance containing the matching rows. It contains a maximum + /// number of rows specified by the maxRows parameter</returns> + public DataSet Search(string connectionString, int maxRows, int searchString) + { + DataSet ds = new DataSet(); + return ds; + } +} +\endcode + +*/ + diff --git a/trunk/examples/Makefile.in b/trunk/examples/Makefile.in new file mode 100644 index 0000000..26b7c24 --- /dev/null +++ b/trunk/examples/Makefile.in @@ -0,0 +1,130 @@ + +all: class/html/index.html \ + define/html/index.html \ + enum/html/index.html \ + file/html/index.html \ + func/html/index.html \ + page/html/index.html \ + relates/html/index.html \ + author/html/index.html \ + par/html/index.html \ + overload/html/index.html \ + example/html/index.html \ + include/html/index.html \ + qtstyle/html/index.html \ + jdstyle/html/index.html \ + structcmd/html/index.html \ + autolink/html/index.html \ + restypedef/html/index.html \ + afterdoc/html/index.html \ + template/html/index.html \ + tag/html/index.html \ + group/html/index.html \ + diagrams/html/index.html \ + memgrp/html/index.html \ + docstring/html/index.html \ + pyexample/html/index.html \ + tclexample/html/index.html \ + mux/html/index.html \ + manual/html/index.html + +# Disabled since it is broken :-( +# dbusxml/html/index.html + +clean: + rm -rf class define enum file func page relates author \ + par overload example include qtstyle jdstyle structcmd \ + autolink tag restypedef afterdoc template tag group diagrams \ + memgrp docstring pyexample mux manual dbusxml tclexample + +class/html/index.html: class.h class.cfg + $(DOXYGEN)/bin/doxygen class.cfg + +define/html/index.html: define.h define.cfg + $(DOXYGEN)/bin/doxygen define.cfg + +enum/html/index.html: enum.h enum.cfg + $(DOXYGEN)/bin/doxygen enum.cfg + +file/html/index.html: file.h file.cfg + $(DOXYGEN)/bin/doxygen file.cfg + +func/html/index.html: func.h func.cfg + $(DOXYGEN)/bin/doxygen func.cfg + +page/html/index.html: page.doc page.cfg + $(DOXYGEN)/bin/doxygen page.cfg + +relates/html/index.html: relates.cpp relates.cfg + $(DOXYGEN)/bin/doxygen relates.cfg + +author/html/index.html: author.cpp author.cfg + $(DOXYGEN)/bin/doxygen author.cfg + +par/html/index.html: par.cpp par.cfg + $(DOXYGEN)/bin/doxygen par.cfg + +overload/html/index.html: overload.cpp overload.cfg + $(DOXYGEN)/bin/doxygen overload.cfg + +example/html/index.html: example.cpp example_test.cpp example.cfg + $(DOXYGEN)/bin/doxygen example.cfg + +include/html/index.html: include.cpp example_test.cpp include.cfg + $(DOXYGEN)/bin/doxygen include.cfg + +qtstyle/html/index.html: qtstyle.cpp qtstyle.cfg + $(DOXYGEN)/bin/doxygen qtstyle.cfg + +jdstyle/html/index.html: jdstyle.cpp jdstyle.cfg + $(DOXYGEN)/bin/doxygen jdstyle.cfg + +structcmd/html/index.html: structcmd.h structcmd.cfg + $(DOXYGEN)/bin/doxygen structcmd.cfg + +autolink/html/index.html: autolink.cpp autolink.cfg + $(DOXYGEN)/bin/doxygen autolink.cfg + +tag/html/index.html: tag.cpp tag.cfg example/html/index.html + $(DOXYGEN)/bin/doxygen tag.cfg +# sed -e "1,1s#perl#$(PERL)#g" tag/html/installdox >tag/html/installdox.perl +# cd tag/html ; $(PERL) installdox.perl -lexample.tag@../../example/html + +restypedef/html/index.html: restypedef.cpp restypedef.cfg + $(DOXYGEN)/bin/doxygen restypedef.cfg + +afterdoc/html/index.html: afterdoc.h afterdoc.cfg + $(DOXYGEN)/bin/doxygen afterdoc.cfg + +template/html/index.html: templ.cpp templ.cfg + $(DOXYGEN)/bin/doxygen templ.cfg + +group/html/index.html: group.cpp group.cfg + $(DOXYGEN)/bin/doxygen group.cfg + +memgrp/html/index.html: memgrp.cpp memgrp.cfg + $(DOXYGEN)/bin/doxygen memgrp.cfg + +pyexample/html/index.html: pyexample.py pyexample.cfg + $(DOXYGEN)/bin/doxygen pyexample.cfg + +tclexample/html/index.html: tclexample.tcl tclexample.cfg + $(DOXYGEN)/bin/doxygen tclexample.cfg + +mux/html/index.html: mux.vhdl mux.cfg + $(DOXYGEN)/bin/doxygen mux.cfg + +manual/html/index.html: manual.c manual.cfg + $(DOXYGEN)/bin/doxygen manual.cfg + +docstring/html/index.html: docstring.py docstring.cfg + $(DOXYGEN)/bin/doxygen docstring.cfg + +#dbusxml/html/index.html: dbusxml.xml dbusxml.cfg +# $(DOXYGEN)/bin/doxygen dbusxml.cfg + +diagrams/html/index.html: diagrams_a.h diagrams_b.h diagrams_c.h diagrams_d.h diagrams_e.h diagrams.cfg +ifneq ($(HAVE_DOT),) + $(DOXYGEN)/bin/doxygen diagrams.cfg +endif + diff --git a/trunk/examples/Makefile.win.in b/trunk/examples/Makefile.win.in new file mode 100644 index 0000000..914c5ed --- /dev/null +++ b/trunk/examples/Makefile.win.in @@ -0,0 +1,122 @@ +DOXYDIR = ..\bin + +all: class/html/index.html \ + define/html/index.html \ + enum/html/index.html \ + file/html/index.html \ + func/html/index.html \ + page/html/index.html \ + relates/html/index.html \ + author/html/index.html \ + par/html/index.html \ + overload/html/index.html \ + example/html/index.html \ + include/html/index.html \ + qtstyle/html/index.html \ + jdstyle/html/index.html \ + structcmd/html/index.html \ + autolink/html/index.html \ + restypedef/html/index.html \ + afterdoc/html/index.html \ + template/html/index.html \ + tag/html/index.html \ + group/html/index.html \ + diagrams/html/index.html \ + memgrp/html/index.html \ + docstring/html/index.html \ + pyexample/html/index.html \ + tclexample/html/index.html \ + mux/html/index.html \ + manual/html/index.html + +clean: + del /s/y class define enum file pyexample tclexample docstring + del /s/y func page relates author + del /s/y par overload example include qtstyle + del /s/y jdstyle structcmd autolink resdefine mux manual + del /s/y restypedef afterdoc template tag group diagrams memgrp + +class/html/index.html: class.h class.cfg + $(DOXYDIR)\doxygen class.cfg + +define/html/index.html: define.h define.cfg + $(DOXYDIR)\doxygen define.cfg + +enum/html/index.html: enum.h enum.cfg + $(DOXYDIR)\doxygen enum.cfg + +file/html/index.html: file.h file.cfg + $(DOXYDIR)\doxygen file.cfg + +func/html/index.html: func.h func.cfg + $(DOXYDIR)\doxygen func.cfg + +page/html/index.html: page.doc page.cfg + $(DOXYDIR)\doxygen page.cfg + +relates/html/index.html: relates.cpp relates.cfg + $(DOXYDIR)\doxygen relates.cfg + +author/html/index.html: author.cpp author.cfg + $(DOXYDIR)\doxygen author.cfg + +par/html/index.html: par.cpp par.cfg + $(DOXYDIR)\doxygen par.cfg + +overload/html/index.html: overload.cpp overload.cfg + $(DOXYDIR)\doxygen overload.cfg + +example/html/index.html: example.cpp example_test.cpp example.cfg + $(DOXYDIR)\doxygen example.cfg + +include/html/index.html: include.cpp example_test.cpp include.cfg + $(DOXYDIR)\doxygen include.cfg + +qtstyle/html/index.html: qtstyle.cpp qtstyle.cfg + $(DOXYDIR)\doxygen qtstyle.cfg + +jdstyle/html/index.html: jdstyle.cpp jdstyle.cfg + $(DOXYDIR)\doxygen jdstyle.cfg + +structcmd/html/index.html: structcmd.h structcmd.cfg + $(DOXYDIR)\doxygen structcmd.cfg + +autolink/html/index.html: autolink.cpp autolink.cfg + $(DOXYDIR)\doxygen autolink.cfg + +tag/html/index.html: tag.cpp tag.cfg + $(DOXYDIR)\doxygen tag.cfg + +restypedef/html/index.html: restypedef.cpp restypedef.cfg + $(DOXYDIR)\doxygen restypedef.cfg + +afterdoc/html/index.html: afterdoc.h afterdoc.cfg + $(DOXYDIR)\doxygen afterdoc.cfg + +template/html/index.html: templ.cpp templ.cfg + $(DOXYDIR)\doxygen templ.cfg + +group/html/index.html: group.cpp group.cfg + $(DOXYDIR)\doxygen group.cfg + +memgrp/html/index.html: memgrp.cpp memgrp.cfg + $(DOXYDIR)\doxygen memgrp.cfg + +pyexample/html/index.html: pyexample.py pyexample.cfg + $(DOXYDIR)\doxygen pyexample.cfg + +tclexample/html/index.html: tclexample.tcl tclexample.cfg + $(DOXYDIR)\doxygen tclexample.cfg + +mux/html/index.html: mux.vhdl mux.cfg + $(DOXYDIR)\doxygen mux.cfg + +manual/html/index.html: manual.c manual.cfg + $(DOXYDIR)\doxygen manual.cfg + +docstring/html/index.html: docstring.py docstring.cfg + $(DOXYDIR)\doxygen docstring.cfg + +diagrams/html/index.html: diagrams_a.h diagrams_b.h diagrams_c.h diagrams_d.h diagrams_e.h diagrams.cfg + $(DOXYDIR)\doxygen diagrams.cfg + diff --git a/trunk/examples/afterdoc.cfg b/trunk/examples/afterdoc.cfg new file mode 100644 index 0000000..fcdbcae --- /dev/null +++ b/trunk/examples/afterdoc.cfg @@ -0,0 +1,10 @@ +PROJECT_NAME = "AfterDocs" +OUTPUT_DIRECTORY = afterdoc +GENERATE_LATEX = NO +GENERATE_MAN = NO +GENERATE_RTF = NO +CASE_SENSE_NAMES = NO +INPUT = afterdoc.h +QUIET = YES +JAVADOC_AUTOBRIEF = YES +SEARCHENGINE = NO diff --git a/trunk/examples/afterdoc.h b/trunk/examples/afterdoc.h new file mode 100644 index 0000000..907dabe --- /dev/null +++ b/trunk/examples/afterdoc.h @@ -0,0 +1,18 @@ +/*! A test class */ + +class Test +{ + public: + /** An enum type. + * The documentation block cannot be put after the enum! + */ + enum EnumType + { + int EVal1, /**< enum value 1 */ + int EVal2 /**< enum value 2 */ + }; + void member(); //!< a member function. + + protected: + int value; /*!< an integer value */ +}; diff --git a/trunk/examples/author.cfg b/trunk/examples/author.cfg new file mode 100644 index 0000000..8bb04f7 --- /dev/null +++ b/trunk/examples/author.cfg @@ -0,0 +1,10 @@ +PROJECT_NAME = "Author Command" +OUTPUT_DIRECTORY = author +GENERATE_LATEX = NO +GENERATE_MAN = NO +GENERATE_RTF = NO +CASE_SENSE_NAMES = NO +INPUT = author.cpp +QUIET = YES +JAVADOC_AUTOBRIEF = YES +SEARCHENGINE = NO diff --git a/trunk/examples/author.cpp b/trunk/examples/author.cpp new file mode 100644 index 0000000..709354f --- /dev/null +++ b/trunk/examples/author.cpp @@ -0,0 +1,13 @@ +/*! + * \brief Pretty nice class. + * \details This class is used to demonstrate a number of section commands. + * \author John Doe + * \author Jan Doe + * \version 4.1a + * \date 1990-2011 + * \pre First initialize the system. + * \bug Not all memory is freed when deleting an object of this class. + * \warning Improper use can crash your application + * \copyright GNU Public License. + */ +class SomeNiceClass {}; diff --git a/trunk/examples/autolink.cfg b/trunk/examples/autolink.cfg new file mode 100644 index 0000000..406d52c --- /dev/null +++ b/trunk/examples/autolink.cfg @@ -0,0 +1,10 @@ +PROJECT_NAME = "Automatic link generation" +OUTPUT_DIRECTORY = autolink +GENERATE_LATEX = NO +GENERATE_MAN = NO +GENERATE_RTF = NO +CASE_SENSE_NAMES = NO +INPUT = autolink.cpp +QUIET = YES +JAVADOC_AUTOBRIEF = YES +SEARCHENGINE = NO diff --git a/trunk/examples/autolink.cpp b/trunk/examples/autolink.cpp new file mode 100644 index 0000000..e028f22 --- /dev/null +++ b/trunk/examples/autolink.cpp @@ -0,0 +1,99 @@ +/*! \file autolink.cpp + Testing automatic link generation. + + A link to a member of the Test class: Test::member, + + More specific links to the each of the overloaded members: + Test::member(int) and Test#member(int,int) + + A link to a protected member variable of Test: Test#var, + + A link to the global enumeration type #GlobEnum. + + A link to the define #ABS(x). + + A link to the destructor of the Test class: Test::~Test, + + A link to the typedef ::B. + + A link to the enumeration type Test::EType + + A link to some enumeration values Test::Val1 and ::GVal2 +*/ + +/*! + Since this documentation block belongs to the class Test no link to + Test is generated. + + Two ways to link to a constructor are: #Test and Test(). + + Links to the destructor are: #~Test and ~Test(). + + A link to a member in this class: member(). + + More specific links to the each of the overloaded members: + member(int) and member(int,int). + + A link to the variable #var. + + A link to the global typedef ::B. + + A link to the global enumeration type #GlobEnum. + + A link to the define ABS(x). + + A link to a variable \link #var using another text\endlink as a link. + + A link to the enumeration type #EType. + + A link to some enumeration values: \link Test::Val1 Val1 \endlink and ::GVal1. + + And last but not least a link to a file: autolink.cpp. + + \sa Inside a see also section any word is checked, so EType, + Val1, GVal1, ~Test and member will be replaced by links in HTML. +*/ + +class Test +{ + public: + Test(); //!< constructor + ~Test(); //!< destructor + void member(int); /**< A member function. Details. */ + void member(int,int); /**< An overloaded member function. Details */ + + /** An enum type. More details */ + enum EType { + Val1, /**< enum value 1 */ + Val2 /**< enum value 2 */ + }; + + protected: + int var; /**< A member variable */ +}; + +/*! details. */ +Test::Test() { } + +/*! details. */ +Test::~Test() { } + +/*! A global variable. */ +int globVar; + +/*! A global enum. */ +enum GlobEnum { + GVal1, /*!< global enum value 1 */ + GVal2 /*!< global enum value 2 */ + }; + +/*! + * A macro definition. + */ +#define ABS(x) (((x)>0)?(x):-(x)) + +typedef Test B; + +/*! \fn typedef Test B + * A type definition. + */ diff --git a/trunk/examples/class.cfg b/trunk/examples/class.cfg new file mode 100644 index 0000000..f2c4796 --- /dev/null +++ b/trunk/examples/class.cfg @@ -0,0 +1,10 @@ +PROJECT_NAME = "Class Command" +OUTPUT_DIRECTORY = class +GENERATE_LATEX = NO +GENERATE_MAN = NO +GENERATE_RTF = NO +CASE_SENSE_NAMES = NO +INPUT = class.h +QUIET = YES +JAVADOC_AUTOBRIEF = YES +SEARCHENGINE = NO diff --git a/trunk/examples/class.h b/trunk/examples/class.h new file mode 100644 index 0000000..e5a9121 --- /dev/null +++ b/trunk/examples/class.h @@ -0,0 +1,11 @@ +/* A dummy class */ + +class Test +{ +}; + +/*! \class Test class.h "inc/class.h" + * \brief This is a test class. + * + * Some details about the Test class + */ diff --git a/trunk/examples/dbusxml.cfg b/trunk/examples/dbusxml.cfg new file mode 100644 index 0000000..23b9dea --- /dev/null +++ b/trunk/examples/dbusxml.cfg @@ -0,0 +1,12 @@ +PROJECT_NAME = "DBusXMLDocs" +OUTPUT_DIRECTORY = dbusxml +GENERATE_LATEX = NO +GENERATE_MAN = NO +GENERATE_RTF = NO +CASE_SENSE_NAMES = NO +INPUT = dbusxml.xml +QUIET = YES +JAVADOC_AUTOBRIEF = YES +EXTRACT_ALL = YES +SEARCHENGINE = NO +EXTENSION_MAPPING = xml=dbusxml diff --git a/trunk/examples/dbusxml.xml b/trunk/examples/dbusxml.xml new file mode 100644 index 0000000..4ab7f78 --- /dev/null +++ b/trunk/examples/dbusxml.xml @@ -0,0 +1,78 @@ +<?xml version="1.0" ?> +<!-- Comment --> +<!--*< File comment --> +<node name="/SomeNode" xmlns:dx="http://psiamp.org/dtd/doxygen_dbusxml.dtd"> + <!--* test struct outside a namespace and interface --> + <dx:struct name="StructOutsideNamespace"> + <!--* member 1 --> + <dx:member name="member1" type="s"/> + <!--* complex member 1 --> + <dx:member name="complexMember1" type="(ssu)"/> + </dx:struct> + + <!--* Test flag set --> + <dx:flagset name="flagset"> + <!--* Flag 1 of flagset. --> + <dx:value name="FLAG1"/> + </dx:flagset> + + <!--* namespace comment --> + <dx:namespace name="SomeNamespace"> + <!--* struct inside a namespace --> + <dx:struct name="StructInNamespace"> + <!--* member 2 --> + <dx:member name="member2" type="s"/> + </dx:struct> + </dx:namespace> + <!--* Documentation on the interface --> + <interface name="nl.stack.doxygen.test.interface"> + <!--* Test Enum documentation --> + <dx:enum name="TestEnum"> + <!--* key 1 with value 13 --> + <dx:value name="KEY1" value="13"/> + <!--* key 2 without a value --> + <dx:value name="KEY2"/> + </dx:enum> + + <!--* struct inside a interface --> + <dx:struct name="StructInInterface"> + <!--* member 3 --> + <dx:member name="member3" type="s"/> + <!--* Struct in a struct --> + <dx:struct name="StructInAStruct"> + <!--* member4 --> + <dx:member name="member4" type="s"/> + </dx:struct> + <!--* struct member --> + <dx:member name="structMembor" type="(s)" named-type="StructInAStruct"/> + </dx:struct> + <!--* Document method + + Some extended documentation for the method. + + @param[in] input blah. + @param[out] output blub + --> + <method name="method"> + <arg direction="in" name="input" type="(s(s))" named-type="::nl::stack::doxygen::test::interface::StructInInterface"/> + <arg direction="out" type="v" name="output"/> + </method> + + <signal name="signal"> + <!--*< Documentation for signal. + + @param parameter some parameter. + --> + <arg name="parameter" type="s"/> + </signal> + + <!--* property documentation --> + <property name="property" type="s" access="readwrite"/> + + <!--* property documentation read-only --> + <property name="propertyRead" type="s" access="read"/> + <!--* property documentation write-only --> + <property name="propertyWrite" type="s" access="write"/> + </interface> +</node> +<!-- vim:set sw=2 sts=2 et ft=xml: --> diff --git a/trunk/examples/define.cfg b/trunk/examples/define.cfg new file mode 100644 index 0000000..547591e --- /dev/null +++ b/trunk/examples/define.cfg @@ -0,0 +1,11 @@ +PROJECT_NAME = "Define Command" +OUTPUT_DIRECTORY = define +GENERATE_LATEX = NO +GENERATE_MAN = NO +GENERATE_RTF = NO +CASE_SENSE_NAMES = NO +INPUT = define.h +ENABLE_PREPROCESSING = YES +QUIET = YES +JAVADOC_AUTOBRIEF = YES +SEARCHENGINE = NO diff --git a/trunk/examples/define.h b/trunk/examples/define.h new file mode 100644 index 0000000..c330447 --- /dev/null +++ b/trunk/examples/define.h @@ -0,0 +1,18 @@ +/*! \file define.h + \brief testing defines + + This is to test the documentation of defines. +*/ + +/*! + \def MAX(x,y) + Computes the maximum of \a x and \a y. +*/ + +/*! + Computes the absolute value of its argument \a x. +*/ +#define ABS(x) (((x)>0)?(x):-(x)) +#define MAX(x,y) ((x)>(y)?(x):(y)) +#define MIN(x,y) ((x)>(y)?(y):(x)) + /*!< Computes the minimum of \a x and \a y. */ diff --git a/trunk/examples/diagrams.cfg b/trunk/examples/diagrams.cfg new file mode 100644 index 0000000..9bc5551 --- /dev/null +++ b/trunk/examples/diagrams.cfg @@ -0,0 +1,14 @@ +PROJECT_NAME = "Diagrams" +OUTPUT_DIRECTORY = diagrams +HAVE_DOT = YES +EXTRACT_ALL = YES +GENERATE_LATEX = NO +GENERATE_MAN = NO +GENERATE_RTF = NO +CASE_SENSE_NAMES = NO +ENABLE_PREPROCESSING = YES +INPUT = . +FILE_PATTERNS = diagrams_*.h +QUIET = YES +JAVADOC_AUTOBRIEF = YES +SEARCHENGINE = NO diff --git a/trunk/examples/diagrams_a.h b/trunk/examples/diagrams_a.h new file mode 100644 index 0000000..047a8ab --- /dev/null +++ b/trunk/examples/diagrams_a.h @@ -0,0 +1,4 @@ +#ifndef _DIAGRAMS_A_H +#define _DIAGRAMS_A_H +class A { public: A *m_self; }; +#endif diff --git a/trunk/examples/diagrams_b.h b/trunk/examples/diagrams_b.h new file mode 100644 index 0000000..5fcd247 --- /dev/null +++ b/trunk/examples/diagrams_b.h @@ -0,0 +1,5 @@ +#ifndef _DIAGRAMS_B_H +#define _DIAGRAMS_B_H +class A; +class B { public: A *m_a; }; +#endif diff --git a/trunk/examples/diagrams_c.h b/trunk/examples/diagrams_c.h new file mode 100644 index 0000000..e4ec11d --- /dev/null +++ b/trunk/examples/diagrams_c.h @@ -0,0 +1,6 @@ +#ifndef _DIAGRAMS_C_H +#define _DIAGRAMS_C_H +#include "diagrams_c.h" +class D; +class C : public A { public: D *m_d; }; +#endif diff --git a/trunk/examples/diagrams_d.h b/trunk/examples/diagrams_d.h new file mode 100644 index 0000000..3e635ce --- /dev/null +++ b/trunk/examples/diagrams_d.h @@ -0,0 +1,7 @@ +#ifndef _DIAGRAM_D_H +#define _DIAGRAM_D_H +#include "diagrams_a.h" +#include "diagrams_b.h" +class C; +class D : virtual protected A, private B { public: C m_c; }; +#endif diff --git a/trunk/examples/diagrams_e.h b/trunk/examples/diagrams_e.h new file mode 100644 index 0000000..5282388 --- /dev/null +++ b/trunk/examples/diagrams_e.h @@ -0,0 +1,5 @@ +#ifndef _DIAGRAM_E_H +#define _DIAGRAM_E_H +#include "diagrams_d.h" +class E : public D {}; +#endif diff --git a/trunk/examples/docstring.cfg b/trunk/examples/docstring.cfg new file mode 100644 index 0000000..2a5cd9a --- /dev/null +++ b/trunk/examples/docstring.cfg @@ -0,0 +1,11 @@ +PROJECT_NAME = "Python" +OUTPUT_DIRECTORY = docstring +EXTRACT_ALL = YES +GENERATE_LATEX = NO +GENERATE_MAN = NO +GENERATE_RTF = NO +OPTIMIZE_OUTPUT_JAVA = YES +INPUT = docstring.py +QUIET = YES +JAVADOC_AUTOBRIEF = YES +SEARCHENGINE = NO diff --git a/trunk/examples/docstring.py b/trunk/examples/docstring.py new file mode 100644 index 0000000..07b13e0 --- /dev/null +++ b/trunk/examples/docstring.py @@ -0,0 +1,27 @@ +"""@package docstring +Documentation for this module. + +More details. +""" + +def func(): + """Documentation for a function. + + More details. + """ + pass + +class PyClass: + """Documentation for a class. + + More details. + """ + + def __init__(self): + """The constructor.""" + self._memVar = 0; + + def PyMethod(self): + """Documentation for a method.""" + pass + diff --git a/trunk/examples/enum.cfg b/trunk/examples/enum.cfg new file mode 100644 index 0000000..ed83670 --- /dev/null +++ b/trunk/examples/enum.cfg @@ -0,0 +1,10 @@ +PROJECT_NAME = "Enum Command" +OUTPUT_DIRECTORY = enum +GENERATE_LATEX = NO +GENERATE_MAN = NO +GENERATE_RTF = NO +CASE_SENSE_NAMES = NO +INPUT = enum.h +QUIET = YES +JAVADOC_AUTOBRIEF = YES +SEARCHENGINE = NO diff --git a/trunk/examples/enum.h b/trunk/examples/enum.h new file mode 100644 index 0000000..4c54fab --- /dev/null +++ b/trunk/examples/enum.h @@ -0,0 +1,24 @@ +class Test +{ + public: + enum TEnum { Val1, Val2 }; + + /*! Another enum, with inline docs */ + enum AnotherEnum + { + V1, /*!< value 1 */ + V2 /*!< value 2 */ + }; +}; + +/*! \class Test + * The class description. + */ + +/*! \enum Test::TEnum + * A description of the enum type. + */ + +/*! \var Test::TEnum Test::Val1 + * The description of the first enum value. + */ diff --git a/trunk/examples/example.cfg b/trunk/examples/example.cfg new file mode 100644 index 0000000..4c5c869 --- /dev/null +++ b/trunk/examples/example.cfg @@ -0,0 +1,12 @@ +PROJECT_NAME = "Example Command" +OUTPUT_DIRECTORY = example +GENERATE_TAGFILE = example.tag +GENERATE_LATEX = NO +GENERATE_MAN = NO +GENERATE_RTF = NO +CASE_SENSE_NAMES = NO +INPUT = example.cpp +EXAMPLE_PATH = example_test.cpp +QUIET = YES +JAVADOC_AUTOBRIEF = YES +SEARCHENGINE = NO diff --git a/trunk/examples/example.cpp b/trunk/examples/example.cpp new file mode 100644 index 0000000..230d6ec --- /dev/null +++ b/trunk/examples/example.cpp @@ -0,0 +1,19 @@ +/** A Test class. + * More details about this class. + */ + +class Test +{ + public: + /** An example member function. + * More details about this function. + */ + void example(); +}; + +void Test::example() {} + +/** \example example_test.cpp + * This is an example of how to use the Test class. + * More details about this example. + */ diff --git a/trunk/examples/example.tag b/trunk/examples/example.tag new file mode 100644 index 0000000..a38ab5c --- /dev/null +++ b/trunk/examples/example.tag @@ -0,0 +1,14 @@ +<?xml version='1.0' encoding='ISO-8859-1' standalone='yes' ?> +<tagfile> + <compound kind="class"> + <name>Test</name> + <filename>class_test.html</filename> + <member kind="function"> + <type>void</type> + <name>example</name> + <anchorfile>class_test.html</anchorfile> + <anchor>a47b775f65718978f1ffcd96376f8ecfa</anchor> + <arglist>()</arglist> + </member> + </compound> +</tagfile> diff --git a/trunk/examples/example_test.cpp b/trunk/examples/example_test.cpp new file mode 100644 index 0000000..a7e1643 --- /dev/null +++ b/trunk/examples/example_test.cpp @@ -0,0 +1,5 @@ +void main() +{ + Test t; + t.example(); +} diff --git a/trunk/examples/file.cfg b/trunk/examples/file.cfg new file mode 100644 index 0000000..e54b1c7 --- /dev/null +++ b/trunk/examples/file.cfg @@ -0,0 +1,10 @@ +PROJECT_NAME = "File Command" +OUTPUT_DIRECTORY = file +GENERATE_LATEX = NO +GENERATE_MAN = NO +GENERATE_RTF = NO +CASE_SENSE_NAMES = NO +INPUT = file.h +QUIET = YES +JAVADOC_AUTOBRIEF = YES +SEARCHENGINE = NO diff --git a/trunk/examples/file.h b/trunk/examples/file.h new file mode 100644 index 0000000..8dff6cb --- /dev/null +++ b/trunk/examples/file.h @@ -0,0 +1,10 @@ +/** \file file.h + * A brief file description. + * A more elaborated file description. + */ + +/** + * A global integer value. + * More details about this value. + */ +extern int globalValue; diff --git a/trunk/examples/func.cfg b/trunk/examples/func.cfg new file mode 100644 index 0000000..32c3190 --- /dev/null +++ b/trunk/examples/func.cfg @@ -0,0 +1,10 @@ +PROJECT_NAME = "Fn Command" +OUTPUT_DIRECTORY = func +GENERATE_LATEX = NO +GENERATE_MAN = NO +GENERATE_RTF = NO +CASE_SENSE_NAMES = NO +INPUT = func.h +QUIET = YES +JAVADOC_AUTOBRIEF = YES +SEARCHENGINE = NO diff --git a/trunk/examples/func.h b/trunk/examples/func.h new file mode 100644 index 0000000..b335448 --- /dev/null +++ b/trunk/examples/func.h @@ -0,0 +1,21 @@ +class Test +{ + public: + const char *member(char,int) throw(std::out_of_range); +}; + +const char *Test::member(char c,int n) throw(std::out_of_range) {} + +/*! \class Test + * \brief Test class. + * + * Details about Test. + */ + +/*! \fn const char *Test::member(char c,int n) + * \brief A member function. + * \param c a character. + * \param n an integer. + * \exception std::out_of_range parameter is out of range. + * \return a character pointer. + */ diff --git a/trunk/examples/group.cfg b/trunk/examples/group.cfg new file mode 100644 index 0000000..98cc27e --- /dev/null +++ b/trunk/examples/group.cfg @@ -0,0 +1,10 @@ +PROJECT_NAME = "Grouping" +OUTPUT_DIRECTORY = group +GENERATE_LATEX = NO +GENERATE_MAN = NO +GENERATE_RTF = NO +CASE_SENSE_NAMES = NO +INPUT = group.cpp +QUIET = YES +JAVADOC_AUTOBRIEF = YES +SEARCHENGINE = NO diff --git a/trunk/examples/group.cpp b/trunk/examples/group.cpp new file mode 100644 index 0000000..b120b90 --- /dev/null +++ b/trunk/examples/group.cpp @@ -0,0 +1,88 @@ +/** @defgroup group1 The First Group + * This is the first group + * @{ + */ + +/** @brief class C1 in group 1 */ +class C1 {}; + +/** @brief class C2 in group 1 */ +class C2 {}; + +/** function in group 1 */ +void func() {} + +/** @} */ // end of group1 + +/** + * @defgroup group2 The Second Group + * This is the second group + */ + +/** @defgroup group3 The Third Group + * This is the third group + */ + +/** @defgroup group4 The Fourth Group + * @ingroup group3 + * Group 4 is a subgroup of group 3 + */ + +/** + * @ingroup group2 + * @brief class C3 in group 2 + */ +class C3 {}; + +/** @ingroup group2 + * @brief class C4 in group 2 + */ +class C4 {}; + +/** @ingroup group3 + * @brief class C5 in @link group3 the third group@endlink. + */ +class C5 {}; + +/** @ingroup group1 group2 group3 group4 + * namespace N1 is in four groups + * @sa @link group1 The first group@endlink, group2, group3, group4 + * + * Also see @ref mypage2 + */ +namespace N1 {}; + +/** @file + * @ingroup group3 + * @brief this file in group 3 + */ + +/** @defgroup group5 The Fifth Group + * This is the fifth group + * @{ + */ + +/** @page mypage1 This is a section in group 5 + * Text of the first section + */ + +/** @page mypage2 This is another section in group 5 + * Text of the second section + */ + +/** @} */ // end of group5 + +/** @addtogroup group1 + * + * More documentation for the first group. + * @{ + */ + +/** another function in group 1 */ +void func2() {} + +/** yet another function in group 1 */ +void func3() {} + +/** @} */ // end of group1 + diff --git a/trunk/examples/include.cfg b/trunk/examples/include.cfg new file mode 100644 index 0000000..8516b32 --- /dev/null +++ b/trunk/examples/include.cfg @@ -0,0 +1,11 @@ +PROJECT_NAME = "Include Command" +OUTPUT_DIRECTORY = include +GENERATE_LATEX = NO +GENERATE_MAN = NO +GENERATE_RTF = NO +CASE_SENSE_NAMES = NO +INPUT = include.cpp +EXAMPLE_PATH = example_test.cpp +QUIET = YES +JAVADOC_AUTOBRIEF = YES +SEARCHENGINE = NO diff --git a/trunk/examples/include.cpp b/trunk/examples/include.cpp new file mode 100644 index 0000000..c50ab96 --- /dev/null +++ b/trunk/examples/include.cpp @@ -0,0 +1,22 @@ + +/*! A test class. */ + +class Test +{ + public: + /// a member function + void example(); +}; + +/*! \page example + * \dontinclude example_test.cpp + * Our main function starts like this: + * \skip main + * \until { + * First we create a object \c t of the Test class. + * \skipline Test + * Then we call the example member function + * \line example + * After that our little test routine ends. + * \line } + */ diff --git a/trunk/examples/jdstyle.cfg b/trunk/examples/jdstyle.cfg new file mode 100644 index 0000000..02bf18c --- /dev/null +++ b/trunk/examples/jdstyle.cfg @@ -0,0 +1,10 @@ +PROJECT_NAME = "JavaDoc Style" +OUTPUT_DIRECTORY = jdstyle +GENERATE_LATEX = NO +GENERATE_MAN = NO +GENERATE_RTF = NO +CASE_SENSE_NAMES = NO +INPUT = jdstyle.cpp +QUIET = YES +JAVADOC_AUTOBRIEF = YES +SEARCHENGINE = NO diff --git a/trunk/examples/jdstyle.cpp b/trunk/examples/jdstyle.cpp new file mode 100644 index 0000000..bd8b9a7 --- /dev/null +++ b/trunk/examples/jdstyle.cpp @@ -0,0 +1,66 @@ +/** + * A test class. A more elaborate class description. + */ + +class Test +{ + public: + + /** + * An enum. + * More detailed enum description. + */ + + enum TEnum { + TVal1, /**< enum value TVal1. */ + TVal2, /**< enum value TVal2. */ + TVal3 /**< enum value TVal3. */ + } + *enumPtr, /**< enum pointer. Details. */ + enumVar; /**< enum variable. Details. */ + + /** + * A constructor. + * A more elaborate description of the constructor. + */ + Test(); + + /** + * A destructor. + * A more elaborate description of the destructor. + */ + ~Test(); + + /** + * a normal member taking two arguments and returning an integer value. + * @param a an integer argument. + * @param s a constant character pointer. + * @see Test() + * @see ~Test() + * @see testMeToo() + * @see publicVar() + * @return The test results + */ + int testMe(int a,const char *s); + + /** + * A pure virtual member. + * @see testMe() + * @param c1 the first argument. + * @param c2 the second argument. + */ + virtual void testMeToo(char c1,char c2) = 0; + + /** + * a public variable. + * Details. + */ + int publicVar; + + /** + * a function variable. + * Details. + */ + int (*handler)(int a,int b); +}; + diff --git a/trunk/examples/manual.c b/trunk/examples/manual.c new file mode 100644 index 0000000..fac6832 --- /dev/null +++ b/trunk/examples/manual.c @@ -0,0 +1,87 @@ +/** + * \file manual.c + */ + +typedef struct Object Object; //!< Object type +typedef struct Vehicle Vehicle; //!< Vehicle type +typedef struct Car Car; //!< Car type +typedef struct Truck Truck; //!< Truck type + +/*! + * Base object class. + */ +struct Object +{ + int ref; //!< \private Reference count. +}; + + +/*! + * Increments object reference count by one. + * \public \memberof Object + */ +static Object * objRef(Object *obj); + + +/*! + * Decrements object reference count by one. + * \public \memberof Object + */ +static Object * objUnref(Object *obj); + + +/*! + * Vehicle class. + * \extends Object + */ +struct Vehicle +{ + Object base; //!< \protected Base class. +}; + + +/*! + * Starts the vehicle. + * \public \memberof Vehicle + */ +void vehicleStart(Vehicle *obj); + + +/*! + * Stops the vehicle. + * \public \memberof Vehicle + */ +void vehicleStop(Vehicle *obj); + + +/*! + * Car class. + * \extends Vehicle + */ +struct Car +{ + Vehicle base; //!< \protected Base class. +}; + + +/*! + * Truck class. + * \extends Vehicle + */ +struct Truck +{ + Vehicle base; //!< \protected Base class. +}; + + +/*! + * Main function. + * + * Ref vehicleStart(), objRef(), objUnref(). + */ +int main(void) +{ + Car c; + vehicleStart((Vehicle*) &c); +} + diff --git a/trunk/examples/manual.cfg b/trunk/examples/manual.cfg new file mode 100644 index 0000000..9359842 --- /dev/null +++ b/trunk/examples/manual.cfg @@ -0,0 +1,16 @@ +PROJECT_NAME = "Manual inheritance and membership" +OUTPUT_DIRECTORY = manual +GENERATE_LATEX = NO +GENERATE_MAN = NO +GENERATE_RTF = NO +CASE_SENSE_NAMES = NO +INPUT = manual.c +QUIET = YES +JAVADOC_AUTOBRIEF = YES +EXTRACT_PRIVATE = YES +EXTRACT_STATIC = YES +TYPEDEF_HIDES_STRUCT = YES +INLINE_SOURCES = YES +REFERENCED_BY_RELATION = YES +REFERENCES_RELATION = YES +SEARCHENGINE = NO diff --git a/trunk/examples/memgrp.cfg b/trunk/examples/memgrp.cfg new file mode 100644 index 0000000..a69c33c --- /dev/null +++ b/trunk/examples/memgrp.cfg @@ -0,0 +1,11 @@ +PROJECT_NAME = "Member Grouping" +OUTPUT_DIRECTORY = memgrp +GENERATE_LATEX = NO +GENERATE_MAN = NO +GENERATE_RTF = NO +CASE_SENSE_NAMES = NO +INPUT = memgrp.cpp +QUIET = YES +DISTRIBUTE_GROUP_DOC = YES +JAVADOC_AUTOBRIEF = YES +SEARCHENGINE = NO diff --git a/trunk/examples/memgrp.cpp b/trunk/examples/memgrp.cpp new file mode 100644 index 0000000..77f03a4 --- /dev/null +++ b/trunk/examples/memgrp.cpp @@ -0,0 +1,41 @@ +/** A class. Details */ +class Test +{ + public: + //@{ + /** Same documentation for both members. Details */ + void func1InGroup1(); + void func2InGroup1(); + //@} + + /** Function without group. Details. */ + void ungroupedFunction(); + void func1InGroup2(); + protected: + void func2InGroup2(); +}; + +void Test::func1InGroup1() {} +void Test::func2InGroup1() {} + +/** @name Group2 + * Description of group 2. + */ +///@{ +/** Function 2 in group 2. Details. */ +void Test::func2InGroup2() {} +/** Function 1 in group 2. Details. */ +void Test::func1InGroup2() {} +///@} + +/*! \file + * docs for this file + */ + +//!@{ +//! one description for all members of this group +//! (because DISTRIBUTE_GROUP_DOC is YES in the config file) +#define A 1 +#define B 2 +void glob_func(); +//!@} diff --git a/trunk/examples/mux.cfg b/trunk/examples/mux.cfg new file mode 100644 index 0000000..86abd9e --- /dev/null +++ b/trunk/examples/mux.cfg @@ -0,0 +1,14 @@ +PROJECT_NAME = Mux +OUTPUT_DIRECTORY = mux +GENERATE_LATEX = NO +GENERATE_MAN = NO +GENERATE_RTF = NO +CASE_SENSE_NAMES = NO +INPUT = mux.vhdl +OPTIMIZE_OUTPUT_VHDL = YES +QUIET = YES +INHERIT_DOCS = YES +EXTRACT_PRIVATE = YES +HIDE_SCOPE_NAMES = YES +INHERIT_DOCS = NO +SEARCHENGINE = NO diff --git a/trunk/examples/mux.vhdl b/trunk/examples/mux.vhdl new file mode 100644 index 0000000..211e56e --- /dev/null +++ b/trunk/examples/mux.vhdl @@ -0,0 +1,32 @@ +------------------------------------------------------- +--! @file +--! @brief 2:1 Mux using with-select +------------------------------------------------------- + +--! Use standard library +library ieee; +--! Use logic elements + use ieee.std_logic_1164.all; + +--! Mux entity brief description + +--! Detailed description of this +--! mux design element. +entity mux_using_with is + port ( + din_0 : in std_logic; --! Mux first input + din_1 : in std_logic; --! Mux Second input + sel : in std_logic; --! Select input + mux_out : out std_logic --! Mux output + ); +end entity; + +--! @brief Architure definition of the MUX +--! @details More details about this mux element. +architecture behavior of mux_using_with is +begin + with (sel) select + mux_out <= din_0 when '0', + din_1 when others; +end architecture; + diff --git a/trunk/examples/overload.cfg b/trunk/examples/overload.cfg new file mode 100644 index 0000000..d29cb9c --- /dev/null +++ b/trunk/examples/overload.cfg @@ -0,0 +1,11 @@ +PROJECT_NAME = "Overloaded Command" +OUTPUT_DIRECTORY = overload +GENERATE_LATEX = NO +GENERATE_MAN = NO +GENERATE_RTF = NO +CASE_SENSE_NAMES = NO +SORT_MEMBER_DOCS = NO +INPUT = overload.cpp +QUIET = YES +JAVADOC_AUTOBRIEF = YES +SEARCHENGINE = NO diff --git a/trunk/examples/overload.cpp b/trunk/examples/overload.cpp new file mode 100644 index 0000000..02bcced --- /dev/null +++ b/trunk/examples/overload.cpp @@ -0,0 +1,25 @@ +class Test +{ + public: + void drawRect(int,int,int,int); + void drawRect(const Rect &r); +}; + +void Test::drawRect(int x,int y,int w,int h) {} +void Test::drawRect(const Rect &r) {} + +/*! \class Test + * \brief A short description. + * + * More text. + */ + +/*! \fn void Test::drawRect(int x,int y,int w,int h) + * This command draws a rectangle with a left upper corner at ( \a x , \a y ), + * width \a w and height \a h. + */ + +/*! + * \overload void Test::drawRect(const Rect &r) + */ + diff --git a/trunk/examples/page.cfg b/trunk/examples/page.cfg new file mode 100644 index 0000000..cd1ff84 --- /dev/null +++ b/trunk/examples/page.cfg @@ -0,0 +1,10 @@ +PROJECT_NAME = "Page Command" +OUTPUT_DIRECTORY = page +GENERATE_LATEX = NO +GENERATE_MAN = NO +GENERATE_RTF = NO +CASE_SENSE_NAMES = NO +INPUT = page.doc +QUIET = YES +JAVADOC_AUTOBRIEF = YES +SEARCHENGINE = NO diff --git a/trunk/examples/page.doc b/trunk/examples/page.doc new file mode 100644 index 0000000..f83f896 --- /dev/null +++ b/trunk/examples/page.doc @@ -0,0 +1,15 @@ +/*! \page page1 A documentation page + \tableofcontents + Leading text. + \section sec An example section + This page contains the subsections \ref subsection1 and \ref subsection2. + For more info see page \ref page2. + \subsection subsection1 The first subsection + Text. + \subsection subsection2 The second subsection + More text. +*/ + +/*! \page page2 Another page + Even more info. +*/ diff --git a/trunk/examples/par.cfg b/trunk/examples/par.cfg new file mode 100644 index 0000000..de6caa9 --- /dev/null +++ b/trunk/examples/par.cfg @@ -0,0 +1,10 @@ +PROJECT_NAME = "Par Command" +OUTPUT_DIRECTORY = par +GENERATE_LATEX = NO +GENERATE_MAN = NO +GENERATE_RTF = NO +CASE_SENSE_NAMES = NO +INPUT = par.cpp +QUIET = YES +JAVADOC_AUTOBRIEF = YES +SEARCHENGINE = NO diff --git a/trunk/examples/par.cpp b/trunk/examples/par.cpp new file mode 100644 index 0000000..6fd2c4e --- /dev/null +++ b/trunk/examples/par.cpp @@ -0,0 +1,20 @@ +/*! \class Test + * Normal text. + * + * \par User defined paragraph: + * Contents of the paragraph. + * + * \par + * New paragraph under the same heading. + * + * \note + * This note consists of two paragraphs. + * This is the first paragraph. + * + * \par + * And this is the second paragraph. + * + * More normal text. + */ + +class Test {}; diff --git a/trunk/examples/pyexample.cfg b/trunk/examples/pyexample.cfg new file mode 100644 index 0000000..27db0f7 --- /dev/null +++ b/trunk/examples/pyexample.cfg @@ -0,0 +1,10 @@ +PROJECT_NAME = "Python" +OUTPUT_DIRECTORY = pyexample +GENERATE_LATEX = NO +GENERATE_MAN = NO +GENERATE_RTF = NO +OPTIMIZE_OUTPUT_JAVA = YES +INPUT = pyexample.py +QUIET = YES +JAVADOC_AUTOBRIEF = YES +SEARCHENGINE = NO diff --git a/trunk/examples/pyexample.py b/trunk/examples/pyexample.py new file mode 100644 index 0000000..666c25b --- /dev/null +++ b/trunk/examples/pyexample.py @@ -0,0 +1,30 @@ +## @package pyexample +# Documentation for this module. +# +# More details. + +## Documentation for a function. +# +# More details. +def func(): + pass + +## Documentation for a class. +# +# More details. +class PyClass: + + ## The constructor. + def __init__(self): + self._memVar = 0; + + ## Documentation for a method. + # @param self The object pointer. + def PyMethod(self): + pass + + ## A class variable. + classVar = 0; + + ## @var _memVar + # a member variable diff --git a/trunk/examples/qtstyle.cfg b/trunk/examples/qtstyle.cfg new file mode 100644 index 0000000..0a930be --- /dev/null +++ b/trunk/examples/qtstyle.cfg @@ -0,0 +1,10 @@ +PROJECT_NAME = "Qt Style" +OUTPUT_DIRECTORY = qtstyle +GENERATE_LATEX = NO +GENERATE_MAN = NO +GENERATE_RTF = NO +CASE_SENSE_NAMES = NO +INPUT = qtstyle.cpp +QUIET = YES +JAVADOC_AUTOBRIEF = YES +SEARCHENGINE = NO diff --git a/trunk/examples/qtstyle.cpp b/trunk/examples/qtstyle.cpp new file mode 100644 index 0000000..e24d541 --- /dev/null +++ b/trunk/examples/qtstyle.cpp @@ -0,0 +1,65 @@ +//! A test class. +/*! + A more elaborate class description. +*/ + +class Test +{ + public: + + //! An enum. + /*! More detailed enum description. */ + enum TEnum { + TVal1, /*!< Enum value TVal1. */ + TVal2, /*!< Enum value TVal2. */ + TVal3 /*!< Enum value TVal3. */ + } + //! Enum pointer. + /*! Details. */ + *enumPtr, + //! Enum variable. + /*! Details. */ + enumVar; + + //! A constructor. + /*! + A more elaborate description of the constructor. + */ + Test(); + + //! A destructor. + /*! + A more elaborate description of the destructor. + */ + ~Test(); + + //! A normal member taking two arguments and returning an integer value. + /*! + \param a an integer argument. + \param s a constant character pointer. + \return The test results + \sa Test(), ~Test(), testMeToo() and publicVar() + */ + int testMe(int a,const char *s); + + //! A pure virtual member. + /*! + \sa testMe() + \param c1 the first argument. + \param c2 the second argument. + */ + virtual void testMeToo(char c1,char c2) = 0; + + //! A public variable. + /*! + Details. + */ + int publicVar; + + //! A function variable. + /*! + Details. + */ + int (*handler)(int a,int b); +}; + diff --git a/trunk/examples/relates.cfg b/trunk/examples/relates.cfg new file mode 100644 index 0000000..4e1d90b --- /dev/null +++ b/trunk/examples/relates.cfg @@ -0,0 +1,10 @@ +PROJECT_NAME = "Relates Command" +OUTPUT_DIRECTORY = relates +GENERATE_LATEX = NO +GENERATE_MAN = NO +GENERATE_RTF = NO +CASE_SENSE_NAMES = NO +INPUT = relates.cpp +QUIET = YES +JAVADOC_AUTOBRIEF = YES +SEARCHENGINE = NO diff --git a/trunk/examples/relates.cpp b/trunk/examples/relates.cpp new file mode 100644 index 0000000..c6f7dc9 --- /dev/null +++ b/trunk/examples/relates.cpp @@ -0,0 +1,23 @@ +/*! + * A String class. + */ + +class String +{ + friend int strcmp(const String &,const String &); +}; + +/*! + * Compares two strings. + */ + +int strcmp(const String &s1,const String &s2) +{ +} + +/*! \relates String + * A string debug function. + */ +void stringDebug() +{ +} diff --git a/trunk/examples/restypedef.cfg b/trunk/examples/restypedef.cfg new file mode 100644 index 0000000..c55926e --- /dev/null +++ b/trunk/examples/restypedef.cfg @@ -0,0 +1,10 @@ +PROJECT_NAME = "Resolving Typedefs" +OUTPUT_DIRECTORY = restypedef +GENERATE_LATEX = NO +GENERATE_MAN = NO +GENERATE_RTF = NO +CASE_SENSE_NAMES = NO +INPUT = restypedef.cpp +QUIET = YES +JAVADOC_AUTOBRIEF = YES +SEARCHENGINE = NO diff --git a/trunk/examples/restypedef.cpp b/trunk/examples/restypedef.cpp new file mode 100644 index 0000000..923cf70 --- /dev/null +++ b/trunk/examples/restypedef.cpp @@ -0,0 +1,25 @@ +/*! \file restypedef.cpp + * An example of resolving typedefs. + */ + +/*! \struct CoordStruct + * A coordinate pair. + */ +struct CoordStruct +{ + /*! The x coordinate */ + float x; + /*! The y coordinate */ + float y; +}; + +/*! Creates a type name for CoordStruct */ +typedef CoordStruct Coord; + +/*! + * This function returns the addition of \a c1 and \a c2, i.e: + * (c1.x+c2.x,c1.y+c2.y) + */ +Coord add(Coord c1,Coord c2) +{ +} diff --git a/trunk/examples/structcmd.cfg b/trunk/examples/structcmd.cfg new file mode 100644 index 0000000..f956ad4 --- /dev/null +++ b/trunk/examples/structcmd.cfg @@ -0,0 +1,10 @@ +PROJECT_NAME = "Structural commands" +OUTPUT_DIRECTORY = structcmd +GENERATE_LATEX = NO +GENERATE_MAN = NO +GENERATE_RTF = NO +CASE_SENSE_NAMES = NO +INPUT = structcmd.h +QUIET = YES +JAVADOC_AUTOBRIEF = YES +SEARCHENGINE = NO diff --git a/trunk/examples/structcmd.h b/trunk/examples/structcmd.h new file mode 100644 index 0000000..3e27029 --- /dev/null +++ b/trunk/examples/structcmd.h @@ -0,0 +1,57 @@ +/*! \file structcmd.h + \brief A Documented file. + + Details. +*/ + +/*! \def MAX(a,b) + \brief A macro that returns the maximum of \a a and \a b. + + Details. +*/ + +/*! \var typedef unsigned int UINT32 + \brief A type definition for a . + + Details. +*/ + +/*! \var int errno + \brief Contains the last error code. + + \warning Not thread safe! +*/ + +/*! \fn int open(const char *pathname,int flags) + \brief Opens a file descriptor. + + \param pathname The name of the descriptor. + \param flags Opening flags. +*/ + +/*! \fn int close(int fd) + \brief Closes the file descriptor \a fd. + \param fd The descriptor to close. +*/ + +/*! \fn size_t write(int fd,const char *buf, size_t count) + \brief Writes \a count bytes from \a buf to the filedescriptor \a fd. + \param fd The descriptor to write to. + \param buf The data buffer to write. + \param count The number of bytes to write. +*/ + +/*! \fn int read(int fd,char *buf,size_t count) + \brief Read bytes from a file descriptor. + \param fd The descriptor to read from. + \param buf The buffer to read into. + \param count The number of bytes to read. +*/ + +#define MAX(a,b) (((a)>(b))?(a):(b)) +typedef unsigned int UINT32; +int errno; +int open(const char *,int); +int close(int); +size_t write(int,const char *, size_t); +int read(int,char *,size_t); diff --git a/trunk/examples/tag.cfg b/trunk/examples/tag.cfg new file mode 100644 index 0000000..3627281 --- /dev/null +++ b/trunk/examples/tag.cfg @@ -0,0 +1,12 @@ +PROJECT_NAME = "Tag Files" +OUTPUT_DIRECTORY = tag +GENERATE_LATEX = NO +GENERATE_MAN = NO +GENERATE_RTF = NO +CASE_SENSE_NAMES = NO +INPUT = tag.cpp +TAGFILES = example.tag=../../example/html +PERL_PATH = perl +QUIET = YES +JAVADOC_AUTOBRIEF = YES +SEARCHENGINE = NO diff --git a/trunk/examples/tag.cpp b/trunk/examples/tag.cpp new file mode 100644 index 0000000..6497dd4 --- /dev/null +++ b/trunk/examples/tag.cpp @@ -0,0 +1,9 @@ +/*! A class that is inherited from the external class Test. +*/ + +class Tag : public Test +{ + public: + /*! an overloaded member. */ + void example(); +}; diff --git a/trunk/examples/tclexample.cfg b/trunk/examples/tclexample.cfg new file mode 100644 index 0000000..a02bb2b --- /dev/null +++ b/trunk/examples/tclexample.cfg @@ -0,0 +1,13 @@ +PROJECT_NAME = "Tcl" +OUTPUT_DIRECTORY = tclexample +GENERATE_LATEX = NO +GENERATE_MAN = NO +GENERATE_RTF = NO +CASE_SENSE_NAMES = NO +INPUT = tclexample.tcl +QUIET = YES +JAVADOC_AUTOBRIEF = YES +SEARCHENGINE = NO +INLINE_SOURCES = YES +EXTRACT_ALL = YES +EXTRACT_PRIVATE = YES diff --git a/trunk/examples/tclexample.tcl b/trunk/examples/tclexample.tcl new file mode 100644 index 0000000..6edef66 --- /dev/null +++ b/trunk/examples/tclexample.tcl @@ -0,0 +1,82 @@ +## \file tclexample.tcl +# File documentation. +#\verbatim + +# Startup code:\ +exec tclsh "$0" "$@" +#\endverbatim +## Documented namespace \c ns . +# The code is inserted here: +#\code +namespace eval ns { + ## Documented proc \c ns_proc . + # param[in] arg some argument + proc ns_proc {arg} {} + ## Documented var \c ns_var . + # Some documentation. + variable ns_var + ## Documented itcl class \c itcl_class . + itcl::class itcl_class { + ## Create object. + constructor {args} {eval $args} + ## Destroy object. + destructor {exit} + ## Documented itcl method \c itcl_method_x . + # param[in] arg Argument + private method itcl_method_x {arg} + ## Documented itcl method \c itcl_method_y . + # param[in] arg Argument + protected method itcl_method_y {arg} {} + ## Documented itcl method \c itcl_method_z . + # param[in] arg Argument + public method itcl_method_z {arg} {} + ## Documented common itcl var \c itcl_Var . + common itcl_Var + ## \protectedsection + + variable itcl_var1;#< Documented itcl var \c itcl_var1 . + variable itcl_var2;#< Documented itcl var \c itcl_var2 . + } + ## Documented oo class \c oo_class . + oo::class create oo_class { + ## Create object. + # Configure with args + constructor {args} {eval $args} + ## Destroy object. + # Exit. + destructor {exit} + ## Documented oo var \c oo_var . + # Defined inside class + variable oo_var + ## \private Documented oo method \c oo_method_x . + # param[in] arg Argument + method oo_method_x {arg} {} + ## \protected Documented oo method \c oo_method_y . + # param[in] arg Argument + method oo_method_y {arg} {} + ## \public Documented oo method \c oo_method_z . + # param[in] arg Argument + method oo_method_z {arg} {} + } +} +#\endcode + +itcl::body ::ns::itcl_class::itcl_method_x {argx} { + puts "$argx OK" +} + +oo::define ns::oo_class { + ## \public Outside defined variable \c oo_var_out . + # Inside oo_class + variable oo_var_out +} + +## Documented global proc \c glob_proc . +# param[in] arg Argument +proc glob_proc {arg} {puts $arg} + +variable glob_var;#< Documented global var \c glob_var\ + with newline +#< and continued line + +# end of file diff --git a/trunk/examples/templ.cfg b/trunk/examples/templ.cfg new file mode 100644 index 0000000..c8d9514 --- /dev/null +++ b/trunk/examples/templ.cfg @@ -0,0 +1,10 @@ +PROJECT_NAME = "Template Test" +OUTPUT_DIRECTORY = template +GENERATE_LATEX = NO +GENERATE_MAN = NO +GENERATE_RTF = NO +CASE_SENSE_NAMES = NO +INPUT = templ.cpp +QUIET = YES +JAVADOC_AUTOBRIEF = YES +SEARCHENGINE = NO diff --git a/trunk/examples/templ.cpp b/trunk/examples/templ.cpp new file mode 100644 index 0000000..9ed48fb --- /dev/null +++ b/trunk/examples/templ.cpp @@ -0,0 +1,35 @@ + +/*! A template class */ +template<class T,int i=100> class Test +{ + public: + Test(); + Test(const Test &); +}; + +/*! complete specialization */ +template<> class Test<void *,200> +{ + public: + Test(); +}; + +/*! A partial template specialization */ +template<class T> class Test<T *> : public Test<void *,200> +{ + public: + Test(); +}; + +/*! The constructor of the template class*/ +template<class T,int i> Test<T,i>::Test() {} + +/*! The copy constructor */ +template<class T,int i> Test<T,i>::Test(const Test &t) {} + +/*! The constructor of the partial specilization */ +template<class T> Test<T *>::Test() {} + +/*! The constructor of the specilization */ +template<> Test<void *,200>::Test() {} + diff --git a/trunk/libmd5/Makefile.in b/trunk/libmd5/Makefile.in new file mode 100644 index 0000000..5f71b11 --- /dev/null +++ b/trunk/libmd5/Makefile.in @@ -0,0 +1,16 @@ +all: Makefile.libmd5 + $(MAKE) -f Makefile.libmd5 + +clean: Makefile.libmd5 + $(MAKE) -f Makefile.libmd5 clean + +distclean: clean + $(RM) -f Makefile.libmd5 libmd5.pro Makefile + +tmake: + $(ENV) $(PERL) $(TMAKE) libmd5.pro >Makefile.libmd5 + +Makefile.libmd5: libmd5.pro + $(ENV) $(PERL) $(TMAKE) libmd5.pro >Makefile.libmd5 + +install: diff --git a/trunk/libmd5/libmd5.pro.in b/trunk/libmd5/libmd5.pro.in new file mode 100644 index 0000000..8cf7118 --- /dev/null +++ b/trunk/libmd5/libmd5.pro.in @@ -0,0 +1,10 @@ +TEMPLATE = lib +CONFIG = warn_on staticlib $extraopts +HEADERS = md5.h md5_loc.h +SOURCES = md5.c +win32:INCLUDEPATH += . +win32-g++:TMAKE_CFLAGS += -D__CYGWIN__ -DALL_STATIC +DESTDIR = ../lib +TARGET = md5 +OBJECTS_DIR = ../objects + diff --git a/trunk/libmd5/md5.c b/trunk/libmd5/md5.c new file mode 100644 index 0000000..0763598 --- /dev/null +++ b/trunk/libmd5/md5.c @@ -0,0 +1,313 @@ +/* + * This code implements the MD5 message-digest algorithm. + * The algorithm is due to Ron Rivest. This code was + * written by Colin Plumb in 1993, no copyright is claimed. + * This code is in the public domain; do with it what you wish. + * + * Equivalent code is available from RSA Data Security, Inc. + * This code has been tested against that, and is equivalent, + * except that you don't need to include two pages of legalese + * with every copy. + * + * To compute the message digest of a chunk of bytes, declare an + * MD5Context structure, pass it to MD5Init, call MD5Update as + * needed on buffers full of bytes, and then call MD5Final, which + * will fill a supplied 16-byte array with the digest. + * + * Changed so as no longer to depend on Colin Plumb's `usual.h' header + * definitions; now uses stuff from dpkg's config.h. + * - Ian Jackson <ian@chiark.greenend.org.uk>. + * Still in the public domain. + */ + +#include <string.h> /* for memcpy() */ +#include <sys/types.h> /* for stupid systems */ + +#include "md5.h" + +void +MD5Transform(UWORD32 buf[4], UWORD32 const in[16]); + +int g_bigEndian = 0; +int g_endianessDetected = 0; + +static void +detectEndianess() +{ + int nl = 0x12345678; + short ns = 0x1234; + + unsigned char *p = (unsigned char *)(&nl); + unsigned char *sp = (unsigned char *)(&ns); + + if (g_endianessDetected) return; + if ( p[0] == 0x12 && p[1] == 0x34 && p[2] == 0x56 && p[3] == 0x78 ) + { + g_bigEndian = 1; + } + else if ( p[0] == 0x78 && p[1] == 0x56 && p[2] == 0x34 && p[3] == 0x12 ) + { + g_bigEndian = 0; + } + else + { + g_bigEndian = *sp != 0x12; + } + + g_endianessDetected=1; +} + +static void +byteSwap(UWORD32 *buf, unsigned words) +{ + md5byte *p; + + if (!g_bigEndian) return; + + p = (md5byte *)buf; + + do { + *buf++ = (UWORD32)((unsigned)p[3] << 8 | p[2]) << 16 | + ((unsigned)p[1] << 8 | p[0]); + p += 4; + } while (--words); +} + +/* + * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious + * initialization constants. + */ +void +MD5Init(struct MD5Context *ctx) +{ + detectEndianess(); + + ctx->buf[0] = 0x67452301; + ctx->buf[1] = 0xefcdab89; + ctx->buf[2] = 0x98badcfe; + ctx->buf[3] = 0x10325476; + + ctx->bytes[0] = 0; + ctx->bytes[1] = 0; +} + +/* + * Update context to reflect the concatenation of another buffer full + * of bytes. + */ +void +MD5Update(struct MD5Context *ctx, md5byte const *buf, unsigned len) +{ + UWORD32 t; + + /* Update byte count */ + + t = ctx->bytes[0]; + if ((ctx->bytes[0] = t + len) < t) + ctx->bytes[1]++; /* Carry from low to high */ + + t = 64 - (t & 0x3f); /* Space available in ctx->in (at least 1) */ + if (t > len) { + memcpy((md5byte *)ctx->in + 64 - t, buf, len); + return; + } + /* First chunk is an odd size */ + memcpy((md5byte *)ctx->in + 64 - t, buf, t); + byteSwap(ctx->in, 16); + MD5Transform(ctx->buf, ctx->in); + buf += t; + len -= t; + + /* Process data in 64-byte chunks */ + while (len >= 64) { + memcpy(ctx->in, buf, 64); + byteSwap(ctx->in, 16); + MD5Transform(ctx->buf, ctx->in); + buf += 64; + len -= 64; + } + + /* Handle any remaining bytes of data. */ + memcpy(ctx->in, buf, len); +} + +/* + * Final wrapup - pad to 64-byte boundary with the bit pattern + * 1 0* (64-bit count of bits processed, MSB-first) + */ +void +MD5Final(md5byte digest[16], struct MD5Context *ctx) +{ + int count = ctx->bytes[0] & 0x3f; /* Number of bytes in ctx->in */ + md5byte *p = (md5byte *)ctx->in + count; + + /* Set the first char of padding to 0x80. There is always room. */ + *p++ = 0x80; + + /* Bytes of padding needed to make 56 bytes (-8..55) */ + count = 56 - 1 - count; + + if (count < 0) { /* Padding forces an extra block */ + memset(p, 0, count + 8); + byteSwap(ctx->in, 16); + MD5Transform(ctx->buf, ctx->in); + p = (md5byte *)ctx->in; + count = 56; + } + memset(p, 0, count); + byteSwap(ctx->in, 14); + + /* Append length in bits and transform */ + ctx->in[14] = ctx->bytes[0] << 3; + ctx->in[15] = ctx->bytes[1] << 3 | ctx->bytes[0] >> 29; + MD5Transform(ctx->buf, ctx->in); + + byteSwap(ctx->buf, 4); + memcpy(digest, ctx->buf, 16); + memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */ +} + +#ifndef ASM_MD5 + +/* The four core functions - F1 is optimized somewhat */ + +/* #define F1(x, y, z) (x & y | ~x & z) */ +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +/* This is the central step in the MD5 algorithm. */ +#define MD5STEP(f,w,x,y,z,in,s) \ + (w += f(x,y,z) + in, w = (w<<s | w>>(32-s)) + x) + +/* + * The core of the MD5 algorithm, this alters an existing MD5 hash to + * reflect the addition of 16 longwords of new data. MD5Update blocks + * the data and converts bytes into longwords for this routine. + */ +void +MD5Transform(UWORD32 buf[4], UWORD32 const in[16]) +{ + register UWORD32 a, b, c, d; + + a = buf[0]; + b = buf[1]; + c = buf[2]; + d = buf[3]; + + MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); + MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); + MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); + MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); + MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); + MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); + MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); + MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); + MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); + MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); + MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); + MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); + MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); + MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); + MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); + MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); + + MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); + MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); + MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); + MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); + MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); + MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); + MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); + MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); + MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); + MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); + MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); + MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); + MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); + MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); + MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); + MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); + + MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); + MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); + MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); + MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); + MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); + MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); + MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); + MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); + MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); + MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); + MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); + MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); + MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); + MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); + MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); + MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); + + MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); + MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); + MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); + MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); + MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); + MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); + MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); + MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); + MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); + MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); + MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); + MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); + MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); + MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); + MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); + MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} + +#endif + +void MD5Buffer (const unsigned char *buf,unsigned int len,unsigned char sig[16]) +{ + struct MD5Context md5; + MD5Init(&md5); + MD5Update(&md5,buf,len); + MD5Final(sig,&md5); +} + +#define HEX_STRING "0123456789abcdef" /* to convert to hex */ + +void MD5SigToString(unsigned char signature[16],char *str,int len) +{ + unsigned char *sig_p; + char *str_p, *max_p; + unsigned int high, low; + + str_p = str; + max_p = str + len; + + for (sig_p = (unsigned char *)signature; + sig_p < (unsigned char *)signature + 16; + sig_p++) + { + high = *sig_p / 16; + low = *sig_p % 16; + /* account for 2 chars */ + if (str_p + 1 >= max_p) { + break; + } + *str_p++ = HEX_STRING[high]; + *str_p++ = HEX_STRING[low]; + } + /* account for 2 chars */ + if (str_p < max_p) { + *str_p++ = '\0'; + } +} + + diff --git a/trunk/libmd5/md5.h b/trunk/libmd5/md5.h new file mode 100644 index 0000000..03f8ff6 --- /dev/null +++ b/trunk/libmd5/md5.h @@ -0,0 +1,57 @@ +/* + * This is the header file for the MD5 message-digest algorithm. + * The algorithm is due to Ron Rivest. This code was + * written by Colin Plumb in 1993, no copyright is claimed. + * This code is in the public domain; do with it what you wish. + * + * Equivalent code is available from RSA Data Security, Inc. + * This code has been tested against that, and is equivalent, + * except that you don't need to include two pages of legalese + * with every copy. + * + * To compute the message digest of a chunk of bytes, declare an + * MD5Context structure, pass it to MD5Init, call MD5Update as + * needed on buffers full of bytes, and then call MD5Final, which + * will fill a supplied 16-byte array with the digest. + * + * Changed so as no longer to depend on Colin Plumb's `usual.h' + * header definitions; now uses stuff from dpkg's config.h + * - Ian Jackson <ian@chiark.greenend.org.uk>. + * Still in the public domain. + */ + +#ifndef MD5_H +#define MD5_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "md5_loc.h" + +#define md5byte unsigned char + +//#if SIZEOF_UNSIGNED_LONG==4 +//# define UWORD32 unsigned long +//#elif SIZEOF_UNSIGNED_INT==4 +//#else +//# error I do not know what to use for a UWORD32. +//#endif + +struct MD5Context { + UWORD32 buf[4]; + UWORD32 bytes[2]; + UWORD32 in[16]; +}; + +void MD5Init(struct MD5Context *context); +void MD5Update(struct MD5Context *context, md5byte const *buf, unsigned len); +void MD5Final(unsigned char digest[16], struct MD5Context *context); +void MD5Buffer (const unsigned char *buf,unsigned int len,unsigned char sig[16]); +void MD5SigToString(unsigned char sig[16],char *str,int len); + +#ifdef __cplusplus +} +#endif + +#endif /* !MD5_H */ diff --git a/trunk/libmd5/md5_loc.h b/trunk/libmd5/md5_loc.h new file mode 100644 index 0000000..ef67c02 --- /dev/null +++ b/trunk/libmd5/md5_loc.h @@ -0,0 +1,6 @@ +#ifndef _MD5LOC_H +#define _MD5LOC_H + +# define UWORD32 unsigned int + +#endif diff --git a/trunk/packages/rpm/doxygen.spec.in b/trunk/packages/rpm/doxygen.spec.in new file mode 100644 index 0000000..2ae6067 --- /dev/null +++ b/trunk/packages/rpm/doxygen.spec.in @@ -0,0 +1,99 @@ +%define name doxygen + +# optionally pass --with-doxywizard to rpmbuild + +%define contentdir /var/www +%define suexec_caller doxygen +%define buildroot /var/tmp/%{name}-%{version}-%{revision}root + +Summary: A documentation system for C/C++. +Name: doxygen +Version: %{version} +Release: %{revision} +URL: http://www.stack.nl/~dimitri/doxygen/index.html +Vendor: Dimitri van Heesch +License: GNU General Public License +Group: Development/Tools +Source: %{name}-%{version}.src.tar.gz +BuildRoot: %{buildroot} +BuildRequires: libstdc++-devel >= 2.96, /usr/bin/perl, /usr/bin/latex, /usr/bin/dvips, /usr/bin/gs +Requires: /sbin/chkconfig, /bin/mktemp, /bin/rm, /bin/mv, libstdc++ >= 2.96 +Provides: doxygen = %{mmn} + +%description +Doxygen can generate an online class browser (in HTML) and/or a +reference manual (in LaTeX) from a set of documented source files. The +documentation is extracted directly from the sources. Doxygen can +also be configured to extract the code structure from undocumented +source files. + +%if %{?_with_doxywizard:1}%{!?_with_doxywizard:0} +%package doxywizard +Group: Development/Libraries +Summary: GUI Interface for doxygen. +Requires: doxygen = %{mmn} +Requires: qt >= 3.3 +Provides: doxywizard = %{mmn} +# Obsoletes: + +%description doxywizard +Doxygen can generate an online class browser (in HTML) and/or a +reference manual (in LaTeX) from a set of documented source files. The +documentation is extracted directly from the sources. Doxygen can +also be configured to extract the code structure from undocumented +source files. + +This is the GUI interface for doxygen. It requires qt and X11 to +install. +%endif + +%prep +%setup -q -n %{name}-%{version} +./configure %{?_with_doxywizard} --prefix $RPM_BUILD_ROOT/usr + +%build +make %{?_smp_mflags} +make %{?_smp_mflags} pdf + +%install +rm -rf $RPM_BUILD_ROOT +make install + +%clean +rm -rf $RPM_BUILD_ROOT + +%files +%defattr(-,root,root) + +%doc README LICENSE LANGUAGE.HOWTO examples ./latex/*.pdf +%doc /usr/man/man1/doxygen.1.gz + +%{_bindir}/doxygen + +%if %{?_with_doxywizard:1}%{!?_with_doxywizard:0} +%files doxywizard +%defattr(-,root,root) +%{_bindir}/doxywizard +%doc /usr/man/man1/doxywizard.1.gz +%endif + +%changelog +* Fri Apr 18 2008 Kenneth Porter <shiva+doxygenspec@sewingwitch.com> 1.5.5-1 +- consolidate with and without doxywizard spec files with rpm macro +- add gs BuildPrereq + +* Sun Nov 18 2007 Kevin McBride <kevin@planetsaphire.com> 1.5.4 +- consolidated manual package in lieu of --excludedocs flag for rpm --install + +* Mon Oct 10 2005 Kevin McBride <kevin@planetsaphire.com> 1.4.5 +- fixed versioning bugs. + +* Tue Oct 4 2005 Kevin McBride <kevin@planetsaphire.com> 1.4.5 +- added obsoletes and proides sections. + +* Sun Sep 20 2005 Kevin McBride <kevin@planetsaphire.com> 1.4.4 +- modified rpm spec file for Fedora Core acceptance criteria. + +* Sun Aug 7 2005 Kevin McBride <kevin@planetsaphire.com> 1.4.4 +- created initial rpm spec file for doxygen-1.4.4 + diff --git a/trunk/qtools/Doxyfile b/trunk/qtools/Doxyfile new file mode 100644 index 0000000..1113edb --- /dev/null +++ b/trunk/qtools/Doxyfile @@ -0,0 +1,283 @@ +# Doxyfile 1.7.4 + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- +DOXYFILE_ENCODING = UTF-8 +PROJECT_NAME = Qtools +PROJECT_NUMBER = +PROJECT_BRIEF = +PROJECT_LOGO = +OUTPUT_DIRECTORY = ../qtools_docs +CREATE_SUBDIRS = NO +OUTPUT_LANGUAGE = English +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ABBREVIATE_BRIEF = +ALWAYS_DETAILED_SEC = NO +INLINE_INHERITED_MEMB = NO +FULL_PATH_NAMES = YES +STRIP_FROM_PATH = $(PWD)/ +STRIP_FROM_INC_PATH = +SHORT_NAMES = NO +JAVADOC_AUTOBRIEF = YES +QT_AUTOBRIEF = NO +MULTILINE_CPP_IS_BRIEF = NO +INHERIT_DOCS = YES +SEPARATE_MEMBER_PAGES = NO +TAB_SIZE = 8 +ALIASES = +OPTIMIZE_OUTPUT_FOR_C = NO +OPTIMIZE_OUTPUT_JAVA = NO +OPTIMIZE_FOR_FORTRAN = NO +OPTIMIZE_OUTPUT_VHDL = NO +EXTENSION_MAPPING = +BUILTIN_STL_SUPPORT = NO +CPP_CLI_SUPPORT = NO +SIP_SUPPORT = NO +IDL_PROPERTY_SUPPORT = YES +DISTRIBUTE_GROUP_DOC = NO +SUBGROUPING = YES +INLINE_GROUPED_CLASSES = NO +TYPEDEF_HIDES_STRUCT = NO +SYMBOL_CACHE_SIZE = 0 +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- +EXTRACT_ALL = YES +EXTRACT_PRIVATE = NO +EXTRACT_STATIC = YES +EXTRACT_LOCAL_CLASSES = YES +EXTRACT_LOCAL_METHODS = NO +EXTRACT_ANON_NSPACES = NO +HIDE_UNDOC_MEMBERS = NO +HIDE_UNDOC_CLASSES = NO +HIDE_FRIEND_COMPOUNDS = NO +HIDE_IN_BODY_DOCS = NO +INTERNAL_DOCS = NO +CASE_SENSE_NAMES = NO +HIDE_SCOPE_NAMES = NO +SHOW_INCLUDE_FILES = YES +FORCE_LOCAL_INCLUDES = NO +INLINE_INFO = YES +SORT_MEMBER_DOCS = YES +SORT_BRIEF_DOCS = NO +SORT_MEMBERS_CTORS_1ST = NO +SORT_GROUP_NAMES = NO +SORT_BY_SCOPE_NAME = NO +STRICT_PROTO_MATCHING = NO +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = YES +GENERATE_BUGLIST = YES +GENERATE_DEPRECATEDLIST= YES +ENABLED_SECTIONS = +MAX_INITIALIZER_LINES = 30 +SHOW_USED_FILES = YES +SHOW_DIRECTORIES = NO +SHOW_FILES = YES +SHOW_NAMESPACES = YES +FILE_VERSION_FILTER = +LAYOUT_FILE = +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- +QUIET = NO +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_IF_DOC_ERROR = YES +WARN_NO_PARAMDOC = NO +WARN_FORMAT = "$file:$line: $text " +WARN_LOGFILE = +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- +INPUT = . +INPUT_ENCODING = UTF-8 +FILE_PATTERNS = *.h \ + *.cpp \ + *.doc +RECURSIVE = NO +EXCLUDE = +EXCLUDE_SYMLINKS = NO +EXCLUDE_PATTERNS = +EXCLUDE_SYMBOLS = +EXAMPLE_PATH = +EXAMPLE_PATTERNS = +EXAMPLE_RECURSIVE = NO +IMAGE_PATH = +INPUT_FILTER = +FILTER_PATTERNS = +FILTER_SOURCE_FILES = NO +FILTER_SOURCE_PATTERNS = +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- +SOURCE_BROWSER = YES +INLINE_SOURCES = NO +STRIP_CODE_COMMENTS = YES +REFERENCED_BY_RELATION = YES +REFERENCES_RELATION = YES +REFERENCES_LINK_SOURCE = YES +USE_HTAGS = NO +VERBATIM_HEADERS = YES +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- +ALPHABETICAL_INDEX = YES +COLS_IN_ALPHA_INDEX = 4 +IGNORE_PREFIX = Q +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- +GENERATE_HTML = YES +HTML_OUTPUT = +HTML_FILE_EXTENSION = .html +HTML_HEADER = +HTML_FOOTER = +HTML_STYLESHEET = +HTML_EXTRA_FILES = +HTML_COLORSTYLE_HUE = 220 +HTML_COLORSTYLE_SAT = 100 +HTML_COLORSTYLE_GAMMA = 80 +HTML_TIMESTAMP = YES +HTML_ALIGN_MEMBERS = YES +HTML_DYNAMIC_SECTIONS = YES +GENERATE_DOCSET = YES +DOCSET_FEEDNAME = "Doxygen generated docs" +DOCSET_BUNDLE_ID = org.doxygen.Project +DOCSET_PUBLISHER_ID = org.doxygen.Publisher +DOCSET_PUBLISHER_NAME = Publisher +GENERATE_HTMLHELP = NO +CHM_FILE = +HHC_LOCATION = +GENERATE_CHI = NO +CHM_INDEX_ENCODING = +BINARY_TOC = NO +TOC_EXPAND = NO +GENERATE_QHP = YES +QCH_FILE = +QHP_NAMESPACE = com.qtools +QHP_VIRTUAL_FOLDER = doc +QHP_CUST_FILTER_NAME = +QHP_CUST_FILTER_ATTRS = +QHP_SECT_FILTER_ATTRS = +QHG_LOCATION = +GENERATE_ECLIPSEHELP = YES +ECLIPSE_DOC_ID = org.doxygen.qtools +DISABLE_INDEX = YES +GENERATE_TREEVIEW = YES +ENUM_VALUES_PER_LINE = 4 +USE_INLINE_TREES = YES +TREEVIEW_WIDTH = 250 +EXT_LINKS_IN_WINDOW = NO +FORMULA_FONTSIZE = 10 +FORMULA_TRANSPARENT = YES +USE_MATHJAX = NO +MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest +SEARCHENGINE = YES +SERVER_BASED_SEARCH = NO +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- +GENERATE_LATEX = NO +LATEX_OUTPUT = +LATEX_CMD_NAME = latex +MAKEINDEX_CMD_NAME = makeindex +COMPACT_LATEX = NO +PAPER_TYPE = a4wide +EXTRA_PACKAGES = +LATEX_HEADER = +LATEX_FOOTER = +PDF_HYPERLINKS = YES +USE_PDFLATEX = YES +LATEX_BATCHMODE = NO +LATEX_HIDE_INDICES = NO +LATEX_SOURCE_CODE = YES +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- +GENERATE_RTF = NO +RTF_OUTPUT = +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +RTF_EXTENSIONS_FILE = +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- +GENERATE_MAN = NO +MAN_OUTPUT = +MAN_EXTENSION = .3 +MAN_LINKS = NO +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- +GENERATE_XML = NO +XML_OUTPUT = xml +XML_SCHEMA = +XML_DTD = +XML_PROGRAMLISTING = YES +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- +GENERATE_AUTOGEN_DEF = NO +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- +GENERATE_PERLMOD = NO +PERLMOD_LATEX = NO +PERLMOD_PRETTY = YES +PERLMOD_MAKEVAR_PREFIX = +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = YES +EXPAND_ONLY_PREDEF = YES +SEARCH_INCLUDES = YES +INCLUDE_PATH = +INCLUDE_FILE_PATTERNS = +PREDEFINED = +EXPAND_AS_DEFINED = +SKIP_FUNCTION_MACROS = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- +TAGFILES = +GENERATE_TAGFILE = ../qtools_docs/qtools.tag +ALLEXTERNALS = NO +EXTERNAL_GROUPS = YES +PERL_PATH = /usr/bin/perl +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- +CLASS_DIAGRAMS = YES +MSCGEN_PATH = +HIDE_UNDOC_RELATIONS = YES +HAVE_DOT = NO +DOT_NUM_THREADS = 0 +DOT_FONTNAME = +DOT_FONTSIZE = 10 +DOT_FONTPATH = +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +GROUP_GRAPHS = YES +UML_LOOK = NO +TEMPLATE_RELATIONS = YES +INCLUDE_GRAPH = YES +INCLUDED_BY_GRAPH = YES +CALL_GRAPH = YES +CALLER_GRAPH = YES +GRAPHICAL_HIERARCHY = YES +DIRECTORY_GRAPH = YES +DOT_IMAGE_FORMAT = svg +INTERACTIVE_SVG = YES +DOT_PATH = +DOTFILE_DIRS = +MSCFILE_DIRS = +DOT_GRAPH_MAX_NODES = 50 +MAX_DOT_GRAPH_DEPTH = 0 +DOT_TRANSPARENT = YES +DOT_MULTI_TARGETS = NO +GENERATE_LEGEND = YES +DOT_CLEANUP = NO diff --git a/trunk/qtools/LICENSE.GPL b/trunk/qtools/LICENSE.GPL new file mode 100644 index 0000000..935a2a0 --- /dev/null +++ b/trunk/qtools/LICENSE.GPL @@ -0,0 +1,349 @@ + + The Qt GUI Toolkit is Copyright (C) 1994-2000 Trolltech AS. + + You may use, distribute and copy the Qt GUI Toolkit under the terms of + GNU General Public License version 2, which is display below. + +------------------------------------------------------------------------- + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) 19yy <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. + +------------------------------------------------------------------------- diff --git a/trunk/qtools/LICENSE.QPL b/trunk/qtools/LICENSE.QPL new file mode 100644 index 0000000..ecdad6e --- /dev/null +++ b/trunk/qtools/LICENSE.QPL @@ -0,0 +1,103 @@ + THE Q PUBLIC LICENSE + version 1.0 + + Copyright (C) 1999-2000 Trolltech AS, Norway. + Everyone is permitted to copy and + distribute this license document. + +The intent of this license is to establish freedom to share and change the +software regulated by this license under the open source model. + +This license applies to any software containing a notice placed by the +copyright holder saying that it may be distributed under the terms of +the Q Public License version 1.0. Such software is herein referred to as +the Software. This license covers modification and distribution of the +Software, use of third-party application programs based on the Software, +and development of free software which uses the Software. + + Granted Rights + +1. You are granted the non-exclusive rights set forth in this license + provided you agree to and comply with any and all conditions in this + license. Whole or partial distribution of the Software, or software + items that link with the Software, in any form signifies acceptance of + this license. + +2. You may copy and distribute the Software in unmodified form provided + that the entire package, including - but not restricted to - copyright, + trademark notices and disclaimers, as released by the initial developer + of the Software, is distributed. + +3. You may make modifications to the Software and distribute your + modifications, in a form that is separate from the Software, such as + patches. The following restrictions apply to modifications: + + a. Modifications must not alter or remove any copyright notices in + the Software. + + b. When modifications to the Software are released under this + license, a non-exclusive royalty-free right is granted to the + initial developer of the Software to distribute your modification + in future versions of the Software provided such versions remain + available under these terms in addition to any other license(s) of + the initial developer. + +4. You may distribute machine-executable forms of the Software or + machine-executable forms of modified versions of the Software, provided + that you meet these restrictions: + + a. You must include this license document in the distribution. + + b. You must ensure that all recipients of the machine-executable forms + are also able to receive the complete machine-readable source code + to the distributed Software, including all modifications, without + any charge beyond the costs of data transfer, and place prominent + notices in the distribution explaining this. + + c. You must ensure that all modifications included in the + machine-executable forms are available under the terms of this + license. + +5. You may use the original or modified versions of the Software to + compile, link and run application programs legally developed by you + or by others. + +6. You may develop application programs, reusable components and other + software items that link with the original or modified versions of the + Software. These items, when distributed, are subject to the following + requirements: + + a. You must ensure that all recipients of machine-executable forms of + these items are also able to receive and use the complete + machine-readable source code to the items without any charge + beyond the costs of data transfer. + + b. You must explicitly license all recipients of your items to use + and re-distribute original and modified versions of the items in + both machine-executable and source code forms. The recipients must + be able to do so without any charges whatsoever, and they must be + able to re-distribute to anyone they choose. + + + c. If the items are not available to the general public, and the + initial developer of the Software requests a copy of the items, + then you must supply one. + + Limitations of Liability + +In no event shall the initial developers or copyright holders be liable +for any damages whatsoever, including - but not restricted to - lost +revenue or profits or other direct, indirect, special, incidental or +consequential damages, even if they have been advised of the possibility +of such damages, except to the extent invariable law, if any, provides +otherwise. + + No Warranty + +The Software and this license document are provided AS IS with NO WARRANTY +OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS +FOR A PARTICULAR PURPOSE. + Choice of Law + +This license is governed by the Laws of Norway. Disputes shall be settled +by Oslo City Court. diff --git a/trunk/qtools/Makefile.in b/trunk/qtools/Makefile.in new file mode 100644 index 0000000..78710fd --- /dev/null +++ b/trunk/qtools/Makefile.in @@ -0,0 +1,30 @@ +# +# +# +# Copyright (C) 1997-2000 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. +# + +all: Makefile.qtools Makefile + $(MAKE) -f Makefile.qtools $@ + +Makefile.qtools: qtools.pro + $(ENV) $(PERL) $(TMAKE) qtools.pro >Makefile.qtools + +tmake: + $(ENV) $(PERL) $(TMAKE) qtools.pro >Makefile.qtools + +clean: Makefile.qtools + $(MAKE) -f Makefile.qtools clean + +distclean: clean + +FORCE: diff --git a/trunk/qtools/README b/trunk/qtools/README new file mode 100644 index 0000000..1e7fc8d --- /dev/null +++ b/trunk/qtools/README @@ -0,0 +1,4 @@ +This directory contains a small subset of Troll-Tech's Qt library +The subset is enough to build the doxygen executable, but lacks many of +the features found in the Qt library. See http://www.trolltech.com +for the full package. diff --git a/trunk/qtools/qarray.doc b/trunk/qtools/qarray.doc new file mode 100644 index 0000000..6914dbc --- /dev/null +++ b/trunk/qtools/qarray.doc @@ -0,0 +1,486 @@ +/**************************************************************************** +** +** +** QArray class documentation +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + + +/***************************************************************************** + QArray documentation + *****************************************************************************/ + +/*! + \class QArray qarray.h + \brief The QArray class is a template class that provides arrays of simple types. + + \ingroup tools + + QArray is implemented as a template class. Define a template + instance QArray\<X\> to create an array that contains X items. + + QArray stores the array elements directly in the array. It can only + deal with simple types, i.e. C++ types, structs and classes that have + no constructors, destructors or virtual functions. QArray uses + bitwise operations to copy and compare array elements. + + The QVector collection class is also a kind of array. Like most + \link collection.html collection classes\endlink, it has pointers to the + contained items. + + QArray uses explicit \link shclass.html sharing\endlink with a reference + count. If more than one array share common data, and one array is + modified, all arrays will be modified. + + The benefit of sharing is that a program does not need to duplicate + data when it is not required, which results in less memory usage and + less copying of data. + + Example: + \code + #include <qarray.h> + #include <stdio.h> + + QArray<int> fib( int num ) // returns fibonacci array + { + ASSERT( num > 2 ); + QArray<int> f( num ); // array of ints + + f[0] = f[1] = 1; // initialize first two numbers + for ( int i=2; i<num; i++ ) + f[i] = f[i-1] + f[i-2]; + + return f; + } + + void main() + { + QArray<int> a = fib( 6 ); // get 6 first fibonaccis + int i; + + for ( i=0; i<a.size(); i++ ) // print them + prinf( "%d: %d\n", i, a[i] ); + + printf( "1 is found %d time(s)\n", a.contains(1) ); + printf( "5 is found at index %d\n", a.find(5) ); + } + \endcode + + Program output: + \code + 0: 1 + 1: 1 + 2: 2 + 3: 3 + 4: 5 + 5: 8 + 1 is found 2 times + 5 is found at index 4 + \endcode + + Note about using QArray for manipulating structs or classes: + Compilers will often pad the size of structs of odd sizes up to the + nearest word boundary. This will then be the size QArray will use + for its bitwise element comparisons. Since the remaining bytes will + typically be uninitialized, this can cause find() etc. to fail to + find the element. Example: + + \code + struct MyStruct + { + short i; // 2 bytes + char c; // 1 byte + }; // sizeof(MyStruct) may be padded to 4 bytes + + QArray<MyStruct> a(1); + a[0].i = 5; + a[0].c = 't'; + + MyStruct x; + x.i = '5'; + x.c = 't'; + int i = a.find( x ); // May return -1 if the pad bytes differ + \endcode + + To workaround this, make sure that you use a struct where sizeof() + returns the same as the sum of the sizes of the members, either by + changing the types of the struct members or by adding dummy members. + + \sa \link shclass.html Shared Classes\endlink +*/ + + +/*! + \fn QArray::QArray() + Constructs a null array. + \sa isNull() +*/ + +/*! + \fn QArray::QArray( int size ) + Constructs an array with room for \e size elements. + Makes a null array if \e size == 0. + + Note that the elements are not initialized. + + \sa resize(), isNull() +*/ + +/*! + \fn QArray::QArray( const QArray<type> &a ) + Constructs a shallow copy of \e a. + \sa assign() +*/ + +/*! + \fn QArray::QArray( int, int ) + Constructs an array <em>without allocating</em> array space. + The arguments should be (0, 0). Use at own risk. +*/ + +/*! + \fn QArray::~QArray() + Dereferences the array data and deletes it if this was the last + reference. +*/ + +/*! + \fn QArray<type> &QArray::operator=( const QArray<type> &a ) + Assigns a shallow copy of \e a to this array and returns a reference + to this array. + + Equivalent to assign( a ). +*/ + +/*! + \fn type *QArray::data() const + Returns a pointer to the actual array data. + + The array is a null array if data() == 0 (null pointer). + + \sa isNull() +*/ + +/*! + \fn uint QArray::nrefs() const + Returns the reference count for the shared array data. This reference count + is always greater than zero. +*/ + +/*! + \fn uint QArray::size() const + Returns the size of the array (max number of elements). + + The array is a null array if size() == 0. + + \sa isNull(), resize() +*/ + +/*! + \fn uint QArray::count() const + Returns the same as size(). + + \sa size() +*/ + +/*! + \fn bool QArray::isEmpty() const + Returns TRUE if the array is empty, i.e. size() == 0, otherwise FALSE. + + isEmpty() is equivalent with isNull() for QArray. Note that this is not + the case for QCString::isEmpty(). +*/ + +/*! + \fn bool QArray::isNull() const + Returns TRUE if the array is null, otherwise FALSE. + + A null array has size() == 0 and data() == 0. +*/ + +/*! + \fn bool QArray::resize( uint size ) + Resizes (expands or shrinks) the array to \e size elements. The array + becomes a null array if \e size == 0. + + Returns TRUE if successful, or FALSE if the memory cannot be allocated. + + New elements will not be initialized. + + \sa size() +*/ + +/*! + \fn bool QArray::truncate( uint pos ) + Truncates the array at position \e pos. + + Returns TRUE if successful, or FALSE if the memory cannot be allocated. + + Equivalent to resize(\e pos). + + \sa resize() +*/ + +/*! + \fn bool QArray::fill( const type &v, int size ) + Fills the array with the value \e v. If \e size is specified as different + from -1, then the array will be resized before filled. + + Returns TRUE if successful, or FALSE if the memory cannot be allocated + (only when \e size != -1). + + \sa resize() +*/ + +/*! + \fn void QArray::detach() + Detaches this array from shared array data, i.e. makes a private, deep + copy of the data. + + Copying will only be performed if the + \link nrefs() reference count\endlink is greater than one. + + \sa copy() +*/ + +/*! + \fn QArray<type> QArray::copy() const + Returns a deep copy of this array. + \sa detach(), duplicate() +*/ + +/*! + \fn QArray<type> &QArray::assign( const QArray<type> &a ) + Shallow copy. Dereferences the current array and references the data + contained in \e a instead. Returns a reference to this array. + \sa operator=() +*/ + +/*! + \fn QArray<type> &QArray::assign( const type *data, uint size ) + Shallow copy. Dereferences the current array and references the + array data \e data, which contains \e size elements. + Returns a reference to this array. + + Do not delete \e data later, QArray takes care of that. +*/ + +/*! + \fn QArray<type> &QArray::duplicate( const QArray<type> &a ) + Deep copy. Dereferences the current array and obtains a copy of the data + contained in \e a instead. Returns a reference to this array. + \sa copy() +*/ + +/*! + \fn QArray<type> &QArray::duplicate( const type *data, uint size ) + Deep copy. Dereferences the current array and obtains a copy of the + array data \e data instead. Returns a reference to this array. + \sa copy() +*/ + +/*! + \fn QArray<type> &QArray::setRawData( const type *data, uint size ) + + Sets raw data and returns a reference to the array. + + Dereferences the current array and sets the new array data to \e data and + the new array size to \e size. Do not attempt to resize or re-assign the + array data when raw data has been set. + Call resetRawData(d,len) to reset the array. + + Setting raw data is useful because it sets QArray data without allocating + memory or copying data. + + Example I (intended use): + \code + static char bindata[] = { 231, 1, 44, ... }; + QByteArray a; + a.setRawData( bindata, sizeof(bindata) ); // a points to bindata + QDataStream s( a, IO_ReadOnly ); // open on a's data + s >> <something>; // read raw bindata + a.resetRawData( bindata, sizeof(bindata) ); // finished + \endcode + + Example II (you don't want to do this): + \code + static char bindata[] = { 231, 1, 44, ... }; + QByteArray a, b; + a.setRawData( bindata, sizeof(bindata) ); // a points to bindata + a.resize( 8 ); // will crash + b = a; // will crash + a[2] = 123; // might crash + // forget to resetRawData - will crash + \endcode + + \warning If you do not call resetRawData(), QArray will attempt to + deallocate or reallocate the raw data, which might not be too good. + Be careful. + + \sa resetRawData() +*/ + +/*! + \fn void QArray::resetRawData( const type *data, uint size ) + Resets raw data that was set using setRawData(). + + The arguments must be the data and length that were passed to + setRawData(). This is for consistency checking. + + \sa setRawData() +*/ + +/*! + \fn int QArray::find( const type &v, uint index ) const + Finds the first occurrence of \e v, starting at position \e index. + + Returns the position of \e v, or -1 if \e v could not be found. + + \sa contains() +*/ + +/*! + \fn int QArray::contains( const type &v ) const + Returns the number of times \e v occurs in the array. + \sa find() +*/ + +/*! + \fn void QArray::sort() + Sorts the array elements in ascending order, using bitwise + comparison (memcmp()). + + \sa bsearch() +*/ + +/*! + \fn int QArray::bsearch( const type &v ) const + In a sorted array, finds the first occurrence of \e v using binary + search. For a sorted array, this is generally much faster than + find(), which does a linear search. + + Returns the position of \e v, or -1 if \e v could not be found. + + \sa sort(), find() +*/ + +/*! + \fn type &QArray::operator[]( int index ) const + Returns a reference to the element at position \e index in the array. + + This can be used to both read and set an element. Equivalent to at(). + + \sa at() +*/ + +/*! + \fn type &QArray::at( uint index ) const + Returns a reference to the element at position \e index in the array. + + This can be used to both read and set an element. + + \sa operator[]() +*/ + +/*! + \fn QArray::operator const type *() const + Cast operator. Returns a pointer to the array. + \sa data() +*/ + +/*! + \fn bool QArray::operator==( const QArray<type> &a ) const + Returns TRUE if this array is equal to \e a, otherwise FALSE. + + The two arrays are bitwise compared. + + \sa operator!=() +*/ + +/*! + \fn bool QArray::operator!=( const QArray<type> &a ) const + Returns TRUE if this array is different from \e a, otherwise FALSE. + + The two arrays are bitwise compared. + + \sa operator==() +*/ + +/*! + \fn Iterator QArray::begin() + Returns an iterator pointing at the beginning of this array. + This iterator can be used as the iterators of QValueList and QMap + for example. In fact it does not only behave like a usual pointer: + It is a pointer. +*/ + +/*! + \fn Iterator QArray::end() + Returns an iterator pointing behind the last element of this array. + This iterator can be used as the iterators of QValueList and QMap + for example. In fact it does not only behave like a usual pointer: + It is a pointer. +*/ + +/*! + \fn ConstIterator QArray::begin() const + Returns a const iterator pointing at the beginning of this array. + This iterator can be used as the iterators of QValueList and QMap + for example. In fact it does not only behave like a usual pointer: + It is a pointer. +*/ + +/*! + \fn ConstIterator QArray::end() const + Returns a const iterator pointing behind the last element of this array. + This iterator can be used as the iterators of QValueList and QMap + for example. In fact it does not only behave like a usual pointer: + It is a pointer. +*/ + + +/***************************************************************************** + QByteArray documentation + *****************************************************************************/ + +/*! + \class QByteArray qcstring.h + \brief The QByteArray class provides an array of bytes. + + \inherit QArray + + \ingroup tools + + The QByteArray class provides an explicitly shared array of + bytes. It is useful for manipulating memory areas with custom + data. QByteArray is implemented as QArray<char>. See the QArray + documentation for further information. +*/ diff --git a/trunk/qtools/qarray.h b/trunk/qtools/qarray.h new file mode 100644 index 0000000..90dcbb7 --- /dev/null +++ b/trunk/qtools/qarray.h @@ -0,0 +1,110 @@ +/**************************************************************************** +** +** +** Definition of QArray template/macro class +** +** Created : 930906 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QARRAY_H +#define QARRAY_H + +#ifndef QT_H +#include "qgarray.h" +#endif // QT_H + + +template<class type> class Q_EXPORT QArray : public QGArray +{ +public: + typedef type* Iterator; + typedef const type* ConstIterator; + typedef type ValueType; + +protected: + QArray( int, int ) : QGArray( 0, 0 ) {} + +public: + QArray() {} + QArray( int size ) : QGArray(size*sizeof(type)) {} + QArray( const QArray<type> &a ) : QGArray(a) {} + ~QArray() {} + QArray<type> &operator=(const QArray<type> &a) + { return (QArray<type>&)QGArray::assign(a); } + type *data() const { return (type *)QGArray::data(); } + uint nrefs() const { return QGArray::nrefs(); } + uint size() const { return QGArray::size()/sizeof(type); } + uint count() const { return size(); } + bool isEmpty() const { return QGArray::size() == 0; } + bool isNull() const { return QGArray::data() == 0; } + bool resize( uint size ) { return QGArray::resize(size*sizeof(type)); } + bool truncate( uint pos ) { return QGArray::resize(pos*sizeof(type)); } + bool fill( const type &d, int size = -1 ) + { return QGArray::fill((char*)&d,size,sizeof(type) ); } + void detach() { QGArray::detach(); } + QArray<type> copy() const + { QArray<type> tmp; return tmp.duplicate(*this); } + QArray<type>& assign( const QArray<type>& a ) + { return (QArray<type>&)QGArray::assign(a); } + QArray<type>& assign( const type *a, uint n ) + { return (QArray<type>&)QGArray::assign((char*)a,n*sizeof(type)); } + QArray<type>& duplicate( const QArray<type>& a ) + { return (QArray<type>&)QGArray::duplicate(a); } + QArray<type>& duplicate( const type *a, uint n ) + { return (QArray<type>&)QGArray::duplicate((char*)a,n*sizeof(type)); } + QArray<type>& setRawData( const type *a, uint n ) + { return (QArray<type>&)QGArray::setRawData((char*)a, + n*sizeof(type)); } + void resetRawData( const type *a, uint n ) + { QGArray::resetRawData((char*)a,n*sizeof(type)); } + int find( const type &d, uint i=0 ) const + { return QGArray::find((char*)&d,i,sizeof(type)); } + int contains( const type &d ) const + { return QGArray::contains((char*)&d,sizeof(type)); } + void sort() { QGArray::sort(sizeof(type)); } + int bsearch( const type &d ) const + { return QGArray::bsearch((const char*)&d,sizeof(type)); } + type& operator[]( int i ) const + { return (type &)(*(type *)QGArray::at(i*sizeof(type))); } + type& at( uint i ) const + { return (type &)(*(type *)QGArray::at(i*sizeof(type))); } + operator const type*() const { return (const type *)QGArray::data(); } + bool operator==( const QArray<type> &a ) const { return isEqual(a); } + bool operator!=( const QArray<type> &a ) const { return !isEqual(a); } + Iterator begin() { return data(); } + Iterator end() { return data() + size(); } + ConstIterator begin() const { return data(); } + ConstIterator end() const { return data() + size(); } +}; + + +#endif // QARRAY_H diff --git a/trunk/qtools/qasciidict.h b/trunk/qtools/qasciidict.h new file mode 100644 index 0000000..29fcf2f --- /dev/null +++ b/trunk/qtools/qasciidict.h @@ -0,0 +1,107 @@ +/**************************************************************************** +** +** +** Definition of QAsciiDict template class +** +** Created : 920821 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QASCIIDICT_H +#define QASCIIDICT_H + +#ifndef QT_H +#include "qgdict.h" +#endif // QT_H + + +template<class type> class Q_EXPORT QAsciiDict : public QGDict +{ +public: + QAsciiDict(int size=17, bool caseSensitive=TRUE, bool copyKeys=TRUE ) + : QGDict(size,AsciiKey,caseSensitive,copyKeys) {} + QAsciiDict( const QAsciiDict<type> &d ) : QGDict(d) {} + ~QAsciiDict() { clear(); } + QAsciiDict<type> &operator=(const QAsciiDict<type> &d) + { return (QAsciiDict<type>&)QGDict::operator=(d); } + uint count() const { return QGDict::count(); } + uint size() const { return QGDict::size(); } + bool isEmpty() const { return QGDict::count() == 0; } + + void insert( const char *k, const type *d ) + { QGDict::look_ascii(k,(Item)d,1); } + void replace( const char *k, const type *d ) + { QGDict::look_ascii(k,(Item)d,2); } + bool remove( const char *k ) { return QGDict::remove_ascii(k); } + type *take( const char *k ) { return (type *)QGDict::take_ascii(k); } + type *find( const char *k ) const + { return (type *)((QGDict*)this)->QGDict::look_ascii(k,0,0); } + type *operator[]( const char *k ) const + { return (type *)((QGDict*)this)->QGDict::look_ascii(k,0,0); } + + void clear() { QGDict::clear(); } + void resize( uint n ) { QGDict::resize(n); } + void statistics() const { QGDict::statistics(); } +private: + void deleteItem( Item d ); +}; + +#if defined(Q_DELETING_VOID_UNDEFINED) +template<> inline void QAsciiDict<void>::deleteItem( Item ) +{ +} +#endif + +template<class type> inline void QAsciiDict<type>::deleteItem( QCollection::Item d ) +{ + if ( del_item ) delete (type *)d; +} + + +template<class type> class Q_EXPORT QAsciiDictIterator : public QGDictIterator +{ +public: + QAsciiDictIterator(const QAsciiDict<type> &d) + : QGDictIterator((QGDict &)d) {} + ~QAsciiDictIterator() {} + uint count() const { return dict->count(); } + bool isEmpty() const { return dict->count() == 0; } + type *toFirst() { return (type *)QGDictIterator::toFirst(); } + operator type *() const { return (type *)QGDictIterator::get(); } + type *current() const { return (type *)QGDictIterator::get(); } + const char *currentKey() const { return QGDictIterator::getKeyAscii(); } + type *operator()() { return (type *)QGDictIterator::operator()(); } + type *operator++() { return (type *)QGDictIterator::operator++(); } + type *operator+=(uint j) { return (type *)QGDictIterator::operator+=(j);} +}; + + +#endif // QASCIIDICT_H diff --git a/trunk/qtools/qbuffer.cpp b/trunk/qtools/qbuffer.cpp new file mode 100644 index 0000000..beed0ba --- /dev/null +++ b/trunk/qtools/qbuffer.cpp @@ -0,0 +1,465 @@ +/**************************************************************************** +** +** +** Implementation of QBuffer class +** +** Created : 930812 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "qbuffer.h" +#include <stdlib.h> + +// REVISED: paul +/*! + \class QBuffer qbuffer.h + \brief The QBuffer class is an I/O device that operates on a QByteArray + + \ingroup io + + QBuffer allows reading and writing a memory buffer. It is normally + used together with a QTextStream or a QDataStream. QBuffer has an + associated QByteArray which holds the buffer data. The size() of the + buffer is automatically adjusted as data is written. + + The constructor \c QBuffer(QByteArray) creates a QBuffer with an + existing byte array. The byte array can also be set with setBuffer(). + Writing to the QBuffer will modify the original byte array, since + QByteArray is \link shclass.html explicitly shared.\endlink + + Use open() to open the buffer before use, and to set the mode + (read-only,write-only, etc.). close() closes the buffer. The buffer + must be closed before reopening or calling setBuffer(). + + The common way to use QBuffer is through \l QDataStream or \l QTextStream + which have constructors that take a QBuffer parameter. For + convenience, there are also QDataStream and QTextStream constructors + that take a QByteArray parameter. These constructors create and open + an internal QBuffer. + + Note that QTextStream can also operate on a QString (a Unicode + string); a QBuffer cannot. + + You can also use QBuffer directly through the standard QIODevice + functions readBlock(), writeBlock() readLine(), at(), getch(), putch() and + ungetch(). + + \sa QFile, QDataStream, QTextStream, QByteArray, \link shclass.html Shared Classes\endlink +*/ + + +/*! + Constructs an empty buffer. +*/ + +QBuffer::QBuffer() +{ + setFlags( IO_Direct ); + a_inc = 16; // initial increment + a_len = 0; + ioIndex = 0; +} + + +/*! + Constructs a buffer that operates on \a buf. + If you open the buffer in write mode (\c IO_WriteOnly or + \c IO_ReadWrite) and write something into the buffer, \a buf + will be modified. + + + Example: + \code + QCString str = "abc"; + QBuffer b( str ); + b.open( IO_WriteOnly ); + b.at( 3 ); // position at \0 + b.writeBlock( "def", 4 ); // write including \0 + b.close(); + // Now, str == "abcdef" + \endcode + + + \sa setBuffer() +*/ + +QBuffer::QBuffer( QByteArray buf ) : a(buf) +{ + setFlags( IO_Direct ); + a_len = a.size(); + a_inc = (a_len > 512) ? 512 : a_len; // initial increment + if ( a_inc < 16 ) + a_inc = 16; + ioIndex = 0; +} + +/*! + Destructs the buffer. +*/ + +QBuffer::~QBuffer() +{ +} + + +/*! + Replaces the buffer's contents with \a buf. + + This may not be done when isOpen() is TRUE. + + Note that if you open the buffer in write mode (\c IO_WriteOnly or + IO_ReadWrite) and write something into the buffer, \a buf is also + modified because QByteArray is an explicitly shared class. + + \sa buffer(), open(), close() +*/ + +bool QBuffer::setBuffer( QByteArray buf ) +{ + if ( isOpen() ) { +#if defined(CHECK_STATE) + qWarning( "QBuffer::setBuffer: Buffer is open"); +#endif + return FALSE; + } + a = buf; + a_len = a.size(); + a_inc = (a_len > 512) ? 512 : a_len; // initial increment + if ( a_inc < 16 ) + a_inc = 16; + ioIndex = 0; + return TRUE; +} + +/*! + \fn QByteArray QBuffer::buffer() const + + Returns this buffer's byte array. + + \sa setBuffer() +*/ + +/*! + \reimp + Opens the buffer in the mode \a m. Returns TRUE if successful, + otherwise FALSE. The buffer must be opened before use. + + The mode parameter \a m must be a combination of the following flags. + <ul> + <li>\c IO_ReadOnly opens a buffer in read-only mode. + <li>\c IO_WriteOnly opens a buffer in write-only mode. + <li>\c IO_ReadWrite opens a buffer in read/write mode. + <li>\c IO_Append sets the buffer index to the end of the buffer. + <li>\c IO_Truncate truncates the buffer. + </ul> + + \sa close(), isOpen() +*/ + +bool QBuffer::open( int m ) +{ + if ( isOpen() ) { // buffer already open +#if defined(CHECK_STATE) + qWarning( "QBuffer::open: Buffer already open" ); +#endif + return FALSE; + } + setMode( m ); + if ( m & IO_Truncate ) { // truncate buffer + a.resize( 0 ); + a_len = 0; + } + if ( m & IO_Append ) { // append to end of buffer + ioIndex = a.size(); + } else { + ioIndex = 0; + } + a_inc = 16; + setState( IO_Open ); + setStatus( 0 ); + return TRUE; +} + +/*! + \reimp + Closes an open buffer. + \sa open() +*/ + +void QBuffer::close() +{ + if ( isOpen() ) { + setFlags( IO_Direct ); + ioIndex = 0; + a_inc = 16; + } +} + +/*! + \reimp + The flush function does nothing for a QBuffer. +*/ + +void QBuffer::flush() +{ + return; +} + + +/*! + \fn int QBuffer::at() const + \reimp +*/ + +/*! + \fn uint QBuffer::size() const + \reimp +*/ + +/*! + \reimp +*/ + +bool QBuffer::at( int pos ) +{ +#if defined(CHECK_STATE) + if ( !isOpen() ) { + qWarning( "QBuffer::at: Buffer is not open" ); + return FALSE; + } +#endif + if ( (uint)pos > a_len ) { +#if defined(CHECK_RANGE) + qWarning( "QBuffer::at: Index %d out of range", pos ); +#endif + return FALSE; + } + ioIndex = pos; + return TRUE; +} + + +/*! + \reimp +*/ + +int QBuffer::readBlock( char *p, uint len ) +{ +#if defined(CHECK_STATE) + CHECK_PTR( p ); + if ( !isOpen() ) { // buffer not open + qWarning( "QBuffer::readBlock: Buffer not open" ); + return -1; + } + if ( !isReadable() ) { // reading not permitted + qWarning( "QBuffer::readBlock: Read operation not permitted" ); + return -1; + } +#endif + if ( (uint)ioIndex + len > a.size() ) { // overflow + if ( (uint)ioIndex >= a.size() ) { + setStatus( IO_ReadError ); + return -1; + } else { + len = a.size() - (uint)ioIndex; + } + } + memcpy( p, a.data()+ioIndex, len ); + ioIndex += len; + return len; +} + +/*! + \reimp + + Writes \a len bytes from \a p into the buffer at the current index, + overwriting any characters there and extending the buffer if necessary. + Returns the number of bytes actually written. + + Returns -1 if a serious error occurred. + + \sa readBlock() +*/ + +int QBuffer::writeBlock( const char *p, uint len ) +{ +#if defined(CHECK_NULL) + if ( p == 0 && len != 0 ) + qWarning( "QBuffer::writeBlock: Null pointer error" ); +#endif +#if defined(CHECK_STATE) + if ( !isOpen() ) { // buffer not open + qWarning( "QBuffer::writeBlock: Buffer not open" ); + return -1; + } + if ( !isWritable() ) { // writing not permitted + qWarning( "QBuffer::writeBlock: Write operation not permitted" ); + return -1; + } +#endif + if ( (uint)ioIndex + len >= a_len ) { // overflow + uint new_len = a_len + a_inc*(((uint)ioIndex+len-a_len)/a_inc+1); + if ( !a.resize( new_len ) ) { // could not resize +#if defined(CHECK_NULL) + qWarning( "QBuffer::writeBlock: Memory allocation error" ); +#endif + setStatus( IO_ResourceError ); + return -1; + } + a_inc *= 2; // double increment + a_len = new_len; + a.shd->len = (uint)ioIndex + len; + } + memcpy( a.data()+ioIndex, p, len ); + ioIndex += len; + if ( a.shd->len < (uint)ioIndex ) + a.shd->len = (uint)ioIndex; // fake (not alloc'd) length + return len; +} + + +/*! + \reimp +*/ + +int QBuffer::readLine( char *p, uint maxlen ) +{ +#if defined(CHECK_STATE) + CHECK_PTR( p ); + if ( !isOpen() ) { // buffer not open + qWarning( "QBuffer::readLine: Buffer not open" ); + return -1; + } + if ( !isReadable() ) { // reading not permitted + qWarning( "QBuffer::readLine: Read operation not permitted" ); + return -1; + } +#endif + if ( maxlen == 0 ) + return 0; + uint start = (uint)ioIndex; + char *d = a.data() + ioIndex; + maxlen--; // make room for 0-terminator + if ( a.size() - (uint)ioIndex < maxlen ) + maxlen = a.size() - (uint)ioIndex; + while ( maxlen-- ) { + if ( (*p++ = *d++) == '\n' ) + break; + } + *p = '\0'; + ioIndex = d - a.data(); + return (uint)ioIndex - start; +} + + +/*! + \reimp +*/ + +int QBuffer::getch() +{ +#if defined(CHECK_STATE) + if ( !isOpen() ) { // buffer not open + qWarning( "QBuffer::getch: Buffer not open" ); + return -1; + } + if ( !isReadable() ) { // reading not permitted + qWarning( "QBuffer::getch: Read operation not permitted" ); + return -1; + } +#endif + if ( (uint)ioIndex+1 > a.size() ) { // overflow + setStatus( IO_ReadError ); + return -1; + } + return uchar(*(a.data()+ioIndex++)); +} + +/*! + \reimp + Writes the character \a ch into the buffer, overwriting + the character at the current index, extending the buffer + if necessary. + + Returns \a ch, or -1 if some error occurred. + + \sa getch(), ungetch() +*/ + +int QBuffer::putch( int ch ) +{ +#if defined(CHECK_STATE) + if ( !isOpen() ) { // buffer not open + qWarning( "QBuffer::putch: Buffer not open" ); + return -1; + } + if ( !isWritable() ) { // writing not permitted + qWarning( "QBuffer::putch: Write operation not permitted" ); + return -1; + } +#endif + if ( (uint)ioIndex + 1 >= a_len ) { // overflow + char buf[1]; + buf[0] = (char)ch; + if ( writeBlock(buf,1) != 1 ) + return -1; // write error + } else { + *(a.data() + ioIndex++) = (char)ch; + if ( a.shd->len < (uint)ioIndex ) + a.shd->len = (uint)ioIndex; + } + return ch; +} + +/*! + \reimp +*/ + +int QBuffer::ungetch( int ch ) +{ +#if defined(CHECK_STATE) + if ( !isOpen() ) { // buffer not open + qWarning( "QBuffer::ungetch: Buffer not open" ); + return -1; + } + if ( !isReadable() ) { // reading not permitted + qWarning( "QBuffer::ungetch: Read operation not permitted" ); + return -1; + } +#endif + if ( ch != -1 ) { + if ( ioIndex ) + ioIndex--; + else + ch = -1; + } + return ch; +} diff --git a/trunk/qtools/qbuffer.h b/trunk/qtools/qbuffer.h new file mode 100644 index 0000000..9dcd286 --- /dev/null +++ b/trunk/qtools/qbuffer.h @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** +** Definition of QBuffer class +** +** Created : 930812 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QBUFFER_H +#define QBUFFER_H + +#ifndef QT_H +#include "qiodevice.h" +#include "qstring.h" +#endif // QT_H + + +class Q_EXPORT QBuffer : public QIODevice +{ +public: + QBuffer(); + QBuffer( QByteArray ); + ~QBuffer(); + + QByteArray buffer() const; + bool setBuffer( QByteArray ); + + bool open( int ); + void close(); + void flush(); + + uint size() const; + int at() const; + bool at( int ); + + int readBlock( char *p, uint ); + int writeBlock( const char *p, uint ); + int readLine( char *p, uint ); + + int getch(); + int putch( int ); + int ungetch( int ); + +protected: + QByteArray a; + +private: + uint a_len; + uint a_inc; + +private: // Disabled copy constructor and operator= +#if defined(Q_DISABLE_COPY) + QBuffer( const QBuffer & ); + QBuffer &operator=( const QBuffer & ); +#endif +}; + + +inline QByteArray QBuffer::buffer() const +{ return a; } + +inline uint QBuffer::size() const +{ return a.size(); } + +inline int QBuffer::at() const +{ return ioIndex; } + + +#endif // QBUFFER_H diff --git a/trunk/qtools/qcache.h b/trunk/qtools/qcache.h new file mode 100644 index 0000000..e1f13d6 --- /dev/null +++ b/trunk/qtools/qcache.h @@ -0,0 +1,152 @@ +/**************************************************************************** +** +** +** Definition of QCache template class +** +** Created : 950209 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QCACHE_H +#define QCACHE_H + +#ifndef QT_H +#include "qgcache.h" +#endif // QT_H + +#define USE_ASCII_STRING + +#ifndef USE_ASCII_STRING + +template<class type> class Q_EXPORT QCache : public QGCache +{ +public: + QCache( const QCache<type> &c ) : QGCache(c) {} + QCache( int maxCost=100, int size=17, bool caseSensitive=TRUE ) + : QGCache( maxCost, size, StringKey, caseSensitive, FALSE ) {} + ~QCache() { clear(); } + QCache<type> &operator=( const QCache<type> &c ) + { return (QCache<type>&)QGCache::operator=(c); } + int maxCost() const { return QGCache::maxCost(); } + int totalCost() const { return QGCache::totalCost(); } + void setMaxCost( int m ) { QGCache::setMaxCost(m); } + uint count() const { return QGCache::count(); } + uint size() const { return QGCache::size(); } + bool isEmpty() const { return QGCache::count() == 0; } + void clear() { QGCache::clear(); } + bool insert( const QString &k, const type *d, int c=1, int p=0 ) + { return QGCache::insert_string(k,(Item)d,c,p);} + bool remove( const QString &k ) + { return QGCache::remove_string(k); } + type *take( const QString &k ) + { return (type *)QGCache::take_string(k); } + type *find( const QString &k, bool ref=TRUE ) const + { return (type *)QGCache::find_string(k,ref);} + type *operator[]( const QString &k ) const + { return (type *)QGCache::find_string(k);} + void statistics() const { QGCache::statistics(); } + int hits() const { return QGCache::hits(); } + int misses() const { return QGCache::misses(); } +private: + void deleteItem( Item d ) { if ( del_item ) delete (type *)d; } +}; + +#else + + +template<class type> class Q_EXPORT QCache : public QGCache +{ +public: + QCache( const QCache<type> &c ) : QGCache(c) {} + QCache( int maxCost=100, int size=17, bool caseSensitive=TRUE ) + : QGCache( maxCost, size, AsciiKey, caseSensitive, TRUE ) {} + ~QCache() { clear(); } + QCache<type> &operator=( const QCache<type> &c ) + { return (QCache<type>&)QGCache::operator=(c); } + int maxCost() const { return QGCache::maxCost(); } + int totalCost() const { return QGCache::totalCost(); } + void setMaxCost( int m ) { QGCache::setMaxCost(m); } + uint count() const { return QGCache::count(); } + uint size() const { return QGCache::size(); } + bool isEmpty() const { return QGCache::count() == 0; } + void clear() { QGCache::clear(); } + bool insert( const char *k, const type *d, int c=1, int p=0 ) + { return QGCache::insert_other(k,(Item)d,c,p);} + bool remove( const char *k ) + { return QGCache::remove_other(k); } + type *take( const char *k ) + { return (type *)QGCache::take_other(k); } + type *find( const char *k, bool ref=TRUE ) const + { return (type *)QGCache::find_other(k,ref);} + type *operator[]( const char *k ) const + { return (type *)QGCache::find_other(k);} + void statistics() const { QGCache::statistics(); } + int hits() const { return QGCache::hits(); } + int misses() const { return QGCache::misses(); } +private: + void deleteItem( Item d ) { if ( del_item ) delete (type *)d; } +}; + + +#endif + + + +template<class type> class Q_EXPORT QCacheIterator : public QGCacheIterator +{ +public: + QCacheIterator( const QCache<type> &c ):QGCacheIterator((QGCache &)c) {} + QCacheIterator( const QCacheIterator<type> &ci) + : QGCacheIterator( (QGCacheIterator &)ci ) {} + QCacheIterator<type> &operator=(const QCacheIterator<type>&ci) + { return ( QCacheIterator<type>&)QGCacheIterator::operator=( ci ); } + uint count() const { return QGCacheIterator::count(); } + bool isEmpty() const { return QGCacheIterator::count() == 0; } + bool atFirst() const { return QGCacheIterator::atFirst(); } + bool atLast() const { return QGCacheIterator::atLast(); } + type *toFirst() { return (type *)QGCacheIterator::toFirst(); } + type *toLast() { return (type *)QGCacheIterator::toLast(); } + operator type *() const { return (type *)QGCacheIterator::get(); } + type *current() const { return (type *)QGCacheIterator::get(); } +#ifndef USE_ASCII_STRING + QString currentKey() const{ return QGCacheIterator::getKeyString(); } +#else + const char *currentKey() const{ return QGCacheIterator::getKeyAscii(); } +#endif + type *operator()() { return (type *)QGCacheIterator::operator()();} + type *operator++() { return (type *)QGCacheIterator::operator++(); } + type *operator+=(uint j) { return (type *)QGCacheIterator::operator+=(j);} + type *operator--() { return (type *)QGCacheIterator::operator--(); } + type *operator-=(uint j) { return (type *)QGCacheIterator::operator-=(j);} +}; + + +#endif // QCACHE_H diff --git a/trunk/qtools/qcollection.cpp b/trunk/qtools/qcollection.cpp new file mode 100644 index 0000000..e70b64b --- /dev/null +++ b/trunk/qtools/qcollection.cpp @@ -0,0 +1,182 @@ +/**************************************************************************** +** +** +** Implementation of base class for all collection classes +** +** Created : 920820 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "qcollection.h" + +// NOT REVISED +/*! + \class QCollection qcollection.h + \brief The QCollection class is the base class of all Qt collections. + + \ingroup collection + \ingroup tools + + The QCollection class is an abstract base class for the Qt \link + collection.html collection classes\endlink QDict, QList etc. via QGDict, + QGList etc. + + A QCollection knows only about the number of objects in the + collection and the deletion strategy (see setAutoDelete()). + + A collection is implemented using the \c Item (generic collection + item) type, which is a \c void*. The template classes that create + the real collections cast the \c Item to the required type. + + \sa \link collection.html Collection Classes\endlink +*/ + + +/*! \enum QCollection::Item + + This type is the generic "item" in a QCollection. +*/ + + +/*! + \fn QCollection::QCollection() + + Constructs a collection. The constructor is protected because + QCollection is an abstract class. +*/ + +/*! + \fn QCollection::QCollection( const QCollection & source ) + + Constructs a copy of \a source with autoDelete() set to FALSE. The + constructor is protected because QCollection is an abstract class. + + Note that if \a source has autoDelete turned on, copying it is a + good way to get memory leaks, reading freed memory, or both. +*/ + +/*! + \fn QCollection::~QCollection() + Destroys the collection. The destructor is protected because QCollection + is an abstract class. +*/ + + +/*! + \fn bool QCollection::autoDelete() const + Returns the setting of the auto-delete option (default is FALSE). + \sa setAutoDelete() +*/ + +/*! + \fn void QCollection::setAutoDelete( bool enable ) + + Sets the auto-delete option of the collection. + + Enabling auto-delete (\e enable is TRUE) will delete objects that + are removed from the collection. This can be useful if the + collection has the only reference to the objects. (Note that the + object can still be copied using the copy constructor - copying such + objects is a good way to get memory leaks, reading freed memory or + both.) + + Disabling auto-delete (\e enable is FALSE) will \e not delete objects + that are removed from the collection. This is useful if the objects + are part of many collections. + + The default setting is FALSE. + + \sa autoDelete() +*/ + + +/*! + \fn virtual uint QCollection::count() const + Returns the number of objects in the collection. +*/ + +/*! + \fn virtual void QCollection::clear() + Removes all objects from the collection. The objects will be deleted + if auto-delete has been enabled. + \sa setAutoDelete() +*/ + + +/*! + Virtual function that creates a copy of an object that is about to + be inserted into the collection. + + The default implementation returns the \e d pointer, i.e. no copy + is made. + + This function is seldom reimplemented in the collection template + classes. It is not common practice to make a copy of something + that is being inserted. + + \sa deleteItem() +*/ + +QCollection::Item QCollection::newItem( Item d ) +{ + return d; // just return reference +} + +/*! + Virtual function that deletes an item that is about to be removed from + the collection. + + The default implementation deletes \e d pointer if and only if + auto-delete has been enabled. + + This function is always reimplemented in the collection template + classes. + + \warning If you reimplement this function you must also reimplement + the destructor and call the virtual function clear() from your + destructor. This is due to the way virtual functions and + destructors work in C++: virtual functions in derived classes cannot + be called from a destructor. If you do not do this your + deleteItem() function will not be called when the container is + destructed. + + \sa newItem(), setAutoDelete() +*/ + +void QCollection::deleteItem( Item d ) +{ + if ( del_item ) +#if defined(Q_DELETING_VOID_UNDEFINED) + delete (char *)d; // default operation +#else + delete d; // default operation +#endif +} diff --git a/trunk/qtools/qcollection.h b/trunk/qtools/qcollection.h new file mode 100644 index 0000000..a169b7c --- /dev/null +++ b/trunk/qtools/qcollection.h @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** +** Definition of base class for all collection classes +** +** Created : 920629 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QCOLLECTION_H +#define QCOLLECTION_H + +#ifndef QT_H +#include "qglobal.h" +#endif // QT_H + + +class QGVector; +class QGList; +class QGDict; + + +class Q_EXPORT QCollection // inherited by all collections +{ +public: + bool autoDelete() const { return del_item; } + void setAutoDelete( bool enable ) { del_item = enable; } + + virtual uint count() const = 0; + virtual void clear() = 0; // delete all objects + + typedef void *Item; // generic collection item + +protected: + QCollection() { del_item = FALSE; } // no deletion of objects + QCollection(const QCollection &) { del_item = FALSE; } + virtual ~QCollection() {} + + bool del_item; // default FALSE + + virtual Item newItem( Item ); // create object + virtual void deleteItem( Item ); // delete object +}; + + +#endif // QCOLLECTION_H diff --git a/trunk/qtools/qconfig.h b/trunk/qtools/qconfig.h new file mode 100644 index 0000000..7a880f9 --- /dev/null +++ b/trunk/qtools/qconfig.h @@ -0,0 +1 @@ +// Everything diff --git a/trunk/qtools/qcstring.cpp b/trunk/qtools/qcstring.cpp new file mode 100644 index 0000000..4038d55 --- /dev/null +++ b/trunk/qtools/qcstring.cpp @@ -0,0 +1,799 @@ +/****************************************************************************** + * + * Copyright (C) 1997-2004 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. + * + */ + +#include "qcstring.h" +#include "qgstring.h" + +#include <qstring.h> +#include <stdlib.h> +#include <stdio.h> +#include <stdarg.h> +#include <ctype.h> +#include <qregexp.h> +#include <qdatastream.h> + + +QCString::QCString(int size) +{ + if (size>0) + { + m_data = (char *)malloc(size); + if (m_data) + { + if (size>1) memset(m_data,' ',size-1); + m_data[size-1]='\0'; + } + } + else + { + m_data=0; + } +} + +QCString::QCString( const QCString &s ) +{ + duplicate(s); +} + +QCString::QCString( const char *str ) +{ + duplicate(str); +} + +QCString::QCString( const char *str, uint maxlen ) +{ + uint l; + if (str && ( l = QMIN(qstrlen(str),maxlen) )) + { + m_data=(char *)malloc(l+1); + strncpy(m_data,str,l+1); + m_data[l]='\0'; + } + else + { + m_data=0; + } +} + +QCString::~QCString() +{ + if (m_data) free(m_data); + m_data=0; +} + +QCString &QCString::assign( const char *str ) +{ + if (m_data) free(m_data); + duplicate(str); + return *this; +} + +bool QCString::resize( uint newlen ) +{ + if (newlen==0) + { + if (m_data) { free(m_data); m_data=0; } + return TRUE; + } + if (m_data==0) // newlen>0 + { + m_data = (char *)malloc(newlen); + } + else + { + m_data = (char *)realloc(m_data,newlen); + } + if (m_data==0) return FALSE; + m_data[newlen-1]='\0'; + return TRUE; +} + +bool QCString::fill( char c, int len ) +{ + uint l=length(); + if (len<0) len=l; + if ((uint)len!=l) + { + if (m_data) free(m_data); + if (len>0) + { + m_data=(char *)malloc(len+1); + if (m_data==0) return FALSE; + m_data[len]='\0'; + } + else + { + m_data=0; + } + } + if (len>0) + { + uint i; + for (i=0;i<(uint)len;i++) m_data[i]=c; + } + return TRUE; +} + +QCString &QCString::sprintf( const char *format, ... ) +{ + va_list ap; + va_start( ap, format ); + uint l = length(); + const uint minlen=256; + if (l<minlen) + { + if (m_data) + m_data = (char *)realloc(m_data,minlen); + else + m_data = (char *)malloc(minlen); + } + vsprintf( m_data, format, ap ); + resize( qstrlen(m_data) + 1 ); // truncate + va_end( ap ); + return *this; +} + + +int QCString::find( char c, int index, bool cs ) const +{ + uint len = length(); + if ( m_data==0 || (uint)index>len ) // index outside string + return -1; + register const char *d; + if ( cs ) // case sensitive + { + d = strchr( m_data+index, c ); + } + else + { + d = m_data+index; + c = tolower( (uchar) c ); + while ( *d && tolower((uchar) *d) != c ) + d++; + if ( !*d && c ) // not found + d = 0; + } + return d ? (int)(d - m_data) : -1; +} + +int QCString::find( const char *str, int index, bool cs ) const +{ + uint l = length(); + if ( m_data==0 || (uint)index > l ) // index outside string + return -1; + if ( !str ) // no search string + return -1; + if ( !*str ) // zero-length search string + return index; + register const char *d; + if ( cs ) // case sensitive + { + d = strstr( m_data+index, str ); + } + else // case insensitive + { + d = m_data+index; + int len = qstrlen( str ); + while ( *d ) + { + if ( qstrnicmp(d, str, len) == 0 ) + break; + d++; + } + if ( !*d ) // not found + d = 0; + } + return d ? (int)(d - m_data) : -1; +} + +int QCString::find( const QCString &str,int index,bool cs) const +{ + return find(str.data(),index,cs); +} + +int QCString::find( const QRegExp &rx, int index ) const +{ + QString d = QString::fromLatin1( m_data ); + return d.find( rx, index ); +} + +int QCString::findRev( char c, int index, bool cs) const +{ + const char *b = m_data; + const char *d; + uint len = length(); + if ( b == 0 ) return -1; // empty string + if ( index < 0 ) // neg index ==> start from end + { + if ( len == 0 ) return -1; + if ( cs ) + { + d = strrchr( b, c ); + return d ? (int)(d - b) : -1; + } + index = len; + } + else if ( (uint)index > len ) // bad index + { + return -1; + } + d = b+index; + if ( cs ) // case sensitive + { + while ( d >= b && *d != c ) + d--; + } + else // case insensitive + { + c = tolower( (uchar) c ); + while ( d >= b && tolower((uchar) *d) != c ) + d--; + } + return d >= b ? (int)(d - b) : -1; +} + +int QCString::findRev( const char *str, int index, bool cs) const +{ + int slen = qstrlen(str); + uint len = length(); + if ( index < 0 ) // neg index ==> start from end + index = len-slen; + else if ( (uint)index > len ) // bad index + return -1; + else if ( (uint)(index + slen) > len ) // str would be too long + index = len - slen; + if ( index < 0 ) + return -1; + + register char *d = m_data + index; + if ( cs ) // case sensitive + { + for ( int i=index; i>=0; i-- ) + if ( qstrncmp(d--,str,slen)==0 ) + return i; + } + else // case insensitive + { + for ( int i=index; i>=0; i-- ) + if ( qstrnicmp(d--,str,slen)==0 ) + return i; + } + return -1; + +} + +int QCString::findRev( const QRegExp &rx, int index ) const +{ + QString d = QString::fromLatin1( m_data ); + return d.findRev( rx, index ); +} + +int QCString::contains( char c, bool cs ) const +{ + int count = 0; + char *d = m_data; + if ( !d ) + return 0; + if ( cs ) // case sensitive + { + while ( *d ) + if ( *d++ == c ) + count++; + } + else // case insensitive + { + c = tolower( (uchar) c ); + while ( *d ) { + if ( tolower((uchar) *d) == c ) + count++; + d++; + } + } + return count; +} + +int QCString::contains( const char *str, bool cs ) const +{ + int count = 0; + char *d = data(); + if ( !d ) + return 0; + int len = qstrlen( str ); + while ( *d ) // counts overlapping strings + { + if ( cs ) + { + if ( qstrncmp( d, str, len ) == 0 ) + count++; + } + else + { + if ( qstrnicmp(d, str, len) == 0 ) + count++; + } + d++; + } + return count; +} + +int QCString::contains( const QRegExp &rx ) const +{ + QString d = QString::fromLatin1( m_data ); + return d.contains( rx ); +} + +QCString QCString::left( uint len ) const +{ + if ( isEmpty() ) + { + return QCString(); + } + else if ( len >= length() ) + { + return *this; + } + else + { + QCString s( len+1 ); + strncpy( s.data(), m_data, len ); + *(s.data()+len) = '\0'; + return s; + } +} + +QCString QCString::right( uint len ) const +{ + if ( isEmpty() ) + { + return QCString(); + } + else + { + uint l = length(); + if ( len > l ) len = l; + char *p = m_data + (l - len); + return QCString( p ); + } +} + +QCString QCString::mid( uint index, uint len) const +{ + uint slen = length(); + if ( len == 0xffffffff ) len = slen-index; + if ( isEmpty() || index >= slen ) + { + return QCString(); + } + else + { + register char *p = data()+index; + QCString s( len+1 ); + strncpy( s.data(), p, len ); + *(s.data()+len) = '\0'; + return s; + } +} + +QCString QCString::lower() const +{ + QCString s( m_data ); + register char *p = s.data(); + if ( p ) + { + while ( *p ) + { + *p = tolower((uchar) *p); + p++; + } + } + return s; +} + +QCString QCString::upper() const +{ + QCString s( m_data ); + register char *p = s.data(); + if ( p ) { + while ( *p ) { + *p = toupper((uchar)*p); + p++; + } + } + return s; +} + +QCString QCString::stripWhiteSpace() const +{ + if ( isEmpty() ) // nothing to do + return *this; + + register char *s = m_data; + int reslen = length(); + if ( !isspace((uchar) s[0]) && !isspace((uchar) s[reslen-1]) ) + return *this; // returns a copy + + QCString result(s); + s = result.data(); + int start = 0; + int end = reslen - 1; + while ( isspace((uchar) s[start]) ) // skip white space from start + start++; + if ( s[start] == '\0' ) + { // only white space + return QCString(); + } + while ( end && isspace((uchar) s[end]) ) // skip white space from end + end--; + end -= start - 1; + memmove( result.data(), &s[start], end ); + result.resize( end + 1 ); + return result; +} + +QCString QCString::simplifyWhiteSpace() const +{ + if ( isEmpty() ) // nothing to do + return *this; + + QCString result( length()+1 ); + char *from = data(); + char *to = result.data(); + char *first = to; + while ( TRUE ) + { + while ( *from && isspace((uchar) *from) ) + from++; + while ( *from && !isspace((uchar)*from) ) + *to++ = *from++; + if ( *from ) + *to++ = 0x20; // ' ' + else + break; + } + if ( to > first && *(to-1) == 0x20 ) + to--; + *to = '\0'; + result.resize( (int)((long)to - (long)result.data()) + 1 ); + return result; +} + +QCString &QCString::insert( uint index, const char *s ) +{ + int len = s ? qstrlen(s) : 0; + if ( len == 0 ) + return *this; + uint olen = length(); + int nlen = olen + len; + if ( index >= olen ) // insert after end of string + { + m_data = (char *)realloc(m_data,nlen+index-olen+1); + if ( m_data ) + { + memset( m_data+olen, ' ', index-olen ); + memcpy( m_data+index, s, len+1 ); + } + } + else if ( (m_data = (char *)realloc(m_data,nlen+1)) ) // normal insert + { + memmove( m_data+index+len, m_data+index, olen-index+1 ); + memcpy( m_data+index, s, len ); + } + return *this; +} + +QCString &QCString::insert( uint index, char c ) // insert char +{ + char buf[2]; + buf[0] = c; + buf[1] = '\0'; + return insert( index, buf ); +} + +QCString& QCString::operator+=( const char *str ) +{ + if ( !str ) return *this; // nothing to append + uint len1 = length(); + uint len2 = qstrlen(str); + char *newData = (char *)realloc( m_data, len1 + len2 + 1 ); + if (newData) + { + m_data = newData; + memcpy( m_data + len1, str, len2 + 1 ); + } + return *this; +} + +QCString &QCString::operator+=( char c ) +{ + uint len = length(); + char *newData = (char *)realloc( m_data, length()+2 ); + if (newData) + { + m_data = newData; + m_data[len] = c; + m_data[len+1] = '\0'; + } + return *this; +} + +QCString &QCString::remove( uint index, uint len ) +{ + uint olen = length(); + if ( index + len >= olen ) // range problems + { + if ( index < olen ) // index ok + { + resize( index+1 ); + } + } + else if ( len != 0 ) + { + memmove( m_data+index, m_data+index+len, olen-index-len+1 ); + resize( olen-len+1 ); + } + return *this; +} + +QCString &QCString::replace( uint index, uint len, const char *s ) +{ + remove( index, len ); + insert( index, s ); + return *this; +} + +QCString &QCString::replace( const QRegExp &rx, const char *str ) +{ + QString d = QString::fromLatin1( m_data ); + QString r = QString::fromLatin1( str ); + d.replace( rx, r ); + operator=( d.ascii() ); + return *this; +} + +long QCString::toLong( bool *ok ) const +{ + QString s(m_data); + return s.toLong(ok); +} + +ulong QCString::toULong( bool *ok ) const +{ + QString s(m_data); + return s.toULong(ok); +} + +short QCString::toShort( bool *ok ) const +{ + QString s(m_data); + return s.toShort(ok); +} + +ushort QCString::toUShort( bool *ok ) const +{ + QString s(m_data); + return s.toUShort(ok); +} + +int QCString::toInt( bool *ok ) const +{ + QString s(m_data); + return s.toInt(ok); +} + +uint QCString::toUInt( bool *ok ) const +{ + QString s(m_data); + return s.toUInt(ok); +} + +QCString &QCString::setNum( long n ) +{ + char buf[20]; + register char *p = &buf[19]; + bool neg; + if ( n < 0 ) + { + neg = TRUE; + n = -n; + } + else + { + neg = FALSE; + } + *p = '\0'; + do + { + *--p = ((int)(n%10)) + '0'; + n /= 10; + } while ( n ); + if ( neg ) *--p = '-'; + operator=( p ); + return *this; +} + +QCString &QCString::setNum( ulong n ) +{ + char buf[20]; + register char *p = &buf[19]; + *p = '\0'; + do + { + *--p = ((int)(n%10)) + '0'; + n /= 10; + } while ( n ); + operator=( p ); + return *this; +} + +void QCString::msg_index( uint index ) +{ +#if defined(CHECK_RANGE) + qWarning( "QCString::at: Absolute index %d out of range", index ); +#else + Q_UNUSED( index ) +#endif +} + +bool QCString::stripPrefix(const char *prefix) +{ + if (prefix==0) return FALSE; + uint plen = qstrlen(prefix); + if (m_data && qstrncmp(prefix,m_data,plen)==0) // prefix matches + { + uint len = qstrlen(m_data); + uint newlen = len-plen+1; + qmemmove(m_data,m_data+plen,newlen); + resize(newlen); + return TRUE; + } + return FALSE; +} + +//--------------------------------------------------------------------------- + +void *qmemmove( void *dst, const void *src, uint len ) +{ + register char *d; + register char *s; + if ( dst > src ) { + d = (char *)dst + len - 1; + s = (char *)src + len - 1; + while ( len-- ) + *d-- = *s--; + } else if ( dst < src ) { + d = (char *)dst; + s = (char *)src; + while ( len-- ) + *d++ = *s++; + } + return dst; +} + +char *qstrdup( const char *str ) +{ + if ( !str ) + return 0; + char *dst = new char[strlen(str)+1]; + CHECK_PTR( dst ); + return strcpy( dst, str ); +} + +char *qstrncpy( char *dst, const char *src, uint len ) +{ + if ( !src ) + return 0; + strncpy( dst, src, len ); + if ( len > 0 ) + dst[len-1] = '\0'; + return dst; +} + +int qstricmp( const char *str1, const char *str2 ) +{ + register const uchar *s1 = (const uchar *)str1; + register const uchar *s2 = (const uchar *)str2; + int res; + uchar c; + if ( !s1 || !s2 ) + return s1 == s2 ? 0 : (int)((long)s2 - (long)s1); + for ( ; !(res = (c=tolower(*s1)) - tolower(*s2)); s1++, s2++ ) + if ( !c ) // strings are equal + break; + return res; +} + +int qstrnicmp( const char *str1, const char *str2, uint len ) +{ + register const uchar *s1 = (const uchar *)str1; + register const uchar *s2 = (const uchar *)str2; + int res; + uchar c; + if ( !s1 || !s2 ) + return (int)((long)s2 - (long)s1); + for ( ; len--; s1++, s2++ ) { + if ( (res = (c=tolower(*s1)) - tolower(*s2)) ) + return res; + if ( !c ) // strings are equal + break; + } + return 0; +} + +#ifndef QT_NO_DATASTREAM + +QDataStream &operator<<( QDataStream &s, const QByteArray &a ) +{ + return s.writeBytes( a.data(), a.size() ); +} + +QDataStream &operator>>( QDataStream &s, QByteArray &a ) +{ + Q_UINT32 len; + s >> len; // read size of array + if ( len == 0 || s.eof() ) { // end of file reached + a.resize( 0 ); + return s; + } + if ( !a.resize( (uint)len ) ) { // resize array +#if defined(CHECK_NULL) + qWarning( "QDataStream: Not enough memory to read QByteArray" ); +#endif + len = 0; + } + if ( len > 0 ) // not null array + s.readRawBytes( a.data(), (uint)len ); + return s; +} + +QDataStream &operator<<( QDataStream &s, const QCString &str ) +{ + return s.writeBytes( str.data(), str.size() ); +} + +QDataStream &operator>>( QDataStream &s, QCString &str ) +{ + Q_UINT32 len; + s >> len; // read size of string + if ( len == 0 || s.eof() ) { // end of file reached + str.resize( 0 ); + return s; + } + if ( !str.resize( (uint)len )) {// resize string +#if defined(CHECK_NULL) + qWarning( "QDataStream: Not enough memory to read QCString" ); +#endif + len = 0; + } + if ( len > 0 ) // not null array + s.readRawBytes( str.data(), (uint)len ); + return s; +} + +#endif //QT_NO_DATASTREAM + +inline QCString operator+( const QCString &s1, const QGString &s2 ) +{ + QCString tmp(s1); + tmp += s2.data(); + return tmp; +} + +inline QCString operator+( const QGString &s1, const QCString &s2 ) +{ + QCString tmp(s1.data()); + tmp += s2; + return tmp; +} + diff --git a/trunk/qtools/qcstring.h b/trunk/qtools/qcstring.h new file mode 100644 index 0000000..bbe8700 --- /dev/null +++ b/trunk/qtools/qcstring.h @@ -0,0 +1,464 @@ +/**************************************************************************** +** +** +** Definition of the extended char array operations, +** and QByteArray and QCString classes +** +** Created : 920609 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QCSTRING_H +#define QCSTRING_H + +#ifndef QT_H +#include "qarray.h" +#endif // QT_H + +#include <stdlib.h> +#include <string.h> + +#if defined(_OS_SUN_) && defined(_CC_GNU_) +#include <strings.h> +#endif + + +class QGString; + +/***************************************************************************** + Fixes and workarounds for some platforms + *****************************************************************************/ + +#if defined(_OS_HPUX_) +// HP-UX has badly defined strstr() etc. +// ### fix in 3.0: change hack_* to qt_hack_* +// by the way HP-UX is probably right, the standard has evolved and +// we'll have to adapt to it +inline char *hack_strstr( const char *s1, const char *s2 ) +{ return (char *)strstr(s1, s2); } +inline char *hack_strchr( const char *s, int c ) +{ return (char *)strchr(s, c); } +inline char *hack_strrchr( const char *s, int c ) +{ return (char *)strrchr(s, c); } +#define strstr(s1,s2) hack_strstr((s1),(s2)) +#define strchr(s,c) hack_strchr((s),(c)) +#define strrchr(s,c) hack_strrchr((s),(c)) +#endif + + +/***************************************************************************** + Safe and portable C string functions; extensions to standard string.h + *****************************************************************************/ + +Q_EXPORT void *qmemmove( void *dst, const void *src, uint len ); + +#if defined(_OS_SUN_) || defined(_CC_OC_) +#define memmove(s1,s2,n) qmemmove((s1),(s2),(n)) +#endif + +Q_EXPORT char *qstrdup( const char * ); + +Q_EXPORT inline uint cstrlen( const char *str ) +{ return (uint)strlen(str); } + +Q_EXPORT inline uint qstrlen( const char *str ) +{ return str ? (uint)strlen(str) : 0; } + +Q_EXPORT inline char *cstrcpy( char *dst, const char *src ) +{ return strcpy(dst,src); } + +Q_EXPORT inline char *qstrcpy( char *dst, const char *src ) +{ return src ? strcpy(dst, src) : 0; } + +Q_EXPORT char *qstrncpy( char *dst, const char *src, uint len ); + +Q_EXPORT inline int cstrcmp( const char *str1, const char *str2 ) +{ return strcmp(str1,str2); } + +Q_EXPORT inline int qstrcmp( const char *str1, const char *str2 ) +{ return (str1 && str2) ? strcmp(str1,str2) : (int)((long)str2 - (long)str1); } + +Q_EXPORT inline int cstrncmp( const char *str1, const char *str2, uint len ) +{ return strncmp(str1,str2,len); } + +Q_EXPORT inline int qstrncmp( const char *str1, const char *str2, uint len ) +{ return (str1 && str2) ? strncmp(str1,str2,len) : + (int)((long)str2 - (long)str1); } + +Q_EXPORT int qstricmp( const char *, const char * ); + +Q_EXPORT int qstrnicmp( const char *, const char *, uint len ); + +// ### TODO for 3.0: these and the cstr* functions should be used if +// !defined(QT_CLEAN_NAMESPACE) +// We want to keep source compatibility for 2.x +// ### TODO for 4.0: completely remove these and the cstr* functions + +#if !defined(QT_GENUINE_STR) + +#undef strlen +#define strlen qstrlen + +#undef strcpy +#define strcpy qstrcpy + +#undef strcmp +#define strcmp qstrcmp + +#undef strncmp +#define strncmp qstrncmp + +#undef stricmp +#define stricmp qstricmp + +#undef strnicmp +#define strnicmp qstrnicmp + +#endif + +// qChecksum: Internet checksum + +Q_EXPORT Q_UINT16 qChecksum( const char *s, uint len ); + +/***************************************************************************** + QByteArray class + *****************************************************************************/ + +#if defined(Q_TEMPLATEDLL) +template class Q_EXPORT QArray<char>; +#endif +typedef QArray<char> QByteArray; + + +/***************************************************************************** + QByteArray stream functions + *****************************************************************************/ +#ifndef QT_NO_DATASTREAM +Q_EXPORT QDataStream &operator<<( QDataStream &, const QByteArray & ); +Q_EXPORT QDataStream &operator>>( QDataStream &, QByteArray & ); +#endif + +class QRegExp; + +/** This is an alternative implementation of QCString. It provides basically + * the same functions but uses less memory for administration. This class + * is just a wrapper around a plain C string requiring only 4 bytes "overhead". + * QCString features sharing of data and stores the string length, but + * requires 4 + 12 bytes for this (even for the empty string). As doxygen + * uses a LOT of string during a run it saves a lot of memory to use a + * more memory efficient implementation at the cost of relatively low + * runtime overhead. + */ +class QCString +{ +public: + QCString() : m_data(0) {} // make null string + QCString( const QCString &s ); + QCString( int size ); + QCString( const char *str ); + QCString( const char *str, uint maxlen ); + ~QCString(); + + QCString &operator=( const QCString &s );// deep copy + QCString &operator=( const char *str ); // deep copy + + bool isNull() const; + bool isEmpty() const; + uint length() const; + uint size() const { return m_data ? length()+1 : 0; } + char * data() const { return m_data; } + bool resize( uint newlen ); + bool truncate( uint pos ); + bool fill( char c, int len = -1 ); + + QCString copy() const; + + QCString &sprintf( const char *format, ... ); + + int find( char c, int index=0, bool cs=TRUE ) const; + int find( const char *str, int index=0, bool cs=TRUE ) const; + int find( const QCString &str, int index=0, bool cs=TRUE ) const; + int find( const QRegExp &, int index=0 ) const; + int findRev( char c, int index=-1, bool cs=TRUE) const; + int findRev( const char *str, int index=-1, bool cs=TRUE) const; + int findRev( const QRegExp &, int index=-1 ) const; + int contains( char c, bool cs=TRUE ) const; + int contains( const char *str, bool cs=TRUE ) const; + int contains( const QRegExp & ) const; + bool stripPrefix(const char *prefix); + + QCString left( uint len ) const; + QCString right( uint len ) const; + QCString mid( uint index, uint len=0xffffffff) const; + + QCString lower() const; + QCString upper() const; + + QCString stripWhiteSpace() const; + QCString simplifyWhiteSpace() const; + + QCString &assign( const char *str ); + QCString &insert( uint index, const char * ); + QCString &insert( uint index, char ); + QCString &append( const char *s ); + QCString &prepend( const char *s ); + QCString &remove( uint index, uint len ); + QCString &replace( uint index, uint len, const char * ); + QCString &replace( const QRegExp &, const char * ); + + short toShort( bool *ok=0 ) const; + ushort toUShort( bool *ok=0 ) const; + int toInt( bool *ok=0 ) const; + uint toUInt( bool *ok=0 ) const; + long toLong( bool *ok=0 ) const; + ulong toULong( bool *ok=0 ) const; + + QCString &setNum( short ); + QCString &setNum( ushort ); + QCString &setNum( int ); + QCString &setNum( uint ); + QCString &setNum( long ); + QCString &setNum( ulong ); + QCString &setNum( float, char f='g', int prec=6 ); + QCString &setNum( double, char f='g', int prec=6 ); + + operator const char *() const; + QCString &operator+=( const char *str ); + QCString &operator+=( char c ); + char &at( uint index ) const; + char &operator[]( int i ) const { return at(i); } + + private: + static void msg_index( uint ); + void duplicate( const QCString &s ); + void duplicate( const char *str); + QCString &duplicate( const char *str, int); + + char * m_data; +}; + +inline char &QCString::at( uint index ) const +{ + return m_data[index]; +} + +inline void QCString::duplicate( const QCString &s ) +{ + if (!s.isEmpty()) + { + uint l = strlen(s.data()); + m_data = (char *)malloc(l+1); + if (m_data) memcpy(m_data,s.data(),l+1); + } + else + m_data=0; +} + +inline void QCString::duplicate( const char *str) +{ + if (str && str[0]!='\0') + { + uint l = strlen(str); + m_data = (char *)malloc(l+1); + if (m_data) memcpy(m_data,str,l+1); + } + else + m_data=0; +} + +inline QCString &QCString::duplicate( const char *str, int) +{ + if (m_data==str) return *this; + if (m_data) free(m_data); + duplicate(str); + return *this; +} + +/***************************************************************************** + QCString stream functions + *****************************************************************************/ +#ifndef QT_NO_DATASTREAM +Q_EXPORT QDataStream &operator<<( QDataStream &, const QCString & ); +Q_EXPORT QDataStream &operator>>( QDataStream &, QCString & ); +#endif + +/***************************************************************************** + QCString inline functions + *****************************************************************************/ + +inline QCString &QCString::operator=( const QCString &s ) +{ return (QCString&)assign( s ); } + +inline QCString &QCString::operator=( const char *str ) +{ return (QCString&)duplicate( str, qstrlen(str)+1 ); } + +inline bool QCString::isNull() const +{ return data() == 0; } + +inline bool QCString::isEmpty() const +{ return data() == 0 || *data() == '\0'; } + +inline uint QCString::length() const +{ return qstrlen( data() ); } + +inline bool QCString::truncate( uint pos ) +{ return resize(pos+1); } + +inline QCString QCString::copy() const +{ return QCString( data() ); } + +inline QCString &QCString::prepend( const char *s ) +{ return insert(0,s); } + +inline QCString &QCString::append( const char *s ) +{ return operator+=(s); } + +inline QCString &QCString::setNum( short n ) +{ return setNum((long)n); } + +inline QCString &QCString::setNum( ushort n ) +{ return setNum((ulong)n); } + +inline QCString &QCString::setNum( int n ) +{ return setNum((long)n); } + +inline QCString &QCString::setNum( uint n ) +{ return setNum((ulong)n); } + +inline QCString &QCString::setNum( float n, char f, int prec ) +{ return setNum((double)n,f,prec); } + +inline QCString::operator const char *() const +{ return (const char *)data(); } + + +/***************************************************************************** + QCString non-member operators + *****************************************************************************/ + +Q_EXPORT inline bool operator==( const QCString &s1, const QCString &s2 ) +{ return qstrcmp(s1.data(),s2.data()) == 0; } + +Q_EXPORT inline bool operator==( const QCString &s1, const char *s2 ) +{ return qstrcmp(s1.data(),s2) == 0; } + +Q_EXPORT inline bool operator==( const char *s1, const QCString &s2 ) +{ return qstrcmp(s1,s2.data()) == 0; } + +Q_EXPORT inline bool operator!=( const QCString &s1, const QCString &s2 ) +{ return qstrcmp(s1.data(),s2.data()) != 0; } + +Q_EXPORT inline bool operator!=( const QCString &s1, const char *s2 ) +{ return qstrcmp(s1.data(),s2) != 0; } + +Q_EXPORT inline bool operator!=( const char *s1, const QCString &s2 ) +{ return qstrcmp(s1,s2.data()) != 0; } + +Q_EXPORT inline bool operator<( const QCString &s1, const QCString& s2 ) +{ return qstrcmp(s1.data(),s2.data()) < 0; } + +Q_EXPORT inline bool operator<( const QCString &s1, const char *s2 ) +{ return qstrcmp(s1.data(),s2) < 0; } + +Q_EXPORT inline bool operator<( const char *s1, const QCString &s2 ) +{ return qstrcmp(s1,s2.data()) < 0; } + +Q_EXPORT inline bool operator<=( const QCString &s1, const char *s2 ) +{ return qstrcmp(s1.data(),s2) <= 0; } + +Q_EXPORT inline bool operator<=( const char *s1, const QCString &s2 ) +{ return qstrcmp(s1,s2.data()) <= 0; } + +Q_EXPORT inline bool operator>( const QCString &s1, const char *s2 ) +{ return qstrcmp(s1.data(),s2) > 0; } + +Q_EXPORT inline bool operator>( const char *s1, const QCString &s2 ) +{ return qstrcmp(s1,s2.data()) > 0; } + +Q_EXPORT inline bool operator>=( const QCString &s1, const char *s2 ) +{ return qstrcmp(s1.data(),s2) >= 0; } + +Q_EXPORT inline bool operator>=( const char *s1, const QCString &s2 ) +{ return qstrcmp(s1,s2.data()) >= 0; } + +Q_EXPORT inline QCString operator+( const QCString &s1, const QCString &s2 ) +{ + QCString tmp(s1); + tmp += s2; + return tmp; +} + + +inline QCString operator+( const QCString &s1, const QGString &s2 ); +inline QCString operator+( const QGString &s1, const QCString &s2 ); + + +Q_EXPORT inline QCString operator+( const QCString &s1, const char *s2 ) +{ + QCString tmp(s1); + tmp += s2; + return tmp; +} + +Q_EXPORT inline QCString operator+( const char *s1, const QCString &s2 ) +{ + QCString tmp(s1); + tmp += s2; + return tmp; +} + +Q_EXPORT inline QCString operator+( const QCString &s1, char c2 ) +{ + QCString tmp( s1.data() ); + tmp += c2; + return tmp; +} + +Q_EXPORT inline QCString operator+( char c1, const QCString &s2 ) +{ + QCString tmp; + tmp += c1; + tmp += s2; + return tmp; +} + +inline const char *qPrint(const char *s) +{ + if (s) return s; else return ""; +} + +inline const char *qPrint(const QCString &s) +{ + if (!s.isEmpty()) return s.data(); else return ""; +} + + +#endif // QCSTRING_H diff --git a/trunk/qtools/qdatastream.cpp b/trunk/qtools/qdatastream.cpp new file mode 100644 index 0000000..7f63cbf --- /dev/null +++ b/trunk/qtools/qdatastream.cpp @@ -0,0 +1,951 @@ +/**************************************************************************** +** +** +** Implementation of QDataStream class +** +** Created : 930831 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "qdatastream.h" + +#ifndef QT_NO_DATASTREAM +#include "qbuffer.h" +#include <stdio.h> +#include <ctype.h> +#include <stdlib.h> + +// REVISED: warwick +/*! + \class QDataStream qdatastream.h + + \brief The QDataStream class provides serialization of + binary data to a QIODevice. + + \ingroup io + + A data stream is a binary stream of encoded information which is 100% + independent of the host computer operation system, CPU or byte order. A + stream that is written by a PC under DOS/Windows can be read by a + Sun SPARC running Solaris. + + The QDataStream class implements serialization of primitive types, like + \c char, \c short, \c int, \c char* etc. Serialization of more complex + data is accomplished by breaking up the data into primitive units. + + The programmer can select which byte order to use when serializing data. + The default setting is big endian (MSB first). Changing it to little + endian breaks the portability (unless the reader also changes to little + endian). We recommend keeping this setting unless you have + special requirements. + + A data stream cooperates closely with a QIODevice. A QIODevice + represents an input/output medium one can read data from and write data + to. The QFile class is an example of an IO device. + + Example (write data to a stream): + \code + QFile f( "file.dta" ); + f.open( IO_WriteOnly ); // open file for writing + QDataStream s( &f ); // serialize using f + s << "the answer is"; // serialize string + s << (Q_INT32)42; // serialize integer + \endcode + + Example (read data from a stream): + \code + QFile f( "file.dta" ); + f.open( IO_ReadOnly ); // open file for reading + QDataStream s( &f ); // serialize using f + char *str; + Q_INT32 a; + s >> str >> a; // "the answer is" and 42 + delete str; // delete string + \endcode + + In the last example, if you read into a QString instead of a \c char* + you do not have to delete it. + + Normally, each item written to the stream is written in a fixed binary + format. + For example, a \c char* is written as a 32-bit integer equal to the + length of the string including the NUL byte, followed by all the + characters of the string including the NUL byte. Similarly when + reading a string, 4 bytes are read to create the 32-bit length value, + then that many characters for the string including the NUL. For a complete + description of all Qt types supporting data streaming see \link + datastreamformat.html Format of the QDataStream operators \endlink . + + If you want a "parsing" input stream, see QTextStream. If you just want the + data to be human-readable to aid in debugging, you can set the data + stream into printable data mode with setPrintableData(). The data is + then written slower, in a human readable bloated form that is sufficient + for debugging. + + If you are producing a new binary data format, such as a file format + for documents created by your application, you could use a QDataStream + to write the data in a portable format. Typically, you would write + a brief header containing a magic string and a version number to give + yourself room for future expansion. For example: + + \code + // Open the file. + QFile f( "file.xxx" ); + f.open( IO_WriteOnly ); + QDataStream s( &f ); + + // Write a header with a "magic number" and a version + s << 0xa0b0c0d0; + s << 123; + + // Write the data + s << [lots of interesting data] + \endcode + + Then read it in with: + + \code + // Open the file. + QFile f( "file.xxx" ); + f.open( IO_ReadOnly ); + QDataStream s( &f ); + + // Read and check the header + Q_UINT32 magic; + s >> magic; + if ( magic != 0xa0b0c0d0 ) + return XXX_BAD_FILE_FORMAT; + + // Read the version + Q_INT32 version; + s >> version; + if ( version < 100 ) + return XXX_BAD_FILE_TOO_OLD; + if ( version > 123 ) + return XXX_BAD_FILE_TOO_NEW; + if ( version <= 110 ) + s.setVersion(1); + + // Read the data + s >> [lots of interesting data]; + if ( version > 120 ) + s >> [data new in XXX version 1.2]; + s >> [other interesting data]; + \endcode + + \sa QTextStream QVariant +*/ + + +/***************************************************************************** + QDataStream member functions + *****************************************************************************/ + +#if defined(CHECK_STATE) +#undef CHECK_STREAM_PRECOND +#define CHECK_STREAM_PRECOND if ( !dev ) { \ + qWarning( "QDataStream: No device" ); \ + return *this; } +#else +#define CHECK_STREAM_PRECOND +#endif + +static int systemWordSize = 0; +static bool systemBigEndian; + +static const int DefaultStreamVersion = 3; +// 3 is default in Qt 2.1 +// 2 is the Qt 2.0.x format +// 1 is the Qt 1.x format + +/*! + Constructs a data stream that has no IO device. + + \sa setDevice() +*/ + +QDataStream::QDataStream() +{ + if ( systemWordSize == 0 ) // get system features + qSysInfo( &systemWordSize, &systemBigEndian ); + dev = 0; // no device set + owndev = FALSE; + byteorder = BigEndian; // default byte order + printable = FALSE; + ver = DefaultStreamVersion; + noswap = systemBigEndian; +} + +/*! + Constructs a data stream that uses the IO device \a d. + + \sa setDevice(), device() +*/ + +QDataStream::QDataStream( QIODevice *d ) +{ + if ( systemWordSize == 0 ) // get system features + qSysInfo( &systemWordSize, &systemBigEndian ); + dev = d; // set device + owndev = FALSE; + byteorder = BigEndian; // default byte order + printable = FALSE; + ver = DefaultStreamVersion; + noswap = systemBigEndian; +} + +/*! + Constructs a data stream that operates on a byte array through an + internal QBuffer device. + + Example: + \code + static char bindata[] = { 231, 1, 44, ... }; + QByteArray a; + a.setRawData( bindata, sizeof(bindata) ); // a points to bindata + QDataStream s( a, IO_ReadOnly ); // open on a's data + s >> [something]; // read raw bindata + a.resetRawData( bindata, sizeof(bindata) ); // finished + \endcode + + The QArray::setRawData() function is not for the inexperienced. +*/ + +QDataStream::QDataStream( QByteArray a, int mode ) +{ + if ( systemWordSize == 0 ) // get system features + qSysInfo( &systemWordSize, &systemBigEndian ); + dev = new QBuffer( a ); // create device + ((QBuffer *)dev)->open( mode ); // open device + owndev = TRUE; + byteorder = BigEndian; // default byte order + printable = FALSE; + ver = DefaultStreamVersion; + noswap = systemBigEndian; +} + +/*! + Destructs the data stream. + + The destructor will not affect the current IO device, unless it + is an internal IO device processing a QByteArray passed in the constructor. +*/ + +QDataStream::~QDataStream() +{ + if ( owndev ) + delete dev; +} + + +/*! + \fn QIODevice *QDataStream::device() const + Returns the IO device currently set. + \sa setDevice(), unsetDevice() +*/ + +/*! + void QDataStream::setDevice(QIODevice *d ) + Sets the IO device to \a d. + \sa device(), unsetDevice() +*/ + +void QDataStream::setDevice(QIODevice *d ) +{ + if ( owndev ) { + delete dev; + owndev = FALSE; + } + dev = d; +} + +/*! + Unsets the IO device. This is the same as calling setDevice( 0 ). + \sa device(), setDevice() +*/ + +void QDataStream::unsetDevice() +{ + setDevice( 0 ); +} + + +/*! + \fn bool QDataStream::atEnd() const + Returns TRUE if the IO device has reached the end position (end of + stream or file) or if there is no IO device set. + + Returns FALSE if the current position of the read/write head of the IO + device is somewhere before the end position. + + \sa QIODevice::atEnd() +*/ + +/*!\fn bool QDataStream::eof() const + + \obsolete + + Returns TRUE if the IO device has reached the end position (end of + stream or file) or if there is no IO device set. + + Returns FALSE if the current position of the read/write head of the IO + device is somewhere before the end position. + + \sa QIODevice::atEnd() +*/ + +/*! + \fn int QDataStream::byteOrder() const + Returns the current byte order setting - either \c BigEndian or + \c LittleEndian. + + \sa setByteOrder() +*/ + +/*! + Sets the serialization byte order to \a bo. + + The \a bo parameter can be \c QDataStream::BigEndian or + \c QDataStream::LittleEndian. + + The default setting is big endian. We recommend leaving this setting unless + you have special requirements. + + \sa byteOrder() +*/ + +void QDataStream::setByteOrder( int bo ) +{ + byteorder = bo; + if ( systemBigEndian ) + noswap = byteorder == BigEndian; + else + noswap = byteorder == LittleEndian; +} + + +/*! + \fn bool QDataStream::isPrintableData() const + Returns TRUE if the printable data flag has been set. + \sa setPrintableData() +*/ + +/*! + \fn void QDataStream::setPrintableData( bool enable ) + Sets or clears the printable data flag. + + If this flag is set, the write functions will generate output that + consists of printable characters (7 bit ASCII). + + We recommend enabling printable data only for debugging purposes + (it is slower and creates larger output). +*/ + + +/*! + \fn int QDataStream::version() const + Returns the version number of the data serialization format. + In Qt 2.1, this number is by default 3. + \sa setVersion() +*/ + +/*! + \fn void QDataStream::setVersion( int v ) + Sets the version number of the data serialization format. + + In order to accomodate for new functionality, the datastream + serialization format of some Qt classes has changed in some versions of + Qt. If you want to read data that was created by an earlier version of + Qt, or write data that can be read by a program that was compiled with + an earlier version of Qt, use this function to modify the serialization + format of QDataStream. + + For Qt 1.x compatibility, use \a v == 1. + + For Qt 2.0.x compatibility, use \a v == 2 (Not required for reading in + Qt 2.1). + + \sa version() +*/ + +/***************************************************************************** + QDataStream read functions + *****************************************************************************/ + + +static Q_INT32 read_int_ascii( QDataStream *s ) +{ + register int n = 0; + char buf[40]; + while ( TRUE ) { + buf[n] = s->device()->getch(); + if ( buf[n] == '\n' || n > 38 ) // $-terminator + break; + n++; + } + buf[n] = '\0'; + return atol( buf ); +} + + +/*! + \fn QDataStream &QDataStream::operator>>( Q_UINT8 &i ) + Reads an unsigned byte from the stream and returns a reference to + the stream. +*/ + +/*! + Reads a signed byte from the stream. +*/ + +QDataStream &QDataStream::operator>>( Q_INT8 &i ) +{ + CHECK_STREAM_PRECOND + if ( printable ) { // printable data + i = (Q_INT8)dev->getch(); + if ( i == '\\' ) { // read octal code + char buf[4]; + dev->readBlock( buf, 3 ); + i = (buf[2] & 0x07)+((buf[1] & 0x07) << 3)+((buf[0] & 0x07) << 6); + } + } else { // data or text + i = (Q_INT8)dev->getch(); + } + return *this; +} + + +/*! + \fn QDataStream &QDataStream::operator>>( Q_UINT16 &i ) + Reads an unsigned 16-bit integer from the stream and returns a reference to + the stream. +*/ + +/*! + Reads a signed 16-bit integer from the stream and returns a reference to + the stream. +*/ + +QDataStream &QDataStream::operator>>( Q_INT16 &i ) +{ + CHECK_STREAM_PRECOND + if ( printable ) { // printable data + i = (Q_INT16)read_int_ascii( this ); + } else if ( noswap ) { // no conversion needed + dev->readBlock( (char *)&i, sizeof(Q_INT16) ); + } else { // swap bytes + register uchar *p = (uchar *)(&i); + char b[2]; + dev->readBlock( b, 2 ); + *p++ = b[1]; + *p = b[0]; + } + return *this; +} + + +/*! + \fn QDataStream &QDataStream::operator>>( Q_UINT32 &i ) + Reads an unsigned 32-bit integer from the stream and returns a reference to + the stream. +*/ + +/*! + Reads a signed 32-bit integer from the stream and returns a reference to + the stream. +*/ + +QDataStream &QDataStream::operator>>( Q_INT32 &i ) +{ + CHECK_STREAM_PRECOND + if ( printable ) { // printable data + i = read_int_ascii( this ); + } else if ( noswap ) { // no conversion needed + dev->readBlock( (char *)&i, sizeof(Q_INT32) ); + } else { // swap bytes + register uchar *p = (uchar *)(&i); + char b[4]; + dev->readBlock( b, 4 ); + *p++ = b[3]; + *p++ = b[2]; + *p++ = b[1]; + *p = b[0]; + } + return *this; +} + +/*! + \fn QDataStream &QDataStream::operator>>( Q_UINT64 &i ) + Reads an unsigned 64-bit integer from the stream and returns a reference to + the stream, or uses the Q_UINT32 operator if 64 bit is not available. +*/ + +/*! + Reads a signed 64-bit integer from the stream and returns a reference to + the stream, or uses the Q_UINT32 operator if 64 bit is not available. +*/ + +QDataStream &QDataStream::operator>>( Q_INT64 &i ) +{ + CHECK_STREAM_PRECOND + if ( printable ) { // printable data + i = read_int_ascii( this ); + } else if ( noswap ) { // no conversion needed + dev->readBlock( (char *)&i, sizeof(Q_INT64) ); + } else { // swap bytes + register uchar *p = (uchar *)(&i); + char b[sizeof(Q_INT64)]; + dev->readBlock( b, sizeof(Q_INT64) ); + if ( sizeof(Q_INT64) == 8 ) { + *p++ = b[7]; + *p++ = b[6]; + *p++ = b[5]; + *p++ = b[4]; + } + *p++ = b[3]; + *p++ = b[2]; + *p++ = b[1]; + *p = b[0]; + } + return *this; +} + +static double read_double_ascii( QDataStream *s ) +{ + register int n = 0; + char buf[80]; + while ( TRUE ) { + buf[n] = s->device()->getch(); + if ( buf[n] == '\n' || n > 78 ) // $-terminator + break; + n++; + } + buf[n] = '\0'; + return atof( buf ); +} + + +/*! + Reads a 32-bit floating point number from the stream using the standard + IEEE754 format. Returns a reference to the stream. +*/ + +QDataStream &QDataStream::operator>>( float &f ) +{ + CHECK_STREAM_PRECOND + if ( printable ) { // printable data + f = (float)read_double_ascii( this ); + } else if ( noswap ) { // no conversion needed + dev->readBlock( (char *)&f, sizeof(float) ); + } else { // swap bytes + register uchar *p = (uchar *)(&f); + char b[4]; + dev->readBlock( b, 4 ); + *p++ = b[3]; + *p++ = b[2]; + *p++ = b[1]; + *p = b[0]; + } + return *this; +} + + +/*! + Reads a 64-bit floating point number from the stream using the standard + IEEE754 format. Returns a reference to the stream. +*/ + +QDataStream &QDataStream::operator>>( double &f ) +{ + CHECK_STREAM_PRECOND + if ( printable ) { // printable data + f = read_double_ascii( this ); + } else if ( noswap ) { // no conversion needed + dev->readBlock( (char *)&f, sizeof(double) ); + } else { // swap bytes + register uchar *p = (uchar *)(&f); + char b[8]; + dev->readBlock( b, 8 ); + *p++ = b[7]; + *p++ = b[6]; + *p++ = b[5]; + *p++ = b[4]; + *p++ = b[3]; + *p++ = b[2]; + *p++ = b[1]; + *p = b[0]; + } + return *this; +} + + +/*! + Reads the '\0'-terminated string \a s from the stream and returns + a reference to the stream. + + Space for the string is allocated using \c new - the caller must + eventually call delete[] on the value. +*/ + +QDataStream &QDataStream::operator>>( char *&s ) +{ + uint len = 0; + return readBytes( s, len ); +} + + +/*! + Reads the buffer \a s from the stream and returns a reference to the + stream. + + The buffer \a s is allocated using \c new. Destroy it with the \c delete[] + operator. If the length is zero or \a s cannot be allocated, \a s is + set to 0. + + The \a l parameter will be set to the length of the buffer. + + The serialization format is an Q_UINT32 length specifier first, then the + data (\a l bytes). + + \sa readRawBytes(), writeBytes() +*/ + +QDataStream &QDataStream::readBytes( char *&s, uint &l ) +{ + CHECK_STREAM_PRECOND + Q_UINT32 len; + *this >> len; // first read length spec + l = (uint)len; + if ( len == 0 || eof() ) { + s = 0; + return *this; + } else { + s = new char[len]; // create char array + CHECK_PTR( s ); + if ( !s ) // no memory + return *this; + return readRawBytes( s, (uint)len ); + } +} + + +/*! + Reads \a len bytes from the stream into \a s and returns a reference to + the stream. + + The buffer \a s must be preallocated. + + \sa readBytes(), QIODevice::readBlock(), writeRawBytes() +*/ + +QDataStream &QDataStream::readRawBytes( char *s, uint len ) +{ + CHECK_STREAM_PRECOND + if ( printable ) { // printable data + register Q_INT8 *p = (Q_INT8*)s; + while ( len-- ) + *this >> *p++; + } else { // read data char array + dev->readBlock( s, len ); + } + return *this; +} + + +/***************************************************************************** + QDataStream write functions + *****************************************************************************/ + + +/*! + \fn QDataStream &QDataStream::operator<<( Q_UINT8 i ) + Writes an unsigned byte to the stream and returns a reference to + the stream. +*/ + +/*! + Writes a signed byte to the stream. +*/ + +QDataStream &QDataStream::operator<<( Q_INT8 i ) +{ + CHECK_STREAM_PRECOND + if ( printable && (i == '\\' || !isprint(i)) ) { + char buf[6]; // write octal code + buf[0] = '\\'; + buf[1] = '0' + ((i >> 6) & 0x07); + buf[2] = '0' + ((i >> 3) & 0x07); + buf[3] = '0' + (i & 0x07); + buf[4] = '\0'; + dev->writeBlock( buf, 4 ); + } else { + dev->putch( i ); + } + return *this; +} + + +/*! + \fn QDataStream &QDataStream::operator<<( Q_UINT16 i ) + Writes an unsigned 16-bit integer to the stream and returns a reference + to the stream. +*/ + +/*! + Writes a signed 16-bit integer to the stream and returns a reference to + the stream. +*/ + +QDataStream &QDataStream::operator<<( Q_INT16 i ) +{ + CHECK_STREAM_PRECOND + if ( printable ) { // printable data + char buf[16]; + sprintf( buf, "%d\n", i ); + dev->writeBlock( buf, strlen(buf) ); + } else if ( noswap ) { // no conversion needed + dev->writeBlock( (char *)&i, sizeof(Q_INT16) ); + } else { // swap bytes + register uchar *p = (uchar *)(&i); + char b[2]; + b[1] = *p++; + b[0] = *p; + dev->writeBlock( b, 2 ); + } + return *this; +} + + +/*! + \fn QDataStream &QDataStream::operator<<( Q_UINT32 i ) + Writes an unsigned 32-bit integer to the stream and returns a reference to + the stream. +*/ + +/*! + Writes a signed 32-bit integer to the stream and returns a reference to + the stream. +*/ + +QDataStream &QDataStream::operator<<( Q_INT32 i ) +{ + CHECK_STREAM_PRECOND + if ( printable ) { // printable data + char buf[16]; + sprintf( buf, "%d\n", i ); + dev->writeBlock( buf, strlen(buf) ); + } else if ( noswap ) { // no conversion needed + dev->writeBlock( (char *)&i, sizeof(Q_INT32) ); + } else { // swap bytes + register uchar *p = (uchar *)(&i); + char b[4]; + b[3] = *p++; + b[2] = *p++; + b[1] = *p++; + b[0] = *p; + dev->writeBlock( b, 4 ); + } + return *this; +} + +/*! + \fn QDataStream &QDataStream::operator<<( Q_UINT64 i ) + Writes an unsigned 64-bit integer to the stream and returns a reference to + the stream, or uses the Q_UINT32-operator if 64 bit is not available. +*/ + +/*! + Writes a signed 64-bit integer to the stream and returns a reference to + the stream, or calls the Q_INT32-operator if 64 bit is not available. +*/ + +QDataStream &QDataStream::operator<<( Q_INT64 i ) +{ + CHECK_STREAM_PRECOND + if ( printable ) { // printable data + char buf[20]; + sprintf( buf, "%ld\n", i ); + dev->writeBlock( buf, strlen(buf) ); + } else if ( noswap ) { // no conversion needed + dev->writeBlock( (char *)&i, sizeof(Q_INT64) ); + } else { // swap bytes + register uchar *p = (uchar *)(&i); + char b[sizeof(Q_INT64)]; + if ( sizeof(Q_INT64) == 8 ) { + b[7] = *p++; + b[6] = *p++; + b[5] = *p++; + b[4] = *p++; + } + b[3] = *p++; + b[2] = *p++; + b[1] = *p++; + b[0] = *p; + dev->writeBlock( b, sizeof(Q_INT64) ); + } + return *this; +} + +/*! + \fn QDataStream &QDataStream::operator<<( uint i ) + Writes an unsigned integer to the stream as a 32-bit unsigned integer + (Q_UINT32). + Returns a reference to the stream. +*/ + +/*! + \fn QDataStream &QDataStream::operator<<( int i ) + Writes a signed integer to the stream as a 32-bit signed integer (Q_INT32). + Returns a reference to the stream. +*/ + + +/*! + Writes a 32-bit floating point number to the stream using the standard + IEEE754 format. Returns a reference to the stream. +*/ + +QDataStream &QDataStream::operator<<( float f ) +{ + CHECK_STREAM_PRECOND + if ( printable ) { // printable data + char buf[32]; + sprintf( buf, "%g\n", (double)f ); + dev->writeBlock( buf, strlen(buf) ); + } else { + float g = f; // fixes float-on-stack problem + if ( noswap ) { // no conversion needed + dev->writeBlock( (char *)&g, sizeof(float) ); + } else { // swap bytes + register uchar *p = (uchar *)(&g); + char b[4]; + b[3] = *p++; + b[2] = *p++; + b[1] = *p++; + b[0] = *p; + dev->writeBlock( b, 4 ); + } + } + return *this; +} + + +/*! + Writes a 64-bit floating point number to the stream using the standard + IEEE754 format. Returns a reference to the stream. +*/ + +QDataStream &QDataStream::operator<<( double f ) +{ + CHECK_STREAM_PRECOND + if ( printable ) { // printable data + char buf[32]; + sprintf( buf, "%g\n", f ); + dev->writeBlock( buf, strlen(buf) ); + } else if ( noswap ) { // no conversion needed + dev->writeBlock( (char *)&f, sizeof(double) ); + } else { // swap bytes + register uchar *p = (uchar *)(&f); + char b[8]; + b[7] = *p++; + b[6] = *p++; + b[5] = *p++; + b[4] = *p++; + b[3] = *p++; + b[2] = *p++; + b[1] = *p++; + b[0] = *p; + dev->writeBlock( b, 8 ); + } + return *this; +} + + +/*! + Writes the '\0'-terminated string \a s to the stream and returns + a reference to the stream. + + The string is serialized using writeBytes(). +*/ + +QDataStream &QDataStream::operator<<( const char *s ) +{ + if ( !s ) { + *this << (Q_UINT32)0; + return *this; + } + uint len = qstrlen( s ) + 1; // also write null terminator + *this << (Q_UINT32)len; // write length specifier + return writeRawBytes( s, len ); +} + + +/*! + Writes the length specifier \a len and the buffer \a s to the stream and + returns a reference to the stream. + + The \a len is serialized as an Q_UINT32, followed by \a len bytes from + \a s. + + \sa writeRawBytes(), readBytes() +*/ + +QDataStream &QDataStream::writeBytes(const char *s, uint len) +{ + CHECK_STREAM_PRECOND + *this << (Q_UINT32)len; // write length specifier + if ( len ) + writeRawBytes( s, len ); + return *this; +} + + +/*! + Writes \a len bytes from \a s to the stream and returns a reference to the + stream. + + \sa writeBytes(), QIODevice::writeBlock(), readRawBytes() +*/ + +QDataStream &QDataStream::writeRawBytes( const char *s, uint len ) +{ + CHECK_STREAM_PRECOND + if ( printable ) { // write printable + register char *p = (char *)s; + while ( len-- ) + *this << *p++; + } else { // write data char array + dev->writeBlock( s, len ); + } + return *this; +} + +#endif // QT_NO_DATASTREAM diff --git a/trunk/qtools/qdatastream.h b/trunk/qtools/qdatastream.h new file mode 100644 index 0000000..3d18062 --- /dev/null +++ b/trunk/qtools/qdatastream.h @@ -0,0 +1,173 @@ +/**************************************************************************** +** +** +** Definition of QDataStream class +** +** Created : 930831 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QDATASTREAM_H +#define QDATASTREAM_H + +#ifndef QT_H +#include "qiodevice.h" +#include "qstring.h" +#endif // QT_H + +#ifndef QT_NO_DATASTREAM +class Q_EXPORT QDataStream // data stream class +{ +public: + QDataStream(); + QDataStream( QIODevice * ); + QDataStream( QByteArray, int mode ); + virtual ~QDataStream(); + + QIODevice *device() const; + void setDevice( QIODevice * ); + void unsetDevice(); + + bool atEnd() const; + bool eof() const; + + enum ByteOrder { BigEndian, LittleEndian }; + int byteOrder() const; + void setByteOrder( int ); + + bool isPrintableData() const; + void setPrintableData( bool ); + + int version() const; + void setVersion( int ); + + QDataStream &operator>>( Q_INT8 &i ); + QDataStream &operator>>( Q_UINT8 &i ); + QDataStream &operator>>( Q_INT16 &i ); + QDataStream &operator>>( Q_UINT16 &i ); + QDataStream &operator>>( Q_INT32 &i ); + QDataStream &operator>>( Q_UINT32 &i ); + QDataStream &operator>>( Q_INT64 &i ); + QDataStream &operator>>( Q_UINT64 &i ); + + QDataStream &operator>>( float &f ); + QDataStream &operator>>( double &f ); + QDataStream &operator>>( char *&str ); + + QDataStream &operator<<( Q_INT8 i ); + QDataStream &operator<<( Q_UINT8 i ); + QDataStream &operator<<( Q_INT16 i ); + QDataStream &operator<<( Q_UINT16 i ); + QDataStream &operator<<( Q_INT32 i ); + QDataStream &operator<<( Q_UINT32 i ); + QDataStream &operator<<( Q_INT64 i ); + QDataStream &operator<<( Q_UINT64 i ); + QDataStream &operator<<( float f ); + QDataStream &operator<<( double f ); + QDataStream &operator<<( const char *str ); + + QDataStream &readBytes( char *&, uint &len ); + QDataStream &readRawBytes( char *, uint len ); + + QDataStream &writeBytes( const char *, uint len ); + QDataStream &writeRawBytes( const char *, uint len ); + +private: + QIODevice *dev; + bool owndev; + int byteorder; + bool printable; + bool noswap; + int ver; + +private: // Disabled copy constructor and operator= +#if defined(Q_DISABLE_COPY) + QDataStream( const QDataStream & ); + QDataStream &operator=( const QDataStream & ); +#endif +}; + + +/***************************************************************************** + QDataStream inline functions + *****************************************************************************/ + +inline QIODevice *QDataStream::device() const +{ return dev; } + +inline bool QDataStream::atEnd() const +{ return dev ? dev->atEnd() : TRUE; } + +inline bool QDataStream::eof() const +{ return atEnd(); } + +inline int QDataStream::byteOrder() const +{ return byteorder; } + +inline bool QDataStream::isPrintableData() const +{ return printable; } + +inline void QDataStream::setPrintableData( bool p ) +{ printable = p; } + +inline int QDataStream::version() const +{ return ver; } + +inline void QDataStream::setVersion( int v ) +{ ver = v; } + +inline QDataStream &QDataStream::operator>>( Q_UINT8 &i ) +{ return *this >> (Q_INT8&)i; } + +inline QDataStream &QDataStream::operator>>( Q_UINT16 &i ) +{ return *this >> (Q_INT16&)i; } + +inline QDataStream &QDataStream::operator>>( Q_UINT32 &i ) +{ return *this >> (Q_INT32&)i; } + +inline QDataStream &QDataStream::operator>>( Q_UINT64 &i ) +{ return *this >> (Q_INT64&)i; } + +inline QDataStream &QDataStream::operator<<( Q_UINT8 i ) +{ return *this << (Q_INT8)i; } + +inline QDataStream &QDataStream::operator<<( Q_UINT16 i ) +{ return *this << (Q_INT16)i; } + +inline QDataStream &QDataStream::operator<<( Q_UINT32 i ) +{ return *this << (Q_INT32)i; } + +inline QDataStream &QDataStream::operator<<( Q_UINT64 i ) +{ return *this << (Q_INT64)i; } + + +#endif // QT_NO_DATASTREAM +#endif // QDATASTREAM_H diff --git a/trunk/qtools/qdatetime.cpp b/trunk/qtools/qdatetime.cpp new file mode 100644 index 0000000..4edaca9 --- /dev/null +++ b/trunk/qtools/qdatetime.cpp @@ -0,0 +1,1434 @@ +/**************************************************************************** +** +** +** Implementation of date and time classes +** +** Created : 940124 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#define gettimeofday __hide_gettimeofday +#include "qdatetime.h" +#include "qdatastream.h" +#include <stdio.h> +#include <time.h> +#if defined(_OS_WIN32_) +#if defined(_CC_BOOL_DEF_) +#undef bool +#include <windows.h> +#define bool int +#else +#include <windows.h> +#endif +#elif defined(_OS_MSDOS_) +#include <dos.h> +#elif defined(_OS_OS2_) +#include <os2.h> +#elif defined(_OS_UNIX_) +#include <sys/time.h> +#include <unistd.h> +#undef gettimeofday +extern "C" int gettimeofday( struct timeval *, struct timezone * ); +#endif + +static const uint FIRST_DAY = 2361222; // Julian day for 1752/09/14 +static const int FIRST_YEAR = 1752; // ### wrong for many countries +static const uint SECS_PER_DAY = 86400; +static const uint MSECS_PER_DAY = 86400000; +static const uint SECS_PER_HOUR = 3600; +static const uint MSECS_PER_HOUR= 3600000; +static const uint SECS_PER_MIN = 60; +static const uint MSECS_PER_MIN = 60000; + +static const short monthDays[] ={0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + +// ##### Localize. + +const char * const QDate::monthNames[] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; + +const char * const QDate::weekdayNames[] ={ + "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" }; + + +/***************************************************************************** + QDate member functions + *****************************************************************************/ + +// REVISED: aavit + +/*! + \class QDate qdatetime.h + \brief The QDate class provides date functions. + + \ingroup time + + A QDate object contains a calendar date, i.e. year, month, and day + numbers in the modern western (Gregorian) calendar. It can read the + current date from the system clock. It provides functions for + comparing dates and for manipulating a date by adding a number of + days. + + A QDate object is typically created either by giving the year, month + and day numbers explicitly, or by using the static function + currentDate(), which makes a QDate object which contains the + system's clock date. An explicit date can also be set using + setYMD(). + + The year(), month(), and day() functions provide access to the year, + month, and day numbers. Also, dayOfWeek() and dayOfYear() functions + are provided. The same information is provided in textual format by + the toString(), dayName(), and monthName() functions. + + QDate provides a full set of operators to compare two QDate + objects. A date is considered smaller than another if it is earlier + than the other. + + The date a given number of days later than a given date can be found + using the addDays() function. Correspondingly, the number of days + between two dates can be found using the daysTo() function. + + The daysInMonth() and daysInYear() functions tell how many days + there are in this date's month and year, respectively. The + isLeapYear() function tells whether this date is in a leap year. + + Note that QDate may not be used for date calculations for dates in + the remote past, i.e. prior to the introduction of the Gregorian + calendar. This calendar was adopted by England Sep. 14. 1752 (hence + this is the earliest valid QDate), and subsequently by most other + western countries, until 1923. + + The end of time is reached around 8000AD, by which time we expect Qt + to be obsolete. + + \sa QTime, QDateTime +*/ + + +/*! + \fn QDate::QDate() + Constructs a null date. Null dates are invalid. + + \sa isNull(), isValid() +*/ + + +/*! + Constructs a date with the year \a y, month \a m and day \a d. + + \a y must be in the range 1752-ca. 8000, \a m must be in the range + 1-12, and \a d must be in the range 1-31. Exception: if \a y is in + the range 0-99, it is interpreted as 1900-1999. + + \sa isValid() +*/ + +QDate::QDate( int y, int m, int d ) +{ + jd = 0; + setYMD( y, m, d ); +} + + +/*! + \fn bool QDate::isNull() const + + Returns TRUE if the date is null. A null date is invalid. + + \sa isValid() +*/ + + +/*! + Returns TRUE if this date is valid. + + \sa isNull() +*/ + +bool QDate::isValid() const +{ + return jd >= FIRST_DAY; +} + + +/*! + Returns the year (>= 1752) of this date. + + \sa month(), day() +*/ + +int QDate::year() const +{ + int y, m, d; + jul2greg( jd, y, m, d ); + return y; +} + +/*! + Returns the month (January=1 .. December=12) of this date. + + \sa year(), day() +*/ + +int QDate::month() const +{ + int y, m, d; + jul2greg( jd, y, m, d ); + return m; +} + +/*! + Returns the day of the month (1..31) of this date. + + \sa year(), month(), dayOfWeek() +*/ + +int QDate::day() const +{ + int y, m, d; + jul2greg( jd, y, m, d ); + return d; +} + +/*! + Returns the weekday (Monday=1 .. Sunday=7) for this date. + + \sa day(), dayOfYear() +*/ + +int QDate::dayOfWeek() const +{ + return (((jd+1) % 7) + 6)%7 + 1; +} + +/*! + Returns the day of the year (1..365) for this date. + + \sa day(), dayOfWeek() +*/ + +int QDate::dayOfYear() const +{ + return jd - greg2jul(year(), 1, 1) + 1; +} + +/*! + Returns the number of days in the month (28..31) for this date. + + \sa day(), daysInYear() +*/ + +int QDate::daysInMonth() const +{ + int y, m, d; + jul2greg( jd, y, m, d ); + if ( m == 2 && leapYear(y) ) + return 29; + else + return monthDays[m]; +} + +/*! + Returns the number of days in the year (365 or 366) for this date. + + \sa day(), daysInMonth() +*/ + +int QDate::daysInYear() const +{ + int y, m, d; + jul2greg( jd, y, m, d ); + return leapYear(y) ? 366 : 365; +} + + +/*! + Returns the name of the \a month. + + Month 1 == "Jan", month 2 == "Feb" etc. + + \sa toString(), dayName() +*/ + +QString QDate::monthName( int month ) const +{ +#if defined(CHECK_RANGE) + if ( month < 1 || month > 12 ) { + qWarning( "QDate::monthName: Parameter out ouf range." ); + month = 1; + } +#endif + // ### Remove the fromLatin1 during localization + return QString::fromLatin1(monthNames[month-1]); +} + +/*! + Returns the name of the \a weekday. + + Weekday 1 == "Mon", day 2 == "Tue" etc. + + \sa toString(), monthName() +*/ + +QString QDate::dayName( int weekday ) const +{ +#if defined(CHECK_RANGE) + if ( weekday < 1 || weekday > 7 ) { + qWarning( "QDate::dayName: Parameter out of range." ); + weekday = 1; + } +#endif + // ### Remove the fromLatin1 during localization + return QString::fromLatin1(weekdayNames[weekday-1]); +} + + +/*! + Returns the date as a string. + + The string format is "Sat May 20 1995". This function uses the + dayName() and monthName() functions to generate the string. + + \sa dayName(), monthName() +*/ + +QString QDate::toString() const +{ + int y, m, d; + jul2greg( jd, y, m, d ); + QString buf = dayName(dayOfWeek()); + buf += ' '; + buf += monthName(m); + QString t; + t.sprintf( " %d %d", d, y); + buf += t; + return buf; +} + + +/*! + Sets the year \a y, month \a m and day \a d. + + \a y must be in the range 1752-ca. 8000, \a m must be in the range + 1-12, and \a d must be in the range 1-31. Exception: if \a y is in + the range 0-99, it is interpreted as 1900-1999. + + Returns TRUE if the date is valid, otherwise FALSE. +*/ + +bool QDate::setYMD( int y, int m, int d ) +{ + if ( !isValid(y,m,d) ) { +#if defined(CHECK_RANGE) + qWarning( "QDate::setYMD: Invalid date %04d/%02d/%02d", y, m, d ); +#endif + return FALSE; + } + jd = greg2jul( y, m, d ); +#if defined(DEBUG) + ASSERT( year() == (y > 99 ? y : 1900+y) && month() == m && day() == d ); +#endif + return TRUE; +} + +/*! + Returns a QDate object containing a date \a ndays later than the + date of this object (or earlier if \a ndays is negative). + + \sa daysTo() +*/ + +QDate QDate::addDays( int ndays ) const +{ + QDate d; + d.jd = jd + ndays; + return d; +} + +/*! + Returns the number of days from this date to \a d (which is negative + if \a d is earlier than this date). + + Example: + \code + QDate d1( 1995, 5, 17 ); // May 17th 1995 + QDate d2( 1995, 5, 20 ); // May 20th 1995 + d1.daysTo( d2 ); // returns 3 + d2.daysTo( d1 ); // returns -3 + \endcode + + \sa addDays() +*/ + +int QDate::daysTo( const QDate &d ) const +{ + return d.jd - jd; +} + + +/*! + \fn bool QDate::operator==( const QDate &d ) const + Returns TRUE if this date is equal to \a d, or FALSE if + they are different. +*/ + +/*! + \fn bool QDate::operator!=( const QDate &d ) const + Returns TRUE if this date is different from \a d, or FALSE if + they are equal. +*/ + +/*! + \fn bool QDate::operator<( const QDate &d ) const + Returns TRUE if this date is earlier than \a d, otherwise FALSE. +*/ + +/*! + \fn bool QDate::operator<=( const QDate &d ) const + Returns TRUE if this date is earlier than or equal to \a d, otherwise FALSE. +*/ + +/*! + \fn bool QDate::operator>( const QDate &d ) const + Returns TRUE if this date is later than \a d, otherwise FALSE. +*/ + +/*! + \fn bool QDate::operator>=( const QDate &d ) const + Returns TRUE if this date is later than or equal to \a d, otherwise FALSE. +*/ + + +/*! + Returns the current date, as reported by the system clock. + + \sa QTime::currentTime(), QDateTime::currentDateTime() +*/ + +QDate QDate::currentDate() +{ +#if defined(_OS_WIN32_) + + SYSTEMTIME t; + GetLocalTime( &t ); + QDate d; + d.jd = greg2jul( t.wYear, t.wMonth, t.wDay ); + return d; + +#else + + time_t ltime; + time( <ime ); + tm *t = localtime( <ime ); + QDate d; + d.jd = greg2jul( t->tm_year + 1900, t->tm_mon + 1, t->tm_mday ); + return d; + +#endif +} + +/*! + Returns TRUE if the specified date (year \a y, month \a m and day \a + d) is valid. + + Example: + \code + QDate::isValid( 2002, 5, 17 ); // TRUE; May 17th 2002 is OK. + QDate::isValid( 2002, 2, 30 ); // FALSE; Feb 30th does not exist + QDate::isValid( 2004, 2, 29 ); // TRUE; 2004 is a leap year + QDate::isValid( 1202, 6, 6 ); // FALSE; 1202 is pre-Gregorian + \endcode + + Note that a \a y value in the range 00-99 is interpreted as + 1900-1999. + + \sa isNull(), setYMD() +*/ + +bool QDate::isValid( int y, int m, int d ) +{ + if ( y >= 0 && y <= 99 ) + y += 1900; + else if ( y < FIRST_YEAR || (y == FIRST_YEAR && (m < 9 || + (m == 9 && d < 14))) ) + return FALSE; + return (d > 0 && m > 0 && m <= 12) && + (d <= monthDays[m] || (d == 29 && m == 2 && leapYear(y))); +} + +/*! + Returns TRUE if the specified year \a y is a leap year. +*/ + +bool QDate::leapYear( int y ) +{ + return (y % 4 == 0 && y % 100 != 0) || (y % 400 == 0); +} + +/*! + \internal + Converts a Gregorian date to a Julian day. + This algorithm is taken from Communications of the ACM, Vol 6, No 8. + \sa jul2greg() +*/ + +uint QDate::greg2jul( int y, int m, int d ) +{ + uint c, ya; + if ( y <= 99 ) + y += 1900; + if ( m > 2 ) { + m -= 3; + } else { + m += 9; + y--; + } + c = y; // NOTE: Sym C++ 6.0 bug + c /= 100; + ya = y - 100*c; + return 1721119 + d + (146097*c)/4 + (1461*ya)/4 + (153*m+2)/5; +} + +/*! + \internal + Converts a Julian day to a Gregorian date. + This algorithm is taken from Communications of the ACM, Vol 6, No 8. + \sa greg2jul() +*/ + +void QDate::jul2greg( uint jd, int &y, int &m, int &d ) +{ + uint x; + uint j = jd - 1721119; + y = (j*4 - 1)/146097; + j = j*4 - 146097*y - 1; + x = j/4; + j = (x*4 + 3) / 1461; + y = 100*y + j; + x = (x*4) + 3 - 1461*j; + x = (x + 4)/4; + m = (5*x - 3)/153; + x = 5*x - 3 - 153*m; + d = (x + 5)/5; + if ( m < 10 ) { + m += 3; + } else { + m -= 9; + y++; + } +} + + +/***************************************************************************** + QTime member functions + *****************************************************************************/ + +/*! + \class QTime qdatetime.h + + \brief The QTime class provides clock time functions. + + \ingroup time + + A QTime object contains a clock time, i.e. a number of hours, + minutes, seconds and milliseconds since midnight. It can read the + current time from the system clock, and measure a span of elapsed + time. It provides functions for comparing times and for manipulating + a time by adding a number of (milli)seconds. + + QTime operates with 24-hour clock format; it has no concept of + AM/PM. It operates with local time; it does not know anything about + time zones or daylight savings time. + + A QTime object is typically created either by giving the number of + hours, minutes, seconds, and milliseconds explicitly, or by using + the static function currentTime(), which makes a QTime object which + contains the system's clock time. Note that the accuracy depends on + the accuracy of the underlying operating system; not all systems + provide 1-millisecond accuracy. + + The hour(), minute(), second(), and msec() functions provide access + to the number of hours, minutes, seconds, and milliseconds of the + time. The same information is provided in textual format by the + toString() function. + + QTime provides a full set of operators to compare two QTime + objects. A time is considered smaller than another if it is earlier + than the other. + + The time a given number of seconds or milliseconds later than a + given time can be found using the addSecs() or addMSecs() + functions. Correspondingly, the number of (milli)seconds between two + times can be found using the secsTo() or msecsTo() functions. + + QTime can be used to measure a span of elapsed time using the + start(), restart(), and elapsed() functions. + + \sa QDate, QDateTime +*/ + +/*! + \fn QTime::QTime() + + Constructs the time 0 hours, minutes, seconds and milliseconds, + i.e. 00:00:00.000 (midnight). This is a valid time. + + \sa isValid() +*/ + +/*! + Constructs a time with hour \a h, minute \a m, seconds \a s and + milliseconds \a ms. + + \a h must be in the range 0-23, \a m and \a s must be in the range + 0-59, and \a ms must be in the range 0-999. + + \sa isValid() +*/ + +QTime::QTime( int h, int m, int s, int ms ) +{ + setHMS( h, m, s, ms ); +} + + +/*! + \fn bool QTime::isNull() const + Returns TRUE if the time is equal to 00:00:00.000. A null time is valid. + + \sa isValid() +*/ + +/*! + Returns TRUE if the time is valid, or FALSE if the time is invalid. + The time 23:30:55.746 is valid, while 24:12:30 is invalid. + + \sa isNull() +*/ + +bool QTime::isValid() const +{ + return ds < MSECS_PER_DAY; +} + + +/*! + Returns the hour part (0..23) of the time. +*/ + +int QTime::hour() const +{ + return ds / MSECS_PER_HOUR; +} + +/*! + Returns the minute part (0..59) of the time. +*/ + +int QTime::minute() const +{ + return (ds % MSECS_PER_HOUR)/MSECS_PER_MIN; +} + +/*! + Returns the second part (0..59) of the time. +*/ + +int QTime::second() const +{ + return (ds / 1000)%SECS_PER_MIN; +} + +/*! + Returns the millisecond part (0..999) of the time. +*/ + +int QTime::msec() const +{ + return ds % 1000; +} + + +/*! + Returns the time of this object in a textual format. Milliseconds + are not included. The string format is HH:MM:SS, e.g. 1 second + before midnight would be "23:59:59". +*/ + +QString QTime::toString() const +{ + QString buf; + buf.sprintf( "%.2d:%.2d:%.2d", hour(), minute(), second() ); + return buf; +} + + +/*! + Sets the time to hour \a h, minute \a m, seconds \a s and + milliseconds \a ms. + + \a h must be in the range 0-23, \a m and \a s must be in the range + 0-59, and \a ms must be in the range 0-999. Returns TRUE if the set + time is valid, otherwise FALSE. + + \sa isValid() +*/ + +bool QTime::setHMS( int h, int m, int s, int ms ) +{ + if ( !isValid(h,m,s,ms) ) { +#if defined(CHECK_RANGE) + qWarning( "QTime::setHMS Invalid time %02d:%02d:%02d.%03d", h, m, s, + ms ); +#endif + ds = MSECS_PER_DAY; // make this invalid + return FALSE; + } + ds = (h*SECS_PER_HOUR + m*SECS_PER_MIN + s)*1000 + ms; + return TRUE; +} + +/*! + Returns a QTime object containing a time \a nsecs seconds later than + the time of this object (or earlier if \a ms is negative). + + Note that the time will wrap if it passes midnight. + + Example: + \code + QTime n( 14, 0, 0 ); // n == 14:00:00 + QTime t; + t = n.addSecs( 70 ); // t == 14:01:10 + t = n.addSecs( -70 ); // t == 13:58:50 + t = n.addSecs( 10*60*60 + 5 ); // t == 00:00:05 + t = n.addSecs( -15*60*60 ); // t == 23:00:00 + \endcode + + \sa addMSecs(), secsTo(), QDateTime::addSecs() +*/ + +QTime QTime::addSecs( int nsecs ) const +{ + return addMSecs(nsecs*1000); +} + +/*! + Returns the number of seconds from this time to \a t (which is + negative if \a t is earlier than this time). + + Since QTime measures time within a day and there are 86400 seconds + in a day, the result is between -86400 and 86400. + + \sa addSecs() QDateTime::secsTo() +*/ + +int QTime::secsTo( const QTime &t ) const +{ + return ((int)t.ds - (int)ds)/1000; +} + +/*! + Returns a QTime object containing a time \a ms milliseconds later than + the time of this object (or earlier if \a ms is negative). + + Note that the time will wrap if it passes midnight. See addSecs() + for an example. + + \sa addSecs(), msecsTo() +*/ + +QTime QTime::addMSecs( int ms ) const +{ + QTime t; + if ( ms < 0 ) { + // % not well-defined for -ve, but / is. + int negdays = (MSECS_PER_DAY-ms) / MSECS_PER_DAY; + t.ds = ((int)ds + ms + negdays*MSECS_PER_DAY) + % MSECS_PER_DAY; + } else { + t.ds = ((int)ds + ms) % MSECS_PER_DAY; + } + return t; +} + +/*! + Returns the number of milliseconds from this time to \a t (which is + negative if \a t is earlier than this time). + + Since QTime measures time within a day and there are 86400000 + milliseconds in a day, the result is between -86400000 and 86400000. + + \sa secsTo() +*/ + +int QTime::msecsTo( const QTime &t ) const +{ + return (int)t.ds - (int)ds; +} + + +/*! + \fn bool QTime::operator==( const QTime &t ) const + + Returns TRUE if this time is equal to \a t, or FALSE if they are + different. +*/ + +/*! + \fn bool QTime::operator!=( const QTime &t ) const + + Returns TRUE if this time is different from \a t, or FALSE if they + are equal. +*/ + +/*! + \fn bool QTime::operator<( const QTime &t ) const + + Returns TRUE if this time is earlier than \a t, otherwise FALSE. +*/ + +/*! + \fn bool QTime::operator<=( const QTime &t ) const + + Returns TRUE if this time is earlier than or equal to \a t, + otherwise FALSE. +*/ + +/*! + \fn bool QTime::operator>( const QTime &t ) const + + Returns TRUE if this time is later than \a t, otherwise FALSE. +*/ + +/*! + \fn bool QTime::operator>=( const QTime &t ) const + + Returns TRUE if this time is later than or equal to \a t, otherwise + FALSE. +*/ + + + +/*! + Returns the current time, as reported by the system clock. + + Note that the accuracy depends on the accuracy of the underlying + operating system; not all systems provide 1-millisecond accuracy. +*/ + +QTime QTime::currentTime() +{ + QTime ct; + currentTime( &ct ); + return ct; +} + +/*! + \internal + + Fetches the current time and returns TRUE if the time is within one + minute after midnight, otherwise FALSE. The return value is used by + QDateTime::currentDateTime() to ensure that the date there is correct. +*/ + +bool QTime::currentTime( QTime *ct ) +{ + if ( !ct ) { +#if defined(CHECK_NULL) + qWarning( "QTime::currentTime(QTime *): Null pointer not allowed" ); +#endif + return FALSE; + } + +#if defined(_OS_WIN32_) + + SYSTEMTIME t; + GetLocalTime( &t ); + ct->ds = MSECS_PER_HOUR*t.wHour + MSECS_PER_MIN*t.wMinute + + 1000*t.wSecond + t.wMilliseconds; + return (t.wHour == 0 && t.wMinute == 0); + +#elif defined(_OS_OS2_) + + DATETIME t; + DosGetDateTime( &t ); + ct->ds = MSECS_PER_HOUR*t.hours + MSECS_PER_MIN*t.minutes + + 1000*t.seconds + 10*t.hundredths; + return (t.hours == 0 && t.minutes == 0); + +#elif defined(_OS_MSDOS_) + + _dostime_t t; + _dos_gettime( &t ); + ct->ds = MSECS_PER_HOUR*t.hour + MSECS_PER_MIN*t.minute + + t.second*1000 + t.hsecond*10; + return (t.hour== 0 && t.minute == 0); + +#elif defined(_OS_UNIX_) + + struct timeval tv; + gettimeofday( &tv, 0 ); + time_t ltime = tv.tv_sec; + tm *t = localtime( <ime ); + ct->ds = (uint)( MSECS_PER_HOUR*t->tm_hour + MSECS_PER_MIN*t->tm_min + + 1000*t->tm_sec + tv.tv_usec/1000 ); + return (t->tm_hour== 0 && t->tm_min == 0); + +#else + + time_t ltime; // no millisecond resolution!! + ::time( <ime ); + tm *t = localtime( <ime ); + ct->ds = MSECS_PER_HOUR*t->tm_hour + MSECS_PER_MIN*t->tm_min + + 1000*t->tm_sec; + return (t->tm_hour== 0 && t->tm_min == 0); +#endif +} + +/*! + Returns TRUE if the specified time is valid, otherwise FALSE. + + The time is valid if \a h is in the range 0-23, \a m and \a s are in + the range 0-59, and \a ms is in the range 0-999. + + Example: + \code + QTime::isValid(21, 10, 30); // returns TRUE + QTime::isValid(22, 5, 62); // returns FALSE + \endcode +*/ + +bool QTime::isValid( int h, int m, int s, int ms ) +{ + return (uint)h < 24 && (uint)m < 60 && (uint)s < 60 && (uint)ms < 1000; +} + + +/*! + Sets this time to the current time. This is practical for timing: + + \code + QTime t; + t.start(); // start clock + ... // some lengthy task + qDebug( "%d\n", t.elapsed() ); // prints # msecs elapsed + \endcode + + \sa restart(), elapsed(), currentTime() +*/ + +void QTime::start() +{ + *this = currentTime(); +} + +/*! + Sets this time to the current time, and returns the number of + milliseconds that have elapsed since the last time start() or + restart() was called. + + This function is guaranteed to be atomic, and is thus very handy for + repeated measurements: call start() to start the first measurement, + then restart() for each later measurement. + + Note that the counter wraps to zero 24 hours after the last call to + start() or restart(). + + \warning If the system's clock setting has been changed since the + last time start() or restart() was called, the result is undefined. + This can happen e.g. when daylight saving is turned on or off. + + \sa start(), elapsed(), currentTime() +*/ + +int QTime::restart() +{ + QTime t = currentTime(); + int n = msecsTo( t ); + if ( n < 0 ) // passed midnight + n += 86400*1000; + *this = t; + return n; +} + +/*! + Returns the number of milliseconds that have elapsed since the last + time start() or restart() was called. + + Note that the counter wraps to zero 24 hours after the last call to + start() or restart. + + Note that the accuracy depends on the accuracy of the underlying + operating system; not all systems provide 1-millisecond accuracy. + + \warning If the system's clock setting has been changed since the + last time start() or restart() was called, the result is undefined. + This can happen e.g. when daylight saving is turned on or off. + + \sa start(), restart() +*/ + +int QTime::elapsed() +{ + int n = msecsTo( currentTime() ); + if ( n < 0 ) // passed midnight + n += 86400*1000; + return n; +} + + +/***************************************************************************** + QDateTime member functions + *****************************************************************************/ + +/*! + \class QDateTime qdatetime.h + \brief The QDateTime class provides date and time functions. + + \ingroup time + + A QDateTime object contains a calendar date and a clock time (a + "datetime"). It is a combination of the QDate and QTime classes. It + can read the current datetime from the system clock. It provides + functions for comparing datetimes and for manipulating a datetime by + adding a number of seconds or days. + + A QDateTime object is typically created either by giving a date and + time explicitly, or by using the static function currentTime(), + which makes a QDateTime object which contains the system's clock + time. + + The date() and time() functions provide access to the date and time + parts of the datetime. The same information is provided in textual + format by the toString() function. + + QDateTime provides a full set of operators to compare two QDateTime + objects. A datetime is considered smaller than another if it is + earlier than the other. + + The datetime a given number of days or seconds later than a given + datetime can be found using the addDays() and addSecs() + functions. Correspondingly, the number of days or seconds between + two times can be found using the daysTo() or secsTo() functions. + + A datetime can also be set using the setTime_t() function, which + takes a POSIX-standard "number of seconds since 00:00:00 on January + 1, 1970" value. + + The limitations regarding range and resolution mentioned in the + QDate and QTime documentation apply for QDateTime also. + + \sa QDate, QTime +*/ + + +/*! + \fn QDateTime::QDateTime() + + Constructs a null datetime (i.e. null date and null time). A null + datetime is invalid, since the date is invalid. + + \sa isValid() +*/ + + +/*! + Constructs a datetime with date \a date and null time (00:00:00.000). +*/ + +QDateTime::QDateTime( const QDate &date ) + : d(date) +{ +} + +/*! + Constructs a datetime with date \a date and time \a time. +*/ + +QDateTime::QDateTime( const QDate &date, const QTime &time ) + : d(date), t(time) +{ +} + + +/*! + \fn bool QDateTime::isNull() const + + Returns TRUE if both the date and the time are null. A null date is invalid. + + \sa QDate::isNull(), QTime::isNull() +*/ + +/*! + \fn bool QDateTime::isValid() const + + Returns TRUE if both the date and the time are valid. + + \sa QDate::isValid(), QTime::isValid() +*/ + +/*! + \fn QDate QDateTime::date() const + + Returns the date part of this datetime. + + \sa setDate(), time() +*/ + +/*! + \fn QTime QDateTime::time() const + + Returns the time part of this datetime. + + \sa setTime(), date() +*/ + +/*! + \fn void QDateTime::setDate( const QDate &date ) + + Sets the date part of this datetime. + + \sa date(), setTime() +*/ + +/*! + \fn void QDateTime::setTime( const QTime &time ) + + Sets the time part of this datetime. + + \sa time(), setDate() +*/ + + +/*! + Sets the local date and time given the number of seconds that have passed + since 00:00:00 on January 1, 1970, Coordinated Universal Time (UTC). + On systems that do not support timezones this function will behave as if + local time were UTC. + + Note that Microsoft Windows supports only a limited range of values for + \a secsSince1Jan1970UTC. +*/ + +void QDateTime::setTime_t( uint secsSince1Jan1970UTC ) +{ + time_t tmp = (time_t) secsSince1Jan1970UTC; + tm *tM = localtime( &tmp ); + if ( !tM ) { + tM = gmtime( &tmp ); + if ( !tM ) { + d.jd = QDate::greg2jul( 1970, 1, 1 ); + t.ds = 0; + return; + } + } + d.jd = QDate::greg2jul( tM->tm_year + 1900, tM->tm_mon + 1, tM->tm_mday ); + t.ds = MSECS_PER_HOUR*tM->tm_hour + MSECS_PER_MIN*tM->tm_min + + 1000*tM->tm_sec; +} + + +/*! + Returns the datetime as a string. + + The string format is "Sat May 20 03:40:13 1998". + + This function uses QDate::dayName(), QDate::monthName(), and + QTime::toString() to generate the string. + +*/ + +QString QDateTime::toString() const +{ + QString buf = d.dayName(d.dayOfWeek()); + buf += ' '; + buf += d.monthName(d.month()); + buf += ' '; + buf += QString().setNum(d.day()); + buf += ' '; + buf += t.toString(); + buf += ' '; + buf += QString().setNum(d.year()); + return buf; +} + +/*! + Returns a QDateTime object containing a datetime \a ndays days later + than the datetime of this object (or earlier if \a ndays is + negative). + + \sa daysTo(), addSecs() +*/ + +QDateTime QDateTime::addDays( int ndays ) const +{ + return QDateTime( d.addDays(ndays), t ); +} + +/*! + Returns a QDateTime object containing a datetime \a nsecs seconds + later than the datetime of this object (or earlier if \a nsecs is + negative). + + \sa secsTo(), addDays() +*/ + +QDateTime QDateTime::addSecs( int nsecs ) const +{ + uint dd = d.jd; + int tt = t.ds; + int sign = 1; + if ( nsecs < 0 ) { + nsecs = -nsecs; + sign = -1; + } + if ( nsecs >= (int)SECS_PER_DAY ) { + dd += sign*(nsecs/SECS_PER_DAY); + nsecs %= SECS_PER_DAY; + } + tt += sign*nsecs*1000; + if ( tt < 0 ) { + tt = MSECS_PER_DAY - tt - 1; + dd -= tt / MSECS_PER_DAY; + tt = tt % MSECS_PER_DAY; + tt = MSECS_PER_DAY - tt - 1; + } else if ( tt >= (int)MSECS_PER_DAY ) { + dd += ( tt / MSECS_PER_DAY ); + tt = tt % MSECS_PER_DAY; + } + QDateTime ret; + ret.t.ds = tt; + ret.d.jd = dd; + return ret; +} + +/*! + Returns the number of days from this datetime to \a dt (which is + negative if \a dt is earlier than this datetime). + + \sa addDays(), secsTo() +*/ + +int QDateTime::daysTo( const QDateTime &dt ) const +{ + return d.daysTo( dt.d ); +} + +/*! + Returns the number of seconds from this datetime to \a dt (which is + negative if \a dt is earlier than this datetime). + + Example: + \code + QDateTime dt = QDateTime::currentDateTime(); + QDateTime x( QDate(dt.year(),12,24), QTime(17,00) ); + qDebug( "There are %d seconds to Christmas", dt.secsTo(x) ); + \endcode + + \sa addSecs(), daysTo(), QTime::secsTo() +*/ + +int QDateTime::secsTo( const QDateTime &dt ) const +{ + return t.secsTo(dt.t) + d.daysTo(dt.d)*SECS_PER_DAY; +} + + +/*! + Returns TRUE if this datetime is equal to \a dt, or FALSE if + they are different. + \sa operator!=() +*/ + +bool QDateTime::operator==( const QDateTime &dt ) const +{ + return t == dt.t && d == dt.d; +} + +/*! + Returns TRUE if this datetime is different from \a dt, or FALSE if + they are equal. + \sa operator==() +*/ + +bool QDateTime::operator!=( const QDateTime &dt ) const +{ + return t != dt.t || d != dt.d; +} + +/*! + Returns TRUE if this datetime is earlier than \a dt, otherwise FALSE. +*/ + +bool QDateTime::operator<( const QDateTime &dt ) const +{ + if ( d < dt.d ) + return TRUE; + return d == dt.d ? t < dt.t : FALSE; +} + +/*! + Returns TRUE if this datetime is earlier than or equal to \a dt, + otherwise FALSE. +*/ + +bool QDateTime::operator<=( const QDateTime &dt ) const +{ + if ( d < dt.d ) + return TRUE; + return d == dt.d ? t <= dt.t : FALSE; +} + +/*! + Returns TRUE if this datetime is later than \a dt, otherwise FALSE. +*/ + +bool QDateTime::operator>( const QDateTime &dt ) const +{ + if ( d > dt.d ) + return TRUE; + return d == dt.d ? t > dt.t : FALSE; +} + +/*! + Returns TRUE if this datetime is later than or equal to \a dt, + otherwise FALSE. +*/ + +bool QDateTime::operator>=( const QDateTime &dt ) const +{ + if ( d > dt.d ) + return TRUE; + return d == dt.d ? t >= dt.t : FALSE; +} + +/*! + Returns the current datetime, as reported by the system clock. + + \sa QDate::currentDate(), QTime::currentTime() +*/ + +QDateTime QDateTime::currentDateTime() +{ + QDate cd = QDate::currentDate(); + QTime ct; + if ( QTime::currentTime(&ct) ) // too close to midnight? + cd = QDate::currentDate(); // YES! time for some midnight + // voodoo, fetch date again + return QDateTime( cd, ct ); +} + + +/***************************************************************************** + Date/time stream functions + *****************************************************************************/ + +#ifndef QT_NO_DATASTREAM +/*! + \relates QDate + Writes the date to the stream. + + \sa \link datastreamformat.html Format of the QDataStream operators \endlink +*/ + +QDataStream &operator<<( QDataStream &s, const QDate &d ) +{ + return s << (Q_UINT32)(d.jd); +} + +/*! + \relates QDate + Reads a date from the stream. + + \sa \link datastreamformat.html Format of the QDataStream operators \endlink +*/ + +QDataStream &operator>>( QDataStream &s, QDate &d ) +{ + Q_UINT32 jd; + s >> jd; + d.jd = jd; + return s; +} + +/*! + \relates QTime + Writes a time to the stream. + + \sa \link datastreamformat.html Format of the QDataStream operators \endlink +*/ + +QDataStream &operator<<( QDataStream &s, const QTime &t ) +{ + return s << (Q_UINT32)(t.ds); +} + +/*! + \relates QTime + Reads a time from the stream. + + \sa \link datastreamformat.html Format of the QDataStream operators \endlink +*/ + +QDataStream &operator>>( QDataStream &s, QTime &t ) +{ + Q_UINT32 ds; + s >> ds; + t.ds = ds; + return s; +} + +/*! + \relates QDateTime + Writes a datetime to the stream. + + \sa \link datastreamformat.html Format of the QDataStream operators \endlink +*/ + +QDataStream &operator<<( QDataStream &s, const QDateTime &dt ) +{ + return s << dt.d << dt.t; +} + +/*! + \relates QDateTime + Reads a datetime from the stream. + + \sa \link datastreamformat.html Format of the QDataStream operators \endlink +*/ + +QDataStream &operator>>( QDataStream &s, QDateTime &dt ) +{ + s >> dt.d >> dt.t; + return s; +} +#endif //QT_NO_DATASTREAM diff --git a/trunk/qtools/qdatetime.h b/trunk/qtools/qdatetime.h new file mode 100644 index 0000000..2d5869c --- /dev/null +++ b/trunk/qtools/qdatetime.h @@ -0,0 +1,216 @@ +/**************************************************************************** +** +** +** Definition of date and time classes +** +** Created : 940124 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QDATETIME_H +#define QDATETIME_H + +#ifndef QT_H +#include "qstring.h" +#endif // QT_H + + +/***************************************************************************** + QDate class + *****************************************************************************/ + +class Q_EXPORT QDate +{ +public: + QDate() { jd=0; } // set null date + QDate( int y, int m, int d ); // set date + virtual ~QDate() {} + + bool isNull() const { return jd == 0; } + bool isValid() const; // valid date + + int year() const; // 1752.. + int month() const; // 1..12 + int day() const; // 1..31 + int dayOfWeek() const; // 1..7 (monday==1) + int dayOfYear() const; // 1..365 + int daysInMonth() const; // 28..31 + int daysInYear() const; // 365 or 366 + + virtual QString monthName( int month ) const; + virtual QString dayName( int weekday ) const; + + QString toString() const; + + bool setYMD( int y, int m, int d ); + + QDate addDays( int days ) const; + int daysTo( const QDate & ) const; + + bool operator==( const QDate &d ) const { return jd == d.jd; } + bool operator!=( const QDate &d ) const { return jd != d.jd; } + bool operator<( const QDate &d ) const { return jd < d.jd; } + bool operator<=( const QDate &d ) const { return jd <= d.jd; } + bool operator>( const QDate &d ) const { return jd > d.jd; } + bool operator>=( const QDate &d ) const { return jd >= d.jd; } + + static QDate currentDate(); + static bool isValid( int y, int m, int d ); + static bool leapYear( int year ); + +protected: + static uint greg2jul( int y, int m, int d ); + static void jul2greg( uint jd, int &y, int &m, int &d ); +private: + static const char * const monthNames[]; + static const char * const weekdayNames[]; + uint jd; + friend class QDateTime; +#ifndef QT_NO_DATASTREAM + friend Q_EXPORT QDataStream &operator<<( QDataStream &, const QDate & ); + friend Q_EXPORT QDataStream &operator>>( QDataStream &, QDate & ); +#endif +}; + + +/***************************************************************************** + QTime class + *****************************************************************************/ + +class Q_EXPORT QTime +{ +public: + QTime() { ds=0; } // set null time + QTime( int h, int m, int s=0, int ms=0 ); // set time + + bool isNull() const { return ds == 0; } + bool isValid() const; // valid time + + int hour() const; // 0..23 + int minute() const; // 0..59 + int second() const; // 0..59 + int msec() const; // 0..999 + + QString toString() const; + + bool setHMS( int h, int m, int s, int ms=0 ); + + QTime addSecs( int secs ) const; + int secsTo( const QTime & ) const; + QTime addMSecs( int ms ) const; + int msecsTo( const QTime & ) const; + + bool operator==( const QTime &d ) const { return ds == d.ds; } + bool operator!=( const QTime &d ) const { return ds != d.ds; } + bool operator<( const QTime &d ) const { return ds < d.ds; } + bool operator<=( const QTime &d ) const { return ds <= d.ds; } + bool operator>( const QTime &d ) const { return ds > d.ds; } + bool operator>=( const QTime &d ) const { return ds >= d.ds; } + + static QTime currentTime(); + static bool isValid( int h, int m, int s, int ms=0 ); + + void start(); + int restart(); + int elapsed(); + +private: + static bool currentTime( QTime * ); + + uint ds; + friend class QDateTime; +#ifndef QT_NO_DATASTREAM + friend Q_EXPORT QDataStream &operator<<( QDataStream &, const QTime & ); + friend Q_EXPORT QDataStream &operator>>( QDataStream &, QTime & ); +#endif +}; + + +/***************************************************************************** + QDateTime class + *****************************************************************************/ + +class Q_EXPORT QDateTime +{ +public: + QDateTime() {} // set null date and null time + QDateTime( const QDate & ); + QDateTime( const QDate &, const QTime & ); + + bool isNull() const { return d.isNull() && t.isNull(); } + bool isValid() const { return d.isValid() && t.isValid(); } + + QDate date() const { return d; } + QTime time() const { return t; } + void setDate( const QDate &date ) { d=date; } + void setTime( const QTime &time ) { t=time; } + void setTime_t( uint secsSince1Jan1970UTC ); + + QString toString() const; + + QDateTime addDays( int days ) const; + QDateTime addSecs( int secs ) const; + int daysTo( const QDateTime & ) const; + int secsTo( const QDateTime & ) const; + + bool operator==( const QDateTime &dt ) const; + bool operator!=( const QDateTime &dt ) const; + bool operator<( const QDateTime &dt ) const; + bool operator<=( const QDateTime &dt ) const; + bool operator>( const QDateTime &dt ) const; + bool operator>=( const QDateTime &dt ) const; + + static QDateTime currentDateTime(); + +private: + QDate d; + QTime t; +#ifndef QT_NO_DATASTREAM + friend Q_EXPORT QDataStream &operator<<( QDataStream &, const QDateTime &); + friend Q_EXPORT QDataStream &operator>>( QDataStream &, QDateTime & ); +#endif +}; + + +/***************************************************************************** + Date and time stream functions + *****************************************************************************/ + +#ifndef QT_NO_DATASTREAM +Q_EXPORT QDataStream &operator<<( QDataStream &, const QDate & ); +Q_EXPORT QDataStream &operator>>( QDataStream &, QDate & ); +Q_EXPORT QDataStream &operator<<( QDataStream &, const QTime & ); +Q_EXPORT QDataStream &operator>>( QDataStream &, QTime & ); +Q_EXPORT QDataStream &operator<<( QDataStream &, const QDateTime & ); +Q_EXPORT QDataStream &operator>>( QDataStream &, QDateTime & ); +#endif // QT_NO_DATASTREAM + +#endif // QDATETIME_H diff --git a/trunk/qtools/qdict.doc b/trunk/qtools/qdict.doc new file mode 100644 index 0000000..d9f6ca5 --- /dev/null +++ b/trunk/qtools/qdict.doc @@ -0,0 +1,492 @@ +/**************************************************************************** +** +** +** QDict and QDictIterator class documentation +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + + +/***************************************************************************** + QDict documentation + *****************************************************************************/ + +/*! + \class QDict qdict.h + \brief The QDict class is a template class that provides a dictionary based on \c QString keys. + + \ingroup collection + \ingroup tools + + QDict is implemented as a template class. Define a template instance + QDict\<X\> to create a dictionary that operates on pointers to X, or X*. + + A dictionary is a collection that associates an item with a key. + The key is used for inserting and looking up an item. QDict has + \l QString keys, which are Unicode strings. If you want to use + non-Unicode, plain 8-bit \c char* keys, use the QAsciiDict template. + A QDict has the same performace as a QAsciiDict. + + The dictionary has very fast insertion and lookup. + + Example: + \code + #include <qdict.h> + #include <stdio.h> + + void main() + { + // Creates a dictionary that maps QString ==> char* (case insensitive) + QDict<char> dict( 17, FALSE ); + + dict.insert( "France", "Paris" ); + dict.insert( "Russia", "Moscow" ); + dict.insert( "Norway", "Oslo" ); + + printf( "%s\n", dict["Norway"] ); + printf( "%s\n", dict["FRANCE"] ); + printf( "%s\n", dict["russia"] ); + + if ( !dict["Italy"] ) + printf( "Italy not defined\n" ); + } + \endcode + + Program output: + \code + Oslo + Paris + Moscow + Italy not defined + \endcode + + The dictionary in our example maps \c QString keys to \c char* items. + Note that the mapping is case insensitive (specified in the + \link QDict::QDict() constructor\endlink). + QDict implements the \link operator[] [] operator\endlink to lookup an item. + + QDict is implemented by QGDict as a hash array with a fixed number of + entries. Each array entry points to a singly linked list of buckets, in + which the dictionary items are stored. + + When an item is inserted with a key, the key is converted (hashed) to + an integer index into the hash array. The item is inserted before the + first bucket in the list of buckets. + + Looking up an item is normally very fast. The key is again hashed to an + array index. Then QDict scans the list of buckets and returns the item + found or null if the item was not found. You cannot insert null pointers + into a dictionary. + + The size of the hash array is very important. In order to get good + performance, you should use a suitably large \link primes.html prime + number\endlink. Suitable means equal to or larger than the maximum + expected number of dictionary items. + + Items with equal keys are allowed. When inserting two items with the + same key, only the last inserted item will be visible (last in, first out) + until it is removed. + + Example: + \code + #include <qdict.h> + #include <stdio.h> + + void main() + { + // Creates a dictionary that maps QString ==> char* (case sensitive) + QDict<char> dict; + + dict.insert( "Germany", "Berlin" ); + dict.insert( "Germany", "Bonn" ); + + printf( "%s\n", dict["Germany"] ); + dict.remove( "Germany" ); // Oct 3rd 1990 + printf( "%s\n", dict["Germany"] ); + } + \endcode + + Program output: + \code + Bonn + Berlin + \endcode + + The QDictIterator class can traverse the dictionary contents, but only + in an arbitrary order. Multiple iterators may independently traverse the + same dictionary. + + Calling setAutoDelete(TRUE) for a dictionary tells it to delete items + that are removed . The default is to not delete items when they are + removed. + + When inserting an item into a dictionary, only the pointer is copied, not + the item itself. This is called a shallow copy. It is possible to make the + dictionary copy all of the item's data (known as a deep copy) when an + item is inserted. insert() calls the virtual function + QCollection::newItem() for the item to be inserted. + Inherit a dictionary and reimplement it if you want deep copies. + + When removing a dictionary item, the virtual function + QCollection::deleteItem() is called. QDict's default implementation + is to delete the item if auto-deletion is enabled. + + \sa QDictIterator, QAsciiDict, QIntDict, QPtrDict, + \link collection.html Collection Classes\endlink +*/ + + +/*! + \fn QDict::QDict( int size, bool caseSensitive ) + Constructs a dictionary with the following properties: + \arg \e size is the size of the internal hash array. + \arg \e caseSensitive specifies whether to use case sensitive lookup or not. + + Setting \e size to a suitably large \link primes.html prime + number\endlink (equal to or greater than the expected number of entries) + makes the hash distribution better and hence the loopup faster. + + Setting \e caseSensitive to TRUE will treat "abc" and "Abc" as different + keys. Setting it to FALSE will make the dictionary ignore case. + Case insensitive comparison includes the whole Unicode alphabeth. +*/ + +/*! + \fn QDict::QDict( const QDict<type> &dict ) + Constructs a copy of \e dict. + + Each item in \e dict are inserted into this dictionary. + Only the pointers are copied (shallow copy). +*/ + +/*! + \fn QDict::~QDict() + Removes all items from the dictionary and destroys it. + All iterators that access this dictionary will be reset. + + \sa setAutoDelete() +*/ + +/*! + \fn QDict<type> &QDict::operator=(const QDict<type> &dict) + Assigns \e dict to this dictionary and returns a reference to this + dictionary. + + This dictionary is first cleared, then each item in \e dict is inserted + into this dictionary. + Only the pointers are copied (shallow copy), unless newItem() has been + reimplemented(). +*/ + +/*! + \fn uint QDict::count() const + Returns the number of items in the dictionary. + \sa isEmpty() +*/ + +/*! + \fn uint QDict::size() const + Returns the size of the internal hash array (as specified in the + constructor). + \sa count() +*/ + +/*! + \fn void QDict::resize( uint newsize ) + Changes the size of the hashtable the \a newsize. + The contents of the dictionary are preserved, + but all iterators on the dictionary become invalid. +*/ + +/*! + \fn bool QDict::isEmpty() const + Returns TRUE if the dictionary is empty, i.e. count() == 0. Returns FALSE + otherwise. + \sa count() +*/ + +/*! + \fn void QDict::insert( const QString &key, const type *item ) + + Inserts the \e key with the \e item into the dictionary. + + The key does not have to be a unique dictionary key. If multiple items + are inserted with the same key, only the last item will be visible. + + Null items are not allowed. + + \sa replace() +*/ + +/*! + \fn void QDict::replace( const QString &key, const type *item ) + + Replaces an item which has a key equal to \e key with \e item. + + If the item does not already exist, it will be inserted. + + Null items are not allowed. + + Equivalent to: + \code + QDict<char> dict; + ... + if ( dict.find(key) ) + dict.remove( key ); + dict.insert( key, item ); + \endcode + + If there are two or more items with equal keys, then the last inserted + of these will be replaced. + + \sa insert() +*/ + +/*! + \fn bool QDict::remove( const QString &key ) + + Removes the item associated with \e key from the dictionary. + Returns TRUE if successful, or FALSE if the key does not exist in the + dictionary. + + If there are two or more items with equal keys, then the last inserted + of these will be removed. + + The removed item is deleted if \link QCollection::setAutoDelete() + auto-deletion\endlink is enabled. + + All dictionary iterators that refer to the removed item will be set to + point to the next item in the dictionary traversing order. + + \sa take(), clear(), setAutoDelete() +*/ + +/*! + \fn type *QDict::take( const QString &key ) + + Takes the item associated with \e key out of the dictionary without + deleting it (even if \link QCollection::setAutoDelete() + auto-deletion\endlink is enabled). + + If there are two or more items with equal keys, then the last inserted + of these will be taken. + + Returns a pointer to the item taken out, or null if the key does not + exist in the dictionary. + + All dictionary iterators that refer to the taken item will be set to + point to the next item in the dictionary traversal order. + + \sa remove(), clear(), setAutoDelete() +*/ + +/*! + \fn void QDict::clear() + + Removes all items from the dictionary. + + The removed items are deleted if \link QCollection::setAutoDelete() + auto-deletion\endlink is enabled. + + All dictionary iterators that operate on dictionary are reset. + + \sa remove(), take(), setAutoDelete() +*/ + +/*! + \fn type *QDict::find( const QString &key ) const + + Returns the item associated with \e key, or null if the key does not + exist in the dictionary. + + This function uses an internal hashing algorithm to optimize lookup. + + If there are two or more items with equal keys, then the last inserted + of these will be found. + + Equivalent to the [] operator. + + \sa operator[]() +*/ + +/*! + \fn type *QDict::operator[]( const QString &key ) const + + Returns the item associated with \e key, or null if the key does not + exist in the dictionary. + + This function uses an internal hashing algorithm to optimize lookup. + + If there are two or more items with equal keys, then the last inserted + of these will be found. + + Equivalent to the find() function. + + \sa find() +*/ + +/*! + \fn void QDict::statistics() const + Debugging-only function that prints out the dictionary distribution + using qDebug(). +*/ + + +/***************************************************************************** + QDictIterator documentation + *****************************************************************************/ + +/*! + \class QDictIterator qdict.h + \brief The QDictIterator class provides an iterator for QDict collections. + + \ingroup collection + \ingroup tools + + QDictIterator is implemented as a template class. + Define a template instance QDictIterator\<X\> to create a + dictionary iterator that operates on QDict\<X\> (dictionary of X*). + + Example: + \code + #include <qdict.h> + #include <stdio.h> + + void main() + { + // Creates a dictionary that maps QString ==> char* (case insensitive) + QDict<char> dict( 17, FALSE ); + + dict.insert( "France", "Paris" ); + dict.insert( "Russia", "Moscow" ); + dict.insert( "Norway", "Oslo" ); + + QDictIterator<char> it( dict ); // iterator for dict + + while ( it.current() ) { + printf( "%s -> %s\n", it.currentKey().latin1(), it.current() ); + ++it; + } + } + \endcode + + Program output: + \code + Russia -> Moscow + Norway -> Oslo + France -> Paris + \endcode + + Note that the traversal order is arbitrary, you are not guaranteed the + order above. + + Multiple iterators may independently traverse the same dictionary. + A QDict knows about all iterators that are operating on the dictionary. + When an item is removed from the dictionary, QDict update all iterators + that are referring the removed item to point to the next item in the + traversing order. + + \sa QDict, \link collection.html Collection Classes\endlink +*/ + +/*! + \fn QDictIterator::QDictIterator( const QDict<type> &dict ) + Constructs an iterator for \e dict. The current iterator item is + set to point on the first item in the \e dict. +*/ + +/*! + \fn QDictIterator::~QDictIterator() + Destroys the iterator. +*/ + +/*! + \fn uint QDictIterator::count() const + Returns the number of items in the dictionary this iterator operates on. + \sa isEmpty() +*/ + +/*! + \fn bool QDictIterator::isEmpty() const + Returns TRUE if the dictionary is empty, i.e. count() == 0, otherwise FALSE. + \sa count() +*/ + +/*! + \fn type *QDictIterator::toFirst() + Sets the current iterator item to point to the first item in the + dictionary and returns a pointer to the item. + If the dictionary is empty it sets the current item to null and + returns null. +*/ + +/*! + \fn QDictIterator::operator type *() const + Cast operator. Returns a pointer to the current iterator item. + Same as current(). +*/ + +/*! + \fn type *QDictIterator::current() const + Returns a pointer to the current iterator item. +*/ + +/*! + \fn QString QDictIterator::currentKey() const + Returns a pointer to the key for the current iterator item. +*/ + +/*! + \fn type *QDictIterator::operator()() + Makes the succeeding item current and returns the original current item. + + If the current iterator item was the last item in the dictionary or if it + was null, null is returned. +*/ + +/*! + \fn type *QDictIterator::operator++() + Prefix ++ makes the succeeding item current and returns the new current + item. + + If the current iterator item was the last item in the dictionary or if it + was null, null is returned. +*/ + +/*! + \fn type *QDictIterator::operator+=( uint jump ) + Sets the current item to the item \e jump positions after the current item, + and returns a pointer to that item. + + If that item is beyond the last item or if the dictionary is empty, + it sets the current item to null and returns null. +*/ + + diff --git a/trunk/qtools/qdict.h b/trunk/qtools/qdict.h new file mode 100644 index 0000000..682b270 --- /dev/null +++ b/trunk/qtools/qdict.h @@ -0,0 +1,116 @@ +/**************************************************************************** +** +** +** Definition of QDict template class +** +** Created : 920821 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QDICT_H +#define QDICT_H + +#ifndef QT_H +#include "qgdict.h" +#endif // QT_H + +#define USE_ASCII_STRING + +#ifdef USE_ASCII_STRING + +#define QAsciiDict QDict +#define QAsciiDictIterator QDictIterator +#include "qasciidict.h" + +#else + +template<class type> class Q_EXPORT QDict : public QGDict +{ +public: + QDict(int size=17, bool caseSensitive=TRUE) + : QGDict(size,StringKey,caseSensitive,FALSE) {} + QDict( const QDict<type> &d ) : QGDict(d) {} + ~QDict() { clear(); } + QDict<type> &operator=(const QDict<type> &d) + { return (QDict<type>&)QGDict::operator=(d); } + uint count() const { return QGDict::count(); } + uint size() const { return QGDict::size(); } + bool isEmpty() const { return QGDict::count() == 0; } + + void insert( const QString &k, const type *d ) + { QGDict::look_string(k,(Item)d,1); } + void replace( const QString &k, const type *d ) + { QGDict::look_string(k,(Item)d,2); } + bool remove( const QString &k ) { return QGDict::remove_string(k); } + type *take( const QString &k ) { return (type *)QGDict::take_string(k); } + type *find( const QString &k ) const + { return (type *)((QGDict*)this)->QGDict::look_string(k,0,0); } + type *operator[]( const QString &k ) const + { return (type *)((QGDict*)this)->QGDict::look_string(k,0,0); } + + void clear() { QGDict::clear(); } + void resize( uint n ) { QGDict::resize(n); } + void statistics() const { QGDict::statistics(); } +private: + void deleteItem( Item d ); +}; + +#if defined(Q_DELETING_VOID_UNDEFINED) +template<> inline void QDict<void>::deleteItem( Item ) +{ +} +#endif + +template<class type> inline void QDict<type>::deleteItem( QCollection::Item d ) +{ + if ( del_item ) delete (type *)d; +} + + +template<class type> class Q_EXPORT QDictIterator : public QGDictIterator +{ +public: + QDictIterator(const QDict<type> &d) :QGDictIterator((QGDict &)d) {} + ~QDictIterator() {} + uint count() const { return dict->count(); } + bool isEmpty() const { return dict->count() == 0; } + type *toFirst() { return (type *)QGDictIterator::toFirst(); } + operator type *() const { return (type *)QGDictIterator::get(); } + type *current() const { return (type *)QGDictIterator::get(); } + QString currentKey() const{ return QGDictIterator::getKeyString(); } + type *operator()() { return (type *)QGDictIterator::operator()(); } + type *operator++() { return (type *)QGDictIterator::operator++(); } + type *operator+=(uint j) { return (type *)QGDictIterator::operator+=(j);} +}; + +#endif // USE_ASCII_STRING + +#endif // QDICT_H diff --git a/trunk/qtools/qdir.cpp b/trunk/qtools/qdir.cpp new file mode 100644 index 0000000..d0c1233 --- /dev/null +++ b/trunk/qtools/qdir.cpp @@ -0,0 +1,1200 @@ +/**************************************************************************** +** +** +** Implementation of QDir class +** +** Created : 950427 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "qglobal.h" + +#include "qdir.h" + +#ifndef QT_NO_DIR +#include "qfileinfo.h" +#include "qfiledefs_p.h" +#include "qregexp.h" +#include "qstringlist.h" +#include <stdlib.h> +#include <ctype.h> + +// NOT REVISED +/*! + \class QDir qdir.h + \brief Traverses directory structures and contents in a + platform-independent way. + + \ingroup io + + A QDir can point to a file using either a relative or an absolute file + path. Absolute file paths begin with the directory separator ('/') or a + drive specification (not applicable to UNIX). Relative file names begin + with a directory name or a file name and specify a path relative to the + current directory. + + An example of an absolute path is the string "/tmp/quartz", a relative + path might look like "src/fatlib". You can use the function isRelative() + to check if a QDir is using a relative or an absolute file path. You can + call the function convertToAbs() to convert a relative QDir to an + absolute one. + + The directory "example" under the current directory is checked for existence + in the example below: + + \code + QDir d( "example" ); // "./example" + if ( !d.exists() ) + qWarning( "Cannot find the example directory" ); + \endcode + + If you always use '/' as a directory separator, Qt will translate your + paths to conform to the underlying operating system. + + cd() and cdUp() can be used to navigate the directory tree. Note that the + logical cd and cdUp operations are not performed if the new directory does + not exist. + + Example: + \code + QDir d = QDir::root(); // "/" + if ( !d.cd("tmp") ) { // "/tmp" + qWarning( "Cannot find the \"/tmp\" directory" ); + } else { + QFile f( d.filePath("ex1.txt") ); // "/tmp/ex1.txt" + if ( !f.open(IO_ReadWrite) ) + qWarning( "Cannot create the file %s", f.name() ); + } + \endcode + + To read the contents of a directory you can use the entryList() and + entryInfoList() functions. + + Example: + \code + #include <stdio.h> + #include <qdir.h> + + // + // This program scans the current directory and lists all files + // that are not symbolic links, sorted by size with the smallest files + // first. + // + + int main( int argc, char **argv ) + { + QDir d; + d.setFilter( QDir::Files | QDir::Hidden | QDir::NoSymLinks ); + d.setSorting( QDir::Size | QDir::Reversed ); + + const QFileInfoList *list = d.entryInfoList(); + QFileInfoListIterator it( *list ); // create list iterator + QFileInfo *fi; // pointer for traversing + + printf( " BYTES FILENAME\n" ); // print header + while ( (fi=it.current()) ) { // for each file... + printf( "%10li %s\n", fi->size(), fi->fileName().data() ); + ++it; // goto next list element + } + } + \endcode +*/ + + +/*! + Constructs a QDir pointing to the current directory. + \sa currentDirPath() +*/ + +QDir::QDir() +{ + dPath = QString::fromLatin1("."); + init(); +} + +/*! + Constructs a QDir. + + \arg \e path is the directory. + \arg \e nameFilter is the file name filter. + \arg \e sortSpec is the sort specification, which describes how to + sort the files in the directory. + \arg \e filterSpec is the filter specification, which describes how + to filter the files in the directory. + + Most of these arguments (except \e path) have optional values. + + Example: + \code + // lists all files in /tmp + + QDir d( "/tmp" ); + for ( int i=0; i<d.count(); i++ ) + printf( "%s\n", d[i] ); + \endcode + + If \e path is "" or null, the directory is set to "." (the current + directory). If \e nameFilter is "" or null, it is set to "*" (all + files). + + No check is made to ensure that the directory exists. + + \sa exists(), setPath(), setNameFilter(), setFilter(), setSorting() +*/ + +QDir::QDir( const QString &path, const QString &nameFilter, + int sortSpec, int filterSpec ) +{ + init(); + dPath = cleanDirPath( path ); + if ( dPath.isEmpty() ) + dPath = QString::fromLatin1("."); + nameFilt = nameFilter; + if ( nameFilt.isEmpty() ) + nameFilt = QString::fromLatin1("*"); + filtS = (FilterSpec)filterSpec; + sortS = (SortSpec)sortSpec; +} + +/*! + Constructs a QDir that is a copy of the given directory. + \sa operator=() +*/ + +QDir::QDir( const QDir &d ) +{ + dPath = d.dPath; + fList = 0; + fiList = 0; + nameFilt = d.nameFilt; + dirty = TRUE; + allDirs = d.allDirs; + filtS = d.filtS; + sortS = d.sortS; +} + + +void QDir::init() +{ + fList = 0; + fiList = 0; + nameFilt = QString::fromLatin1("*"); + dirty = TRUE; + allDirs = FALSE; + filtS = All; + sortS = SortSpec(Name | IgnoreCase); +} + +/*! + Destructs the QDir and cleans up. +*/ + +QDir::~QDir() +{ + if ( fList ) + delete fList; + if ( fiList ) + delete fiList; +} + + +/*! + Sets the path of the directory. The path is cleaned of redundant ".", ".." + and multiple separators. No check is made to ensure that a directory + with this path exists. + + The path can be either absolute or relative. Absolute paths begin with the + directory separator ('/') or a drive specification (not + applicable to UNIX). + Relative file names begin with a directory name or a file name and specify + a path relative to the current directory. An example of + an absolute path is the string "/tmp/quartz", a relative path might look like + "src/fatlib". You can use the function isRelative() to check if a QDir + is using a relative or an absolute file path. You can call the function + convertToAbs() to convert a relative QDir to an absolute one. + + \sa path(), absPath(), exists(), cleanDirPath(), dirName(), + absFilePath(), isRelative(), convertToAbs() +*/ + +void QDir::setPath( const QString &path ) +{ + dPath = cleanDirPath( path ); + if ( dPath.isEmpty() ) + dPath = QString::fromLatin1("."); + dirty = TRUE; +} + +/*! + \fn QString QDir::path() const + Returns the path, this may contain symbolic links, but never contains + redundant ".", ".." or multiple separators. + + The returned path can be either absolute or relative (see setPath()). + + \sa setPath(), absPath(), exists(), cleanDirPath(), dirName(), + absFilePath(), convertSeparators() +*/ + +/*! + Returns the absolute (a path that starts with '/') path, which may + contain symbolic links, but never contains redundant ".", ".." or + multiple separators. + + \sa setPath(), canonicalPath(), exists(), cleanDirPath(), dirName(), + absFilePath() +*/ + +QString QDir::absPath() const +{ + if ( QDir::isRelativePath(dPath) ) { + QString tmp = currentDirPath(); + if ( tmp.right(1) != QString::fromLatin1("/") ) + tmp += '/'; + tmp += dPath; + return cleanDirPath( tmp ); + } else { + return cleanDirPath( dPath ); + } +} + +/*! + Returns the name of the directory, this is NOT the same as the path, e.g. + a directory with the name "mail", might have the path "/var/spool/mail". + If the directory has no name (e.g. the root directory) a null string is + returned. + + No check is made to ensure that a directory with this name actually exists. + + \sa path(), absPath(), absFilePath(), exists(), QString::isNull() +*/ + +QString QDir::dirName() const +{ + int pos = dPath.findRev( '/' ); + if ( pos == -1 ) + return dPath; + return dPath.right( dPath.length() - pos - 1 ); +} + +/*! + Returns the path name of a file in the directory. Does NOT check if + the file actually exists in the directory. If the QDir is relative + the returned path name will also be relative. Redundant multiple separators + or "." and ".." directories in \e fileName will not be removed (see + cleanDirPath()). + + If \e acceptAbsPath is TRUE a \e fileName starting with a separator + ('/') will be returned without change. + If \e acceptAbsPath is FALSE an absolute path will be appended to + the directory path. + + \sa absFilePath(), isRelative(), canonicalPath() +*/ + +QString QDir::filePath( const QString &fileName, + bool acceptAbsPath ) const +{ + if ( acceptAbsPath && !isRelativePath(fileName) ) + return QString(fileName); + + QString tmp = dPath; + if ( tmp.isEmpty() || (tmp[(int)tmp.length()-1] != '/' && !!fileName && + fileName[0] != '/') ) + tmp += '/'; + tmp += fileName; + return tmp; +} + +/*! + Returns the absolute path name of a file in the directory. Does NOT check if + the file actually exists in the directory. Redundant multiple separators + or "." and ".." directories in \e fileName will NOT be removed (see + cleanDirPath()). + + If \e acceptAbsPath is TRUE a \e fileName starting with a separator + ('/') will be returned without change. + if \e acceptAbsPath is FALSE an absolute path will be appended to + the directory path. + + \sa filePath() +*/ + +QString QDir::absFilePath( const QString &fileName, + bool acceptAbsPath ) const +{ + if ( acceptAbsPath && !isRelativePath( fileName ) ) + return fileName; + + QString tmp = absPath(); + if ( tmp.isEmpty() || (tmp[(int)tmp.length()-1] != '/' && !!fileName && + fileName[0] != '/') ) + tmp += '/'; + tmp += fileName; + return tmp; +} + + +/*! + Converts the '/' separators in \a pathName to system native + separators. Returns the translated string. + + On Windows, convertSeparators("c:/winnt/system32") returns + "c:\winnt\system32". + + No conversion is done on UNIX. +*/ + +QString QDir::convertSeparators( const QString &pathName ) +{ + QString n( pathName ); +#if defined(_OS_FATFS_) || defined(_OS_OS2EMX_) + for ( int i=0; i<(int)n.length(); i++ ) { + if ( n[i] == '/' ) + n[i] = '\\'; + } +#endif + return n; +} + + +/*! + Changes directory by descending into the given directory. Returns + TRUE if the new directory exists and is readable. Note that the logical + cd operation is NOT performed if the new directory does not exist. + + If \e acceptAbsPath is TRUE a path starting with a separator ('/') + will cd to the absolute directory, if \e acceptAbsPath is FALSE + any number of separators at the beginning of \e dirName will be removed. + + Example: + \code + QDir d = QDir::home(); // now points to home directory + if ( !d.cd("c++") ) { // now points to "c++" under home directory if OK + QFileInfo fi( d, "c++" ); + if ( fi.exists() ) { + if ( fi.isDir() ) + qWarning( "Cannot cd into \"%s\".", (char*)d.absFilePath("c++") ); + else + qWarning( "Cannot create directory \"%s\"\n" + "A file named \"c++\" already exists in \"%s\"", + (const char *)d.absFilePath("c++"), + (const char *)d.path() ); + return; + } else { + qWarning( "Creating directory \"%s\"", + (const char *) d.absFilePath("c++") ); + if ( !d.mkdir( "c++" ) ) { + qWarning("Could not create directory \"%s\"", + (const char *)d.absFilePath("c++") ); + return; + } + } + } + \endcode + + Calling cd( ".." ) is equivalent to calling cdUp(). + + \sa cdUp(), isReadable(), exists(), path() +*/ + +bool QDir::cd( const QString &dirName, bool acceptAbsPath ) +{ + if ( dirName.isEmpty() || dirName==QString::fromLatin1(".") ) + return TRUE; + QString old = dPath; + if ( acceptAbsPath && !isRelativePath(dirName) ) { + dPath = cleanDirPath( dirName ); + } else { + if ( !isRoot() ) + dPath += '/'; + dPath += dirName; + if ( dirName.find('/') >= 0 + || old == QString::fromLatin1(".") + || dirName == QString::fromLatin1("..") ) + dPath = cleanDirPath( dPath ); + } + if ( !exists() ) { + dPath = old; // regret + return FALSE; + } + dirty = TRUE; + return TRUE; +} + +/*! + Changes directory by moving one directory up the path followed to arrive + at the current directory. + + Returns TRUE if the new directory exists and is readable. Note that the + logical cdUp() operation is not performed if the new directory does not + exist. + + \sa cd(), isReadable(), exists(), path() +*/ + +bool QDir::cdUp() +{ + return cd( QString::fromLatin1("..") ); +} + +/*! + \fn QString QDir::nameFilter() const + Returns the string set by setNameFilter() +*/ + +/*! + Sets the name filter used by entryList() and entryInfoList(). + + The name filter is a wildcarding filter that understands "*" and "?" + wildcards, You may specify several filter entries separated by a " " or a ";". If + you want entryList() and entryInfoList() to list all files ending with + ".cpp" and all files ending with ".h", you simply call + dir.setNameFilter("*.cpp *.h") or dir.setNameFilter("*.cpp;*.h") + + \sa nameFilter(), setFilter() +*/ + +void QDir::setNameFilter( const QString &nameFilter ) +{ + nameFilt = nameFilter; + if ( nameFilt.isEmpty() ) + nameFilt = QString::fromLatin1("*"); + dirty = TRUE; +} + +/*! + \fn QDir::FilterSpec QDir::filter() const + Returns the value set by setFilter() +*/ + +/*! \enum QDir::FilterSpec + + This enum describes how QDir is to select what entries in a + directory to return. The filter value is specified by or-ing + together values from the following list: <ul> + + <li> \c Dirs - List directories only + <li> \c Files - List files only + + <li> \c Drives - List disk drives (does nothing under unix) + <li> \c NoSymLinks - Do not list symbolic links (where they exist) + <li> \c Readable - List files for which the application has read access. + <li> \c Writable - List files for which the application has write access. + <li> \c Executable - List files for which the application has execute access + <li> \c Modified - Only list files that have been modified (does nothing + under unix) + <li> \c Hidden - List hidden files (on unix, files starting with a .) + <li> \c System - List system files (does nothing under unix) + </ul> + + If you do not set any of \c Readable, \c Writable or \c Executable, + QDir will set all three of them. This makes the default easy to + write and at the same time useful. + + Examples: \c Readable|Writable means list all files for which the + application has read access, write access or both. \c Dirs|Drives + means list drives, directories, all files that the application can + read, write or execute, and also symlinks to such files/directories. +*/ + + +/*! + Sets the filter used by entryList() and entryInfoList(). The filter is used + to specify the kind of files that should be returned by entryList() and + entryInfoList(). + + \sa filter(), setNameFilter() +*/ + +void QDir::setFilter( int filterSpec ) +{ + if ( filtS == (FilterSpec) filterSpec ) + return; + filtS = (FilterSpec) filterSpec; + dirty = TRUE; +} + +/*! + \fn QDir::SortSpec QDir::sorting() const + + Returns the value set by setSorting() + + \sa setSorting() +*/ + +/*! \enum QDir::SortSpec + + This enum describes how QDir is to sort entries in a directory when + it returns a list of them. The sort value is specified by or-ing + together values from the following list: <ul> + + <li> \c Name - sort by name + <li> \c Time - sort by time (modification time) + <li> \c Size - sort by file size + <li> \c Unsorted - do not sort + + <li> \c DirsFirst - put all directories first in the list + <li> \c Reversed - reverse the sort order + <li> \c IgnoreCase - sort case-insensitively + + </ul> + + You can only specify one of the first four. If you specify both \c + DirsFirst and \c Reversed, directories are still put first but the + list is otherwise reversed. +*/ + +// ### Unsorted+DirsFirst ? Unsorted+Reversed? + +/*! + Sets the sorting order used by entryList() and entryInfoList(). + + The \e sortSpec is specified by or-ing values from the enum + SortSpec. The different values are: + + One of these: + <dl compact> + <dt>Name<dd> Sort by name (alphabetical order). + <dt>Time<dd> Sort by time (most recent first). + <dt>Size<dd> Sort by size (largest first). + <dt>Unsorted<dd> Use the operating system order (UNIX does NOT sort + alphabetically). + + ORed with zero or more of these: + + <dt>DirsFirst<dd> Always put directory names first. + <dt>Reversed<dd> Reverse sort order. + <dt>IgnoreCase<dd> Ignore case when sorting by name. + </dl> +*/ + +void QDir::setSorting( int sortSpec ) +{ + if ( sortS == (SortSpec) sortSpec ) + return; + sortS = (SortSpec) sortSpec; + dirty = TRUE; +} + +/*! + \fn bool QDir::matchAllDirs() const + Returns the value set by setMatchAllDirs() + + \sa setMatchAllDirs() +*/ + +/*! + If \e enable is TRUE, all directories will be listed (even if they do not + match the filter or the name filter), otherwise only matched directories + will be listed. + + \bug Currently, directories that do not match the filter will not be + included (the name filter will be ignored as expected). + + \sa matchAllDirs() +*/ + +void QDir::setMatchAllDirs( bool enable ) +{ + if ( (bool)allDirs == enable ) + return; + allDirs = enable; + dirty = TRUE; +} + + +/*! + Returns the number of files that was found. + Equivalent to entryList().count(). + \sa operator[](), entryList() +*/ + +uint QDir::count() const +{ + return entryList().count(); +} + +/*! + Returns the file name at position \e index in the list of found file + names. + Equivalent to entryList().at(index). + + Returns null if the \e index is out of range or if the entryList() + function failed. + + \sa count(), entryList() +*/ + +QString QDir::operator[]( int index ) const +{ + entryList(); + return fList && index >= 0 && index < (int)fList->count() ? + (*fList)[index] : QString::null; +} + + +/*! + This function is included to easy porting from Qt 1.x to Qt 2.0, + it is the same as entryList(), but encodes the filenames as 8-bit + strings using QFile::encodedName(). + + It is more efficient to use entryList(). +*/ +QStrList QDir::encodedEntryList( int filterSpec, int sortSpec ) const +{ + QStrList r; + QStringList l = entryList(filterSpec,sortSpec); + for ( QStringList::Iterator it = l.begin(); it != l.end(); ++it ) { + r.append( QFile::encodeName(*it) ); + } + return r; +} + +/*! + This function is included to easy porting from Qt 1.x to Qt 2.0, + it is the same as entryList(), but encodes the filenames as 8-bit + strings using QFile::encodedName(). + + It is more efficient to use entryList(). +*/ +QStrList QDir::encodedEntryList( const QString &nameFilter, + int filterSpec, + int sortSpec ) const +{ + QStrList r; + QStringList l = entryList(nameFilter,filterSpec,sortSpec); + for ( QStringList::Iterator it = l.begin(); it != l.end(); ++it ) { + r.append( QFile::encodeName(*it) ); + } + return r; +} + + + +/*! + Returns a list of the names of all files and directories in the directory + indicated by the setSorting(), setFilter() and setNameFilter() + specifications. + + The the filter and sorting specifications can be overridden using the + \e filterSpec and \e sortSpec arguments. + + Returns an empty list if the directory is unreadable or does not exist. + + \sa entryInfoList(), setNameFilter(), setSorting(), setFilter(), + encodedEntryList() +*/ + +QStringList QDir::entryList( int filterSpec, int sortSpec ) const +{ + if ( !dirty && filterSpec == (int)DefaultFilter && + sortSpec == (int)DefaultSort ) + return *fList; + return entryList( nameFilt, filterSpec, sortSpec ); +} + +/*! + Returns a list of the names of all files and directories in the directory + indicated by the setSorting(), setFilter() and setNameFilter() + specifications. + + The the filter and sorting specifications can be overridden using the + \e nameFilter, \e filterSpec and \e sortSpec arguments. + + Returns and empty list if the directory is unreadable or does not exist. + + \sa entryInfoList(), setNameFilter(), setSorting(), setFilter(), + encodedEntryList() +*/ + +QStringList QDir::entryList( const QString &nameFilter, + int filterSpec, int sortSpec ) const +{ + if ( filterSpec == (int)DefaultFilter ) + filterSpec = filtS; + if ( sortSpec == (int)DefaultSort ) + sortSpec = sortS; + QDir *that = (QDir*)this; // mutable function + if ( that->readDirEntries(nameFilter, filterSpec, sortSpec) ) + return *that->fList; + else + return QStringList(); +} + +/*! + Returns a list of QFileInfo objects for all files and directories in + the directory pointed to using the setSorting(), setFilter() and + setNameFilter() specifications. + + The the filter and sorting specifications can be overridden using the + \e filterSpec and \e sortSpec arguments. + + Returns 0 if the directory is unreadable or does not exist. + + The returned pointer is a const pointer to a QFileInfoList. The list is + owned by the QDir object and will be reused on the next call to + entryInfoList() for the same QDir instance. If you want to keep the + entries of the list after a subsequent call to this function you will + need to copy them. + + \sa entryList(), setNameFilter(), setSorting(), setFilter() +*/ + +const QFileInfoList *QDir::entryInfoList( int filterSpec, int sortSpec ) const +{ + if ( !dirty && filterSpec == (int)DefaultFilter && + sortSpec == (int)DefaultSort ) + return fiList; + return entryInfoList( nameFilt, filterSpec, sortSpec ); +} + +/*! + Returns a list of QFileInfo objects for all files and directories in + the directory pointed to using the setSorting(), setFilter() and + setNameFilter() specifications. + + The the filter and sorting specifications can be overridden using the + \e nameFilter, \e filterSpec and \e sortSpec arguments. + + Returns 0 if the directory is unreadable or does not exist. + + The returned pointer is a const pointer to a QFileInfoList. The list is + owned by the QDir object and will be reused on the next call to + entryInfoList() for the same QDir instance. If you want to keep the + entries of the list after a subsequent call to this function you will + need to copy them. + + \sa entryList(), setNameFilter(), setSorting(), setFilter() +*/ + +const QFileInfoList *QDir::entryInfoList( const QString &nameFilter, + int filterSpec, int sortSpec ) const +{ + if ( filterSpec == (int)DefaultFilter ) + filterSpec = filtS; + if ( sortSpec == (int)DefaultSort ) + sortSpec = sortS; + QDir *that = (QDir*)this; // mutable function + if ( that->readDirEntries(nameFilter, filterSpec, sortSpec) ) + return that->fiList; + else + return 0; +} + +/*! + Returns TRUE if the directory exists. (If a file with the same + name is found this function will of course return FALSE). + + \sa QFileInfo::exists(), QFile::exists() +*/ + +bool QDir::exists() const +{ + QFileInfo fi( dPath ); + return fi.exists() && fi.isDir(); +} + +/*! + Returns TRUE if the directory path is relative to the current directory, + FALSE if the path is absolute (e.g. under UNIX a path is relative if it + does not start with a '/'). + + According to Einstein this function should always return TRUE. + + \sa convertToAbs() +*/ + +bool QDir::isRelative() const +{ + return isRelativePath( dPath ); +} + +/*! + Converts the directory path to an absolute path. If it is already + absolute nothing is done. + + \sa isRelative() +*/ + +void QDir::convertToAbs() +{ + dPath = absPath(); +} + +/*! + Makes a copy of d and assigns it to this QDir. +*/ + +QDir &QDir::operator=( const QDir &d ) +{ + dPath = d.dPath; + delete fList; + fList = 0; + delete fiList; + fiList = 0; + nameFilt = d.nameFilt; + dirty = TRUE; + allDirs = d.allDirs; + filtS = d.filtS; + sortS = d.sortS; + return *this; +} + +/*! + Sets the directory path to be the given path. +*/ + +QDir &QDir::operator=( const QString &path ) +{ + dPath = cleanDirPath( path ); + dirty = TRUE; + return *this; +} + + +/*! + \fn bool QDir::operator!=( const QDir &d ) const + Returns TRUE if the \e d and this dir have different path or + different sort/filter settings, otherwise FALSE. +*/ + +/*! + Returns TRUE if the \e d and this dir have the same path and all sort + and filter settings are equal, otherwise FALSE. +*/ + +bool QDir::operator==( const QDir &d ) const +{ + return dPath == d.dPath && + nameFilt == d.nameFilt && + allDirs == d.allDirs && + filtS == d.filtS && + sortS == d.sortS; +} + + +/*! + Removes a file. + + If \e acceptAbsPath is TRUE a path starting with a separator ('/') + will remove the file with the absolute path, if \e acceptAbsPath is FALSE + any number of separators at the beginning of \e fileName will be removed. + + Returns TRUE if successful, otherwise FALSE. +*/ + +bool QDir::remove( const QString &fileName, bool acceptAbsPath ) +{ + if ( fileName.isEmpty() ) { +#if defined(CHECK_NULL) + qWarning( "QDir::remove: Empty or null file name" ); +#endif + return FALSE; + } + QString p = filePath( fileName, acceptAbsPath ); + return QFile::remove( p ); +} + +/*! + Checks for existence of a file. + + If \e acceptAbsPaths is TRUE a path starting with a separator ('/') + will check the file with the absolute path, if \e acceptAbsPath is FALSE + any number of separators at the beginning of \e name will be removed. + + Returns TRUE if the file exists, otherwise FALSE. + + \sa QFileInfo::exists(), QFile::exists() +*/ + +bool QDir::exists( const QString &name, bool acceptAbsPath ) +{ + if ( name.isEmpty() ) { +#if defined(CHECK_NULL) + qWarning( "QDir::exists: Empty or null file name" ); +#endif + return FALSE; + } + QString tmp = filePath( name, acceptAbsPath ); + return QFile::exists( tmp ); +} + +/*! + Returns the native directory separator; '/' under UNIX and '\' under + MS-DOS, Windows NT and OS/2. + + You do not need to use this function to build file paths. If you always + use '/', Qt will translate your paths to conform to the underlying + operating system. +*/ + +char QDir::separator() +{ +#if defined(_OS_UNIX_) + return '/'; +#elif defined (_OS_FATFS_) + return '\\'; +#elif defined (_OS_MAC_) + return ':'; +#else + return '/'; +#endif +} + +/*! + Returns the current directory. + \sa currentDirPath(), QDir::QDir() +*/ + +QDir QDir::current() +{ + return QDir( currentDirPath() ); +} + +/*! + Returns the home directory. + \sa homeDirPath() +*/ + +QDir QDir::home() +{ + return QDir( homeDirPath() ); +} + +/*! + Returns the root directory. + \sa rootDirPath() drives() +*/ + +QDir QDir::root() +{ + return QDir( rootDirPath() ); +} + +/*! + \fn QString QDir::homeDirPath() + + Returns the absolute path for the user's home directory, + \sa home() +*/ + +QStringList qt_makeFilterList( const QString &filter ) +{ + if ( filter.isEmpty() ) + return QStringList(); + + QChar sep( ';' ); + int i = filter.find( sep, 0 ); + if ( i == -1 && filter.find( ' ', 0 ) != -1 ) + sep = QChar( ' ' ); + + QStringList lst = QStringList::split( sep, filter ); + QStringList lst2; + QStringList::Iterator it = lst.begin(); + + for ( ; it != lst.end(); ++it ) { + QString s = *it; + lst2 << s.stripWhiteSpace(); + } + return lst2; +} + +/*! + Returns TRUE if the \e fileName matches one of the wildcards in the list \e filters. + \sa QRegExp +*/ + +bool QDir::match( const QStringList &filters, const QString &fileName ) +{ + QStringList::ConstIterator sit = filters.begin(); + bool matched = FALSE; + for ( ; sit != filters.end(); ++sit ) { + QRegExp regexp( (*sit).data(), FALSE, TRUE ); + if ( regexp.match( fileName.data() ) != -1 ) { + matched = TRUE; + break; + } + } + + return matched; +} + +/*! + Returns TRUE if the \e fileName matches the wildcard \e filter. + \a Filter may also contain multiple wildcards separated by spaces or + semicolons. + \sa QRegExp +*/ + +bool QDir::match( const QString &filter, const QString &fileName ) +{ + QStringList lst = qt_makeFilterList( filter ); + return match( lst, fileName ); +} + + +/*! + Removes all multiple directory separators ('/') and resolves + any "." or ".." found in the path. + + Symbolic links are kept. This function does not return the + canonical path, but rather the most simplified version of the input. + "../stuff" becomes "stuff", "stuff/../nonsense" becomes "nonsense" + and "\\stuff\\more\\..\\nonsense" becomes "\\stuff\\nonsense". + + \sa absPath() canonicalPath() +*/ + +QString QDir::cleanDirPath( const QString &filePath ) +{ + QString name = filePath; + QString newPath; + + if ( name.isEmpty() ) + return name; + + slashify( name ); + + bool addedSeparator; + if ( isRelativePath(name) ) { + addedSeparator = TRUE; + name.insert( 0, '/' ); + } else { + addedSeparator = FALSE; + } + + int ePos, pos, upLevel; + + pos = ePos = name.length(); + upLevel = 0; + int len; + + while ( pos && (pos = name.findRev('/',--pos)) != -1 ) { + len = ePos - pos - 1; + if ( len == 2 && name.at(pos + 1) == '.' + && name.at(pos + 2) == '.' ) { + upLevel++; + } else { + if ( len != 0 && (len != 1 || name.at(pos + 1) != '.') ) { + if ( !upLevel ) + newPath = QString::fromLatin1("/") + + name.mid(pos + 1, len) + newPath; + else + upLevel--; + } + } + ePos = pos; + } + if ( addedSeparator ) { + while ( upLevel-- ) + newPath.insert( 0, QString::fromLatin1("/..") ); + if ( !newPath.isEmpty() ) + newPath.remove( 0, 1 ); + else + newPath = QString::fromLatin1("."); + } else { + if ( newPath.isEmpty() ) + newPath = QString::fromLatin1("/"); +#if defined(_OS_FATFS_) || defined(_OS_OS2EMX_) + if ( name[0] == '/' ) { + if ( name[1] == '/' ) // "\\machine\x\ ..." + newPath.insert( 0, '/' ); + } else { + newPath = name.left(2) + newPath; + } +#endif + } + return newPath; +} + +int qt_cmp_si_sortSpec; + +#if defined(Q_C_CALLBACKS) +extern "C" { +#endif + +int qt_cmp_si( const void *n1, const void *n2 ) +{ + if ( !n1 || !n2 ) + return 0; + + QDirSortItem* f1 = (QDirSortItem*)n1; + QDirSortItem* f2 = (QDirSortItem*)n2; + + if ( qt_cmp_si_sortSpec & QDir::DirsFirst ) + if ( f1->item->isDir() != f2->item->isDir() ) + return f1->item->isDir() ? -1 : 1; + + int r = 0; + int sortBy = qt_cmp_si_sortSpec & QDir::SortByMask; + + switch ( sortBy ) { + case QDir::Time: + r = f1->item->lastModified().secsTo(f2->item->lastModified()); + break; + case QDir::Size: + r = f2->item->size() - f1->item->size(); + break; + default: + ; + } + + if ( r == 0 && sortBy != QDir::Unsorted ) { + // Still not sorted - sort by name + bool ic = qt_cmp_si_sortSpec & QDir::IgnoreCase; + + if ( f1->filename_cache.isNull() ) + f1->filename_cache = ic ? f1->item->fileName().lower() + : f1->item->fileName(); + if ( f2->filename_cache.isNull() ) + f2->filename_cache = ic ? f2->item->fileName().lower() + : f2->item->fileName(); + + r = f1->filename_cache.compare(f2->filename_cache); + } + + if ( r == 0 ) { + // Enforce an order - the order the items appear in the array + r = (char*)n1 - (char*)n2; + } + + if ( qt_cmp_si_sortSpec & QDir::Reversed ) + return -r; + else + return r; +} + +#if defined(Q_C_CALLBACKS) +} +#endif + +#endif // QT_NO_DIR diff --git a/trunk/qtools/qdir.h b/trunk/qtools/qdir.h new file mode 100644 index 0000000..dd74271 --- /dev/null +++ b/trunk/qtools/qdir.h @@ -0,0 +1,235 @@ +/**************************************************************************** +** +** +** Definition of QDir class +** +** Created : 950427 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QDIR_H +#define QDIR_H + +#ifndef QT_H +#include "qstrlist.h" +#include "qfileinfo.h" +#endif // QT_H + +#ifndef QT_NO_DIR +typedef QList<QFileInfo> QFileInfoList; +typedef QListIterator<QFileInfo> QFileInfoListIterator; +class QStringList; + + +class Q_EXPORT QDir +{ +public: + enum FilterSpec { Dirs = 0x001, + Files = 0x002, + Drives = 0x004, + NoSymLinks = 0x008, + All = 0x007, + TypeMask = 0x00F, + + Readable = 0x010, + Writable = 0x020, + Executable = 0x040, + RWEMask = 0x070, + + Modified = 0x080, + Hidden = 0x100, + System = 0x200, + AccessMask = 0x3F0, + + DefaultFilter = -1 }; + + enum SortSpec { Name = 0x00, + Time = 0x01, + Size = 0x02, + Unsorted = 0x03, + SortByMask = 0x03, + + DirsFirst = 0x04, + Reversed = 0x08, + IgnoreCase = 0x10, + DefaultSort = -1 }; + + QDir(); + QDir( const QString &path, const QString &nameFilter = QString::null, + int sortSpec = Name | IgnoreCase, int filterSpec = All ); + QDir( const QDir & ); + + virtual ~QDir(); + + QDir &operator=( const QDir & ); + QDir &operator=( const QString &path ); + + virtual void setPath( const QString &path ); + virtual QString path() const; + virtual QString absPath() const; + virtual QString canonicalPath() const; + + virtual QString dirName() const; + virtual QString filePath( const QString &fileName, + bool acceptAbsPath = TRUE ) const; + virtual QString absFilePath( const QString &fileName, + bool acceptAbsPath = TRUE ) const; + + static QString convertSeparators( const QString &pathName ); + + virtual bool cd( const QString &dirName, bool acceptAbsPath = TRUE ); + virtual bool cdUp(); + + QString nameFilter() const; + virtual void setNameFilter( const QString &nameFilter ); + FilterSpec filter() const; + virtual void setFilter( int filterSpec ); + SortSpec sorting() const; + virtual void setSorting( int sortSpec ); + + bool matchAllDirs() const; + virtual void setMatchAllDirs( bool ); + + uint count() const; + QString operator[]( int ) const; + + virtual QStrList encodedEntryList( int filterSpec = DefaultFilter, + int sortSpec = DefaultSort ) const; + virtual QStrList encodedEntryList( const QString &nameFilter, + int filterSpec = DefaultFilter, + int sortSpec = DefaultSort ) const; + virtual QStringList entryList( int filterSpec = DefaultFilter, + int sortSpec = DefaultSort ) const; + virtual QStringList entryList( const QString &nameFilter, + int filterSpec = DefaultFilter, + int sortSpec = DefaultSort ) const; + + virtual const QFileInfoList *entryInfoList( int filterSpec = DefaultFilter, + int sortSpec = DefaultSort ) const; + virtual const QFileInfoList *entryInfoList( const QString &nameFilter, + int filterSpec = DefaultFilter, + int sortSpec = DefaultSort ) const; + + static const QFileInfoList *drives(); + + virtual bool mkdir( const QString &dirName, + bool acceptAbsPath = TRUE ) const; + virtual bool rmdir( const QString &dirName, + bool acceptAbsPath = TRUE ) const; + + virtual bool isReadable() const; + virtual bool exists() const; + virtual bool isRoot() const; + + virtual bool isRelative() const; + virtual void convertToAbs(); + + virtual bool operator==( const QDir & ) const; + virtual bool operator!=( const QDir & ) const; + + virtual bool remove( const QString &fileName, + bool acceptAbsPath = TRUE ); + virtual bool rename( const QString &name, const QString &newName, + bool acceptAbsPaths = TRUE ); + virtual bool exists( const QString &name, + bool acceptAbsPath = TRUE ); + + static char separator(); + + static bool setCurrent( const QString &path ); + static QDir current(); + static QDir home(); + static QDir root(); + static QString currentDirPath(); + static QString homeDirPath(); + static QString rootDirPath(); + + static bool match( const QStringList &filters, const QString &fileName ); + static bool match( const QString &filter, const QString &fileName ); + static QString cleanDirPath( const QString &dirPath ); + static bool isRelativePath( const QString &path ); + +private: + void init(); + virtual bool readDirEntries( const QString &nameFilter, + int FilterSpec, int SortSpec ); + + static void slashify ( QString &); + + QString dPath; + QStringList *fList; + QFileInfoList *fiList; + QString nameFilt; + FilterSpec filtS; + SortSpec sortS; + uint dirty : 1; + uint allDirs : 1; +}; + + +inline QString QDir::path() const +{ + return dPath; +} + +inline QString QDir::nameFilter() const +{ + return nameFilt; +} + +inline QDir::FilterSpec QDir::filter() const +{ + return filtS; +} + +inline QDir::SortSpec QDir::sorting() const +{ + return sortS; +} + +inline bool QDir::matchAllDirs() const +{ + return allDirs; +} + +inline bool QDir::operator!=( const QDir &d ) const +{ + return !(*this == d); +} + + +struct QDirSortItem { + QString filename_cache; + QFileInfo* item; +}; + +#endif // QT_NO_DIR +#endif // QDIR_H diff --git a/trunk/qtools/qdir_unix.cpp b/trunk/qtools/qdir_unix.cpp new file mode 100644 index 0000000..e845043 --- /dev/null +++ b/trunk/qtools/qdir_unix.cpp @@ -0,0 +1,288 @@ +/**************************************************************************** +** +** +** Implementation of QDirclass +** +** Created : 950628 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses for Unix/X11 or for Qt/Embedded may use this file in accordance +** with the Qt Commercial License Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "qglobal.h" + +#include "qdir.h" +#ifndef QT_NO_DIR + +#include "qfileinfo.h" +#include "qfiledefs_p.h" +#include "qregexp.h" +#include "qstringlist.h" +#include <stdlib.h> +#include <ctype.h> + +extern QStringList qt_makeFilterList( const QString &filter ); + +extern int qt_cmp_si_sortSpec; + +#if defined(Q_C_CALLBACKS) +extern "C" { +#endif + +extern int qt_cmp_si( const void *, const void * ); + +#if defined(Q_C_CALLBACKS) +} +#endif + + +void QDir::slashify( QString& ) +{ +} + +QString QDir::homeDirPath() +{ + QString d; + d = QFile::decodeName(getenv("HOME")); + slashify( d ); + if ( d.isNull() ) + d = rootDirPath(); + return d; +} + +QString QDir::canonicalPath() const +{ + QString r; + + char cur[PATH_MAX]; + char tmp[PATH_MAX]; + (void)GETCWD( cur, PATH_MAX ); + if ( CHDIR(QFile::encodeName(dPath)) >= 0 ) { + (void)GETCWD( tmp, PATH_MAX ); + r = QFile::decodeName(tmp); + } + (void)CHDIR( cur ); + + slashify( r ); + return r; +} + +bool QDir::mkdir( const QString &dirName, bool acceptAbsPath ) const +{ + return MKDIR( QFile::encodeName(filePath(dirName,acceptAbsPath)), 0777 ) + == 0; +} + +bool QDir::rmdir( const QString &dirName, bool acceptAbsPath ) const +{ + return RMDIR( QFile::encodeName(filePath(dirName,acceptAbsPath)) ) == 0; +} + +bool QDir::isReadable() const +{ + return ACCESS( QFile::encodeName(dPath), R_OK | X_OK ) == 0; +} + +bool QDir::isRoot() const +{ + return dPath == QString::fromLatin1("/"); +} + +bool QDir::rename( const QString &name, const QString &newName, + bool acceptAbsPaths ) +{ + if ( name.isEmpty() || newName.isEmpty() ) { +#if defined(CHECK_NULL) + qWarning( "QDir::rename: Empty or null file name(s)" ); +#endif + return FALSE; + } + QString fn1 = filePath( name, acceptAbsPaths ); + QString fn2 = filePath( newName, acceptAbsPaths ); + return ::rename( QFile::encodeName(fn1), + QFile::encodeName(fn2) ) == 0; +} + +bool QDir::setCurrent( const QString &path ) +{ + int r; + r = CHDIR( QFile::encodeName(path) ); + return r >= 0; +} + +QString QDir::currentDirPath() +{ + QString result; + + STATBUF st; + if ( STAT( ".", &st ) == 0 ) { + char currentName[PATH_MAX]; + if ( GETCWD( currentName, PATH_MAX ) != 0 ) + result = QFile::decodeName(currentName); +#if defined(DEBUG) + if ( result.isNull() ) + qWarning( "QDir::currentDirPath: getcwd() failed" ); +#endif + } else { +#if defined(DEBUG) + qWarning( "QDir::currentDirPath: stat(\".\") failed" ); +#endif + } + slashify( result ); + return result; +} + +QString QDir::rootDirPath() +{ + QString d = QString::fromLatin1( "/" ); + return d; +} + +bool QDir::isRelativePath( const QString &path ) +{ + int len = path.length(); + if ( len == 0 ) + return TRUE; + return path[0] != '/'; +} + +bool QDir::readDirEntries( const QString &nameFilter, + int filterSpec, int sortSpec ) +{ + int i; + if ( !fList ) { + fList = new QStringList; + CHECK_PTR( fList ); + fiList = new QFileInfoList; + CHECK_PTR( fiList ); + fiList->setAutoDelete( TRUE ); + } else { + fList->clear(); + fiList->clear(); + } + + QStringList filters = qt_makeFilterList( nameFilter ); + + bool doDirs = (filterSpec & Dirs) != 0; + bool doFiles = (filterSpec & Files) != 0; + bool noSymLinks = (filterSpec & NoSymLinks) != 0; + bool doReadable = (filterSpec & Readable) != 0; + bool doWritable = (filterSpec & Writable) != 0; + bool doExecable = (filterSpec & Executable) != 0; + bool doHidden = (filterSpec & Hidden) != 0; + +#if defined(_OS_OS2EMX_) + //QRegExp wc( nameFilter, FALSE, TRUE ); // wild card, case insensitive +#else + //QRegExp wc( nameFilter, TRUE, TRUE ); // wild card, case sensitive +#endif + QFileInfo fi; + DIR *dir; + dirent *file; + + dir = opendir( QFile::encodeName(dPath) ); + if ( !dir ) { +#if defined(CHECK_NULL) + qWarning( "QDir::readDirEntries: Cannot read the directory: %s", + QFile::encodeName(dPath).data() ); +#endif + return FALSE; + } + + while ( (file = readdir(dir)) ) { + QString fn = QFile::decodeName(file->d_name); + fi.setFile( *this, fn ); + if ( !match( filters, fn ) && !(allDirs && fi.isDir()) ) + continue; + if ( (doDirs && fi.isDir()) || (doFiles && fi.isFile()) ) { + if ( noSymLinks && fi.isSymLink() ) + continue; + if ( (filterSpec & RWEMask) != 0 ) + if ( (doReadable && !fi.isReadable()) || + (doWritable && !fi.isWritable()) || + (doExecable && !fi.isExecutable()) ) + continue; + if ( !doHidden && fn[0] == '.' && + fn != QString::fromLatin1(".") + && fn != QString::fromLatin1("..") ) + continue; + fiList->append( new QFileInfo( fi ) ); + } + } + if ( closedir(dir) != 0 ) { +#if defined(CHECK_NULL) + qWarning( "QDir::readDirEntries: Cannot close the directory: %s", + dPath.local8Bit().data() ); +#endif + } + + // Sort... + if(fiList->count()) { + QDirSortItem* si= new QDirSortItem[fiList->count()]; + QFileInfo* itm; + i=0; + for (itm = fiList->first(); itm; itm = fiList->next()) + si[i++].item = itm; + qt_cmp_si_sortSpec = sortSpec; + qsort( si, i, sizeof(si[0]), qt_cmp_si ); + // put them back in the list + fiList->setAutoDelete( FALSE ); + fiList->clear(); + int j; + for ( j=0; j<i; j++ ) { + fiList->append( si[j].item ); + fList->append( si[j].item->fileName() ); + } + delete [] si; + fiList->setAutoDelete( TRUE ); + } + + if ( filterSpec == (FilterSpec)filtS && sortSpec == (SortSpec)sortS && + nameFilter == nameFilt ) + dirty = FALSE; + else + dirty = TRUE; + return TRUE; +} + +const QFileInfoList * QDir::drives() +{ + // at most one instance of QFileInfoList is leaked, and this variable + // points to that list + static QFileInfoList * knownMemoryLeak = 0; + + if ( !knownMemoryLeak ) { + knownMemoryLeak = new QFileInfoList; + // non-win32 versions both use just one root directory + knownMemoryLeak->append( new QFileInfo( rootDirPath() ) ); + } + + return knownMemoryLeak; +} +#endif //QT_NO_DIR diff --git a/trunk/qtools/qdir_win32.cpp b/trunk/qtools/qdir_win32.cpp new file mode 100644 index 0000000..f1515a1 --- /dev/null +++ b/trunk/qtools/qdir_win32.cpp @@ -0,0 +1,485 @@ +/****************************************************************************** + * + * + * + * 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. + * + * Based on qdir_unix.cpp + * + * Copyright (C) 1992-2000 Trolltech AS. + */ + + +#include "qglobal.h" + +#include "qdir.h" +#ifndef QT_NO_DIR + + +#include "qfileinfo.h" +#include "qfiledefs_p.h" +#include "qregexp.h" +#include "qstringlist.h" +#include <stdlib.h> +#include <ctype.h> +#if defined(_OS_WIN32_) +#if defined(_CC_BOOL_DEF_) +#undef bool +#include <windows.h> +#define bool int +#else +#include <windows.h> +#endif +#endif +#if defined(_OS_OS2EMX_) +extern Q_UINT32 DosQueryCurrentDisk(Q_UINT32*,Q_UINT32*); +#define NO_ERROR 0 +#endif + +extern QStringList qt_makeFilterList( const QString &filter ); + +extern int qt_cmp_si_sortSpec; + +#if defined(Q_C_CALLBACKS) +extern "C" { +#endif + +extern int qt_cmp_si( const void *, const void * ); + +#if defined(Q_C_CALLBACKS) +} +#endif + +static QString p_getenv( QString name ) +{ + DWORD len = GetEnvironmentVariableW( ( LPCWSTR ) qt_winTchar ( name, TRUE ), NULL, 0 ); + if ( len == 0 ) + return QString::null; + /* ansi: we allocate too much memory, but this shouldn't be the problem here ... */ + LPWSTR buf = (LPWSTR)new WCHAR[ len ]; + len = GetEnvironmentVariableW ( ( LPCWSTR ) qt_winTchar ( name, TRUE ), buf, len ); + if ( len == 0 ) + { + delete[] buf; + return QString::null; + } + QString ret = qt_winQString ( buf ); + delete[] buf; + return ret; +} + + +void QDir::slashify( QString& n ) +{ + for ( int i=0; i<(int)n.length(); i++ ) + { + if ( n[i] == '\\' ) + n[i] = '/'; + } +} + +QString QDir::homeDirPath() +{ + QString d = p_getenv ( "HOME" ); + if ( d.isNull () ) { + d = p_getenv ( "USERPROFILE" ); + if ( d.isNull () ) { + QString homeDrive = p_getenv ( "HOMEDRIVE" ); + QString homePath = p_getenv ( "HOMEPATH" ); + if ( !homeDrive.isNull () && !homePath.isNull () ) { + d = homeDrive + homePath; + } else { + d = rootDirPath (); + } + } + } + slashify( d ); + return d; +} + +QString QDir::canonicalPath() const +{ + QString r; + + char cur[PATH_MAX]; + char tmp[PATH_MAX]; + GETCWD( cur, PATH_MAX ); + if ( CHDIR(QFile::encodeName(dPath)) >= 0 ) { + GETCWD( tmp, PATH_MAX ); + r = QFile::decodeName(tmp); + } + CHDIR( cur ); + + slashify( r ); + return r; +} + +bool QDir::mkdir( const QString &dirName, bool acceptAbsPath ) const +{ +#if defined(__CYGWIN32_) + return MKDIR( QFile::encodeName(filePath(dirName,acceptAbsPath)), 0777 ) == 0; +#else + return _wmkdir( ( LPCWSTR ) filePath( dirName, acceptAbsPath ).ucs2() ) == 0; +#endif +} + +bool QDir::rmdir( const QString &dirName, bool acceptAbsPath ) const +{ +#if defined(__CYGWIN32_) + return RMDIR( QFile::encodeName(filePath(dirName,acceptAbsPath)) ) == 0; +#else + return _wrmdir( ( LPCWSTR ) filePath( dirName, acceptAbsPath ).ucs2() ) == 0; +#endif +} + +bool QDir::isReadable() const +{ + QString path = dPath; + if ( ( path[ 0 ] == '\\' ) || ( path[ 0 ] == '/' ) ) + path = rootDirPath() + path; +#if defined(__CYGWIN32_) + return ACCESS( QFile::encodeName(dPath), R_OK ) == 0; +#else + return ( _waccess( (wchar_t*) path.ucs2(), R_OK ) == 0 ); +#endif +} + +bool QDir::isRoot() const +{ + QString path = dPath; + slashify( path ); + return path == rootDirPath (); +} + +bool QDir::rename( const QString &name, const QString &newName, + bool acceptAbsPaths ) +{ + if ( name.isEmpty() || newName.isEmpty() ) { +#if defined(CHECK_NULL) + qWarning( "QDir::rename: Empty or null file name(s)" ); +#endif + return FALSE; + } + QString fn1 = filePath( name, acceptAbsPaths ); + QString fn2 = filePath( newName, acceptAbsPaths ); +#if defined(__CYGWIN32_) + return ::rename( QFile::encodeName(fn1), + QFile::encodeName(fn2) ) == 0; +#else + return MoveFileW( ( LPCWSTR ) fn1.ucs2(), ( LPCWSTR ) fn2.ucs2() ) != 0; +#endif +} + +bool QDir::setCurrent( const QString &path ) +{ +#if defined(__CYGWIN32_) + int r; + r = CHDIR( QFile::encodeName(path) ); + return r >= 0; +#else + if ( !QDir( path ).exists() ) + return false; + return ( SetCurrentDirectoryW( ( LPCWSTR ) path.ucs2() ) >= 0 ); +#endif +} + +QString QDir::currentDirPath() +{ + QString result; + +#if defined(__CYGWIN32_) + + STATBUF st; + if ( STAT( ".", &st ) == 0 ) { + char currentName[PATH_MAX]; + if ( GETCWD( currentName, PATH_MAX ) != 0 ) + result = QFile::decodeName(currentName); +#if defined(DEBUG) + if ( result.isNull() ) + qWarning( "QDir::currentDirPath: getcwd() failed" ); +#endif + } else { +#if defined(DEBUG) + qWarning( "QDir::currentDirPath: stat(\".\") failed" ); +#endif + } + +#else + + DWORD size = 0; + WCHAR currentName[ PATH_MAX ]; + size = ::GetCurrentDirectoryW( PATH_MAX, currentName ); + if ( size != 0 ) { + if ( size > PATH_MAX ) { + WCHAR * newCurrentName = new WCHAR[ size ]; + if ( ::GetCurrentDirectoryW( PATH_MAX, newCurrentName ) != 0 ) + result = QString::fromUcs2( ( ushort* ) newCurrentName ); + delete [] newCurrentName; + } else { + result = QString::fromUcs2( ( ushort* ) currentName ); + } + } + + if ( result.length() >= 2 && result[ 1 ] == ':' ) + result[ 0 ] = result.at( 0 ).upper(); // Force uppercase drive letters. +#endif + slashify( result ); + return result; +} + +QString QDir::rootDirPath() +{ + QString d = p_getenv ( "SystemDrive" ); + if ( d.isNull () ) + d = QString::fromLatin1( "c:" ); // not "c:\\" ! + slashify ( d ); + return d; +} + +bool QDir::isRelativePath( const QString &path ) +{ + if ( path.isEmpty() ) + return TRUE; + int p = 0; + if ( path[ 0 ].isLetter() && path[ 1 ] == ':' ) + p = 2; // we have checked the first 2. + return ( ( path[ p ] != '/' ) && ( path[ p ] != '\\' ) ); +} + +#undef IS_SUBDIR +#undef IS_RDONLY +#undef IS_ARCH +#undef IS_HIDDEN +#undef IS_SYSTEM +#undef FF_GETFIRST +#undef FF_GETNEXT +#undef FF_ERROR + +#if defined(_OS_WIN32_) +#define IS_SUBDIR FILE_ATTRIBUTE_DIRECTORY +#define IS_RDONLY FILE_ATTRIBUTE_READONLY +#define IS_ARCH FILE_ATTRIBUTE_ARCHIVE +#define IS_HIDDEN FILE_ATTRIBUTE_HIDDEN +#define IS_SYSTEM FILE_ATTRIBUTE_SYSTEM +#define FF_GETFIRST FindFirstFile +#define FF_GETNEXT FindNextFile +#define FF_ERROR INVALID_HANDLE_VALUE +#else +#define IS_SUBDIR _A_SUBDIR +#define IS_RDONLY _A_RDONLY +#define IS_ARCH _A_ARCH +#define IS_HIDDEN _A_HIDDEN +#define IS_SYSTEM _A_SYSTEM +#define FF_GETFIRST _findfirst +#define FF_GETNEXT _findnext +#define FF_ERROR -1 +#endif + + +bool QDir::readDirEntries( const QString &nameFilter, + int filterSpec, int sortSpec ) +{ + int i; + if ( !fList ) { + fList = new QStringList; + CHECK_PTR( fList ); + fiList = new QFileInfoList; + CHECK_PTR( fiList ); + fiList->setAutoDelete( TRUE ); + } else { + fList->clear(); + fiList->clear(); + } + + QStringList filters = qt_makeFilterList( nameFilter ); + + bool doDirs = (filterSpec & Dirs) != 0; + bool doFiles = (filterSpec & Files) != 0; + bool noSymLinks = (filterSpec & NoSymLinks) != 0; + bool doReadable = (filterSpec & Readable) != 0; + bool doWritable = (filterSpec & Writable) != 0; + bool doExecable = (filterSpec & Executable) != 0; + bool doHidden = (filterSpec & Hidden) != 0; + // show hidden files if the user asks explicitly for e.g. .* + if ( !doHidden && !nameFilter.isEmpty() && nameFilter[0] == '.' ) + doHidden = TRUE; + bool doModified = (filterSpec & Modified) != 0; + bool doSystem = (filterSpec & System) != 0; + + QRegExp wc( nameFilter.data(), FALSE, TRUE ); // wild card, case insensitive + bool first = TRUE; + QString p = dPath.copy(); + int plen = p.length(); +#if defined(_OS_WIN32_) + HANDLE ff; + WIN32_FIND_DATAW finfo; +#else + long ff; + _finddata_t finfo; +#endif + QFileInfo fi; + if ( plen == 0 ) + { +#if defined(CHECK_NULL) + warning( "QDir::readDirEntries: No directory name specified" ); +#endif + return FALSE; + } + if ( p.at(plen-1) != '/' && p.at(plen-1) != '\\' ) + p += '/'; + p += "*.*"; + +#if defined(__CYGWIN32_) + ff = FF_GETFIRST( p.data(), &finfo ); +#else + ff = FindFirstFileW ( ( LPCWSTR ) p.ucs2(), &finfo ); +#endif + if ( ff == FF_ERROR ) + { +#if defined(DEBUG) + warning( "QDir::readDirEntries: Cannot read the directory: %s", + (const char *)dPath ); +#endif + return FALSE; + } + + while ( TRUE ) + { + if ( first ) + first = FALSE; + else + { +#if defined(__CYGWIN32_) + if ( FF_GETNEXT(ff,&finfo) == -1 ) + break; +#else + //if ( !FF_GETNEXT(ff,&finfo) ) + // break; + if (!FindNextFileW(ff, &finfo )) + break; +#endif + } +#if defined(__CYGWIN32_) + int attrib = finfo.attrib; +#else + int attrib = finfo.dwFileAttributes; +#endif + bool isDir = (attrib & IS_SUBDIR) != 0; + bool isFile = !isDir; + bool isSymLink = FALSE; + bool isReadable = TRUE; + bool isWritable = (attrib & IS_RDONLY) == 0; + bool isExecable = FALSE; + bool isModified = (attrib & IS_ARCH) != 0; + bool isHidden = (attrib & IS_HIDDEN) != 0; + bool isSystem = (attrib & IS_SYSTEM) != 0; + +#if defined(__CYGWIN32_) + const char *fname = finfo.name; +#else + //const char *fname = finfo.cFileName; + QString fname = QString::fromUcs2( ( const unsigned short* ) finfo.cFileName); +#endif + if ( wc.match(fname.utf8()) == -1 && !(allDirs && isDir) ) + continue; + + QString name = fname; + if ( doExecable ) + { + QString ext = name.right(4).lower(); + if ( ext == ".exe" || ext == ".com" || ext == ".bat" || + ext == ".pif" || ext == ".cmd" ) + isExecable = TRUE; + } + + if ( (doDirs && isDir) || (doFiles && isFile) ) + { + if ( noSymLinks && isSymLink ) + continue; + if ( (filterSpec & RWEMask) != 0 ) + if ( (doReadable && !isReadable) || + (doWritable && !isWritable) || + (doExecable && !isExecable) ) + continue; + if ( doModified && !isModified ) + continue; + if ( !doHidden && isHidden ) + continue; + if ( !doSystem && isSystem ) + continue; + fi.setFile( *this, name ); + fiList->append( new QFileInfo( fi ) ); + } + } +#if defined(__CYGWIN32_) + _findclose( ff ); +#else + FindClose( ff ); +#endif + + // Sort... + QDirSortItem* si= new QDirSortItem[fiList->count()]; + QFileInfo* itm; + i=0; + for (itm = fiList->first(); itm; itm = fiList->next()) + si[i++].item = itm; + qt_cmp_si_sortSpec = sortSpec; + qsort( si, i, sizeof(si[0]), qt_cmp_si ); + // put them back in the list + fiList->setAutoDelete( FALSE ); + fiList->clear(); + int j; + for ( j=0; j<i; j++ ) { + fiList->append( si[j].item ); + fList->append( si[j].item->fileName() ); + } + delete [] si; + fiList->setAutoDelete( TRUE ); + + if ( filterSpec == (FilterSpec)filtS && sortSpec == (SortSpec)sortS && + nameFilter == nameFilt ) + dirty = FALSE; + else + dirty = TRUE; + return TRUE; +} + +const QFileInfoList * QDir::drives() +{ + // at most one instance of QFileInfoList is leaked, and this variable + // points to that list + static QFileInfoList * knownMemoryLeak = 0; + + if ( !knownMemoryLeak ) { + knownMemoryLeak = new QFileInfoList; + +#if defined(_OS_WIN32_) + Q_UINT32 driveBits = (Q_UINT32) GetLogicalDrives() & 0x3ffffff; +#elif defined(_OS_OS2EMX_) + Q_UINT32 driveBits, cur; + if (DosQueryCurrentDisk(&cur,&driveBits) != NO_ERROR) + exit(1); + driveBits &= 0x3ffffff; +#endif + char driveName[4]; + qstrcpy( driveName, "a:/" ); + while( driveBits ) { + if ( driveBits & 1 ) + knownMemoryLeak->append( new QFileInfo( driveName ) ); + driveName[0]++; + driveBits = driveBits >> 1; + } + } + + return knownMemoryLeak; +} +#endif //QT_NO_DIR diff --git a/trunk/qtools/qfeatures.h b/trunk/qtools/qfeatures.h new file mode 100644 index 0000000..84fa715 --- /dev/null +++ b/trunk/qtools/qfeatures.h @@ -0,0 +1,978 @@ +/**************************************************************************** +** +** +** Global feature selection +** +** Created : 000417 +** +** Copyright (C) 2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QFEATURES_H +#define QFEATURES_H + +/*! \page features....html + ... +*/ + +// Qt ships with a number of pre-defined configurations. If none suit +// your needs, define QCONFIG_LOCAL and create a "qconfig-local.h" file. +// +// Note that disabling some features will produce a libqt that is not +// compatible with other libqt builds. Such modifications are only +// supported on Qt/Embedded where reducing the library size is important +// and where the application-suite is often a fixed set. +// +#if defined(QCONFIG_LOCAL) +#include <qconfig-local.h> +#elif defined(QCONFIG_MINIMAL) +#include <qconfig-minimal.h> +#elif defined(QCONFIG_SMALL) +#include <qconfig-small.h> +#elif defined(QCONFIG_MEDIUM) +#include <qconfig-medium.h> +#elif defined(QCONFIG_LARGE) +#include <qconfig-large.h> +#else // everything... +#include <qconfig.h> +#endif + + +// Data structures +/*! + QStringList +*/ +//#define QT_NO_STRINGLIST + +#if defined(QT_NO_IMAGE_SMOOTHSCALE) +/*! + QIconSet +*/ +# define QT_NO_ICONSET +#endif + +// File I/O +#if defined(QT_NO_STRINGLIST) + /*! + QDir + */ +# define QT_NO_DIR +#endif + +/*! + Palettes +*/ +//#define QT_NO_PALETTE + +/*! + QTextStream +*/ +//#define QT_NO_TEXTSTREAM +/*! + QDataStream +*/ +//#define QT_NO_DATASTREAM + +/*! + Dynamic module linking +*/ +//#define QT_NO_PLUGIN + + +// Images +/*! + BMP image I/O + <p>The Windows Bitmap (BMP) image format is common on MS-Windows. + <p>This is an uncompressed image format + offering few advantages over PNG or JPEG. +*/ +#if defined(QT_NO_DATASTREAM) +# define QT_NO_IMAGEIO_BMP +#endif +/*! + PPM image I/O + <p>The Portable PixMap (PPM) image format is common on Unix. + <p>This is an uncompressed image format + offering few advantages over PNG or JPEG. +*/ +//#define QT_NO_IMAGEIO_PPM +/*! + XBM image I/O + <p>The X11 BitMap (XBM) image format is common on X11. + <p>This is an uncompressed monochrome image format. + Qt uses this format for some internal images (eg. mouse cursors). +*/ +//#define QT_NO_IMAGEIO_XBM +/*! + XPM image I/O + <p>The X11 PixMap (XPM) image format is common on X11. + <p>This is an uncompressed image format. + XPM images have the small advantage that they can be trivially + included in source files as they are C code. + Qt uses this format for some internal images (eg. QMessageBox icons). +*/ +#if defined(QT_NO_TEXTSTREAM) +# define QT_NO_IMAGEIO_XPM +#endif +/*! + PNG image I/O + <p>The Portable Network Graphics (PNG) is a compressed image format. + <p>See <a href=http://www.libpng.org/pub/png/>The PNG Home Site</a> for + details of the format. +*/ +//#define QT_NO_IMAGEIO_PNG +/*! + MNG image I/O + <p>The Multiple-image Network Graphics (MNG) is a compressed animation format. + <p>See <a href=http://www.libpng.org/pub/mng/>The MNG Home Site</a> for + details of the format. +*/ +//#define QT_NO_IMAGEIO_MNG +/*! + JPEG image I/O + <p>The Joint Photographic Experts Group (JPEG) is a compressed lossy image format that gives high compression + for real-world and photo-realistic images. +*/ +//#define QT_NO_IMAGEIO_JPEG + +/*! + Asynchronous I/O + <p>Allows push-driven data processing. +*/ +//#define QT_NO_ASYNC_IO +/*! + Asynchronous image I/O + <p>Allows push-driven images. +*/ +//#define QT_NO_ASYNC_IMAGE_IO +#if defined(QT_NO_ASYNC_IO) || defined(QT_NO_ASYNC_IMAGE_IO) + /*! + Animated images + <p>This includes animated GIFs. + <p><b>Note: this currently also requires <tt>QT_BUILTIN_GIF_READER</tt> to + be defined when building Qt.</b> + */ +# define QT_NO_MOVIE +#endif + +// Fonts +/*! + TrueType font files + <p>Scalable font format common on MS-Windows and becoming common on Unix. + <p>Only supported on Qt/Embedded. +*/ +//#define QT_NO_TRUETYPE +/*! + BDF font files + <p>The Bitmap Distribution Format (BDF) font file format, common + on Unix. + <p>Only supported on Qt/Embedded. +*/ +#if defined(QT_NO_TEXTSTREAM) || defined(QT_NO_STRINGLIST) +# define QT_NO_BDF +#endif +/*! + QFontDatabase +*/ +#if defined(QT_NO_STRINGLIST) +# define QT_NO_FONTDATABASE +#endif + +// Internationalization + +/*! + QObject::tr() +*/ +#if defined(QT_NO_DATASTREAM) +# define QT_NO_TRANSLATION +#endif + +/*! + QTextCodec class and subclasses +*/ +//#define QT_NO_TEXTCODEC + +#if defined(QT_NO_TEXTCODEC) + /*! + QTextCodec classes + <p>This includes some large conversion tables. + */ +# define QT_NO_CODECS +#endif +#if defined(QT_LITE_UNICODE) + /*! + Unicode property tables + <p>These include some large tables. + */ +# define QT_NO_UNICODETABLES +#endif + +/*! + MIME +*/ +#if defined(QT_NO_DIR) +# define QT_NO_MIME +#endif +#if defined(QT_NO_MIME) || defined(QT_NO_TEXTSTREAM) || defined(QT_NO_DRAWUTIL) || defined(QT_NO_IMAGE_SMOOTHSCALE) + /*! + RichText (HTML) display + */ +# define QT_NO_RICHTEXT +#endif + +/*! + XML +*/ +#if defined(QT_NO_STRINGLIST) || defined(QT_NO_TEXTSTREAM) || defined(QT_NO_TEXTCODEC) +# define QT_NO_XML +#endif + +/*! + Document Object Model +*/ +#if defined(QT_NO_XML) || defined(QT_NO_MIME) +# define QT_NO_DOM +#endif + +// Sound +/*! + Playing sounds +*/ +//#define QT_NO_SOUND + +/*! + Properties +*/ +#if defined(QT_NO_STRINGLIST) || defined(QT_NO_ICONSET) +# define QT_NO_PROPERTIES +#endif + + + +// Networking + +/*! + Network support +*/ +//#define QT_NO_NETWORK + +#if defined(QT_NO_NETWORK) || defined(QT_NO_STRINGLIST) || defined(QT_NO_TEXTSTREAM) + /*! + DNS + */ +# define QT_NO_DNS +#endif +/*! + Network file access +*/ +#if defined(QT_NO_NETWORK) || defined(QT_NO_DIR) || defined(QT_NO_STRINGLIST) +# define QT_NO_NETWORKPROTOCOL +#endif +#if defined(QT_NO_NETWORKPROTOCOL) || defined(QT_NO_DNS) + /*! + FTP file access + */ +# define QT_NO_NETWORKPROTOCOL_FTP + /*! + HTTP file access + */ +# define QT_NO_NETWORKPROTOCOL_HTTP +#endif + +/*! + External process invocation. +*/ +//#define QT_NO_PROCESS + + +// Qt/Embedded-specific + +#if defined(QT_NO_NETWORK) + /*! + Multi-process support. + */ +# define QT_NO_QWS_MULTIPROCESS +#endif + +#if defined(QT_NO_QWS_MULTIPROCESS) || defined(QT_NO_DATASTREAM) + /*! + Palmtop Communication Protocol + */ +# define QT_NO_COP +#endif + +/*! + Console keyboard support +*/ +//#define QT_NO_QWS_KEYBOARD + +/*! + Visible cursor +*/ +#if defined(QT_NO_CURSOR) +# define QT_NO_QWS_CURSOR +#endif + +/*! + Alpha-blended cursor +*/ +//#define QT_NO_QWS_ALPHA_CURSOR +/*! + Mach64 acceleration +*/ +//#define QT_NO_QWS_MACH64 +/*! + Voodoo3 acceleration +*/ +//#define QT_NO_QWS_VOODOO3 +/*! + Matrox MGA acceleration (Millennium/Millennium II/Mystique/G200/G400) +*/ +//#define QT_NO_QWS_MATROX +/*! + Virtual frame buffer +*/ + +//#define QT_NO_QWS_VFB +/*! + Transformed frame buffer +*/ +//#define QT_NO_QWS_TRANSFORMED +#if defined(QT_NO_NETWORK) +/*! + Remote frame buffer (VNC) +*/ +# ifndef QT_NO_QWS_VNC +# define QT_NO_QWS_VNC +# endif +#endif +/*! + 1-bit monochrome +*/ +//#define QT_NO_QWS_DEPTH_1 +/*! + 4-bit greyscale +*/ +//#define QT_NO_QWS_DEPTH_4 +/*! + 4-bit VGA +*/ +//#define QT_NO_QWS_VGA_16 +/*! + SVGALib Support + Not implemented yet +*/ +#define QT_NO_QWS_SVGALIB +/*! + 8-bit grayscale +*/ +#define QT_NO_QWS_DEPTH_8GRAYSCALE +/*! + 8-bit color +*/ +//#define QT_NO_QWS_DEPTH_8 +/*! + 15 or 16-bit color (define QT_QWS_DEPTH16_RGB as 555 for 15-bit) +*/ +//#define QT_NO_QWS_DEPTH_16 +/*! + 24-bit color +*/ +//#define QT_NO_QWS_DEPTH_24 +/*! + 32-bit color +*/ +//#define QT_NO_QWS_DEPTH_32 + +/*! + Window Manager +*/ +//#define QT_NO_QWS_MANAGER + +/*! + Window Manager Styles +*/ +#define QT_NO_QWS_KDE2_WM_STYLE +#if defined( QT_NO_QWS_MANAGER ) || defined( QT_NO_IMAGEIO_XPM ) +# define QT_NO_QWS_AQUA_WM_STYLE +# define QT_NO_QWS_BEOS_WM_STYLE +# define QT_NO_QWS_KDE_WM_STYLE +# define QT_NO_QWS_QPE_WM_STYLE +# define QT_NO_QWS_WINDOWS_WM_STYLE +#endif + +/*! + Saving of fonts +*/ +//#define QT_NO_QWS_SAVEFONTS + +/*! + Favour code size over graphics speed + <p>Smaller, slower code will be used for drawing operations. + <p>Only supported on Qt/Embedded. +*/ +//#define QT_NO_QWS_GFX_SPEED + +/*! + Qt/Embedded window system properties. +*/ +//#define QT_NO_QWS_PROPERTIES + +#if defined(QT_NO_QWS_PROPERTIES) || defined(QT_NO_MIME) + /*! + Cut and paste + */ +# define QT_NO_CLIPBOARD +#endif + +#if defined(QT_NO_MIME) || defined(QT_NO_QWS_PROPERTIES) + /*! + Drag and drop + */ +# define QT_NO_DRAGANDDROP +#endif + +#if defined(QT_NO_PROPERTIES) + /*! + SQL + */ +# define QT_NO_SQL +#endif + +#if defined(QT_NO_CLIPBOARD) || defined(QT_NO_MIME) || defined(_WS_QWS_) + /*! + Cut and paste of complex data types (non-text) + Not yet implemented for QWS. + */ +# define QT_NO_MIMECLIPBOARD +#endif + + +/*! + Drawing utility functions +*/ +//#define QT_NO_DRAWUTIL +/*! + TrueColor QImage +*/ +//#define QT_NO_IMAGE_TRUECOLOR +/*! + Smooth QImage scaling +*/ +//#define QT_NO_IMAGE_SMOOTHSCALE +/*! + Image file text strings +*/ +#if defined(QT_NO_STRINGLIST) +# define QT_NO_IMAGE_TEXT +#endif + +#if defined(QT_NO_IMAGE_TRUECOLOR) + /*! + 16-bit QImage + */ +# define QT_NO_IMAGE_16_BIT +#endif +/*! + Cursors +*/ +//#define QT_NO_CURSOR + +// Painting +/*! + Named colors +*/ +//#define QT_NO_COLORNAMES +/*! + Scaling and rotation +*/ +//#define QT_NO_TRANSFORMATIONS + +/*! + Printing +*/ +#if defined(QT_NO_TEXTSTREAM) +# define QT_NO_PRINTER +#endif + +/*! + QPicture +*/ +#if defined(QT_NO_DATASTREAM) +# define QT_NO_PICTURE +#endif + +// Layout +/*! + Automatic widget layout +*/ +//#define QT_NO_LAYOUT + +// Widgets +#if defined(QT_NO_DRAWUTIL) || defined(QT_NO_PALETTE) +/*! + QStyle +*/ +# define QT_NO_STYLE +#endif + + +/*! + Dialogs +*/ +//#define QT_NO_DIALOG +/*! + Semi-modal dialogs +*/ +//#define QT_NO_SEMIMODAL +/*! + Framed widgets +*/ +//#define QT_NO_FRAME + +/*! + Special widget effects (fading, scrolling) +*/ +//#define QT_NO_EFFECTS + + +/*! + QLabel +*/ +#ifdef QT_NO_FRAME +# define QT_NO_LABEL +#endif + +/*! + Toolbars +*/ +#ifdef QT_NO_LAYOUT +# define QT_NO_TOOLBAR +#endif + +/*! + Buttons +*/ +#if defined(QT_NO_BUTTON) || defined(QT_NO_STYLE) +/*! + Check-boxes +*/ +# define QT_NO_CHECKBOX +/*! + Radio-buttons +*/ +# define QT_NO_RADIOBUTTON +#endif +#if defined(QT_NO_BUTTON) || defined(QT_NO_TOOLBAR) || defined(QT_NO_ICONSET) +/*! + Tool-buttons +*/ +# define QT_NO_TOOLBUTTON +#endif +/*! + Grid layout widgets +*/ +#ifdef QT_NO_FRAME +# define QT_NO_GRID +#endif +/*! + Group boxes +*/ +#ifdef QT_NO_FRAME +# define QT_NO_GROUPBOX +#endif +#if defined(QT_NO_GROUPBOX) +/*! + Button groups +*/ +# define QT_NO_BUTTONGROUP +/*! + Horizontal group boxes +*/ +# define QT_NO_HGROUPBOX +#endif +#if defined(QT_NO_HGROUPBOX) +/*! + Vertical group boxes +*/ +# define QT_NO_VGROUPBOX +#endif +#if defined(QT_NO_BUTTONGROUP) +/*! + Horizontal button groups +*/ +# define QT_NO_HBUTTONGROUP +#endif +#if defined(QT_NO_HBUTTONGROUP) +/*! + Vertical button groups +*/ +# define QT_NO_VBUTTONGROUP +#endif +/*! + Horizonal box layout widgets +*/ +#ifdef QT_NO_FRAME +# define QT_NO_HBOX +#endif +#if defined(QT_NO_HBOX) +/*! + Vertical box layout widgets +*/ +# define QT_NO_VBOX +#endif +/*! + Single-line edits +*/ +#if defined(QT_NO_PALETTE) +# define QT_NO_LINEEDIT +#endif +#if defined(QT_NO_TOOLBAR) +/*! + Main-windows +*/ +# define QT_NO_MAINWINDOW +#endif +#if defined(QT_NO_ICONSET) +/*! + Menu-like widgets +*/ +# define QT_NO_MENUDATA +#endif +#if defined(QT_NO_MENUDATA) +/*! + Popup-menus +*/ +# define QT_NO_POPUPMENU +/*! + Menu bars +*/ +# define QT_NO_MENUBAR +#endif +#if defined(QT_NO_BUTTON) || defined(QT_NO_ICONSET) || defined(QT_NO_POPUPMENU) +/*! + Push-buttons +*/ +# define QT_NO_PUSHBUTTON +#endif +/*! + Progress bars +*/ +#ifdef QT_NO_FRAME +# define QT_NO_PROGRESSBAR +#endif +/*! + Range-control widgets +*/ +//#define QT_NO_RANGECONTROL +#if defined(QT_NO_RANGECONTROL) || defined(QT_NO_STYLE) +/*! + Scroll bars +*/ +# define QT_NO_SCROLLBAR +/*! + Sliders +*/ +# define QT_NO_SLIDER +/*! + Spin boxes +*/ +# define QT_NO_SPINBOX +/*! + Dials +*/ +# define QT_NO_DIAL +#endif + + +#if defined(QT_NO_SCROLLBAR) || defined(QT_NO_FRAME) +/*! + Scrollable view widgets +*/ +# define QT_NO_SCROLLVIEW +#endif +#if defined(QT_NO_SCROLLVIEW) +/*! + QCanvas +*/ +# define QT_NO_CANVAS +/*! + QIconView +*/ +# define QT_NO_ICONVIEW +#endif + +#if defined(QT_NO_SCROLLBAR) +/*! + Table-like widgets +*/ +# define QT_NO_TABLEVIEW +#endif +#if defined(QT_NO_TABLEVIEW) +/*! + Multi-line edits +*/ +# define QT_NO_MULTILINEEDIT +#endif + +/*! + Splitters +*/ +#ifdef QT_NO_FRAME +# define QT_NO_SPLITTER +#endif +/*! + Status bars +*/ +#ifdef QT_NO_LAYOUT +# define QT_NO_STATUSBAR +#endif +/*! + Tab-bars +*/ +#if defined(QT_NO_ICONSET) +# define QT_NO_TABBAR +#endif +#if defined(QT_NO_TABBAR) +/*! + Tab widgets +*/ +# define QT_NO_TABWIDGET +#endif +/*! + Tool tips +*/ +#if defined( QT_NO_LABEL ) || defined( QT_NO_PALETTE ) +# define QT_NO_TOOLTIP +#endif +/*! + Input validators +*/ +//#define QT_NO_VALIDATOR +/*! + "What's this" help +*/ +#if defined( QT_NO_TOOLTIP ) +# define QT_NO_WHATSTHIS +#endif +/*! + Widget stacks +*/ +#ifdef QT_NO_FRAME +# define QT_NO_WIDGETSTACK +#endif + +#if defined(QT_NO_RICHTEXT) || defined(QT_NO_SCROLLVIEW) + /*! + QTextView + */ +# define QT_NO_TEXTVIEW +#endif + +#if defined(QT_NO_TEXTVIEW) + /*! + QTextBrowser + */ +# define QT_NO_TEXTBROWSER +#endif + +#if defined(QT_NO_STYLE) + /*! + Windows style + */ +# define QT_NO_STYLE_WINDOWS + /*! + Motif style + */ +# define QT_NO_STYLE_MOTIF +#endif + +#if defined(QT_NO_STYLE_MOTIF) + /*! + Motif-plus style + */ +# define QT_NO_STYLE_MOTIFPLUS +#endif + + +#if defined(QT_NO_SCROLLVIEW) || defined(QT_NO_STRINGLIST) + /*! + QListBox + */ +# define QT_NO_LISTBOX +#endif + +/*! + QAccel +*/ +//#define QT_NO_ACCEL + +/*! + QSizeGrip +*/ +#ifdef QT_NO_PALETTE +# define QT_NO_SIZEGRIP +#endif +/*! + QHeader +*/ +#ifdef QT_NO_ICONSET +# define QT_NO_HEADER +#endif +/*! + QWorkSpace +*/ +#ifdef QT_NO_FRAME +# define QT_NO_WORKSPACE +#endif +/*! + QLCDNumber +*/ +#ifdef QT_NO_FRAME +# define QT_NO_LCDNUMBER +#endif +/*! + QAction +*/ +//#define QT_NO_ACTION + +#if defined(QT_NO_HEADER) + /*! + QTable + */ +# define QT_NO_TABLE +#endif + +#if defined(QT_NO_LISTBOX) + /*! + QComboBox + */ +# define QT_NO_COMBOBOX +#endif + +#if defined(QT_NO_HEADER) || defined(QT_NO_SCROLLVIEW) + /*! + QListView + */ +# define QT_NO_LISTVIEW +#endif + +#if defined(QT_NO_STYLE_WINDOWS) + /*! + Compact Windows style + */ +# define QT_NO_STYLE_COMPACT +#endif + +#if defined(QT_NO_STYLE_MOTIF) || defined(QT_NO_TRANSFORMATIONS) + /*! + CDE style + */ +# define QT_NO_STYLE_CDE + /*! + SGI style + */ +# define QT_NO_STYLE_SGI +#endif +#if defined(QT_NO_STYLE_WINDOWS) + /*! + Platinum style + */ +# define QT_NO_STYLE_PLATINUM +#endif + +/*! + QColorDialog +*/ +#if defined(QT_NO_LAYOUT) || defined(QT_NO_LABEL) || defined(QT_NO_PUSHBUTTON) || defined(QT_NO_DIALOG) +# define QT_NO_COLORDIALOG +#endif +#if defined(QT_NO_DIALOG) +/*! + QMessageBox +*/ +# define QT_NO_MESSAGEBOX +#endif +#if defined(QT_NO_DIALOG) || defined(QT_NO_TABBAR) +/*! + QTabDialog +*/ +#define QT_NO_TABDIALOG +#endif + +#if defined(QT_NO_DIALOG) +/*! + QWizard +*/ +# define QT_NO_WIZARD +#endif + +#if defined(QT_NO_DIALOG) || defined(QT_NO_LISTVIEW) || defined(QT_NO_NETWORKPROTOCOL) || defined(QT_NO_COMBOBOX) || defined(QT_NO_DIR) || defined(QT_NO_MESSAGEBOX) || defined(QT_NO_SEMIMODAL) + /*! + QFileDialog + */ +# define QT_NO_FILEDIALOG +#endif + +#if defined(QT_NO_DIALOG) || defined(QT_NO_FONTDATABASE) || defined(QT_NO_COMBOBOX) + /*! + QFontDialog + */ +# define QT_NO_FONTDIALOG +#endif + +#if defined(QT_NO_DIALOG) || defined(QT_NO_LISTVIEW) || defined(QT_NO_PRINTER) || defined(QT_NO_COMBOBOX) || defined(QT_NO_DIR) || defined(QT_NO_LAYOUT) || defined(QT_NO_LABEL) + /*! + QPrintDialog + */ +# define QT_NO_PRINTDIALOG +#endif + +#if defined(QT_NO_SEMIMODAL) + /*! + QProgressDialog + */ +# define QT_NO_PROGRESSDIALOG +#endif +#if defined(QT_NO_DIALOG) || defined(QT_NO_COMBOBOX) + /*! + QInputDialog + */ +# define QT_NO_INPUTDIALOG +#endif + +#if defined(QT_NO_STRINGLIST) + /*! + Session management support + */ +# define QT_NO_SESSIONMANAGER +#endif + +#endif // QFEATURES_H diff --git a/trunk/qtools/qfile.cpp b/trunk/qtools/qfile.cpp new file mode 100644 index 0000000..98ed9a3 --- /dev/null +++ b/trunk/qtools/qfile.cpp @@ -0,0 +1,550 @@ +/**************************************************************************** +** +** +** Implementation of QFile class +** +** Created : 930812 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "qglobal.h" +#if defined(_OS_WIN32_) +#ifdef UNICODE +#ifndef _UNICODE +#define _UNICODE +#endif +#endif +#endif + +#include "qfile.h" +#include "qfiledefs_p.h" + +extern bool qt_file_access( const QString& fn, int t ); + +// NOT REVISED +/*! + \class QFile qfile.h + \brief The QFile class is an I/O device that operates on files. + + \ingroup io + + QFile is an I/O device for reading and writing binary and text files. A + QFile may be used by itself (readBlock and writeBlock) or by more + conveniently using QDataStream or QTextStream. + + Here is a code fragment that uses QTextStream to read a text + file line by line. It prints each line with a line number. + \code + QFile f("file.txt"); + if ( f.open(IO_ReadOnly) ) { // file opened successfully + QTextStream t( &f ); // use a text stream + QString s; + int n = 1; + while ( !t.eof() ) { // until end of file... + s = t.readLine(); // line of text excluding '\n' + printf( "%3d: %s\n", n++, (const char *)s ); + } + f.close(); + } + \endcode + + The QFileInfo class holds detailed information about a file, such as + access permissions, file dates and file types. + + The QDir class manages directories and lists of file names. + + \sa QDataStream, QTextStream +*/ + + +/*! + Constructs a QFile with no name. +*/ + +QFile::QFile() +{ + init(); +} + +/*! + Constructs a QFile with a file name \e name. + \sa setName() +*/ + +QFile::QFile( const QString &name ) + : fn(name) +{ + init(); +} + + +/*! + Destructs a QFile. Calls close(). +*/ + +QFile::~QFile() +{ + close(); +} + + +/*! + \internal + Initialize internal data. +*/ + +void QFile::init() +{ + setFlags( IO_Direct ); + setStatus( IO_Ok ); + fh = 0; + fd = 0; + length = 0; + ioIndex = 0; + ext_f = FALSE; // not an external file handle +} + + +/*! + \fn QString QFile::name() const + Returns the name set by setName(). + \sa setName(), QFileInfo::fileName() +*/ + +/*! + Sets the name of the file. The name can include an absolute directory + path or it can be a name or a path relative to the current directory. + + Do not call this function if the file has already been opened. + + Note that if the name is relative QFile does not associate it with the + current directory. If you change directory before calling open(), open + uses the new current directory. + + Example: + \code + QFile f; + QDir::setCurrent( "/tmp" ); + f.setName( "readme.txt" ); + QDir::setCurrent( "/home" ); + f.open( IO_ReadOnly ); // opens "/home/readme.txt" under UNIX + \endcode + + Also note that the directory separator '/' works for all operating + systems supported by Qt. + + \sa name(), QFileInfo, QDir +*/ + +void QFile::setName( const QString &name ) +{ + if ( isOpen() ) { +#if defined(CHECK_STATE) + qWarning( "QFile::setName: File is open" ); +#endif + close(); + } + fn = name; +} + +/*! + Returns TRUE if this file exists, otherwise FALSE. + \sa name() +*/ + +bool QFile::exists() const +{ + return qt_file_access( fn, F_OK ); +} + +/*! + Returns TRUE if the file given by \e fileName exists, otherwise FALSE. +*/ + +bool QFile::exists( const QString &fileName ) +{ + return qt_file_access( fileName, F_OK ); +} + + +/*! + Removes the file specified by the file name currently set. + Returns TRUE if successful, otherwise FALSE. + + The file is closed before it is removed. +*/ + +bool QFile::remove() +{ + close(); + return remove( fn ); +} + +#if defined(_OS_MAC_) || defined(_OS_MSDOS_) || defined(_OS_WIN32_) || defined(_OS_OS2_) || defined(_OS_CYGWIN_) +# define HAS_TEXT_FILEMODE // has translate/text filemode +#endif +#if defined(O_NONBLOCK) +# define HAS_ASYNC_FILEMODE +# define OPEN_ASYNC O_NONBLOCK +#elif defined(O_NDELAY) +# define HAS_ASYNC_FILEMODE +# define OPEN_ASYNC O_NDELAY +#endif + +/*! + Flushes the file buffer to the disk. + + close() also flushes the file buffer. +*/ + +void QFile::flush() +{ + if ( isOpen() && fh ) // can only flush open/buffered + fflush( fh ); // file +} + +/*! + Returns TRUE if the end of file has been reached, otherwise FALSE. + \sa size() +*/ + +bool QFile::atEnd() const +{ + if ( !isOpen() ) { +#if defined(CHECK_STATE) + qWarning( "QFile::atEnd: File is not open" ); +#endif + return FALSE; + } + if ( isDirectAccess() && !isTranslated() ) { + if ( at() < length ) + return FALSE; + } + return QIODevice::atEnd(); +} + +/*! + Reads a line of text. + + Reads bytes from the file until end-of-line is reached, or up to \a + maxlen bytes, and returns the number of bytes read, or -1 in case of + error. The terminating newline is not stripped. + + This function is efficient only for buffered files. Avoid + readLine() for files that have been opened with the \c IO_Raw + flag. + + \sa readBlock(), QTextStream::readLine() +*/ + +int QFile::readLine( char *p, uint maxlen ) +{ + if ( maxlen == 0 ) // application bug? + return 0; +#if defined(CHECK_STATE) + CHECK_PTR( p ); + if ( !isOpen() ) { // file not open + qWarning( "QFile::readLine: File not open" ); + return -1; + } + if ( !isReadable() ) { // reading not permitted + qWarning( "QFile::readLine: Read operation not permitted" ); + return -1; + } +#endif + int nread; // number of bytes read + if ( isRaw() ) { // raw file + nread = QIODevice::readLine( p, maxlen ); + } else { // buffered file + p = fgets( p, maxlen, fh ); + if ( p ) { + nread = qstrlen( p ); + ioIndex += nread; + } else { + nread = -1; + setStatus(IO_ReadError); + } + } + return nread; +} + + +/*! + Reads a line of text. + + Reads bytes from the file until end-of-line is reached, or up to \a + maxlen bytes, and returns the number of bytes read, or -1 in case of + error. The terminating newline is not stripped. + + This function is efficient only for buffered files. Avoid + readLine() for files that have been opened with the \c IO_Raw + flag. + + Note that the string is read as plain Latin1 bytes, not Unicode. + + \sa readBlock(), QTextStream::readLine() +*/ + +int QFile::readLine( QString& s, uint maxlen ) +{ + QByteArray ba(maxlen); + int l = readLine(ba.data(),maxlen); + if ( l >= 0 ) { + ba.truncate(l); + s = QString(ba); + } + return l; +} + + +/*! + Reads a single byte/character from the file. + + Returns the byte/character read, or -1 if the end of the file has been + reached. + + \sa putch(), ungetch() +*/ + +int QFile::getch() +{ +#if defined(CHECK_STATE) + if ( !isOpen() ) { // file not open + qWarning( "QFile::getch: File not open" ); + return EOF; + } + if ( !isReadable() ) { // reading not permitted + qWarning( "QFile::getch: Read operation not permitted" ); + return EOF; + } +#endif + + int ch; + + if ( !ungetchBuffer.isEmpty() ) { + int len = ungetchBuffer.length(); + ch = ungetchBuffer[ len-1 ]; + ungetchBuffer.truncate( len - 1 ); + return ch; + } + + if ( isRaw() ) { // raw file (inefficient) + char buf[1]; + ch = readBlock( buf, 1 ) == 1 ? buf[0] : EOF; + } else { // buffered file + if ( (ch = getc( fh )) != EOF ) + ioIndex++; + else + setStatus(IO_ReadError); + } + return ch; +} + +/*! + \fn int QFile::writeBlock( const QByteArray& data ) + \reimp + \internal + Should be removed in 3.0 +*/ + +/*! + Writes the character \e ch to the file. + + Returns \e ch, or -1 if some error occurred. + + \sa getch(), ungetch() +*/ + +int QFile::putch( int ch ) +{ +#if defined(CHECK_STATE) + if ( !isOpen() ) { // file not open + qWarning( "QFile::putch: File not open" ); + return EOF; + } + if ( !isWritable() ) { // writing not permitted + qWarning( "QFile::putch: Write operation not permitted" ); + return EOF; + } +#endif + if ( isRaw() ) { // raw file (inefficient) + char buf[1]; + buf[0] = ch; + ch = writeBlock( buf, 1 ) == 1 ? ch : EOF; + } else { // buffered file + if ( (ch = putc( ch, fh )) != EOF ) { + ioIndex++; + if ( ioIndex > length ) // update file length + length = ioIndex; + } else { + setStatus(IO_WriteError); + } + } + return ch; +} + +/*! + Puts the character \e ch back into the file and decrements the index if it + is not zero. + + This function is normally called to "undo" a getch() operation. + + Returns \e ch, or -1 if some error occurred. + + \sa getch(), putch() +*/ + +int QFile::ungetch( int ch ) +{ +#if defined(CHECK_STATE) + if ( !isOpen() ) { // file not open + qWarning( "QFile::ungetch: File not open" ); + return EOF; + } + if ( !isReadable() ) { // reading not permitted + qWarning( "QFile::ungetch: Read operation not permitted" ); + return EOF; + } +#endif + if ( ch == EOF ) // cannot unget EOF + return ch; + + if ( isSequentialAccess() && !fh) { + // pipe or similar => we cannot ungetch, so do it manually + ungetchBuffer +=ch; + return ch; + } + + if ( isRaw() ) { // raw file (very inefficient) + char buf[1]; + at( ioIndex-1 ); + buf[0] = ch; + if ( writeBlock(buf, 1) == 1 ) + at ( ioIndex-1 ); + else + ch = EOF; + } else { // buffered file + if ( (ch = ungetc(ch, fh)) != EOF ) + ioIndex--; + else + setStatus( IO_ReadError ); + } + return ch; +} + + +static QCString locale_encoder( const QString &fileName ) +{ + return fileName.local8Bit(); +} + + +static QFile::EncoderFn encoder = locale_encoder; + +/*! + When you use QFile, QFileInfo, and QDir to access the filesystem + with Qt, you can use Unicode filenames. On Unix, these filenames + are converted to an 8-bit encoding. If you want to do your own + file I/O on Unix, you should convert the filename using this + function. On Windows NT, Unicode filenames are supported directly + in the filesystem and this function should be avoided. On Windows 95, + non-Latin1 locales are not supported at this time. + + By default, this function converts to the local 8-bit encoding + determined by the user's locale. This is sufficient for + filenames that the user chooses. Filenames hard-coded into the + application should only use 7-bit ASCII filename characters. + + The conversion scheme can be changed using setEncodingFunction(). + This might be useful if you wish to give the user an option to + store in filenames in UTF-8, etc., but beware that such filenames + would probably then be unrecognizable when seen by other programs. + + \sa decodeName() +*/ + +QCString QFile::encodeName( const QString &fileName ) +{ + return (*encoder)(fileName); +} + +/*! + \enum QFile::EncoderFn + + This is used by QFile::setEncodingFunction(). +*/ + +/*! + Sets the function for encoding Unicode filenames. + The default encodes in the locale-specific 8-bit encoding. + + \sa encodeName() +*/ +void QFile::setEncodingFunction( EncoderFn f ) +{ + encoder = f; +} + +static +QString locale_decoder( const QCString &localFileName ) +{ + return QString::fromLocal8Bit(localFileName); +} + +static QFile::DecoderFn decoder = locale_decoder; + +/*! + This does the reverse of QFile::encodeName(). + + \sa setDecodingFunction() +*/ +QString QFile::decodeName( const QCString &localFileName ) +{ + return (*decoder)(localFileName); +} + +/*! + \enum QFile::DecoderFn + + This is used by QFile::setDecodingFunction(). +*/ + +/*! + Sets the function for decoding 8-bit filenames. + The default uses the locale-specific 8-bit encoding. + + \sa encodeName(), decodeName() +*/ + +void QFile::setDecodingFunction( DecoderFn f ) +{ + decoder = f; +} diff --git a/trunk/qtools/qfile.h b/trunk/qtools/qfile.h new file mode 100644 index 0000000..a447d2f --- /dev/null +++ b/trunk/qtools/qfile.h @@ -0,0 +1,128 @@ +/**************************************************************************** +** +** +** Definition of QFile class +** +** Created : 930831 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QFILE_H +#define QFILE_H + +#ifndef QT_H +#include "qiodevice.h" +#include "qstring.h" +#include <stdio.h> +#endif // QT_H + +class QDir; + + +class Q_EXPORT QFile : public QIODevice // file I/O device class +{ +public: + QFile(); + QFile( const QString &name ); + virtual ~QFile(); + + QString name() const; + void setName( const QString &name ); + + typedef QCString (*EncoderFn)( const QString &fileName ); + typedef QString (*DecoderFn)( const QCString &localfileName ); + static QCString encodeName( const QString &fileName ); + static QString decodeName( const QCString &localFileName ); + static void setEncodingFunction( EncoderFn ); + static void setDecodingFunction( DecoderFn ); + + bool exists() const; + static bool exists( const QString &fileName ); + + bool remove(); + static bool remove( const QString &fileName ); + + bool open( int ); + bool open( int, FILE * ); + bool open( int, int ); + void close(); + void flush(); + + uint size() const; + int at() const; + bool at( int ); + bool atEnd() const; + + int readBlock( char *data, uint len ); + int writeBlock( const char *data, uint len ); + int writeBlock( const QByteArray& data ) + { return QIODevice::writeBlock(data); } + int readLine( char *data, uint maxlen ); + int readLine( QString &, uint maxlen ); + + int getch(); + int putch( int ); + int ungetch( int ); + + int handle() const; + + int64 pos() const; + int64 toEnd(); + bool seek(int64 pos); + +protected: + QString fn; + FILE *fh; + int fd; + int length; + bool ext_f; + void * d; + +private: + void init(); + QCString ungetchBuffer; + +private: // Disabled copy constructor and operator= +#if defined(Q_DISABLE_COPY) + QFile( const QFile & ); + QFile &operator=( const QFile & ); +#endif +}; + + +inline QString QFile::name() const +{ return fn; } + +inline int QFile::at() const +{ return ioIndex; } + + +#endif // QFILE_H diff --git a/trunk/qtools/qfile_unix.cpp b/trunk/qtools/qfile_unix.cpp new file mode 100644 index 0000000..fa53d13 --- /dev/null +++ b/trunk/qtools/qfile_unix.cpp @@ -0,0 +1,668 @@ +/**************************************************************************** +** +** +** Implementation of QFileInfo class +** +** Created : 950628 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses for Unix/X11 or for Qt/Embedded may use this file in accordance +** with the Qt Commercial License Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "qglobal.h" + +#include "qfile.h" +#include "qfiledefs_p.h" + +#if (defined(_OS_MAC_) && (!defined(_OS_UNIX_))) || defined(_OS_MSDOS_) || defined(_OS_WIN32_) || defined(_OS_OS2_) || defined(_OS_CYGWIN_) +# define HAS_TEXT_FILEMODE // has translate/text filemode +#endif +#if defined(O_NONBLOCK) +# define HAS_ASYNC_FILEMODE +# define OPEN_ASYNC O_NONBLOCK +#elif defined(O_NDELAY) +# define HAS_ASYNC_FILEMODE +# define OPEN_ASYNC O_NDELAY +#endif + +bool qt_file_access( const QString& fn, int t ) +{ + if ( fn.isEmpty() ) + return FALSE; + return ACCESS( QFile::encodeName(fn), t ) == 0; +} + +/*! + Removes the file \a fileName. + Returns TRUE if successful, otherwise FALSE. +*/ + +bool QFile::remove( const QString &fileName ) +{ + if ( fileName.isEmpty() ) { +#if defined(CHECK_NULL) + qWarning( "QFile::remove: Empty or null file name" ); +#endif + return FALSE; + } + return unlink( QFile::encodeName(fileName) ) == 0; + // unlink more common in UNIX +} + +#if defined(O_NONBLOCK) +# define HAS_ASYNC_FILEMODE +# define OPEN_ASYNC O_NONBLOCK +#elif defined(O_NDELAY) +# define HAS_ASYNC_FILEMODE +# define OPEN_ASYNC O_NDELAY +#endif + +/*! + Opens the file specified by the file name currently set, using the mode \e m. + Returns TRUE if successful, otherwise FALSE. + + The mode parameter \e m must be a combination of the following flags: + <ul> + <li>\c IO_Raw specified raw (non-buffered) file access. + <li>\c IO_ReadOnly opens the file in read-only mode. + <li>\c IO_WriteOnly opens the file in write-only mode (and truncates). + <li>\c IO_ReadWrite opens the file in read/write mode, equivalent to + \c (IO_ReadOnly|IO_WriteOnly). + <li>\c IO_Append opens the file in append mode. This mode is very useful + when you want to write something to a log file. The file index is set to + the end of the file. Note that the result is undefined if you position the + file index manually using at() in append mode. + <li>\c IO_Truncate truncates the file. + <li>\c IO_Translate enables carriage returns and linefeed translation + for text files under MS-DOS, Windows and OS/2. + </ul> + + The raw access mode is best when I/O is block-operated using 4kB block size + or greater. Buffered access works better when reading small portions of + data at a time. + + <strong>Important:</strong> When working with buffered files, data may + not be written to the file at once. Call \link flush() flush\endlink + to make sure the data is really written. + + \warning We have experienced problems with some C libraries when a buffered + file is opened for both reading and writing. If a read operation takes place + immediately after a write operation, the read buffer contains garbage data. + Worse, the same garbage is written to the file. Calling flush() before + readBlock() solved this problem. + + If the file does not exist and \c IO_WriteOnly or \c IO_ReadWrite is + specified, it is created. + + Example: + \code + QFile f1( "/tmp/data.bin" ); + QFile f2( "readme.txt" ); + f1.open( IO_Raw | IO_ReadWrite | IO_Append ); + f2.open( IO_ReadOnly | IO_Translate ); + \endcode + + \sa name(), close(), isOpen(), flush() +*/ + +bool QFile::open( int m ) +{ + if ( isOpen() ) { // file already open +#if defined(CHECK_STATE) + qWarning( "QFile::open: File already open" ); +#endif + return FALSE; + } + if ( fn.isNull() ) { // no file name defined +#if defined(CHECK_NULL) + qWarning( "QFile::open: No file name specified" ); +#endif + return FALSE; + } + init(); // reset params + setMode( m ); + if ( !(isReadable() || isWritable()) ) { +#if defined(CHECK_RANGE) + qWarning( "QFile::open: File access not specified" ); +#endif + return FALSE; + } + bool ok = TRUE; + STATBUF st; + if ( isRaw() ) { // raw file I/O + int oflags = OPEN_RDONLY; + if ( isReadable() && isWritable() ) + oflags = OPEN_RDWR; + else if ( isWritable() ) + oflags = OPEN_WRONLY; + if ( flags() & IO_Append ) { // append to end of file? + if ( flags() & IO_Truncate ) + oflags |= (OPEN_CREAT | OPEN_TRUNC); + else + oflags |= (OPEN_APPEND | OPEN_CREAT); + setFlags( flags() | IO_WriteOnly ); // append implies write + } else if ( isWritable() ) { // create/trunc if writable + if ( flags() & IO_Truncate ) + oflags |= (OPEN_CREAT | OPEN_TRUNC); + else + oflags |= OPEN_CREAT; + } +#if defined(HAS_TEXT_FILEMODE) + if ( isTranslated() ) +#ifdef __CYGWIN__ + /* Do nothing, allowing the Cygwin mount mode to take effect. */; +#else + oflags |= OPEN_TEXT; +#endif + else + oflags |= OPEN_BINARY; +#endif +#if defined(HAS_ASYNC_FILEMODE) + if ( isAsynchronous() ) + oflags |= OPEN_ASYNC; +#endif + fd = OPEN( QFile::encodeName(fn), oflags, 0666 ); + + if ( fd != -1 ) { // open successful + FSTAT( fd, &st ); // get the stat for later usage + } else { + ok = FALSE; + } + } else { // buffered file I/O + QCString perm; + char perm2[4]; + bool try_create = FALSE; + if ( flags() & IO_Append ) { // append to end of file? + setFlags( flags() | IO_WriteOnly ); // append implies write + perm = isReadable() ? "a+" : "a"; + } else { + if ( isReadWrite() ) { + if ( flags() & IO_Truncate ) { + perm = "w+"; + } else { + perm = "r+"; + try_create = TRUE; // try to create if not exists + } + } else if ( isReadable() ) { + perm = "r"; + } else if ( isWritable() ) { + perm = "w"; + } + } + qstrcpy( perm2, perm ); +#if defined(HAS_TEXT_FILEMODE) + if ( isTranslated() ) +#ifdef __CYGWIN__ + /* Do nothing, allowing the Cygwin mount mode to take effect. */; +#else + strcat( perm2, "t" ); +#endif + else + strcat( perm2, "b" ); +#endif + while (1) { // At most twice + + fh = fopen( QFile::encodeName(fn), perm2 ); + + if ( !fh && try_create ) { + perm2[0] = 'w'; // try "w+" instead of "r+" + try_create = FALSE; + } else { + break; + } + } + if ( fh ) { + FSTAT( FILENO(fh), &st ); // get the stat for later usage + } else { + ok = FALSE; + } + } + if ( ok ) { + setState( IO_Open ); + // on successful open the file stat was got; now test what type + // of file we have + if ( (st.st_mode & STAT_MASK) != STAT_REG ) { + // non-seekable + setType( IO_Sequential ); + length = INT_MAX; + ioIndex = (flags() & IO_Append) == 0 ? 0 : length; + } else { + length = (int)st.st_size; + ioIndex = (flags() & IO_Append) == 0 ? 0 : length; + if ( !(flags()&IO_Truncate) && length == 0 && isReadable() ) { + // try if you can read from it (if you can, it's a sequential + // device; e.g. a file in the /proc filesystem) + int c = getch(); + if ( c != -1 ) { + ungetch(c); + setType( IO_Sequential ); + length = INT_MAX; + } + } + } + } else { + init(); + if ( errno == EMFILE ) // no more file handles/descrs + setStatus( IO_ResourceError ); + else + setStatus( IO_OpenError ); + } + return ok; +} + +/*! + Opens a file in the mode \e m using an existing file handle \e f. + Returns TRUE if successful, otherwise FALSE. + + Example: + \code + #include <stdio.h> + + void printError( const char* msg ) + { + QFile f; + f.open( IO_WriteOnly, stderr ); + f.writeBlock( msg, qstrlen(msg) ); // write to stderr + f.close(); + } + \endcode + + When a QFile is opened using this function, close() does not actually + close the file, only flushes it. + + \warning If \e f is \c stdin, \c stdout, \c stderr, you may not + be able to seek. See QIODevice::isSequentialAccess() for more + information. + + \sa close() +*/ + +bool QFile::open( int m, FILE *f ) +{ + if ( isOpen() ) { +#if defined(CHECK_RANGE) + qWarning( "QFile::open: File already open" ); +#endif + return FALSE; + } + init(); + setMode( m &~IO_Raw ); + setState( IO_Open ); + fh = f; + ext_f = TRUE; + STATBUF st; + FSTAT( FILENO(fh), &st ); + ioIndex = (int)ftell( fh ); + if ( (st.st_mode & STAT_MASK) != STAT_REG || f == stdin ) { //stdin is non seekable + // non-seekable + setType( IO_Sequential ); + length = INT_MAX; + } else { + length = (int)st.st_size; + if ( !(flags()&IO_Truncate) && length == 0 && isReadable() ) { + // try if you can read from it (if you can, it's a sequential + // device; e.g. a file in the /proc filesystem) + int c = getch(); + if ( c != -1 ) { + ungetch(c); + setType( IO_Sequential ); + length = INT_MAX; + } + } + } + return TRUE; +} + +/*! + Opens a file in the mode \e m using an existing file descriptor \e f. + Returns TRUE if successful, otherwise FALSE. + + When a QFile is opened using this function, close() does not actually + close the file. + + \warning If \e f is one of 0 (stdin), 1 (stdout) or 2 (stderr), you may not + be able to seek. size() is set to \c INT_MAX (in limits.h). + + \sa close() +*/ + + +bool QFile::open( int m, int f ) +{ + if ( isOpen() ) { +#if defined(CHECK_RANGE) + qWarning( "QFile::open: File already open" ); +#endif + return FALSE; + } + init(); + setMode( m |IO_Raw ); + setState( IO_Open ); + fd = f; + ext_f = TRUE; + STATBUF st; + FSTAT( fd, &st ); + ioIndex = (int)LSEEK(fd, 0, SEEK_CUR); + if ( (st.st_mode & STAT_MASK) != STAT_REG || f == 0 ) { // stdin is not seekable... + // non-seekable + setType( IO_Sequential ); + length = INT_MAX; + } else { + length = (int)st.st_size; + if ( length == 0 && isReadable() ) { + // try if you can read from it (if you can, it's a sequential + // device; e.g. a file in the /proc filesystem) + int c = getch(); + if ( c != -1 ) { + ungetch(c); + setType( IO_Sequential ); + length = INT_MAX; + } + resetStatus(); + } + } + return TRUE; +} + +/*! + Returns the file size. + \sa at() +*/ + +uint QFile::size() const +{ + STATBUF st; + if ( isOpen() ) { + FSTAT( fh ? FILENO(fh) : fd, &st ); + } else { + STAT( QFile::encodeName(fn), &st ); + } + return st.st_size; +} + +/*! + \fn int QFile::at() const + Returns the file index. + \sa size() +*/ + +/*! + Sets the file index to \e pos. Returns TRUE if successful, otherwise FALSE. + + Example: + \code + QFile f( "data.bin" ); + f.open( IO_ReadOnly ); // index set to 0 + f.at( 100 ); // set index to 100 + f.at( f.at()+50 ); // set index to 150 + f.at( f.size()-80 ); // set index to 80 before EOF + f.close(); + \endcode + + \warning The result is undefined if the file was \link open() opened\endlink + using the \c IO_Append specifier. + + \sa size(), open() +*/ + +bool QFile::at( int pos ) +{ + if ( !isOpen() ) { +#if defined(CHECK_STATE) + qWarning( "QFile::at: File is not open" ); +#endif + return FALSE; + } + bool ok; + if ( isRaw() ) { // raw file + pos = (int)LSEEK(fd, pos, SEEK_SET); + ok = pos != -1; + } else { // buffered file + ok = fseek(fh, pos, SEEK_SET) == 0; + } + if ( ok ) + ioIndex = pos; +#if defined(CHECK_RANGE) + else + qWarning( "QFile::at: Cannot set file position %d", pos ); +#endif + return ok; +} + +/*! + Reads at most \e len bytes from the file into \e p and returns the + number of bytes actually read. + + Returns -1 if a serious error occurred. + + \warning We have experienced problems with some C libraries when a buffered + file is opened for both reading and writing. If a read operation takes place + immediately after a write operation, the read buffer contains garbage data. + Worse, the same garbage is written to the file. Calling flush() before + readBlock() solved this problem. + + \sa writeBlock() +*/ + +int QFile::readBlock( char *p, uint len ) +{ +#if defined(CHECK_NULL) + if ( !p ) + qWarning( "QFile::readBlock: Null pointer error" ); +#endif +#if defined(CHECK_STATE) + if ( !isOpen() ) { // file not open + qWarning( "QFile::readBlock: File not open" ); + return -1; + } + if ( !isReadable() ) { // reading not permitted + qWarning( "QFile::readBlock: Read operation not permitted" ); + return -1; + } +#endif + int nread = 0; // number of bytes read + if ( !ungetchBuffer.isEmpty() ) { + // need to add these to the returned string. + int l = ungetchBuffer.length(); + while( nread < l ) { + *p = ungetchBuffer[ l - nread - 1 ]; + p++; + nread++; + } + ungetchBuffer.truncate( l - nread ); + } + + if ( nread < (int)len ) { + if ( isRaw() ) { // raw file + nread += READ( fd, p, len-nread ); + if ( len && nread <= 0 ) { + nread = 0; + setStatus(IO_ReadError); + } + } else { // buffered file + nread += fread( p, 1, len-nread, fh ); + if ( (uint)nread != len ) { + if ( ferror( fh ) || nread==0 ) + setStatus(IO_ReadError); + } + } + } + ioIndex += nread; + return nread; +} + +/*! \overload int writeBlock( const QByteArray& data ) +*/ + +/*! \reimp + + Writes \e len bytes from \e p to the file and returns the number of + bytes actually written. + + Returns -1 if a serious error occurred. + + \warning When working with buffered files, data may not be written + to the file at once. Call flush() to make sure the data is really + written. + + \sa readBlock() +*/ + +int QFile::writeBlock( const char *p, uint len ) +{ +#if defined(CHECK_NULL) + if ( p == 0 && len != 0 ) + qWarning( "QFile::writeBlock: Null pointer error" ); +#endif +#if defined(CHECK_STATE) + if ( !isOpen() ) { // file not open + qWarning( "QFile::writeBlock: File not open" ); + return -1; + } + if ( !isWritable() ) { // writing not permitted + qWarning( "QFile::writeBlock: Write operation not permitted" ); + return -1; + } +#endif + int nwritten; // number of bytes written + if ( isRaw() ) // raw file + nwritten = WRITE( fd, p, len ); + else // buffered file + nwritten = fwrite( p, 1, len, fh ); + if ( nwritten != (int)len ) { // write error + if ( errno == ENOSPC ) // disk is full + setStatus( IO_ResourceError ); + else + setStatus( IO_WriteError ); + if ( isRaw() ) // recalc file position + ioIndex = (int)LSEEK( fd, 0, SEEK_CUR ); + else + ioIndex = fseek( fh, 0, SEEK_CUR ); + } else { + ioIndex += nwritten; + } + if ( ioIndex > length ) // update file length + length = ioIndex; + return nwritten; +} + +/*! + Returns the file handle of the file. + + This is a small positive integer, suitable for use with C library + functions such as fdopen() and fcntl(), as well as with QSocketNotifier. + + If the file is not open or there is an error, handle() returns -1. + + \sa QSocketNotifier +*/ + +int QFile::handle() const +{ + if ( !isOpen() ) + return -1; + else if ( fh ) + return FILENO( fh ); + else + return fd; +} + +/*! + Closes an open file. + + The file is not closed if it was opened with an existing file handle. + If the existing file handle is a \c FILE*, the file is flushed. + If the existing file handle is an \c int file descriptor, nothing + is done to the file. + + Some "write-behind" filesystems may report an unspecified error on + closing the file. These errors only indicate that something may + have gone wrong since the previous open(). In such a case status() + reports IO_UnspecifiedError after close(), otherwise IO_Ok. + + \sa open(), flush() +*/ + + +void QFile::close() +{ + bool ok = FALSE; + if ( isOpen() ) { // file is not open + if ( fh ) { // buffered file + if ( ext_f ) + ok = fflush( fh ) != -1; // flush instead of closing + else + ok = fclose( fh ) != -1; + } else { // raw file + if ( ext_f ) + ok = TRUE; // cannot close + else + ok = CLOSE( fd ) != -1; + } + init(); // restore internal state + } + if (!ok) + setStatus (IO_UnspecifiedError); + + return; +} + +int64 QFile::pos() const +{ + if (isOpen()) + { + // TODO: support 64 bit size + return ftell( fh ); + } + return -1; +} + +int64 QFile::toEnd() +{ + if (isOpen()) + { + // TODO: support 64 bit size + if (fseek( fh, 0, SEEK_END )!=-1) + { + return ftell( fh ); + } + } + return -1; +} + +bool QFile::seek( int64 pos ) +{ + if (isOpen()) + { + // TODO: support 64 bit size + return fseek( fh, pos, SEEK_SET )!=-1; + } + return FALSE; +} + diff --git a/trunk/qtools/qfile_win32.cpp b/trunk/qtools/qfile_win32.cpp new file mode 100644 index 0000000..80ad628 --- /dev/null +++ b/trunk/qtools/qfile_win32.cpp @@ -0,0 +1,678 @@ +/****************************************************************************** + * + * + * + * 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. + * + * Based on qfile_unix.cpp + * + * Copyright (C) 1992-2000 Trolltech AS. + */ + +#include "qglobal.h" + +#include "qfile.h" +#include "qfiledefs_p.h" + +#if defined(_OS_MAC_) || defined(_OS_MSDOS_) || defined(_OS_WIN32_) || defined(_OS_OS2_) +# define HAS_TEXT_FILEMODE // has translate/text filemode +#endif +#if defined(O_NONBLOCK) +# define HAS_ASYNC_FILEMODE +# define OPEN_ASYNC O_NONBLOCK +#elif defined(O_NDELAY) +# define HAS_ASYNC_FILEMODE +# define OPEN_ASYNC O_NDELAY +#endif + +static void reslashify( QString& n ) +{ + for ( int i=0; i<(int)n.length(); i++ ) + { + if ( n[i] == '/' ) + n[i] = '\\'; + } +} + +bool qt_file_access( const QString& fn, int t ) +{ + if ( fn.isEmpty() ) + return FALSE; +#if defined(__CYGWIN32_) + return ACCESS( QFile::encodeName(fn), t ) == 0; +#else + QString str = fn; + reslashify(str); + return ( _waccess( (wchar_t*) str.ucs2(), t ) == 0 ); +#endif +} + +/*! + Removes the file \a fileName. + Returns TRUE if successful, otherwise FALSE. +*/ + +bool QFile::remove( const QString &fileName ) +{ + if ( fileName.isEmpty() ) { +#if defined(CHECK_NULL) + qWarning( "QFile::remove: Empty or null file name" ); +#endif + return FALSE; + } +#if defined(__CYGWIN32_) + // unlink more common in UNIX + return ::remove( QFile::encodeName(fileName) ) == 0; +#else + QString str = fileName; + reslashify(str); + return ( _wunlink( (wchar_t*) str.ucs2() ) == 0 ); +#endif +} + +#if defined(O_NONBLOCK) +# define HAS_ASYNC_FILEMODE +# define OPEN_ASYNC O_NONBLOCK +#elif defined(O_NDELAY) +# define HAS_ASYNC_FILEMODE +# define OPEN_ASYNC O_NDELAY +#endif + +/*! + Opens the file specified by the file name currently set, using the mode \e m. + Returns TRUE if successful, otherwise FALSE. + + The mode parameter \e m must be a combination of the following flags: + <ul> + <li>\c IO_Raw specified raw (non-buffered) file access. + <li>\c IO_ReadOnly opens the file in read-only mode. + <li>\c IO_WriteOnly opens the file in write-only mode (and truncates). + <li>\c IO_ReadWrite opens the file in read/write mode, equivalent to + \c (IO_ReadOnly|IO_WriteOnly). + <li>\c IO_Append opens the file in append mode. This mode is very useful + when you want to write something to a log file. The file index is set to + the end of the file. Note that the result is undefined if you position the + file index manually using at() in append mode. + <li>\c IO_Truncate truncates the file. + <li>\c IO_Translate enables carriage returns and linefeed translation + for text files under MS-DOS, Windows and OS/2. + </ul> + + The raw access mode is best when I/O is block-operated using 4kB block size + or greater. Buffered access works better when reading small portions of + data at a time. + + <strong>Important:</strong> When working with buffered files, data may + not be written to the file at once. Call \link flush() flush\endlink + to make sure the data is really written. + + \warning We have experienced problems with some C libraries when a buffered + file is opened for both reading and writing. If a read operation takes place + immediately after a write operation, the read buffer contains garbage data. + Worse, the same garbage is written to the file. Calling flush() before + readBlock() solved this problem. + + If the file does not exist and \c IO_WriteOnly or \c IO_ReadWrite is + specified, it is created. + + Example: + \code + QFile f1( "/tmp/data.bin" ); + QFile f2( "readme.txt" ); + f1.open( IO_Raw | IO_ReadWrite | IO_Append ); + f2.open( IO_ReadOnly | IO_Translate ); + \endcode + + \sa name(), close(), isOpen(), flush() +*/ + +bool QFile::open( int m ) +{ + if ( isOpen() ) { // file already open +#if defined(CHECK_STATE) + qWarning( "QFile::open: File already open" ); +#endif + return FALSE; + } + if ( fn.isNull() ) { // no file name defined +#if defined(CHECK_NULL) + qWarning( "QFile::open: No file name specified" ); +#endif + return FALSE; + } + init(); // reset params + setMode( m ); + if ( !(isReadable() || isWritable()) ) { +#if defined(CHECK_RANGE) + qWarning( "QFile::open: File access not specified" ); +#endif + return FALSE; + } + bool ok = TRUE; + STATBUF st; + if ( isRaw() ) { // raw file I/O + int oflags = OPEN_RDONLY; + if ( isReadable() && isWritable() ) + oflags = OPEN_RDWR; + else if ( isWritable() ) + oflags = OPEN_WRONLY; + if ( flags() & IO_Append ) { // append to end of file? + if ( flags() & IO_Truncate ) + oflags |= (OPEN_CREAT | OPEN_TRUNC); + else + oflags |= (OPEN_APPEND | OPEN_CREAT); + setFlags( flags() | IO_WriteOnly ); // append implies write + } else if ( isWritable() ) { // create/trunc if writable + if ( flags() & IO_Truncate ) + oflags |= (OPEN_CREAT | OPEN_TRUNC); + else + oflags |= OPEN_CREAT; + } +#if defined(HAS_TEXT_FILEMODE) + if ( isTranslated() ) + oflags |= OPEN_TEXT; + else + oflags |= OPEN_BINARY; +#endif +#if defined(HAS_ASYNC_FILEMODE) + if ( isAsynchronous() ) + oflags |= OPEN_ASYNC; +#endif + + +#if defined(__CYGWIN32_) + fd = OPEN( QFile::encodeName(fn), oflags, 0666 ); +#else + QString str = fn; + reslashify(str); + fd = _wopen( (wchar_t*) str.ucs2(), oflags, 0666 ); +#endif + + if ( fd != -1 ) { // open successful + FSTAT( fd, &st ); // get the stat for later usage + } else { + ok = FALSE; + } + } else { // buffered file I/O + QCString perm; + char perm2[4]; + bool try_create = FALSE; + if ( flags() & IO_Append ) { // append to end of file? + setFlags( flags() | IO_WriteOnly ); // append implies write + perm = isReadable() ? "a+" : "a"; + } else { + if ( isReadWrite() ) { + if ( flags() & IO_Truncate ) { + perm = "w+"; + } else { + perm = "r+"; + try_create = TRUE; // try to create if not exists + } + } else if ( isReadable() ) { + perm = "r"; + } else if ( isWritable() ) { + perm = "w"; + } + } + qstrcpy( perm2, perm ); + if ( isTranslated() ) + strcat( perm2, "t" ); + else + strcat( perm2, "b" ); + while (1) { // At most twice + +#if defined(__CYGWIN32_) + fh = fopen( QFile::encodeName(fn), perm2 ); +#else + QString str = fn; + QString prm( perm2 ); + reslashify(str); + fh = _wfopen( (wchar_t*) str.ucs2(), (wchar_t*) prm.ucs2() ); +#endif + + if ( !fh && try_create ) { + perm2[0] = 'w'; // try "w+" instead of "r+" + try_create = FALSE; + } else { + break; + } + } + if ( fh ) { + FSTAT( FILENO(fh), &st ); // get the stat for later usage + } else { + ok = FALSE; + } + } + if ( ok ) { + setState( IO_Open ); + // on successful open the file stat was got; now test what type + // of file we have + if ( (st.st_mode & STAT_MASK) != STAT_REG ) { + // non-seekable + setType( IO_Sequential ); + length = INT_MAX; + ioIndex = (flags() & IO_Append) == 0 ? 0 : length; + } else { + length = (int)st.st_size; + ioIndex = (flags() & IO_Append) == 0 ? 0 : length; + if ( (flags() & !IO_Truncate) && length == 0 && isReadable() ) { + // try if you can read from it (if you can, it's a sequential + // device; e.g. a file in the /proc filesystem) + int c = getch(); + if ( c != -1 ) { + ungetch(c); + setType( IO_Sequential ); + length = INT_MAX; + } + } + } + } else { + init(); + if ( errno == EMFILE ) // no more file handles/descrs + setStatus( IO_ResourceError ); + else + setStatus( IO_OpenError ); + } + return ok; +} + +/*! + Opens a file in the mode \e m using an existing file handle \e f. + Returns TRUE if successful, otherwise FALSE. + + Example: + \code + #include <stdio.h> + + void printError( const char* msg ) + { + QFile f; + f.open( IO_WriteOnly, stderr ); + f.writeBlock( msg, qstrlen(msg) ); // write to stderr + f.close(); + } + \endcode + + When a QFile is opened using this function, close() does not actually + close the file, only flushes it. + + \warning If \e f is \c stdin, \c stdout, \c stderr, you may not + be able to seek. See QIODevice::isSequentialAccess() for more + information. + + \sa close() +*/ + +bool QFile::open( int m, FILE *f ) +{ + if ( isOpen() ) { +#if defined(CHECK_RANGE) + qWarning( "QFile::open: File already open" ); +#endif + return FALSE; + } + init(); + setMode( m &~IO_Raw ); + setState( IO_Open ); + fh = f; + ext_f = TRUE; + STATBUF st; + FSTAT( FILENO(fh), &st ); + ioIndex = (int)ftell( fh ); + if ( (st.st_mode & STAT_MASK) != STAT_REG ) { + // non-seekable + setType( IO_Sequential ); + length = INT_MAX; + } else { + length = (int)st.st_size; + if ( (flags() & !IO_Truncate) && length == 0 && isReadable() ) { + // try if you can read from it (if you can, it's a sequential + // device; e.g. a file in the /proc filesystem) + int c = getch(); + if ( c != -1 ) { + ungetch(c); + setType( IO_Sequential ); + length = INT_MAX; + } + } + } + return TRUE; +} + +/*! + Opens a file in the mode \e m using an existing file descriptor \e f. + Returns TRUE if successful, otherwise FALSE. + + When a QFile is opened using this function, close() does not actually + close the file. + + \warning If \e f is one of 0 (stdin), 1 (stdout) or 2 (stderr), you may not + be able to seek. size() is set to \c INT_MAX (in limits.h). + + \sa close() +*/ + + +bool QFile::open( int m, int f ) +{ + if ( isOpen() ) { +#if defined(CHECK_RANGE) + qWarning( "QFile::open: File already open" ); +#endif + return FALSE; + } + init(); + setMode( m |IO_Raw ); + setState( IO_Open ); + fd = f; + ext_f = TRUE; + STATBUF st; + FSTAT( fd, &st ); + ioIndex = (int)LSEEK(fd, 0, SEEK_CUR); + if ( (st.st_mode & STAT_MASK) != STAT_REG ) { + // non-seekable + setType( IO_Sequential ); + length = INT_MAX; + } else { + length = (int)st.st_size; + if ( length == 0 && isReadable() ) { + // try if you can read from it (if you can, it's a sequential + // device; e.g. a file in the /proc filesystem) + int c = getch(); + if ( c != -1 ) { + ungetch(c); + setType( IO_Sequential ); + length = INT_MAX; + } + } + } + return TRUE; +} + +/*! + Returns the file size. + \sa at() +*/ + +uint QFile::size() const +{ + STATBUF st; + if ( isOpen() ) { + FSTAT( fh ? FILENO(fh) : fd, &st ); + return st.st_size; + } else { +#if defined(__CYGWIN32_) + STAT( QFile::encodeName(fn), &st ); +#else + QString str = fn; + reslashify(str); +#ifdef QT_LARGEFILE_SUPPORT + if ( _wstati64( (wchar_t*) str.ucs2(), &st ) != -1 ) { +#else + if ( _wstat( (wchar_t*) str.ucs2(), &st ) != -1 ) { +#endif +#endif + return st.st_size; + } + } + return 0; +} + +/*! + \fn int QFile::at() const + Returns the file index. + \sa size() +*/ + +/*! + Sets the file index to \e pos. Returns TRUE if successful, otherwise FALSE. + + Example: + \code + QFile f( "data.bin" ); + f.open( IO_ReadOnly ); // index set to 0 + f.at( 100 ); // set index to 100 + f.at( f.at()+50 ); // set index to 150 + f.at( f.size()-80 ); // set index to 80 before EOF + f.close(); + \endcode + + \warning The result is undefined if the file was \link open() opened\endlink + using the \c IO_Append specifier. + + \sa size(), open() +*/ + +bool QFile::at( int pos ) +{ + if ( !isOpen() ) { +#if defined(CHECK_STATE) + qWarning( "QFile::at: File is not open" ); +#endif + return FALSE; + } + bool ok; + if ( isRaw() ) { // raw file + pos = (int)LSEEK(fd, pos, SEEK_SET); + ok = pos != -1; + } else { // buffered file + ok = fseek(fh, pos, SEEK_SET) == 0; + } + if ( ok ) + ioIndex = pos; +#if defined(CHECK_RANGE) + else + qWarning( "QFile::at: Cannot set file position %d", pos ); +#endif + return ok; +} + +/*! + Reads at most \e len bytes from the file into \e p and returns the + number of bytes actually read. + + Returns -1 if a serious error occurred. + + \warning We have experienced problems with some C libraries when a buffered + file is opened for both reading and writing. If a read operation takes place + immediately after a write operation, the read buffer contains garbage data. + Worse, the same garbage is written to the file. Calling flush() before + readBlock() solved this problem. + + \sa writeBlock() +*/ + +int QFile::readBlock( char *p, uint len ) +{ +#if defined(CHECK_NULL) + if ( !p ) + qWarning( "QFile::readBlock: Null pointer error" ); +#endif +#if defined(CHECK_STATE) + if ( !isOpen() ) { // file not open + qWarning( "QFile::readBlock: File not open" ); + return -1; + } + if ( !isReadable() ) { // reading not permitted + qWarning( "QFile::readBlock: Read operation not permitted" ); + return -1; + } +#endif + int nread; // number of bytes read + if ( isRaw() ) { // raw file + nread = READ( fd, p, len ); + if ( len && nread <= 0 ) { + nread = 0; + setStatus(IO_ReadError); + } + } else { // buffered file + nread = fread( p, 1, len, fh ); + if ( (uint)nread != len ) { + if ( ferror( fh ) || nread==0 ) + setStatus(IO_ReadError); + } + } + ioIndex += nread; + return nread; +} + +/*! \overload int writeBlock( const QByteArray& data ) +*/ + +/*! \reimp + + Writes \e len bytes from \e p to the file and returns the number of + bytes actually written. + + Returns -1 if a serious error occurred. + + \warning When working with buffered files, data may not be written + to the file at once. Call flush() to make sure the data is really + written. + + \sa readBlock() +*/ + +int QFile::writeBlock( const char *p, uint len ) +{ +#if defined(CHECK_NULL) + if ( p == 0 && len != 0 ) + qWarning( "QFile::writeBlock: Null pointer error" ); +#endif +#if defined(CHECK_STATE) + if ( !isOpen() ) { // file not open + qWarning( "QFile::writeBlock: File not open" ); + return -1; + } + if ( !isWritable() ) { // writing not permitted + qWarning( "QFile::writeBlock: Write operation not permitted" ); + return -1; + } +#endif + int nwritten; // number of bytes written + if ( isRaw() ) // raw file + nwritten = WRITE( fd, p, len ); + else // buffered file + nwritten = fwrite( p, 1, len, fh ); + if ( nwritten != (int)len ) { // write error + if ( errno == ENOSPC ) // disk is full + setStatus( IO_ResourceError ); + else + setStatus( IO_WriteError ); + if ( isRaw() ) // recalc file position + ioIndex = (int)LSEEK( fd, 0, SEEK_CUR ); + else + ioIndex = fseek( fh, 0, SEEK_CUR ); + } else { + ioIndex += nwritten; + } + if ( ioIndex > length ) // update file length + length = ioIndex; + return nwritten; +} + +/*! + Returns the file handle of the file. + + This is a small positive integer, suitable for use with C library + functions such as fdopen() and fcntl(), as well as with QSocketNotifier. + + If the file is not open or there is an error, handle() returns -1. + + \sa QSocketNotifier +*/ + +int QFile::handle() const +{ + if ( !isOpen() ) + return -1; + else if ( fh ) + return FILENO( fh ); + else + return fd; +} + +/*! + Closes an open file. + + The file is not closed if it was opened with an existing file handle. + If the existing file handle is a \c FILE*, the file is flushed. + If the existing file handle is an \c int file descriptor, nothing + is done to the file. + + Some "write-behind" filesystems may report an unspecified error on + closing the file. These errors only indicate that something may + have gone wrong since the previous open(). In such a case status() + reports IO_UnspecifiedError after close(), otherwise IO_Ok. + + \sa open(), flush() +*/ + + +void QFile::close() +{ + bool ok = FALSE; + if ( isOpen() ) { // file is not open + if ( fh ) { // buffered file + if ( ext_f ) + ok = fflush( fh ) != -1; // flush instead of closing + else + ok = fclose( fh ) != -1; + } else { // raw file + if ( ext_f ) + ok = TRUE; // cannot close + else + ok = CLOSE( fd ) != -1; + } + init(); // restore internal state + } + if (!ok) + setStatus (IO_UnspecifiedError); + + return; +} + +int64 QFile::pos() const +{ + if (isOpen()) + { + // TODO: support 64 bit size + return ftell( fh ); + } + return -1; +} + +int64 QFile::toEnd() +{ + if (isOpen()) + { + // TODO: support 64 bit size + if (fseek( fh, 0, SEEK_END )!=-1) + { + return ftell( fh ); + } + } + return -1; +} + +bool QFile::seek( int64 pos ) +{ + if (isOpen()) + { + // TODO: support 64 bit size + return fseek( fh, pos, SEEK_SET )!=-1; + } + return FALSE; +} + + + diff --git a/trunk/qtools/qfiledefs_p.h b/trunk/qtools/qfiledefs_p.h new file mode 100644 index 0000000..5105c45 --- /dev/null +++ b/trunk/qtools/qfiledefs_p.h @@ -0,0 +1,261 @@ +/**************************************************************************** +** +** +** Common macros and system include files for QFile, QFileInfo and QDir. +** +** Created : 930812 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QFILEDEFS_P_H +#define QFILEDEFS_P_H + + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of qfile.cpp, qfileinfo.cpp and qdir.cpp. +// This header file may change from version to version without notice, +// or even be removed. +// +// +#if defined(_CC_MWERKS_) +# include <stdlib.h> +# include <stat.h> +#elif !defined(_OS_MAC_) +# include <sys/types.h> +# include <sys/stat.h> +#elif defined(_OS_MAC_) +# include <sys/types.h> +# include <sys/stat.h> +# define _OS_UNIX_ +#endif +#include <fcntl.h> +#include <errno.h> +#if defined(_OS_UNIX_) +# include <dirent.h> +# include <unistd.h> +#endif +#if defined(_OS_MSDOS_) || defined(_OS_WIN32_) || defined(_OS_OS2_) +# define _OS_FATFS_ +# if defined(__CYGWIN32__) +# include <dirent.h> +# include <unistd.h> +# if !defined(_OS_UNIX_) +# define _OS_UNIX_ +# endif +# else +# include <io.h> +# if !defined(_CC_MWERKS_) +# include <dos.h> +# endif +# include <direct.h> +# endif +#endif +#include <limits.h> + + +#if !defined(PATH_MAX) +#if defined( MAXPATHLEN ) +#define PATH_MAX MAXPATHLEN +#else +#define PATH_MAX 1024 +#endif +#endif + + +#undef STATBUF +#undef STAT +#undef STAT_REG +#undef STAT_DIR +#undef STAT_LNK +#undef STAT_MASK +#undef FILENO +#undef OPEN +#undef CLOSE +#undef LSEEK +#undef READ +#undef WRITE +#undef ACCESS +#undef GETCWD +#undef CHDIR +#undef MKDIR +#undef RMDIR +#undef OPEN_RDONLY +#undef OPEN_WRONLY +#undef OPEN_CREAT +#undef OPEN_TRUNC +#undef OPEN_APPEND +#undef OPEN_TEXT +#undef OPEN_BINARY + + +#if defined(_CC_MSVC_) || defined(_CC_SYM_) + +# define STATBUF struct _stat // non-ANSI defs +# define STATBUF4TSTAT struct _stat // non-ANSI defs +# define STAT ::_stat +# define FSTAT ::_fstat +# define STAT_REG _S_IFREG +# define STAT_DIR _S_IFDIR +# define STAT_MASK _S_IFMT +# if defined(_S_IFLNK) +# define STAT_LNK _S_IFLNK +# endif +# define FILENO _fileno +# define OPEN ::_open +# define CLOSE ::_close +# define LSEEK ::_lseek +# define READ ::_read +# define WRITE ::_write +# define ACCESS ::_access +# define GETCWD ::_getcwd +# define CHDIR ::_chdir +# define MKDIR ::_mkdir +# define RMDIR ::_rmdir +# define OPEN_RDONLY _O_RDONLY +# define OPEN_WRONLY _O_WRONLY +# define OPEN_RDWR _O_RDWR +# define OPEN_CREAT _O_CREAT +# define OPEN_TRUNC _O_TRUNC +# define OPEN_APPEND _O_APPEND +# if defined(O_TEXT) +# define OPEN_TEXT _O_TEXT +# define OPEN_BINARY _O_BINARY +# endif + +#elif defined(_CC_BOR_) && __BORLANDC__ >= 0x550 + +# define STATBUF struct stat // non-ANSI defs +# define STATBUF4TSTAT struct _stat // non-ANSI defs +# define STAT ::stat +# define FSTAT ::fstat +# define STAT_REG _S_IFREG +# define STAT_DIR _S_IFDIR +# define STAT_MASK _S_IFMT +# if defined(_S_IFLNK) +# define STAT_LNK _S_IFLNK +# endif +# define FILENO _fileno +# define OPEN ::open +# define CLOSE ::_close +# define LSEEK ::_lseek +# define READ ::_read +# define WRITE ::_write +# define ACCESS ::_access +# define GETCWD ::_getcwd +# define CHDIR ::chdir +# define MKDIR ::_mkdir +# define RMDIR ::_rmdir +# define OPEN_RDONLY _O_RDONLY +# define OPEN_WRONLY _O_WRONLY +# define OPEN_RDWR _O_RDWR +# define OPEN_CREAT _O_CREAT +# define OPEN_TRUNC _O_TRUNC +# define OPEN_APPEND _O_APPEND +# if defined(O_TEXT) +# define OPEN_TEXT _O_TEXT +# define OPEN_BINARY _O_BINARY +# endif + +#else // all other systems + +# define STATBUF struct stat +# define STATBUF4TSTAT struct stat +# define STAT ::stat +# define FSTAT ::fstat +# define STAT_REG S_IFREG +# define STAT_DIR S_IFDIR +# define STAT_MASK S_IFMT +# if defined(S_IFLNK) +# define STAT_LNK S_IFLNK +# endif +# define FILENO fileno +# define OPEN ::open +# define CLOSE ::close +# define LSEEK ::lseek +# define READ ::read +# define WRITE ::write +# define ACCESS ::access +# if defined(_OS_OS2EMX_) +# define GETCWD ::_getcwd2 +# define CHDIR ::_chdir2 +# else +# define GETCWD ::getcwd +# define CHDIR ::chdir +# endif +# define MKDIR ::mkdir +# define RMDIR ::rmdir +# define OPEN_RDONLY O_RDONLY +# define OPEN_WRONLY O_WRONLY +# define OPEN_RDWR O_RDWR +# define OPEN_CREAT O_CREAT +# define OPEN_TRUNC O_TRUNC +# define OPEN_APPEND O_APPEND +# if defined(O_TEXT) +# define OPEN_TEXT O_TEXT +# define OPEN_BINARY O_BINARY +# endif +#endif + +#if defined(_CC_MWERKS_) +#undef mkdir +#undef MKDIR +#define MKDIR _mkdir +#undef rmdir +#undef RMDIR +#define RMDIR _rmdir +#endif + + +#if defined(_OS_FATFS_) +# define F_OK 0 +# define X_OK 1 +# define W_OK 2 +# define R_OK 4 +#endif + +#if defined(_OS_MAC_) && !defined(_OS_UNIX_) +# define F_OK 0 +# define X_OK 1 +# define W_OK 2 +# define R_OK 4 +#endif + +struct QFileInfoCache +{ + STATBUF st; + bool isSymLink; +}; + +#endif diff --git a/trunk/qtools/qfileinfo.cpp b/trunk/qtools/qfileinfo.cpp new file mode 100644 index 0000000..5053b76 --- /dev/null +++ b/trunk/qtools/qfileinfo.cpp @@ -0,0 +1,458 @@ +/**************************************************************************** +** +** +** Implementation of QFileInfo class +** +** Created : 950628 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "qglobal.h" + +#include "qfileinfo.h" +#include "qfiledefs_p.h" +#include "qdatetime.h" +#include "qdir.h" + +extern bool qt_file_access( const QString& fn, int t ); + +// NOT REVISED +/*! + \class QFileInfo qfileinfo.h + \brief The QFileInfo class provides system-independent file information. + + \ingroup io + + QFileInfo provides information about a file's name and position (path) in + the file system, its access rights and whether it is a directory or a + symbolic link. Its size and last modified/read times are also available. + + To speed up performance QFileInfo caches information about the file. Since + files can be changed by other users or programs, or even by other parts of + the same program there is a function that refreshes the file information; + refresh(). If you would rather like a QFileInfo to access the file system + every time you request information from it, you can call the function + setCaching( FALSE ). + + A QFileInfo can point to a file using either a relative or an absolute + file path. Absolute file paths begin with the directory separator + ('/') or a drive specification (not applicable to UNIX). + Relative file names begin with a directory name or a file name and specify + a path relative to the current directory. An example of + an absolute path is the string "/tmp/quartz". A relative path might look like + "src/fatlib". You can use the function isRelative() to check if a QFileInfo + is using a relative or an absolute file path. You can call the function + convertToAbs() to convert a relative QFileInfo to an absolute one. + + If you need to read and traverse directories, see the QDir class. +*/ + + +/*! + Constructs a new empty QFileInfo. +*/ + +QFileInfo::QFileInfo() +{ + fic = 0; + cache = TRUE; +} + +/*! + Constructs a new QFileInfo that gives information about the given file. + The string given can be an absolute or a relative file path. + + \sa bool setFile(QString ), isRelative(), QDir::setCurrent(), + QDir::isRelativePath() +*/ + +QFileInfo::QFileInfo( const QString &file ) +{ + fn = file; + slashify( fn ); + fic = 0; + cache = TRUE; +} + +/*! + Constructs a new QFileInfo that gives information about \e file. + + If the file has a relative path, the QFileInfo will also have one. + + \sa isRelative() +*/ + +QFileInfo::QFileInfo( const QFile &file ) +{ + fn = file.name(); + slashify( fn ); + fic = 0; + cache = TRUE; +} + +/*! + Constructs a new QFileInfo that gives information about the file + named \e fileName in the directory \e d. + + If the directory has a relative path, the QFileInfo will also have one. + + \sa isRelative() +*/ +#ifndef QT_NO_DIR +QFileInfo::QFileInfo( const QDir &d, const QString &fileName ) +{ + fn = d.filePath( fileName ); + slashify( fn ); + fic = 0; + cache = TRUE; +} +#endif +/*! + Constructs a new QFileInfo that is a copy of \e fi. +*/ + +QFileInfo::QFileInfo( const QFileInfo &fi ) +{ + fn = fi.fn; + if ( fi.fic ) { + fic = new QFileInfoCache; + *fic = *fi.fic; + } else { + fic = 0; + } + cache = fi.cache; +} + +/*! + Destructs the QFileInfo. +*/ + +QFileInfo::~QFileInfo() +{ + delete fic; +} + + +/*! + Makes a copy of \e fi and assigns it to this QFileInfo. +*/ + +QFileInfo &QFileInfo::operator=( const QFileInfo &fi ) +{ + fn = fi.fn; + if ( !fi.fic ) { + delete fic; + fic = 0; + } else { + if ( !fic ) { + fic = new QFileInfoCache; + CHECK_PTR( fic ); + } + *fic = *fi.fic; + } + cache = fi.cache; + return *this; +} + + +/*! + Sets the file to obtain information about. + + The string given can be an absolute or a relative file path. Absolute file + paths begin with the directory separator (e.g. '/' under UNIX) or a drive + specification (not applicable to UNIX). Relative file names begin with a + directory name or a file name and specify a path relative to the current + directory. + + Example: + \code + #include <qfileinfo.h> + #include <qdir.h> + + void test() + { + QString absolute = "/liver/aorta"; + QString relative = "liver/aorta"; + QFileInfo fi1( absolute ); + QFileInfo fi2( relative ); + + QDir::setCurrent( QDir::rootDirPath() ); + // fi1 and fi2 now point to the same file + + QDir::setCurrent( "/tmp" ); + // fi1 now points to "/liver/aorta", + // while fi2 points to "/tmp/liver/aorta" + } + \endcode + + \sa isRelative(), QDir::setCurrent(), QDir::isRelativePath() +*/ + +void QFileInfo::setFile( const QString &file ) +{ + fn = file; + slashify( fn ); + delete fic; + fic = 0; +} + +/*! + Sets the file to obtain information about. + + If the file has a relative path, the QFileInfo will also have one. + + \sa isRelative() +*/ + +void QFileInfo::setFile( const QFile &file ) +{ + fn = file.name(); + slashify( fn ); + delete fic; + fic = 0; +} + +/*! + Sets the file to obtains information about to \e fileName in the + directory \e d. + + If the directory has a relative path, the QFileInfo will also have one. + + \sa isRelative() +*/ +#ifndef QT_NO_DIR +void QFileInfo::setFile( const QDir &d, const QString &fileName ) +{ + fn = d.filePath( fileName ); + slashify( fn ); + delete fic; + fic = 0; +} +#endif + +/*! + Returns TRUE if the file pointed to exists, otherwise FALSE. +*/ + +bool QFileInfo::exists() const +{ + return qt_file_access( fn, F_OK ); +} + +/*! + Refresh the information about the file, i.e. read in information from the + file system the next time a cached property is fetched. + + \sa setCaching() +*/ + +void QFileInfo::refresh() const +{ + QFileInfo *that = (QFileInfo*)this; // Mutable function + delete that->fic; + that->fic = 0; +} + +/*! + \fn bool QFileInfo::caching() const + Returns TRUE if caching is enabled. + \sa setCaching(), refresh() +*/ + +/*! + Enables caching of file information if \e enable is TRUE, or disables it + if \e enable is FALSE. + + When caching is enabled, QFileInfo reads the file information the first + time + + Caching is enabled by default. + + \sa refresh(), caching() +*/ + +void QFileInfo::setCaching( bool enable ) +{ + if ( cache == enable ) + return; + cache = enable; + if ( cache ) { + delete fic; + fic = 0; + } +} + + +/*! + Returns the name, i.e. the file name including the path (which can be + absolute or relative). + + \sa isRelative(), absFilePath() +*/ + +QString QFileInfo::filePath() const +{ + return fn; +} + +/*! + Returns the base name of the file. + + The base name consists of all characters in the file name up to (but not + including) the first '.' character. The path is not included. + + Example: + \code + QFileInfo fi( "/tmp/abdomen.lower" ); + QString base = fi.baseName(); // base = "abdomen" + \endcode + + \sa fileName(), extension() +*/ + +QString QFileInfo::baseName() const +{ + QString tmp = fileName(); + int pos = tmp.find( '.' ); + if ( pos == -1 ) + return tmp; + else + return tmp.left( pos ); +} + +/*! + Returns the extension name of the file. + + If \a complete is TRUE (the default), extension() returns the string + of all characters in the file name after (but not including) the + first '.' character. For a file named "archive.tar.gz" this + returns "tar.gz". + + If \a complete is FALSE, extension() returns the string of all + characters in the file name after (but not including) the last '.' + character. For a file named "archive.tar.gz" this returns "gz". + + Example: + \code + QFileInfo fi( "lex.yy.c" ); + QString ext = fi.extension(); // ext = "yy.c" + QString ext = fi.extension( FALSE ); // ext = "c" + \endcode + + \sa fileName(), baseName() + +*/ + +QString QFileInfo::extension( bool complete ) const +{ + QString s = fileName(); + int pos = complete ? s.find( '.' ) : s.findRev( '.' ); + if ( pos < 0 ) + return QString::fromLatin1( "" ); + else + return s.right( s.length() - pos - 1 ); +} + +/*! + Returns the directory path of the file. + + If the QFileInfo is relative and \e absPath is FALSE, the QDir will be + relative, otherwise it will be absolute. + + \sa dirPath(), filePath(), fileName(), isRelative() +*/ +#ifndef QT_NO_DIR +QDir QFileInfo::dir( bool absPath ) const +{ + return QDir( dirPath(absPath) ); +} +#endif + + +/*! + Returns TRUE if the file is readable. + \sa isWritable(), isExecutable(), permission() +*/ + +bool QFileInfo::isReadable() const +{ + return qt_file_access( fn, R_OK ); +} + +/*! + Returns TRUE if the file is writable. + \sa isReadable(), isExecutable(), permission() +*/ + +bool QFileInfo::isWritable() const +{ + return qt_file_access( fn, W_OK ); +} + +/*! + Returns TRUE if the file is executable. + \sa isReadable(), isWritable(), permission() +*/ + +bool QFileInfo::isExecutable() const +{ + return qt_file_access( fn, X_OK ); +} + + +/*! + Returns TRUE if the file path name is relative to the current directory, + FALSE if the path is absolute (e.g. under UNIX a path is relative if it + does not start with a '/'). + + According to Einstein this function should always return TRUE. +*/ +#ifndef QT_NO_DIR +bool QFileInfo::isRelative() const +{ + return QDir::isRelativePath( fn ); +} + +/*! + Converts the file path name to an absolute path. + + If it is already absolute nothing is done. + + \sa filePath(), isRelative() +*/ + +bool QFileInfo::convertToAbs() +{ + if ( isRelative() ) + fn = absFilePath(); + return QDir::isRelativePath( fn ); +} +#endif diff --git a/trunk/qtools/qfileinfo.h b/trunk/qtools/qfileinfo.h new file mode 100644 index 0000000..76ef8c2 --- /dev/null +++ b/trunk/qtools/qfileinfo.h @@ -0,0 +1,138 @@ +/**************************************************************************** +** +** +** Definition of QFileInfo class +** +** Created : 950628 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QFILEINFO_H +#define QFILEINFO_H + +#ifndef QT_H +#include "qfile.h" +#include "qdatetime.h" +#endif // QT_H + + +class QDir; +struct QFileInfoCache; + + +class Q_EXPORT QFileInfo // file information class +{ +public: + enum PermissionSpec { + ReadUser = 0400, WriteUser = 0200, ExeUser = 0100, + ReadGroup = 0040, WriteGroup = 0020, ExeGroup = 0010, + ReadOther = 0004, WriteOther = 0002, ExeOther = 0001 }; + + QFileInfo(); + QFileInfo( const QString &file ); + QFileInfo( const QFile & ); +#ifndef QT_NO_DIR + QFileInfo( const QDir &, const QString &fileName ); +#endif + QFileInfo( const QFileInfo & ); + ~QFileInfo(); + + QFileInfo &operator=( const QFileInfo & ); + + void setFile( const QString &file ); + void setFile( const QFile & ); +#ifndef QT_NO_DIR + void setFile( const QDir &, const QString &fileName ); +#endif + bool exists() const; + void refresh() const; + bool caching() const; + void setCaching( bool ); + + QString filePath() const; + QString fileName() const; +#ifndef QT_NO_DIR //### + QString absFilePath() const; +#endif + QString baseName() const; + QString extension( bool complete = TRUE ) const; + +#ifndef QT_NO_DIR //### + QString dirPath( bool absPath = FALSE ) const; +#endif +#ifndef QT_NO_DIR + QDir dir( bool absPath = FALSE ) const; +#endif + bool isReadable() const; + bool isWritable() const; + bool isExecutable() const; + +#ifndef QT_NO_DIR //### + bool isRelative() const; + bool convertToAbs(); +#endif + + bool isFile() const; + bool isDir() const; + bool isSymLink() const; + + QString readLink() const; + + QString owner() const; + uint ownerId() const; + QString group() const; + uint groupId() const; + + bool permission( int permissionSpec ) const; + + uint size() const; + + QDateTime lastModified() const; + QDateTime lastRead() const; + +private: + void doStat() const; + static void slashify( QString & ); + static void makeAbs( QString & ); + + QString fn; + QFileInfoCache *fic; + bool cache; +}; + + +inline bool QFileInfo::caching() const +{ + return cache; +} + + +#endif // QFILEINFO_H diff --git a/trunk/qtools/qfileinfo_unix.cpp b/trunk/qtools/qfileinfo_unix.cpp new file mode 100644 index 0000000..5a8fe04 --- /dev/null +++ b/trunk/qtools/qfileinfo_unix.cpp @@ -0,0 +1,425 @@ +/**************************************************************************** +** +** +** Implementation of QFileInfo class +** +** Created : 950628 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses for Unix/X11 or for Qt/Embedded may use this file in accordance +** with the Qt Commercial License Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "qglobal.h" + +#if defined(_OS_SUN_) +#define readlink _qt_hide_readlink +#endif + +#include <pwd.h> +#include <grp.h> + +#include "qfileinfo.h" +#include "qfiledefs_p.h" +#include "qdatetime.h" +#include "qdir.h" + +#if defined(_OS_SUN_) +#undef readlink +extern "C" int readlink( const char *, void *, uint ); +#endif + + +void QFileInfo::slashify( QString& ) +{ + return; +} + + +void QFileInfo::makeAbs( QString & ) +{ + return; +} + +extern bool qt_file_access( const QString& fn, int t ); + +/*! + Returns TRUE if we are pointing to a real file. + \sa isDir(), isSymLink() +*/ +bool QFileInfo::isFile() const +{ + if ( !fic || !cache ) + doStat(); + return fic ? (fic->st.st_mode & STAT_MASK) == STAT_REG : FALSE; +} + +/*! + Returns TRUE if we are pointing to a directory or a symbolic link to + a directory. + \sa isFile(), isSymLink() +*/ + +bool QFileInfo::isDir() const +{ + if ( !fic || !cache ) + doStat(); + return fic ? (fic->st.st_mode & STAT_MASK) == STAT_DIR : FALSE; +} + +/*! + Returns TRUE if we are pointing to a symbolic link. + \sa isFile(), isDir(), readLink() +*/ + +bool QFileInfo::isSymLink() const +{ + if ( !fic || !cache ) + doStat(); + return fic ? fic->isSymLink : FALSE; +} + + +/*! + Returns the name a symlink points to, or a null QString if the + object does not refer to a symbolic link. + + This name may not represent an existing file; it is only a string. + QFileInfo::exists() returns TRUE if the symlink points to an + existing file. + + \sa exists(), isSymLink(), isDir(), isFile() +*/ + +QString QFileInfo::readLink() const +{ + QString r; + +#if defined(_OS_UNIX_) && !defined(_OS_OS2EMX_) + char s[PATH_MAX+1]; + if ( !isSymLink() ) + return QString(); + int len = readlink( QFile::encodeName(fn).data(), s, PATH_MAX ); + if ( len >= 0 ) { + s[len] = '\0'; + r = QFile::decodeName(s); + } +#endif + + return r; +} + +static const uint nobodyID = (uint) -2; + +/*! + Returns the owner of the file. + + On systems where files do not have owners this function returns 0. + + Note that this function can be time-consuming under UNIX. (in the order + of milliseconds on a 486 DX2/66 running Linux). + + \sa ownerId(), group(), groupId() +*/ + +QString QFileInfo::owner() const +{ + passwd *pw = getpwuid( ownerId() ); + if ( pw ) + return QFile::decodeName( pw->pw_name ); + return QString::null; +} + +/*! + Returns the id of the owner of the file. + + On systems where files do not have owners this function returns ((uint) -2). + + \sa owner(), group(), groupId() +*/ + +uint QFileInfo::ownerId() const +{ + if ( !fic || !cache ) + doStat(); + if ( fic ) + return fic->st.st_uid; + return nobodyID; +} + +/*! + Returns the group the file belongs to. + + On systems where files do not have groups this function always + returns 0. + + Note that this function can be time-consuming under UNIX (in the order of + milliseconds on a 486 DX2/66 running Linux). + + \sa groupId(), owner(), ownerId() +*/ + +QString QFileInfo::group() const +{ + struct group *gr = getgrgid( groupId() ); + if ( gr ) + return QFile::decodeName( gr->gr_name ); + return QString::null; +} + +/*! + Returns the id of the group the file belongs to. + + On systems where files do not have groups this function always + returns ((uind) -2). + + \sa group(), owner(), ownerId() +*/ + +uint QFileInfo::groupId() const +{ + if ( !fic || !cache ) + doStat(); + if ( fic ) + return fic->st.st_gid; + return nobodyID; +} + + +/*! + \fn bool QFileInfo::permission( int permissionSpec ) const + + Tests for file permissions. The \e permissionSpec argument can be several + flags of type PermissionSpec or'ed together to check for permission + combinations. + + On systems where files do not have permissions this function always + returns TRUE. + + Example: + \code + QFileInfo fi( "/tmp/tonsils" ); + if ( fi.permission( QFileInfo::WriteUser | QFileInfo::ReadGroup ) ) + qWarning( "Tonsils can be changed by me, and the group can read them."); + if ( fi.permission( QFileInfo::WriteGroup | QFileInfo::WriteOther ) ) + qWarning( "Danger! Tonsils can be changed by the group or others!" ); + \endcode + + \sa isReadable(), isWritable(), isExecutable() +*/ + +bool QFileInfo::permission( int permissionSpec ) const +{ + if ( !fic || !cache ) + doStat(); + if ( fic ) { + uint mask = 0; + if ( permissionSpec & ReadUser) + mask |= S_IRUSR; + if ( permissionSpec & WriteUser) + mask |= S_IWUSR; + if ( permissionSpec & ExeUser) + mask |= S_IXUSR; + if ( permissionSpec & ReadGroup) + mask |= S_IRGRP; + if ( permissionSpec & WriteGroup) + mask |= S_IWGRP; + if ( permissionSpec & ExeGroup) + mask |= S_IXGRP; + if ( permissionSpec & ReadOther) + mask |= S_IROTH; + if ( permissionSpec & WriteOther) + mask |= S_IWOTH; + if ( permissionSpec & ExeOther) + mask |= S_IXOTH; + if ( mask ) { + return (fic->st.st_mode & mask) == mask; + } else { +#if defined(CHECK_NULL) + qWarning( "QFileInfo::permission: permissionSpec is 0" ); +#endif + return TRUE; + } + } else { + return FALSE; + } +} + +/*! + Returns the file size in bytes, or 0 if the file does not exist if the size + cannot be fetched. +*/ + +uint QFileInfo::size() const +{ + if ( !fic || !cache ) + doStat(); + if ( fic ) + return (uint)fic->st.st_size; + else + return 0; +} + + +/*! + Returns the date and time when the file was last modified. + \sa lastRead() +*/ + +QDateTime QFileInfo::lastModified() const +{ + QDateTime dt; + if ( !fic || !cache ) + doStat(); + if ( fic ) + dt.setTime_t( fic->st.st_mtime ); + return dt; +} + +/*! + Returns the date and time when the file was last read (accessed). + + On systems that do not support last read times, the modification time is + returned. + + \sa lastModified() +*/ + +QDateTime QFileInfo::lastRead() const +{ + QDateTime dt; + if ( !fic || !cache ) + doStat(); + if ( fic ) + dt.setTime_t( fic->st.st_atime ); + return dt; +} + + +void QFileInfo::doStat() const +{ + QFileInfo *that = ((QFileInfo*)this); // mutable function + if ( !that->fic ) + that->fic = new QFileInfoCache; + STATBUF *b = &that->fic->st; + that->fic->isSymLink = FALSE; + +#if defined(_OS_UNIX_) && defined(S_IFLNK) + if ( ::lstat(QFile::encodeName(fn),b) == 0 ) { + if ( S_ISLNK( b->st_mode ) ) + that->fic->isSymLink = TRUE; + else + return; + } +#endif + int r; + + r = STAT( QFile::encodeName(fn), b ); + + if ( r != 0 ) { + delete that->fic; + that->fic = 0; + } +} + +/*! + Returns the directory path of the file. + + If \e absPath is TRUE an absolute path is always returned. + + \sa dir(), filePath(), fileName(), isRelative() +*/ +#ifndef QT_NO_DIR +QString QFileInfo::dirPath( bool absPath ) const +{ + QString s; + if ( absPath ) + s = absFilePath(); + else + s = fn; + int pos = s.findRev( '/' ); + if ( pos == -1 ) { + return QString::fromLatin1("."); + } else { + if ( pos == 0 ) + return QString::fromLatin1( "/" ); + return s.left( pos ); + } +} +#endif +/*! + Returns the name of the file, the file path is not included. + + Example: + \code + QFileInfo fi( "/tmp/abdomen.lower" ); + QString name = fi.fileName(); // name = "abdomen.lower" + \endcode + + \sa isRelative(), filePath(), baseName(), extension() +*/ + +QString QFileInfo::fileName() const +{ + int p = fn.findRev( '/' ); + if ( p == -1 ) { + return fn; + } else { + return fn.mid(p+1); + } +} + +/*! + Returns the absolute path name. + + The absolute path name is the file name including the absolute path. If + the QFileInfo is absolute (i.e. not relative) this function will return + the same string as filePath(). + + Note that this function can be time-consuming under UNIX. (in the order + of milliseconds on a 486 DX2/66 running Linux). + + \sa isRelative(), filePath() +*/ +#ifndef QT_NO_DIR +QString QFileInfo::absFilePath() const +{ + if ( QDir::isRelativePath(fn) ) { + QString tmp = QDir::currentDirPath(); + tmp += '/'; + tmp += fn; + makeAbs( tmp ); + return QDir::cleanDirPath( tmp ); + } else { + QString tmp = fn; + makeAbs( tmp ); + return QDir::cleanDirPath( tmp ); + } + +} +#endif diff --git a/trunk/qtools/qfileinfo_win32.cpp b/trunk/qtools/qfileinfo_win32.cpp new file mode 100644 index 0000000..8f83107 --- /dev/null +++ b/trunk/qtools/qfileinfo_win32.cpp @@ -0,0 +1,356 @@ +/****************************************************************************** + * + * + * + * 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. + * + * Based on qfileinfo_unix.cpp + * + * Copyright (C) 1992-2000 Trolltech AS. + */ + +#include "qglobal.h" + +#include "qfileinfo.h" +#include "qfiledefs_p.h" +#include "qdatetime.h" +#include "qdir.h" + +static void reslashify( QString& n ) +{ + for ( int i=0; i<(int)n.length(); i++ ) + { + if ( n[i] == '/' ) + n[i] = '\\'; + } +} + +void QFileInfo::slashify( QString& n ) +{ + for ( int i=0; i<(int)n.length(); i++ ) + { + if ( n[i] == '\\' ) + n[i] = '/'; + } +} + +void QFileInfo::makeAbs( QString & ) +{ + // TODO: what to do here? + return; +} + +extern bool qt_file_access( const QString& fn, int t ); + +/*! + Returns TRUE if we are pointing to a real file. + \sa isDir(), isSymLink() +*/ +bool QFileInfo::isFile() const +{ + if ( !fic || !cache ) + doStat(); + return fic ? (fic->st.st_mode & STAT_MASK) == STAT_REG : FALSE; +} + +/*! + Returns TRUE if we are pointing to a directory or a symbolic link to + a directory. + \sa isFile(), isSymLink() +*/ + +bool QFileInfo::isDir() const +{ + if ( !fic || !cache ) + doStat(); + return fic ? (fic->st.st_mode & STAT_MASK) == STAT_DIR : FALSE; +} + +/*! + Returns TRUE if we are pointing to a symbolic link. + \sa isFile(), isDir(), readLink() +*/ + +bool QFileInfo::isSymLink() const +{ + if ( !fic || !cache ) + doStat(); + return fic ? fic->isSymLink : FALSE; +} + + +/*! + Returns the name a symlink points to, or a null QString if the + object does not refer to a symbolic link. + + This name may not represent an existing file; it is only a string. + QFileInfo::exists() returns TRUE if the symlink points to an + existing file. + + \sa exists(), isSymLink(), isDir(), isFile() +*/ + +QString QFileInfo::readLink() const +{ + QString r; + return r; +} + +static const uint nobodyID = (uint) -2; + +/*! + Returns the owner of the file. + + On systems where files do not have owners this function returns + a null string. + + Note that this function can be time-consuming under UNIX. (in the order + of milliseconds on a 486 DX2/66 running Linux). + + \sa ownerId(), group(), groupId() +*/ + +QString QFileInfo::owner() const +{ + return QString::null; +} + +/*! + Returns the id of the owner of the file. + + On systems where files do not have owners this function returns ((uint) -2). + + \sa owner(), group(), groupId() +*/ + +uint QFileInfo::ownerId() const +{ + return (uint)-2; +} + +/*! + Returns the group the file belongs to. + + On systems where files do not have groups this function always + returns 0. + + Note that this function can be time-consuming under UNIX (in the order of + milliseconds on a 486 DX2/66 running Linux). + + \sa groupId(), owner(), ownerId() +*/ + +QString QFileInfo::group() const +{ + return QString::null; +} + +/*! + Returns the id of the group the file belongs to. + + On systems where files do not have groups this function always + returns ((uind) -2). + + \sa group(), owner(), ownerId() +*/ + +uint QFileInfo::groupId() const +{ + return (uint)-2; +} + + +/*! + \fn bool QFileInfo::permission( int permissionSpec ) const + + Tests for file permissions. The \e permissionSpec argument can be several + flags of type PermissionSpec or'ed together to check for permission + combinations. + + On systems where files do not have permissions this function always + returns TRUE. + + Example: + \code + QFileInfo fi( "/tmp/tonsils" ); + if ( fi.permission( QFileInfo::WriteUser | QFileInfo::ReadGroup ) ) + qWarning( "Tonsils can be changed by me, and the group can read them."); + if ( fi.permission( QFileInfo::WriteGroup | QFileInfo::WriteOther ) ) + qWarning( "Danger! Tonsils can be changed by the group or others!" ); + \endcode + + \sa isReadable(), isWritable(), isExecutable() +*/ + +bool QFileInfo::permission( int permissionSpec ) const +{ + return TRUE; +} + +/*! + Returns the file size in bytes, or 0 if the file does not exist if the size + cannot be fetched. +*/ + +uint QFileInfo::size() const +{ + if ( !fic || !cache ) + doStat(); + if ( fic ) + return (uint)fic->st.st_size; + else + return 0; +} + + +/*! + Returns the date and time when the file was last modified. + \sa lastRead() +*/ + +QDateTime QFileInfo::lastModified() const +{ + QDateTime dt; + if ( !fic || !cache ) + doStat(); + if ( fic ) + dt.setTime_t( fic->st.st_mtime ); + return dt; +} + +/*! + Returns the date and time when the file was last read (accessed). + + On systems that do not support last read times, the modification time is + returned. + + \sa lastModified() +*/ + +QDateTime QFileInfo::lastRead() const +{ + QDateTime dt; + if ( !fic || !cache ) + doStat(); + if ( fic ) + dt.setTime_t( fic->st.st_atime ); + return dt; +} + + +void QFileInfo::doStat() const +{ + QFileInfo *that = ((QFileInfo*)this); // mutable function + if ( !that->fic ) + that->fic = new QFileInfoCache; + STATBUF *b = &that->fic->st; + that->fic->isSymLink = FALSE; + +#if defined(__CYGWIN32_) + int r; + + r = STAT( QFile::encodeName(fn), b ); + + if ( r != 0 ) { + delete that->fic; + that->fic = 0; + } +#else + QString file = fn; + reslashify(file); +#ifdef QT_LARGEFILE_SUPPORT + if ( _wstati64( (wchar_t*) file.ucs2(), b ) == -1 ) { +#else + if ( _wstat( (wchar_t*) file.ucs2(), b ) == -1 ) { +#endif + delete that->fic; + that->fic = 0; + } +#endif +} + +/*! + Returns the directory path of the file. + + If \e absPath is TRUE an absolute path is always returned. + + \sa dir(), filePath(), fileName(), isRelative() +*/ +#ifndef QT_NO_DIR +QString QFileInfo::dirPath( bool absPath ) const +{ + QString s; + if ( absPath ) + s = absFilePath(); + else + s = fn; + int pos = s.findRev( '/' ); + if ( pos == -1 ) { + return QString::fromLatin1("."); + } else { + if ( pos == 0 ) + return QString::fromLatin1( "/" ); + return s.left( pos ); + } +} +#endif +/*! + Returns the name of the file, the file path is not included. + + Example: + \code + QFileInfo fi( "/tmp/abdomen.lower" ); + QString name = fi.fileName(); // name = "abdomen.lower" + \endcode + + \sa isRelative(), filePath(), baseName(), extension() +*/ + +QString QFileInfo::fileName() const +{ + int p = fn.findRev( '/' ); + if ( p == -1 ) { + return fn; + } else { + return fn.mid(p+1); + } +} + +/*! + Returns the absolute path name. + + The absolute path name is the file name including the absolute path. If + the QFileInfo is absolute (i.e. not relative) this function will return + the same string as filePath(). + + Note that this function can be time-consuming under UNIX. (in the order + of milliseconds on a 486 DX2/66 running Linux). + + \sa isRelative(), filePath() +*/ +#ifndef QT_NO_DIR +QString QFileInfo::absFilePath() const +{ + if ( QDir::isRelativePath(fn) ) { + QString tmp = QDir::currentDirPath(); + tmp += '/'; + tmp += fn; + makeAbs( tmp ); + return QDir::cleanDirPath( tmp ); + } else { + QString tmp = fn; + makeAbs( tmp ); + return QDir::cleanDirPath( tmp ); + } + +} +#endif diff --git a/trunk/qtools/qgarray.cpp b/trunk/qtools/qgarray.cpp new file mode 100644 index 0000000..efc9de0 --- /dev/null +++ b/trunk/qtools/qgarray.cpp @@ -0,0 +1,747 @@ +/**************************************************************************** +** +** +** Implementation of QGArray class +** +** Created : 930906 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#define QGARRAY_CPP +#include "qgarray.h" +#include "qstring.h" +#include <stdlib.h> + +#define USE_MALLOC // comment to use new/delete + +#undef NEW +#undef DELETE + +#if defined(USE_MALLOC) +#define NEW(type,size) ((type*)malloc(size*sizeof(type))) +#define DELETE(array) (free((char*)array)) +#else +#define NEW(type,size) (new type[size]) +#define DELETE(array) (delete[] array) +#define DONT_USE_REALLOC // comment to use realloc() +#endif + + +// NOT REVISED +/*! + \class QShared qshared.h + \brief The QShared struct is internally used for implementing shared classes. + + It only contains a reference count and member functions to increment and + decrement it. + + Shared classes normally have internal classes that inherit QShared and + add the shared data. + + \sa \link shclass.html Shared Classes\endlink +*/ + + +/*! + \class QGArray qgarray.h + \brief The QGArray class is an internal class for implementing the QArray class. + + QGArray is a strictly internal class that acts as base class for the + QArray template array. + + It contains an array of bytes and has no notion of an array element. +*/ + + +/*! + \internal + Constructs a null array. +*/ + +QGArray::QGArray() +{ + shd = newData(); + CHECK_PTR( shd ); +} + +/*! + \internal + Dummy constructor; does not allocate any data. + + This constructor does not initialize any array data so subclasses + must do it. The intention is to make the code more efficient. +*/ + +QGArray::QGArray( int, int ) +{ +} + +/*! + \internal + Constructs an array with room for \e size bytes. +*/ + +QGArray::QGArray( int size ) +{ + if ( size < 0 ) { +#if defined(CHECK_RANGE) + qWarning( "QGArray: Cannot allocate array with negative length" ); +#endif + size = 0; + } + shd = newData(); + CHECK_PTR( shd ); + if ( size == 0 ) // zero length + return; + shd->data = NEW(char,size); + CHECK_PTR( shd->data ); + shd->len = size; +} + +/*! + \internal + Constructs a shallow copy of \e a. +*/ + +QGArray::QGArray( const QGArray &a ) +{ + shd = a.shd; + shd->ref(); +} + +/*! + \internal + Dereferences the array data and deletes it if this was the last + reference. +*/ + +QGArray::~QGArray() +{ + if ( shd && shd->deref() ) { // delete when last reference + if ( shd->data ) // is lost + DELETE(shd->data); + deleteData( shd ); + } +} + + +/*! + \fn QGArray &QGArray::operator=( const QGArray &a ) + \internal + Assigns a shallow copy of \e a to this array and returns a reference to + this array. Equivalent to assign(). +*/ + +/*! + \fn void QGArray::detach() + \internal + Detaches this array from shared array data. +*/ + +/*! + \fn char *QGArray::data() const + \internal + Returns a pointer to the actual array data. +*/ + +/*! + \fn uint QGArray::nrefs() const + \internal + Returns the reference count. +*/ + +/*! + \fn uint QGArray::size() const + \internal + Returns the size of the array, in bytes. +*/ + + +/*! + \internal + Returns TRUE if this array is equal to \e a, otherwise FALSE. + The comparison is bitwise, of course. +*/ + +bool QGArray::isEqual( const QGArray &a ) const +{ + if ( size() != a.size() ) // different size + return FALSE; + if ( data() == a.data() ) // has same data + return TRUE; + return (size() ? memcmp( data(), a.data(), size() ) : 0) == 0; +} + + +/*! + \internal + Resizes the array to \e newsize bytes. +*/ + +bool QGArray::resize( uint newsize ) +{ + if ( newsize == shd->len ) // nothing to do + return TRUE; + if ( newsize == 0 ) { // remove array + duplicate( 0, 0 ); + return TRUE; + } + if ( shd->data ) { // existing data +#if defined(DONT_USE_REALLOC) + char *newdata = NEW(char,newsize); // manual realloc + memcpy( newdata, shd->data, QMIN(shd->len,newsize) ); + DELETE(shd->data); + shd->data = newdata; +#else + shd->data = (char *)realloc( shd->data, newsize ); +#endif + } else { + shd->data = NEW(char,newsize); + } + CHECK_PTR( shd->data ); + if ( !shd->data ) // no memory + return FALSE; + shd->len = newsize; + return TRUE; +} + +/*! + \internal + Fills the array with the repeated occurrences of \e d, which is + \e sz bytes long. + If \e len is specified as different from -1, then the array will be + resized to \e len*sz before it is filled. + + Returns TRUE if successful, or FALSE if the memory cannot be allocated + (only when \e len != -1). + + \sa resize() +*/ + +bool QGArray::fill( const char *d, int len, uint sz ) +{ + if ( len < 0 ) + len = shd->len/sz; // default: use array length + else if ( !resize( len*sz ) ) + return FALSE; + if ( sz == 1 ) // 8 bit elements + memset( data(), *d, len ); + else if ( sz == 4 ) { // 32 bit elements + register Q_INT32 *x = (Q_INT32*)data(); + Q_INT32 v = *((Q_INT32*)d); + while ( len-- ) + *x++ = v; + } else if ( sz == 2 ) { // 16 bit elements + register Q_INT16 *x = (Q_INT16*)data(); + Q_INT16 v = *((Q_INT16*)d); + while ( len-- ) + *x++ = v; + } else { // any other size elements + register char *x = data(); + while ( len-- ) { // more complicated + memcpy( x, d, sz ); + x += sz; + } + } + return TRUE; +} + +/*! + \internal + Shallow copy. Dereference the current array and references the data + contained in \e a instead. Returns a reference to this array. + \sa operator=() +*/ + +QGArray &QGArray::assign( const QGArray &a ) +{ + a.shd->ref(); // avoid 'a = a' + if ( shd->deref() ) { // delete when last reference + if ( shd->data ) // is lost + DELETE(shd->data); + deleteData( shd ); + } + shd = a.shd; + return *this; +} + +/*! + \internal + Shallow copy. Dereference the current array and references the + array data \e d, which contains \e len bytes. + Returns a reference to this array. + + Do not delete \e d later, because QGArray takes care of that. +*/ + +QGArray &QGArray::assign( const char *d, uint len ) +{ + if ( shd->count > 1 ) { // disconnect this + shd->count--; + shd = newData(); + CHECK_PTR( shd ); + } else { + if ( shd->data ) + DELETE(shd->data); + } + shd->data = (char *)d; + shd->len = len; + return *this; +} + +/*! + \internal + Deep copy. Dereference the current array and obtains a copy of the data + contained in \e a instead. Returns a reference to this array. + \sa assign(), operator=() +*/ + +QGArray &QGArray::duplicate( const QGArray &a ) +{ + if ( a.shd == shd ) { // a.duplicate(a) ! + if ( shd->count > 1 ) { + shd->count--; + register array_data *n = newData(); + CHECK_PTR( n ); + if ( (n->len=shd->len) ) { + n->data = NEW(char,n->len); + CHECK_PTR( n->data ); + if ( n->data ) + memcpy( n->data, shd->data, n->len ); + } else { + n->data = 0; + } + shd = n; + } + return *this; + } + char *oldptr = 0; + if ( shd->count > 1 ) { // disconnect this + shd->count--; + shd = newData(); + CHECK_PTR( shd ); + } else { // delete after copy was made + oldptr = shd->data; + } + if ( a.shd->len ) { // duplicate data + shd->data = NEW(char,a.shd->len); + CHECK_PTR( shd->data ); + if ( shd->data ) + memcpy( shd->data, a.shd->data, a.shd->len ); + } else { + shd->data = 0; + } + shd->len = a.shd->len; + if ( oldptr ) + DELETE(oldptr); + return *this; +} + +/*! + \internal + Deep copy. Dereferences the current array and obtains a copy of the + array data \e d instead. Returns a reference to this array. + \sa assign(), operator=() +*/ + +QGArray &QGArray::duplicate( const char *d, uint len ) +{ + char *data; + if ( d == 0 || len == 0 ) { + data = 0; + len = 0; + } else { + if ( shd->count == 1 && shd->len == len ) { + memcpy( shd->data, d, len ); // use same buffer + return *this; + } + data = NEW(char,len); + CHECK_PTR( data ); + memcpy( data, d, len ); + } + if ( shd->count > 1 ) { // detach + shd->count--; + shd = newData(); + CHECK_PTR( shd ); + } else { // just a single reference + if ( shd->data ) + DELETE(shd->data); + } + shd->data = data; + shd->len = len; + return *this; +} + +/*! + \internal + Resizes this array to \e len bytes and copies the \e len bytes at + address \e into it. + + \warning This function disregards the reference count mechanism. If + other QGArrays reference the same data as this, all will be updated. +*/ + +void QGArray::store( const char *d, uint len ) +{ // store, but not deref + resize( len ); + memcpy( shd->data, d, len ); +} + + +/*! + \fn array_data *QGArray::sharedBlock() const + \internal + Returns a pointer to the shared array block. + + \warning + + Do not use this function. Using it is begging for trouble. We dare + not remove it, for fear of breaking code, but we \e strongly + discourage new use of it. +*/ + +/*! + \fn void QGArray::setSharedBlock( array_data *p ) + \internal + Sets the shared array block to \e p. + + \warning + + Do not use this function. Using it is begging for trouble. We dare + not remove it, for fear of breaking code, but we \e strongly + discourage new use of it. +*/ + + +/*! + \internal + Sets raw data and returns a reference to the array. + + Dereferences the current array and sets the new array data to \e d and + the new array size to \e len. Do not attempt to resize or re-assign the + array data when raw data has been set. + Call resetRawData(d,len) to reset the array. + + Setting raw data is useful because it set QArray data without allocating + memory or copying data. + + Example of intended use: + \code + static uchar bindata[] = { 231, 1, 44, ... }; + QByteArray a; + a.setRawData( bindata, sizeof(bindata) ); // a points to bindata + QDataStream s( a, IO_ReadOnly ); // open on a's data + s >> <something>; // read raw bindata + s.close(); + a.resetRawData( bindata, sizeof(bindata) ); // finished + \endcode + + Example of misuse (do not do this): + \code + static uchar bindata[] = { 231, 1, 44, ... }; + QByteArray a, b; + a.setRawData( bindata, sizeof(bindata) ); // a points to bindata + a.resize( 8 ); // will crash + b = a; // will crash + a[2] = 123; // might crash + // forget to resetRawData - will crash + \endcode + + \warning If you do not call resetRawData(), QGArray will attempt to + deallocate or reallocate the raw data, which might not be too good. + Be careful. +*/ + +QGArray &QGArray::setRawData( const char *d, uint len ) +{ + duplicate( 0, 0 ); // set null data + shd->data = (char *)d; + shd->len = len; + return *this; +} + +/*! + \internal + Resets raw data. + + The arguments must be the data and length that were passed to + setRawData(). This is for consistency checking. +*/ + +void QGArray::resetRawData( const char *d, uint len ) +{ + if ( d != shd->data || len != shd->len ) { +#if defined(CHECK_STATE) + qWarning( "QGArray::resetRawData: Inconsistent arguments" ); +#endif + return; + } + shd->data = 0; + shd->len = 0; +} + + +/*! + \internal + Finds the first occurrence of \e d in the array from position \e index, + where \e sz is the size of the \e d element. + + Note that \e index is given in units of \e sz, not bytes. + + This function only compares whole cells, not bytes. +*/ + +int QGArray::find( const char *d, uint index, uint sz ) const +{ + index *= sz; + if ( index >= shd->len ) { +#if defined(CHECK_RANGE) + qWarning( "QGArray::find: Index %d out of range", index/sz ); +#endif + return -1; + } + register uint i; + uint ii; + switch ( sz ) { + case 1: { // 8 bit elements + register char *x = data() + index; + char v = *d; + for ( i=index; i<shd->len; i++ ) { + if ( *x++ == v ) + break; + } + ii = i; + } + break; + case 2: { // 16 bit elements + register Q_INT16 *x = (Q_INT16*)(data() + index); + Q_INT16 v = *((Q_INT16*)d); + for ( i=index; i<shd->len; i+=2 ) { + if ( *x++ == v ) + break; + } + ii = i/2; + } + break; + case 4: { // 32 bit elements + register Q_INT32 *x = (Q_INT32*)(data() + index); + Q_INT32 v = *((Q_INT32*)d); + for ( i=index; i<shd->len; i+=4 ) { + if ( *x++ == v ) + break; + } + ii = i/4; + } + break; + default: { // any size elements + for ( i=index; i<shd->len; i+=sz ) { + if ( memcmp( d, &shd->data[i], sz ) == 0 ) + break; + } + ii = i/sz; + } + break; + } + return i<shd->len ? (int)ii : -1; +} + +/*! + \internal + Returns the number of occurrences of \e d in the array, where \e sz is + the size of the \e d element. + + This function only compares whole cells, not bytes. +*/ + +int QGArray::contains( const char *d, uint sz ) const +{ + register uint i = shd->len; + int count = 0; + switch ( sz ) { + case 1: { // 8 bit elements + register char *x = data(); + char v = *d; + while ( i-- ) { + if ( *x++ == v ) + count++; + } + } + break; + case 2: { // 16 bit elements + register Q_INT16 *x = (Q_INT16*)data(); + Q_INT16 v = *((Q_INT16*)d); + i /= 2; + while ( i-- ) { + if ( *x++ == v ) + count++; + } + } + break; + case 4: { // 32 bit elements + register Q_INT32 *x = (Q_INT32*)data(); + Q_INT32 v = *((Q_INT32*)d); + i /= 4; + while ( i-- ) { + if ( *x++ == v ) + count++; + } + } + break; + default: { // any size elements + for ( i=0; i<shd->len; i+=sz ) { + if ( memcmp(d, &shd->data[i], sz) == 0 ) + count++; + } + } + break; + } + return count; +} + +static int cmp_item_size = 0; + +#if defined(Q_C_CALLBACKS) +extern "C" { +#endif + +static int cmp_arr( const void *n1, const void *n2 ) +{ + return ( n1 && n2 ) ? memcmp( n1, n2, cmp_item_size ) + : (int)((long)n1 - (long)n2); + // Qt 3.0: Add a virtual compareItems() method and call that instead +} + +#if defined(Q_C_CALLBACKS) +} +#endif + +/*! + \internal + + Sort the array. +*/ + +void QGArray::sort( uint sz ) +{ + int numItems = size() / sz; + if ( numItems < 2 ) + return; + cmp_item_size = sz; + qsort( shd->data, numItems, sz, cmp_arr ); +} + +/*! + \internal + + Binary search; assumes sorted array +*/ + +int QGArray::bsearch( const char *d, uint sz ) const +{ + int numItems = size() / sz; + if ( !numItems ) + return -1; + cmp_item_size = sz; + char* r = (char*)::bsearch( d, shd->data, numItems, sz, cmp_arr ); + if ( !r ) + return -1; + while( (r >= shd->data + sz) && (cmp_arr( r - sz, d ) == 0) ) + r -= sz; // search to first of equal elements; bsearch is undef + return (int)(( r - shd->data ) / sz); +} + + +/*! + \fn char *QGArray::at( uint index ) const + \internal + Returns a pointer to the byte at offset \e index in the array. +*/ + +/*! + \internal + Expand the array if necessary, and copies (the first part of) its + contents from the \e index*zx bytes at \e d. + + Returns TRUE if the operation succeeds, FALSE if it runs out of + memory. + + \warning This function disregards the reference count mechanism. If + other QGArrays reference the same data as this, all will be changed. +*/ + +bool QGArray::setExpand( uint index, const char *d, uint sz ) +{ + index *= sz; + if ( index >= shd->len ) { + if ( !resize( index+sz ) ) // no memory + return FALSE; + } + memcpy( data() + index, d, sz ); + return TRUE; +} + + +/*! + \internal + Prints a warning message if at() or [] is given a bad index. +*/ + +void QGArray::msg_index( uint index ) +{ +#if defined(CHECK_RANGE) + qWarning( "QGArray::at: Absolute index %d out of range", index ); +#else + Q_UNUSED( index ) +#endif +} + + +/*! + \internal + Returns a new shared array block. +*/ + +QGArray::array_data * QGArray::newData() +{ + return new array_data; +} + + +/*! + \internal + Deletes the shared array block. +*/ + +void QGArray::deleteData( array_data *p ) +{ + delete p; + p = 0; +} diff --git a/trunk/qtools/qgarray.h b/trunk/qtools/qgarray.h new file mode 100644 index 0000000..12c463b --- /dev/null +++ b/trunk/qtools/qgarray.h @@ -0,0 +1,120 @@ +/**************************************************************************** +** +** +** Definition of QGArray class +** +** Created : 930906 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QGARRAY_H +#define QGARRAY_H + +#ifndef QT_H +#include "qshared.h" +#endif // QT_H + + +class Q_EXPORT QGArray // generic array +{ +friend class QBuffer; +public: + //### DO NOT USE THIS. IT IS PUBLIC BUT DO NOT USE IT IN NEW CODE. + struct array_data : public QShared { // shared array + array_data() { data=0; len=0; } + char *data; // actual array data + uint len; + }; + QGArray(); +protected: + QGArray( int, int ); // dummy; does not alloc + QGArray( int size ); // allocate 'size' bytes + QGArray( const QGArray &a ); // shallow copy + virtual ~QGArray(); + + QGArray &operator=( const QGArray &a ) { return assign( a ); } + + virtual void detach() { duplicate(*this); } + + char *data() const { return shd->data; } + uint nrefs() const { return shd->count; } + uint size() const { return shd->len; } + bool isEqual( const QGArray &a ) const; + + bool resize( uint newsize ); + + bool fill( const char *d, int len, uint sz ); + + QGArray &assign( const QGArray &a ); + QGArray &assign( const char *d, uint len ); + QGArray &duplicate( const QGArray &a ); + QGArray &duplicate( const char *d, uint len ); + void store( const char *d, uint len ); + + array_data *sharedBlock() const { return shd; } + void setSharedBlock( array_data *p ) { shd=(array_data*)p; } + + QGArray &setRawData( const char *d, uint len ); + void resetRawData( const char *d, uint len ); + + int find( const char *d, uint index, uint sz ) const; + int contains( const char *d, uint sz ) const; + + void sort( uint sz ); + int bsearch( const char *d, uint sz ) const; + + char *at( uint index ) const; + + bool setExpand( uint index, const char *d, uint sz ); + +protected: + virtual array_data *newData(); + virtual void deleteData( array_data *p ); + +private: + static void msg_index( uint ); + array_data *shd; +}; + + +inline char *QGArray::at( uint index ) const +{ +#if defined(CHECK_RANGE) + if ( index >= size() ) { + msg_index( index ); + index = 0; + } +#endif + return &shd->data[index]; +} + + +#endif // QGARRAY_H diff --git a/trunk/qtools/qgcache.cpp b/trunk/qtools/qgcache.cpp new file mode 100644 index 0000000..e5dd8de --- /dev/null +++ b/trunk/qtools/qgcache.cpp @@ -0,0 +1,878 @@ +/**************************************************************************** +** +** +** Implementation of QGCache and QGCacheIterator classes +** +** Created : 950208 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "qgcache.h" +#include "qlist.h" +#include "qdict.h" +#include "qstring.h" + + +// NOT REVISED +/*! + \class QGCache qgcache.h + + \brief The QGCache class is an internal class for implementing QCache template classes. + + QGCache is a strictly internal class that acts as a base class for the + \link collection.html collection classes\endlink QCache and QIntCache. +*/ + + +/***************************************************************************** + QGCacheItem class (internal cache item) + *****************************************************************************/ + +struct QCacheItem +{ + QCacheItem( void *k, QCollection::Item d, int c, short p ) + : priority(p), skipPriority(p), cost(c), key(k), data(d), node(0) {} + short priority; + short skipPriority; + int cost; + void *key; + QCollection::Item data; + QLNode *node; +}; + + +/***************************************************************************** + QCList class (internal list of cache items) + *****************************************************************************/ + +class QCList : private QList<QCacheItem> +{ +friend class QGCacheIterator; +friend class QCListIt; +public: + QCList() {} + ~QCList(); + + void insert( QCacheItem * ); // insert according to priority + void insert( int, QCacheItem * ); + void take( QCacheItem * ); + void reference( QCacheItem * ); + + void setAutoDelete( bool del ) { QCollection::setAutoDelete(del); } + + bool removeFirst() { return QList<QCacheItem>::removeFirst(); } + bool removeLast() { return QList<QCacheItem>::removeLast(); } + + QCacheItem *first() { return QList<QCacheItem>::first(); } + QCacheItem *last() { return QList<QCacheItem>::last(); } + QCacheItem *prev() { return QList<QCacheItem>::prev(); } + QCacheItem *next() { return QList<QCacheItem>::next(); } + +#if defined(DEBUG) + int inserts; // variables for statistics + int insertCosts; + int insertMisses; + int finds; + int hits; + int hitCosts; + int dumps; + int dumpCosts; +#endif +}; + + +QCList::~QCList() +{ +#if defined(DEBUG) + ASSERT( count() == 0 ); +#endif +} + + +void QCList::insert( QCacheItem *ci ) +{ + QCacheItem *item = first(); + while( item && item->skipPriority > ci->priority ) { + item->skipPriority--; + item = next(); + } + if ( item ) + QList<QCacheItem>::insert( at(), ci ); + else + append( ci ); +#if defined(DEBUG) + ASSERT( ci->node == 0 ); +#endif + ci->node = currentNode(); +} + +inline void QCList::insert( int i, QCacheItem *ci ) +{ + QList<QCacheItem>::insert( i, ci ); +#if defined(DEBUG) + ASSERT( ci->node == 0 ); +#endif + ci->node = currentNode(); +} + + +void QCList::take( QCacheItem *ci ) +{ + if ( ci ) { +#if defined(DEBUG) + ASSERT( ci->node != 0 ); +#endif + takeNode( ci->node ); + ci->node = 0; + } +} + + +inline void QCList::reference( QCacheItem *ci ) +{ +#if defined(DEBUG) + ASSERT( ci != 0 && ci->node != 0 ); +#endif + ci->skipPriority = ci->priority; + relinkNode( ci->node ); // relink as first item +} + + +class QCListIt: public QListIterator<QCacheItem> +{ +public: + QCListIt( const QCList *p ): QListIterator<QCacheItem>( *p ) {} + QCListIt( const QCListIt *p ): QListIterator<QCacheItem>( *p ) {} +}; + + +/***************************************************************************** + QCDict class (internal dictionary of cache items) + *****************************************************************************/ + +// +// Since we need to decide if the dictionary should use an int or const +// char * key (the "bool trivial" argument in the constructor below) +// we cannot use the macro/template dict, but inherit directly from QGDict. +// + +class QCDict : public QGDict +{ +public: + QCDict( uint size, uint kt, bool caseSensitive, bool copyKeys ) + : QGDict( size, (KeyType)kt, caseSensitive, copyKeys ) {} + + QCacheItem *find_string(const QString &key) const + { return (QCacheItem*)((QCDict*)this)->look_string(key, 0, 0); } + QCacheItem *find_ascii(const char *key) const + { return (QCacheItem*)((QCDict*)this)->look_ascii(key, 0, 0); } + QCacheItem *find_int(long key) const + { return (QCacheItem*)((QCDict*)this)->look_int(key, 0, 0); } + + QCacheItem *take_string(const QString &key) + { return (QCacheItem*)QGDict::take_string(key); } + QCacheItem *take_ascii(const char *key) + { return (QCacheItem*)QGDict::take_ascii(key); } + QCacheItem *take_int(long key) + { return (QCacheItem*)QGDict::take_int(key); } + + bool insert_string( const QString &key, const QCacheItem *ci ) + { return QGDict::look_string(key,(Item)ci,1)!=0;} + bool insert_ascii( const char *key, const QCacheItem *ci ) + { return QGDict::look_ascii(key,(Item)ci,1)!=0;} + bool insert_int( long key, const QCacheItem *ci ) + { return QGDict::look_int(key,(Item)ci,1)!=0;} + + bool remove_string( QCacheItem *item ) + { return QGDict::remove_string(*((QString*)(item->key)),item); } + bool remove_ascii( QCacheItem *item ) + { return QGDict::remove_ascii((const char *)item->key,item); } + bool remove_int( QCacheItem *item ) + { return QGDict::remove_int((long)item->key,item);} + + void statistics() { QGDict::statistics(); } +}; + + +/***************************************************************************** + QGDict member functions + *****************************************************************************/ + +/*! + \internal + Constructs a cache. +*/ + +QGCache::QGCache( int maxCost, uint size, KeyType kt, bool caseSensitive, + bool copyKeys ) +{ + keytype = kt; + lruList = new QCList; + CHECK_PTR( lruList ); + lruList->setAutoDelete( TRUE ); + copyk = ((keytype == AsciiKey) && copyKeys); + dict = new QCDict( size, kt, caseSensitive, FALSE ); + CHECK_PTR( dict ); + mCost = maxCost; + tCost = 0; +#if defined(DEBUG) + lruList->inserts = 0; + lruList->insertCosts = 0; + lruList->insertMisses = 0; + lruList->finds = 0; + lruList->hits = 0; + lruList->hitCosts = 0; + lruList->dumps = 0; + lruList->dumpCosts = 0; +#endif +} + +/*! + \internal + Cannot copy a cache. +*/ + +QGCache::QGCache( const QGCache & ) + : QCollection() +{ +#if defined(CHECK_NULL) + qFatal( "QGCache::QGCache(QGCache &): Cannot copy a cache" ); +#endif +} + +/*! + \internal + Removes all items from the cache and destroys it. +*/ + +QGCache::~QGCache() +{ + clear(); // delete everything first + delete dict; + delete lruList; +} + +/*! + \internal + Cannot assign a cache. +*/ + +QGCache &QGCache::operator=( const QGCache & ) +{ +#if defined(CHECK_NULL) + qFatal( "QGCache::operator=: Cannot copy a cache" ); +#endif + return *this; // satisfy the compiler +} + + +/*! + \fn uint QGCache::count() const + \internal + Returns the number of items in the cache. +*/ + +/*! + \fn uint QGCache::size() const + \internal + Returns the size of the hash array. +*/ + +/*! + \fn int QGCache::maxCost() const + \internal + Returns the maximum cache cost. +*/ + +/*! + \fn int QGCache::totalCost() const + \internal + Returns the total cache cost. +*/ + +/*! + \internal + Sets the maximum cache cost. +*/ + +void QGCache::setMaxCost( int maxCost ) +{ + if ( maxCost < tCost ) { + if ( !makeRoomFor(tCost - maxCost) ) // remove excess cost + return; + } + mCost = maxCost; +} + + +/*! + \internal + Inserts an item into the cache. + + \warning If this function returns FALSE, you must delete \a data + yourself. Additionally, be very careful about using \a data after + calling this function, as any other insertions into the cache, from + anywhere in the application, or within Qt itself, could cause the + data to be discarded from the cache, and the pointer to become + invalid. +*/ + +bool QGCache::insert_string( const QString &key, QCollection::Item data, + int cost, int priority) +{ + if ( tCost + cost > mCost ) { + if ( !makeRoomFor(tCost + cost - mCost, priority) ) { +#if defined(DEBUG) + lruList->insertMisses++; +#endif + return FALSE; + } + } +#if defined(DEBUG) + ASSERT( keytype == StringKey ); + lruList->inserts++; + lruList->insertCosts += cost; +#endif + if ( priority < -32768 ) + priority = -32768; + else if ( priority > 32767 ) + priority = 32677; + QCacheItem *ci = new QCacheItem( new QString(key), newItem(data), + cost, (short)priority ); + CHECK_PTR( ci ); + lruList->insert( 0, ci ); + dict->insert_string( key, ci ); + tCost += cost; + return TRUE; +} + + +/*! \internal */ + +bool QGCache::insert_other( const char *key, QCollection::Item data, + int cost, int priority) +{ + if ( tCost + cost > mCost ) { + if ( !makeRoomFor(tCost + cost - mCost, priority) ) { +#if defined(DEBUG) + lruList->insertMisses++; +#endif + return FALSE; + } + } +#if defined(DEBUG) + ASSERT( keytype != StringKey ); + lruList->inserts++; + lruList->insertCosts += cost; +#endif + if ( keytype == AsciiKey && copyk ) + key = qstrdup( key ); + if ( priority < -32768 ) + priority = -32768; + else if ( priority > 32767 ) + priority = 32677; + QCacheItem *ci = new QCacheItem( (void*)key, newItem(data), cost, + (short)priority ); + CHECK_PTR( ci ); + lruList->insert( 0, ci ); + if ( keytype == AsciiKey ) + dict->insert_ascii( key, ci ); + else + dict->insert_int( (long)key, ci ); + tCost += cost; + return TRUE; +} + + +/*! + \internal + Removes an item from the cache. +*/ + +bool QGCache::remove_string( const QString &key ) +{ + Item d = take_string( key ); + if ( d ) + deleteItem( d ); + return d != 0; +} + + +/*! \internal */ + +bool QGCache::remove_other( const char *key ) +{ + Item d = take_other( key ); + if ( d ) + deleteItem( d ); + return d != 0; +} + + +/*! + \internal + Takes an item out of the cache (no delete). +*/ + +QCollection::Item QGCache::take_string( const QString &key ) +{ + QCacheItem *ci = dict->take_string( key ); // take from dict + Item d; + if ( ci ) { + d = ci->data; + tCost -= ci->cost; + lruList->take( ci ); // take from list + delete (QString*)ci->key; + delete ci; + } else { + d = 0; + } + return d; +} + +/*! + \internal + Takes an item out of the cache (no delete). +*/ + +QCollection::Item QGCache::take_other( const char *key ) +{ + QCacheItem *ci; + if ( keytype == AsciiKey ) + ci = dict->take_ascii( key ); + else + ci = dict->take_int( (long)key ); + Item d; + if ( ci ) { + d = ci->data; + tCost -= ci->cost; + lruList->take( ci ); // take from list + if ( copyk ) + delete [] (char *)ci->key; + delete ci; + } else { + d = 0; + } + return d; +} + + +/*! + \internal + Clears the cache. +*/ + +void QGCache::clear() +{ + QCacheItem *ci; + while ( (ci = lruList->first()) ) { + switch ( keytype ) { + case StringKey: + dict->remove_string( ci ); + delete (QString*)ci->key; + break; + case AsciiKey: + dict->remove_ascii( ci ); + if ( copyk ) + delete [] (char*)ci->key; + break; + case IntKey: + dict->remove_int( ci ); + break; + case PtrKey: // unused + break; + } + deleteItem( ci->data ); // delete data + lruList->removeFirst(); // remove from list + } + tCost = 0; +} + + +/*! + \internal + Finds an item in the cache. +*/ + +QCollection::Item QGCache::find_string( const QString &key, bool ref ) const +{ + QCacheItem *ci = dict->find_string( key ); +#if defined(DEBUG) + lruList->finds++; +#endif + if ( ci ) { +#if defined(DEBUG) + lruList->hits++; + lruList->hitCosts += ci->cost; +#endif + if ( ref ) + lruList->reference( ci ); + return ci->data; + } + return 0; +} + + +/*! + \internal + Finds an item in the cache. +*/ + +QCollection::Item QGCache::find_other( const char *key, bool ref ) const +{ + QCacheItem *ci = keytype == AsciiKey ? dict->find_ascii(key) + : dict->find_int((long)key); +#if defined(DEBUG) + lruList->finds++; +#endif + if ( ci ) { +#if defined(DEBUG) + lruList->hits++; + lruList->hitCosts += ci->cost; +#endif + if ( ref ) + lruList->reference( ci ); + return ci->data; + } + return 0; +} + + +/*! + \internal + Allocates cache space for one or more items. +*/ + +bool QGCache::makeRoomFor( int cost, int priority ) +{ + if ( cost > mCost ) // cannot make room for more + return FALSE; // than maximum cost + if ( priority == -1 ) + priority = 32767; + register QCacheItem *ci = lruList->last(); + int cntCost = 0; + int dumps = 0; // number of items to dump + while ( cntCost < cost && ci && ci->skipPriority <= priority ) { + cntCost += ci->cost; + ci = lruList->prev(); + dumps++; + } + if ( cntCost < cost ) // can enough cost be dumped? + return FALSE; // no +#if defined(DEBUG) + ASSERT( dumps > 0 ); +#endif + while ( dumps-- ) { + ci = lruList->last(); +#if defined(DEBUG) + lruList->dumps++; + lruList->dumpCosts += ci->cost; +#endif + switch ( keytype ) { + case StringKey: + dict->remove_string( ci ); + delete (QString*)ci->key; + break; + case AsciiKey: + dict->remove_ascii( ci ); + if ( copyk ) + delete [] (char *)ci->key; + break; + case IntKey: + dict->remove_int( ci ); + break; + case PtrKey: // unused + break; + } + deleteItem( ci->data ); // delete data + lruList->removeLast(); // remove from list + } + tCost -= cntCost; + return TRUE; +} + + +/*! + \internal + Outputs debug statistics. +*/ + +void QGCache::statistics() const +{ +#if defined(DEBUG) + QString line; + line.fill( '*', 80 ); + qDebug( "%s",line.ascii() ); + qDebug( "CACHE STATISTICS:" ); + qDebug( "cache contains %d item%s, with a total cost of %d", + count(), count() != 1 ? "s" : "", tCost ); + qDebug( "maximum cost is %d, cache is %d%% full.", + mCost, (200*tCost + mCost) / (mCost*2) ); + qDebug( "find() has been called %d time%s", + lruList->finds, lruList->finds != 1 ? "s" : "" ); + qDebug( "%d of these were hits, items found had a total cost of %d.", + lruList->hits,lruList->hitCosts ); + qDebug( "%d item%s %s been inserted with a total cost of %d.", + lruList->inserts,lruList->inserts != 1 ? "s" : "", + lruList->inserts != 1 ? "have" : "has", lruList->insertCosts ); + qDebug( "%d item%s %s too large or had too low priority to be inserted.", + lruList->insertMisses, lruList->insertMisses != 1 ? "s" : "", + lruList->insertMisses != 1 ? "were" : "was" ); + qDebug( "%d item%s %s been thrown away with a total cost of %d.", + lruList->dumps, lruList->dumps != 1 ? "s" : "", + lruList->dumps != 1 ? "have" : "has", lruList->dumpCosts ); + qDebug( "Statistics from internal dictionary class:" ); + dict->statistics(); + qDebug( "%s",line.ascii() ); +#endif +} + +int QGCache::hits() const +{ + return lruList->hits; +} + +int QGCache::misses() const +{ + return lruList->finds - lruList->hits; +} + + +/***************************************************************************** + QGCacheIterator member functions + *****************************************************************************/ + +/*! + \class QGCacheIterator qgcache.h + + \brief An internal class for implementing QCacheIterator and QIntCacheIterator. + + QGCacheIterator is a strictly internal class that does the heavy work for + QCacheIterator and QIntCacheIterator. +*/ + +/*! + \internal + Constructs an iterator that operates on the cache \e c. +*/ + +QGCacheIterator::QGCacheIterator( const QGCache &c ) +{ + it = new QCListIt( c.lruList ); +#if defined(DEBUG) + ASSERT( it != 0 ); +#endif +} + +/*! + \internal + Constructs an iterator that operates on the same cache as \e ci. +*/ + +QGCacheIterator::QGCacheIterator( const QGCacheIterator &ci ) +{ + it = new QCListIt( ci.it ); +#if defined(DEBUG) + ASSERT( it != 0 ); +#endif +} + +/*! + \internal + Destroys the iterator. +*/ + +QGCacheIterator::~QGCacheIterator() +{ + delete it; +} + +/*! + \internal + Assigns the iterator \e ci to this cache iterator. +*/ + +QGCacheIterator &QGCacheIterator::operator=( const QGCacheIterator &ci ) +{ + *it = *ci.it; + return *this; +} + +/*! + \internal + Returns the number of items in the cache. +*/ + +uint QGCacheIterator::count() const +{ + return it->count(); +} + +/*! + \internal + Returns TRUE if the iterator points to the first item. +*/ + +bool QGCacheIterator::atFirst() const +{ + return it->atFirst(); +} + +/*! + \internal + Returns TRUE if the iterator points to the last item. +*/ + +bool QGCacheIterator::atLast() const +{ + return it->atLast(); +} + +/*! + \internal + Sets the list iterator to point to the first item in the cache. +*/ + +QCollection::Item QGCacheIterator::toFirst() +{ + QCacheItem *item = it->toFirst(); + return item ? item->data : 0; +} + +/*! + \internal + Sets the list iterator to point to the last item in the cache. +*/ + +QCollection::Item QGCacheIterator::toLast() +{ + QCacheItem *item = it->toLast(); + return item ? item->data : 0; +} + +/*! + \internal + Returns the current item. +*/ + +QCollection::Item QGCacheIterator::get() const +{ + QCacheItem *item = it->current(); + return item ? item->data : 0; +} + +/*! + \internal + Returns the key of the current item. +*/ + +QString QGCacheIterator::getKeyString() const +{ + QCacheItem *item = it->current(); + return item ? *((QString*)item->key) : QString::null; +} + +/*! + \internal + Returns the key of the current item, as a \0-terminated C string. +*/ + +const char *QGCacheIterator::getKeyAscii() const +{ + QCacheItem *item = it->current(); + return item ? (const char *)item->key : 0; +} + +/*! + \internal + Returns the key of the current item, as a long. +*/ + +long QGCacheIterator::getKeyInt() const +{ + QCacheItem *item = it->current(); + return item ? (long)item->key : 0; +} + +/*! + \internal + Moves to the next item (postfix). +*/ + +QCollection::Item QGCacheIterator::operator()() +{ + QCacheItem *item = it->operator()(); + return item ? item->data : 0; +} + +/*! + \internal + Moves to the next item (prefix). +*/ + +QCollection::Item QGCacheIterator::operator++() +{ + QCacheItem *item = it->operator++(); + return item ? item->data : 0; +} + +/*! + \internal + Moves \e jumps positions forward. +*/ + +QCollection::Item QGCacheIterator::operator+=( uint jump ) +{ + QCacheItem *item = it->operator+=(jump); + return item ? item->data : 0; +} + +/*! + \internal + Moves to the previous item (prefix). +*/ + +QCollection::Item QGCacheIterator::operator--() +{ + QCacheItem *item = it->operator--(); + return item ? item->data : 0; +} + +/*! + \internal + Moves \e jumps positions backward. +*/ + +QCollection::Item QGCacheIterator::operator-=( uint jump ) +{ + QCacheItem *item = it->operator-=(jump); + return item ? item->data : 0; +} diff --git a/trunk/qtools/qgcache.h b/trunk/qtools/qgcache.h new file mode 100644 index 0000000..2f35c41 --- /dev/null +++ b/trunk/qtools/qgcache.h @@ -0,0 +1,130 @@ +/**************************************************************************** +** +** +** Definition of QGCache and QGCacheIterator classes +** +** Created : 950208 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QGCACHE_H +#define QGCACHE_H + +#ifndef QT_H +#include "qcollection.h" +#include "qglist.h" +#include "qgdict.h" +#endif // QT_H + + +class QCList; // internal classes +class QCListIt; +class QCDict; + + +class Q_EXPORT QGCache : public QCollection // generic LRU cache +{ +friend class QGCacheIterator; +protected: + enum KeyType { StringKey, AsciiKey, IntKey, PtrKey }; + // identical to QGDict's, but PtrKey is not used at the moment + + QGCache( int maxCost, uint size, KeyType kt, bool caseSensitive, + bool copyKeys ); + QGCache( const QGCache & ); // not allowed, calls fatal() + ~QGCache(); + QGCache &operator=( const QGCache & ); // not allowed, calls fatal() + + uint count() const { return ((QGDict*)dict)->count(); } + uint size() const { return ((QGDict*)dict)->size(); } + int maxCost() const { return mCost; } + int totalCost() const { return tCost; } + void setMaxCost( int maxCost ); + void clear(); + + bool insert_string( const QString &key, QCollection::Item, + int cost, int priority ); + bool insert_other( const char *key, QCollection::Item, + int cost, int priority ); + bool remove_string( const QString &key ); + bool remove_other( const char *key ); + QCollection::Item take_string( const QString &key ); + QCollection::Item take_other( const char *key ); + + QCollection::Item find_string( const QString &key, bool ref=TRUE ) const; + QCollection::Item find_other( const char *key, bool ref=TRUE ) const; + + void statistics() const; + int hits() const; + int misses() const; + +private: + bool makeRoomFor( int cost, int priority = -1 ); + KeyType keytype; + QCList *lruList; + QCDict *dict; + int mCost; + int tCost; + bool copyk; +}; + + +class Q_EXPORT QGCacheIterator // generic cache iterator +{ +protected: + QGCacheIterator( const QGCache & ); + QGCacheIterator( const QGCacheIterator & ); + ~QGCacheIterator(); + QGCacheIterator &operator=( const QGCacheIterator & ); + + uint count() const; + bool atFirst() const; + bool atLast() const; + QCollection::Item toFirst(); + QCollection::Item toLast(); + + QCollection::Item get() const; + QString getKeyString() const; + const char *getKeyAscii() const; + long getKeyInt() const; + + QCollection::Item operator()(); + QCollection::Item operator++(); + QCollection::Item operator+=( uint ); + QCollection::Item operator--(); + QCollection::Item operator-=( uint ); + +protected: + QCListIt *it; // iterator on cache list +}; + + +#endif // QGCACHE_H diff --git a/trunk/qtools/qgdict.cpp b/trunk/qtools/qgdict.cpp new file mode 100644 index 0000000..e51b9c1 --- /dev/null +++ b/trunk/qtools/qgdict.cpp @@ -0,0 +1,1218 @@ +/**************************************************************************** +** +** +** Implementation of QGDict and QGDictIterator classes +** +** Created : 920529 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "qgdict.h" +#include "qlist.h" +#include "qstring.h" +#include "qdatastream.h" +#include <ctype.h> + +// NOT REVISED +/*! + \class QGDict qgdict.h + \brief The QGDict class is an internal class for implementing QDict template classes. + + QGDict is a strictly internal class that acts as a base class for the + \link collection.html collection classes\endlink QDict and QIntDict. + + QGDict has some virtual functions that can be reimplemented to customize + the subclasses. + <ul> + <li> read() reads a collection/dictionary item from a QDataStream. + <li> write() writes a collection/dictionary item to a QDataStream. + </ul> + Normally, you do not have to reimplement any of these functions. +*/ + +static const int op_find = 0; +static const int op_insert = 1; +static const int op_replace = 2; + + +class QGDItList : public QList<QGDictIterator> +{ +public: + QGDItList() : QList<QGDictIterator>() {} + QGDItList( const QGDItList &list ) : QList<QGDictIterator>(list) {} + ~QGDItList() { clear(); } + QGDItList &operator=(const QGDItList &list) + { return (QGDItList&)QList<QGDictIterator>::operator=(list); } +}; + + +/***************************************************************************** + Default implementation of special and virtual functions + *****************************************************************************/ + +/*! + \internal + Returns the hash key for \e key, when key is a string. +*/ + +int QGDict::hashKeyString( const QString &key ) +{ +#if defined(CHECK_NULL) + if ( key.isNull() ) + qWarning( "QGDict::hashStringKey: Invalid null key" ); +#endif + int i; + register uint h=0; + uint g; + int len = key.length(); + const QChar *p = key.unicode(); + if ( cases ) { // case sensitive + for ( i=0; i<len; i++ ) { + h = (h<<4) + p[i].cell(); + if ( (g = h & 0xf0000000) ) + h ^= g >> 24; + h &= ~g; + } + } else { // case insensitive + for ( i=0; i<len; i++ ) { + h = (h<<4) + p[i].lower().cell(); + if ( (g = h & 0xf0000000) ) + h ^= g >> 24; + h &= ~g; + } + } + int index = h; + if ( index < 0 ) // adjust index to table size + index = -index; + return index; +} + +/*! + \internal + Returns the hash key for \a key, which is a C string. +*/ + +int QGDict::hashKeyAscii( const char *key ) +{ +#if defined(CHECK_NULL) + if ( key == 0 ) + { + qWarning( "QGDict::hashAsciiKey: Invalid null key" ); + return 0; + } +#endif + register const char *k = key; + register uint h=0; + uint g; + if ( cases ) { // case sensitive + while ( *k ) { + h = (h<<4) + *k++; + if ( (g = h & 0xf0000000) ) + h ^= g >> 24; + h &= ~g; + } + } else { // case insensitive + while ( *k ) { + h = (h<<4) + tolower(*k); + if ( (g = h & 0xf0000000) ) + h ^= g >> 24; + h &= ~g; + k++; + } + } + int index = h; + if ( index < 0 ) // adjust index to table size + index = -index; + return index; +} + +#ifndef QT_NO_DATASTREAM + +/*! + Reads a collection/dictionary item from the stream \e s and returns a + reference to the stream. + + The default implementation sets \e item to 0. + + \sa write() +*/ + +QDataStream& QGDict::read( QDataStream &s, QCollection::Item &item ) +{ + item = 0; + return s; +} + +/*! + Writes a collection/dictionary item to the stream \e s and returns a + reference to the stream. + + \sa read() +*/ + +QDataStream& QGDict::write( QDataStream &s, QCollection::Item ) const +{ + return s; +} +#endif //QT_NO_DATASTREAM + +/***************************************************************************** + QGDict member functions + *****************************************************************************/ + +/*! + \internal + Constructs a dictionary. +*/ + +QGDict::QGDict( uint len, KeyType kt, bool caseSensitive, bool copyKeys ) +{ + init( len, kt, caseSensitive, copyKeys ); +} + + +void QGDict::init( uint len, KeyType kt, bool caseSensitive, bool copyKeys ) +{ + vec = new QBaseBucket *[vlen = len]; // allocate hash table + CHECK_PTR( vec ); + memset( (char*)vec, 0, vlen*sizeof(QBaseBucket*) ); + numItems = 0; + iterators = 0; + // The caseSensitive and copyKey options don't make sense for + // all dict types. + switch ( (keytype = (uint)kt) ) { + case StringKey: + cases = caseSensitive; + copyk = FALSE; + break; + case AsciiKey: + cases = caseSensitive; + copyk = copyKeys; + break; + default: + cases = FALSE; + copyk = FALSE; + break; + } +} + + +/*! + \internal + Constructs a copy of \e dict. +*/ + +QGDict::QGDict( const QGDict & dict ) + : QCollection( dict ) +{ + init( dict.vlen, (KeyType)dict.keytype, dict.cases, dict.copyk ); + QGDictIterator it( dict ); + while ( it.get() ) { // copy from other dict + switch ( keytype ) { + case StringKey: + look_string( it.getKeyString(), it.get(), op_insert ); + break; + case AsciiKey: + look_ascii( it.getKeyAscii(), it.get(), op_insert ); + break; + case IntKey: + look_int( it.getKeyInt(), it.get(), op_insert ); + break; + case PtrKey: + look_ptr( it.getKeyPtr(), it.get(), op_insert ); + break; + } + ++it; + } +} + + +/*! + \internal + Removes all items from the dictionary and destroys it. +*/ + +QGDict::~QGDict() +{ + clear(); // delete everything + delete [] vec; + if ( !iterators ) // no iterators for this dict + return; + QGDictIterator *i = iterators->first(); + while ( i ) { // notify all iterators that + i->dict = 0; // this dict is deleted + i = iterators->next(); + } + delete iterators; +} + + +/*! + \internal + Assigns \e dict to this dictionary. +*/ + +QGDict &QGDict::operator=( const QGDict &dict ) +{ + clear(); + QGDictIterator it( dict ); + while ( it.get() ) { // copy from other dict + switch ( keytype ) { + case StringKey: + look_string( it.getKeyString(), it.get(), op_insert ); + break; + case AsciiKey: + look_ascii( it.getKeyAscii(), it.get(), op_insert ); + break; + case IntKey: + look_int( it.getKeyInt(), it.get(), op_insert ); + break; + case PtrKey: + look_ptr( it.getKeyPtr(), it.get(), op_insert ); + break; + } + ++it; + } + return *this; +} + + +/*! \fn QCollection::Item QGDictIterator::get() const + + \internal +*/ + + +/*! \fn QString QGDictIterator::getKeyString() const + + \internal +*/ + + +/*! \fn const char * QGDictIterator::getKeyAscii() const + + \internal +*/ + + +/*! \fn void * QGDictIterator::getKeyPtr() const + + \internal +*/ + + +/*! \fn long QGDictIterator::getKeyInt() const + + \internal +*/ + + +/*! + \fn uint QGDict::count() const + \internal + Returns the number of items in the dictionary. +*/ + +/*! + \fn uint QGDict::size() const + \internal + Returns the size of the hash array. +*/ + + +/*! + \internal + The do-it-all function; op is one of op_find, op_insert, op_replace +*/ + +QCollection::Item QGDict::look_string( const QString &key, QCollection::Item d, int op ) +{ + QStringBucket *n; + int index = hashKeyString(key) % vlen; + if ( op == op_find ) { // find + if ( cases ) { + for ( n=(QStringBucket*)vec[index]; n; + n=(QStringBucket*)n->getNext() ) { + if ( key == n->getKey() ) + return n->getData(); // item found + } + } else { + QString k = key.lower(); + for ( n=(QStringBucket*)vec[index]; n; + n=(QStringBucket*)n->getNext() ) { + if ( k == n->getKey().lower() ) + return n->getData(); // item found + } + } + return 0; // not found + } + if ( op == op_replace ) { // replace + if ( vec[index] != 0 ) // maybe something there + remove_string( key ); + } + // op_insert or op_replace + n = new QStringBucket(key,newItem(d),vec[index]); + CHECK_PTR( n ); +#if defined(CHECK_NULL) + if ( n->getData() == 0 ) + qWarning( "QDict: Cannot insert null item" ); +#endif + vec[index] = n; + numItems++; + return n->getData(); +} + + +/*! \internal */ + +QCollection::Item QGDict::look_ascii( const char *key, QCollection::Item d, int op ) +{ + QAsciiBucket *n; + int index = hashKeyAscii(key) % vlen; + if ( op == op_find ) { // find + if ( cases ) { + for ( n=(QAsciiBucket*)vec[index]; n; + n=(QAsciiBucket*)n->getNext() ) { + if ( qstrcmp(n->getKey(),key) == 0 ) + return n->getData(); // item found + } + } else { + for ( n=(QAsciiBucket*)vec[index]; n; + n=(QAsciiBucket*)n->getNext() ) { + if ( qstricmp(n->getKey(),key) == 0 ) + return n->getData(); // item found + } + } + return 0; // not found + } + if ( op == op_replace ) { // replace + if ( vec[index] != 0 ) // maybe something there + remove_ascii( key ); + } + // op_insert or op_replace + n = new QAsciiBucket(copyk ? qstrdup(key) : key,newItem(d),vec[index]); + CHECK_PTR( n ); +#if defined(CHECK_NULL) + if ( n->getData() == 0 ) + qWarning( "QAsciiDict: Cannot insert null item" ); +#endif + vec[index] = n; + numItems++; + return n->getData(); +} + + +/*! \internal */ + +QCollection::Item QGDict::look_int( long key, QCollection::Item d, int op ) +{ + QIntBucket *n; + int index = (int)((ulong)key % vlen); // simple hash + if ( op == op_find ) { // find + for ( n=(QIntBucket*)vec[index]; n; + n=(QIntBucket*)n->getNext() ) { + if ( n->getKey() == key ) + return n->getData(); // item found + } + return 0; // not found + } + if ( op == op_replace ) { // replace + if ( vec[index] != 0 ) // maybe something there + remove_int( key ); + } + // op_insert or op_replace + n = new QIntBucket(key,newItem(d),vec[index]); + CHECK_PTR( n ); +#if defined(CHECK_NULL) + if ( n->getData() == 0 ) + qWarning( "QIntDict: Cannot insert null item" ); +#endif + vec[index] = n; + numItems++; + return n->getData(); +} + + +/*! \internal */ + +QCollection::Item QGDict::look_ptr( void *key, QCollection::Item d, int op ) +{ + QPtrBucket *n; + int index = (int)((ulong)key % vlen); // simple hash + if ( op == op_find ) { // find + for ( n=(QPtrBucket*)vec[index]; n; + n=(QPtrBucket*)n->getNext() ) { + if ( n->getKey() == key ) + return n->getData(); // item found + } + return 0; // not found + } + if ( op == op_replace ) { // replace + if ( vec[index] != 0 ) // maybe something there + remove_ptr( key ); + } + // op_insert or op_replace + n = new QPtrBucket(key,newItem(d),vec[index]); + CHECK_PTR( n ); +#if defined(CHECK_NULL) + if ( n->getData() == 0 ) + qWarning( "QPtrDict: Cannot insert null item" ); +#endif + vec[index] = n; + numItems++; + return n->getData(); +} + + +/*! + \internal + Changes the size of the hashtable. + The contents of the dictionary are preserved, + but all iterators on the dictionary become invalid. +*/ +void QGDict::resize( uint newsize ) +{ + // Save old information + QBaseBucket **old_vec = vec; + uint old_vlen = vlen; + bool old_copyk = copyk; + + vec = new QBaseBucket *[vlen = newsize]; + CHECK_PTR( vec ); + memset( (char*)vec, 0, vlen*sizeof(QBaseBucket*) ); + numItems = 0; + copyk = FALSE; + + // Reinsert every item from vec, deleting vec as we go + for ( uint index = 0; index < old_vlen; index++ ) { + switch ( keytype ) { + case StringKey: + { + QStringBucket *n=(QStringBucket *)old_vec[index]; + while ( n ) { + look_string( n->getKey(), n->getData(), op_insert ); + QStringBucket *t=(QStringBucket *)n->getNext(); + delete n; + n = t; + } + } + break; + case AsciiKey: + { + QAsciiBucket *n=(QAsciiBucket *)old_vec[index]; + while ( n ) { + look_ascii( n->getKey(), n->getData(), op_insert ); + QAsciiBucket *t=(QAsciiBucket *)n->getNext(); + delete n; + n = t; + } + } + break; + case IntKey: + { + QIntBucket *n=(QIntBucket *)old_vec[index]; + while ( n ) { + look_int( n->getKey(), n->getData(), op_insert ); + QIntBucket *t=(QIntBucket *)n->getNext(); + delete n; + n = t; + } + } + break; + case PtrKey: + { + QPtrBucket *n=(QPtrBucket *)old_vec[index]; + while ( n ) { + look_ptr( n->getKey(), n->getData(), op_insert ); + QPtrBucket *t=(QPtrBucket *)n->getNext(); + delete n; + n = t; + } + } + break; + } + } + delete [] old_vec; + + // Restore state + copyk = old_copyk; + + // Invalidate all iterators, since order is lost + if ( iterators && iterators->count() ) { + QGDictIterator *i = iterators->first(); + while ( i ) { + i->toFirst(); + i = iterators->next(); + } + } +} + +/*! + \internal + Unlinks the bucket with the specified key (and specified data pointer, + if it is set). +*/ + +void QGDict::unlink_common( int index, QBaseBucket *node, QBaseBucket *prev ) +{ + if ( iterators && iterators->count() ) { // update iterators + QGDictIterator *i = iterators->first(); + while ( i ) { // invalidate all iterators + if ( i->curNode == node ) // referring to pending node + i->operator++(); + i = iterators->next(); + } + } + if ( prev ) // unlink node + prev->setNext( node->getNext() ); + else + vec[index] = node->getNext(); + numItems--; +} + +QStringBucket *QGDict::unlink_string( const QString &key, QCollection::Item d ) +{ + if ( numItems == 0 ) // nothing in dictionary + return 0; + QStringBucket *n; + QStringBucket *prev = 0; + int index = hashKeyString(key) % vlen; + if ( cases ) { + for ( n=(QStringBucket*)vec[index]; n; + n=(QStringBucket*)n->getNext() ) { + bool found = (key == n->getKey()); + if ( found && d ) + found = (n->getData() == d); + if ( found ) { + unlink_common(index,n,prev); + return n; + } + prev = n; + } + } else { + QString k = key.lower(); + for ( n=(QStringBucket*)vec[index]; n; + n=(QStringBucket*)n->getNext() ) { + bool found = (k == n->getKey().lower()); + if ( found && d ) + found = (n->getData() == d); + if ( found ) { + unlink_common(index,n,prev); + return n; + } + prev = n; + } + } + return 0; +} + +QAsciiBucket *QGDict::unlink_ascii( const char *key, QCollection::Item d ) +{ + if ( numItems == 0 ) // nothing in dictionary + return 0; + QAsciiBucket *n; + QAsciiBucket *prev = 0; + int index = hashKeyAscii(key) % vlen; + for ( n=(QAsciiBucket *)vec[index]; n; n=(QAsciiBucket *)n->getNext() ) { + bool found = (cases ? qstrcmp(n->getKey(),key) + : qstricmp(n->getKey(),key)) == 0; + if ( found && d ) + found = (n->getData() == d); + if ( found ) { + unlink_common(index,n,prev); + return n; + } + prev = n; + } + return 0; +} + +QIntBucket *QGDict::unlink_int( long key, QCollection::Item d ) +{ + if ( numItems == 0 ) // nothing in dictionary + return 0; + QIntBucket *n; + QIntBucket *prev = 0; + int index = (int)((ulong)key % vlen); + for ( n=(QIntBucket *)vec[index]; n; n=(QIntBucket *)n->getNext() ) { + bool found = (n->getKey() == key); + if ( found && d ) + found = (n->getData() == d); + if ( found ) { + unlink_common(index,n,prev); + return n; + } + prev = n; + } + return 0; +} + +QPtrBucket *QGDict::unlink_ptr( void *key, QCollection::Item d ) +{ + if ( numItems == 0 ) // nothing in dictionary + return 0; + QPtrBucket *n; + QPtrBucket *prev = 0; + int index = (int)((ulong)key % vlen); + for ( n=(QPtrBucket *)vec[index]; n; n=(QPtrBucket *)n->getNext() ) { + bool found = (n->getKey() == key); + if ( found && d ) + found = (n->getData() == d); + if ( found ) { + unlink_common(index,n,prev); + return n; + } + prev = n; + } + return 0; +} + + +/*! + \internal + Removes the item with the specified key. If item is non-null, + the remove will match the \a item as well (used to remove an + item when several items have the same key). +*/ + +bool QGDict::remove_string( const QString &key, QCollection::Item item ) +{ + QStringBucket *n = unlink_string( key, item ); + if ( n ) { + deleteItem( n->getData() ); + delete n; + return TRUE; + } else { + return FALSE; + } +} + + +/*! \internal */ + +bool QGDict::remove_ascii( const char *key, QCollection::Item item ) +{ + QAsciiBucket *n = unlink_ascii( key, item ); + if ( n ) { + if ( copyk ) + delete [] (char *)n->getKey(); + deleteItem( n->getData() ); + delete n; + } + return n != 0; +} + + +/*! \internal */ + +bool QGDict::remove_int( long key, QCollection::Item item ) +{ + QIntBucket *n = unlink_int( key, item ); + if ( n ) { + deleteItem( n->getData() ); + delete n; + } + return n != 0; +} + + +/*! \internal */ + +bool QGDict::remove_ptr( void *key, QCollection::Item item ) +{ + QPtrBucket *n = unlink_ptr( key, item ); + if ( n ) { + deleteItem( n->getData() ); + delete n; + } + return n != 0; +} + + +/*! \internal */ + +QCollection::Item QGDict::take_string( const QString &key ) +{ + QStringBucket *n = unlink_string( key ); + Item d; + if ( n ) { + d = n->getData(); + delete n; + } else { + d = 0; + } + return d; +} + + +/*! \internal */ + +QCollection::Item QGDict::take_ascii( const char *key ) +{ + QAsciiBucket *n = unlink_ascii( key ); + Item d; + if ( n ) { + if ( copyk ) + delete [] (char *)n->getKey(); + d = n->getData(); + delete n; + } else { + d = 0; + } + return d; +} + + +/*! \internal */ + +QCollection::Item QGDict::take_int( long key ) +{ + QIntBucket *n = unlink_int( key ); + Item d; + if ( n ) { + d = n->getData(); + delete n; + } else { + d = 0; + } + return d; +} + + +/*! \internal */ + +QCollection::Item QGDict::take_ptr( void *key ) +{ + QPtrBucket *n = unlink_ptr( key ); + Item d; + if ( n ) { + d = n->getData(); + delete n; + } else { + d = 0; + } + return d; +} + + +/*! + \internal + Removes all items from the dictionary. +*/ + +void QGDict::clear() +{ + if ( !numItems ) + return; + numItems = 0; // disable remove() function + for ( uint j=0; j<vlen; j++ ) { // destroy hash table + if ( vec[j] ) { + switch ( keytype ) { + case StringKey: + { + QStringBucket *n=(QStringBucket *)vec[j]; + while ( n ) { + QStringBucket *next = (QStringBucket*)n->getNext(); + deleteItem( n->getData() ); + delete n; + n = next; + } + } + break; + case AsciiKey: + { + QAsciiBucket *n=(QAsciiBucket *)vec[j]; + while ( n ) { + QAsciiBucket *next = (QAsciiBucket*)n->getNext(); + if ( copyk ) + delete [] (char *)n->getKey(); + deleteItem( n->getData() ); + delete n; + n = next; + } + } + break; + case IntKey: + { + QIntBucket *n=(QIntBucket *)vec[j]; + while ( n ) { + QIntBucket *next = (QIntBucket*)n->getNext(); + deleteItem( n->getData() ); + delete n; + n = next; + } + } + break; + case PtrKey: + { + QPtrBucket *n=(QPtrBucket *)vec[j]; + while ( n ) { + QPtrBucket *next = (QPtrBucket*)n->getNext(); + deleteItem( n->getData() ); + delete n; + n = next; + } + } + break; + } + vec[j] = 0; // detach list of buckets + } + } + if ( iterators && iterators->count() ) { // invalidate all iterators + QGDictIterator *i = iterators->first(); + while ( i ) { + i->curNode = 0; + i = iterators->next(); + } + } +} + + +/*! + \internal + Outputs debug statistics. +*/ + +void QGDict::statistics() const +{ +#if defined(DEBUG) + QString line; + line.fill( '-', 60 ); + double real, ideal; + qDebug( "%s",line.ascii() ); + qDebug( "DICTIONARY STATISTICS:" ); + if ( count() == 0 ) { + qDebug( "Empty!" ); + qDebug( "%s", line.ascii() ); + return; + } + real = 0.0; + ideal = (float)count()/(2.0*size())*(count()+2.0*size()-1); + uint i = 0; + while ( i<size() ) { + QBaseBucket *n = vec[i]; + int b = 0; + while ( n ) { // count number of buckets + b++; + n = n->getNext(); + } + real = real + (double)b * ((double)b+1.0)/2.0; + char buf[80], *pbuf; + if ( b > 78 ) + b = 78; + pbuf = buf; + while ( b-- ) + *pbuf++ = '*'; + *pbuf = '\0'; + qDebug( "%s", buf ); + i++; + } + qDebug( "Array size = %d", size() ); + qDebug( "# items = %d", count() ); + qDebug( "Real dist = %g", real ); + qDebug( "Rand dist = %g", ideal ); + qDebug( "Real/Rand = %g", real/ideal ); + qDebug( "%s",line.ascii() ); +#endif // DEBUG +} + + +/***************************************************************************** + QGDict stream functions + *****************************************************************************/ +#ifndef QT_NO_DATASTREAM +QDataStream &operator>>( QDataStream &s, QGDict &dict ) +{ + return dict.read( s ); +} + +QDataStream &operator<<( QDataStream &s, const QGDict &dict ) +{ + return dict.write( s ); +} + +#if defined(_CC_DEC_) && defined(__alpha) && (__DECCXX_VER >= 50190001) +#pragma message disable narrowptr +#endif + +/*! + \internal + Reads a dictionary from the stream \e s. +*/ + +QDataStream &QGDict::read( QDataStream &s ) +{ + uint num; + s >> num; // read number of items + clear(); // clear dict + while ( num-- ) { // read all items + Item d; + switch ( keytype ) { + case StringKey: + { + QString k; + s >> k; + read( s, d ); + look_string( k, d, op_insert ); + } + break; + case AsciiKey: + { + char *k; + s >> k; + read( s, d ); + look_ascii( k, d, op_insert ); + if ( copyk ) + delete [] k; + } + break; + case IntKey: + { + Q_UINT32 k; + s >> k; + read( s, d ); + look_int( k, d, op_insert ); + } + break; + case PtrKey: + { + Q_UINT32 k; + s >> k; + read( s, d ); + // ### cannot insert 0 - this renders the thing + // useless since all pointers are written as 0, + // but hey, serializing pointers? can it be done + // at all, ever? + if ( k ) + look_ptr( (void *)k, d, op_insert ); + } + break; + } + } + return s; +} + +/*! + \internal + Writes the dictionary to the stream \e s. +*/ + +QDataStream& QGDict::write( QDataStream &s ) const +{ + s << count(); // write number of items + uint i = 0; + while ( i<size() ) { + QBaseBucket *n = vec[i]; + while ( n ) { // write all buckets + switch ( keytype ) { + case StringKey: + s << ((QStringBucket*)n)->getKey(); + break; + case AsciiKey: + s << ((QAsciiBucket*)n)->getKey(); + break; + case IntKey: + s << (Q_UINT32)((QIntBucket*)n)->getKey(); + break; + case PtrKey: + s << (Q_UINT32)0; // ### cannot serialize a pointer + break; + } + write( s, n->getData() ); // write data + n = n->getNext(); + } + i++; + } + return s; +} +#endif //QT_NO_DATASTREAM + +/***************************************************************************** + QGDictIterator member functions + *****************************************************************************/ + +/*! + \class QGDictIterator qgdict.h + \brief An internal class for implementing QDictIterator and QIntDictIterator. + + QGDictIterator is a strictly internal class that does the heavy work for + QDictIterator and QIntDictIterator. +*/ + +/*! + \internal + Constructs an iterator that operates on the dictionary \e d. +*/ + +QGDictIterator::QGDictIterator( const QGDict &d ) +{ + dict = (QGDict *)&d; // get reference to dict + toFirst(); // set to first noe + if ( !dict->iterators ) { + dict->iterators = new QGDItList; // create iterator list + CHECK_PTR( dict->iterators ); + } + dict->iterators->append( this ); // attach iterator to dict +} + +/*! + \internal + Constructs a copy of the iterator \e it. +*/ + +QGDictIterator::QGDictIterator( const QGDictIterator &it ) +{ + dict = it.dict; + curNode = it.curNode; + curIndex = it.curIndex; + if ( dict ) + dict->iterators->append( this ); // attach iterator to dict +} + +/*! + \internal + Assigns a copy of the iterator \e it and returns a reference to this + iterator. +*/ + +QGDictIterator &QGDictIterator::operator=( const QGDictIterator &it ) +{ + if ( dict ) // detach from old dict + dict->iterators->removeRef( this ); + dict = it.dict; + curNode = it.curNode; + curIndex = it.curIndex; + if ( dict ) + dict->iterators->append( this ); // attach to new list + return *this; +} + +/*! + \internal + Destroys the iterator. +*/ + +QGDictIterator::~QGDictIterator() +{ + if ( dict ) // detach iterator from dict + dict->iterators->removeRef( this ); +} + + +/*! + \internal + Sets the iterator to point to the first item in the dictionary. +*/ + +QCollection::Item QGDictIterator::toFirst() +{ + if ( !dict ) { +#if defined(CHECK_NULL) + qWarning( "QGDictIterator::toFirst: Dictionary has been deleted" ); +#endif + return 0; + } + if ( dict->count() == 0 ) { // empty dictionary + curNode = 0; + return 0; + } + register uint i = 0; + register QBaseBucket **v = dict->vec; + while ( !(*v++) ) + i++; + curNode = dict->vec[i]; + curIndex = i; + return curNode->getData(); +} + + +/*! + \internal + Moves to the next item (postfix). +*/ + +QCollection::Item QGDictIterator::operator()() +{ + if ( !dict ) { +#if defined(CHECK_NULL) + qWarning( "QGDictIterator::operator(): Dictionary has been deleted" ); +#endif + return 0; + } + if ( !curNode ) + return 0; + QCollection::Item d = curNode->getData(); + this->operator++(); + return d; +} + +/*! + \internal + Moves to the next item (prefix). +*/ + +QCollection::Item QGDictIterator::operator++() +{ + if ( !dict ) { +#if defined(CHECK_NULL) + qWarning( "QGDictIterator::operator++: Dictionary has been deleted" ); +#endif + return 0; + } + if ( !curNode ) + return 0; + curNode = curNode->getNext(); + if ( !curNode ) { // no next bucket + register uint i = curIndex + 1; // look from next vec element + register QBaseBucket **v = &dict->vec[i]; + while ( i < dict->size() && !(*v++) ) + i++; + if ( i == dict->size() ) { // nothing found + curNode = 0; + return 0; + } + curNode = dict->vec[i]; + curIndex = i; + } + return curNode->getData(); +} + +/*! + \internal + Moves \e jumps positions forward. +*/ + +QCollection::Item QGDictIterator::operator+=( uint jumps ) +{ + while ( curNode && jumps-- ) + operator++(); + return curNode ? curNode->getData() : 0; +} diff --git a/trunk/qtools/qgdict.h b/trunk/qtools/qgdict.h new file mode 100644 index 0000000..6243364 --- /dev/null +++ b/trunk/qtools/qgdict.h @@ -0,0 +1,222 @@ +/**************************************************************************** +** +** +** Definition of QGDict and QGDictIterator classes +** +** Created : 920529 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QGDICT_H +#define QGDICT_H + +#ifndef QT_H +#include "qcollection.h" +#include "qstring.h" +#endif // QT_H + +class QGDictIterator; +class QGDItList; + + +class QBaseBucket // internal dict node +{ +public: + QCollection::Item getData() { return data; } + QCollection::Item setData( QCollection::Item d ) { return data = d; } + QBaseBucket *getNext() { return next; } + void setNext( QBaseBucket *n) { next = n; } +protected: + QBaseBucket( QCollection::Item d, QBaseBucket *n ) : data(d), next(n) {} + QCollection::Item data; + QBaseBucket *next; +}; + +class QStringBucket : public QBaseBucket +{ +public: + QStringBucket( const QString &k, QCollection::Item d, QBaseBucket *n ) + : QBaseBucket(d,n), key(k) {} + const QString &getKey() const { return key; } +private: + QString key; +}; + +class QAsciiBucket : public QBaseBucket +{ +public: + QAsciiBucket( const char *k, QCollection::Item d, QBaseBucket *n ) + : QBaseBucket(d,n), key(k) {} + const char *getKey() const { return key; } +private: + const char *key; +}; + +class QIntBucket : public QBaseBucket +{ +public: + QIntBucket( long k, QCollection::Item d, QBaseBucket *n ) + : QBaseBucket(d,n), key(k) {} + long getKey() const { return key; } +private: + long key; +}; + +class QPtrBucket : public QBaseBucket +{ +public: + QPtrBucket( void *k, QCollection::Item d, QBaseBucket *n ) + : QBaseBucket(d,n), key(k) {} + void *getKey() const { return key; } +private: + void *key; +}; + + +class Q_EXPORT QGDict : public QCollection // generic dictionary class +{ +public: + uint count() const { return numItems; } + uint size() const { return vlen; } + QCollection::Item look_string( const QString& key, QCollection::Item, + int ); + QCollection::Item look_ascii( const char *key, QCollection::Item, int ); + QCollection::Item look_int( long key, QCollection::Item, int ); + QCollection::Item look_ptr( void *key, QCollection::Item, int ); +#ifndef QT_NO_DATASTREAM + QDataStream &read( QDataStream & ); + QDataStream &write( QDataStream & ) const; +#endif +protected: + enum KeyType { StringKey, AsciiKey, IntKey, PtrKey }; + + QGDict( uint len, KeyType kt, bool cs, bool ck ); + QGDict( const QGDict & ); + ~QGDict(); + + QGDict &operator=( const QGDict & ); + + bool remove_string( const QString &key, QCollection::Item item=0 ); + bool remove_ascii( const char *key, QCollection::Item item=0 ); + bool remove_int( long key, QCollection::Item item=0 ); + bool remove_ptr( void *key, QCollection::Item item=0 ); + QCollection::Item take_string( const QString &key ); + QCollection::Item take_ascii( const char *key ); + QCollection::Item take_int( long key ); + QCollection::Item take_ptr( void *key ); + + void clear(); + void resize( uint ); + + int hashKeyString( const QString & ); + int hashKeyAscii( const char * ); + + void statistics() const; + +#ifndef QT_NO_DATASTREAM + virtual QDataStream &read( QDataStream &, QCollection::Item & ); + virtual QDataStream &write( QDataStream &, QCollection::Item ) const; +#endif +private: + QBaseBucket **vec; + uint vlen; + uint numItems; + uint keytype : 2; + uint cases : 1; + uint copyk : 1; + QGDItList *iterators; + void unlink_common( int, QBaseBucket *, QBaseBucket * ); + QStringBucket *unlink_string( const QString &, + QCollection::Item item = 0 ); + QAsciiBucket *unlink_ascii( const char *, QCollection::Item item = 0 ); + QIntBucket *unlink_int( long, QCollection::Item item = 0 ); + QPtrBucket *unlink_ptr( void *, QCollection::Item item = 0 ); + void init( uint, KeyType, bool, bool ); + friend class QGDictIterator; +}; + + +class Q_EXPORT QGDictIterator // generic dictionary iterator +{ +friend class QGDict; +public: + QGDictIterator( const QGDict & ); + QGDictIterator( const QGDictIterator & ); + QGDictIterator &operator=( const QGDictIterator & ); + ~QGDictIterator(); + + QCollection::Item toFirst(); + + QCollection::Item get() const; + QString getKeyString() const; + const char *getKeyAscii() const; + long getKeyInt() const; + void *getKeyPtr() const; + + QCollection::Item operator()(); + QCollection::Item operator++(); + QCollection::Item operator+=(uint); + +protected: + QGDict *dict; + +private: + QBaseBucket *curNode; + uint curIndex; +}; + +inline QCollection::Item QGDictIterator::get() const +{ + return curNode ? curNode->getData() : 0; +} + +inline QString QGDictIterator::getKeyString() const +{ + return curNode ? ((QStringBucket*)curNode)->getKey() : QString::null; +} + +inline const char *QGDictIterator::getKeyAscii() const +{ + return curNode ? ((QAsciiBucket*)curNode)->getKey() : 0; +} + +inline long QGDictIterator::getKeyInt() const +{ + return curNode ? ((QIntBucket*)curNode)->getKey() : 0; +} + +inline void *QGDictIterator::getKeyPtr() const +{ + return curNode ? ((QPtrBucket*)curNode)->getKey() : 0; +} + + +#endif // QGDICT_H diff --git a/trunk/qtools/qgeneric.h b/trunk/qtools/qgeneric.h new file mode 100644 index 0000000..c2892a0 --- /dev/null +++ b/trunk/qtools/qgeneric.h @@ -0,0 +1,43 @@ +/**************************************************************************** +** +** +** Macros for pasting tokens; utilized by our generic classes +** +** Created : 920529 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QGENERIC_H +#define QGENERIC_H + +#error "do not include qgeneric.h any more" + +#endif // QGENERIC_H diff --git a/trunk/qtools/qglist.cpp b/trunk/qtools/qglist.cpp new file mode 100644 index 0000000..f464a73 --- /dev/null +++ b/trunk/qtools/qglist.cpp @@ -0,0 +1,1223 @@ +/**************************************************************************** +** +** +** Implementation of QGList and QGListIterator classes +** +** Created : 920624 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "qglist.h" +#include "qgvector.h" +#include "qdatastream.h" + + +// NOT REVISED +/*! + \class QLNode qglist.h + \brief The QLNode class is an internal class for the QList template collection. + + QLNode is a doubly linked list node; it has three pointers: + <ol> + <li> Pointer to the previous node. + <li> Pointer to the next node. + <li> Pointer to the actual data. + </ol> + + Sometimes it might be practical to have direct access to the list nodes + in a QList, but it is seldom required. + + \warning Be very careful if you want to access the list nodes. The heap + can easily get corrupted if you make a mistake. + + \sa QList::currentNode(), QList::removeNode(), QList::takeNode() +*/ + +/*! + \fn QCollection::Item QLNode::getData() + Returns a pointer (\c void*) to the actual data in the list node. +*/ + + +/*! + \class QGList qglist.h + \brief The QGList class is an internal class for implementing Qt collection classes. + + QGList is a strictly internal class that acts as a base class for several + \link collection.html collection classes\endlink; QList, QQueue and + QStack. + + QGList has some virtual functions that can be reimplemented to customize + the subclasses. + <ul> + <li> compareItems() compares two collection/list items. + <li> read() reads a collection/list item from a QDataStream. + <li> write() writes a collection/list item to a QDataStream. + </ul> + Normally, you do not have to reimplement any of these functions. + If you still want to reimplement them, see the QStrList class (qstrlist.h), + which is a good example. +*/ + + +/***************************************************************************** + Default implementation of virtual functions + *****************************************************************************/ + +/*! + This virtual function compares two list items. + + Returns: + <ul> + <li> 0 if \e item1 == \e item2 + <li> non-zero if \e item1 != \e item2 + </ul> + + This function returns \e int rather than \e bool so that + reimplementations can return three values and use it to sort by: + + <ul> + <li> 0 if \e item1 == \e item2 + <li> \> 0 (positive integer) if \e item1 \> \e item2 + <li> \< 0 (negative integer) if \e item1 \< \e item2 + </ul> + + The QList::inSort() function requires that compareItems() is implemented + as described here. + + This function should not modify the list because some const functions + call compareItems(). + + The default implementation compares the pointers: + \code + + \endcode +*/ + +int QGList::compareItems( QCollection::Item item1, QCollection::Item item2 ) +{ + return item1 != item2; // compare pointers +} + +#ifndef QT_NO_DATASTREAM +/*! + Reads a collection/list item from the stream \a s and returns a reference + to the stream. + + The default implementation sets \a item to 0. + + \sa write() +*/ + +QDataStream &QGList::read( QDataStream &s, QCollection::Item &item ) +{ + item = 0; + return s; +} + +/*! + Writes a collection/list item to the stream \a s and returns a reference + to the stream. + + The default implementation does nothing. + + \sa read() +*/ + +QDataStream &QGList::write( QDataStream &s, QCollection::Item ) const +{ + return s; +} +#endif // QT_NO_DATASTREAM + +/***************************************************************************** + QGList member functions + *****************************************************************************/ + +/*! + \internal + Constructs an empty list. +*/ + +QGList::QGList() +{ + firstNode = lastNode = curNode = 0; // initialize list + numNodes = 0; + curIndex = -1; + iterators = 0; // initialize iterator list +} + +/*! + \internal + Constructs a copy of \e list. +*/ + +QGList::QGList( const QGList & list ) + : QCollection( list ) +{ + firstNode = lastNode = curNode = 0; // initialize list + numNodes = 0; + curIndex = -1; + iterators = 0; // initialize iterator list + QLNode *n = list.firstNode; + while ( n ) { // copy all items from list + append( n->data ); + n = n->next; + } +} + +/*! + \internal + Removes all items from the list and destroys the list. +*/ + +QGList::~QGList() +{ + clear(); + if ( !iterators ) // no iterators for this list + return; + QGListIterator *i = (QGListIterator*)iterators->first(); + while ( i ) { // notify all iterators that + i->list = 0; // this list is deleted + i->curNode = 0; + i = (QGListIterator*)iterators->next(); + } + delete iterators; +} + + +/*! + \internal + Assigns \e list to this list. +*/ + +QGList& QGList::operator=( const QGList &list ) +{ + clear(); + if ( list.count() > 0 ) { + QLNode *n = list.firstNode; + while ( n ) { // copy all items from list + append( n->data ); + n = n->next; + } + curNode = firstNode; + curIndex = 0; + } + return *this; +} + +/*! + Compares this list with \a list. Retruns TRUE if the lists + contain the same data, else FALSE. +*/ + +bool QGList::operator==( const QGList &list ) const +{ + if ( count() != list.count() ) + return FALSE; + + if ( count() == 0 ) + return TRUE; + + QLNode *n1 = firstNode; + QLNode *n2 = list.firstNode; + while ( n1 && n2 ) { + // should be mutable + if ( ( (QGList*)this )->compareItems( n1->data, n2->data ) != 0 ) + return FALSE; + n1 = n1->next; + n2 = n2->next; + } + + return TRUE; +} + +/*! + \fn uint QGList::count() const + \internal + Returns the number of items in the list. +*/ + + +/*! + \internal + Returns the node at position \e index. Sets this node to current. +*/ + +QLNode *QGList::locate( uint index ) +{ + if ( index == (uint)curIndex ) // current node ? + return curNode; + if ( !curNode && firstNode ) { // set current node + curNode = firstNode; + curIndex = 0; + } + register QLNode *node; + int distance = index - curIndex; // node distance to cur node + bool forward; // direction to traverse + + if ( index >= numNodes ) { +#if defined(CHECK_RANGE) + qWarning( "QGList::locate: Index %d out of range", index ); +#endif + return 0; + } + + if ( distance < 0 ) + distance = -distance; + if ( (uint)distance < index && (uint)distance < numNodes - index ) { + node = curNode; // start from current node + forward = index > (uint)curIndex; + } else if ( index < numNodes - index ) { // start from first node + node = firstNode; + distance = index; + forward = TRUE; + } else { // start from last node + node = lastNode; + distance = numNodes - index - 1; + if ( distance < 0 ) + distance = 0; + forward = FALSE; + } + if ( forward ) { // now run through nodes + while ( distance-- ) + node = node->next; + } else { + while ( distance-- ) + node = node->prev; + } + curIndex = index; // must update index + return curNode = node; +} + + +/*! + \internal + Inserts an item at its sorted position in the list. +*/ + +void QGList::inSort( QCollection::Item d ) +{ + int index = 0; + register QLNode *n = firstNode; + while ( n && compareItems(n->data,d) < 0 ){ // find position in list + n = n->next; + index++; + } + insertAt( index, d ); +} + + +/*! + \internal + Inserts an item at the start of the list. +*/ + +void QGList::prepend( QCollection::Item d ) +{ + register QLNode *n = new QLNode( newItem(d) ); + CHECK_PTR( n ); + n->prev = 0; + if ( (n->next = firstNode) ) // list is not empty + firstNode->prev = n; + else // initialize list + lastNode = n; + firstNode = curNode = n; // curNode affected + numNodes++; + curIndex = 0; +} + + +/*! + \internal + Inserts an item at the end of the list. +*/ + +void QGList::append( QCollection::Item d ) +{ + register QLNode *n = new QLNode( newItem(d) ); + CHECK_PTR( n ); + n->next = 0; + if ( (n->prev = lastNode) ) // list is not empty + lastNode->next = n; + else // initialize list + firstNode = n; + lastNode = curNode = n; // curNode affected + curIndex = numNodes; + numNodes++; +} + + +/*! + \internal + Inserts an item at position \e index in the list. +*/ + +bool QGList::insertAt( uint index, QCollection::Item d ) +{ + if ( index == 0 ) { // insert at head of list + prepend( d ); + return TRUE; + } else if ( index == numNodes ) { // append at tail of list + append( d ); + return TRUE; + } + QLNode *nextNode = locate( index ); + if ( !nextNode ) // illegal position + return FALSE; + QLNode *prevNode = nextNode->prev; + register QLNode *n = new QLNode( newItem(d) ); + CHECK_PTR( n ); + nextNode->prev = n; + prevNode->next = n; + n->prev = prevNode; // link new node into list + n->next = nextNode; + curNode = n; // curIndex set by locate() + numNodes++; + return TRUE; +} + + +/*! + \internal + Relinks node \e n and makes it the first node in the list. +*/ + +void QGList::relinkNode( QLNode *n ) +{ + if ( n == firstNode ) // already first + return; + curNode = n; + unlink(); + n->prev = 0; + if ( (n->next = firstNode) ) // list is not empty + firstNode->prev = n; + else // initialize list + lastNode = n; + firstNode = curNode = n; // curNode affected + numNodes++; + curIndex = 0; +} + + +/*! + \internal + Unlinks the current list node and returns a pointer to this node. +*/ + +QLNode *QGList::unlink() +{ + if ( curNode == 0 ) // null current node + return 0; + register QLNode *n = curNode; // unlink this node + if ( n == firstNode ) { // removing first node ? + if ( (firstNode = n->next) ) { + firstNode->prev = 0; + } else { + lastNode = curNode = 0; // list becomes empty + curIndex = -1; + } + } else { + if ( n == lastNode ) { // removing last node ? + lastNode = n->prev; + lastNode->next = 0; + } else { // neither last nor first node + n->prev->next = n->next; + n->next->prev = n->prev; + } + } + if ( n->next ) { // change current node + curNode = n->next; + } else if ( n->prev ) { + curNode = n->prev; + curIndex--; + } + if ( iterators && iterators->count() ) { // update iterators + QGListIterator *i = (QGListIterator*)iterators->first(); + while ( i ) { // fix all iterators that + if ( i->curNode == n ) // refers to pending node + i->curNode = curNode; + i = (QGListIterator*)iterators->next(); + } + } + numNodes--; + return n; +} + + +/*! + \internal + Removes the node \e n from the list. +*/ + +bool QGList::removeNode( QLNode *n ) +{ +#if defined(CHECK_NULL) + if ( n == 0 || (n->prev && n->prev->next != n) || + (n->next && n->next->prev != n) ) { + qWarning( "QGList::removeNode: Corrupted node" ); + return FALSE; + } +#endif + curNode = n; + unlink(); // unlink node + deleteItem( n->data ); // deallocate this node + delete n; + curNode = firstNode; + curIndex = curNode ? 0 : -1; + return TRUE; +} + +/*! + \internal + Removes the item \e d from the list. Uses compareItems() to find the item. +*/ + +bool QGList::remove( QCollection::Item d ) +{ + if ( d ) { // find the item + if ( find(d) == -1 ) + return FALSE; + } + QLNode *n = unlink(); // unlink node + if ( !n ) + return FALSE; + deleteItem( n->data ); // deallocate this node + delete n; + return TRUE; +} + +/*! + \internal + Removes the item \e d from the list. +*/ + +bool QGList::removeRef( QCollection::Item d ) +{ + if ( d ) { // find the item + if ( findRef(d) == -1 ) + return FALSE; + } + QLNode *n = unlink(); // unlink node + if ( !n ) + return FALSE; + deleteItem( n->data ); // deallocate this node + delete n; + return TRUE; +} + +/*! + \fn bool QGList::removeFirst() + \internal + Removes the first item in the list. +*/ + +/*! + \fn bool QGList::removeLast() + \internal + Removes the last item in the list. +*/ + +/*! + \internal + Removes the item at position \e index from the list. +*/ + +bool QGList::removeAt( uint index ) +{ + if ( !locate(index) ) + return FALSE; + QLNode *n = unlink(); // unlink node + if ( !n ) + return FALSE; + deleteItem( n->data ); // deallocate this node + delete n; + return TRUE; +} + + +/*! + \internal + Takes the node \e n out of the list. +*/ + +QCollection::Item QGList::takeNode( QLNode *n ) +{ +#if defined(CHECK_NULL) + if ( n == 0 || (n->prev && n->prev->next != n) || + (n->next && n->next->prev != n) ) { + qWarning( "QGList::takeNode: Corrupted node" ); + return 0; + } +#endif + curNode = n; + unlink(); // unlink node + Item d = n->data; + delete n; // delete the node, not data + curNode = firstNode; + curIndex = curNode ? 0 : -1; + return d; +} + +/*! + \internal + Takes the current item out of the list. +*/ + +QCollection::Item QGList::take() +{ + QLNode *n = unlink(); // unlink node + Item d = n ? n->data : 0; + delete n; // delete node, keep contents + return d; +} + +/*! + \internal + Takes the item at position \e index out of the list. +*/ + +QCollection::Item QGList::takeAt( uint index ) +{ + if ( !locate(index) ) + return 0; + QLNode *n = unlink(); // unlink node + Item d = n ? n->data : 0; + delete n; // delete node, keep contents + return d; +} + +/*! + \internal + Takes the first item out of the list. +*/ + +QCollection::Item QGList::takeFirst() +{ + first(); + QLNode *n = unlink(); // unlink node + Item d = n ? n->data : 0; + delete n; + return d; +} + +/*! + \internal + Takes the last item out of the list. +*/ + +QCollection::Item QGList::takeLast() +{ + last(); + QLNode *n = unlink(); // unlink node + Item d = n ? n->data : 0; + delete n; + return d; +} + + +/*! + \internal + Removes all items from the list. +*/ + +void QGList::clear() +{ + register QLNode *n = firstNode; + + firstNode = lastNode = curNode = 0; // initialize list + numNodes = 0; + curIndex = -1; + + if ( iterators && iterators->count() ) { + QGListIterator *i = (QGListIterator*)iterators->first(); + while ( i ) { // notify all iterators that + i->curNode = 0; // this list is empty + i = (QGListIterator*)iterators->next(); + } + } + + QLNode *prevNode; + while ( n ) { // for all nodes ... + deleteItem( n->data ); // deallocate data + prevNode = n; + n = n->next; + delete prevNode; // deallocate node + } +} + + +/*! + \internal + Finds an item in the list. +*/ + +int QGList::findRef( QCollection::Item d, bool fromStart ) +{ + register QLNode *n; + int index; + if ( fromStart ) { // start from first node + n = firstNode; + index = 0; + } else { // start from current node + n = curNode; + index = curIndex; + } + while ( n && n->data != d ) { // find exact match + n = n->next; + index++; + } + curNode = n; + curIndex = n ? index : -1; + return curIndex; // return position of item +} + +/*! + \internal + Finds an item in the list. Uses compareItems(). +*/ + +int QGList::find( QCollection::Item d, bool fromStart ) +{ + register QLNode *n; + int index; + if ( fromStart ) { // start from first node + n = firstNode; + index = 0; + } else { // start from current node + n = curNode; + index = curIndex; + } + while ( n && compareItems(n->data,d) ){ // find equal match + n = n->next; + index++; + } + curNode = n; + curIndex = n ? index : -1; + return curIndex; // return position of item +} + + +/*! + \internal + Counts the number an item occurs in the list. +*/ + +uint QGList::containsRef( QCollection::Item d ) const +{ + register QLNode *n = firstNode; + uint count = 0; + while ( n ) { // for all nodes... + if ( n->data == d ) // count # exact matches + count++; + n = n->next; + } + return count; +} + +/*! + \internal + Counts the number an item occurs in the list. Uses compareItems(). +*/ + +uint QGList::contains( QCollection::Item d ) const +{ + register QLNode *n = firstNode; + uint count = 0; + QGList *that = (QGList*)this; // mutable for compareItems() + while ( n ) { // for all nodes... + if ( !that->compareItems(n->data,d) ) // count # equal matches + count++; + n = n->next; + } + return count; +} + + +/*! + \fn QCollection::Item QGList::at( uint index ) + \internal + Sets the item at position \e index to the current item. +*/ + +/*! + \fn int QGList::at() const + \internal + Returns the current index. +*/ + +/*! + \fn QLNode *QGList::currentNode() const + \internal + Returns the current node. +*/ + +/*! + \fn QCollection::Item QGList::get() const + \internal + Returns the current item. +*/ + +/*! + \fn QCollection::Item QGList::cfirst() const + \internal + Returns the first item in the list. +*/ + +/*! + \fn QCollection::Item QGList::clast() const + \internal + Returns the last item in the list. +*/ + + +/*! + \internal + Returns the first list item. Sets this to current. +*/ + +QCollection::Item QGList::first() +{ + if ( firstNode ) { + curIndex = 0; + return (curNode=firstNode)->data; + } + return 0; +} + +/*! + \internal + Returns the last list item. Sets this to current. +*/ + +QCollection::Item QGList::last() +{ + if ( lastNode ) { + curIndex = numNodes-1; + return (curNode=lastNode)->data; + } + return 0; +} + +/*! + \internal + Returns the next list item (after current). Sets this to current. +*/ + +QCollection::Item QGList::next() +{ + if ( curNode ) { + if ( curNode->next ) { + curIndex++; + curNode = curNode->next; + return curNode->data; + } + curIndex = -1; + curNode = 0; + } + return 0; +} + +/*! + \internal + Returns the previous list item (before current). Sets this to current. +*/ + +QCollection::Item QGList::prev() +{ + if ( curNode ) { + if ( curNode->prev ) { + curIndex--; + curNode = curNode->prev; + return curNode->data; + } + curIndex = -1; + curNode = 0; + } + return 0; +} + + +/*! + \internal + Converts the list to a vector. +*/ + +void QGList::toVector( QGVector *vector ) const +{ + vector->clear(); + if ( !vector->resize( count() ) ) + return; + register QLNode *n = firstNode; + uint i = 0; + while ( n ) { + vector->insert( i, n->data ); + n = n->next; + i++; + } +} + +void QGList::heapSortPushDown( QCollection::Item* heap, int first, int last ) +{ + int r = first; + while( r <= last/2 ) { + // Node r has only one child ? + if ( last == 2*r ) { + // Need for swapping ? + if ( compareItems( heap[r], heap[ 2*r ] ) > 0 ) { + QCollection::Item tmp = heap[r]; + heap[ r ] = heap[ 2*r ]; + heap[ 2*r ] = tmp; + } + // That's it ... + r = last; + } else { + // Node has two children + if ( compareItems( heap[r], heap[ 2*r ] ) > 0 && + compareItems( heap[ 2*r ], heap[ 2*r+1 ] ) <= 0 ) { + // Swap with left child + QCollection::Item tmp = heap[r]; + heap[ r ] = heap[ 2*r ]; + heap[ 2*r ] = tmp; + r *= 2; + } else if ( compareItems( heap[r], heap[ 2*r+1 ] ) > 0 && + compareItems( heap[ 2*r+1 ], heap[ 2*r ] ) < 0 ) { + // Swap with right child + QCollection::Item tmp = heap[r]; + heap[ r ] = heap[ 2*r+1 ]; + heap[ 2*r+1 ] = tmp; + r = 2*r+1; + } else { + // We are done + r = last; + } + } + } +} + + +/*! Sorts the list by the result of the virtual compareItems() function. + + The Heap-Sort algorithm is used for sorting. It sorts n items with + O(n*log n) compares. This is the asymptotic optimal solution of the + sorting problem. +*/ + +void QGList::sort() +{ + uint n = count(); + if ( n < 2 ) + return; + + // Create the heap + QCollection::Item* realheap = new QCollection::Item[ n ]; + // Wow, what a fake. But I want the heap to be indexed as 1...n + QCollection::Item* heap = realheap - 1; + int size = 0; + QLNode* insert = firstNode; + for( ; insert != 0; insert = insert->next ) { + heap[++size] = insert->data; + int i = size; + while( i > 1 && compareItems( heap[i], heap[ i / 2 ] ) < 0 ) { + QCollection::Item tmp = heap[ i ]; + heap[ i ] = heap[ i/2 ]; + heap[ i/2 ] = tmp; + i /= 2; + } + } + + insert = firstNode; + // Now do the sorting + for ( int i = n; i > 0; i-- ) { + insert->data = heap[1]; + insert = insert->next; + if ( i > 1 ) { + heap[1] = heap[i]; + heapSortPushDown( heap, 1, i - 1 ); + } + } + + delete [] realheap; +} + + +/***************************************************************************** + QGList stream functions + *****************************************************************************/ + +#ifndef QT_NO_DATASTREAM +QDataStream &operator>>( QDataStream &s, QGList &list ) +{ // read list + return list.read( s ); +} + +QDataStream &operator<<( QDataStream &s, const QGList &list ) +{ // write list + return list.write( s ); +} + +/*! + \internal + Reads a list from the stream \e s. +*/ + +QDataStream &QGList::read( QDataStream &s ) +{ + uint num; + s >> num; // read number of items + clear(); // clear list + while ( num-- ) { // read all items + Item d; + read( s, d ); + CHECK_PTR( d ); + if ( !d ) // no memory + break; + QLNode *n = new QLNode( d ); + CHECK_PTR( n ); + if ( !n ) // no memory + break; + n->next = 0; + if ( (n->prev = lastNode) ) // list is not empty + lastNode->next = n; + else // initialize list + firstNode = n; + lastNode = n; + numNodes++; + } + curNode = firstNode; + curIndex = curNode ? 0 : -1; + return s; +} + +/*! + \internal + Writes the list to the stream \e s. +*/ + +QDataStream &QGList::write( QDataStream &s ) const +{ + s << count(); // write number of items + QLNode *n = firstNode; + while ( n ) { // write all items + write( s, n->data ); + n = n->next; + } + return s; +} + +#endif // QT_NO_DATASTREAM + +/***************************************************************************** + QGListIterator member functions + *****************************************************************************/ + +/*! + \class QGListIterator qglist.h + \brief The QGListIterator class is an internal class for implementing QListIterator. + + QGListIterator is a strictly internal class that does the heavy work for + QListIterator. +*/ + +/*! + \internal + Constructs an iterator that operates on the list \e l. +*/ + +QGListIterator::QGListIterator( const QGList &l ) +{ + list = (QGList *)&l; // get reference to list + curNode = list->firstNode; // set to first node + if ( !list->iterators ) { + list->iterators = new QGList; // create iterator list + CHECK_PTR( list->iterators ); + } + list->iterators->append( this ); // attach iterator to list +} + +/*! + \internal + Constructs a copy of the iterator \e it. +*/ + +QGListIterator::QGListIterator( const QGListIterator &it ) +{ + list = it.list; + curNode = it.curNode; + if ( list ) + list->iterators->append( this ); // attach iterator to list +} + +/*! + \internal + Assigns a copy of the iterator \e it and returns a reference to this + iterator. +*/ + +QGListIterator &QGListIterator::operator=( const QGListIterator &it ) +{ + if ( list ) // detach from old list + list->iterators->removeRef( this ); + list = it.list; + curNode = it.curNode; + if ( list ) + list->iterators->append( this ); // attach to new list + return *this; +} + +/*! + \internal + Destroys the iterator. +*/ + +QGListIterator::~QGListIterator() +{ + if ( list ) // detach iterator from list + list->iterators->removeRef(this); +} + + +/*! + \fn bool QGListIterator::atFirst() const + \internal + Returns TRUE if the iterator points to the first item, otherwise FALSE. +*/ + +/*! + \fn bool QGListIterator::atLast() const + \internal + Returns TRUE if the iterator points to the last item, otherwise FALSE. +*/ + + +/*! + \internal + Sets the list iterator to point to the first item in the list. +*/ + +QCollection::Item QGListIterator::toFirst() +{ + if ( !list ) { +#if defined(CHECK_NULL) + qWarning( "QGListIterator::toFirst: List has been deleted" ); +#endif + return 0; + } + return list->firstNode ? (curNode = list->firstNode)->getData() : 0; +} + +/*! + \internal + Sets the list iterator to point to the last item in the list. +*/ + +QCollection::Item QGListIterator::toLast() +{ + if ( !list ) { +#if defined(CHECK_NULL) + qWarning( "QGListIterator::toLast: List has been deleted" ); +#endif + return 0; + } + return list->lastNode ? (curNode = list->lastNode)->getData() : 0; +} + + +/*! + \fn QCollection::Item QGListIterator::get() const + \internal + Returns the iterator item. +*/ + + +/*! + \internal + Moves to the next item (postfix). +*/ + +QCollection::Item QGListIterator::operator()() +{ + if ( !curNode ) + return 0; + QCollection::Item d = curNode->getData(); + curNode = curNode->next; + return d; +} + +/*! + \internal + Moves to the next item (prefix). +*/ + +QCollection::Item QGListIterator::operator++() +{ + if ( !curNode ) + return 0; + curNode = curNode->next; + return curNode ? curNode->getData() : 0; +} + +/*! + \internal + Moves \e jumps positions forward. +*/ + +QCollection::Item QGListIterator::operator+=( uint jumps ) +{ + while ( curNode && jumps-- ) + curNode = curNode->next; + return curNode ? curNode->getData() : 0; +} + +/*! + \internal + Moves to the previous item (prefix). +*/ + +QCollection::Item QGListIterator::operator--() +{ + if ( !curNode ) + return 0; + curNode = curNode->prev; + return curNode ? curNode->getData() : 0; +} + +/*! + \internal + Moves \e jumps positions backward. +*/ + +QCollection::Item QGListIterator::operator-=( uint jumps ) +{ + while ( curNode && jumps-- ) + curNode = curNode->prev; + return curNode ? curNode->getData() : 0; +} diff --git a/trunk/qtools/qglist.h b/trunk/qtools/qglist.h new file mode 100644 index 0000000..f400b64 --- /dev/null +++ b/trunk/qtools/qglist.h @@ -0,0 +1,257 @@ +/**************************************************************************** +** +** +** Definition of QGList and QGListIterator classes +** +** Created : 920624 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QGLIST_H +#define QGLIST_H + +#ifndef QT_H +#include "qcollection.h" +#endif // QT_H + + +/***************************************************************************** + QLNode class (internal doubly linked list node) + *****************************************************************************/ + +class Q_EXPORT QLNode +{ +friend class QGList; +friend class QGListIterator; +public: + QCollection::Item getData() { return data; } +private: + QCollection::Item data; + QLNode *prev; + QLNode *next; + QLNode( QCollection::Item d ) { data = d; } +}; + + +/***************************************************************************** + QGList class + *****************************************************************************/ + +class Q_EXPORT QGList : public QCollection // doubly linked generic list +{ +friend class QGListIterator; +friend class QGVector; // needed by QGVector::toList +public: + uint count() const; // return number of nodes + +#ifndef QT_NO_DATASTREAM + QDataStream &read( QDataStream & ); // read list from stream + QDataStream &write( QDataStream & ) const; // write list to stream +#endif +protected: + QGList(); // create empty list + QGList( const QGList & ); // make copy of other list + virtual ~QGList(); + + QGList &operator=( const QGList & ); // assign from other list + bool operator==( const QGList& ) const; + + void inSort( QCollection::Item ); // add item sorted in list + void append( QCollection::Item ); // add item at end of list + bool insertAt( uint index, QCollection::Item ); // add item at i'th position + void relinkNode( QLNode * ); // relink as first item + bool removeNode( QLNode * ); // remove node + bool remove( QCollection::Item = 0 ); // remove item (0=current) + bool removeRef( QCollection::Item = 0 ); // remove item (0=current) + bool removeFirst(); // remove first item + bool removeLast(); // remove last item + bool removeAt( uint index ); // remove item at i'th position + QCollection::Item takeNode( QLNode * ); // take out node + QCollection::Item take(); // take out current item + QCollection::Item takeAt( uint index ); // take out item at i'th pos + QCollection::Item takeFirst(); // take out first item + QCollection::Item takeLast(); // take out last item + + void sort(); // sort all items; + void clear(); // remove all items + + int findRef( QCollection::Item, bool = TRUE ); // find exact item in list + int find( QCollection::Item, bool = TRUE ); // find equal item in list + + uint containsRef( QCollection::Item ) const; // get number of exact matches + uint contains( QCollection::Item ) const; // get number of equal matches + + QCollection::Item at( uint index ); // access item at i'th pos + int at() const; // get current index + QLNode *currentNode() const; // get current node + + QCollection::Item get() const; // get current item + + QCollection::Item cfirst() const; // get ptr to first list item + QCollection::Item clast() const; // get ptr to last list item + QCollection::Item first(); // set first item in list curr + QCollection::Item last(); // set last item in list curr + QCollection::Item next(); // set next item in list curr + QCollection::Item prev(); // set prev item in list curr + + void toVector( QGVector * ) const; // put items in vector + + virtual int compareItems( QCollection::Item, QCollection::Item ); + +#ifndef QT_NO_DATASTREAM + virtual QDataStream &read( QDataStream &, QCollection::Item & ); + virtual QDataStream &write( QDataStream &, QCollection::Item ) const; +#endif +private: + void prepend( QCollection::Item ); // add item at start of list + + void heapSortPushDown( QCollection::Item* heap, int first, int last ); + + QLNode *firstNode; // first node + QLNode *lastNode; // last node + QLNode *curNode; // current node + int curIndex; // current index + uint numNodes; // number of nodes + QGList *iterators; // list of iterators + + QLNode *locate( uint ); // get node at i'th pos + QLNode *unlink(); // unlink node +}; + + +inline uint QGList::count() const +{ + return numNodes; +} + +inline bool QGList::removeFirst() +{ + first(); + return remove(); +} + +inline bool QGList::removeLast() +{ + last(); + return remove(); +} + +inline int QGList::at() const +{ + return curIndex; +} + +inline QCollection::Item QGList::at( uint index ) +{ + QLNode *n = locate( index ); + return n ? n->data : 0; +} + +inline QLNode *QGList::currentNode() const +{ + return curNode; +} + +inline QCollection::Item QGList::get() const +{ + return curNode ? curNode->data : 0; +} + +inline QCollection::Item QGList::cfirst() const +{ + return firstNode ? firstNode->data : 0; +} + +inline QCollection::Item QGList::clast() const +{ + return lastNode ? lastNode->data : 0; +} + + +/***************************************************************************** + QGList stream functions + *****************************************************************************/ + +#ifndef QT_NO_DATASTREAM +Q_EXPORT QDataStream &operator>>( QDataStream &, QGList & ); +Q_EXPORT QDataStream &operator<<( QDataStream &, const QGList & ); +#endif + +/***************************************************************************** + QGListIterator class + *****************************************************************************/ + +class Q_EXPORT QGListIterator // QGList iterator +{ +friend class QGList; +protected: + QGListIterator( const QGList & ); + QGListIterator( const QGListIterator & ); + QGListIterator &operator=( const QGListIterator & ); + ~QGListIterator(); + + bool atFirst() const; // test if at first item + bool atLast() const; // test if at last item + QCollection::Item toFirst(); // move to first item + QCollection::Item toLast(); // move to last item + + QCollection::Item get() const; // get current item + QCollection::Item operator()(); // get current and move to next + QCollection::Item operator++(); // move to next item (prefix) + QCollection::Item operator+=(uint); // move n positions forward + QCollection::Item operator--(); // move to prev item (prefix) + QCollection::Item operator-=(uint); // move n positions backward + +protected: + QGList *list; // reference to list + +private: + QLNode *curNode; // current node in list +}; + + +inline bool QGListIterator::atFirst() const +{ + return curNode == list->firstNode; +} + +inline bool QGListIterator::atLast() const +{ + return curNode == list->lastNode; +} + +inline QCollection::Item QGListIterator::get() const +{ + return curNode ? curNode->data : 0; +} + + +#endif // QGLIST_H diff --git a/trunk/qtools/qglobal.cpp b/trunk/qtools/qglobal.cpp new file mode 100644 index 0000000..50f5202 --- /dev/null +++ b/trunk/qtools/qglobal.cpp @@ -0,0 +1,685 @@ +/**************************************************************************** +** +** +** Global functions +** +** Created : 920604 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "qglobal.h" +#include "qasciidict.h" +#include "qstring.h" +#include <stdio.h> +#include <stdarg.h> +#include <stdlib.h> + +// NOT REVISED + +/*! + \relates QApplication + Returns the Qt version number for the library, typically "1.30" + or "2.1.0". +*/ + +const char *qVersion() +{ + return QT_VERSION_STR; +} + + +/***************************************************************************** + System detection routines + *****************************************************************************/ + +static bool si_alreadyDone = FALSE; +static int si_wordSize; +static bool si_bigEndian; + +/*! + \relates QApplication + Obtains information about the system. + + The system's word size in bits (typically 32) is returned in \e *wordSize. + The \e *bigEndian is set to TRUE if this is a big-endian machine, + or to FALSE if this is a little-endian machine. + + This function calls qFatal() with a message if the computer is truly weird + (i.e. different endianness for 16 bit and 32 bit integers). +*/ + +bool qSysInfo( int *wordSize, bool *bigEndian ) +{ +#if defined(CHECK_NULL) + ASSERT( wordSize != 0 ); + ASSERT( bigEndian != 0 ); +#endif + + if ( si_alreadyDone ) { // run it only once + *wordSize = si_wordSize; + *bigEndian = si_bigEndian; + return TRUE; + } + si_alreadyDone = TRUE; + + si_wordSize = 0; + uint n = (uint)(~0); + while ( n ) { // detect word size + si_wordSize++; + n /= 2; + } + *wordSize = si_wordSize; + + if ( *wordSize != 64 && + *wordSize != 32 && + *wordSize != 16 ) { // word size: 16, 32 or 64 +#if defined(CHECK_RANGE) + qFatal( "qSysInfo: Unsupported system word size %d", *wordSize ); +#endif + return FALSE; + } + if ( sizeof(Q_INT8) != 1 || sizeof(Q_INT16) != 2 || sizeof(Q_INT32) != 4 || + sizeof(float) != 4 || sizeof(double) != 8 ) { +#if defined(CHECK_RANGE) + qFatal( "qSysInfo: Unsupported system data type size" ); +#endif + return FALSE; + } + + bool be16, be32; // determine byte ordering + short ns = 0x1234; + int nl = 0x12345678; + + unsigned char *p = (unsigned char *)(&ns); // 16-bit integer + be16 = *p == 0x12; + + p = (unsigned char *)(&nl); // 32-bit integer + if ( p[0] == 0x12 && p[1] == 0x34 && p[2] == 0x56 && p[3] == 0x78 ) + be32 = TRUE; + else + if ( p[0] == 0x78 && p[1] == 0x56 && p[2] == 0x34 && p[3] == 0x12 ) + be32 = FALSE; + else + be32 = !be16; + + if ( be16 != be32 ) { // strange machine! +#if defined(CHECK_RANGE) + qFatal( "qSysInfo: Inconsistent system byte order" ); +#endif + return FALSE; + } + + *bigEndian = si_bigEndian = be32; + return TRUE; +} + + +/***************************************************************************** + Debug output routines + *****************************************************************************/ + +/*! + \fn void qDebug( const char *msg, ... ) + + \relates QApplication + Prints a debug message, or calls the message handler (if it has been + installed). + + This function takes a format string and a list of arguments, similar to + the C printf() function. + + Example: + \code + qDebug( "my window handle = %x", myWidget->id() ); + \endcode + + Under X11, the text is printed to stderr. Under Windows, the text is + sent to the debugger. + + \warning The internal buffer is limited to 8196 bytes (including the + 0-terminator). + + \sa qWarning(), qFatal(), qInstallMsgHandler(), + \link debug.html Debugging\endlink +*/ + +/*! + \fn void qWarning( const char *msg, ... ) + + \relates QApplication + Prints a warning message, or calls the message handler (if it has been + installed). + + This function takes a format string and a list of arguments, similar to + the C printf() function. + + Example: + \code + void f( int c ) + { + if ( c > 200 ) + qWarning( "f: bad argument, c == %d", c ); + } + \endcode + + Under X11, the text is printed to stderr. Under Windows, the text is + sent to the debugger. + + \warning The internal buffer is limited to 8196 bytes (including the + 0-terminator). + + \sa qDebug(), qFatal(), qInstallMsgHandler(), + \link debug.html Debugging\endlink +*/ + +/*! + \fn void qFatal( const char *msg, ... ) + + \relates QApplication + Prints a fatal error message and exits, or calls the message handler (if it + has been installed). + + This function takes a format string and a list of arguments, similar to + the C printf() function. + + Example: + \code + int divide( int a, int b ) + { + if ( b == 0 ) // program error + qFatal( "divide: cannot divide by zero" ); + return a/b; + } + \endcode + + Under X11, the text is printed to stderr. Under Windows, the text is + sent to the debugger. + + \warning The internal buffer is limited to 8196 bytes (including the + 0-terminator). + + \sa qDebug(), qWarning(), qInstallMsgHandler(), + \link debug.html Debugging\endlink +*/ + + +static msg_handler handler = 0; // pointer to debug handler + + +#ifdef _OS_MAC_ + +static FILE * mac_debug=0; + +void qDebug( const char *msg, ... ) +{ + mac_debug=fopen( "debug.txt", "a+" ); + if(mac_debug) { + char buf[8196]; + va_list ap; + va_start( ap, msg ); // use variable arg list + if ( handler ) { + vsprintf( buf, msg, ap ); + va_end( ap ); + (*handler)( QtDebugMsg, buf ); + } else { + vfprintf( mac_debug, msg, ap ); + va_end( ap ); + fprintf( mac_debug, "\n" ); // add newline + fflush( mac_debug ); + } + fclose(mac_debug); + } else { + exit(0); + } +} + +// copied... this looks really bad. +void debug( const char *msg, ... ) +{ + mac_debug=fopen( "debug.txt", "a+" ); + if(mac_debug) { + char buf[8196]; + va_list ap; + va_start( ap, msg ); // use variable arg list + if ( handler ) { + vsprintf( buf, msg, ap ); + va_end( ap ); + (*handler)( QtDebugMsg, buf ); + } else { + vfprintf( mac_debug, msg, ap ); + va_end( ap ); + fprintf( mac_debug, "\n" ); // add newline + fflush( mac_debug ); + } + fclose(mac_debug); + } +} + +void qWarning( const char *msg, ... ) +{ + mac_debug=fopen( "debug.txt", "a+" ); + if(mac_debug) { + char buf[8196]; + va_list ap; + va_start( ap, msg ); // use variable arg list + if ( handler ) { + vsprintf( buf, msg, ap ); + va_end( ap ); + (*handler)( QtDebugMsg, buf ); + } else { + vfprintf( mac_debug, msg, ap ); + va_end( ap ); + fprintf( mac_debug, "\n" ); // add newline + fflush( mac_debug ); + } + fclose(mac_debug); + } +} + +// copied... this looks really bad. +void warning( const char *msg, ... ) +{ + mac_debug=fopen( "debug.txt", "a+" ); + if(mac_debug) { + char buf[8196]; + va_list ap; + va_start( ap, msg ); // use variable arg list + if ( handler ) { + vsprintf( buf, msg, ap ); + va_end( ap ); + (*handler)( QtDebugMsg, buf ); + } else { + vfprintf( mac_debug, msg, ap ); + va_end( ap ); + fprintf( mac_debug, "\n" ); // add newline + fflush( mac_debug ); + } + fclose(mac_debug); + } +} + +void qFatal( const char *msg, ... ) +{ + mac_debug=fopen( "debug.txt", "a+"); + if(mac_debug) { + char buf[8196]; + va_list ap; + va_start( ap, msg ); // use variable arg list + if ( handler ) { + vsprintf( buf, msg, ap ); + va_end( ap ); + (*handler)( QtDebugMsg, buf ); + } else { + vfprintf( mac_debug, msg, ap ); + va_end( ap ); + fprintf( mac_debug, "\n" ); // add newline + fflush( mac_debug ); + } + fclose(mac_debug); + } + exit(0); +} + +// copied... this looks really bad. +void fatal( const char *msg, ... ) +{ + mac_debug=fopen( "debug.txt", "a+" ); + if(mac_debug) { + char buf[8196]; + va_list ap; + va_start( ap, msg ); // use variable arg list + if ( handler ) { + vsprintf( buf, msg, ap ); + va_end( ap ); + (*handler)( QtDebugMsg, buf ); + } else { + vfprintf( mac_debug, msg, ap ); + va_end( ap ); + fprintf( mac_debug, "\n" ); // add newline + fflush( mac_debug ); + } + fclose(mac_debug); + } + exit(0); +} + +#else + +void qDebug( const char *msg, ... ) +{ + char buf[8196]; + va_list ap; + va_start( ap, msg ); // use variable arg list + if ( handler ) { + vsprintf( buf, msg, ap ); // ### vsnprintf would be great here + va_end( ap ); + (*handler)( QtDebugMsg, buf ); + } else { + vfprintf( stderr, msg, ap ); + va_end( ap ); + fprintf( stderr, "\n" ); // add newline + } +} + +// copied... this looks really bad. +void debug( const char *msg, ... ) +{ + char buf[8196]; + va_list ap; + va_start( ap, msg ); // use variable arg list + if ( handler ) { + vsprintf( buf, msg, ap ); + va_end( ap ); + (*handler)( QtDebugMsg, buf ); + } else { + vfprintf( stderr, msg, ap ); + va_end( ap ); + fprintf( stderr, "\n" ); // add newline + } +} + +void qWarning( const char *msg, ... ) +{ + char buf[8196]; + va_list ap; + va_start( ap, msg ); // use variable arg list + if ( handler ) { + vsprintf( buf, msg, ap ); + va_end( ap ); + (*handler)( QtWarningMsg, buf ); + } else { + vfprintf( stderr, msg, ap ); + va_end( ap ); + fprintf( stderr, "\n" ); // add newline + } +} + + +// again, copied +void warning( const char *msg, ... ) +{ + char buf[8196]; + va_list ap; + va_start( ap, msg ); // use variable arg list + if ( handler ) { + vsprintf( buf, msg, ap ); + va_end( ap ); + (*handler)( QtWarningMsg, buf ); + } else { + vfprintf( stderr, msg, ap ); + va_end( ap ); + fprintf( stderr, "\n" ); // add newline + } +} + +void qFatal( const char *msg, ... ) +{ + char buf[8196]; + va_list ap; + va_start( ap, msg ); // use variable arg list + if ( handler ) { + vsprintf( buf, msg, ap ); + va_end( ap ); + (*handler)( QtFatalMsg, buf ); + } else { + vfprintf( stderr, msg, ap ); + va_end( ap ); + fprintf( stderr, "\n" ); // add newline +#if defined(_OS_UNIX_) && defined(DEBUG) + abort(); // trap; generates core dump +#else + exit( 1 ); // goodbye cruel world +#endif + } +} + +// yet again, copied +void fatal( const char *msg, ... ) +{ + char buf[8196]; + va_list ap; + va_start( ap, msg ); // use variable arg list + if ( handler ) { + vsprintf( buf, msg, ap ); + va_end( ap ); + (*handler)( QtFatalMsg, buf ); + } else { + vfprintf( stderr, msg, ap ); + va_end( ap ); + fprintf( stderr, "\n" ); // add newline +#if defined(_OS_UNIX_) && defined(DEBUG) + abort(); // trap; generates core dump +#else + exit( 1 ); // goodbye cruel world +#endif + } +} + +#endif + + +/*! + \fn void ASSERT( bool test ) + \relates QApplication + Prints a warning message containing the source code file name and line number + if \e test is FALSE. + + This is really a macro defined in qglobal.h. + + ASSERT is useful for testing required conditions in your program. + + Example: + \code + // + // File: div.cpp + // + + #include <qglobal.h> + + int divide( int a, int b ) + { + ASSERT( b != 0 ); // this is line 9 + return a/b; + } + \endcode + + If \c b is zero, the ASSERT statement will output the following message + using the qWarning() function: + \code + ASSERT: "b == 0" in div.cpp (9) + \endcode + + \sa qWarning(), \link debug.html Debugging\endlink +*/ + + +/*! + \fn void CHECK_PTR( void *p ) + \relates QApplication + If \e p is null, a fatal messages says that the program ran out of memory + and exits. If \e p is not null, nothing happens. + + This is really a macro defined in qglobal.h. + + Example: + \code + int *a; + CHECK_PTR( a = new int[80] ); // never do this! + // do this instead: + a = new int[80]; + CHECK_PTR( a ); // this is fine + \endcode + + \sa qFatal(), \link debug.html Debugging\endlink +*/ + + +// +// The CHECK_PTR macro calls this function to check if an allocation went ok. +// + +bool qt_check_pointer( bool c, const char *n, int l ) +{ + if ( c ) + qFatal( "In file %s, line %d: Out of memory", n, l ); + return TRUE; +} + + +static bool firstObsoleteWarning(const char *obj, const char *oldfunc ) +{ + static QAsciiDict<int> *obsoleteDict = 0; + if ( !obsoleteDict ) { // first time func is called + obsoleteDict = new QAsciiDict<int>; +#if defined(DEBUG) + qDebug( + "You are using obsolete functions in the Qt library. Call the function\n" + "qSuppressObsoleteWarnings() to suppress obsolete warnings.\n" + ); +#endif + } + QCString s( obj ); + s += "::"; + s += oldfunc; + if ( obsoleteDict->find(s.data()) == 0 ) { + obsoleteDict->insert( s.data(), (int*)1 ); // anything different from 0 + return TRUE; + } + return FALSE; +} + +static bool suppressObsolete = FALSE; + +void qSuppressObsoleteWarnings( bool suppress ) +{ + suppressObsolete = suppress; +} + +void qObsolete( const char *obj, const char *oldfunc, const char *newfunc ) +{ + if ( suppressObsolete ) + return; + if ( !firstObsoleteWarning(obj, oldfunc) ) + return; + if ( obj ) + qDebug( "%s::%s: This function is obsolete, use %s instead.", + obj, oldfunc, newfunc ); + else + qDebug( "%s: This function is obsolete, use %s instead.", + oldfunc, newfunc ); +} + +void qObsolete( const char *obj, const char *oldfunc ) +{ + if ( suppressObsolete ) + return; + if ( !firstObsoleteWarning(obj, oldfunc) ) + return; + if ( obj ) + qDebug( "%s::%s: This function is obsolete.", obj, oldfunc ); + else + qDebug( "%s: This function is obsolete.", oldfunc ); +} + +void qObsolete( const char *message ) +{ + if ( suppressObsolete ) + return; + if ( !firstObsoleteWarning( "Qt", message) ) + return; + qDebug( "%s", message ); +} + + +/*! + \relates QApplication + Installs a Qt message handler. Returns a pointer to the message handler + previously defined. + + The message handler is a function that prints out debug messages, + warnings and fatal error messages. The Qt library (debug version) + contains hundreds of warning messages that are printed when internal + errors (usually invalid function arguments) occur. If you implement + your own message handler, you get total control of these messages. + + The default message handler prints the message to the standard output + under X11 or to the debugger under Windows. If it is a fatal message, + the application aborts immediately. + + Only one message handler can be defined, since this is usually done on + an application-wide basis to control debug output. + + To restore the message handler, call \c qInstallMsgHandler(0). + + Example: + \code + #include <qapplication.h> + #include <stdio.h> + #include <stdlib.h> + + void myMessageOutput( QtMsgType type, const char *msg ) + { + switch ( type ) { + case QtDebugMsg: + fprintf( stderr, "Debug: %s\n", msg ); + break; + case QtWarningMsg: + fprintf( stderr, "Warning: %s\n", msg ); + break; + case QtFatalMsg: + fprintf( stderr, "Fatal: %s\n", msg ); + abort(); // dump core on purpose + } + } + + int main( int argc, char **argv ) + { + qInstallMsgHandler( myMessageOutput ); + QApplication a( argc, argv ); + ... + return a.exec(); + } + \endcode + + \sa qDebug(), qWarning(), qFatal(), \link debug.html Debugging\endlink +*/ + +msg_handler qInstallMsgHandler( msg_handler h ) +{ + msg_handler old = handler; + handler = h; + return old; +} + + +#ifdef _WS_WIN_ +bool qt_winunicode=FALSE; +#endif diff --git a/trunk/qtools/qglobal.h b/trunk/qtools/qglobal.h new file mode 100644 index 0000000..352d985 --- /dev/null +++ b/trunk/qtools/qglobal.h @@ -0,0 +1,644 @@ +/**************************************************************************** +** +** +** Global type declarations and definitions +** +** Created : 920529 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QGLOBAL_H +#define QGLOBAL_H + + +#define QT_VERSION 223 +#define QT_VERSION_STR "2.2.3" + + +// +// The operating system, must be one of: (_OS_x_) +// +// MAC - Macintosh +// MSDOS - MS-DOS and Windows +// OS2 - OS/2 +// OS2EMX - XFree86 on OS/2 (not PM) +// WIN32 - Win32 (Windows 95/98 and Windows NT) +// SUN - SunOS +// SOLARIS - Sun Solaris +// HPUX - HP-UX +// ULTRIX - DEC Ultrix +// LINUX - Linux +// FREEBSD - FreeBSD +// NETBSD - NetBSD +// OPENBSD - OpenBSD +// IRIX - SGI Irix +// OSF - OSF Unix +// BSDI - BSDI Unix +// SCO - SCO of some sort +// AIX - AIX Unix +// UNIXWARE - SCO UnixWare +// GNU - GNU Hurd +// DGUX - DG Unix +// UNIX - Any UNIX bsd/sysv system +// + +#if defined(__APPLE__) || defined(macintosh) +#define _OS_MAC_ +# ifdef MAC_OS_X_VERSION_MIN_REQUIRED +# undef MAC_OS_X_VERSION_MIN_REQUIRED +# endif +# define MAC_OS_X_VERSION_MIN_REQUIRED MAC_OS_X_VERSION_10_3 +# include <AvailabilityMacros.h> +# if !defined(MAC_OS_X_VERSION_10_3) +# define MAC_OS_X_VERSION_10_3 MAC_OS_X_VERSION_10_2 + 1 +# endif +# if !defined(MAC_OS_X_VERSION_10_4) +# define MAC_OS_X_VERSION_10_4 MAC_OS_X_VERSION_10_3 + 1 +# endif +# if !defined(MAC_OS_X_VERSION_10_5) +# define MAC_OS_X_VERSION_10_5 MAC_OS_X_VERSION_10_4 + 1 +# endif +# if !defined(MAC_OS_X_VERSION_10_6) +# define MAC_OS_X_VERSION_10_6 MAC_OS_X_VERSION_10_5 + 1 +# endif +# if !defined(MAC_OS_X_VERSION_10_7) +# define MAC_OS_X_VERSION_10_7 MAC_OS_X_VERSION_10_6 + 1 +# endif +# if (MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_7) +# warning "This version of Mac OS X is unsupported" +# endif +#elif defined(MSDOS) || defined(_MSDOS) || defined(__MSDOS__) +#define _OS_MSDOS_ +#elif defined(OS2) || defined(_OS2) || defined(__OS2__) +#if defined(__EMX__) +#define _OS_OS2EMX_ +#else +#define _OS_OS2_ +#endif +#elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__) +#define _OS_WIN32_ +#elif defined(__MWERKS__) && defined(__INTEL__) +#define _OS_WIN32_ +#elif defined(sun) || defined(__sun) || defined(__sun__) +#if defined(__SVR4) +#define _OS_SOLARIS_ +#else +#define _OS_SUN_ +#endif +#elif defined(hpux) || defined(__hpux) || defined(__hpux__) +#define _OS_HPUX_ +#elif defined(ultrix) || defined(__ultrix) || defined(__ultrix__) +#define _OS_ULTRIX_ +#elif defined(reliantunix) +#define _OS_RELIANTUNIX_ +#elif defined(linux) || defined(__linux) || defined(__linux__) || defined(__GNU__) || defined(__GLIBC__) +#define _OS_LINUX_ +#elif defined(__FreeBSD__) +#define _OS_FREEBSD_ +#elif defined(__NetBSD__) +#define _OS_NETBSD_ +#elif defined(__OpenBSD__) +#define _OS_OPENBSD_ +#elif defined(sgi) || defined(__sgi) +#define _OS_IRIX_ +#elif defined(__osf__) +#define _OS_OSF_ +#elif defined(bsdi) || defined(__bsdi__) +#define _OS_BSDI_ +#elif defined(_AIX) +#define _OS_AIX_ +#elif defined(__Lynx__) +#define _OS_LYNXOS_ +#elif defined(_UNIXWARE) +#define _OS_UNIXWARE_ +#elif defined(DGUX) +#define _OS_DGUX_ +#elif defined(__QNX__) +#define _OS_QNX_ +#elif defined(_SCO_DS) || defined(M_UNIX) || defined(M_XENIX) +#define _OS_SCO_ +#elif defined(sco) || defined(_UNIXWARE7) +#define _OS_UNIXWARE7_ +#elif !defined(_SCO_DS) && defined(__USLC__) && defined(__SCO_VERSION__) +#define _OS_UNIXWARE7_ +#elif defined(__CYGWIN__) +#define _OS_CYGWIN_ +#elif defined(__BEOS__) +#define _OS_BEOS_ +#elif defined(__MINT__) +#define _OS_MINT_ +#else +#error "Qt has not been ported to this OS - talk to qt-bugs@trolltech.com" +#endif + +#if defined(_OS_MAC_) || defined(_OS_MSDOS_) || defined(_OS_OS2_) || defined(_OS_WIN32_) +#undef _OS_UNIX_ +#elif !defined(_OS_UNIX_) +#define _OS_UNIX_ +// QT_CLEAN_NAMESPACE is not defined by default; it would break too +// much code. +#if !defined(QT_CLEAN_NAMESPACE) && !defined(UNIX) +// ### remove 3.0 +#define UNIX +#endif +#endif + + +// +// The compiler, must be one of: (_CC_x_) +// +// SYM - Symantec C++ for both PC and Macintosh +// MPW - MPW C++ +// MWERKS - Metrowerks CodeWarrior +// MSVC - Microsoft Visual C/C++ +// BOR - Borland/Turbo C++ +// WAT - Watcom C++ +// GNU - GNU C++ +// COMEAU - Comeau C++ +// EDG - Edison Design Group C++ +// OC - CenterLine C++ +// SUN - Sun C++ +// DEC - DEC C++ +// HP - HPUX C++ +// USLC - SCO UnixWare7 C++ +// CDS - Reliant C++ +// KAI - KAI C++ +// + + +// Should be sorted most-authorative to least-authorative + +#if defined(__SC__) +#define _CC_SYM_ +#elif defined( __KCC ) +#define _CC_KAI_ +#define _CC_EDG_ +#define Q_HAS_BOOL_TYPE +#elif defined(applec) +#define _CC_MPW_ +#elif defined(__MWERKS__) +#define _CC_MWERKS_ +#define Q_HAS_BOOL_TYPE +#elif defined(_MSC_VER) +#define _CC_MSVC_ +#elif defined(__BORLANDC__) || defined(__TURBOC__) +#define _CC_BOR_ +#elif defined(__WATCOMC__) +#define _CC_WAT_ +#define Q_HAS_BOOL_TYPE +#elif defined(__GNUC__) +#define _CC_GNU_ +#if __GNUC__ == 2 && __GNUC_MINOR__ <= 7 +#define Q_FULL_TEMPLATE_INSTANTIATION +#define Q_TEMPLATE_NEEDS_CLASS_DECLARATION +#define Q_TEMPLATE_NEEDS_EXPLICIT_CONVERSION +#define Q_SPURIOUS_NON_VOID_WARNING +#endif +#if __GNUC__ == 2 && __GNUC_MINOR__ >= 95 +#define Q_DELETING_VOID_UNDEFINED +#endif +#if (defined(__arm__) || defined(__ARMEL__)) && !defined(QT_MOC_CPP) +#define Q_PACKED __attribute__ ((packed)) +#endif +#elif defined(__xlC__) +#define _CC_XLC_ +#define Q_FULL_TEMPLATE_INSTANTIATION +#if __xlC__ >= 0x400 +#define Q_HAS_BOOL_TYPE +#endif +#if __xlC__ <= 0x0306 +#define Q_TEMPLATE_NEEDS_EXPLICIT_CONVERSION +#endif +#elif defined(como40) +#define _CC_EDG_ +#define _CC_COMEAU_ +#define Q_HAS_BOOL_TYPE +#define Q_C_CALLBACKS +#elif defined(__USLC__) +#define _CC_USLC_ +#ifdef __EDG__ // UnixWare7 +#define Q_HAS_BOOL_TYPE +#endif +#elif defined(__DECCXX) +#define _CC_DEC_ +#if __DECCXX_VER >= 60060005 +#define Q_HAS_BOOL_TYPE +#endif +#elif defined(__EDG) || defined(__EDG__) +// one observed on SGI DCC, the other documented +#define _CC_EDG_ +#elif defined(OBJECTCENTER) || defined(CENTERLINE_CLPP) +#define _CC_OC_ +#if defined(_BOOL) +#define Q_HAS_BOOL_TYPE +#endif +#elif defined(__SUNPRO_CC) +#define _CC_SUN_ +#if __SUNPRO_CC >= 0x500 +#define Q_HAS_BOOL_TYPE +#define Q_C_CALLBACKS +#endif +#elif defined(__CDS__) +#define _CC_CDS_ +#define Q_HAS_BOOL_TYPE +#elif defined(_OS_HPUX_) +// this test is from aCC online help +#if defined(__HP_aCC) || __cplusplus >= 199707L +// this is the aCC +#define _CC_HP_ACC_ +#define Q_HAS_BOOL_TYPE +#else +// this is the CC +#define _CC_HP_ +#define Q_FULL_TEMPLATE_INSTANTIATION +#define Q_TEMPLATE_NEEDS_EXPLICIT_CONVERSION +#endif // __HP_aCC +#else +#error "Qt has not been tested with this compiler - talk to qt-bugs@trolltech.com" +#endif + +// detect Microsoft compiler version +#ifdef _CC_MSVC_ +#if _MSC_VER >= 1400 +#define _CC_V2005 +#elif _MSC_VER >= 1310 +#define _CC_V2003 +#elif _MSC_VER > 1300 +#define _CC_V2002 +#else +#define _CC_V1998 +#endif +#endif + +#ifndef Q_PACKED +#define Q_PACKED +#endif + +// Window system setting + +#if defined(_OS_MAC_) +#define _WS_MAC_ +#elif defined(_OS_MSDOS_) +#define _WS_WIN16_ +#error "Qt requires Win32 and does not work with Windows 3.x" +#elif defined(_WIN32_X11_) +#define _WS_X11_ +#elif defined(_OS_WIN32_) +#define _WS_WIN32_ +#elif defined(_OS_OS2_) +#error "Qt does not work with OS/2 Presentation Manager or Workplace Shell" +#elif defined(_OS_UNIX_) +#ifdef QWS +#define _WS_QWS_ +#else +#define _WS_X11_ +#endif +#endif + +#if defined(_WS_WIN16_) || defined(_WS_WIN32_) +#define _WS_WIN_ +#endif + + +// +// Some classes do not permit copies to be made of an object. +// These classes contains a private copy constructor and operator= +// to disable copying (the compiler gives an error message). +// Undefine Q_DISABLE_COPY to turn off this checking. +// + +#define Q_DISABLE_COPY + + +// +// Useful type definitions for Qt +// + +#if defined(bool) +#define Q_HAS_BOOL_TYPE +#elif __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 6) +#define Q_HAS_BOOL_TYPE +#elif _MSC_VER >= 1100 || __BORLANDC__ >= 0x500 +#define Q_HAS_BOOL_TYPE +#elif defined(sgi) && defined(_BOOL) +#define Q_HAS_BOOL_TYPE +#endif + +#if (QT_VERSION >= 300) +#error "Use an enum for bool" +#endif + +#if !defined(Q_HAS_BOOL_TYPE) +#if defined(_CC_MSVC_) +#define _CC_BOOL_DEF_ +#define bool int +#else +typedef int bool; +#endif +#endif + +typedef unsigned char uchar; +typedef unsigned short ushort; +typedef unsigned uint; +typedef unsigned long ulong; +typedef char *pchar; +typedef uchar *puchar; +typedef const char *pcchar; +#if defined(_OS_WIN32_) && !defined(_CC_GNU_) +typedef __int64 int64; +typedef unsigned __int64 uint64; +#else +typedef long long int64; +typedef unsigned long long uint64; +#endif + + +// +// Constant bool values +// + +#ifndef TRUE +const bool FALSE = 0; +const bool TRUE = !0; +#endif + + +#if defined(_CC_MSVC_) +// Workaround for static const members. +#define QT_STATIC_CONST static +#define QT_STATIC_CONST_IMPL +#else +#define QT_STATIC_CONST static const +#define QT_STATIC_CONST_IMPL const +#endif + + + +// +// Utility macros and inline functions +// + +#define QMAX(a,b) ((a) > (b) ? (a) : (b)) +#define QMIN(a,b) ((a) < (b) ? (a) : (b)) +#define QABS(a) ((a) >= 0 ? (a) : -(a)) + +inline int qRound( double d ) +{ + return d > 0.0 ? int(d+0.5) : int(d-0.5); +} + + +// +// Size-dependent types (architechture-dependent byte order) +// + +// QT_CLEAN_NAMESPACE is not defined by default; it would break too +// much code. +#if !defined(QT_CLEAN_NAMESPACE) +typedef signed char INT8; // 8 bit signed +typedef unsigned char UINT8; // 8 bit unsigned +typedef short INT16; // 16 bit signed +typedef unsigned short UINT16; // 16 bit unsigned +typedef int INT32; // 32 bit signed +typedef unsigned int UINT32; // 32 bit unsigned +#endif + +typedef signed char Q_INT8; // 8 bit signed +typedef unsigned char Q_UINT8; // 8 bit unsigned +typedef short Q_INT16; // 16 bit signed +typedef unsigned short Q_UINT16; // 16 bit unsigned +typedef int Q_INT32; // 32 bit signed +typedef unsigned int Q_UINT32; // 32 bit unsigned +typedef long Q_INT64; // up to 64 bit signed +typedef unsigned long Q_UINT64; // up to 64 bit unsigned + +// +// Data stream functions is provided by many classes (defined in qdatastream.h) +// + +class QDataStream; + + + +#ifdef _WS_WIN_ +extern bool qt_winunicode; +#endif + +#ifndef QT_H +#include <qfeatures.h> +#endif // QT_H + +// +// Create Qt DLL if QT_DLL is defined (Windows only) +// + +#if defined(_OS_WIN32_) +#if defined(QT_NODLL) +#undef QT_MAKEDLL +#undef QT_DLL +#endif +#ifdef QT_DLL +#if defined(QT_MAKEDLL) /* create a Qt DLL library */ +#undef QT_DLL +#define Q_EXPORT __declspec(dllexport) +#define Q_TEMPLATEDLL +#undef Q_DISABLE_COPY /* avoid unresolved externals */ +#endif +#endif +#if defined(QT_DLL) /* use a Qt DLL library */ +#define Q_EXPORT __declspec(dllimport) +#define Q_TEMPLATEDLL +#undef Q_DISABLE_COPY /* avoid unresolved externals */ +#endif +#else // ! _OS_WIN32_ +#undef QT_MAKEDLL /* ignore these for other platforms */ +#undef QT_DLL +#endif + +#ifndef Q_EXPORT +#define Q_EXPORT +#endif + +// +// System information +// + +Q_EXPORT const char *qVersion(); +Q_EXPORT bool qSysInfo( int *wordSize, bool *bigEndian ); + + +// +// Debugging and error handling +// + +#if !defined(NO_CHECK) +#define CHECK_STATE // check state of objects etc. +#define CHECK_RANGE // check range of indexes etc. +#define CHECK_NULL // check null pointers +#define CHECK_MATH // check math functions +#endif + +#if !defined(NO_DEBUG) && !defined(DEBUG) +#define DEBUG // display debug messages +#endif + +// +// Avoid some particularly useless warnings from some stupid compilers. +// To get ALL C++ compiler warnings, define CC_WARNINGS or comment out +// the line "#define Q_NO_WARNINGS" +// + +#if !defined(CC_WARNINGS) +#define Q_NO_WARNINGS +#endif +#if defined(Q_NO_WARNINGS) +#if defined(_CC_MSVC_) +#pragma warning(disable: 4244) +#pragma warning(disable: 4275) +#pragma warning(disable: 4514) +#pragma warning(disable: 4800) +#pragma warning(disable: 4097) +#pragma warning(disable: 4706) +#elif defined(_CC_BOR_) +#pragma option -w-inl +#pragma option -w-aus +#pragma warn -inl +#pragma warn -pia +#pragma warn -ccc +#pragma warn -rch +#pragma warn -sig +#elif defined(_CC_MWERKS_) +#pragma warn_possunwant off +#endif +#endif // Q_NO_WARNINGS + +// +// Avoid dead code +// + +#if defined(_CC_EDG_) || defined(_CC_WAT_) +#define Q_NO_DEAD_CODE +#endif + +// +// Use to avoid "unused parameter" warnings +// + +#define Q_UNUSED(x) x=x; +#define Q_CONST_UNUSED(x) (void)x; + +Q_EXPORT void qDebug( const char *, ... ) // print debug message +#if defined(_CC_GNU_) && !defined(__INSURE__) + __attribute__ ((format (printf, 1, 2))) +#endif +; + +Q_EXPORT void qWarning( const char *, ... ) // print warning message +#if defined(_CC_GNU_) && !defined(__INSURE__) + __attribute__ ((format (printf, 1, 2))) +#endif +; + +Q_EXPORT void qFatal( const char *, ... ) // print fatal message and exit +#if defined(_CC_GNU_) + __attribute__ ((format (printf, 1, 2))) +#endif +; + + +// QT_CLEAN_NAMESPACE is not defined by default; it would break too +// much code. +#if !defined(QT_CLEAN_NAMESPACE) +// in that case, also define the old ones... + +Q_EXPORT void debug( const char *, ... ) // print debug message +#if defined(_CC_GNU_) && !defined(__INSURE__) + __attribute__ ((format (printf, 1, 2))) +#endif +; + +Q_EXPORT void warning( const char *, ... ) // print warning message +#if defined(_CC_GNU_) && !defined(__INSURE__) + __attribute__ ((format (printf, 1, 2))) +#endif +; + +Q_EXPORT void fatal( const char *, ... ) // print fatal message and exit +#if defined(_CC_GNU_) && !defined(__INSURE__) + __attribute__ ((format (printf, 1, 2))) +#endif +; + +// okay, that was debug()/warning()/fatal() +#endif + +#if !defined(ASSERT) +#if defined(CHECK_STATE) +#if defined(QT_FATAL_ASSERT) +#define ASSERT(x) if ( !(x) )\ + qFatal("ASSERT: \"%s\" in %s (%d)",#x,__FILE__,__LINE__) +#else +#define ASSERT(x) if ( !(x) )\ + qWarning("ASSERT: \"%s\" in %s (%d)",#x,__FILE__,__LINE__) +#endif +#else +#define ASSERT(x) +#endif +#endif + +Q_EXPORT bool qt_check_pointer( bool c, const char *, int ); + +#if defined(CHECK_NULL) +#define CHECK_PTR(p) (qt_check_pointer((p)==0,__FILE__,__LINE__)) +#else +#define CHECK_PTR(p) +#endif + +enum QtMsgType { QtDebugMsg, QtWarningMsg, QtFatalMsg }; + +typedef void (*msg_handler)(QtMsgType, const char *); +Q_EXPORT msg_handler qInstallMsgHandler( msg_handler ); + + +Q_EXPORT void qSuppressObsoleteWarnings( bool = TRUE ); + +#if !defined(QT_REJECT_OBSOLETE) +#define QT_OBSOLETE +Q_EXPORT void qObsolete( const char *obj, const char *oldfunc, + const char *newfunc ); +Q_EXPORT void qObsolete( const char *obj, const char *oldfunc ); +Q_EXPORT void qObsolete( const char *message ); +#endif + +// DvH: added to avoid warnings on recent gcc versions +#define Q_DELETING_VOID_UNDEFINED + +#endif // QGLOBAL_H diff --git a/trunk/qtools/qgstring.cpp b/trunk/qtools/qgstring.cpp new file mode 100644 index 0000000..85dd879 --- /dev/null +++ b/trunk/qtools/qgstring.cpp @@ -0,0 +1,258 @@ +/****************************************************************************** + * + * Copyright (C) 1997-2004 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. + * + */ + +#include <stdio.h> +#include "qgstring.h" + +#include <assert.h> + +#define BLOCK_SIZE 64 +#define ROUND_SIZE(x) ((x)+BLOCK_SIZE-1)&~(BLOCK_SIZE-1) + +#define DBG_STR(x) do { } while(0) +//#define DBG_STR(x) printf x + +QGString::QGString() // make null string + : m_data(0), m_len(0), m_memSize(0) +{ + DBG_STR(("%p: QGString::QGString() %d:%s\n",this,m_len,m_data?m_data:"<none>")); +} + +QGString::QGString(uint size) +{ + if (size==0) + { + m_data=0; + m_len=0; + } + else + { + m_memSize = ROUND_SIZE(size+1); + m_data = (char*)malloc(m_memSize); + memset(m_data,' ',size); + m_data[size]='\0'; + m_len=size; + } + DBG_STR(("%p: QGString::QGString(uint size=%d) %d:%s\n", + this,size,m_len,m_data?m_data:"<none>")); +} + +QGString::QGString( const QGString &s ) +{ + if (s.m_memSize==0) + { + m_data = 0; + m_len = 0; + m_memSize = 0; + } + else + { + m_data = (char *)malloc(s.m_memSize); + m_len = s.m_len; + m_memSize = s.m_memSize; + qstrcpy(m_data,s.m_data); + } + DBG_STR(("%p: QGString::QGString(const QGString &) %d:%s\n",this,m_len,m_data?m_data:"<none>")); +} + +QGString::QGString( const char *str ) +{ + if (str==0) + { + m_data=0; + m_len=0; + m_memSize=0; + } + else + { + m_len = qstrlen(str); + m_memSize = ROUND_SIZE(m_len+1); + assert(m_memSize>=m_len+1); + m_data = (char *)malloc(m_memSize); + qstrcpy(m_data,str); + } + DBG_STR(("%p: QGString::QGString(const char *) %d:%s\n",this,m_len,m_data?m_data:"<none>")); +} + +QGString::~QGString() +{ + free(m_data); + m_data=0; + DBG_STR(("%p: QGString::~QGString() %d:%s\n",this,m_len,m_data?m_data:"<none>")); +} + +bool QGString::resize( uint newlen ) +{ + m_len = 0; + if (newlen==0) + { + if (m_data) { free(m_data); m_data=0; } + m_memSize=0; + DBG_STR(("%p: 1.QGString::resize() %d:%s\n",this,m_len,m_data?m_data:"<none>")); + return TRUE; + } + m_memSize = ROUND_SIZE(newlen+1); + assert(m_memSize>=newlen+1); + if (m_data==0) + { + m_data = (char *)malloc(m_memSize); + } + else + { + m_data = (char *)realloc(m_data,m_memSize); + } + if (m_data==0) + { + DBG_STR(("%p: 2.QGString::resize() %d:%s\n",this,m_len,m_data?m_data:"<none>")); + return FALSE; + } + m_data[newlen]='\0'; + m_len = qstrlen(m_data); + DBG_STR(("%p: 3.QGString::resize() %d:%s\n",this,m_len,m_data?m_data:"<none>")); + return TRUE; +} + +bool QGString::enlarge( uint newlen ) +{ + if (newlen==0) + { + if (m_data) { free(m_data); m_data=0; } + m_memSize=0; + m_len=0; + return TRUE; + } + uint newMemSize = ROUND_SIZE(newlen+1); + if (newMemSize==m_memSize) return TRUE; + m_memSize = newMemSize; + if (m_data==0) + { + m_data = (char *)malloc(m_memSize); + } + else + { + m_data = (char *)realloc(m_data,m_memSize); + } + if (m_data==0) + { + return FALSE; + } + m_data[newlen-1]='\0'; + if (m_len>newlen) m_len=newlen; + return TRUE; +} + +void QGString::setLen( uint newlen ) +{ + m_len = newlen<=m_memSize ? newlen : m_memSize; +} + +QGString &QGString::operator=( const QGString &s ) +{ + if (m_data) free(m_data); + if (s.m_memSize==0) // null string + { + m_data = 0; + m_len = 0; + m_memSize = 0; + } + else + { + m_len = s.m_len; + m_memSize = s.m_memSize; + m_data = (char*)malloc(m_memSize); + qstrcpy(m_data,s.m_data); + } + DBG_STR(("%p: QGString::operator=(const QGString &%p) %d:%s\n", + this,&s,m_len,m_data?m_data:"<none>")); + return *this; +} + +QGString &QGString::operator=( const char *str ) +{ + if (m_data) free(m_data); + if (str==0) // null string + { + m_data = 0; + m_len = 0; + m_memSize = 0; + } + else + { + m_len = qstrlen(str); + m_memSize = ROUND_SIZE(m_len+1); + assert(m_memSize>=m_len+1); + m_data = (char*)malloc(m_memSize); + qstrcpy(m_data,str); + } + DBG_STR(("%p: QGString::operator=(const char *) %d:%s\n",this,m_len,m_data?m_data:"<none>")); + return *this; +} + +QGString &QGString::operator+=( const QGString &s ) +{ + if (s.m_memSize==0) return *this; + uint len1 = length(); + uint len2 = s.length(); + uint memSize = ROUND_SIZE(len1 + len2 + 1); + assert(memSize>=len1+len2+1); + char *newData = memSize!=m_memSize ? (char*)realloc( m_data, memSize ) : m_data; + m_memSize = memSize; + if (m_data) + { + m_data = newData; + memcpy( m_data + len1, s, len2 + 1 ); + } + m_len = len1+len2; + DBG_STR(("%p: QGString::operator+=(const QGString &) %d:%s\n",this,m_len,m_data?m_data:"<none>")); + return *this; +} + +QGString &QGString::operator+=( const char *str ) +{ + if (!str) return *this; + uint len1 = length(); + uint len2 = qstrlen(str); + uint memSize = ROUND_SIZE(len1 + len2 + 1); + assert(memSize>=len1+len2+1); + char *newData = memSize!=m_memSize ? (char *)realloc( m_data, memSize ) : m_data; + m_memSize = memSize; + if (newData) + { + m_data = newData; + memcpy( m_data + len1, str, len2 + 1 ); + } + m_len+=len2; + DBG_STR(("%p: QGString::operator+=(const char *) %d:%s\n",this,m_len,m_data?m_data:"<none>")); + return *this; +} + +QGString &QGString::operator+=( char c ) +{ + uint len = m_len; + uint memSize = ROUND_SIZE(len+2); + assert(memSize>=len+2); + char *newData = memSize!=m_memSize ? (char *)realloc( m_data, memSize ) : m_data; + m_memSize = memSize; + if (newData) + { + m_data = newData; + m_data[len] = c; + m_data[len+1] = '\0'; + } + m_len++; + DBG_STR(("%p: QGString::operator+=(char s) %d:%s\n",this,m_len,m_data?m_data:"<none>")); + return *this; +} + diff --git a/trunk/qtools/qgstring.h b/trunk/qtools/qgstring.h new file mode 100644 index 0000000..6934c93 --- /dev/null +++ b/trunk/qtools/qgstring.h @@ -0,0 +1,139 @@ +#ifndef QGSTRING_H +#define QGSTRING_H + +#include <stdlib.h> +#include <string.h> + +#if defined(_OS_SUN_) && defined(_CC_GNU_) +#include <strings.h> +#endif + +#include "qcstring.h" + +/***************************************************************************** + Fixes and workarounds for some platforms + *****************************************************************************/ + +/** This is an alternative implementation of QCString. + */ +class QGString +{ + public: + QGString(); // make null string + QGString(uint size); + QGString( const QGString &s ); + QGString( const char *str ); + ~QGString() ; + + bool resize( uint newlen ); + bool enlarge( uint newlen ); + void setLen( uint newlen ); + + QGString &operator=( const QGString &s ); + QGString &operator=( const char *str ); + QGString &operator+=( const QGString &s ); + QGString &operator+=( const char *str ); + QGString &operator+=( char c ); + + bool isNull() const { return m_data==0; } + bool isEmpty() const { return m_len==0; } + uint length() const { return m_len; } + uint size() const { return m_memSize; } + char * data() const { return m_data; } + bool truncate( uint pos ) { return resize(pos+1); } + operator const char *() const { return (const char *)data(); } + char &at( uint index ) const { return m_data[index]; } + char &operator[]( int i ) const { return at(i); } + + private: + char * m_data; + uint m_len; + uint m_memSize; +}; + +/***************************************************************************** + QGString non-member operators + *****************************************************************************/ + +Q_EXPORT inline bool operator==( const QGString &s1, const QGString &s2 ) +{ return qstrcmp(s1.data(),s2.data()) == 0; } + +Q_EXPORT inline bool operator==( const QGString &s1, const char *s2 ) +{ return qstrcmp(s1.data(),s2) == 0; } + +Q_EXPORT inline bool operator==( const char *s1, const QGString &s2 ) +{ return qstrcmp(s1,s2.data()) == 0; } + +Q_EXPORT inline bool operator!=( const QGString &s1, const QGString &s2 ) +{ return qstrcmp(s1.data(),s2.data()) != 0; } + +Q_EXPORT inline bool operator!=( const QGString &s1, const char *s2 ) +{ return qstrcmp(s1.data(),s2) != 0; } + +Q_EXPORT inline bool operator!=( const char *s1, const QGString &s2 ) +{ return qstrcmp(s1,s2.data()) != 0; } + +Q_EXPORT inline bool operator<( const QGString &s1, const QGString& s2 ) +{ return qstrcmp(s1.data(),s2.data()) < 0; } + +Q_EXPORT inline bool operator<( const QGString &s1, const char *s2 ) +{ return qstrcmp(s1.data(),s2) < 0; } + +Q_EXPORT inline bool operator<( const char *s1, const QGString &s2 ) +{ return qstrcmp(s1,s2.data()) < 0; } + +Q_EXPORT inline bool operator<=( const QGString &s1, const char *s2 ) +{ return qstrcmp(s1.data(),s2) <= 0; } + +Q_EXPORT inline bool operator<=( const char *s1, const QGString &s2 ) +{ return qstrcmp(s1,s2.data()) <= 0; } + +Q_EXPORT inline bool operator>( const QGString &s1, const char *s2 ) +{ return qstrcmp(s1.data(),s2) > 0; } + +Q_EXPORT inline bool operator>( const char *s1, const QGString &s2 ) +{ return qstrcmp(s1,s2.data()) > 0; } + +Q_EXPORT inline bool operator>=( const QGString &s1, const char *s2 ) +{ return qstrcmp(s1.data(),s2) >= 0; } + +Q_EXPORT inline bool operator>=( const char *s1, const QGString &s2 ) +{ return qstrcmp(s1,s2.data()) >= 0; } + +Q_EXPORT inline QGString operator+( const QGString &s1, const QGString &s2 ) +{ + QGString tmp( s1.data() ); + tmp += s2; + return tmp; +} + +Q_EXPORT inline QGString operator+( const QGString &s1, const char *s2 ) +{ + QGString tmp( s1.data() ); + tmp += s2; + return tmp; +} + +Q_EXPORT inline QGString operator+( const char *s1, const QGString &s2 ) +{ + QGString tmp( s1 ); + tmp += s2; + return tmp; +} + +Q_EXPORT inline QGString operator+( const QGString &s1, char c2 ) +{ + QGString tmp( s1.data() ); + tmp += c2; + return tmp; +} + +Q_EXPORT inline QGString operator+( char c1, const QGString &s2 ) +{ + QGString tmp; + tmp += c1; + tmp += s2; + return tmp; +} + +#endif // QGSTRING_H diff --git a/trunk/qtools/qgvector.cpp b/trunk/qtools/qgvector.cpp new file mode 100644 index 0000000..88409ce --- /dev/null +++ b/trunk/qtools/qgvector.cpp @@ -0,0 +1,638 @@ +/**************************************************************************** +** +** +** Implementation of QGVector class +** +** Created : 930907 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#define QGVECTOR_CPP +#include "qgvector.h" +#include "qglist.h" +#include "qstring.h" +#include "qdatastream.h" +#include <stdlib.h> + +#define USE_MALLOC // comment to use new/delete + +#undef NEW +#undef DELETE + +#if defined(USE_MALLOC) +#define NEW(type,size) ((type*)malloc(size*sizeof(type))) +#define DELETE(array) (free((char*)array)) +#else +#define NEW(type,size) (new type[size]) +#define DELETE(array) (delete[] array) +#define DONT_USE_REALLOC // comment to use realloc() +#endif + +// NOT REVISED + +/*! + \class QGVector qgvector.h + + \brief The QGVector class is an internal class for implementing Qt + collection classes. + + QGVector is a strictly internal class that acts as a base class for + the QVector collection class. + + QGVector has some virtual functions that may be reimplemented in + subclasses to to customize behavior. + + <ul> + <li> compareItems() compares two collection/vector items. + <li> read() reads a collection/vector item from a QDataStream. + <li> write() writes a collection/vector item to a QDataStream. + </ul> +*/ + +/***************************************************************************** + Default implementation of virtual functions + *****************************************************************************/ + +/*! + This virtual function compares two list items. + + Returns: + <ul> + <li> 0 if \a item1 == \a item2 + <li> non-zero if \a item1 != \a item2 + </ul> + + This function returns \e int rather than \e bool so that + reimplementations can return one of three values and use it to sort + by: + + <ul> + <li> 0 if \e item1 == \e item2 + <li> \> 0 (positive integer) if \a item1 \> \a item2 + <li> \< 0 (negative integer) if \a item1 \< \a item2 + </ul> + + The QVector::sort() and QVector::bsearch() functions require that + compareItems() is implemented as described here. + + This function should not modify the vector because some const + functions call compareItems(). +*/ + +int QGVector::compareItems( Item d1, Item d2 ) +{ + return d1 != d2; // compare pointers +} + +#ifndef QT_NO_DATASTREAM +/*! + Reads a collection/vector item from the stream \a s and returns a reference + to the stream. + + The default implementation sets \e item to 0. + + \sa write() +*/ + +QDataStream &QGVector::read( QDataStream &s, Item &d ) +{ // read item from stream + d = 0; + return s; +} + +/*! + Writes a collection/vector item to the stream \a s and returns a reference + to the stream. + + The default implementation does nothing. + + \sa read() +*/ + +QDataStream &QGVector::write( QDataStream &s, Item ) const +{ // write item to stream + return s; +} +#endif // QT_NO_DATASTREAM + +/***************************************************************************** + QGVector member functions + *****************************************************************************/ + +/*! + \internal +*/ + +QGVector::QGVector() // create empty vector +{ + vec = 0; + len = numItems = 0; +} + +/*! + \internal +*/ +QGVector::QGVector( uint size ) // create vectors with nullptrs +{ + len = size; + numItems = 0; + if ( len == 0 ) { // zero length + vec = 0; + return; + } + vec = NEW(Item,len); + CHECK_PTR( vec ); + memset( (void*)vec, 0, len*sizeof(Item) ); // fill with nulls +} + +/*! + \internal +*/ + +QGVector::QGVector( const QGVector &a ) // make copy of other vector + : QCollection( a ) +{ + len = a.len; + numItems = a.numItems; + vec = NEW(Item,len); + CHECK_PTR( vec ); + for ( uint i=0; i<len; i++ ) { + vec[i] = a.vec[i] ? newItem( a.vec[i] ) : 0; + CHECK_PTR( vec[i] ); + } +} + +/*! + \internal +*/ + +QGVector::~QGVector() +{ + clear(); +} + + +/*! + \internal +*/ + +QGVector& QGVector::operator=( const QGVector &v ) +{ // assign from other vector + clear(); // first delete old vector + len = v.len; + numItems = v.numItems; + vec = NEW(Item,len); // create new vector + CHECK_PTR( vec ); + for ( uint i=0; i<len; i++ ) { // copy elements + vec[i] = v.vec[i] ? newItem( v.vec[i] ) : 0; + CHECK_PTR( vec[i] ); + } + return *this; +} + + +/*! + \fn Item *QGVector::data() const + \internal +*/ + +/*! + \fn uint QGVector::size() const + \internal +*/ + +/*! + \fn uint QGVector::count() const + \internal +*/ + +/*! + \fn Item QGVector::at( uint index ) const + \internal +*/ + +/*! + \internal +*/ + +bool QGVector::insert( uint index, Item d ) // insert item at index +{ +#if defined(CHECK_RANGE) + if ( index >= len ) { // range error + qWarning( "QGVector::insert: Index %d out of range", index ); + return FALSE; + } +#endif + if ( vec[index] ) { // remove old item + deleteItem( vec[index] ); + numItems--; + } + if ( d ) { + vec[index] = newItem( d ); + CHECK_PTR( vec[index] ); + numItems++; + return vec[index] != 0; + } else { + vec[index] = 0; // reset item + } + return TRUE; +} + +/*! + \internal +*/ + +bool QGVector::remove( uint index ) // remove item at index +{ +#if defined(CHECK_RANGE) + if ( index >= len ) { // range error + qWarning( "QGVector::remove: Index %d out of range", index ); + return FALSE; + } +#endif + if ( vec[index] ) { // valid item + deleteItem( vec[index] ); // delete it + vec[index] = 0; // reset pointer + numItems--; + } + return TRUE; +} + +/*! + \internal +*/ + +QCollection::Item QGVector::take( uint index ) // take out item +{ +#if defined(CHECK_RANGE) + if ( index >= len ) { // range error + qWarning( "QGVector::take: Index %d out of range", index ); + return 0; + } +#endif + Item d = vec[index]; // don't delete item + if ( d ) + numItems--; + vec[index] = 0; + return d; +} + + +/*! + \internal +*/ + +void QGVector::clear() // clear vector +{ + if ( vec ) { + for ( uint i=0; i<len; i++ ) { // delete each item + if ( vec[i] ) + deleteItem( vec[i] ); + } + DELETE(vec); + vec = 0; + len = numItems = 0; + } +} + +/*! + \internal +*/ + +bool QGVector::resize( uint newsize ) // resize array +{ + if ( newsize == len ) // nothing to do + return TRUE; + if ( vec ) { // existing data + if ( newsize < len ) { // shrink vector + uint i = newsize; + while ( i < len ) { // delete lost items + if ( vec[i] ) { + deleteItem( vec[i] ); + numItems--; + } + i++; + } + } + if ( newsize == 0 ) { // vector becomes empty + DELETE(vec); + vec = 0; + len = numItems = 0; + return TRUE; + } +#if defined(DONT_USE_REALLOC) + Item *newvec = NEW(Item,newsize); // manual realloc + memcpy( newvec, vec, (len < newsize ? len : newsize)*sizeof(Item) ); + DELETE(vec); + vec = newvec; +#else + vec = (Item*)realloc( (char *)vec, newsize*sizeof(Item) ); +#endif + } else { // create new vector + vec = NEW(Item,newsize); + len = numItems = 0; + } + CHECK_PTR( vec ); + if ( !vec ) // no memory + return FALSE; + if ( newsize > len ) // init extra space added + memset( (void*)&vec[len], 0, (newsize-len)*sizeof(Item) ); + len = newsize; + return TRUE; +} + + +/*! + \internal +*/ + +bool QGVector::fill( Item d, int flen ) // resize and fill vector +{ + if ( flen < 0 ) + flen = len; // default: use vector length + else if ( !resize( flen ) ) + return FALSE; + for ( uint i=0; i<(uint)flen; i++ ) // insert d at every index + insert( i, d ); + return TRUE; +} + + +static QGVector *sort_vec=0; // current sort vector + + +#if defined(Q_C_CALLBACKS) +extern "C" { +#endif + +static int cmp_vec( const void *n1, const void *n2 ) +{ + return sort_vec->compareItems( *((QCollection::Item*)n1), *((QCollection::Item*)n2) ); +} + +#if defined(Q_C_CALLBACKS) +} +#endif + + +/*! + \internal +*/ + +void QGVector::sort() // sort vector +{ + if ( count() == 0 ) // no elements + return; + register Item *start = &vec[0]; + register Item *end = &vec[len-1]; + Item tmp; + while ( TRUE ) { // put all zero elements behind + while ( start < end && *start != 0 ) + start++; + while ( end > start && *end == 0 ) + end--; + if ( start < end ) { + tmp = *start; + *start = *end; + *end = tmp; + } else { + break; + } + } + sort_vec = (QGVector*)this; + qsort( vec, count(), sizeof(Item), cmp_vec ); + sort_vec = 0; +} + +/*! + \internal +*/ + +int QGVector::bsearch( Item d ) const // binary search; when sorted +{ + if ( !len ) + return -1; + if ( !d ) { +#if defined(CHECK_NULL) + qWarning( "QGVector::bsearch: Cannot search for null object" ); +#endif + return -1; + } + int n1 = 0; + int n2 = len - 1; + int mid = 0; + bool found = FALSE; + while ( n1 <= n2 ) { + int res; + mid = (n1 + n2)/2; + if ( vec[mid] == 0 ) // null item greater + res = -1; + else + res = ((QGVector*)this)->compareItems( d, vec[mid] ); + if ( res < 0 ) + n2 = mid - 1; + else if ( res > 0 ) + n1 = mid + 1; + else { // found it + found = TRUE; + break; + } + } + if ( !found ) + return -1; + // search to first of equal items + while ( (mid - 1 >= 0) && !((QGVector*)this)->compareItems(d, vec[mid-1]) ) + mid--; + return mid; +} + + +/*! + \internal +*/ + +int QGVector::findRef( Item d, uint index) const // find exact item in vector +{ +#if defined(CHECK_RANGE) + if ( index >= len ) { // range error + qWarning( "QGVector::findRef: Index %d out of range", index ); + return -1; + } +#endif + for ( uint i=index; i<len; i++ ) { + if ( vec[i] == d ) + return i; + } + return -1; +} + +/*! + \internal +*/ + +int QGVector::find( Item d, uint index ) const // find equal item in vector +{ +#if defined(CHECK_RANGE) + if ( index >= len ) { // range error + qWarning( "QGVector::find: Index %d out of range", index ); + return -1; + } +#endif + for ( uint i=index; i<len; i++ ) { + if ( vec[i] == 0 && d == 0 ) // found null item + return i; + if ( vec[i] && ((QGVector*)this)->compareItems( vec[i], d ) == 0 ) + return i; + } + return -1; +} + +/*! + \internal +*/ + +uint QGVector::containsRef( Item d ) const // get number of exact matches +{ + uint count = 0; + for ( uint i=0; i<len; i++ ) { + if ( vec[i] == d ) + count++; + } + return count; +} + +/*! + \internal +*/ + +uint QGVector::contains( Item d ) const // get number of equal matches +{ + uint count = 0; + for ( uint i=0; i<len; i++ ) { + if ( vec[i] == 0 && d == 0 ) // count null items + count++; + if ( vec[i] && ((QGVector*)this)->compareItems( vec[i], d ) == 0 ) + count++; + } + return count; +} + + +/*! + \internal +*/ + +bool QGVector::insertExpand( uint index, Item d )// insert and grow if necessary +{ + if ( index >= len ) { + if ( !resize( index+1 ) ) // no memory + return FALSE; + } + insert( index, d ); + return TRUE; +} + + +/*! + \internal +*/ + +void QGVector::toList( QGList *list ) const // store items in list +{ + list->clear(); + for ( uint i=0; i<len; i++ ) { + if ( vec[i] ) + list->append( vec[i] ); + } +} + + +void QGVector::warningIndexRange( uint i ) +{ +#if defined(CHECK_RANGE) + qWarning( "QGVector::operator[]: Index %d out of range", i ); +#else + Q_UNUSED( i ) +#endif +} + + +/***************************************************************************** + QGVector stream functions + *****************************************************************************/ +#ifndef QT_NO_DATASTREAM +QDataStream &operator>>( QDataStream &s, QGVector &vec ) +{ // read vector + return vec.read( s ); +} + +QDataStream &operator<<( QDataStream &s, const QGVector &vec ) +{ // write vector + return vec.write( s ); +} + +/*! + \internal +*/ + +QDataStream &QGVector::read( QDataStream &s ) // read vector from stream +{ + uint num; + s >> num; // read number of items + clear(); // clear vector + resize( num ); + for (uint i=0; i<num; i++) { // read all items + Item d; + read( s, d ); + CHECK_PTR( d ); + if ( !d ) // no memory + break; + vec[i] = d; + } + return s; +} + +/*! + \internal +*/ + +QDataStream &QGVector::write( QDataStream &s ) const +{ // write vector to stream + uint num = count(); + s << num; // number of items to write + num = size(); + for (uint i=0; i<num; i++) { // write non-null items + if ( vec[i] ) + write( s, vec[i] ); + } + return s; +} +#endif // QT_NO_DATASTREAM diff --git a/trunk/qtools/qgvector.h b/trunk/qtools/qgvector.h new file mode 100644 index 0000000..6a7999d --- /dev/null +++ b/trunk/qtools/qgvector.h @@ -0,0 +1,120 @@ +/**************************************************************************** +** +** +** Definition of QGVector class +** +** Created : 930907 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QGVECTOR_H +#define QGVECTOR_H + +#ifndef QT_H +#include "qcollection.h" +#endif // QT_H + + +class Q_EXPORT QGVector : public QCollection // generic vector +{ +friend class QGList; // needed by QGList::toVector +public: +#ifndef QT_NO_DATASTREAM + QDataStream &read( QDataStream & ); // read vector from stream + QDataStream &write( QDataStream & ) const; // write vector to stream +#endif + virtual int compareItems( Item, Item ); + +protected: + QGVector(); // create empty vector + QGVector( uint size ); // create vector with nullptrs + QGVector( const QGVector &v ); // make copy of other vector + ~QGVector(); + + QGVector &operator=( const QGVector &v ); // assign from other vector + + Item *data() const { return vec; } + uint size() const { return len; } + uint count() const { return numItems; } + + bool insert( uint index, Item ); // insert item at index + bool remove( uint index ); // remove item + Item take( uint index ); // take out item + + void clear(); // clear vector + bool resize( uint newsize ); // resize vector + + bool fill( Item, int flen ); // resize and fill vector + + void sort(); // sort vector + int bsearch( Item ) const; // binary search (when sorted) + + int findRef( Item, uint index ) const; // find exact item in vector + int find( Item, uint index ) const; // find equal item in vector + uint containsRef( Item ) const; // get number of exact matches + uint contains( Item ) const; // get number of equal matches + + Item at( uint index ) const // return indexed item + { +#if defined(CHECK_RANGE) + if ( index >= len ) + warningIndexRange( index ); +#endif + return vec[index]; + } + + bool insertExpand( uint index, Item ); // insert, expand if necessary + + void toList( QGList * ) const; // put items in list + +#ifndef QT_NO_DATASTREAM + virtual QDataStream &read( QDataStream &, Item & ); + virtual QDataStream &write( QDataStream &, Item ) const; +#endif +private: + Item *vec; + uint len; + uint numItems; + + static void warningIndexRange( uint ); +}; + + +/***************************************************************************** + QGVector stream functions + *****************************************************************************/ + +#ifndef QT_NO_DATASTREAM +Q_EXPORT QDataStream &operator>>( QDataStream &, QGVector & ); +Q_EXPORT QDataStream &operator<<( QDataStream &, const QGVector & ); +#endif + +#endif // QGVECTOR_H diff --git a/trunk/qtools/qintdict.doc b/trunk/qtools/qintdict.doc new file mode 100644 index 0000000..e027fb2 --- /dev/null +++ b/trunk/qtools/qintdict.doc @@ -0,0 +1,475 @@ +/**************************************************************************** +** +** +** QIntDict and QIntDictIterator class documentation +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + + +/***************************************************************************** + QIntDict documentation + *****************************************************************************/ + +/*! + \class QIntDict qintdict.h + \brief The QIntDict class is a template class that provides a dictionary based on \c long keys. + + \ingroup collection + \ingroup tools + + QIntDict is implemented as a template class. Define a + template instance QIntDict\<X\> to create a dictionary that operates on + pointers to X, or X*. + + A dictionary is a collection that associates an item with a key. + The key is used for inserting and looking up an item. QIntDict has + \c long keys. + + The dictionary has very fast insertion and lookup. + + Example: + \code + #include <qintdict.h> + #include <stdio.h> + + void main() + { + QIntDict<char> dict; // maps long ==> char* + + dict.insert( 33, "France" ); + dict.insert( 7, "Russia" ); + dict.insert( 49, "Norway" ); + + printf( "%s\n", dict[49] ); + printf( "%s\n", dict[33] ); + printf( "%s\n", dict[7] ); + + if ( !dict[39] ) + printf( "39 not defined\n" ); + } + \endcode + + Program output: + \code + Norway + France + Russia + 39 not defined + \endcode + + The dictionary in our example maps \c long keys to \c char* items. + QIntDict implements the \link operator[] [] operator\endlink to lookup + an item. + + QIntDict is implemented by QGDict as a hash array with a fixed number of + entries. Each array entry points to a singly linked list of buckets, in + which the dictionary items are stored. + + When an item is inserted with a key, the key is converted (hashed) to + an integer index into the hash array using the \c mod operation. The + item is inserted before the first bucket in the list of buckets. + + Looking up an item is normally very fast. The key is again hashed to an + array index. Then QIntDict scans the list of buckets and returns the item + found or null if the item was not found. You cannot insert null pointers + into a dictionary. + + The size of the hash array is very important. In order to get good + performance, you should use a suitably large \link primes.html prime + number\endlink. Suitable means equal to or larger than the maximum + expected number of dictionary items. + + Items with equal keys are allowed. When inserting two items with the + same key, only the last inserted item will be visible (last in, first out) + until it is removed. + + Example: + \code + #include <qintdict.h> + #include <stdio.h> + + void main() + { + QIntDict<char> dict; // maps long ==> char* + + dict.insert( 7, "Russia" ); + dict.insert( 7, "USSR" ); + + printf( "%s\n", dict[7] ); + dict.remove( 7 ); // Gorbie was here + printf( "%s\n", dict[7] ); + } + \endcode + + Program output: + \code + USSR + Russia + \endcode + + The QIntDictIterator class can traverse the dictionary contents, but only + in an arbitrary order. Multiple iterators may independently traverse the + same dictionary. + + Calling setAutoDelete(TRUE) for a dictionary tells it to delete items + that are removed . The default is to not delete items when they are + removed. + + When inserting an item into a dictionary, only the pointer is copied, not + the item itself. This is called a shallow copy. It is possible to make the + dictionary copy all of the item's data (known as a deep copy) when an + item is inserted. insert() calls the virtual function + QCollection::newItem() for the item to be inserted. + Inherit a dictionary and reimplement it if you want deep copies. + + When removing a dictionary item, the virtual function + QCollection::deleteItem() is called. QIntDict's default implementation + is to delete the item if auto-deletion is enabled. + + \sa QIntDictIterator, QDict, QAsciiDict, QPtrDict, + \link collection.html Collection Classes\endlink +*/ + + +/*! + \fn QIntDict::QIntDict( int size ) + Constructs a dictionary using an internal hash array with the size + \e size. + + Setting \e size to a suitably large \link primes.html prime number\endlink + (equal to or greater than the expected number of entries) makes the hash + distribution better and hence the loopup faster. +*/ + +/*! + \fn QIntDict::QIntDict( const QIntDict<type> &dict ) + Constructs a copy of \e dict. + + Each item in \e dict are inserted into this dictionary. + Only the pointers are copied (shallow copy). +*/ + +/*! + \fn QIntDict::~QIntDict() + Removes all items from the dictionary and destroys it. + + All iterators that access this dictionary will be reset. + + \sa setAutoDelete() +*/ + +/*! + \fn QIntDict<type> &QIntDict::operator=(const QIntDict<type> &dict) + Assigns \e dict to this dictionary and returns a reference to this + dictionary. + + This dictionary is first cleared, then each item in \e dict is inserted + into this dictionary. + Only the pointers are copied (shallow copy), unless newItem() has been + reimplemented. +*/ + +/*! + \fn uint QIntDict::count() const + Returns the number of items in the dictionary. + \sa isEmpty() +*/ + +/*! + \fn uint QIntDict::size() const + Returns the size of the internal hash array (as specified in the + constructor). + \sa count() +*/ + +/*! + \fn void QIntDict::resize( uint newsize ) + Changes the size of the hashtable the \a newsize. + The contents of the dictionary are preserved, + but all iterators on the dictionary become invalid. +*/ + +/*! + \fn bool QIntDict::isEmpty() const + Returns TRUE if the dictionary is empty, i.e. count() == 0. Returns FALSE + otherwise. + \sa count() +*/ + +/*! + \fn void QIntDict::insert( long key, const type *item ) + Inserts the \e key with the \e item into the dictionary. + + The key does not have to be a unique dictionary key. If multiple items + are inserted with the same key, only the last item will be visible. + + Null items are not allowed. + + \sa replace() +*/ + +/*! + \fn void QIntDict::replace( long key, const type *item ) + Replaces an item which has a key equal to \e key with \e item. + + If the item does not already exist, it will be inserted. + + Null items are not allowed. + + Equivalent to: + \code + QIntDict<char> dict; + ... + if ( dict.find(key) ) + dict.remove( key ); + dict.insert( key, item ); + \endcode + + If there are two or more items with equal keys, then the last inserted + of these will be replaced. + + \sa insert() +*/ + +/*! + \fn bool QIntDict::remove( long key ) + Removes the item associated with \e key from the dictionary. + Returns TRUE if successful, or FALSE if the key does not exist in the + dictionary. + + If there are two or more items with equal keys, then the last inserted + of these will be removed. + + The removed item is deleted if \link QCollection::setAutoDelete() + auto-deletion\endlink is enabled. + + All dictionary iterators that refer to the removed item will be set to + point to the next item in the dictionary traversing order. + + \sa take(), clear(), setAutoDelete() +*/ + +/*! + \fn type *QIntDict::take( long key ) + Takes the item associated with \e key out of the dictionary without + deleting it (even if \link QCollection::setAutoDelete() + auto-deletion\endlink is enabled). + + If there are two or more items with equal keys, then the last inserted + of these will be taken. + + Returns a pointer to the item taken out, or null if the key does not + exist in the dictionary. + + All dictionary iterators that refer to the taken item will be set to + point to the next item in the dictionary traversing order. + + \sa remove(), clear(), setAutoDelete() +*/ + +/*! + \fn void QIntDict::clear() + Removes all items from the dictionary. + + The removed items are deleted if \link QCollection::setAutoDelete() + auto-deletion\endlink is enabled. + + All dictionary iterators that access this dictionary will be reset. + + \sa remove(), take(), setAutoDelete() +*/ + +/*! + \fn type *QIntDict::find( long key ) const + Returns the item associated with \e key, or null if the key does not + exist in the dictionary. + + This function uses an internal hashing algorithm to optimize lookup. + + If there are two or more items with equal keys, then the last inserted + of these will be found. + + Equivalent to the [] operator. + + \sa operator[]() +*/ + +/*! + \fn type *QIntDict::operator[]( long key ) const + Returns the item associated with \e key, or null if the key does not + exist in the dictionary. + + This function uses an internal hashing algorithm to optimize lookup. + + If there are two or more items with equal keys, then the last inserted + of these will be found. + + Equivalent to the find() function. + + \sa find() +*/ + +/*! + \fn void QIntDict::statistics() const + Debugging-only function that prints out the dictionary distribution + using qDebug(). +*/ + + +/***************************************************************************** + QIntDictIterator documentation + *****************************************************************************/ + +/*! + \class QIntDictIterator qintdict.h + \brief The QIntDictIterator class provides an iterator for QIntDict collections. + + \ingroup collection + \ingroup tools + + QIntDictIterator is implemented as a template class. + Define a template instance QIntDictIterator\<X\> to create a + dictionary iterator that operates on QIntDict\<X\> (dictionary of X*). + + Example: + \code + #include <qintdict.h> + #include <stdio.h> + + void main() + { + QIntDict<char> dict; // maps long ==> char* + + dict.insert( 33, "France" ); + dict.insert( 7, "Russia" ); + dict.insert( 49, "Norway" ); + + QIntDictIterator<char> it( dict ); // iterator for dict + + while ( it.current() ) { + printf( "%d -> %s\n", it.currentKey(), it.current() ); + ++it; + } + } + \endcode + + Program output: + \code + 7 -> Russia + 49 -> Norway + 33 -> France + \endcode + + Note that the traversal order is arbitrary, you are not guaranteed the + order above. + + Multiple iterators may independently traverse the same dictionary. + A QIntDict knows about all iterators that are operating on the dictionary. + When an item is removed from the dictionary, QIntDict update all + iterators that are referring the removed item to point to the next item + in the traversing order. + + \sa QIntDict, \link collection.html Collection Classes\endlink +*/ + +/*! + \fn QIntDictIterator::QIntDictIterator( const QIntDict<type> &dict ) + Constructs an iterator for \e dict. The current iterator item is + set to point on the first item in the \e dict. +*/ + +/*! + \fn QIntDictIterator::~QIntDictIterator() + Destroys the iterator. +*/ + +/*! + \fn uint QIntDictIterator::count() const + Returns the number of items in the dictionary this iterator operates on. + \sa isEmpty() +*/ + +/*! + \fn bool QIntDictIterator::isEmpty() const + Returns TRUE if the dictionary is empty, i.e. count() == 0. Returns FALSE + otherwise. + \sa count() +*/ + +/*! + \fn type *QIntDictIterator::toFirst() + Sets the current iterator item to point to the first item in the + dictionary and returns a pointer to the item. + If the dictionary is empty it sets the current item to null and + returns null. +*/ + +/*! + \fn QIntDictIterator::operator type *() const + Cast operator. Returns a pointer to the current iterator item. + Same as current(). +*/ + +/*! + \fn type *QIntDictIterator::current() const + Returns a pointer to the current iterator item. +*/ + +/*! + \fn long QIntDictIterator::currentKey() const + Returns the key for the current iterator item. +*/ + +/*! + \fn type *QIntDictIterator::operator()() + Makes the succeeding item current and returns the original current item. + + If the current iterator item was the last item in the dictionary or if it + was null, null is returned. +*/ + +/*! + \fn type *QIntDictIterator::operator++() + Prefix ++ makes the succeeding item current and returns the new current + item. + + If the current iterator item was the last item in the dictionary or if it + was null, null is returned. +*/ + +/*! + \fn type *QIntDictIterator::operator+=( uint jump ) + Sets the current item to the item \e jump positions after the current item, + and returns a pointer to that item. + + If that item is beyond the last item or if the dictionary is empty, + it sets the current item to null and returns null. +*/ diff --git a/trunk/qtools/qintdict.h b/trunk/qtools/qintdict.h new file mode 100644 index 0000000..ddc5fdf --- /dev/null +++ b/trunk/qtools/qintdict.h @@ -0,0 +1,102 @@ +/**************************************************************************** +** +** +** Definition of QIntDict template class +** +** Created : 940624 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QINTDICT_H +#define QINTDICT_H + +#ifndef QT_H +#include "qgdict.h" +#endif // QT_H + + +template<class type> class Q_EXPORT QIntDict : public QGDict +{ +public: + QIntDict(int size=17) : QGDict(size,IntKey,0,0) {} + QIntDict( const QIntDict<type> &d ) : QGDict(d) {} + ~QIntDict() { clear(); } + QIntDict<type> &operator=(const QIntDict<type> &d) + { return (QIntDict<type>&)QGDict::operator=(d); } + uint count() const { return QGDict::count(); } + uint size() const { return QGDict::size(); } + bool isEmpty() const { return QGDict::count() == 0; } + void insert( long k, const type *d ) + { QGDict::look_int(k,(Item)d,1); } + void replace( long k, const type *d ) + { QGDict::look_int(k,(Item)d,2); } + bool remove( long k ) { return QGDict::remove_int(k); } + type *take( long k ) { return (type*)QGDict::take_int(k); } + type *find( long k ) const + { return (type *)((QGDict*)this)->QGDict::look_int(k,0,0); } + type *operator[]( long k ) const + { return (type *)((QGDict*)this)->QGDict::look_int(k,0,0); } + void clear() { QGDict::clear(); } + void resize( uint n ) { QGDict::resize(n); } + void statistics() const { QGDict::statistics(); } +private: + void deleteItem( Item d ); +}; + +#if defined(Q_DELETING_VOID_UNDEFINED) +template<> inline void QIntDict<void>::deleteItem( QCollection::Item ) +{ +} +#endif + +template<class type> inline void QIntDict<type>::deleteItem( QCollection::Item d ) +{ + if ( del_item ) delete (type *)d; +} + +template<class type> class Q_EXPORT QIntDictIterator : public QGDictIterator +{ +public: + QIntDictIterator(const QIntDict<type> &d) :QGDictIterator((QGDict &)d) {} + ~QIntDictIterator() {} + uint count() const { return dict->count(); } + bool isEmpty() const { return dict->count() == 0; } + type *toFirst() { return (type *)QGDictIterator::toFirst(); } + operator type *() const { return (type *)QGDictIterator::get(); } + type *current() const { return (type *)QGDictIterator::get(); } + long currentKey() const { return QGDictIterator::getKeyInt(); } + type *operator()() { return (type *)QGDictIterator::operator()(); } + type *operator++() { return (type *)QGDictIterator::operator++(); } + type *operator+=(uint j) { return (type *)QGDictIterator::operator+=(j);} +}; + + +#endif // QINTDICT_H diff --git a/trunk/qtools/qiodevice.cpp b/trunk/qtools/qiodevice.cpp new file mode 100644 index 0000000..43b2787 --- /dev/null +++ b/trunk/qtools/qiodevice.cpp @@ -0,0 +1,638 @@ +/**************************************************************************** +** +** +** Implementation of QIODevice class +** +** Created : 940913 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "qiodevice.h" + +// NOT REVISED +/*! + \class QIODevice qiodevice.h + + \brief The QIODevice class is the base class of I/O devices. + + \ingroup io + + An I/O device represents a medium that one can read bytes from + and/or write bytes to. The QIODevice class is the abstract + superclass of all such devices; classes like QFile, QBuffer and + QSocket inherit QIODevice and implement virtual functions like + write() appropriately. + + While applications sometimes use QIODevice directly, mostly it is + better to go through QTextStream and QDataStream, which provide + stream operations on any QIODevice subclass. QTextStream provides + text-oriented stream functionality (for human-readable ASCII files, + for example), while QDataStream deals with binary data in a totally + platform-independent manner. + + The public member functions in QIODevice roughly fall into two + groups: The action functions and the state access functions. The + most important action functions are: <ul> + + <li> open() opens a device for reading and/or writing, depending on + the argument to open(). + + <li> close() closes the device and tidies up. + + <li> readBlock() reads a block of data from the device. + + <li> writeBlock() writes a block of data to the device. + + <li> readLine() reads a line (of text, usually) from the device. + + <li> flush() ensures that all buffered data are written to the real device. + + </ul>There are also some other, less used, action functions: <ul> + + <li> getch() reads a single character. + + <li> ungetch() forgets the last call to getch(), if possible. + + <li> putch() writes a single character. + + <li> size() returns the size of the device, if there is one. + + <li> at() returns the current read/write pointer, if there is one + for this device, or it moves the pointer. + + <li> atEnd() says whether there is more to read, if that is a + meaningful question for this device. + + <li> reset() moves the read/write pointer to the start of the + device, if that is possible for this device. + + </ul>The state access are all "get" functions. The QIODevice subclass + calls setState() to update the state, and simple access functions + tell the user of the device what the device's state is. Here are + the settings, and their associated access functions: <ul> + + <li> Access type. Some devices are direct access (it is possible to + read/write anywhere) while others are sequential. QIODevice + provides the access functions isDirectAccess(), isSequentialAccess() + and isCombinedAccess() to tell users what a given I/O device + supports. + + <li> Buffering. Some devices are accessed in raw mode while others + are buffered. Buffering usually provides greater efficiency, + particularly for small read/write operations. isBuffered() tells + the user whether a given device is buffered. (This can often be set + by the application in the call to open().) + + <li> Synchronicity. Synchronous devices work there and then, for + example files. When you read from a file, the file delivers its + data right away. Others, such as a socket connected to a HTTP + server, may not deliver the data until seconds after you ask to read + it. isSynchronous() and isAsynchronous() tells the user how this + device operates. + + <li> CR/LF translation. For simplicity, applications often like to + see just a single CR/LF style, and QIODevice subclasses can provide + that. isTranslated() returns TRUE if this object translates CR/LF + to just LF. (This can often be set by the application in the call + to open().) + + <li> Accessibility. Some files cannot be written, for example. + isReadable(), isWritable and isReadWrite() tells the application + whether it can read from and write to a given device. (This can + often be set by the application in the call to open().) + + <li> Finally, isOpen() returns TRUE if the device is open. This can + quite obviously be set using open() :) + + </ul> + + QIODevice provides numerous pure virtual functions you need to + implement when subclassing it. Here is a skeleton subclass with all + the members you are certain to need, and some it's likely that you + will need: + + \code + class YourDevice : public QIODevice + { + public: + YourDevice(); + ~YourDevice(); + + bool open( int mode ); + void close(); + void flush(); + + uint size() const; + int at() const; // not a pure virtual function + bool at( int ); // not a pure virtual function + bool atEnd() const; // not a pure virtual function + + int readBlock( char *data, uint maxlen ); + int writeBlock( const char *data, uint len ); + int readLine( char *data, uint maxlen ); + + int getch(); + int putch( int ); + int ungetch( int ); + }; + \endcode + + The three non-pure virtual functions can be ignored if your device + is sequential (e.g. an RS-232 port). + + \sa QDataStream, QTextStream +*/ + + +/*! + Constructs an I/O device. +*/ + +QIODevice::QIODevice() +{ + ioMode = 0; // initial mode + ioSt = IO_Ok; + ioIndex = 0; +} + +/*! + Destructs the I/O device. +*/ + +QIODevice::~QIODevice() +{ +} + + +/*! + \fn int QIODevice::flags() const + Returns the current I/O device flags setting. + + Flags consists of mode flags and state flags. + + \sa mode(), state() +*/ + +/*! + \fn int QIODevice::mode() const + Returns bits OR'ed together that specify the current operation mode. + + These are the flags that were given to the open() function. + + The flags are: \c IO_ReadOnly, \c IO_WriteOnly, \c IO_ReadWrite, + \c IO_Append, \c IO_Truncate and \c IO_Translate. +*/ + +/*! + \fn int QIODevice::state() const + Returns bits OR'ed together that specify the current state. + + The flags are: \c IO_Open. + + Subclasses may define more flags. +*/ + +/*! + \fn bool QIODevice::isDirectAccess() const + Returns TRUE if the I/O device is a direct access (not sequential) device, + otherwise FALSE. + \sa isSequentialAccess() +*/ + +/*! + \fn bool QIODevice::isSequentialAccess() const + Returns TRUE if the I/O device is a sequential access (not direct) device, + otherwise FALSE. Operations involving size() and at(int) are not valid + on sequential devices. + \sa isDirectAccess() +*/ + +/*! + \fn bool QIODevice::isCombinedAccess() const + Returns TRUE if the I/O device is a combined access (both direct and + sequential) device, otherwise FALSE. + + This access method is currently not in use. +*/ + +/*! + \fn bool QIODevice::isBuffered() const + Returns TRUE if the I/O device is a buffered (not raw) device, otherwise + FALSE. + \sa isRaw() +*/ + +/*! + \fn bool QIODevice::isRaw() const + Returns TRUE if the I/O device is a raw (not buffered) device, otherwise + FALSE. + \sa isBuffered() +*/ + +/*! + \fn bool QIODevice::isSynchronous() const + Returns TRUE if the I/O device is a synchronous device, otherwise + FALSE. + \sa isAsynchronous() +*/ + +/*! + \fn bool QIODevice::isAsynchronous() const + Returns TRUE if the I/O device is a asynchronous device, otherwise + FALSE. + + This mode is currently not in use. + + \sa isSynchronous() +*/ + +/*! + \fn bool QIODevice::isTranslated() const + Returns TRUE if the I/O device translates carriage-return and linefeed + characters. + + A QFile is translated if it is opened with the \c IO_Translate mode + flag. +*/ + +/*! + \fn bool QIODevice::isReadable() const + Returns TRUE if the I/O device was opened using \c IO_ReadOnly or + \c IO_ReadWrite mode. + \sa isWritable(), isReadWrite() +*/ + +/*! + \fn bool QIODevice::isWritable() const + Returns TRUE if the I/O device was opened using \c IO_WriteOnly or + \c IO_ReadWrite mode. + \sa isReadable(), isReadWrite() +*/ + +/*! + \fn bool QIODevice::isReadWrite() const + Returns TRUE if the I/O device was opened using \c IO_ReadWrite mode. + \sa isReadable(), isWritable() +*/ + +/*! + \fn bool QIODevice::isInactive() const + Returns TRUE if the I/O device state is 0, i.e. the device is not open. + \sa isOpen() +*/ + +/*! + \fn bool QIODevice::isOpen() const + Returns TRUE if the I/O device state has been opened, otherwise FALSE. + \sa isInactive() +*/ + + +/*! + \fn int QIODevice::status() const + Returns the I/O device status. + + The I/O device status returns an error code. If open() returns FALSE + or readBlock() or writeBlock() return -1, this function can be called to + get the reason why the operation did not succeed. + + The status codes are: + <ul> + <li>\c IO_Ok The operation was successful. + <li>\c IO_ReadError Could not read from the device. + <li>\c IO_WriteError Could not write to the device. + <li>\c IO_FatalError A fatal unrecoverable error occurred. + <li>\c IO_OpenError Could not open the device. + <li>\c IO_ConnectError Could not connect to the device. + <li>\c IO_AbortError The operation was unexpectedly aborted. + <li>\c IO_TimeOutError The operation timed out. + <li>\c IO_OnCloseError An unspecified error happened on close. + </ul> + + \sa resetStatus() +*/ + +/*! + \fn void QIODevice::resetStatus() + + Sets the I/O device status to \c IO_Ok. + + \sa status() +*/ + + +/*! + \fn void QIODevice::setFlags( int f ) + \internal + Used by subclasses to set the device flags. +*/ + +/*! + \internal + Used by subclasses to set the device type. +*/ + +void QIODevice::setType( int t ) +{ +#if defined(CHECK_RANGE) + if ( (t & IO_TypeMask) != t ) + qWarning( "QIODevice::setType: Specified type out of range" ); +#endif + ioMode &= ~IO_TypeMask; // reset type bits + ioMode |= t; +} + +/*! + \internal + Used by subclasses to set the device mode. +*/ + +void QIODevice::setMode( int m ) +{ +#if defined(CHECK_RANGE) + if ( (m & IO_ModeMask) != m ) + qWarning( "QIODevice::setMode: Specified mode out of range" ); +#endif + ioMode &= ~IO_ModeMask; // reset mode bits + ioMode |= m; +} + +/*! + \internal + Used by subclasses to set the device state. +*/ + +void QIODevice::setState( int s ) +{ +#if defined(CHECK_RANGE) + if ( ((uint)s & IO_StateMask) != (uint)s ) + qWarning( "QIODevice::setState: Specified state out of range" ); +#endif + ioMode &= ~IO_StateMask; // reset state bits + ioMode |= (uint)s; +} + +/*! + \internal + Used by subclasses to set the device status (not state). +*/ + +void QIODevice::setStatus( int s ) +{ + ioSt = s; +} + + +/*! + \fn bool QIODevice::open( int mode ) + Opens the I/O device using the specified \e mode. + Returns TRUE if successful, or FALSE if the device could not be opened. + + The mode parameter \e m must be a combination of the following flags. + <ul> + <li>\c IO_Raw specified raw (unbuffered) file access. + <li>\c IO_ReadOnly opens a file in read-only mode. + <li>\c IO_WriteOnly opens a file in write-only mode. + <li>\c IO_ReadWrite opens a file in read/write mode. + <li>\c IO_Append sets the file index to the end of the file. + <li>\c IO_Truncate truncates the file. + <li>\c IO_Translate enables carriage returns and linefeed translation + for text files under MS-DOS, Window, OS/2 and Macintosh. On Unix systems + this flag has no effect. Use with caution as it will also transform every linefeed + written to the file into a CRLF pair. This is likely to corrupt your file when + writing binary data to it. Cannot be combined with \c IO_Raw. + </ul> + + This virtual function must be reimplemented by all subclasses. + + \sa close() +*/ + +/*! + \fn void QIODevice::close() + Closes the I/O device. + + This virtual function must be reimplemented by all subclasses. + + \sa open() +*/ + +/*! + \fn void QIODevice::flush() + + Flushes an open I/O device. + + This virtual function must be reimplemented by all subclasses. +*/ + + +/*! + \fn uint QIODevice::size() const + Virtual function that returns the size of the I/O device. + \sa at() +*/ + +/*! + Virtual function that returns the current I/O device index. + + This index is the data read/write head of the I/O device. + + \sa size() +*/ + +int QIODevice::at() const +{ + return ioIndex; +} + +/*! + Virtual function that sets the I/O device index to \e pos. + \sa size() +*/ + +bool QIODevice::at( int pos ) +{ +#if defined(CHECK_RANGE) + if ( (uint)pos > size() ) { + qWarning( "QIODevice::at: Index %d out of range", pos ); + return FALSE; + } +#endif + ioIndex = pos; + return TRUE; +} + +/*! + Virtual function that returns TRUE if the I/O device index is at the + end of the input. +*/ + +bool QIODevice::atEnd() const +{ + if ( isSequentialAccess() || isTranslated() ) { + QIODevice* that = (QIODevice*)this; + int c = that->getch(); + bool result = c < 0; + that->ungetch(c); + return result; + } else { + return at() == (int)size(); + } +} + +/*! + \fn bool QIODevice::reset() + Sets the device index to 0. + \sa at() +*/ + + +/*! + \fn int QIODevice::readBlock( char *data, uint maxlen ) + Reads at most \e maxlen bytes from the I/O device into \e data and + returns the number of bytes actually read. + + This virtual function must be reimplemented by all subclasses. + + \sa writeBlock() +*/ + +/*! + This convenience function returns all of the remaining data in the + device. Note that this only works for direct access devices, such + as QFile. + + \sa isDirectAccess() +*/ +QByteArray QIODevice::readAll() +{ + int n = size()-at(); + QByteArray ba(size()-at()); + char* c = ba.data(); + while ( n ) { + int r = readBlock( c, n ); + if ( r < 0 ) + return QByteArray(); + n -= r; + c += r; + } + return ba; +} + +/*! + \fn int QIODevice::writeBlock( const char *data, uint len ) + Writes \e len bytes from \e p to the I/O device and returns the number of + bytes actually written. + + This virtual function must be reimplemented by all subclasses. + + \sa readBlock() +*/ + +/*! + This convenience function is the same as calling + writeBlock( data.data(), data.size() ). +*/ +int QIODevice::writeBlock( const QByteArray& data ) +{ + return writeBlock( data.data(), data.size() ); +} + +/*! + Reads a line of text, up to \e maxlen bytes including a terminating + \0. If there is a newline at the end if the line, it is not stripped. + + Returns the number of bytes read, or -1 in case of error. + + This virtual function can be reimplemented much more efficiently by + the most subclasses. + + \sa readBlock(), QTextStream::readLine() +*/ + +int QIODevice::readLine( char *data, uint maxlen ) +{ + if ( maxlen == 0 ) // application bug? + return 0; + int pos = at(); // get current position + int s = (int)size(); // size of I/O device + char *p = data; + if ( pos >= s ) + return 0; + while ( pos++ < s && --maxlen ) { // read one byte at a time + readBlock( p, 1 ); + if ( *p++ == '\n' ) // end of line + break; + } + *p++ = '\0'; + return (int)((long)p - (long)data); +} + + +/*! + \fn int QIODevice::getch() + + Reads a single byte/character from the I/O device. + + Returns the byte/character read, or -1 if the end of the I/O device has been + reached. + + This virtual function must be reimplemented by all subclasses. + + \sa putch(), ungetch() +*/ + +/*! + \fn int QIODevice::putch( int ch ) + + Writes the character \e ch to the I/O device. + + Returns \e ch, or -1 if some error occurred. + + This virtual function must be reimplemented by all subclasses. + + \sa getch(), ungetch() +*/ + +/*! + \fn int QIODevice::ungetch( int ch ) + + Puts the character \e ch back into the I/O device and decrements the + index if it is not zero. + + This function is normally called to "undo" a getch() operation. + + Returns \e ch, or -1 if some error occurred. + + This virtual function must be reimplemented by all subclasses. + + \sa getch(), putch() +*/ diff --git a/trunk/qtools/qiodevice.h b/trunk/qtools/qiodevice.h new file mode 100644 index 0000000..1c54217 --- /dev/null +++ b/trunk/qtools/qiodevice.h @@ -0,0 +1,155 @@ +/**************************************************************************** +** +** +** Definition of QIODevice class +** +** Created : 940913 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QIODEVICE_H +#define QIODEVICE_H + +#ifndef QT_H +#include "qglobal.h" +#include "qcstring.h" +#endif // QT_H + + +// IO device access types + +#define IO_Direct 0x0100 // direct access device +#define IO_Sequential 0x0200 // sequential access device +#define IO_Combined 0x0300 // combined direct/sequential +#define IO_TypeMask 0x0f00 + +// IO handling modes + +#define IO_Raw 0x0040 // raw access (not buffered) +#define IO_Async 0x0080 // asynchronous mode + +// IO device open modes + +#define IO_ReadOnly 0x0001 // readable device +#define IO_WriteOnly 0x0002 // writable device +#define IO_ReadWrite 0x0003 // read+write device +#define IO_Append 0x0004 // append +#define IO_Truncate 0x0008 // truncate device +#define IO_Translate 0x0010 // translate CR+LF +#define IO_ModeMask 0x00ff + +// IO device state + +#define IO_Open 0x1000 // device is open +#define IO_StateMask 0xf000 + + +// IO device status + +#define IO_Ok 0 +#define IO_ReadError 1 // read error +#define IO_WriteError 2 // write error +#define IO_FatalError 3 // fatal unrecoverable error +#define IO_ResourceError 4 // resource limitation +#define IO_OpenError 5 // cannot open device +#define IO_ConnectError 5 // cannot connect to device +#define IO_AbortError 6 // abort error +#define IO_TimeOutError 7 // time out +#define IO_UnspecifiedError 8 // unspecified error + +class Q_EXPORT QIODevice // IO device class +{ +public: + QIODevice(); + virtual ~QIODevice(); + + int flags() const { return ioMode; } + int mode() const { return ioMode & IO_ModeMask; } + int state() const { return ioMode & IO_StateMask; } + + bool isDirectAccess() const { return ((ioMode & IO_Direct) == IO_Direct); } + bool isSequentialAccess() const { return ((ioMode & IO_Sequential) == IO_Sequential); } + bool isCombinedAccess() const { return ((ioMode & IO_Combined) == IO_Combined); } + bool isBuffered() const { return ((ioMode & IO_Raw) != IO_Raw); } + bool isRaw() const { return ((ioMode & IO_Raw) == IO_Raw); } + bool isSynchronous() const { return ((ioMode & IO_Async) != IO_Async); } + bool isAsynchronous() const { return ((ioMode & IO_Async) == IO_Async); } + bool isTranslated() const { return ((ioMode & IO_Translate) == IO_Translate); } + bool isReadable() const { return ((ioMode & IO_ReadOnly) == IO_ReadOnly); } + bool isWritable() const { return ((ioMode & IO_WriteOnly) == IO_WriteOnly); } + bool isReadWrite() const { return ((ioMode & IO_ReadWrite) == IO_ReadWrite); } + bool isInactive() const { return state() == 0; } + bool isOpen() const { return state() == IO_Open; } + + int status() const { return ioSt; } + void resetStatus() { ioSt = IO_Ok; } + + virtual bool open( int mode ) = 0; + virtual void close() = 0; + virtual void flush() = 0; + + virtual uint size() const = 0; + virtual int at() const; + virtual bool at( int ); + virtual bool atEnd() const; + bool reset() { return at(0); } + + virtual int readBlock( char *data, uint maxlen ) = 0; + virtual int writeBlock( const char *data, uint len ) = 0; + virtual int readLine( char *data, uint maxlen ); + int writeBlock( const QByteArray& data ); + QByteArray readAll(); + + virtual int getch() = 0; + virtual int putch( int ) = 0; + virtual int ungetch( int ) = 0; + +protected: + void setFlags( int f ) { ioMode = f; } + void setType( int ); + void setMode( int ); + void setState( int ); + void setStatus( int ); + int ioIndex; + +private: + int ioMode; + int ioSt; + +private: // Disabled copy constructor and operator= +#if defined(Q_DISABLE_COPY) + QIODevice( const QIODevice & ); + QIODevice &operator=( const QIODevice & ); +#endif +}; + + +#endif // QIODEVICE_H diff --git a/trunk/qtools/qlist.doc b/trunk/qtools/qlist.doc new file mode 100644 index 0000000..98decd1 --- /dev/null +++ b/trunk/qtools/qlist.doc @@ -0,0 +1,1048 @@ +/**************************************************************************** +** +** +** QList and QListIterator class documentation +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + + +/***************************************************************************** + QList documentation + *****************************************************************************/ + +/*! + \class QList qlist.h + \brief The QList class is a template class that provides doubly linked lists. + + \ingroup collection + \ingroup tools + + In Qt 2.0 QList is only implemented as a template class. Define a + template instance QList\<X\> to create a list that operates on pointers + to X, or X*. + + Example: + \code + #include <qlist.h> + #include <qstring.h> + #include <stdio.h> + + class Employee + { + public: + Employee( const QString& name, int salary ) { n=name; s=salary; } + QString name() const { return n; } + int salary() const { return s; } + private: + QString n; + int s; + }; + + void main() + { + QList<Employee> list; // list of pointers to Employee + list.setAutoDelete( TRUE ); // delete items when they are removed + + list.append( new Employee("Bill", 50000) ); + list.append( new Employee("Steve",80000) ); + list.append( new Employee("Ron", 60000) ); + + Employee *emp; + for ( emp=list.first(); emp != 0; emp=list.next() ) + printf( "%s earns %d\n", emp->name().latin1(), emp->salary() ); + } + \endcode + + Program output: + \code + Bill earns 50000 + Steve earns 80000 + Ron earns 60000 + \endcode + + The list class is indexable and has a \link at() current index\endlink + and a \link current() current item\endlink. The first item corresponds + to index 0. The current index is -1 if the current item is null. + + QList has several member functions for traversing the list, but using + a QListIterator can be more practical. Multiple list iterators may + traverse the same list, independent of each other and independent of + the current list item. + + In the example above, we make the call setAutoDelete(TRUE). + Enabling auto-deletion tells the list to delete items that are removed + from the list. The default is to not delete items when they are + removed, but that would cause a memory leak in our example since we have + no other references to the list items. + + List items are stored as \c void* in an internal QLNode, which also + holds pointers to the next and previous list items. The functions + currentNode(), removeNode() and takeNode() operate directly on the + QLNode, but they should be used with care. + + When inserting an item into a list, only the pointer is copied, not the + item itself. This is called a shallow copy. It is possible to make the + list copy all of the item's data (known as a deep copy) when an item is + inserted. insert(), inSort() and append() call the virtual function + QCollection::newItem() for the item to be inserted. + Inherit a list and reimplement it if you want deep copies. + + When removing an item from a list, the virtual function + QCollection::deleteItem() is called. QList's default implementation + is to delete the item if auto-deletion is enabled. + + The virtual function QGList::compareItems() can be reimplemented to + compare two list items. This function is called from all list functions + that need to compare list items, for instance remove(const type*). + If you only want to deal with pointers, there are functions that + compare pointers instead, for instance removeRef(const type*). + These functions are somewhat faster than those that call compareItems(). + + The QStrList class in qstrlist.h is a list of \c char*. QStrList is + a good example of a list that reimplements newItem(), deleteItem() and + compareItems() + + \sa QListIterator, \link collection.html Collection Classes\endlink +*/ + + +/*! + \fn QList::QList() + Constructs an empty list. +*/ + +/*! + \fn QList::QList( const QList<type> &list ) + Constructs a copy of \e list. + + Each item in \e list is \link append() appended\endlink to this list. + Only the pointers are copied (shallow copy). +*/ + +/*! + \fn QList::~QList() + Removes all items from the list and destroys the list. + + All list iterators that access this list will be reset. + + \sa setAutoDelete() +*/ + +/*! + \fn QList<type> &QList::operator=(const QList<type> &list) + Assigns \e list to this list and returns a reference to this list. + + This list is first cleared, then each item in \e list is + \link append() appended\endlink to this list. Only the pointers are copied + (shallow copy), unless newItem() has been reimplemented(). +*/ + +/*! + \fn bool QList::operator==(const QList<type> &list ) const + + Compares this list with \a list. Retruns TRUE if the lists + contain the same data, else FALSE. +*/ + +/*! + \fn uint QList::count() const + Returns the number of items in the list. + \sa isEmpty() +*/ + +/*! + \fn void QList::sort() + + Sorts the list by the result of the virtual compareItems() function. + + The Heap-Sort algorithm is used for sorting. It sorts n items with + O(n*log n) compares. This is the asymptotic optimal solution of the + sorting problem. + + If the items in your list support operator< and operator== then you + might be better off with QSortedList since it implements the + compareItems() function for you using these two operators. + + \sa inSort() +*/ + +/*! + \fn bool QList::isEmpty() const + Returns TRUE if the list is empty, i.e. count() == 0. Returns FALSE + otherwise. + \sa count() +*/ + +/*! + \fn bool QList::insert( uint index, const type *item ) + Inserts the \e item at the position \e index in the list. + + Returns TRUE if successful, or FALSE if \e index is out of range. + The valid range is <code>0 .. count()</code> inclusive. + The item is appended if \e index == count(). + + The inserted item becomes the current list item. + + The \e item must not be a null pointer. + + \sa append(), current() +*/ + +/*! + \fn void QList::inSort( const type *item ) + Inserts the \e item at its sorted position in the list. + + The sort order depends on the virtual QGList::compareItems() function. + All items must be inserted with inSort() to maintain the sorting order. + + The inserted item becomes the current list item. + + The \e item must not be a null pointer. + + Please note that inSort is slow. If you want to insert lots of items + in a list and sort after inserting then you should use sort(). + inSort() takes up to O(n) compares. That means inserting n items in + your list will need O(n^2) compares while sort() only needs O(n*logn) + for the same task. So you inSort() only if you already have a pre-sorted + list and want to insert only few additional items. + + \sa insert(), QGList::compareItems(), current(), sort() +*/ + +/*! + \fn void QList::append( const type *item ) + Inserts the \e item at the end of the list. + + The inserted item becomes the current list item. + This is equivalent to \c insert(count(),item). + + + The \e item must not be a null pointer. + + \sa insert(), current(), prepend() +*/ + +/*! + \fn void QList::prepend( const type *item ) + + Inserts the \e item at the start of the list. + + The inserted item becomes the current list item. + This is equivalent to \c insert(0,item). + + The \e item must not be a null pointer. + + \sa append(), insert(), current() +*/ + +/*! + \fn bool QList::remove( uint index ) + Removes the item at position \e index in the list. + + Returns TRUE if successful, or FALSE if \e index is out of range. + The valid range is <code>0 .. (count() - 1)</code> inclusive. + + The removed item is deleted if \link QCollection::setAutoDelete() + auto-deletion\endlink is enabled. + + The item after the removed item becomes the new current list item if + the removed item is not the last item in the list. If the last item + is removed, the new last item becomes the current item in Qt 2.x. + In 3.0, the current item will be set to null. The current item is + set to null if the list becomes empty. + + All list iterators that refer to the removed item will be set to point + to the new current item. + + \sa take(), clear(), setAutoDelete(), current() removeRef() +*/ + +/*! + \fn bool QList::remove() + Removes the current list item. + + Returns TRUE if successful, or FALSE if the current item is null. + + The removed item is deleted if \link QCollection::setAutoDelete() + auto-deletion\endlink is enabled. + + The item after the removed item becomes the new current list item if + the removed item is not the last item in the list. If the last item + is removed, the new last item becomes the current item in Qt 2.x. + In 3.0, the current item will be set to null. The current item is + set to null if the list becomes empty. + + All list iterators that refer to the removed item will be set to point + to the new current item. + + \sa take(), clear(), setAutoDelete(), current() removeRef() +*/ + +/*! + \fn bool QList::remove( const type *item ) + Removes the first occurrence of \e item from the list. + + Returns TRUE if successful, or FALSE if the item could not be found in the + list. + + The removed item is deleted if \link QCollection::setAutoDelete() + auto-deletion\endlink is enabled. + + The compareItems() function is called when searching for the item + in the list. If compareItems() is not reimplemented, it is more + efficient to call removeRef(). + + The item after the removed item becomes the new current list item if + the removed item is not the last item in the list. If the last item + is removed, the new last item becomes the current item in Qt 2.x. + In 3.0, the current item will be set to null. The current item is + set to null if the list becomes empty. + + All list iterators that refer to the removed item will be set to point + to the new current item. + + \sa removeRef(), take(), clear(), setAutoDelete(), compareItems(), current() +*/ + +/*! + \fn bool QList::removeRef( const type *item ) + Removes the first occurrence of \e item from the list. + + Returns TRUE if successful, or FALSE if the item cannot be found in the + list. + + The removed item is deleted if \link QCollection::setAutoDelete() + auto-deletion\endlink is enabled. + + The list is scanned until the pointer \e item is found. It is removed + if it is found. + + Equivalent to: + \code + if ( list.findRef(item) != -1 ) + list.remove(); + \endcode + + The item after the removed item becomes the new current list item if + the removed item is not the last item in the list. If the last item + is removed, the new last item becomes the current item in Qt 2.x. + In 3.0, the current item will be set to null. The current item is + set to null if the list becomes empty. + + All list iterators that refer to the removed item will be set to point + to the new current item. + + \sa remove(), clear(), setAutoDelete(), current() +*/ + +/*! + \fn void QList::removeNode( QLNode *node ) + Removes the \e node from the list. + + This node must exist in the list, otherwise the program may crash. + + The removed item is deleted if \link QCollection::setAutoDelete() + auto-deletion\endlink is enabled. + + The first item in the list will become the new current list item. + The current item is set to null if the list becomes empty. + + All list iterators that refer to the removed item will be set to point to + the item succeeding this item, or the preceding item if the removed item + was the last item. + + \warning Do not call this function unless you are an expert. + + \sa takeNode(), currentNode() remove() removeRef() +*/ + +/*! + \fn bool QList::removeFirst() + Removes the first item from the list. + Returns TRUE if successful, or FALSE if the list is empty. + + The removed item is deleted if \link QCollection::setAutoDelete() + auto-deletion\endlink is enabled. + + The first item in the list becomes the new current list item. + The current item is set to null if the list becomes empty. + + All list iterators that refer to the removed item will be set to point + to the new current item. + + \sa removeLast(), setAutoDelete(), current() remove() +*/ + +/*! + \fn bool QList::removeLast() + Removes the last item from the list. + Returns TRUE if successful, or FALSE if the list is empty. + + The removed item is deleted if \link QCollection::setAutoDelete() + auto-deletion\endlink is enabled. + + The last item in the list becomes the new current list item. + The current item is set to null if the list becomes empty. + + All list iterators that refer to the removed item will be set to point + to the new current item. + + \sa removeFirst(), setAutoDelete(), current() +*/ + +/*! + \fn type *QList::take( uint index ) + Takes the item at position \e index out of the list without + deleting it (even if \link QCollection::setAutoDelete() + auto-deletion\endlink is enabled). + + Returns a pointer to the item taken out of the list, or null if + the index is out of range. + The valid range is <code>0 .. (count() - 1)</code> inclusive. + + The item after the taken item becomes the new current list item if + the taken item is not the last item in the list. If the last item + is taken, the new last item becomes the current item in Qt 2.x. In + 3.0, the current item will be set to null. The current item is set + to null if the list becomes empty. + + All list iterators that refer to the taken item will be set to point to + the new current item. + + \sa remove(), clear(), current() +*/ + +/*! + \fn type *QList::take() + Takes the current item out of the list without deleting it (even if + \link QCollection::setAutoDelete() auto-deletion\endlink is enabled). + Returns a pointer to the item taken out of the list, or null if + the current item is null. + + The item after the taken item becomes the new current list item if + the taken item is not the last item in the list. If the last item + is taken, the new last item becomes the current item in Qt 2.x. In + 3.0, the current item will be set to null. The current item is set + to null if the list becomes empty. + + All list iterators that refer to the taken item will be set to point to + the new current item. + + \sa remove(), clear(), current() +*/ + +/*! + \fn type *QList::takeNode( QLNode *node ) + Takes the \e node out of the list without deleting its item (even if + \link QCollection::setAutoDelete() auto-deletion\endlink is enabled). + Returns a pointer to the item taken out of the list. + + This node must exist in the list, otherwise the program may crash. + + The first item in the list becomes the new current list item. + + All list iterators that refer to the taken item will be set to point to + the item succeeding this item, or the preceding item if the taken item + was the last item. + + \warning Do not call this function unless you are an expert. + + \sa removeNode(), currentNode() +*/ + +/*! + \fn void QList::clear() + Removes all items from the list. + + The removed items are deleted if \link QCollection::setAutoDelete() + auto-deletion\endlink is enabled. + + All list iterators that access this list will be reset. + + \sa remove(), take(), setAutoDelete() +*/ + +/*! + \fn int QList::find( const type *item ) + Finds the first occurrence of \e item in the list. + + If the item is found, the list sets the current item to point to + the found item and returns the index of this item. + If the item is not found, the list sets the current item to null, + the current index to -1 and returns -1. + + The compareItems() function is called when searching for the item + in the list. If compareItems() is not reimplemented, it is more + efficient to call findRef(). + + \sa findNext(), findRef(), compareItems(), current() +*/ + +/*! + \fn int QList::findNext( const type *item ) + Finds the next occurrence of \e item in the list, starting from + the current list item. + + If the item is found, the list sets the current item to point to + the found item and returns the index of this item. + If the item is not found, the list sets the current item to null, + the current index to -1 and returns -1. + + The compareItems() function is called when searching for the item + in the list. If compareItems() is not reimplemented, it is more + efficient to call findNextRef(). + + \sa find(), findNextRef(), compareItems(), current() +*/ + +/*! + \fn int QList::findRef( const type *item ) + Finds the first occurrence of \e item in the list. + + If the item is found, the list sets the current item to point to + the found item and returns the index of this item. + If the item is not found, the list sets the current item to null, + the current index to -1 and returns -1. + + Calling this function is must faster than find(), because find() + compares \e item with each list item using compareItems(). + This function only compares the pointers. + + \sa findNextRef(), find(), current() +*/ + +/*! + \fn int QList::findNextRef( const type *item ) + Finds the next occurrence of \e item in the list, starting from the + current list item. + + If the item is found, the list sets the current item to point to + the found item and returns the index of this item. + If the item is not found, the list sets the current item to null, + the current index to -1 and returns -1. + + Calling this function is must faster than findNext(), because findNext() + compares \e item with each list item using compareItems(). + This function only compares the pointers. + + \sa findRef(), findNext(), current() +*/ + +/*! + \fn uint QList::contains( const type *item ) const + Counts and returns the number of occurrences of \e item in the list. + + The compareItems() function is called when looking for the \e item + in the list. If compareItems() is not reimplemented, it is more + efficient to call containsRef(). + + Does not affect the current list item. + + \sa containsRef(), compareItems() +*/ + +/*! + \fn uint QList::containsRef( const type *item ) const + Counts and returns the number of occurrences of \e item in the list. + + Calling this function is must faster than contains(), because contains() + compares \e item with each list item using compareItems(). + This function only compares the pointers. + + Does not affect the current list item. + + \sa contains() +*/ + +/*! + \fn type *QList::at( uint index ) + Returns a pointer to the item at position \e index in the list, or + null if the index is out of range. + + Sets the current list item to this item if \e index is valid. + The valid range is <code>0 .. (count() - 1)</code> inclusive. + + This function is very efficient. It starts scanning from the first + item, last item or current item, whichever is closest to \e index. + + \sa current() +*/ + +/*! + \fn int QList::at() const + Returns the index of the current list item. The returned value is -1 + if the current item is null. + \sa current() +*/ + +/*! + \fn type *QList::current() const + Returns a pointer to the current list item. The current item may be + null (implies that the current index is -1). + \sa at() +*/ + +/*! + \fn QLNode *QList::currentNode() const + Returns a pointer to the current list node. + + The node can be kept and removed later using removeNode(). + The advantage is that the item can be removed directly without + searching the list. + + \warning Do not call this function unless you are an expert. + + \sa removeNode(), takeNode(), current() +*/ + +/*! + \fn type *QList::getFirst() const + Returns a pointer to the first item in the list, or null if the + list is empty. + + Does not affect the current list item. + + \sa first(), getLast() +*/ + +/*! + \fn type *QList::getLast() const + Returns a pointer to the last item in the list, or null if the + list is empty. + + Does not affect the current list item. + + \sa last(), getFirst() +*/ + +/*! + \fn type *QList::first() + Returns a pointer to the first item in the list and makes this the + current list item, or null if the list is empty. + \sa getFirst(), last(), next(), prev(), current() +*/ + +/*! + \fn type *QList::last() + Returns a pointer to the last item in the list and makes this the + current list item, or null if the list is empty. + \sa getLast(), first(), next(), prev(), current() +*/ + +/*! + \fn type *QList::next() + Returns a pointer to the item succeeding the current item. + Returns null if the current item is null or equal to the last item. + + Makes the succeeding item current. If the current item before this + function call was the last item, the current item will be set to null. + If the current item was null, this function does nothing. + + \sa first(), last(), prev(), current() +*/ + +/*! + \fn type *QList::prev() + Returns a pointer to the item preceding the current item. + Returns null if the current item is null or equal to the first item. + + Makes the preceding item current. If the current item before this + function call was the first item, the current item will be set to null. + If the current item was null, this function does nothing. + + \sa first(), last(), next(), current() +*/ + +/*! + \fn void QList::toVector( QGVector *vec ) const + Stores all list items in the vector \e vec. + + The vector must be have the same item type, otherwise the result + will be undefined. +*/ + + +/***************************************************************************** + QListIterator documentation + *****************************************************************************/ + +/*! + \class QListIterator qlist.h + \brief The QListIterator class provides an iterator for QList collections. + + \ingroup collection + \ingroup tools + + Define a template instance QListIterator\<X\> to create a list iterator + that operates on QList\<X\> (list of X*). + + Example: + \code + #include <qlist.h> + #include <qstring.h> + #include <stdio.h> + + class Employee + { + public: + Employee( const char *name, int salary ) { n=name; s=salary; } + const char *name() const { return n; } + int salary() const { return s; } + private: + QString n; + int s; + }; + + void main() + { + QList<Employee> list; // list of pointers to Employee + list.setAutoDelete( TRUE ); // delete items when they are removed + + list.append( new Employee("Bill", 50000) ); + list.append( new Employee("Steve",80000) ); + list.append( new Employee("Ron", 60000) ); + + QListIterator<Employee> it(list); // iterator for employee list + for ( ; it.current(); ++it ) { + Employee *emp = it.current(); + printf( "%s earns %d\n", emp->name().latin1(), emp->salary() ); + } + } + \endcode + + Program output: + \code + Bill earns 50000 + Steve earns 80000 + Ron earns 60000 + \endcode + + Although QList has member functions to traverse the doubly linked list + structure, using a list iterator is a much more robust way of traversing + the list, because multiple list iterators can operate on the same list, + independent of each other and independent of the QList's current item. + An iterator has its own current list item and can get the next and + previous list items. It can only traverse the list, never modify it. + + A QList knows about all list iterators that are operating on the list. + When an item is removed from the list, the list update all iterators + that are pointing the removed item to point to the new current list item. + + Example: + \code + #include <qlist.h> + #include <qstring.h> + #include <stdio.h> + + class Employee + { + ... // same as above + }; + + void main() + { + QList<Employee> list; // list of pointers to Employee + list.setAutoDelete( TRUE ); // delete items when they are removed + + list.append( new Employee("Bill", 50000) ); + list.append( new Employee("Steve",80000) ); + list.append( new Employee("Ron", 60000) ); + + QListIterator<Employee> it(list); + + list.at( 1 ); // current list item: "Steve" + it.toLast(); // it: "Ron" + --it; // it: "Steve" + + // Now, both the list and the iterator are referring the same item + + list.remove(); + printf( "%s\n", it.current()->name().latin1() ); + } + \endcode + + Program output: + \code + Ron + \endcode + + \sa QList, \link collection.html collection classes\endlink +*/ + +/*! + \fn QListIterator::QListIterator( const QList<type> &list ) + Constructs an iterator for \e list. The current iterator item is + set to point on the first item in the \e list. +*/ + +/*! + \fn QListIterator::~QListIterator() + Destroys the iterator. +*/ + +/*! + \fn uint QListIterator::count() const + Returns the number of items in the list this iterator operates on. + \sa isEmpty() +*/ + +/*! + \fn bool QListIterator::isEmpty() const + Returns TRUE if the list is empty, i.e. count() == 0, otherwise FALSE. + \sa count() +*/ + +/*! + \fn bool QListIterator::atFirst() const + Returns TRUE if the current iterator item is the first list item, otherwise + FALSE. + \sa toFirst(), atLast() +*/ + +/*! + \fn bool QListIterator::atLast() const + Returns TRUE if the current iterator item is the last list item, otherwise + FALSE. + \sa toLast(), atFirst() +*/ + +/*! + \fn type *QListIterator::toFirst() + Sets the current iterator item to point to the first list item and returns + a pointer to the item. Sets the current item to null and returns null + if the list is empty. + \sa toLast(), atFirst() +*/ + +/*! + \fn type *QListIterator::toLast() + Sets the current iterator item to point to the last list item and returns + a pointer to the item. Sets the current item to null and returns null + if the list is empty. + \sa toFirst(), atLast() +*/ + +/*! + \fn QListIterator::operator type *() const + Cast operator. Returns a pointer to the current iterator item. + Same as current(). +*/ + +/*! + \fn type *QListIterator::operator*() + Asterix operator. Returns a pointer to the current iterator item. + Same as current(). +*/ + +/*! + \fn type *QListIterator::current() const + Returns a pointer to the current iterator item. +*/ + +/*! + \fn type *QListIterator::operator()() + Makes the succeeding item current and returns the original current item. + + If the current iterator item was the last item in the list or if it was + null, null is returned. +*/ + +/*! + \fn char *QStrListIterator::operator()() + Makes the succeeding item current and returns the original current item. + + If the current iterator item was the last item in the list or if it was + null, null is returned. +*/ + +/*! + \fn type *QListIterator::operator++() + Prefix ++ makes the succeeding item current and returns the new current + item. + + If the current iterator item was the last item in the list or if it was + null, null is returned. +*/ + +/*! + \fn type *QListIterator::operator+=( uint jump ) + Sets the current item to the item \e jump positions after the current item, + and returns a pointer to that item. + + If that item is beyond the last item or if the dictionary is empty, + it sets the current item to null and returns null +*/ + +/*! + \fn type *QListIterator::operator--() + Prefix -- makes the preceding item current and returns the new current + item. + + If the current iterator item was the first item in the list or if it was + null, null is returned. +*/ + +/*! + \fn type *QListIterator::operator-=( uint jump ) + Returns the item \e jump positions before the current item, or null if + it is beyond the first item. Makes this the current item. +*/ + +/*! + \fn QListIterator<type>& QListIterator::operator=( const QListIterator<type> &it ) + Assignment. Makes a copy of the iterator \a it and returns a reference + to this iterator. +*/ + + +/***************************************************************************** + QStrList documentation + *****************************************************************************/ + +typedef QList<char> QStrList + +/*! + \class QStrList qstrlist.h + \brief The QStrList class provides a doubly linked list of \c char*. + + \inherit QList + + \ingroup collection + \ingroup tools + + This class is a QList\<char\> instance (a list of char*). + + QStrList can make deep or shallow copies of the strings that are inserted. + + A deep copy means to allocate space for the string and then copy the string + data into it. A shallow copy is just a copy of the pointer value and not + the string data. + + The disadvantage with shallow copies is that since a pointer can only + be deleted once, the program must put all strings in a central place and + know when it is safe to delete them (i.e. when the strings are no longer + referenced by other parts of the program). This can make the program + more complex. The advantage of shallow copies is that shallow copies + consume far less memory than deep copies. It is also much faster + to copy a pointer (typically 4 or 8 bytes) than to copy string data. + + A QStrList that operates on deep copies will by default turn on + auto-deletion (see setAutoDelete()). Thus, by default, QStrList will + deallocate any string copies it allocates. + + The virtual compareItems() function is reimplemented and does a case + sensitive string comparison. The inSort() function will insert + strings in a sorted order. + + The QStrListIterator class is an iterator for QStrList. +*/ + +/*! + \fn QStrList::QStrList( bool deepCopies ) + Constructs an empty list of strings. Will make deep copies of all inserted + strings if \e deepCopies is TRUE, or uses shallow copies if \e deepCopies + is FALSE. +*/ + +/*! + \fn QStrList::QStrList( const QStrList &list ) + Constructs a copy of \e list. + + If \e list has deep copies, this list will also get deep copies. + Only the pointers are copied (shallow copy) if the other list does not + use deep copies. +*/ + +/*! + \fn QStrList::~QStrList() + Destroys the list. All strings are removed. +*/ + +/*! + \fn QStrList& QStrList::operator=( const QStrList& list ) + Assigns \e list to this list and returns a reference to this list. + + If \e list has deep copies, this list will also get deep copies. + Only the pointers are copied (shallow copy) if the other list does not + use deep copies. +*/ + + +/***************************************************************************** + QStrIList documentation + *****************************************************************************/ + +/*! + \class QStrIList qstrlist.h + \brief The QStrIList class provides a doubly linked list of \c char* with +case insensitive compare. + + \ingroup collection + \ingroup tools + + This class is a QList\<char\> instance (a list of char*). + + QStrIList is similar to QStrList except that it is case insensitive. + The virtual compareItems() function is reimplemented and does a + case insensitive string comparison. + The inSort() function will insert strings in a sorted order. + + The QStrListIterator class is an iterator for QStrList. +*/ + +/*! + \fn QStrIList::QStrIList( bool deepCopies ) + Constructs a list of strings. Will make deep copies of all inserted + strings if \e deepCopies is TRUE, or uses shallow copies if \e deepCopies + is FALSE. +*/ + +/*! + \fn QStrIList::~QStrIList() + Destroys the list. All strings are removed. +*/ + + +/***************************************************************************** + QStrListIterator documentation + *****************************************************************************/ + +/*! + \class QStrListIterator qstrlist.h + \brief The QStrListIterator class is an iterator for the QStrList and QStrIList classes. + + \inherit QListIterator + + \ingroup tools + + This class is a QListIterator\<char\> instance. + It can traverse the strings in the QStrList and QStrIList classes. +*/ diff --git a/trunk/qtools/qlist.h b/trunk/qtools/qlist.h new file mode 100644 index 0000000..a4608fb --- /dev/null +++ b/trunk/qtools/qlist.h @@ -0,0 +1,139 @@ +/**************************************************************************** +** +** +** Definition of QList template/macro class +** +** Created : 920701 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QLIST_H +#define QLIST_H + +#ifndef QT_H +#include "qglist.h" +#endif // QT_H + + +template<class type> class Q_EXPORT QList : public QGList +{ +public: + QList() {} + QList( const QList<type> &l ) : QGList(l) {} + ~QList() { clear(); } + QList<type> &operator=(const QList<type> &l) + { return (QList<type>&)QGList::operator=(l); } + bool operator==( const QList<type> &list ) const + { return QGList::operator==( list ); } + uint count() const { return QGList::count(); } + bool isEmpty() const { return QGList::count() == 0; } + bool insert( uint i, const type *d){ return QGList::insertAt(i,(QCollection::Item)d); } + void inSort( const type *d ) { QGList::inSort((QCollection::Item)d); } + void prepend( const type *d ) { QGList::insertAt(0,(QCollection::Item)d); } + void append( const type *d ) { QGList::append((QCollection::Item)d); } + bool remove( uint i ) { return QGList::removeAt(i); } + bool remove() { return QGList::remove((QCollection::Item)0); } + bool remove( const type *d ) { return QGList::remove((QCollection::Item)d); } + bool removeRef( const type *d ) { return QGList::removeRef((QCollection::Item)d); } + void removeNode( QLNode *n ) { QGList::removeNode(n); } + bool removeFirst() { return QGList::removeFirst(); } + bool removeLast() { return QGList::removeLast(); } + type *take( uint i ) { return (type *)QGList::takeAt(i); } + type *take() { return (type *)QGList::take(); } + type *takeNode( QLNode *n ) { return (type *)QGList::takeNode(n); } + void clear() { QGList::clear(); } + void sort() { QGList::sort(); } + int find( const type *d ) { return QGList::find((QCollection::Item)d); } + int findNext( const type *d ) { return QGList::find((QCollection::Item)d,FALSE); } + int findRef( const type *d ) { return QGList::findRef((QCollection::Item)d); } + int findNextRef( const type *d ){ return QGList::findRef((QCollection::Item)d,FALSE);} + uint contains( const type *d ) const { return QGList::contains((QCollection::Item)d); } + uint containsRef( const type *d ) const + { return QGList::containsRef((QCollection::Item)d); } + type *at( uint i ) { return (type *)QGList::at(i); } + int at() const { return QGList::at(); } + type *current() const { return (type *)QGList::get(); } + QLNode *currentNode() const { return QGList::currentNode(); } + type *getFirst() const { return (type *)QGList::cfirst(); } + type *getLast() const { return (type *)QGList::clast(); } + type *first() { return (type *)QGList::first(); } + type *last() { return (type *)QGList::last(); } + type *next() { return (type *)QGList::next(); } + type *prev() { return (type *)QGList::prev(); } + void toVector( QGVector *vec )const{ QGList::toVector(vec); } +private: + void deleteItem( QCollection::Item d ); +}; + +#if defined(Q_DELETING_VOID_UNDEFINED) +template<> inline void QList<void>::deleteItem( QCollection::Item ) +{ +} +#endif + +template<class type> inline void QList<type>::deleteItem( QCollection::Item d ) +{ + if ( del_item ) delete (type *)d; +} + + +template<class type> class Q_EXPORT QListIterator : public QGListIterator +{ +public: + QListIterator(const QList<type> &l) :QGListIterator((QGList &)l) {} + ~QListIterator() {} + uint count() const { return list->count(); } + bool isEmpty() const { return list->count() == 0; } + bool atFirst() const { return QGListIterator::atFirst(); } + bool atLast() const { return QGListIterator::atLast(); } + type *toFirst() { return (type *)QGListIterator::toFirst(); } + type *toLast() { return (type *)QGListIterator::toLast(); } + operator type *() const { return (type *)QGListIterator::get(); } + type *operator*() { return (type *)QGListIterator::get(); } + + // No good, since QList<char> (ie. QStrList fails... + // + // MSVC++ gives warning + // Sunpro C++ 4.1 gives error + // type *operator->() { return (type *)QGListIterator::get(); } + + type *current() const { return (type *)QGListIterator::get(); } + type *operator()() { return (type *)QGListIterator::operator()();} + type *operator++() { return (type *)QGListIterator::operator++(); } + type *operator+=(uint j) { return (type *)QGListIterator::operator+=(j);} + type *operator--() { return (type *)QGListIterator::operator--(); } + type *operator-=(uint j) { return (type *)QGListIterator::operator-=(j);} + QListIterator<type>& operator=(const QListIterator<type>&it) + { QGListIterator::operator=(it); return *this; } +}; + + +#endif // QLIST_H diff --git a/trunk/qtools/qmap.cpp b/trunk/qtools/qmap.cpp new file mode 100644 index 0000000..1d2510a --- /dev/null +++ b/trunk/qtools/qmap.cpp @@ -0,0 +1,254 @@ +/**************************************************************************** +** +** +** Implementation of QMap +** +** Created : 990406 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "qmap.h" + +typedef QMapNodeBase* NodePtr; +typedef QMapNodeBase Node; + + +void QMapPrivateBase::rotateLeft( NodePtr x, NodePtr& root) +{ + NodePtr y = x->right; + x->right = y->left; + if (y->left !=0) + y->left->parent = x; + y->parent = x->parent; + if (x == root) + root = y; + else if (x == x->parent->left) + x->parent->left = y; + else + x->parent->right = y; + y->left = x; + x->parent = y; +} + + +void QMapPrivateBase::rotateRight( NodePtr x, NodePtr& root ) +{ + NodePtr y = x->left; + x->left = y->right; + if (y->right != 0) + y->right->parent = x; + y->parent = x->parent; + if (x == root) + root = y; + else if (x == x->parent->right) + x->parent->right = y; + else + x->parent->left = y; + y->right = x; + x->parent = y; +} + + +void QMapPrivateBase::rebalance( NodePtr x, NodePtr& root) +{ + x->color = Node::Red; + while ( x != root && x->parent->color == Node::Red ) { + if ( x->parent == x->parent->parent->left ) { + NodePtr y = x->parent->parent->right; + if (y && y->color == Node::Red) { + x->parent->color = Node::Black; + y->color = Node::Black; + x->parent->parent->color = Node::Red; + x = x->parent->parent; + } else { + if (x == x->parent->right) { + x = x->parent; + rotateLeft( x, root ); + } + x->parent->color = Node::Black; + x->parent->parent->color = Node::Red; + rotateRight (x->parent->parent, root ); + } + } else { + NodePtr y = x->parent->parent->left; + if ( y && y->color == Node::Red ) { + x->parent->color = Node::Black; + y->color = Node::Black; + x->parent->parent->color = Node::Red; + x = x->parent->parent; + } else { + if (x == x->parent->left) { + x = x->parent; + rotateRight( x, root ); + } + x->parent->color = Node::Black; + x->parent->parent->color = Node::Red; + rotateLeft( x->parent->parent, root ); + } + } + } + root->color = Node::Black; +} + + +NodePtr QMapPrivateBase::removeAndRebalance( NodePtr z, NodePtr& root, + NodePtr& leftmost, + NodePtr& rightmost ) +{ + NodePtr y = z; + NodePtr x; + NodePtr x_parent; + if (y->left == 0) { + x = y->right; + } else { + if (y->right == 0) + x = y->left; + else + { + y = y->right; + while (y->left != 0) + y = y->left; + x = y->right; + } + } + if (y != z) { + z->left->parent = y; + y->left = z->left; + if (y != z->right) { + x_parent = y->parent; + if (x) + x->parent = y->parent; + y->parent->left = x; + y->right = z->right; + z->right->parent = y; + } else { + x_parent = y; + } + if (root == z) + root = y; + else if (z->parent->left == z) + z->parent->left = y; + else + z->parent->right = y; + y->parent = z->parent; + // Swap the colors + Node::Color c = y->color; + y->color = z->color; + z->color = c; + y = z; + } else { + x_parent = y->parent; + if (x) + x->parent = y->parent; + if (root == z) + root = x; + else if (z->parent->left == z) + z->parent->left = x; + else + z->parent->right = x; + if ( leftmost == z ) { + if (z->right == 0) + leftmost = z->parent; + else + leftmost = x->minimum(); + } + if (rightmost == z) { + if (z->left == 0) + rightmost = z->parent; + else + rightmost = x->maximum(); + } + } + if (y->color != Node::Red) { + while (x != root && (x == 0 || x->color == Node::Black)) { + if (x == x_parent->left) { + NodePtr w = x_parent->right; + if (w->color == Node::Red) { + w->color = Node::Black; + x_parent->color = Node::Red; + rotateLeft(x_parent, root); + w = x_parent->right; + } + if ((w->left == 0 || w->left->color == Node::Black) && + (w->right == 0 || w->right->color == Node::Black)) { + w->color = Node::Red; + x = x_parent; + x_parent = x_parent->parent; + } else { + if (w->right == 0 || w->right->color == Node::Black) { + if (w->left) + w->left->color = Node::Black; + w->color = Node::Red; + rotateRight(w, root); + w = x_parent->right; + } + w->color = x_parent->color; + x_parent->color = Node::Black; + if (w->right) + w->right->color = Node::Black; + rotateLeft(x_parent, root); + break; + } + } else { + NodePtr w = x_parent->left; + if (w->color == Node::Red) { + w->color = Node::Black; + x_parent->color = Node::Red; + rotateRight(x_parent, root); + w = x_parent->left; + } + if ((w->right == 0 || w->right->color == Node::Black) && + (w->left == 0 || w->left->color == Node::Black)) { + w->color = Node::Red; + x = x_parent; + x_parent = x_parent->parent; + } else { + if (w->left == 0 || w->left->color == Node::Black) { + if (w->right) + w->right->color = Node::Black; + w->color = Node::Red; + rotateLeft(w, root); + w = x_parent->left; + } + w->color = x_parent->color; + x_parent->color = Node::Black; + if (w->left) + w->left->color = Node::Black; + rotateRight(x_parent, root); + break; + } + } + } + if (x) + x->color = Node::Black; + } + return y; +} diff --git a/trunk/qtools/qmap.h b/trunk/qtools/qmap.h new file mode 100644 index 0000000..f384a3d --- /dev/null +++ b/trunk/qtools/qmap.h @@ -0,0 +1,606 @@ +/**************************************************************************** +** +** +** Definition of QMap class +** +** Created : 990406 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QMAP_H +#define QMAP_H + +#ifndef QT_H +#include "qshared.h" +#include "qdatastream.h" +#endif // QT_H + + +struct QMapNodeBase +{ + enum Color { Red, Black }; + + QMapNodeBase* left; + QMapNodeBase* right; + QMapNodeBase* parent; + + Color color; + + QMapNodeBase* minimum() { + QMapNodeBase* x = this; + while ( x->left ) + x = x->left; + return x; + } + + QMapNodeBase* maximum() { + QMapNodeBase* x = this; + while ( x->right ) + x = x->right; + return x; + } +}; + + +template <class K, class T> +struct QMapNode : public QMapNodeBase +{ + QMapNode( const K& _key, const T& _data ) { data = _data; key = _key; } + QMapNode( const K& _key ) { key = _key; } + QMapNode( const QMapNode<K,T>& _n ) { key = _n.key; data = _n.data; } + QMapNode() { } + T data; + K key; +}; + + +template<class K, class T> +class Q_EXPORT QMapIterator +{ + public: + /** + * Typedefs + */ + typedef QMapNode< K, T >* NodePtr; + + /** + * Variables + */ + QMapNode<K,T>* node; + + /** + * Functions + */ + QMapIterator() : node( 0 ) {} + QMapIterator( QMapNode<K,T>* p ) : node( p ) {} + QMapIterator( const QMapIterator<K,T>& it ) : node( it.node ) {} + + bool operator==( const QMapIterator<K,T>& it ) const { return node == it.node; } + bool operator!=( const QMapIterator<K,T>& it ) const { return node != it.node; } + T& operator*() { return node->data; } + const T& operator*() const { return node->data; } + + // Cannot have this - some compilers are too stupid + //T* operator->() const { return &(node->data); } + + const K& key() const { return node->key; } + T& data() { return node->data; } + const T& data() const { return node->data; } + +private: + int inc() { + QMapNodeBase* tmp = node; + if ( tmp->right ) { + tmp = tmp->right; + while ( tmp->left ) + tmp = tmp->left; + } else { + QMapNodeBase* y = tmp->parent; + while (tmp == y->right) { + tmp = y; + y = y->parent; + } + if (tmp->right != y) + tmp = y; + } + node = (NodePtr)tmp; + return 0; + } + + int dec() { + QMapNodeBase* tmp = node; + if (tmp->color == QMapNodeBase::Red && + tmp->parent->parent == tmp ) { + tmp = tmp->right; + } else if (tmp->left != 0) { + QMapNodeBase* y = tmp->left; + while ( y->right ) + y = y->right; + tmp = y; + } else { + QMapNodeBase* y = tmp->parent; + while (tmp == y->left) { + tmp = y; + y = y->parent; + } + tmp = y; + } + node = (NodePtr)tmp; + return 0; + } + +public: + QMapIterator<K,T>& operator++() { + inc(); + return *this; + } + + QMapIterator<K,T> operator++(int) { + QMapIterator<K,T> tmp = *this; + inc(); + return tmp; + } + + QMapIterator<K,T>& operator--() { + dec(); + return *this; + } + + QMapIterator<K,T> operator--(int) { + QMapIterator<K,T> tmp = *this; + dec(); + return tmp; + } +}; + +template<class K, class T> +class Q_EXPORT QMapConstIterator +{ + public: + /** + * Typedefs + */ + typedef QMapNode< K, T >* NodePtr; + + /** + * Variables + */ + QMapNode<K,T>* node; + + /** + * Functions + */ + QMapConstIterator() : node( 0 ) {} + QMapConstIterator( QMapNode<K,T>* p ) : node( p ) {} + QMapConstIterator( const QMapConstIterator<K,T>& it ) : node( it.node ) {} + QMapConstIterator( const QMapIterator<K,T>& it ) : node( it.node ) {} + + bool operator==( const QMapConstIterator<K,T>& it ) const { return node == it.node; } + bool operator!=( const QMapConstIterator<K,T>& it ) const { return node != it.node; } + const T& operator*() const { return node->data; } + + // Cannot have this - some compilers are too stupid + //const T* operator->() const { return &(node->data); } + + const K& key() const { return node->key; } + const T& data() const { return node->data; } + +private: + int inc() { + QMapNodeBase* tmp = node; + if ( tmp->right ) { + tmp = tmp->right; + while ( tmp->left ) + tmp = tmp->left; + } else { + QMapNodeBase* y = tmp->parent; + while (tmp == y->right) { + tmp = y; + y = y->parent; + } + if (tmp->right != y) + tmp = y; + } + node = (NodePtr)tmp; + return 0; + } + + int dec() { + QMapNodeBase* tmp = node; + if (tmp->color == QMapNodeBase::Red && + tmp->parent->parent == tmp ) { + tmp = tmp->right; + } else if (tmp->left != 0) { + QMapNodeBase* y = tmp->left; + while ( y->right ) + y = y->right; + tmp = y; + } else { + QMapNodeBase* y = tmp->parent; + while (tmp == y->left) { + tmp = y; + y = y->parent; + } + tmp = y; + } + node = (NodePtr)tmp; + return 0; + } + +public: + QMapConstIterator<K,T>& operator++() { + inc(); + return *this; + } + + QMapConstIterator<K,T> operator++(int) { + QMapConstIterator<K,T> tmp = *this; + inc(); + return tmp; + } + + QMapConstIterator<K,T>& operator--() { + dec(); + return *this; + } + + QMapConstIterator<K,T> operator--(int) { + QMapConstIterator<K,T> tmp = *this; + dec(); + return tmp; + } +}; + + +class Q_EXPORT QMapPrivateBase : public QShared +{ +public: + QMapPrivateBase() { + node_count = 0; + } + QMapPrivateBase( const QMapPrivateBase* _map) { + node_count = _map->node_count; + } + + /** + * Implementations of basic tree algorithms + */ + void rotateLeft( QMapNodeBase* x, QMapNodeBase*& root); + void rotateRight( QMapNodeBase* x, QMapNodeBase*& root ); + void rebalance( QMapNodeBase* x, QMapNodeBase*& root ); + QMapNodeBase* removeAndRebalance( QMapNodeBase* z, QMapNodeBase*& root, + QMapNodeBase*& leftmost, + QMapNodeBase*& rightmost ); + + /** + * Variables + */ + int node_count; +}; + + +template <class Key, class T> +class QMapPrivate : public QMapPrivateBase +{ +public: + /** + * Typedefs + */ + typedef QMapIterator< Key, T > Iterator; + typedef QMapConstIterator< Key, T > ConstIterator; + typedef QMapNode< Key, T > Node; + typedef QMapNode< Key, T >* NodePtr; + + /** + * Functions + */ + QMapPrivate() { + header = new Node; + header->color = QMapNodeBase::Red; // Mark the header + header->parent = 0; + header->left = header->right = header; + } + QMapPrivate( const QMapPrivate< Key, T >* _map ) : QMapPrivateBase( _map ) { + header = new Node; + header->color = QMapNodeBase::Red; // Mark the header + if ( _map->header->parent == 0 ) { + header->parent = 0; + header->left = header->right = header; + } else { + header->parent = copy( (NodePtr)(_map->header->parent) ); + header->parent->parent = header; + header->left = header->parent->minimum(); + header->right = header->parent->maximum(); + } + } + ~QMapPrivate() { clear(); delete header; } + + NodePtr copy( NodePtr p ) { + if ( !p ) + return 0; + NodePtr n = new Node( *p ); + n->color = p->color; + if ( p->left ) { + n->left = copy( (NodePtr)(p->left) ); + n->left->parent = n; + } else { + n->left = 0; + } + if ( p->right ) { + n->right = copy( (NodePtr)(p->right) ); + n->right->parent = n; + } else { + n->right = 0; + } + return n; + } + + void clear() { + clear( (NodePtr)(header->parent) ); + header->color = QMapNodeBase::Red; + header->parent = 0; + header->left = header->right = header; + node_count = 0; + } + + void clear( NodePtr p ) { + while ( p != 0 ) { + clear( (NodePtr)p->right ); + NodePtr y = (NodePtr)p->left; + delete p; + p = y; + } + } + + Iterator begin() { return Iterator( (NodePtr)(header->left ) ); } + Iterator end() { return Iterator( header ); } + ConstIterator begin() const { return ConstIterator( (NodePtr)(header->left ) ); } + ConstIterator end() const { return ConstIterator( header ); } + + ConstIterator find(const Key& k) const { + QMapNodeBase* y = header; // Last node + QMapNodeBase* x = header->parent; // Root node. + + while ( x != 0 ) { + // If as k <= key(x) go left + if ( !( key(x) < k ) ) { + y = x; + x = x->left; + } else { + x = x->right; + } + } + + // Was k bigger/smaller then the biggest/smallest + // element of the tree ? Return end() + if ( y == header || k < key(y) ) + return ConstIterator( header ); + return ConstIterator( (NodePtr)y ); + } + + void remove( Iterator it ) { + NodePtr del = (NodePtr) removeAndRebalance( it.node, header->parent, header->left, header->right ); + delete del; + --node_count; + } + +#ifdef QT_QMAP_DEBUG + void inorder( QMapNodeBase* x = 0, int level = 0 ){ + if ( !x ) + x = header->parent; + if ( x->left ) + inorder( x->left, level + 1 ); + //cout << level << " Key=" << key(x) << " Value=" << ((NodePtr)x)->data << endl; + if ( x->right ) + inorder( x->right, level + 1 ); + } +#endif + + Iterator insertMulti(const Key& v){ + QMapNodeBase* y = header; + QMapNodeBase* x = header->parent; + while (x != 0){ + y = x; + x = ( v < key(x) ) ? x->left : x->right; + } + return insert(x, y, v); + } + + Iterator insertSingle( const Key& k ) { + // Search correct position in the tree + QMapNodeBase* y = header; + QMapNodeBase* x = header->parent; + bool result = TRUE; + while ( x != 0 ) { + result = ( k < key(x) ); + y = x; + x = result ? x->left : x->right; + } + // Get iterator on the last not empty one + Iterator j( (NodePtr)y ); + if ( result ) { + // Smaller then the leftmost one ? + if ( j == begin() ) { + return insert(x, y, k ); + } else { + // Perhaps daddy is the right one ? + --j; + } + } + // Really bigger ? + if ( (j.node->key) < k ) + return insert(x, y, k ); + // We are going to replace a node + return j; + } + + Iterator insert( QMapNodeBase* x, QMapNodeBase* y, const Key& k ) { + NodePtr z = new Node( k ); + if (y == header || x != 0 || k < key(y) ) { + y->left = z; // also makes leftmost = z when y == header + if ( y == header ) { + header->parent = z; + header->right = z; + } else if ( y == header->left ) + header->left = z; // maintain leftmost pointing to min node + } else { + y->right = z; + if ( y == header->right ) + header->right = z; // maintain rightmost pointing to max node + } + z->parent = y; + z->left = 0; + z->right = 0; + rebalance( z, header->parent ); + ++node_count; + return Iterator(z); + } + +protected: + /** + * Helpers + */ + const Key& key( QMapNodeBase* b ) const { return ((NodePtr)b)->key; } + + /** + * Variables + */ + NodePtr header; +}; + + +template<class Key, class T> +class Q_EXPORT QMap +{ +public: + /** + * Typedefs + */ + typedef QMapIterator< Key, T > Iterator; + typedef QMapConstIterator< Key, T > ConstIterator; + typedef T ValueType; + typedef QMapPrivate< Key, T > Priv; + + /** + * API + */ + QMap() { sh = new QMapPrivate< Key, T >; } + QMap( const QMap<Key,T>& m ) { sh = m.sh; sh->ref(); } + ~QMap() { if ( sh->deref() ) delete sh; } + + QMap<Key,T>& operator= ( const QMap<Key,T>& m ) + { m.sh->ref(); if ( sh->deref() ) delete sh; sh = m.sh; return *this; } + + Iterator begin() { detach(); return sh->begin(); } + Iterator end() { detach(); return sh->end(); } + ConstIterator begin() const { return ((const Priv*)sh)->begin(); } + ConstIterator end() const { return ((const Priv*)sh)->end(); } + + Iterator find ( const Key& k ) + { detach(); return Iterator( sh->find( k ).node ); } + ConstIterator find ( const Key& k ) const + { return sh->find( k ); } + T& operator[] ( const Key& k ) { + detach(); QMapNode<Key,T>* p = sh->find( k ).node; + if ( p != sh->end().node ) return p->data; + return insert( k, T() ).data(); } + const T& operator[] ( const Key& k ) const + { return sh->find( k ).data(); } + bool contains ( const Key& k ) const + { return find( k ) != end(); } + //{ return sh->find( k ) != ((const Priv*)sh)->end(); } + + uint count() const { return sh->node_count; } + + bool isEmpty() const { return sh->node_count == 0; } + + Iterator insert( const Key& key, const T& value ) { + detach(); + Iterator it = sh->insertSingle( key ); + it.data() = value; + return it; + } + + void remove( Iterator it ) { detach(); sh->remove( it ); } + void remove( const Key& k ) { + detach(); + Iterator it( sh->find( k ).node ); + if ( it != end() ) + sh->remove( it ); + } + + Iterator replace( const Key& k, const T& v ) { + remove( k ); + return insert( k, v ); + } + + void clear() { if ( sh->count == 1 ) sh->clear(); else { sh->deref(); sh = new QMapPrivate<Key,T>; } } + +#if defined(Q_FULL_TEMPLATE_INSTANTIATION) + bool operator==( const QMap<Key,T>& ) const { return FALSE; } +#endif + +protected: + /** + * Helpers + */ + void detach() { if ( sh->count > 1 ) { sh->deref(); sh = new QMapPrivate<Key,T>( sh ); } } + + Priv* sh; +}; + + +#ifndef QT_NO_DATASTREAM +template<class Key, class T> +inline QDataStream& operator>>( QDataStream& s, QMap<Key,T>& m ) { + m.clear(); + Q_UINT32 c; + s >> c; + for( Q_UINT32 i = 0; i < c; ++i ) { + Key k; T t; + s >> k >> t; + m.insert( k, t ); + } + return s; +} + + +template<class Key, class T> +inline QDataStream& operator<<( QDataStream& s, const QMap<Key,T>& m ) { + s << (Q_UINT32)m.count(); + QMapConstIterator<Key,T> it = m.begin(); + for( ; it != m.end(); ++it ) + s << it.key() << it.data(); + return s; +} +#endif + +#endif // QMAP_H diff --git a/trunk/qtools/qmodules.h b/trunk/qtools/qmodules.h new file mode 100644 index 0000000..08f0baf --- /dev/null +++ b/trunk/qtools/qmodules.h @@ -0,0 +1,11 @@ +// These modules are licensed to you +#define QT_MODULE_TOOLS +#define QT_MODULE_KERNEL +#define QT_MODULE_WIDGETS +#define QT_MODULE_DIALOGS +#define QT_MODULE_ICONVIEW +#define QT_MODULE_WORKSPACE +#define QT_MODULE_NETWORK +#define QT_MODULE_CANVAS +#define QT_MODULE_TABLE +#define QT_MODULE_XML diff --git a/trunk/qtools/qmutex.cpp b/trunk/qtools/qmutex.cpp new file mode 100644 index 0000000..08a13bc --- /dev/null +++ b/trunk/qtools/qmutex.cpp @@ -0,0 +1,95 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <stdio.h> + +#include "qglobal.h" + +#include "qmutex.h" +#include "qmutex_p.h" + +QMutex::QMutex() : d(new QMutexPrivate()) +{ +} + +QMutex::~QMutex() +{ + delete d; +} + +void QMutex::lock() +{ + //printf("%p: QMutex::lock(): enter\n",this); + bool isLocked; + isLocked = d->contenders.testAndSet(0, 1); + if (!isLocked) + { + isLocked = d->contenders.fetchAndAdd(1)==0; + if (!isLocked) + { + // didn't get the lock, wait for it + //printf("%p: QMutex::lock(): wait() %d\n",this,(int)d->contenders); + d->wait(); + + // release lock + d->contenders.fetchAndAdd(-1); + } + } + //printf("%p: QMutex::lock(): leave\n",this); +} + +bool QMutex::tryLock() +{ + bool isLocked = d->contenders.testAndSet(0, 1); + return isLocked; +} + +void QMutex::unlock() +{ + //printf("%p: QMutex::unlock(): enter %d\n",this,(int)d->contenders); + if (!d->contenders.testAndSet(1, 0)) + { + //printf("%p: QMutex::unlock(): wakeUp()\n",this); + d->wakeUp(); + } + //printf("%p: QMutex::unlock(): leave\n",this); +} + diff --git a/trunk/qtools/qmutex.h b/trunk/qtools/qmutex.h new file mode 100644 index 0000000..d3d2ac0 --- /dev/null +++ b/trunk/qtools/qmutex.h @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMUTEX_H +#define QMUTEX_H + +#include "qglobal.h" + +class QMutexPrivate; + +class QMutex +{ +public: + QMutex(); + ~QMutex(); + + void lock(); + bool tryLock(); + void unlock(); + +private: + QMutex(const QMutex &); + QMutex &operator=(const QMutex &); + + QMutexPrivate *d; +}; + +class QMutexLocker +{ + public: + QMutexLocker(QMutex *m) : m_mutex(m) + { + m_mutex->lock(); + } + ~QMutexLocker() + { + m_mutex->unlock(); + } + QMutex *mutex() const { return m_mutex; } + + private: + QMutex *m_mutex; +}; + +#endif // QMUTEX_H diff --git a/trunk/qtools/qmutex_p.h b/trunk/qtools/qmutex_p.h new file mode 100644 index 0000000..a47b407 --- /dev/null +++ b/trunk/qtools/qmutex_p.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMUTEX_P_H +#define QMUTEX_P_H + +#include "qglobal.h" + +#if defined(_OS_UNIX_) || defined(_OS_MAC_) +#include <pthread.h> +#elif defined(_OS_WIN32_) +#include <windows.h> +#endif + +class QAtomicInt +{ + public: + QAtomicInt(int v=0) : m_value(v) {} + bool testAndSet(int expectedValue,int newValue); + int fetchAndAdd(int valueToAdd); + operator int () const { return m_value; } + bool operator==(int value) const { return m_value == value; } + bool operator!=(int value) const { return m_value != value; } + bool operator!() const { return m_value == 0; } + + private: + volatile int m_value; +}; + +class QMutexPrivate +{ +public: + QMutexPrivate(); + ~QMutexPrivate(); + + void wait(); + void wakeUp(); + + QAtomicInt contenders; + +#if defined(_OS_UNIX_) || defined(_OS_MAC_) + volatile bool wakeup; + pthread_mutex_t mutex; + pthread_cond_t cond; +#elif defined(_OS_WIN32_) + HANDLE event; +#else +#error "unsupported platform" +#endif +}; + +#endif // QMUTEX_P_H diff --git a/trunk/qtools/qmutex_unix.cpp b/trunk/qtools/qmutex_unix.cpp new file mode 100644 index 0000000..4fe9a58 --- /dev/null +++ b/trunk/qtools/qmutex_unix.cpp @@ -0,0 +1,117 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <errno.h> +#include <pthread.h> + +#include "qglobal.h" +#include "qmutex.h" +#include "qmutex_p.h" + +static pthread_mutex_t qAtomicMutex = PTHREAD_MUTEX_INITIALIZER; + +static void report_error(int code, const char *where, const char *what) +{ + if (code != 0) + qWarning("%s: %s failure: %d", where, what, code); +} + + +QMutexPrivate::QMutexPrivate() + : contenders(0), wakeup(FALSE) +{ + report_error(pthread_mutex_init(&mutex, NULL), "QMutex", "mutex init"); + report_error(pthread_cond_init(&cond, NULL), "QMutex", "cv init"); +} + +QMutexPrivate::~QMutexPrivate() +{ + report_error(pthread_cond_destroy(&cond), "QMutex", "cv destroy"); + report_error(pthread_mutex_destroy(&mutex), "QMutex", "mutex destroy"); +} + +void QMutexPrivate::wait() +{ + report_error(pthread_mutex_lock(&mutex), "QMutex::lock", "mutex lock"); + int errorCode = 0; + while (!wakeup) + { + errorCode = pthread_cond_wait(&cond, &mutex); + if (errorCode) + { + report_error(errorCode, "QMutex::lock()", "cv wait"); + } + } + wakeup = FALSE; + report_error(pthread_mutex_unlock(&mutex), "QMutex::lock", "mutex unlock"); +} + +void QMutexPrivate::wakeUp() +{ + report_error(pthread_mutex_lock(&mutex), "QMutex::unlock", "mutex lock"); + wakeup = TRUE; + report_error(pthread_cond_signal(&cond), "QMutex::unlock", "cv signal"); + report_error(pthread_mutex_unlock(&mutex), "QMutex::unlock", "mutex unlock"); +} + +bool QAtomicInt::testAndSet(int expectedValue,int newValue) +{ + bool returnValue = false; + pthread_mutex_lock(&qAtomicMutex); + if (m_value == expectedValue) + { + m_value = newValue; + returnValue = true; + } + pthread_mutex_unlock(&qAtomicMutex); + return returnValue; +} + +int QAtomicInt::fetchAndAdd(int valueToAdd) +{ + int returnValue; + pthread_mutex_lock(&qAtomicMutex); + returnValue = m_value; + m_value += valueToAdd; + pthread_mutex_unlock(&qAtomicMutex); + return returnValue; +} + diff --git a/trunk/qtools/qmutex_win32.cpp b/trunk/qtools/qmutex_win32.cpp new file mode 100644 index 0000000..2d662ea --- /dev/null +++ b/trunk/qtools/qmutex_win32.cpp @@ -0,0 +1,108 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <windows.h> + +#include "qmutex.h" +#include "qmutex_p.h" + +QMutexPrivate::QMutexPrivate() + : contenders(0) +{ + event = CreateEvent(0, FALSE, FALSE, 0); + if (!event) + qWarning("QMutexPrivate::QMutexPrivate: Cannot create event"); +} + +QMutexPrivate::~QMutexPrivate() +{ + CloseHandle(event); +} + +void QMutexPrivate::wait() +{ + WaitForSingleObject(event, INFINITE); +} + +void QMutexPrivate::wakeUp() +{ + SetEvent(event); +} + +//---------------------------------------------------------------------- + +class QCriticalSection +{ + public: + QCriticalSection() { InitializeCriticalSection(§ion); } + ~QCriticalSection() { DeleteCriticalSection(§ion); } + void lock() { EnterCriticalSection(§ion); } + void unlock() { LeaveCriticalSection(§ion); } + + private: + CRITICAL_SECTION section; +}; + +static QCriticalSection qAtomicCriticalSection; + +bool QAtomicInt::testAndSet(int expectedValue,int newValue) +{ + bool returnValue = false; + qAtomicCriticalSection.lock(); + if (m_value == expectedValue) + { + m_value = newValue; + returnValue = true; + } + qAtomicCriticalSection.unlock(); + return returnValue; +} + +int QAtomicInt::fetchAndAdd(int valueToAdd) +{ + int returnValue; + qAtomicCriticalSection.lock(); + returnValue = m_value; + m_value += valueToAdd; + qAtomicCriticalSection.unlock(); + return returnValue; +} + diff --git a/trunk/qtools/qptrdict.doc b/trunk/qtools/qptrdict.doc new file mode 100644 index 0000000..bff6a15 --- /dev/null +++ b/trunk/qtools/qptrdict.doc @@ -0,0 +1,486 @@ +/**************************************************************************** +** +** +** QPtrDict and QPtrDictIterator class documentation +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + + +/***************************************************************************** + QPtrDict documentation + *****************************************************************************/ + +/*! + \class QPtrDict qptrdict.h + \brief The QPtrDict class is a template class that provides a dictionary based on \c void* keys. + + \ingroup collection + \ingroup tools + + QPtrDict is implemented as a template class. Define a + template instance QPtrDict\<X\> to create a dictionary that operates on + pointers to X, or X*. + + A dictionary is a collection that associates an item with a key. + The key is used for inserting and looking up an item. QPtrDict has + \c void* keys. + + The dictionary has very fast insertion and lookup. + + Example: + \code + #include <qptrdict.h> + #include <stdio.h> + + void main() + { + int *a = new int[12]; + int *b = new int[10]; + int *c = new int[18]; + int *d = new int[13]; + + QPtrDict<char> dict; // maps void* -> char* + + dict.insert( a, "a is int[12]" ); // describe pointers + dict.insert( b, "b is int[10]" ); + dict.insert( c, "c is int[18]" ); + + printf( "%s\n", dict[a] ); // print descriptions + printf( "%s\n", dict[b] ); + printf( "%s\n", dict[c] ); + + if ( !dict[d] ) + printf( "d not in dictionary\n" ); + } + \endcode + + Program output: + \code + a is int[12] + b is int[10] + c is int[18] + d not in dictionary + \endcode + + The dictionary in our example maps \c int* keys to \c char* items. + QPtrDict implements the \link operator[] [] operator\endlink to lookup + an item. + + QPtrDict is implemented by QGDict as a hash array with a fixed number of + entries. Each array entry points to a singly linked list of buckets, in + which the dictionary items are stored. + + When an item is inserted with a key, the key is converted (hashed) to + an integer index into the hash array using the \c mod operation. The + item is inserted before the first bucket in the list of buckets. + + Looking up an item is normally very fast. The key is again hashed to an + array index. Then QPtrDict scans the list of buckets and returns the item + found or null if the item was not found. You cannot insert null pointers + into a dictionary. + + The size of the hash array is very important. In order to get good + performance, you should use a suitably large \link primes.html prime + number\endlink. Suitable means equal to or larger than the maximum + expected number of dictionary items. + + Items with equal keys are allowed. When inserting two items with the + same key, only the last inserted item will be visible (last in, first out) + until it is removed. + + Example: + \code + #include <qptrdict.h> + #include <stdio.h> + + void main() + { + QPtrDict<char> dict; // maps char* ==> char* + + double *ptr = new double[28]; + dict.insert( ptr, "first" ); + dict.insert( ptr, "second" ); + + printf( "%s\n", dict[ptr] ); + dict.remove( ptr ); + printf( "%s\n", dict[ptr] ); + } + \endcode + + Program output: + \code + second + first + \endcode + + The QPtrDictIterator class can traverse the dictionary contents, but only + in an arbitrary order. Multiple iterators may independently traverse the + same dictionary. + + Calling setAutoDelete(TRUE) for a dictionary tells it to delete items + that are removed . The default is to not delete items when they are + removed. + + When inserting an item into a dictionary, only the pointer is copied, not + the item itself. This is called a shallow copy. It is possible to make the + dictionary copy all of the item's data (known as a deep copy) when an + item is inserted. insert() calls the virtual function + QCollection::newItem() for the item to be inserted. + Inherit a dictionary and reimplement it if you want deep copies. + + When removing a dictionary item, the virtual function + QCollection::deleteItem() is called. QPtrDict's default implementation + is to delete the item if auto-deletion is enabled. + + \sa QPtrDictIterator, QDict, QAsciiDict, QIntDict, + \link collection.html Collection Classes\endlink +*/ + + +/*! + \fn QPtrDict::QPtrDict( int size ) + Constructs a dictionary using an internal hash array with the size + \e size. + + Setting \e size to a suitably large \link primes.html prime number\endlink + (equal to or greater than the expected number of entries) makes the hash + distribution better and hence the loopup faster. +*/ + +/*! + \fn QPtrDict::QPtrDict( const QPtrDict<type> &dict ) + Constructs a copy of \e dict. + + Each item in \e dict are inserted into this dictionary. + Only the pointers are copied (shallow copy). +*/ + +/*! + \fn QPtrDict::~QPtrDict() + Removes all items from the dictionary and destroys it. + + All iterators that access this dictionary will be reset. + + \sa setAutoDelete() +*/ + +/*! + \fn QPtrDict<type> &QPtrDict::operator=(const QPtrDict<type> &dict) + Assigns \e dict to this dictionary and returns a reference to this + dictionary. + + This dictionary is first cleared, then each item in \e dict is inserted + into this dictionary. + Only the pointers are copied (shallow copy), unless newItem() has been + reimplemented(). +*/ + +/*! + \fn uint QPtrDict::count() const + Returns the number of items in the dictionary. + \sa isEmpty() +*/ + +/*! + \fn uint QPtrDict::size() const + Returns the size of the internal hash array (as specified in the + constructor). + \sa count() +*/ + +/*! + \fn void QPtrDict::resize( uint newsize ) + Changes the size of the hashtable the \a newsize. + The contents of the dictionary are preserved, + but all iterators on the dictionary become invalid. +*/ + +/*! + \fn bool QPtrDict::isEmpty() const + Returns TRUE if the dictionary is empty, i.e. count() == 0. Returns FALSE + otherwise. + \sa count() +*/ + +/*! + \fn void QPtrDict::insert( void *key, const type *item ) + Inserts the \e key with the \e item into the dictionary. + + The key does not have to be a unique dictionary key. If multiple items + are inserted with the same key, only the last item will be visible. + + Null items are not allowed. + + \sa replace() +*/ + +/*! + \fn void QPtrDict::replace( void *key, const type *item ) + Replaces an item which has a key equal to \e key with \e item. + + If the item does not already exist, it will be inserted. + + Null items are not allowed. + + Equivalent to: + \code + QPtrDict<char> dict; + ... + if ( dict.find(key) ) + dict.remove( key ); + dict.insert( key, item ); + \endcode + + If there are two or more items with equal keys, then the last inserted + of these will be replaced. + + \sa insert() +*/ + +/*! + \fn bool QPtrDict::remove( void *key ) + Removes the item associated with \e key from the dictionary. + Returns TRUE if successful, or FALSE if the key does not exist in the + dictionary. + + If there are two or more items with equal keys, then the last inserted + of these will be removed. + + The removed item is deleted if \link QCollection::setAutoDelete() + auto-deletion\endlink is enabled. + + All dictionary iterators that refer to the removed item will be set to + point to the next item in the dictionary traversing order. + + \sa take(), clear(), setAutoDelete() +*/ + +/*! + \fn type *QPtrDict::take( void *key ) + Takes the item associated with \e key out of the dictionary without + deleting it (even if \link QCollection::setAutoDelete() + auto-deletion\endlink is enabled). + + If there are two or more items with equal keys, then the last inserted + of these will be taken. + + Returns a pointer to the item taken out, or null if the key does not + exist in the dictionary. + + All dictionary iterators that refer to the taken item will be set to + point to the next item in the dictionary traversing order. + + \sa remove(), clear(), setAutoDelete() +*/ + +/*! + \fn void QPtrDict::clear() + Removes all items from the dictionary. + + The removed items are deleted if \link QCollection::setAutoDelete() + auto-deletion\endlink is enabled. + + All dictionary iterators that access this dictionary will be reset. + + \sa remove(), take(), setAutoDelete() +*/ + +/*! + \fn type *QPtrDict::find( void *key ) const + Returns the item associated with \e key, or null if the key does not + exist in the dictionary. + + This function uses an internal hashing algorithm to optimize lookup. + + If there are two or more items with equal keys, then the last inserted + of these will be found. + + Equivalent to the [] operator. + + \sa operator[]() +*/ + +/*! + \fn type *QPtrDict::operator[]( void *key ) const + Returns the item associated with \e key, or null if the key does not + exist in the dictionary. + + This function uses an internal hashing algorithm to optimize lookup. + + If there are two or more items with equal keys, then the last inserted + of these will be found. + + Equivalent to the find() function. + + \sa find() +*/ + +/*! + \fn void QPtrDict::statistics() const + Debugging-only function that prints out the dictionary distribution + using qDebug(). +*/ + + +/***************************************************************************** + QPtrDictIterator documentation + *****************************************************************************/ + +/*! + \class QPtrDictIterator qptrdict.h + \brief The QPtrDictIterator class provides an iterator for QPtrDict collections. + + \ingroup collection + \ingroup tools + + QPtrDictIterator is implemented as a template class. + Define a template instance QPtrDictIterator\<X\> to create a + dictionary iterator that operates on QPtrDict\<X\> (dictionary of X*). + + Example: + \code + #include <qptrdict.h> + #include <stdio.h> + + void main() + { + int *a = new int[12]; + int *b = new int[10]; + int *c = new int[18]; + int *d = new int[13]; + + QPtrDict<char> dict; // maps void* -> char* + + dict.insert( a, "a is int[12]" ); // describe pointers + dict.insert( b, "b is int[10]" ); + dict.insert( c, "c is int[18]" ); + + QPtrDictIterator<char> it( dict ); // iterator for dict + + while ( it.current() ) { + printf( "%x -> %s\n", it.currentKey(), it.current() ); + ++it; + } + } + \endcode + + Program output: + \code + 804a788 -> a is int[12] + 804a7f0 -> c is int[18] + 804a7c0 -> b is int[10] + \endcode + + Note that the traversal order is arbitrary, you are not guaranteed the + order above. + + Multiple iterators may independently traverse the same dictionary. + A QPtrDict knows about all iterators that are operating on the dictionary. + When an item is removed from the dictionary, QPtrDict update all + iterators that are referring the removed item to point to the next item + in the traversing order. + + \sa QPtrDict, \link collection.html Collection Classes\endlink +*/ + +/*! + \fn QPtrDictIterator::QPtrDictIterator( const QPtrDict<type> &dict ) + Constructs an iterator for \e dict. The current iterator item is + set to point on the first item in the \e dict. +*/ + +/*! + \fn QPtrDictIterator::~QPtrDictIterator() + Destroys the iterator. +*/ + +/*! + \fn uint QPtrDictIterator::count() const + Returns the number of items in the dictionary this iterator operates on. + \sa isEmpty() +*/ + +/*! + \fn bool QPtrDictIterator::isEmpty() const + Returns TRUE if the dictionary is empty, i.e. count() == 0. Returns FALSE + otherwise. + \sa count() +*/ + +/*! + \fn type *QPtrDictIterator::toFirst() + Sets the current iterator item to point to the first item in the + dictionary and returns a pointer to the item. + If the dictionary is empty it sets the current item to null and + returns null. +*/ + +/*! + \fn QPtrDictIterator::operator type *() const + Cast operator. Returns a pointer to the current iterator item. + Same as current(). +*/ + +/*! + \fn type *QPtrDictIterator::current() const + Returns a pointer to the current iterator item. +*/ + +/*! + \fn void *QPtrDictIterator::currentKey() const + Returns the key for the current iterator item. +*/ + +/*! + \fn type *QPtrDictIterator::operator()() + Makes the succeeding item current and returns the original current item. + + If the current iterator item was the last item in the dictionary or if it + was null, null is returned. +*/ + +/*! + \fn type *QPtrDictIterator::operator++() + Prefix ++ makes the succeeding item current and returns the new current + item. + + If the current iterator item was the last item in the dictionary or if it + was null, null is returned. +*/ + +/*! + \fn type *QPtrDictIterator::operator+=( uint jump ) + Sets the current item to the item \e jump positions after the current item, + and returns a pointer to that item. + + If that item is beyond the last item or if the dictionary is empty, + it sets the current item to null and returns null. +*/ diff --git a/trunk/qtools/qptrdict.h b/trunk/qtools/qptrdict.h new file mode 100644 index 0000000..c075e30 --- /dev/null +++ b/trunk/qtools/qptrdict.h @@ -0,0 +1,103 @@ +/**************************************************************************** +** +** +** Definition of QPtrDict template class +** +** Created : 970415 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QPTRDICT_H +#define QPTRDICT_H + +#ifndef QT_H +#include "qgdict.h" +#endif // QT_H + + +template<class type> class Q_EXPORT QPtrDict : public QGDict +{ +public: + QPtrDict(int size=17) : QGDict(size,PtrKey,0,0) {} + QPtrDict( const QPtrDict<type> &d ) : QGDict(d) {} + ~QPtrDict() { clear(); } + QPtrDict<type> &operator=(const QPtrDict<type> &d) + { return (QPtrDict<type>&)QGDict::operator=(d); } + uint count() const { return QGDict::count(); } + uint size() const { return QGDict::size(); } + bool isEmpty() const { return QGDict::count() == 0; } + void insert( void *k, const type *d ) + { QGDict::look_ptr(k,(Item)d,1); } + void replace( void *k, const type *d ) + { QGDict::look_ptr(k,(Item)d,2); } + bool remove( void *k ) { return QGDict::remove_ptr(k); } + type *take( void *k ) { return (type*)QGDict::take_ptr(k); } + type *find( void *k ) const + { return (type *)((QGDict*)this)->QGDict::look_ptr(k,0,0); } + type *operator[]( void *k ) const + { return (type *)((QGDict*)this)->QGDict::look_ptr(k,0,0); } + void clear() { QGDict::clear(); } + void resize( uint n ) { QGDict::resize(n); } + void statistics() const { QGDict::statistics(); } +private: + void deleteItem( Item d ); +}; + +#if defined(Q_DELETING_VOID_UNDEFINED) +template<> inline void QPtrDict<void>::deleteItem( QCollection::Item ) +{ +} +#endif + +template<class type> inline void QPtrDict<type>::deleteItem( QCollection::Item d ) +{ + if ( del_item ) delete (type *)d; +} + + +template<class type> class Q_EXPORT QPtrDictIterator : public QGDictIterator +{ +public: + QPtrDictIterator(const QPtrDict<type> &d) :QGDictIterator((QGDict &)d) {} + ~QPtrDictIterator() {} + uint count() const { return dict->count(); } + bool isEmpty() const { return dict->count() == 0; } + type *toFirst() { return (type *)QGDictIterator::toFirst(); } + operator type *() const { return (type *)QGDictIterator::get(); } + type *current() const { return (type *)QGDictIterator::get(); } + void *currentKey() const { return QGDictIterator::getKeyPtr(); } + type *operator()() { return (type *)QGDictIterator::operator()(); } + type *operator++() { return (type *)QGDictIterator::operator++(); } + type *operator+=(uint j) { return (type *)QGDictIterator::operator+=(j);} +}; + + +#endif // QPTRDICT_H diff --git a/trunk/qtools/qqueue.h b/trunk/qtools/qqueue.h new file mode 100644 index 0000000..94bc130 --- /dev/null +++ b/trunk/qtools/qqueue.h @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** +** Definition of QQueue template/macro class +** +** Created : 920917 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QQUEUE_H +#define QQUEUE_H + +#ifndef QT_H +#include "qglist.h" +#endif // QT_H + + +template<class type> class QQueue : private QGList +{ +public: + QQueue() {} + QQueue( const QQueue<type> &q ) : QGList(q) {} + ~QQueue() { clear(); } + QQueue<type>& operator=(const QQueue<type> &q) + { return (QQueue<type>&)QGList::operator=(q); } + bool autoDelete() const { return QCollection::autoDelete(); } + void setAutoDelete( bool del ) { QCollection::setAutoDelete(del); } + uint count() const { return QGList::count(); } + bool isEmpty() const { return QGList::count() == 0; } + void enqueue( const type *d ) { QGList::append(Item(d)); } + type *dequeue() { return (type *)QGList::takeFirst();} + bool remove() { return QGList::removeFirst(); } + void clear() { QGList::clear(); } + type *head() const { return (type *)QGList::cfirst(); } + operator type *() const { return (type *)QGList::cfirst(); } + type *current() const { return (type *)QGList::cfirst(); } +private: + void deleteItem( Item d ) { if ( del_item ) delete (type *)d; } +}; + + +#endif // QQUEUE_H diff --git a/trunk/qtools/qregexp.cpp b/trunk/qtools/qregexp.cpp new file mode 100644 index 0000000..b151558 --- /dev/null +++ b/trunk/qtools/qregexp.cpp @@ -0,0 +1,1092 @@ +/**************************************************************************** +** +** +** Implementation of QRegExp class +** +** Created : 950126 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "qregexp.h" +#include <ctype.h> +#include <stdlib.h> + +// NOT REVISED +/*! + \class QRegExp qregexp.h + \ingroup tools + \ingroup misc + \brief The QRegExp class provides pattern matching using regular + expressions or wildcards. + + QRegExp knows these regexp primitives: + <ul plain> + <li><dfn>c</dfn> matches the character 'c' + <li><dfn>.</dfn> matches any character + <li><dfn>^</dfn> matches start of input + <li><dfn>$</dfn> matches end of input + <li><dfn>[]</dfn> matches a defined set of characters - see below. + <li><dfn>a*</dfn> matches a sequence of zero or more a's + <li><dfn>a+</dfn> matches a sequence of one or more a's + <li><dfn>a?</dfn> matches an optional a + <li><dfn>\c</dfn> escape code for matching special characters such + as \, [, *, +, . etc. + <li><dfn>\t</dfn> matches the TAB character (9) + <li><dfn>\n</dfn> matches newline (10) + <li><dfn>\r</dfn> matches return (13) + <li><dfn>\s</dfn> matches a white space (defined as any character + for which QChar::isSpace() returns TRUE. This includes at least + ASCII characters 9 (TAB), 10 (LF), 11 (VT), 12(FF), 13 (CR) and 32 + (Space)). + <li><dfn>\d</dfn> matches a digit (defined as any character for + which QChar::isDigit() returns TRUE. This includes at least ASCII + characters '0'-'9'). + <li><dfn>\x1f6b</dfn> matches the character with unicode point U1f6b + (hexadecimal 1f6b). \x0012 will match the ASCII/Latin1 character + 0x12 (18 decimal, 12 hexadecimal). + <li><dfn>\022</dfn> matches the ASCII/Latin1 character 022 (18 + decimal, 22 octal). + </ul> + + In wildcard mode, it only knows four primitives: + <ul plain> + <li><dfn>c</dfn> matches the character 'c' + <li><dfn>?</dfn> matches any character + <li><dfn>*</dfn> matches any sequence of characters + <li><dfn>[]</dfn> matches a defined set of characters - see below. + </ul> + + QRegExp supports Unicode both in the pattern strings and in the + strings to be matched. + + When writing regular expressions in C++ code, remember that C++ + processes \ characters. So in order to match e.g. a "." character, + you must write "\\." in C++ source, not "\.". + + A character set matches a defined set of characters. For example, + [BSD] matches any of 'B', 'D' and 'S'. Within a character set, the + special characters '.', '*', '?', '^', '$', '+' and '[' lose their + special meanings. The following special characters apply: + <ul plain> + <li><dfn>^</dfn> When placed first in the list, changes the + character set to match any character \e not in the list. To include + the character '^' itself in the set, escape it or place it anywhere + but first. + <li><dfn>-</dfn> Defines a range of characters. To include the + character '-' itself in the set, escape it or place it last. + <li><dfn>]</dfn> Ends the character set definition. To include the + character ']' itself in the set, escape it or place it first (but + after the negation operator '^', if present) + </ul> + Thus, [a-zA-Z0-9.] matches upper and lower case ASCII letters, + digits and dot; and [^\s] matches everything except white space. + + \bug Case insensitive matching is not supported for non-ASCII/Latin1 + (non-8bit) characters. Any character with a non-zero QChar.row() is + matched case sensitively even if the QRegExp is in case insensitive + mode. + + \note In Qt 3.0, the language of regular expressions will contain + five more special characters, namely '(', ')', '{', '|' and '}'. To + ease porting, it's a good idea to escape these characters with a + backslash in all the regular expressions you'll write from now on. +*/ + + +// +// The regexp pattern is internally represented as an array of uints, +// each element containing an 16-bit character or a 32-bit code +// (listed below). User-defined character classes (e.g. [a-zA-Z]) +// are encoded as this: +// uint no: 1 2 3 ... +// value: CCL | n from | to from | to +// +// where n is the (16-bit) number of following range definitions and +// from and to define the ranges inclusive. from <= to is always true, +// otherwise it is a built-in charclass (Pxx, eg \s - PWS). Single +// characters in the class are coded as from==to. Negated classes +// (e.g. [^a-z]) use CCN instead of CCL. + +const uint END = 0x00000000; +const uint PWS = 0x10010000; // predef charclass: whitespace (\s) +const uint PDG = 0x10020000; // predef charclass: digit (\d) +const uint CCL = 0x20010000; // character class [] +const uint CCN = 0x20020000; // neg character class [^] +const uint CHR = 0x40000000; // character +const uint BOL = 0x80010000; // beginning of line ^ +const uint EOL = 0x80020000; // end of line $ +const uint BOW = 0x80030000; // beginning of word \< +const uint EOW = 0x80040000; // end of word \> +const uint ANY = 0x80050000; // any character . +const uint CLO = 0x80070000; // Kleene closure * +const uint OPT = 0x80080000; // Optional closure ? + +const uint MCC = 0x20000000; // character class bitmask +const uint MCD = 0xffff0000; // code mask +const uint MVL = 0x0000ffff; // value mask + +// +// QRegExp::error codes (internal) +// + +const int PatOk = 0; // pattern ok +const int PatNull = 1; // no pattern defined +const int PatSyntax = 2; // pattern syntax error +const int PatOverflow = 4; // pattern too long + + +/***************************************************************************** + QRegExp member functions + *****************************************************************************/ + +/*! + Constructs an empty regular expression. +*/ + +QRegExp::QRegExp() +{ + rxdata = 0; + cs = TRUE; + wc = FALSE; + error = PatOk; +} + +/*! + Constructs a regular expression. + + \arg \e pattern is the regular expression pattern string. + \arg \e caseSensitive specifies whether or not to use case sensitive + matching. + \arg \e wildcard specifies whether the pattern string should be used for + wildcard matching (also called globbing expression), normally used for + matching file names. + + \sa setWildcard() +*/ + +QRegExp::QRegExp( const QCString &pattern, bool caseSensitive, bool wildcard ) +{ + rxstring = pattern; + rxdata = 0; + cs = caseSensitive; + wc = wildcard; + compile(); +} + +/*! + Constructs a regular expression which is a copy of \e r. + \sa operator=(const QRegExp&) +*/ + +QRegExp::QRegExp( const QRegExp &r ) +{ + rxstring = r.pattern(); + rxdata = 0; + cs = r.caseSensitive(); + wc = r.wildcard(); + compile(); +} + +/*! + Destructs the regular expression and cleans up its internal data. +*/ + +QRegExp::~QRegExp() +{ + if ( rxdata ) // Avoid purify complaints + delete [] rxdata; +} + +/*! + Copies the regexp \e r and returns a reference to this regexp. + The case sensitivity and wildcard options are copied, as well. +*/ + +QRegExp &QRegExp::operator=( const QRegExp &r ) +{ + rxstring = r.rxstring; + cs = r.cs; + wc = r.wc; + compile(); + return *this; +} + +/*! + \obsolete + Consider using setPattern() instead of this method. + + Sets the pattern string to \e pattern and returns a reference to this regexp. + The case sensitivity or wildcard options do not change. +*/ + +QRegExp &QRegExp::operator=( const QCString &pattern ) +{ + rxstring = pattern; + compile(); + return *this; +} + + +/*! + Returns TRUE if this regexp is equal to \e r. + + Two regexp objects are equal if they have equal pattern strings, + case sensitivity options and wildcard options. +*/ + +bool QRegExp::operator==( const QRegExp &r ) const +{ + return rxstring == r.rxstring && cs == r.cs && wc == r.wc; +} + +/*! + \fn bool QRegExp::operator!=( const QRegExp &r ) const + + Returns TRUE if this regexp is \e not equal to \e r. + + \sa operator==() +*/ + +/*! + \fn bool QRegExp::isEmpty() const + Returns TRUE if the regexp is empty. +*/ + +/*! + \fn bool QRegExp::isValid() const + Returns TRUE if the regexp is valid, or FALSE if it is invalid. + + The pattern "[a-z" is an example of an invalid pattern, since it lacks a + closing bracket. +*/ + + +/*! + \fn bool QRegExp::wildcard() const + Returns TRUE if wildcard mode is on, otherwise FALSE. \sa setWildcard(). +*/ + +/*! + Sets the wildcard option for the regular expression. The default + is FALSE. + + Setting \e wildcard to TRUE makes it convenient to match filenames + instead of plain text. + + For example, "qr*.cpp" matches the string "qregexp.cpp" in wildcard mode, + but not "qicpp" (which would be matched in normal mode). + + \sa wildcard() +*/ + +void QRegExp::setWildcard( bool wildcard ) +{ + if ( wildcard != wc ) { + wc = wildcard; + compile(); + } +} + +/*! + \fn bool QRegExp::caseSensitive() const + + Returns TRUE if case sensitivity is enabled, otherwise FALSE. The + default is TRUE. + + \sa setCaseSensitive() +*/ + +/*! + Enables or disables case sensitive matching. + + In case sensitive mode, "a.e" matches "axe" but not "Axe". + + See also: caseSensitive() +*/ + +void QRegExp::setCaseSensitive( bool enable ) +{ + if ( cs != enable ) { + cs = enable; + compile(); + } +} + + +/*! + \fn QCString QRegExp::pattern() const + Returns the pattern string of the regexp. +*/ + + +/*! + \fn void QRegExp::setPattern(const QCString & pattern) + Sets the pattern string to \a pattern and returns a reference to this regexp. + The case sensitivity or wildcard options do not change. +*/ + +static inline bool iswordchar( int x ) +{ + return isalnum(x) || x == '_'; //# Only 8-bit support +} + + +/*! + \internal + Match character class +*/ + +static bool matchcharclass( uint *rxd, char c ) +{ + uint *d = rxd; + uint clcode = *d & MCD; + bool neg = clcode == CCN; + if ( clcode != CCL && clcode != CCN) + qWarning("QRegExp: Internal error, please report to qt-bugs@trolltech.com"); + uint numFields = *d & MVL; + uint cval = (uint)c; //(((uint)(c.row())) << 8) | ((uint)c.cell()); + bool found = FALSE; + for ( int i = 0; i < (int)numFields; i++ ) { + d++; + if ( *d == PWS && isspace(c) ) { + found = TRUE; + break; + } + if ( *d == PDG && isdigit(c) ) { + found = TRUE; + break; + } + else { + uint from = ( *d & MCD ) >> 16; + uint to = *d & MVL; + if ( (cval >= from) && (cval <= to) ) { + found = TRUE; + break; + } + } + } + return neg ? !found : found; +} + + + +/* + Internal: Recursively match string. +*/ + +static int matchstring( uint *rxd, const char *str, uint strlength, + const char *bol, bool cs ) +{ + const char *p = str; + const char *start = p; + uint pl = strlength; + uint *d = rxd; + + //### in all cases here: handle pl == 0! (don't read past strlen) + while ( *d ) { + if ( *d & CHR ) { // match char + if ( !pl ) + return -1; + char c = *d; + if ( !cs /*&& !c.row()*/ ) { // case insensitive, #Only 8bit + if ( tolower(*p) != c ) + return -1; + p++; + pl--; + } else { // case insensitive + if ( *p != c ) + return -1; + p++; + pl--; + } + d++; + } + else if ( *d & MCC ) { // match char class + if ( !pl ) + return -1; + if ( !matchcharclass( d, *p ) ) + return -1; + p++; + pl--; + d += (*d & MVL) + 1; + } + else switch ( *d++ ) { + case PWS: // match whitespace + if ( !pl || !isspace(*p) ) + return -1; + p++; + pl--; + break; + case PDG: // match digits + if ( !pl || !isdigit(*p) ) + return -1; + p++; + pl--; + break; + case ANY: // match anything + if ( !pl ) + return -1; + p++; + pl--; + break; + case BOL: // match beginning of line + if ( p != bol ) + return -1; + break; + case EOL: // match end of line + if ( pl ) + return -1; + break; + case BOW: // match beginning of word + if ( !iswordchar(*p) || (p > bol && iswordchar(*(p-1)) ) ) + return -1; + break; + case EOW: // match end of word + if ( iswordchar(*p) || p == bol || !iswordchar(*(p-1)) ) + return -1; + break; + case CLO: // Kleene closure + { + const char *first_p = p; + if ( *d & CHR ) { // match char + char c = *d; + if ( !cs /*&& !c.row()*/ ) { // case insensitive, #only 8bit + while ( pl /*&& !p->row()*/ && tolower(*p)==c ) { + p++; + pl--; + } + } + else { // case sensitive + while ( pl && *p == c ) { + p++; + pl--; + } + } + d++; + } + else if ( *d & MCC ) { // match char class + while( pl && matchcharclass( d, *p ) ) { + p++; + pl--; + } + d += (*d & MVL) + 1; + } + else if ( *d == PWS ) { + while ( pl && isspace(*p) ) { + p++; + pl--; + } + d++; + } + else if ( *d == PDG ) { + while ( pl && isdigit(*p) ) { + p++; + pl--; + } + d++; + } + else if ( *d == ANY ) { + p += pl; + pl = 0; + d++; + } + else { + return -1; // error + } + d++; // skip CLO's END + while ( p >= first_p ) { // go backwards + int end = matchstring( d, p, pl, bol, cs ); + if ( end >= 0 ) + return ( p - start ) + end; + if ( !p ) + return -1; + --p; + ++pl; + } + } + return -1; + case OPT: // optional closure + { + const char *first_p = p; + if ( *d & CHR ) { // match char + char c = *d; + if ( !cs /*&& !c.row()*/ ) { // case insensitive, #only 8bit + if ( pl && /*!p->row() &&*/ tolower(*p) == c ) { + p++; + pl--; + } + } + else { // case sensitive + if ( pl && *p == c ) { + p++; + pl--; + } + } + d++; + } + else if ( *d & MCC ) { // match char class + if ( pl && matchcharclass( d, *p ) ) { + p++; + pl--; + } + d += (*d & MVL) + 1; + } + else if ( *d == PWS ) { + if ( pl && isspace(*p) ) { + p++; + pl--; + } + d++; + } + else if ( *d == PDG ) { + if ( pl && isdigit(*p) ) { + p++; + pl--; + } + d++; + } + else if ( *d == ANY ) { + if ( pl ) { + p++; + pl--; + } + d++; + } + else { + return -1; // error + } + d++; // skip OPT's END + while ( p >= first_p ) { // go backwards + int end = matchstring( d, p, pl, bol, cs ); + if ( end >= 0 ) + return ( p - start ) + end; + if ( !p ) + return -1; + --p; + ++pl; + } + } + return -1; + + default: // error + return -1; + } + } + return p - start; +} + + +/*! + \internal + Recursively match string. +*/ + +// This is obsolete now, but since it is protected (not private), it +// is still implemented on the off-chance that somebody has made a +// class derived from QRegExp and calls this directly. +// Qt 3.0: Remove this? + +#if 0 +const char *QRegExp::matchstr( uint *rxd, const QChar *str, uint strlength, + const QChar *bol ) const +{ + int len = matchstring( rxd, str, strlength, bol, cs ); + if ( len < 0 ) + return 0; + return str + len; +} +#endif + +/*! + Attempts to match in \e str, starting from position \e index. + Returns the position of the match, or -1 if there was no match. + + If \e len is not a null pointer, the length of the match is stored in + \e *len. + + If \e indexIsStart is TRUE (the default), the position \e index in + the string will match the start-of-input primitive (^) in the + regexp, if present. Otherwise, position 0 in \e str will match. + + Example: + \code + QRegExp r("[0-9]*\\.[0-9]+"); // matches floating point + int len; + r.match("pi = 3.1416", 0, &len); // returns 5, len == 6 + \endcode + + \note In Qt 3.0, this function will be replaced by find(). +*/ + +int QRegExp::match( const QCString &str, int index, int *len, + bool indexIsStart ) const +{ + if ( !isValid() || isEmpty() ) + return -1; + if ( str.length() < (uint)index ) + return -1; + const char *start = str.data(); + const char *p = start + index; + uint pl = str.length() - index; + uint *d = rxdata; + int ep = -1; + + if ( *d == BOL ) { // match from beginning of line + ep = matchstring( d, p, pl, indexIsStart ? p : start, cs ); + } else { + if ( *d & CHR ) { + char c = *d; + if ( !cs /*&& !c.row()*/ ) { // case sensitive, # only 8bit + while ( pl && ( /*p->row() ||*/ tolower(*p) != c ) ) { + p++; + pl--; + } + } else { // case insensitive + while ( pl && *p != c ) { + p++; + pl--; + } + } + } + while( 1 ) { // regular match + ep = matchstring( d, p, pl, indexIsStart ? start+index : start, cs ); + if ( ep >= 0 ) + break; + if ( !pl ) + break; + p++; + pl--; + } + } + if ( len ) + *len = ep >= 0 ? ep : 0; // No match -> 0, for historical reasons + return ep >= 0 ? (int)(p - start) : -1; // return index; +} + +/*! \fn int QRegExp::find( const QCString& str, int index ) + + Attempts to match in \e str, starting from position \e index. + Returns the position of the match, or -1 if there was no match. + + \sa match() +*/ + +// +// Translate wildcard pattern to standard regexp pattern. +// Ex: *.cpp ==> ^.*\.cpp$ +// + +static QCString wc2rx( const QCString &pattern ) +{ + int patlen = (int)pattern.length(); + QCString wcpattern("^"); + + char c; + for( int i = 0; i < patlen; i++ ) { + c = pattern[i]; + switch ( (char)c ) { + case '*': // '*' ==> '.*' + wcpattern += '.'; + break; + case '?': // '?' ==> '.' + c = '.'; + break; + case '.': // quote special regexp chars + case '+': + case '\\': + case '$': + case '^': + wcpattern += '\\'; + break; + case '[': + if ( (char)pattern[i+1] == '^' ) { // don't quote '^' after '[' + wcpattern += '['; + c = pattern[i+1]; + i++; + } + break; + } + wcpattern += c; + + } + wcpattern += '$'; + return wcpattern; // return new regexp pattern +} + + +// +// Internal: Get char value and increment pointer. +// + +static uint char_val( const char **str, uint *strlength ) // get char value +{ + const char *p = *str; + uint pl = *strlength; + uint len = 1; + uint v = 0; + if ( (char)*p == '\\' ) { // escaped code + p++; + pl--; + if ( !pl ) { // it is just a '\' + (*str)++; + (*strlength)--; + return '\\'; + } + len++; // length at least 2 + int i; + char c; + char ch = tolower((char)*p); + switch ( ch ) { + case 'b': v = '\b'; break; // bell + case 'f': v = '\f'; break; // form feed + case 'n': v = '\n'; break; // newline + case 'r': v = '\r'; break; // return + case 't': v = '\t'; break; // tab + case 's': v = PWS; break; // whitespace charclass + case 'd': v = PDG; break; // digit charclass + case '<': v = BOW; break; // word beginning matcher + case '>': v = EOW; break; // word ending matcher + + case 'x': { // hex code + p++; + pl--; + for ( i = 0; (i < 4) && pl; i++ ) { //up to 4 hex digits + c = tolower((char)*p); + bool a = ( c >= 'a' && c <= 'f' ); + if ( (c >= '0' && c <= '9') || a ) { + v <<= 4; + v += a ? 10 + c - 'a' : c - '0'; + len++; + } + else { + break; + } + p++; + pl--; + } + } + break; + + default: { + if ( ch >= '0' && ch <= '7' ) { //octal code + len--; + for ( i = 0; (i < 3) && pl; i++ ) { // up to 3 oct digits + c = (char)*p; + if ( c >= '0' && c <= '7' ) { + v <<= 3; + v += c - '0'; + len++; + } + else { + break; + } + p++; + pl--; + } + } + else { // not an octal number + v = (uint)*p; //(((uint)(p->row())) << 8) | ((uint)p->cell()); + } + } + } + } else { + v = (uint)*p; //(((uint)(p->row())) << 8) | ((uint)p->cell()); + } + *str += len; + *strlength -= len; + return v; +} + + +#if defined(DEBUG) +static uint *dump( uint *p ) +{ + while ( *p != END ) { + if ( *p & CHR ) { + uchar uc = (uchar)*p; + char c = (char)uc; + uint u = (uint)uc; //(((uint)(uc.row())) << 8) | ((uint)uc.cell()); + qDebug( "\tCHR\tU%04x (%c)", u, (c ? c : ' ')); + p++; + } + else if ( *p & MCC ) { + uint clcode = *p & MCD; + uint numFields = *p & MVL; + if ( clcode == CCL ) + qDebug( "\tCCL\t%i", numFields ); + else if ( clcode == CCN ) + qDebug( "\tCCN\t%i", numFields ); + else + qDebug("coding error!"); + for ( int i = 0; i < (int)numFields; i++ ) { + p++; + if ( *p == PWS ) + qDebug( "\t\tPWS" ); + else if ( *p == PDG ) + qDebug( "\t\tPDG" ); + else { + uint from = ( *p & MCD ) >> 16; + uint to = *p & MVL; + char fc = (char)from; + char tc = (char)to; + qDebug( "\t\tU%04x (%c) - U%04x (%c)", from, + (fc ? fc : ' '), to, (tc ? tc : ' ') ); + } + } + p++; + } + else switch ( *p++ ) { + case PWS: + qDebug( "\tPWS" ); + break; + case PDG: + qDebug( "\tPDG" ); + break; + case BOL: + qDebug( "\tBOL" ); + break; + case EOL: + qDebug( "\tEOL" ); + break; + case BOW: + qDebug( "\tBOW" ); + break; + case EOW: + qDebug( "\tEOW" ); + break; + case ANY: + qDebug( "\tANY" ); + break; + case CLO: + qDebug( "\tCLO" ); + p = dump( p ); + break; + case OPT: + qDebug( "\tOPT" ); + p = dump( p ); + break; + } + } + qDebug( "\tEND" ); + return p+1; +} +#endif // DEBUG + + +static const int maxlen = 1024; // max length of regexp array +static uint rxarray[ maxlen ]; // tmp regexp array + +/*! + \internal + Compiles the regular expression and stores the result in rxdata. + The 'error' flag is set to non-zero if an error is detected. + NOTE! This function is not reentrant! +*/ + +void QRegExp::compile() +{ + if ( rxdata ) { // delete old data + delete [] rxdata; + rxdata = 0; + } + if ( rxstring.isEmpty() ) { // no regexp pattern set + error = PatNull; + return; + } + + error = PatOk; // assume pattern is ok + + QCString pattern; + if ( wc ) + pattern = wc2rx(rxstring); + else + pattern = rxstring; + const char *start = pattern.data(); // pattern pointer + const char *p = start; // pattern pointer + uint pl = pattern.length(); + uint *d = rxarray; // data pointer + uint *prev_d = 0; + +#define GEN(x) *d++ = (x) + + while ( pl ) { + char ch = (char)*p; + switch ( ch ) { + + case '^': // beginning of line + prev_d = d; + GEN( p == start ? BOL : (CHR | ch) ); + p++; + pl--; + break; + + case '$': // end of line + prev_d = d; + GEN( pl == 1 ? EOL : (CHR | ch) ); + p++; + pl--; + break; + + case '.': // any char + prev_d = d; + GEN( ANY ); + p++; + pl--; + break; + + case '[': // character class + { + prev_d = d; + p++; + pl--; + if ( !pl ) { + error = PatSyntax; + return; + } + bool firstIsEscaped = ( (char)*p == '\\' ); + uint cch = char_val( &p, &pl ); + if ( cch == '^' && !firstIsEscaped ) { // negate! + GEN( CCN ); + if ( !pl ) { + error = PatSyntax; + return; + } + cch = char_val( &p, &pl ); + } else { + GEN( CCL ); + } + uint numFields = 0; + while ( pl ) { + if ((pl>2) && ((char)*p == '-') && ((char)*(p+1) != ']')) { + // Found a range + char_val( &p, &pl ); // Read the '-' + uint cch2 = char_val( &p, &pl ); // Read the range end + if ( cch > cch2 ) { // swap start and stop + int tmp = cch; + cch = cch2; + cch2 = tmp; + } + GEN( (cch << 16) | cch2 ); // from < to + numFields++; + } + else { + // Found a single character + if ( cch & MCD ) // It's a code; will not be mistaken + GEN( cch ); // for a range, since from > to + else + GEN( (cch << 16) | cch ); // from == to range + numFields++; + } + if ( d >= rxarray + maxlen ) { // pattern too long + error = PatOverflow; + return; + } + if ( !pl ) { // At least ']' should be left + error = PatSyntax; + return; + } + bool nextIsEscaped = ( (char)*p == '\\' ); + cch = char_val( &p, &pl ); + if ( cch == (uint)']' && !nextIsEscaped ) + break; + if ( !pl ) { // End, should have seen ']' + error = PatSyntax; + return; + } + } + *prev_d |= numFields; // Store number of fields + } + break; + + case '*': // Kleene closure, or + case '+': // positive closure, or + case '?': // optional closure + { + if ( prev_d == 0 ) { // no previous expression + error = PatSyntax; // empty closure + return; + } + switch ( *prev_d ) { // test if invalid closure + case BOL: + case BOW: + case EOW: + case CLO: + case OPT: + error = PatSyntax; + return; + } + int ddiff = d - prev_d; + if ( *p == '+' ) { // convert to Kleene closure + if ( d + ddiff >= rxarray + maxlen ) { + error = PatOverflow; // pattern too long + return; + } + memcpy( d, prev_d, ddiff*sizeof(uint) ); + d += ddiff; + prev_d += ddiff; + } + memmove( prev_d+1, prev_d, ddiff*sizeof(uint) ); + *prev_d = ch == '?' ? OPT : CLO; + d++; + GEN( END ); + p++; + pl--; + } + break; + + default: + { + prev_d = d; + uint cv = char_val( &p, &pl ); + if ( cv & MCD ) { // It's a code + GEN( cv ); + } + else { + if ( !cs && cv <= 0xff ) // #only 8bit support + cv = tolower( cv ); + GEN( CHR | cv ); + } + } + } + if ( d >= rxarray + maxlen ) { // oops! + error = PatOverflow; // pattern too long + return; + } + } + GEN( END ); + int len = d - rxarray; + rxdata = new uint[ len ]; // copy from rxarray to rxdata + CHECK_PTR( rxdata ); + memcpy( rxdata, rxarray, len*sizeof(uint) ); +#if defined(DEBUG) + //dump( rxdata ); // uncomment this line for debugging +#endif +} diff --git a/trunk/qtools/qregexp.h b/trunk/qtools/qregexp.h new file mode 100644 index 0000000..4bb0230 --- /dev/null +++ b/trunk/qtools/qregexp.h @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** +** Definition of QRegExp class +** +** Created : 950126 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QREGEXP_H +#define QREGEXP_H + +#ifndef QT_H +#include "qcstring.h" +#endif // QT_H + + +class Q_EXPORT QRegExp +{ +public: + QRegExp(); + QRegExp( const QCString &, bool caseSensitive=TRUE, bool wildcard=FALSE ); + QRegExp( const QRegExp & ); + ~QRegExp(); + QRegExp &operator=( const QRegExp & ); + QRegExp &operator=( const QCString &pattern ); + + bool operator==( const QRegExp & ) const; + bool operator!=( const QRegExp &r ) const + { return !(this->operator==(r)); } + + bool isEmpty() const { return rxdata == 0; } + bool isValid() const { return error == 0; } + + bool caseSensitive() const { return cs; } + void setCaseSensitive( bool ); + + bool wildcard() const { return wc; } + void setWildcard( bool ); + + QCString pattern() const { return rxstring; } + // ### in Qt 3.0, provide a real implementation + void setPattern( const QCString& pattern ) + { operator=( pattern ); } + + int match( const QCString &str, int index=0, int *len=0, + bool indexIsStart = TRUE ) const; + int find( const QCString& str, int index ) + { return match( str, index ); } + +protected: + void compile(); + const char *matchstr( uint *, const char *, uint, const char * ) const; + +private: + QCString rxstring; // regular expression pattern + uint *rxdata; // compiled regexp pattern + int error; // error status + bool cs; // case sensitive + bool wc; // wildcard +}; + + +#endif // QREGEXP_H diff --git a/trunk/qtools/qshared.h b/trunk/qtools/qshared.h new file mode 100644 index 0000000..79fab7b --- /dev/null +++ b/trunk/qtools/qshared.h @@ -0,0 +1,55 @@ +/**************************************************************************** +** +** +** Definition of QShared struct +** +** Created : 940112 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QSHARED_H +#define QSHARED_H + +#ifndef QT_H +#include "qglobal.h" +#endif // QT_H + + +struct QShared +{ + QShared() { count = 1; } + void ref() { count++; } + bool deref() { return !--count; } + uint count; +}; + + +#endif // QSHARED_H diff --git a/trunk/qtools/qsortedlist.doc b/trunk/qtools/qsortedlist.doc new file mode 100644 index 0000000..6f16f19 --- /dev/null +++ b/trunk/qtools/qsortedlist.doc @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** +** QSortedList documentation +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + + +/***************************************************************************** + QSortedList documentation + *****************************************************************************/ + +/*! + \class QSortedList qsortedlist.h + \brief The QSortedList class provides a list sorted by operator< and operator== + + \ingroup collection + \ingroup tools + + If you want to sort a QList you have to reimplement the + QGList::compareItems() method. If the elements of your list support + operator<() and operator==() then you can use QSortedList instead. + Its compareItems() calls operator<() and operator==() and returns an + appropriate result. + + Otherwise, this is as QList. + + \sa QList, \link collection.html Collection Classes\endlink +*/ + + +/*! + \fn QSortedList::QSortedList() + Constructs an empty list. +*/ + +/*! + \fn QSortedList::QSortedList( const QSortedList<type> &list ) + Constructs a copy of \e list. + + Each item in \e list is copied to this new list. +*/ + +/*! + \fn QSortedList::~QSortedList() + Removes all items from the list and destroys the list. + + All list iterators that access this list will be reset. +*/ + +/*! + \fn QSortedList<type>& QSortedList::operator=(const QSortedList<type>& list) + Assigns \e list to this list and returns a reference to this list. + + This list is first cleared, then each item in \e list is + appended to this list. Only the pointers are copied + (shallow copy), unless newItem() has been reimplemented(). +*/ + +/*! + \fn int QSortedList::compareItems( QCollection::Item s1, QCollection::Item s2 ) + + \reimp + + This reimplementation uses operator< and operator== to compare. +*/ diff --git a/trunk/qtools/qsortedlist.h b/trunk/qtools/qsortedlist.h new file mode 100644 index 0000000..aeadd90 --- /dev/null +++ b/trunk/qtools/qsortedlist.h @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** +** Definition of QList template/macro class +** +** Created : 920701 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QSORTEDLIST_H +#define QSORTEDLIST_H + +#ifndef QT_H +#include "qlist.h" +#endif // QT_H + + +template<class type> class Q_EXPORT QSortedList : public QList<type> +{ +public: + QSortedList() {} + QSortedList( const QSortedList<type> &l ) : QList<type>(l) {} + ~QSortedList() { clear(); } + QSortedList<type> &operator=(const QSortedList<type> &l) + { return (QSortedList<type>&)QList<type>::operator=(l); } + + virtual int compareItems( QCollection::Item s1, QCollection::Item s2 ) + { if ( *((type*)s1) == *((type*)s2) ) return 0; return ( *((type*)s1) < *((type*)s2) ? -1 : 1 ); } +}; + +#endif diff --git a/trunk/qtools/qstack.doc b/trunk/qtools/qstack.doc new file mode 100644 index 0000000..ece1e2a --- /dev/null +++ b/trunk/qtools/qstack.doc @@ -0,0 +1,135 @@ +/**************************************************************************** +** +** +** QStack class documentation +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + + +/***************************************************************************** + QStack documentation + *****************************************************************************/ + +/*! + \class QStack qstack.h + \brief The QStack class is a template class that provides a stack. + + \ingroup collection + \ingroup tools + + QStack is implemented as a template class. Define a template + instance QStack\<X\> to create a stack that operates on pointers to + X, or X*. + + A stack is a Last In, First Out (LIFO) structure. Items are added to + the top of the stack with push() and retrieved from the top + with pop(). + + \sa \link collection.html Collection Classes\endlink +*/ + +/*! \fn QStack::QStack () + Creates and empty stack. +*/ + +/*! \fn QStack::QStack (const QStack<type>& s) + Creates a stack by making a shallow copy of another stack. +*/ + +/*! \fn QStack::~QStack () + Destroys the stack. All items will be deleted if autoDelete() is TRUE. +*/ + +/*! \fn QStack<type>& QStack::operator= (const QStack<type>& s) + Sets the contents of this stack by making a shallow copy of another stack. + Elements currently in this stack will be deleted if autoDelete() is TRUE. +*/ + +/*! \fn bool QStack::isEmpty () const + Returns TRUE is the stack contains no elements to be \link pop() popped\endlink. +*/ + +/*! \fn void QStack::push (const type* d) + Adds an element to the top of the stack. Last in, first out. +*/ + +/*! \fn type* QStack::pop () + Removes the top item from the stack and returns it. +*/ + +/*! \fn bool QStack::remove () + Removes the top item from the stack and deletes it if + autoDelete() is TRUE. Returns TRUE if there was an item to pop. + + \sa clear() +*/ + +/*! \fn void QStack::clear() + Removes all items from the stack, deleting them if + autoDelete() is TRUE. + + \sa remove() +*/ + +/*! \fn uint QStack::count() const + Returns the number of items in the stack. + + \sa isEmpty() +*/ + +/*! \fn type* QStack::top () const + Returns a reference to the top item on the stack (most recently pushed). + The stack is not changed. +*/ + +/*! \fn QStack::operator type* ()const + Returns a reference to the top item on the stack (most recently pushed). + The stack is not changed. +*/ + +/*! \fn type* QStack::current () const + Returns a reference to the top item on the stack (most recently pushed). + The stack is not changed. +*/ + +/*! \fn bool QStack::autoDelete() const + + The same as QCollection::autoDelete(). + + \sa setAutoDelete() +*/ + +/*! \fn void QStack::setAutoDelete( bool enable ) + + The same as QCollection::setAutoDelete(). + + \sa autoDelete() +*/ diff --git a/trunk/qtools/qstack.h b/trunk/qtools/qstack.h new file mode 100644 index 0000000..c84d8d2 --- /dev/null +++ b/trunk/qtools/qstack.h @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** +** Definition of QStack template/macro class +** +** Created : 920917 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QSTACK_H +#define QSTACK_H + +#ifndef QT_H +#include "qglist.h" +#endif // QT_H + + +template<class type> class QStack : private QGList +{ +public: + QStack() {} + QStack( const QStack<type> &s ) : QGList(s) {} + ~QStack() { clear(); } + QStack<type> &operator=(const QStack<type> &s) + { return (QStack<type>&)QGList::operator=(s); } + bool autoDelete() const { return QCollection::autoDelete(); } + void setAutoDelete( bool del ) { QCollection::setAutoDelete(del); } + uint count() const { return QGList::count(); } + bool isEmpty() const { return QGList::count() == 0; } + void push( const type *d ) { QGList::insertAt(0,Item(d)); } + type *pop() { return (type *)QGList::takeFirst(); } + bool remove() { return QGList::removeFirst(); } + void clear() { QGList::clear(); } + type *bottom() const { return (type *)QGList::clast(); } + type *top() const { return (type *)QGList::cfirst(); } + operator type *() const { return (type *)QGList::cfirst(); } + type *current() const { return (type *)QGList::cfirst(); } +private: + void deleteItem( Item d ) { if ( del_item ) delete (type *)d; } +}; + + +#endif // QSTACK_H diff --git a/trunk/qtools/qstring.cpp b/trunk/qtools/qstring.cpp new file mode 100644 index 0000000..bc3dfc7 --- /dev/null +++ b/trunk/qtools/qstring.cpp @@ -0,0 +1,15318 @@ +/**************************************************************************** +** +** +** Implementation of the QString class and related Unicode functions +** +** Created : 920722 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +// Don't define it while compiling this module, or USERS of Qt will +// not be able to link. +#ifdef QT_NO_CAST_ASCII +#undef QT_NO_CAST_ASCII +#endif + +#include "qstring.h" +#include "qregexp.h" +#include "qdatastream.h" +#include "qtextcodec.h" +#include "qstack.h" +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <ctype.h> +#include <limits.h> + + +/* ------------------------------------------------------------------------- + * unicode information + * these tables are generated from the unicode reference file + * ftp://ftp.unicode.org/Public/3.0-Update/UnicodeData-3.0.0.html + * + * Lars Knoll <knoll@mpi-hd.mpg.de> + * ------------------------------------------------------------------------- + */ + +/* Perl script to generate (run perl -x tools/qstring.cpp) + +#!perl + +sub numberize +{ + my(%r, $n, $id); + for $id ( @_ ) { + $id="" if $id eq "EMPTY"; + $r{$id}=$n++; + } + return %r; +} + + +# Code to integer mappings... +# +%category_code = numberize(qw{ + EMPTY + Mn Mc Me + Nd Nl No + Zs Zl Zp + Cc Cf Cs Co Cn + + Lu Ll Lt Lm Lo + Pc Pd Ps Pe Pi Pf Po + Sm Sc Sk So +}); +%bidi_category_code = numberize(qw{ + L R EN ES ET AN CS B S WS ON LRE LRO AL RLE RLO PDF NSM BN}); +%character_decomposition_tag = numberize(qw{ + <single> <canonical> <font> <noBreak> <initial> <medial> + <final> <isolated> <circle> <super> <sub> <vertical> + <wide> <narrow> <small> <square> <compat> <fraction> +}); +%mirrored_code = numberize(qw{N Y}); + +%joining_code = numberize(qw{U D R C}); + +# Read data into hashes... +# +open IN, "UnicodeData.txt"; +$position = 1; +while (<IN>) { + @fields = split /;/; + $code = shift @fields; + for $n (qw{ + name category combining_class bidi_category + character_decomposition decimal_digit_value digit_value + numeric_value mirrored oldname comment + uppercase lowercase titlecase}) + { + $id = shift @fields; + $codes = "${n}_code"; + if ( defined %$codes && defined $$codes{$id} ) { + $id = $$codes{$id}; + } + ${$n}{$code}=$id; + } + $decomp = $character_decomposition{$code}; + if ( length $decomp == 0 ) { + $decomp = "<single>"; + } + if (substr($decomp, 0, 1) ne '<') { + $decomp = "<canonical> " . $decomp; + } + @fields = split(" ", $decomp); + $tag = shift @fields; + $tag = $character_decomposition_tag{$tag}; + $decomp = join( ", 0x", @fields ); + $decomp = "0x".$decomp; + $decomposition{$code} = $decomp; + $decomposition_tag{$code} = $tag; + $decomposition_pos{$code} = $position; + $len = scalar(@fields); + $decomposition_len{$code} = $len; + +# we use canonical decompositions longer than 1 char +# and all arabic ligatures for the ligature table + if(($len > 1 and $tag == 1) or ($tag > 3 and $tag < 8)) { +# ligature to add... + $start = shift @fields; + $ligature{$start} = $ligature{$start}." ".$code; + } + +# adjust position + if($len != 0) { + $position += $len + 3; + } + + +} + +open IN2, "ArabicShaping.txt"; +$position = 1; +while (<IN2>) { + @fields = split /;/; + $code = shift @fields; + $dummy = shift @fields; + $join = shift @fields; + $join =~ s/ //g; + $join = $joining_code{$join}; + $joining{$code}=$join; +} + +# Build pages... +# +$rowtable_txt = + "static const Q_UINT8 * const unicode_info[256] = {"; +for $row ( 0..255 ) { + $nonzero=0; + $txt = ""; + for $cell ( 0..255 ) { + $code = sprintf("%02X%02X",$row,$cell); + $info = $category{$code}; + $info = 0 if !defined $info; + $txt .= "\n " if $cell%8 == 0; + $txt .= "$info, "; + } + $therow = $row{$txt}; + if ( !defined $therow ) { + $size+=256; + $therow = "ui_".sprintf("%02X",$row); + $rowtext{$therow} = + "static const Q_UINT8 ${therow}[] = {$txt\n};\n\n"; + $row{$txt}=$therow; + } + $rowtable_txt .= "\n " if $row%8 == 0; + $rowtable_txt .= "$therow, "; +} + +print "// START OF GENERATED DATA\n\n"; +print "#ifndef QT_NO_UNICODETABLES\n\n"; + +# Print pages... +# +for $r ( sort keys %rowtext ) { + print $rowtext{$r}; +} +print "$rowtable_txt\n};\n"; +$size += 256*4; +print "// $size bytes\n\n"; + +# Build decomposition tables +# +$rowtable_txt = + "static const Q_UINT16 * const decomposition_info[256] = {"; +$table_txt = + "static const Q_UINT16 decomposition_map[] = {\n 0,\n"; +for $row ( 0..255 ) { + $nonzero=0; + $txt = ""; + for $cell ( 0..255 ) { + $code = sprintf("%02X%02X",$row,$cell); + $txt .= "\n " if $cell%8 == 0; + if( $decomposition_tag{$code} != 0 ) { + $txt .= " $decomposition_pos{$code},"; + $table_txt .= " $decomposition_tag{$code},"; + $table_txt .= " 0x$code,"; + $table_txt .= " $decomposition{$code}, 0,\n"; + $size += 2 * $decomposition_len{$code} + 6; + } else { + $txt .= " 0,"; + } + } + $therow = $row{$txt}; + if ( !defined $therow ) { + $size+=512; + $therow = "di_".sprintf("%02X",$row); + $dec_rowtext{$therow} = + "static const Q_UINT16 ${therow}[] = {$txt\n};\n\n"; + $row{$txt}=$therow; + } + $rowtable_txt .= "\n " if $row%8 == 0; + $rowtable_txt .= "$therow, "; +} + +# Print decomposition tables +# +print "$table_txt\n};\n\n"; +for $r ( sort keys %dec_rowtext ) { + print $dec_rowtext{$r}; +} +print "$rowtable_txt\n};\n"; +$size += 256*4; +print "// $size bytes\n\n"; + + +# build ligature tables +# +$size = 0; +$position = 1; +$rowtable_txt = + "static const Q_UINT16 * const ligature_info[256] = {"; +$table_txt = + "static const Q_UINT16 ligature_map[] = {\n 0,\n"; +for $lig_row ( 0..255 ) { + $nonzero=0; + $txt = ""; + for $cell ( 0..255 ) { + $code = sprintf("%02X%02X",$lig_row,$cell); + $txt .= "\n " if $cell%8 == 0; + if( defined $ligature{$code} ) { + $txt .= " $position,"; + @ligature = split(" ", $ligature{$code}); +# we need to sort ligatures according to their length. +# long ones have to come first! + @ligature_sort = sort { $decomposition_len{$b} <=> $decomposition_len{$a} } @ligature; +# now replace each code by it's position in +# the decomposition map. + undef(@lig_pos); + for $n (@ligature_sort) { + push(@lig_pos, $decomposition_pos{$n}); + } +# debug info + if( 0 ) { + print "ligatures: $ligature{$code}\n"; + $sort = join(" ", @ligature_sort); + print "sorted : $sort\n"; + } + $lig = join(", ", @lig_pos); + $table_txt .= " $lig, 0,\n"; + $size += 2 * scalar(@ligature) + 2; + $position += scalar(@ligature) + 1; + } else { + $txt .= " 0,"; + } + } + $therow = $lig_row{$txt}; + if ( !defined $therow ) { + $size+=512; + $therow = "li_".sprintf("%02X",$lig_row); + $lig_rowtext{$therow} = + "static const Q_UINT16 ${therow}[] = {$txt\n};\n\n"; + $lig_row{$txt}=$therow; + } + $rowtable_txt .= "\n " if $lig_row%8 == 0; + $rowtable_txt .= "$therow, "; +} + +# Print ligature tables +# +print "$table_txt\n};\n\n"; +for $r ( sort keys %lig_rowtext ) { + print $lig_rowtext{$r}; +} +print "$rowtable_txt\n};\n"; +$size += 256*4; +print "// $size bytes\n\n"; + + + +# Build direction/joining/mirrored pages... +# +$rowtable_txt = + "static const Q_UINT8 * const direction_info[256] = {"; +for $dir_row ( 0..255 ) { + $nonzero=0; + $txt = ""; + for $cell ( 0..255 ) { + $code = sprintf("%02X%02X",$dir_row,$cell); + $dir = $bidi_category{$code}; + $dir = 0 if !defined $dir; + $join = $joining{$code}; + $join = 0 if !defined $join; + $mirr = $mirrored{$code}; + $mirr = 0 if !defined $mirr; + $info = $dir + 32*$join + 128*$mirr; + $txt .= "\n " if $cell%8 == 0; + $txt .= "$info, "; + } + $therow = $dir_row{$txt}; + if ( !defined $therow ) { + $size+=256; + $therow = "dir_".sprintf("%02X",$dir_row); + $dir_rowtext{$therow} = + "static const Q_UINT8 ${therow}[] = {$txt\n};\n\n"; + $dir_row{$txt}=$therow; + } + $rowtable_txt .= "\n " if $dir_row%8 == 0; + $rowtable_txt .= "$therow, "; +} + +# Print pages... +# +for $r ( sort keys %dir_rowtext ) { + print $dir_rowtext{$r}; +} +print "$rowtable_txt\n};\n"; +$size += 256*4; +print "// $size bytes\n\n"; + + + +print "#endif\n\n"; +print "// END OF GENERATED DATA\n\n"; + + +__END__ + +*/ + + +// START OF GENERATED DATA + +static const Q_UINT8 ui_00[] = { + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 7, 26, 26, 26, 28, 26, 26, 26, + 22, 23, 26, 27, 26, 21, 26, 26, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 26, 26, 27, 27, 27, 26, + 26, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 22, 26, 23, 29, 20, + 29, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 22, 27, 23, 27, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 7, 26, 28, 28, 28, 28, 30, 30, + 29, 30, 16, 24, 27, 21, 30, 29, + 30, 27, 6, 6, 29, 16, 30, 26, + 29, 6, 16, 25, 6, 6, 6, 26, + 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 27, + 15, 15, 15, 15, 15, 15, 15, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 27, + 16, 16, 16, 16, 16, 16, 16, 16, +}; + +#ifndef QT_NO_UNICODETABLES + +static const Q_UINT8 ui_01[] = { + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 16, 15, 16, 15, 16, 15, 16, 15, + 16, 15, 16, 15, 16, 15, 16, 15, + 16, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 15, 16, 15, 16, 15, 16, 16, + 16, 15, 15, 16, 15, 16, 15, 15, + 16, 15, 15, 15, 16, 16, 15, 15, + 15, 15, 16, 15, 15, 16, 15, 15, + 15, 16, 16, 16, 15, 15, 16, 15, + 15, 16, 15, 16, 15, 16, 15, 15, + 16, 15, 16, 16, 15, 16, 15, 15, + 16, 15, 15, 15, 16, 15, 16, 15, + 15, 16, 16, 19, 15, 16, 16, 16, + 19, 19, 19, 19, 15, 17, 16, 15, + 17, 16, 15, 17, 16, 15, 16, 15, + 16, 15, 16, 15, 16, 15, 16, 15, + 16, 15, 16, 15, 16, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 16, 15, 17, 16, 15, 16, 15, 15, + 15, 16, 15, 16, 15, 16, 15, 16, +}; + +static const Q_UINT8 ui_02[] = { + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 0, 0, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 0, 0, + 18, 18, 18, 18, 18, 18, 18, 18, + 18, 29, 29, 18, 18, 18, 18, 18, + 18, 18, 29, 29, 29, 29, 29, 29, + 29, 29, 29, 29, 29, 29, 29, 29, + 18, 18, 29, 29, 29, 29, 29, 29, + 29, 29, 29, 29, 29, 29, 29, 29, + 18, 18, 18, 18, 18, 29, 29, 29, + 29, 29, 29, 29, 29, 29, 18, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 ui_03[] = { + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 29, 29, 0, 0, + 0, 0, 18, 0, 0, 0, 26, 0, + 0, 0, 0, 0, 29, 29, 15, 26, + 15, 15, 15, 0, 15, 0, 15, 15, + 16, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 0, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 0, + 16, 16, 15, 15, 15, 16, 16, 16, + 0, 0, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 16, 16, 16, 16, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 ui_04[] = { + 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 30, 1, 1, 1, 1, 0, + 3, 3, 0, 0, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 15, 16, 15, 16, 0, 0, 15, + 16, 0, 0, 15, 16, 0, 0, 0, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 0, 0, + 15, 16, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 ui_05[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 0, + 0, 18, 26, 26, 26, 26, 26, 26, + 0, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 0, 26, 21, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 0, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 0, 1, 1, 1, 26, 1, + 26, 1, 1, 26, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 0, 0, 0, 0, 0, + 19, 19, 19, 26, 26, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 ui_06[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 26, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 26, 0, 0, 0, 26, + 0, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 0, 0, 0, 0, 0, + 18, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 26, 26, 26, 26, 0, 0, + 1, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 26, 19, 1, 1, + 1, 1, 1, 1, 1, 3, 3, 1, + 1, 1, 1, 1, 1, 18, 18, 1, + 1, 30, 1, 1, 1, 1, 0, 0, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 19, 19, 19, 30, 30, 0, +}; + +static const Q_UINT8 ui_07[] = { + 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 0, 11, + 19, 1, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 ui_08[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 ui_09[] = { + 0, 1, 1, 2, 0, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 0, 0, 1, 19, 2, 2, + 2, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 2, 2, 2, 1, 0, 0, + 19, 1, 1, 1, 1, 0, 0, 0, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 1, 1, 26, 26, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 26, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 2, 2, 0, 19, 19, 19, + 19, 19, 19, 19, 19, 0, 0, 19, + 19, 0, 0, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 0, 19, 19, 19, 19, 19, 19, + 19, 0, 19, 0, 0, 0, 19, 19, + 19, 19, 0, 0, 1, 0, 2, 2, + 2, 1, 1, 1, 1, 0, 0, 2, + 2, 0, 0, 2, 2, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 2, + 0, 0, 0, 0, 19, 19, 0, 19, + 19, 19, 1, 1, 0, 0, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 19, 19, 28, 28, 6, 6, 6, 6, + 6, 6, 30, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 ui_0A[] = { + 0, 0, 1, 0, 0, 19, 19, 19, + 19, 19, 19, 0, 0, 0, 0, 19, + 19, 0, 0, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 0, 19, 19, 19, 19, 19, 19, + 19, 0, 19, 19, 0, 19, 19, 0, + 19, 19, 0, 0, 1, 0, 2, 2, + 2, 1, 1, 0, 0, 0, 0, 1, + 1, 0, 0, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 19, 19, 19, 19, 0, 19, 0, + 0, 0, 0, 0, 0, 0, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 1, 1, 19, 19, 19, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 1, 2, 0, 19, 19, 19, + 19, 19, 19, 19, 0, 19, 0, 19, + 19, 19, 0, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 0, 19, 19, 19, 19, 19, 19, + 19, 0, 19, 19, 0, 19, 19, 19, + 19, 19, 0, 0, 1, 19, 2, 2, + 2, 1, 1, 1, 1, 1, 0, 1, + 1, 2, 0, 2, 2, 1, 0, 0, + 19, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 19, 0, 0, 0, 0, 0, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 ui_0B[] = { + 0, 1, 2, 2, 0, 19, 19, 19, + 19, 19, 19, 19, 19, 0, 0, 19, + 19, 0, 0, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 0, 19, 19, 19, 19, 19, 19, + 19, 0, 19, 19, 0, 0, 19, 19, + 19, 19, 0, 0, 1, 19, 2, 1, + 2, 1, 1, 1, 0, 0, 0, 2, + 2, 0, 0, 2, 2, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 2, + 0, 0, 0, 0, 19, 19, 0, 19, + 19, 19, 0, 0, 0, 0, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 30, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 2, 0, 19, 19, 19, + 19, 19, 19, 0, 0, 0, 19, 19, + 19, 0, 19, 19, 19, 19, 0, 0, + 0, 19, 19, 0, 19, 0, 19, 19, + 0, 0, 0, 19, 19, 0, 0, 0, + 19, 19, 19, 0, 0, 0, 19, 19, + 19, 19, 19, 19, 19, 19, 0, 19, + 19, 19, 0, 0, 0, 0, 2, 2, + 1, 2, 2, 0, 0, 0, 2, 2, + 2, 0, 2, 2, 2, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 2, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 6, 6, 6, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 ui_0C[] = { + 0, 2, 2, 2, 0, 19, 19, 19, + 19, 19, 19, 19, 19, 0, 19, 19, + 19, 0, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 0, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 0, 19, 19, 19, + 19, 19, 0, 0, 0, 0, 1, 1, + 1, 2, 2, 2, 2, 0, 1, 1, + 1, 0, 1, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 1, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 19, 19, 0, 0, 0, 0, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 2, 2, 0, 19, 19, 19, + 19, 19, 19, 19, 19, 0, 19, 19, + 19, 0, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 0, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 0, 19, 19, 19, + 19, 19, 0, 0, 0, 0, 2, 1, + 2, 2, 2, 2, 2, 0, 1, 2, + 2, 0, 2, 2, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 2, 2, 0, + 0, 0, 0, 0, 0, 0, 19, 0, + 19, 19, 0, 0, 0, 0, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 ui_0D[] = { + 0, 0, 2, 2, 0, 19, 19, 19, + 19, 19, 19, 19, 19, 0, 19, 19, + 19, 0, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 0, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 0, 0, 0, 0, 2, 2, + 2, 1, 1, 1, 0, 0, 2, 2, + 2, 0, 2, 2, 2, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 2, + 0, 0, 0, 0, 0, 0, 0, 0, + 19, 19, 0, 0, 0, 0, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 2, 2, 0, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 0, + 0, 0, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 0, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 0, 19, 0, 0, + 19, 19, 19, 19, 19, 19, 19, 0, + 0, 0, 1, 0, 0, 0, 0, 2, + 2, 2, 1, 1, 1, 0, 1, 0, + 2, 2, 2, 2, 2, 2, 2, 2, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 2, 2, 26, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 ui_0E[] = { + 0, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 1, 19, 19, 1, 1, 1, 1, + 1, 1, 1, 0, 0, 0, 0, 28, + 19, 19, 19, 19, 19, 19, 18, 1, + 1, 1, 1, 1, 1, 1, 1, 26, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 26, 26, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 19, 19, 0, 19, 0, 0, 19, + 19, 0, 19, 0, 0, 19, 0, 0, + 0, 0, 0, 0, 19, 19, 19, 19, + 0, 19, 19, 19, 19, 19, 19, 19, + 0, 19, 19, 19, 0, 19, 0, 19, + 0, 0, 19, 19, 0, 19, 19, 19, + 19, 1, 19, 19, 1, 1, 1, 1, + 1, 1, 0, 1, 1, 19, 0, 0, + 19, 19, 19, 19, 19, 0, 18, 0, + 1, 1, 1, 1, 1, 1, 0, 0, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 0, 0, 19, 19, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 ui_0F[] = { + 19, 30, 30, 30, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 30, 30, 30, 30, 30, + 1, 1, 30, 30, 30, 30, 30, 30, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 30, 1, 30, 1, + 30, 1, 22, 23, 22, 23, 2, 2, + 19, 19, 19, 19, 19, 19, 19, 19, + 0, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 2, + 1, 1, 1, 1, 1, 26, 1, 1, + 19, 19, 19, 19, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, + 0, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 0, 30, 30, + 30, 30, 30, 30, 30, 30, 1, 30, + 30, 30, 30, 30, 30, 0, 0, 30, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 ui_10[] = { + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 0, 19, 19, 19, 19, 19, + 0, 19, 19, 0, 2, 1, 1, 1, + 1, 2, 1, 0, 0, 0, 1, 1, + 2, 1, 0, 0, 0, 0, 0, 0, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 26, 26, 26, 26, 26, 26, + 19, 19, 19, 19, 19, 19, 2, 2, + 1, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 0, + 0, 0, 0, 26, 0, 0, 0, 0, +}; + +static const Q_UINT8 ui_11[] = { + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 0, 0, 0, 0, 0, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 0, 0, 0, 0, 0, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 ui_12[] = { + 19, 19, 19, 19, 19, 19, 19, 0, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 0, + 19, 0, 19, 19, 19, 19, 0, 0, + 19, 19, 19, 19, 19, 19, 19, 0, + 19, 0, 19, 19, 19, 19, 0, 0, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 0, + 19, 0, 19, 19, 19, 19, 0, 0, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 0, + 19, 0, 19, 19, 19, 19, 0, 0, + 19, 19, 19, 19, 19, 19, 19, 0, + 19, 0, 19, 19, 19, 19, 0, 0, + 19, 19, 19, 19, 19, 19, 19, 0, + 19, 19, 19, 19, 19, 19, 19, 0, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 0, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, +}; + +static const Q_UINT8 ui_13[] = { + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 0, + 19, 0, 19, 19, 19, 19, 0, 0, + 19, 19, 19, 19, 19, 19, 19, 0, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 0, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 0, 0, 0, 0, 0, + 0, 26, 26, 26, 26, 26, 26, 26, + 26, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 ui_14[] = { + 0, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, +}; + +static const Q_UINT8 ui_15[] = { + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, +}; + +static const Q_UINT8 ui_16[] = { + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 26, 26, 19, + 19, 19, 19, 19, 19, 19, 19, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 7, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 22, 23, 0, 0, 0, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 26, 26, 26, 6, 6, + 6, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 ui_17[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 2, 2, 2, 1, + 1, 1, 1, 1, 1, 1, 2, 2, + 2, 2, 2, 2, 2, 2, 1, 2, + 2, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 26, 26, 26, 26, + 26, 26, 26, 28, 26, 0, 0, 0, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 ui_18[] = { + 26, 26, 26, 26, 26, 26, 21, 26, + 26, 26, 26, 11, 11, 11, 11, 0, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 0, 0, 0, 0, 0, 0, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 18, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 0, 0, 0, 0, 0, 0, 0, 0, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 ui_1E[] = { + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 16, 16, + 16, 16, 16, 16, 0, 0, 0, 0, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 ui_1F[] = { + 16, 16, 16, 16, 16, 16, 16, 16, + 15, 15, 15, 15, 15, 15, 15, 15, + 16, 16, 16, 16, 16, 16, 0, 0, + 15, 15, 15, 15, 15, 15, 0, 0, + 16, 16, 16, 16, 16, 16, 16, 16, + 15, 15, 15, 15, 15, 15, 15, 15, + 16, 16, 16, 16, 16, 16, 16, 16, + 15, 15, 15, 15, 15, 15, 15, 15, + 16, 16, 16, 16, 16, 16, 0, 0, + 15, 15, 15, 15, 15, 15, 0, 0, + 16, 16, 16, 16, 16, 16, 16, 16, + 0, 15, 0, 15, 0, 15, 0, 15, + 16, 16, 16, 16, 16, 16, 16, 16, + 15, 15, 15, 15, 15, 15, 15, 15, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 0, 0, + 16, 16, 16, 16, 16, 16, 16, 16, + 17, 17, 17, 17, 17, 17, 17, 17, + 16, 16, 16, 16, 16, 16, 16, 16, + 17, 17, 17, 17, 17, 17, 17, 17, + 16, 16, 16, 16, 16, 16, 16, 16, + 17, 17, 17, 17, 17, 17, 17, 17, + 16, 16, 16, 16, 16, 0, 16, 16, + 15, 15, 15, 15, 17, 29, 16, 29, + 29, 29, 16, 16, 16, 0, 16, 16, + 15, 15, 15, 15, 17, 29, 29, 29, + 16, 16, 16, 16, 0, 0, 16, 16, + 15, 15, 15, 15, 0, 29, 29, 29, + 16, 16, 16, 16, 16, 16, 16, 16, + 15, 15, 15, 15, 15, 29, 29, 29, + 0, 0, 16, 16, 16, 0, 16, 16, + 15, 15, 15, 15, 17, 29, 29, 0, +}; + +static const Q_UINT8 ui_20[] = { + 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 11, 11, 11, 11, + 21, 21, 21, 21, 21, 21, 26, 26, + 24, 25, 22, 24, 24, 25, 22, 24, + 26, 26, 26, 26, 26, 26, 26, 26, + 8, 9, 11, 11, 11, 11, 11, 7, + 26, 26, 26, 26, 26, 26, 26, 26, + 26, 24, 25, 26, 26, 26, 26, 20, + 20, 26, 26, 26, 27, 22, 23, 0, + 26, 26, 26, 26, 26, 26, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 11, 11, 11, 11, 11, 11, + 6, 0, 0, 0, 6, 6, 6, 6, + 6, 6, 27, 27, 27, 22, 23, 16, + 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 27, 27, 27, 22, 23, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 28, 28, 28, 28, 28, 28, 28, 28, + 28, 28, 28, 28, 28, 28, 28, 28, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 3, 3, 3, + 3, 1, 3, 3, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 ui_21[] = { + 30, 30, 15, 30, 30, 30, 30, 15, + 30, 30, 16, 15, 15, 15, 16, 16, + 15, 15, 15, 16, 30, 15, 30, 30, + 30, 15, 15, 15, 15, 15, 30, 30, + 30, 30, 30, 30, 15, 30, 15, 30, + 15, 30, 15, 15, 15, 15, 30, 16, + 15, 15, 30, 15, 16, 19, 19, 19, + 19, 16, 30, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, + 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 27, 27, 27, 27, 27, 30, 30, 30, + 30, 30, 27, 27, 30, 30, 30, 30, + 27, 30, 30, 27, 30, 30, 27, 30, + 30, 30, 30, 30, 30, 30, 27, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 27, 27, + 30, 30, 27, 30, 27, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 ui_22[] = { + 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 ui_23[] = { + 30, 30, 30, 30, 30, 30, 30, 30, + 27, 27, 27, 27, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 27, 27, 30, 30, 30, 30, 30, 30, + 30, 22, 23, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 0, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 ui_24[] = { + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 6, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 ui_25[] = { + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 27, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 27, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 ui_26[] = { + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 0, 0, 0, 0, + 0, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 27, + 30, 30, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 ui_27[] = { + 0, 30, 30, 30, 30, 0, 30, 30, + 30, 30, 0, 0, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 0, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 0, 30, 0, 30, + 30, 30, 30, 0, 0, 0, 30, 0, + 30, 30, 30, 30, 30, 30, 30, 0, + 0, 30, 30, 30, 30, 30, 30, 30, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 30, 0, 0, 0, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 0, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 ui_28[] = { + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, +}; + +static const Q_UINT8 ui_2E[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 0, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 ui_2F[] = { + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 0, 0, 0, 0, +}; + +static const Q_UINT8 ui_30[] = { + 7, 26, 26, 26, 30, 18, 19, 5, + 22, 23, 22, 23, 22, 23, 22, 23, + 22, 23, 30, 30, 22, 23, 22, 23, + 22, 23, 22, 23, 21, 22, 23, 23, + 30, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 1, 1, 1, 1, 1, 1, + 21, 18, 18, 18, 18, 18, 30, 30, + 5, 5, 5, 0, 0, 0, 30, 30, + 0, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 0, 0, 0, + 0, 1, 1, 29, 29, 18, 18, 0, + 0, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 20, 18, 18, 18, 0, +}; + +static const Q_UINT8 ui_31[] = { + 0, 0, 0, 0, 0, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 0, 0, 0, + 0, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 0, + 30, 30, 6, 6, 6, 6, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 ui_32[] = { + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 0, 0, 0, + 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 0, 0, 0, 30, + 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 0, 0, 0, 0, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 0, +}; + +static const Q_UINT8 ui_33[] = { + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 0, + 0, 0, 0, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 0, 0, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 0, +}; + +static const Q_UINT8 ui_34[] = { + 19, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 ui_4D[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 19, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 ui_9F[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 19, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 ui_A4[] = { + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 0, 0, 0, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 0, 0, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 0, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 0, 30, 30, 30, 0, 30, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 ui_D7[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 19, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 ui_D8[] = { + 12, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 ui_DB[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 12, + 12, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 12, +}; + +static const Q_UINT8 ui_DF[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 12, +}; + +static const Q_UINT8 ui_E0[] = { + 13, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 ui_F8[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 13, +}; + +static const Q_UINT8 ui_FA[] = { + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 ui_FB[] = { + 16, 16, 16, 16, 16, 16, 16, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 16, 16, 16, 16, 16, + 0, 0, 0, 0, 0, 19, 1, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 27, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 0, + 19, 19, 19, 19, 19, 0, 19, 0, + 19, 19, 0, 19, 19, 0, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, +}; + +static const Q_UINT8 ui_FD[] = { + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 22, 23, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 0, 0, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 0, 0, 0, 0, +}; + +static const Q_UINT8 ui_FE[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 26, 21, 21, 20, 20, 22, 23, 22, + 23, 22, 23, 22, 23, 22, 23, 22, + 23, 22, 23, 22, 23, 0, 0, 0, + 0, 26, 26, 26, 26, 20, 20, 20, + 26, 26, 26, 0, 26, 26, 26, 26, + 21, 22, 23, 22, 23, 22, 23, 26, + 26, 26, 27, 21, 27, 27, 27, 0, + 26, 28, 26, 26, 0, 0, 0, 0, + 19, 19, 19, 0, 19, 0, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 0, 0, 11, +}; + +static const Q_UINT8 ui_FF[] = { + 0, 26, 26, 26, 28, 26, 26, 26, + 22, 23, 26, 27, 26, 21, 26, 26, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 26, 26, 27, 27, 27, 26, + 26, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 22, 26, 23, 29, 20, + 29, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 22, 27, 23, 27, 0, + 0, 26, 22, 23, 26, 20, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 18, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 18, 18, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 0, + 0, 0, 19, 19, 19, 19, 19, 19, + 0, 0, 19, 19, 19, 19, 19, 19, + 0, 0, 19, 19, 19, 19, 19, 19, + 0, 0, 19, 19, 19, 0, 0, 0, + 28, 28, 27, 29, 30, 28, 28, 0, + 30, 27, 27, 27, 27, 30, 30, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 11, 11, 11, 30, 30, 0, 0, +}; + +static const Q_UINT8 * const unicode_info[256] = { + ui_00, ui_01, ui_02, ui_03, ui_04, ui_05, ui_06, ui_07, + ui_08, ui_09, ui_0A, ui_0B, ui_0C, ui_0D, ui_0E, ui_0F, + ui_10, ui_11, ui_12, ui_13, ui_14, ui_15, ui_16, ui_17, + ui_18, ui_08, ui_08, ui_08, ui_08, ui_08, ui_1E, ui_1F, + ui_20, ui_21, ui_22, ui_23, ui_24, ui_25, ui_26, ui_27, + ui_28, ui_08, ui_08, ui_08, ui_08, ui_08, ui_2E, ui_2F, + ui_30, ui_31, ui_32, ui_33, ui_34, ui_08, ui_08, ui_08, + ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, + ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, + ui_08, ui_08, ui_08, ui_08, ui_08, ui_4D, ui_34, ui_08, + ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, + ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, + ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, + ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, + ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, + ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, + ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, + ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, + ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, + ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, ui_9F, + ui_15, ui_15, ui_15, ui_15, ui_A4, ui_08, ui_08, ui_08, + ui_08, ui_08, ui_08, ui_08, ui_34, ui_08, ui_08, ui_08, + ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, + ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, + ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, + ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, + ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, ui_D7, + ui_D8, ui_08, ui_08, ui_DB, ui_D8, ui_08, ui_08, ui_DF, + ui_E0, ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, + ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, + ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, + ui_F8, ui_15, ui_FA, ui_FB, ui_15, ui_FD, ui_FE, ui_FF, +}; +// 15616 bytes + +static const Q_UINT16 decomposition_map [] = { + 0, + 3, 0x00A0, 0x0020, 0, + 16, 0x00A8, 0x0020, 0x0308, 0, + 9, 0x00AA, 0x0061, 0, + 16, 0x00AF, 0x0020, 0x0304, 0, + 9, 0x00B2, 0x0032, 0, + 9, 0x00B3, 0x0033, 0, + 16, 0x00B4, 0x0020, 0x0301, 0, + 16, 0x00B5, 0x03BC, 0, + 16, 0x00B8, 0x0020, 0x0327, 0, + 9, 0x00B9, 0x0031, 0, + 9, 0x00BA, 0x006F, 0, + 17, 0x00BC, 0x0031, 0x2044, 0x0034, 0, + 17, 0x00BD, 0x0031, 0x2044, 0x0032, 0, + 17, 0x00BE, 0x0033, 0x2044, 0x0034, 0, + 1, 0x00C0, 0x0041, 0x0300, 0, + 1, 0x00C1, 0x0041, 0x0301, 0, + 1, 0x00C2, 0x0041, 0x0302, 0, + 1, 0x00C3, 0x0041, 0x0303, 0, + 1, 0x00C4, 0x0041, 0x0308, 0, + 1, 0x00C5, 0x0041, 0x030A, 0, + 1, 0x00C7, 0x0043, 0x0327, 0, + 1, 0x00C8, 0x0045, 0x0300, 0, + 1, 0x00C9, 0x0045, 0x0301, 0, + 1, 0x00CA, 0x0045, 0x0302, 0, + 1, 0x00CB, 0x0045, 0x0308, 0, + 1, 0x00CC, 0x0049, 0x0300, 0, + 1, 0x00CD, 0x0049, 0x0301, 0, + 1, 0x00CE, 0x0049, 0x0302, 0, + 1, 0x00CF, 0x0049, 0x0308, 0, + 1, 0x00D1, 0x004E, 0x0303, 0, + 1, 0x00D2, 0x004F, 0x0300, 0, + 1, 0x00D3, 0x004F, 0x0301, 0, + 1, 0x00D4, 0x004F, 0x0302, 0, + 1, 0x00D5, 0x004F, 0x0303, 0, + 1, 0x00D6, 0x004F, 0x0308, 0, + 1, 0x00D9, 0x0055, 0x0300, 0, + 1, 0x00DA, 0x0055, 0x0301, 0, + 1, 0x00DB, 0x0055, 0x0302, 0, + 1, 0x00DC, 0x0055, 0x0308, 0, + 1, 0x00DD, 0x0059, 0x0301, 0, + 1, 0x00E0, 0x0061, 0x0300, 0, + 1, 0x00E1, 0x0061, 0x0301, 0, + 1, 0x00E2, 0x0061, 0x0302, 0, + 1, 0x00E3, 0x0061, 0x0303, 0, + 1, 0x00E4, 0x0061, 0x0308, 0, + 1, 0x00E5, 0x0061, 0x030A, 0, + 1, 0x00E7, 0x0063, 0x0327, 0, + 1, 0x00E8, 0x0065, 0x0300, 0, + 1, 0x00E9, 0x0065, 0x0301, 0, + 1, 0x00EA, 0x0065, 0x0302, 0, + 1, 0x00EB, 0x0065, 0x0308, 0, + 1, 0x00EC, 0x0069, 0x0300, 0, + 1, 0x00ED, 0x0069, 0x0301, 0, + 1, 0x00EE, 0x0069, 0x0302, 0, + 1, 0x00EF, 0x0069, 0x0308, 0, + 1, 0x00F1, 0x006E, 0x0303, 0, + 1, 0x00F2, 0x006F, 0x0300, 0, + 1, 0x00F3, 0x006F, 0x0301, 0, + 1, 0x00F4, 0x006F, 0x0302, 0, + 1, 0x00F5, 0x006F, 0x0303, 0, + 1, 0x00F6, 0x006F, 0x0308, 0, + 1, 0x00F9, 0x0075, 0x0300, 0, + 1, 0x00FA, 0x0075, 0x0301, 0, + 1, 0x00FB, 0x0075, 0x0302, 0, + 1, 0x00FC, 0x0075, 0x0308, 0, + 1, 0x00FD, 0x0079, 0x0301, 0, + 1, 0x00FF, 0x0079, 0x0308, 0, + 1, 0x0100, 0x0041, 0x0304, 0, + 1, 0x0101, 0x0061, 0x0304, 0, + 1, 0x0102, 0x0041, 0x0306, 0, + 1, 0x0103, 0x0061, 0x0306, 0, + 1, 0x0104, 0x0041, 0x0328, 0, + 1, 0x0105, 0x0061, 0x0328, 0, + 1, 0x0106, 0x0043, 0x0301, 0, + 1, 0x0107, 0x0063, 0x0301, 0, + 1, 0x0108, 0x0043, 0x0302, 0, + 1, 0x0109, 0x0063, 0x0302, 0, + 1, 0x010A, 0x0043, 0x0307, 0, + 1, 0x010B, 0x0063, 0x0307, 0, + 1, 0x010C, 0x0043, 0x030C, 0, + 1, 0x010D, 0x0063, 0x030C, 0, + 1, 0x010E, 0x0044, 0x030C, 0, + 1, 0x010F, 0x0064, 0x030C, 0, + 1, 0x0112, 0x0045, 0x0304, 0, + 1, 0x0113, 0x0065, 0x0304, 0, + 1, 0x0114, 0x0045, 0x0306, 0, + 1, 0x0115, 0x0065, 0x0306, 0, + 1, 0x0116, 0x0045, 0x0307, 0, + 1, 0x0117, 0x0065, 0x0307, 0, + 1, 0x0118, 0x0045, 0x0328, 0, + 1, 0x0119, 0x0065, 0x0328, 0, + 1, 0x011A, 0x0045, 0x030C, 0, + 1, 0x011B, 0x0065, 0x030C, 0, + 1, 0x011C, 0x0047, 0x0302, 0, + 1, 0x011D, 0x0067, 0x0302, 0, + 1, 0x011E, 0x0047, 0x0306, 0, + 1, 0x011F, 0x0067, 0x0306, 0, + 1, 0x0120, 0x0047, 0x0307, 0, + 1, 0x0121, 0x0067, 0x0307, 0, + 1, 0x0122, 0x0047, 0x0327, 0, + 1, 0x0123, 0x0067, 0x0327, 0, + 1, 0x0124, 0x0048, 0x0302, 0, + 1, 0x0125, 0x0068, 0x0302, 0, + 1, 0x0128, 0x0049, 0x0303, 0, + 1, 0x0129, 0x0069, 0x0303, 0, + 1, 0x012A, 0x0049, 0x0304, 0, + 1, 0x012B, 0x0069, 0x0304, 0, + 1, 0x012C, 0x0049, 0x0306, 0, + 1, 0x012D, 0x0069, 0x0306, 0, + 1, 0x012E, 0x0049, 0x0328, 0, + 1, 0x012F, 0x0069, 0x0328, 0, + 1, 0x0130, 0x0049, 0x0307, 0, + 16, 0x0132, 0x0049, 0x004A, 0, + 16, 0x0133, 0x0069, 0x006A, 0, + 1, 0x0134, 0x004A, 0x0302, 0, + 1, 0x0135, 0x006A, 0x0302, 0, + 1, 0x0136, 0x004B, 0x0327, 0, + 1, 0x0137, 0x006B, 0x0327, 0, + 1, 0x0139, 0x004C, 0x0301, 0, + 1, 0x013A, 0x006C, 0x0301, 0, + 1, 0x013B, 0x004C, 0x0327, 0, + 1, 0x013C, 0x006C, 0x0327, 0, + 1, 0x013D, 0x004C, 0x030C, 0, + 1, 0x013E, 0x006C, 0x030C, 0, + 16, 0x013F, 0x004C, 0x00B7, 0, + 16, 0x0140, 0x006C, 0x00B7, 0, + 1, 0x0143, 0x004E, 0x0301, 0, + 1, 0x0144, 0x006E, 0x0301, 0, + 1, 0x0145, 0x004E, 0x0327, 0, + 1, 0x0146, 0x006E, 0x0327, 0, + 1, 0x0147, 0x004E, 0x030C, 0, + 1, 0x0148, 0x006E, 0x030C, 0, + 16, 0x0149, 0x02BC, 0x006E, 0, + 1, 0x014C, 0x004F, 0x0304, 0, + 1, 0x014D, 0x006F, 0x0304, 0, + 1, 0x014E, 0x004F, 0x0306, 0, + 1, 0x014F, 0x006F, 0x0306, 0, + 1, 0x0150, 0x004F, 0x030B, 0, + 1, 0x0151, 0x006F, 0x030B, 0, + 1, 0x0154, 0x0052, 0x0301, 0, + 1, 0x0155, 0x0072, 0x0301, 0, + 1, 0x0156, 0x0052, 0x0327, 0, + 1, 0x0157, 0x0072, 0x0327, 0, + 1, 0x0158, 0x0052, 0x030C, 0, + 1, 0x0159, 0x0072, 0x030C, 0, + 1, 0x015A, 0x0053, 0x0301, 0, + 1, 0x015B, 0x0073, 0x0301, 0, + 1, 0x015C, 0x0053, 0x0302, 0, + 1, 0x015D, 0x0073, 0x0302, 0, + 1, 0x015E, 0x0053, 0x0327, 0, + 1, 0x015F, 0x0073, 0x0327, 0, + 1, 0x0160, 0x0053, 0x030C, 0, + 1, 0x0161, 0x0073, 0x030C, 0, + 1, 0x0162, 0x0054, 0x0327, 0, + 1, 0x0163, 0x0074, 0x0327, 0, + 1, 0x0164, 0x0054, 0x030C, 0, + 1, 0x0165, 0x0074, 0x030C, 0, + 1, 0x0168, 0x0055, 0x0303, 0, + 1, 0x0169, 0x0075, 0x0303, 0, + 1, 0x016A, 0x0055, 0x0304, 0, + 1, 0x016B, 0x0075, 0x0304, 0, + 1, 0x016C, 0x0055, 0x0306, 0, + 1, 0x016D, 0x0075, 0x0306, 0, + 1, 0x016E, 0x0055, 0x030A, 0, + 1, 0x016F, 0x0075, 0x030A, 0, + 1, 0x0170, 0x0055, 0x030B, 0, + 1, 0x0171, 0x0075, 0x030B, 0, + 1, 0x0172, 0x0055, 0x0328, 0, + 1, 0x0173, 0x0075, 0x0328, 0, + 1, 0x0174, 0x0057, 0x0302, 0, + 1, 0x0175, 0x0077, 0x0302, 0, + 1, 0x0176, 0x0059, 0x0302, 0, + 1, 0x0177, 0x0079, 0x0302, 0, + 1, 0x0178, 0x0059, 0x0308, 0, + 1, 0x0179, 0x005A, 0x0301, 0, + 1, 0x017A, 0x007A, 0x0301, 0, + 1, 0x017B, 0x005A, 0x0307, 0, + 1, 0x017C, 0x007A, 0x0307, 0, + 1, 0x017D, 0x005A, 0x030C, 0, + 1, 0x017E, 0x007A, 0x030C, 0, + 16, 0x017F, 0x0073, 0, + 1, 0x01A0, 0x004F, 0x031B, 0, + 1, 0x01A1, 0x006F, 0x031B, 0, + 1, 0x01AF, 0x0055, 0x031B, 0, + 1, 0x01B0, 0x0075, 0x031B, 0, + 16, 0x01C4, 0x0044, 0x017D, 0, + 16, 0x01C5, 0x0044, 0x017E, 0, + 16, 0x01C6, 0x0064, 0x017E, 0, + 16, 0x01C7, 0x004C, 0x004A, 0, + 16, 0x01C8, 0x004C, 0x006A, 0, + 16, 0x01C9, 0x006C, 0x006A, 0, + 16, 0x01CA, 0x004E, 0x004A, 0, + 16, 0x01CB, 0x004E, 0x006A, 0, + 16, 0x01CC, 0x006E, 0x006A, 0, + 1, 0x01CD, 0x0041, 0x030C, 0, + 1, 0x01CE, 0x0061, 0x030C, 0, + 1, 0x01CF, 0x0049, 0x030C, 0, + 1, 0x01D0, 0x0069, 0x030C, 0, + 1, 0x01D1, 0x004F, 0x030C, 0, + 1, 0x01D2, 0x006F, 0x030C, 0, + 1, 0x01D3, 0x0055, 0x030C, 0, + 1, 0x01D4, 0x0075, 0x030C, 0, + 1, 0x01D5, 0x00DC, 0x0304, 0, + 1, 0x01D6, 0x00FC, 0x0304, 0, + 1, 0x01D7, 0x00DC, 0x0301, 0, + 1, 0x01D8, 0x00FC, 0x0301, 0, + 1, 0x01D9, 0x00DC, 0x030C, 0, + 1, 0x01DA, 0x00FC, 0x030C, 0, + 1, 0x01DB, 0x00DC, 0x0300, 0, + 1, 0x01DC, 0x00FC, 0x0300, 0, + 1, 0x01DE, 0x00C4, 0x0304, 0, + 1, 0x01DF, 0x00E4, 0x0304, 0, + 1, 0x01E0, 0x0226, 0x0304, 0, + 1, 0x01E1, 0x0227, 0x0304, 0, + 1, 0x01E2, 0x00C6, 0x0304, 0, + 1, 0x01E3, 0x00E6, 0x0304, 0, + 1, 0x01E6, 0x0047, 0x030C, 0, + 1, 0x01E7, 0x0067, 0x030C, 0, + 1, 0x01E8, 0x004B, 0x030C, 0, + 1, 0x01E9, 0x006B, 0x030C, 0, + 1, 0x01EA, 0x004F, 0x0328, 0, + 1, 0x01EB, 0x006F, 0x0328, 0, + 1, 0x01EC, 0x01EA, 0x0304, 0, + 1, 0x01ED, 0x01EB, 0x0304, 0, + 1, 0x01EE, 0x01B7, 0x030C, 0, + 1, 0x01EF, 0x0292, 0x030C, 0, + 1, 0x01F0, 0x006A, 0x030C, 0, + 16, 0x01F1, 0x0044, 0x005A, 0, + 16, 0x01F2, 0x0044, 0x007A, 0, + 16, 0x01F3, 0x0064, 0x007A, 0, + 1, 0x01F4, 0x0047, 0x0301, 0, + 1, 0x01F5, 0x0067, 0x0301, 0, + 1, 0x01F8, 0x004E, 0x0300, 0, + 1, 0x01F9, 0x006E, 0x0300, 0, + 1, 0x01FA, 0x00C5, 0x0301, 0, + 1, 0x01FB, 0x00E5, 0x0301, 0, + 1, 0x01FC, 0x00C6, 0x0301, 0, + 1, 0x01FD, 0x00E6, 0x0301, 0, + 1, 0x01FE, 0x00D8, 0x0301, 0, + 1, 0x01FF, 0x00F8, 0x0301, 0, + 1, 0x0200, 0x0041, 0x030F, 0, + 1, 0x0201, 0x0061, 0x030F, 0, + 1, 0x0202, 0x0041, 0x0311, 0, + 1, 0x0203, 0x0061, 0x0311, 0, + 1, 0x0204, 0x0045, 0x030F, 0, + 1, 0x0205, 0x0065, 0x030F, 0, + 1, 0x0206, 0x0045, 0x0311, 0, + 1, 0x0207, 0x0065, 0x0311, 0, + 1, 0x0208, 0x0049, 0x030F, 0, + 1, 0x0209, 0x0069, 0x030F, 0, + 1, 0x020A, 0x0049, 0x0311, 0, + 1, 0x020B, 0x0069, 0x0311, 0, + 1, 0x020C, 0x004F, 0x030F, 0, + 1, 0x020D, 0x006F, 0x030F, 0, + 1, 0x020E, 0x004F, 0x0311, 0, + 1, 0x020F, 0x006F, 0x0311, 0, + 1, 0x0210, 0x0052, 0x030F, 0, + 1, 0x0211, 0x0072, 0x030F, 0, + 1, 0x0212, 0x0052, 0x0311, 0, + 1, 0x0213, 0x0072, 0x0311, 0, + 1, 0x0214, 0x0055, 0x030F, 0, + 1, 0x0215, 0x0075, 0x030F, 0, + 1, 0x0216, 0x0055, 0x0311, 0, + 1, 0x0217, 0x0075, 0x0311, 0, + 1, 0x0218, 0x0053, 0x0326, 0, + 1, 0x0219, 0x0073, 0x0326, 0, + 1, 0x021A, 0x0054, 0x0326, 0, + 1, 0x021B, 0x0074, 0x0326, 0, + 1, 0x021E, 0x0048, 0x030C, 0, + 1, 0x021F, 0x0068, 0x030C, 0, + 1, 0x0226, 0x0041, 0x0307, 0, + 1, 0x0227, 0x0061, 0x0307, 0, + 1, 0x0228, 0x0045, 0x0327, 0, + 1, 0x0229, 0x0065, 0x0327, 0, + 1, 0x022A, 0x00D6, 0x0304, 0, + 1, 0x022B, 0x00F6, 0x0304, 0, + 1, 0x022C, 0x00D5, 0x0304, 0, + 1, 0x022D, 0x00F5, 0x0304, 0, + 1, 0x022E, 0x004F, 0x0307, 0, + 1, 0x022F, 0x006F, 0x0307, 0, + 1, 0x0230, 0x022E, 0x0304, 0, + 1, 0x0231, 0x022F, 0x0304, 0, + 1, 0x0232, 0x0059, 0x0304, 0, + 1, 0x0233, 0x0079, 0x0304, 0, + 9, 0x02B0, 0x0068, 0, + 9, 0x02B1, 0x0266, 0, + 9, 0x02B2, 0x006A, 0, + 9, 0x02B3, 0x0072, 0, + 9, 0x02B4, 0x0279, 0, + 9, 0x02B5, 0x027B, 0, + 9, 0x02B6, 0x0281, 0, + 9, 0x02B7, 0x0077, 0, + 9, 0x02B8, 0x0079, 0, + 16, 0x02D8, 0x0020, 0x0306, 0, + 16, 0x02D9, 0x0020, 0x0307, 0, + 16, 0x02DA, 0x0020, 0x030A, 0, + 16, 0x02DB, 0x0020, 0x0328, 0, + 16, 0x02DC, 0x0020, 0x0303, 0, + 16, 0x02DD, 0x0020, 0x030B, 0, + 9, 0x02E0, 0x0263, 0, + 9, 0x02E1, 0x006C, 0, + 9, 0x02E2, 0x0073, 0, + 9, 0x02E3, 0x0078, 0, + 9, 0x02E4, 0x0295, 0, + 1, 0x0340, 0x0300, 0, + 1, 0x0341, 0x0301, 0, + 1, 0x0343, 0x0313, 0, + 1, 0x0344, 0x0308, 0x0301, 0, + 1, 0x0374, 0x02B9, 0, + 16, 0x037A, 0x0020, 0x0345, 0, + 1, 0x037E, 0x003B, 0, + 16, 0x0384, 0x0020, 0x0301, 0, + 1, 0x0385, 0x00A8, 0x0301, 0, + 1, 0x0386, 0x0391, 0x0301, 0, + 1, 0x0387, 0x00B7, 0, + 1, 0x0388, 0x0395, 0x0301, 0, + 1, 0x0389, 0x0397, 0x0301, 0, + 1, 0x038A, 0x0399, 0x0301, 0, + 1, 0x038C, 0x039F, 0x0301, 0, + 1, 0x038E, 0x03A5, 0x0301, 0, + 1, 0x038F, 0x03A9, 0x0301, 0, + 1, 0x0390, 0x03CA, 0x0301, 0, + 1, 0x03AA, 0x0399, 0x0308, 0, + 1, 0x03AB, 0x03A5, 0x0308, 0, + 1, 0x03AC, 0x03B1, 0x0301, 0, + 1, 0x03AD, 0x03B5, 0x0301, 0, + 1, 0x03AE, 0x03B7, 0x0301, 0, + 1, 0x03AF, 0x03B9, 0x0301, 0, + 1, 0x03B0, 0x03CB, 0x0301, 0, + 1, 0x03CA, 0x03B9, 0x0308, 0, + 1, 0x03CB, 0x03C5, 0x0308, 0, + 1, 0x03CC, 0x03BF, 0x0301, 0, + 1, 0x03CD, 0x03C5, 0x0301, 0, + 1, 0x03CE, 0x03C9, 0x0301, 0, + 16, 0x03D0, 0x03B2, 0, + 16, 0x03D1, 0x03B8, 0, + 16, 0x03D2, 0x03A5, 0, + 1, 0x03D3, 0x03D2, 0x0301, 0, + 1, 0x03D4, 0x03D2, 0x0308, 0, + 16, 0x03D5, 0x03C6, 0, + 16, 0x03D6, 0x03C0, 0, + 16, 0x03F0, 0x03BA, 0, + 16, 0x03F1, 0x03C1, 0, + 16, 0x03F2, 0x03C2, 0, + 1, 0x0400, 0x0415, 0x0300, 0, + 1, 0x0401, 0x0415, 0x0308, 0, + 1, 0x0403, 0x0413, 0x0301, 0, + 1, 0x0407, 0x0406, 0x0308, 0, + 1, 0x040C, 0x041A, 0x0301, 0, + 1, 0x040D, 0x0418, 0x0300, 0, + 1, 0x040E, 0x0423, 0x0306, 0, + 1, 0x0419, 0x0418, 0x0306, 0, + 1, 0x0439, 0x0438, 0x0306, 0, + 1, 0x0450, 0x0435, 0x0300, 0, + 1, 0x0451, 0x0435, 0x0308, 0, + 1, 0x0453, 0x0433, 0x0301, 0, + 1, 0x0457, 0x0456, 0x0308, 0, + 1, 0x045C, 0x043A, 0x0301, 0, + 1, 0x045D, 0x0438, 0x0300, 0, + 1, 0x045E, 0x0443, 0x0306, 0, + 1, 0x0476, 0x0474, 0x030F, 0, + 1, 0x0477, 0x0475, 0x030F, 0, + 1, 0x04C1, 0x0416, 0x0306, 0, + 1, 0x04C2, 0x0436, 0x0306, 0, + 1, 0x04D0, 0x0410, 0x0306, 0, + 1, 0x04D1, 0x0430, 0x0306, 0, + 1, 0x04D2, 0x0410, 0x0308, 0, + 1, 0x04D3, 0x0430, 0x0308, 0, + 1, 0x04D6, 0x0415, 0x0306, 0, + 1, 0x04D7, 0x0435, 0x0306, 0, + 1, 0x04DA, 0x04D8, 0x0308, 0, + 1, 0x04DB, 0x04D9, 0x0308, 0, + 1, 0x04DC, 0x0416, 0x0308, 0, + 1, 0x04DD, 0x0436, 0x0308, 0, + 1, 0x04DE, 0x0417, 0x0308, 0, + 1, 0x04DF, 0x0437, 0x0308, 0, + 1, 0x04E2, 0x0418, 0x0304, 0, + 1, 0x04E3, 0x0438, 0x0304, 0, + 1, 0x04E4, 0x0418, 0x0308, 0, + 1, 0x04E5, 0x0438, 0x0308, 0, + 1, 0x04E6, 0x041E, 0x0308, 0, + 1, 0x04E7, 0x043E, 0x0308, 0, + 1, 0x04EA, 0x04E8, 0x0308, 0, + 1, 0x04EB, 0x04E9, 0x0308, 0, + 1, 0x04EC, 0x042D, 0x0308, 0, + 1, 0x04ED, 0x044D, 0x0308, 0, + 1, 0x04EE, 0x0423, 0x0304, 0, + 1, 0x04EF, 0x0443, 0x0304, 0, + 1, 0x04F0, 0x0423, 0x0308, 0, + 1, 0x04F1, 0x0443, 0x0308, 0, + 1, 0x04F2, 0x0423, 0x030B, 0, + 1, 0x04F3, 0x0443, 0x030B, 0, + 1, 0x04F4, 0x0427, 0x0308, 0, + 1, 0x04F5, 0x0447, 0x0308, 0, + 1, 0x04F8, 0x042B, 0x0308, 0, + 1, 0x04F9, 0x044B, 0x0308, 0, + 16, 0x0587, 0x0565, 0x0582, 0, + 1, 0x0622, 0x0627, 0x0653, 0, + 1, 0x0623, 0x0627, 0x0654, 0, + 1, 0x0624, 0x0648, 0x0654, 0, + 1, 0x0625, 0x0627, 0x0655, 0, + 1, 0x0626, 0x064A, 0x0654, 0, + 16, 0x0675, 0x0627, 0x0674, 0, + 16, 0x0676, 0x0648, 0x0674, 0, + 16, 0x0677, 0x06C7, 0x0674, 0, + 16, 0x0678, 0x064A, 0x0674, 0, + 1, 0x06C0, 0x06D5, 0x0654, 0, + 1, 0x06C2, 0x06C1, 0x0654, 0, + 1, 0x06D3, 0x06D2, 0x0654, 0, + 1, 0x0929, 0x0928, 0x093C, 0, + 1, 0x0931, 0x0930, 0x093C, 0, + 1, 0x0934, 0x0933, 0x093C, 0, + 1, 0x0958, 0x0915, 0x093C, 0, + 1, 0x0959, 0x0916, 0x093C, 0, + 1, 0x095A, 0x0917, 0x093C, 0, + 1, 0x095B, 0x091C, 0x093C, 0, + 1, 0x095C, 0x0921, 0x093C, 0, + 1, 0x095D, 0x0922, 0x093C, 0, + 1, 0x095E, 0x092B, 0x093C, 0, + 1, 0x095F, 0x092F, 0x093C, 0, + 1, 0x09CB, 0x09C7, 0x09BE, 0, + 1, 0x09CC, 0x09C7, 0x09D7, 0, + 1, 0x09DC, 0x09A1, 0x09BC, 0, + 1, 0x09DD, 0x09A2, 0x09BC, 0, + 1, 0x09DF, 0x09AF, 0x09BC, 0, + 1, 0x0A33, 0x0A32, 0x0A3C, 0, + 1, 0x0A36, 0x0A38, 0x0A3C, 0, + 1, 0x0A59, 0x0A16, 0x0A3C, 0, + 1, 0x0A5A, 0x0A17, 0x0A3C, 0, + 1, 0x0A5B, 0x0A1C, 0x0A3C, 0, + 1, 0x0A5E, 0x0A2B, 0x0A3C, 0, + 1, 0x0B48, 0x0B47, 0x0B56, 0, + 1, 0x0B4B, 0x0B47, 0x0B3E, 0, + 1, 0x0B4C, 0x0B47, 0x0B57, 0, + 1, 0x0B5C, 0x0B21, 0x0B3C, 0, + 1, 0x0B5D, 0x0B22, 0x0B3C, 0, + 1, 0x0B94, 0x0B92, 0x0BD7, 0, + 1, 0x0BCA, 0x0BC6, 0x0BBE, 0, + 1, 0x0BCB, 0x0BC7, 0x0BBE, 0, + 1, 0x0BCC, 0x0BC6, 0x0BD7, 0, + 1, 0x0C48, 0x0C46, 0x0C56, 0, + 1, 0x0CC0, 0x0CBF, 0x0CD5, 0, + 1, 0x0CC7, 0x0CC6, 0x0CD5, 0, + 1, 0x0CC8, 0x0CC6, 0x0CD6, 0, + 1, 0x0CCA, 0x0CC6, 0x0CC2, 0, + 1, 0x0CCB, 0x0CCA, 0x0CD5, 0, + 1, 0x0D4A, 0x0D46, 0x0D3E, 0, + 1, 0x0D4B, 0x0D47, 0x0D3E, 0, + 1, 0x0D4C, 0x0D46, 0x0D57, 0, + 1, 0x0DDA, 0x0DD9, 0x0DCA, 0, + 1, 0x0DDC, 0x0DD9, 0x0DCF, 0, + 1, 0x0DDD, 0x0DDC, 0x0DCA, 0, + 1, 0x0DDE, 0x0DD9, 0x0DDF, 0, + 16, 0x0E33, 0x0E4D, 0x0E32, 0, + 16, 0x0EB3, 0x0ECD, 0x0EB2, 0, + 16, 0x0EDC, 0x0EAB, 0x0E99, 0, + 16, 0x0EDD, 0x0EAB, 0x0EA1, 0, + 3, 0x0F0C, 0x0F0B, 0, + 1, 0x0F43, 0x0F42, 0x0FB7, 0, + 1, 0x0F4D, 0x0F4C, 0x0FB7, 0, + 1, 0x0F52, 0x0F51, 0x0FB7, 0, + 1, 0x0F57, 0x0F56, 0x0FB7, 0, + 1, 0x0F5C, 0x0F5B, 0x0FB7, 0, + 1, 0x0F69, 0x0F40, 0x0FB5, 0, + 1, 0x0F73, 0x0F71, 0x0F72, 0, + 1, 0x0F75, 0x0F71, 0x0F74, 0, + 1, 0x0F76, 0x0FB2, 0x0F80, 0, + 16, 0x0F77, 0x0FB2, 0x0F81, 0, + 1, 0x0F78, 0x0FB3, 0x0F80, 0, + 16, 0x0F79, 0x0FB3, 0x0F81, 0, + 1, 0x0F81, 0x0F71, 0x0F80, 0, + 1, 0x0F93, 0x0F92, 0x0FB7, 0, + 1, 0x0F9D, 0x0F9C, 0x0FB7, 0, + 1, 0x0FA2, 0x0FA1, 0x0FB7, 0, + 1, 0x0FA7, 0x0FA6, 0x0FB7, 0, + 1, 0x0FAC, 0x0FAB, 0x0FB7, 0, + 1, 0x0FB9, 0x0F90, 0x0FB5, 0, + 1, 0x1026, 0x1025, 0x102E, 0, + 1, 0x1E00, 0x0041, 0x0325, 0, + 1, 0x1E01, 0x0061, 0x0325, 0, + 1, 0x1E02, 0x0042, 0x0307, 0, + 1, 0x1E03, 0x0062, 0x0307, 0, + 1, 0x1E04, 0x0042, 0x0323, 0, + 1, 0x1E05, 0x0062, 0x0323, 0, + 1, 0x1E06, 0x0042, 0x0331, 0, + 1, 0x1E07, 0x0062, 0x0331, 0, + 1, 0x1E08, 0x00C7, 0x0301, 0, + 1, 0x1E09, 0x00E7, 0x0301, 0, + 1, 0x1E0A, 0x0044, 0x0307, 0, + 1, 0x1E0B, 0x0064, 0x0307, 0, + 1, 0x1E0C, 0x0044, 0x0323, 0, + 1, 0x1E0D, 0x0064, 0x0323, 0, + 1, 0x1E0E, 0x0044, 0x0331, 0, + 1, 0x1E0F, 0x0064, 0x0331, 0, + 1, 0x1E10, 0x0044, 0x0327, 0, + 1, 0x1E11, 0x0064, 0x0327, 0, + 1, 0x1E12, 0x0044, 0x032D, 0, + 1, 0x1E13, 0x0064, 0x032D, 0, + 1, 0x1E14, 0x0112, 0x0300, 0, + 1, 0x1E15, 0x0113, 0x0300, 0, + 1, 0x1E16, 0x0112, 0x0301, 0, + 1, 0x1E17, 0x0113, 0x0301, 0, + 1, 0x1E18, 0x0045, 0x032D, 0, + 1, 0x1E19, 0x0065, 0x032D, 0, + 1, 0x1E1A, 0x0045, 0x0330, 0, + 1, 0x1E1B, 0x0065, 0x0330, 0, + 1, 0x1E1C, 0x0228, 0x0306, 0, + 1, 0x1E1D, 0x0229, 0x0306, 0, + 1, 0x1E1E, 0x0046, 0x0307, 0, + 1, 0x1E1F, 0x0066, 0x0307, 0, + 1, 0x1E20, 0x0047, 0x0304, 0, + 1, 0x1E21, 0x0067, 0x0304, 0, + 1, 0x1E22, 0x0048, 0x0307, 0, + 1, 0x1E23, 0x0068, 0x0307, 0, + 1, 0x1E24, 0x0048, 0x0323, 0, + 1, 0x1E25, 0x0068, 0x0323, 0, + 1, 0x1E26, 0x0048, 0x0308, 0, + 1, 0x1E27, 0x0068, 0x0308, 0, + 1, 0x1E28, 0x0048, 0x0327, 0, + 1, 0x1E29, 0x0068, 0x0327, 0, + 1, 0x1E2A, 0x0048, 0x032E, 0, + 1, 0x1E2B, 0x0068, 0x032E, 0, + 1, 0x1E2C, 0x0049, 0x0330, 0, + 1, 0x1E2D, 0x0069, 0x0330, 0, + 1, 0x1E2E, 0x00CF, 0x0301, 0, + 1, 0x1E2F, 0x00EF, 0x0301, 0, + 1, 0x1E30, 0x004B, 0x0301, 0, + 1, 0x1E31, 0x006B, 0x0301, 0, + 1, 0x1E32, 0x004B, 0x0323, 0, + 1, 0x1E33, 0x006B, 0x0323, 0, + 1, 0x1E34, 0x004B, 0x0331, 0, + 1, 0x1E35, 0x006B, 0x0331, 0, + 1, 0x1E36, 0x004C, 0x0323, 0, + 1, 0x1E37, 0x006C, 0x0323, 0, + 1, 0x1E38, 0x1E36, 0x0304, 0, + 1, 0x1E39, 0x1E37, 0x0304, 0, + 1, 0x1E3A, 0x004C, 0x0331, 0, + 1, 0x1E3B, 0x006C, 0x0331, 0, + 1, 0x1E3C, 0x004C, 0x032D, 0, + 1, 0x1E3D, 0x006C, 0x032D, 0, + 1, 0x1E3E, 0x004D, 0x0301, 0, + 1, 0x1E3F, 0x006D, 0x0301, 0, + 1, 0x1E40, 0x004D, 0x0307, 0, + 1, 0x1E41, 0x006D, 0x0307, 0, + 1, 0x1E42, 0x004D, 0x0323, 0, + 1, 0x1E43, 0x006D, 0x0323, 0, + 1, 0x1E44, 0x004E, 0x0307, 0, + 1, 0x1E45, 0x006E, 0x0307, 0, + 1, 0x1E46, 0x004E, 0x0323, 0, + 1, 0x1E47, 0x006E, 0x0323, 0, + 1, 0x1E48, 0x004E, 0x0331, 0, + 1, 0x1E49, 0x006E, 0x0331, 0, + 1, 0x1E4A, 0x004E, 0x032D, 0, + 1, 0x1E4B, 0x006E, 0x032D, 0, + 1, 0x1E4C, 0x00D5, 0x0301, 0, + 1, 0x1E4D, 0x00F5, 0x0301, 0, + 1, 0x1E4E, 0x00D5, 0x0308, 0, + 1, 0x1E4F, 0x00F5, 0x0308, 0, + 1, 0x1E50, 0x014C, 0x0300, 0, + 1, 0x1E51, 0x014D, 0x0300, 0, + 1, 0x1E52, 0x014C, 0x0301, 0, + 1, 0x1E53, 0x014D, 0x0301, 0, + 1, 0x1E54, 0x0050, 0x0301, 0, + 1, 0x1E55, 0x0070, 0x0301, 0, + 1, 0x1E56, 0x0050, 0x0307, 0, + 1, 0x1E57, 0x0070, 0x0307, 0, + 1, 0x1E58, 0x0052, 0x0307, 0, + 1, 0x1E59, 0x0072, 0x0307, 0, + 1, 0x1E5A, 0x0052, 0x0323, 0, + 1, 0x1E5B, 0x0072, 0x0323, 0, + 1, 0x1E5C, 0x1E5A, 0x0304, 0, + 1, 0x1E5D, 0x1E5B, 0x0304, 0, + 1, 0x1E5E, 0x0052, 0x0331, 0, + 1, 0x1E5F, 0x0072, 0x0331, 0, + 1, 0x1E60, 0x0053, 0x0307, 0, + 1, 0x1E61, 0x0073, 0x0307, 0, + 1, 0x1E62, 0x0053, 0x0323, 0, + 1, 0x1E63, 0x0073, 0x0323, 0, + 1, 0x1E64, 0x015A, 0x0307, 0, + 1, 0x1E65, 0x015B, 0x0307, 0, + 1, 0x1E66, 0x0160, 0x0307, 0, + 1, 0x1E67, 0x0161, 0x0307, 0, + 1, 0x1E68, 0x1E62, 0x0307, 0, + 1, 0x1E69, 0x1E63, 0x0307, 0, + 1, 0x1E6A, 0x0054, 0x0307, 0, + 1, 0x1E6B, 0x0074, 0x0307, 0, + 1, 0x1E6C, 0x0054, 0x0323, 0, + 1, 0x1E6D, 0x0074, 0x0323, 0, + 1, 0x1E6E, 0x0054, 0x0331, 0, + 1, 0x1E6F, 0x0074, 0x0331, 0, + 1, 0x1E70, 0x0054, 0x032D, 0, + 1, 0x1E71, 0x0074, 0x032D, 0, + 1, 0x1E72, 0x0055, 0x0324, 0, + 1, 0x1E73, 0x0075, 0x0324, 0, + 1, 0x1E74, 0x0055, 0x0330, 0, + 1, 0x1E75, 0x0075, 0x0330, 0, + 1, 0x1E76, 0x0055, 0x032D, 0, + 1, 0x1E77, 0x0075, 0x032D, 0, + 1, 0x1E78, 0x0168, 0x0301, 0, + 1, 0x1E79, 0x0169, 0x0301, 0, + 1, 0x1E7A, 0x016A, 0x0308, 0, + 1, 0x1E7B, 0x016B, 0x0308, 0, + 1, 0x1E7C, 0x0056, 0x0303, 0, + 1, 0x1E7D, 0x0076, 0x0303, 0, + 1, 0x1E7E, 0x0056, 0x0323, 0, + 1, 0x1E7F, 0x0076, 0x0323, 0, + 1, 0x1E80, 0x0057, 0x0300, 0, + 1, 0x1E81, 0x0077, 0x0300, 0, + 1, 0x1E82, 0x0057, 0x0301, 0, + 1, 0x1E83, 0x0077, 0x0301, 0, + 1, 0x1E84, 0x0057, 0x0308, 0, + 1, 0x1E85, 0x0077, 0x0308, 0, + 1, 0x1E86, 0x0057, 0x0307, 0, + 1, 0x1E87, 0x0077, 0x0307, 0, + 1, 0x1E88, 0x0057, 0x0323, 0, + 1, 0x1E89, 0x0077, 0x0323, 0, + 1, 0x1E8A, 0x0058, 0x0307, 0, + 1, 0x1E8B, 0x0078, 0x0307, 0, + 1, 0x1E8C, 0x0058, 0x0308, 0, + 1, 0x1E8D, 0x0078, 0x0308, 0, + 1, 0x1E8E, 0x0059, 0x0307, 0, + 1, 0x1E8F, 0x0079, 0x0307, 0, + 1, 0x1E90, 0x005A, 0x0302, 0, + 1, 0x1E91, 0x007A, 0x0302, 0, + 1, 0x1E92, 0x005A, 0x0323, 0, + 1, 0x1E93, 0x007A, 0x0323, 0, + 1, 0x1E94, 0x005A, 0x0331, 0, + 1, 0x1E95, 0x007A, 0x0331, 0, + 1, 0x1E96, 0x0068, 0x0331, 0, + 1, 0x1E97, 0x0074, 0x0308, 0, + 1, 0x1E98, 0x0077, 0x030A, 0, + 1, 0x1E99, 0x0079, 0x030A, 0, + 16, 0x1E9A, 0x0061, 0x02BE, 0, + 1, 0x1E9B, 0x017F, 0x0307, 0, + 1, 0x1EA0, 0x0041, 0x0323, 0, + 1, 0x1EA1, 0x0061, 0x0323, 0, + 1, 0x1EA2, 0x0041, 0x0309, 0, + 1, 0x1EA3, 0x0061, 0x0309, 0, + 1, 0x1EA4, 0x00C2, 0x0301, 0, + 1, 0x1EA5, 0x00E2, 0x0301, 0, + 1, 0x1EA6, 0x00C2, 0x0300, 0, + 1, 0x1EA7, 0x00E2, 0x0300, 0, + 1, 0x1EA8, 0x00C2, 0x0309, 0, + 1, 0x1EA9, 0x00E2, 0x0309, 0, + 1, 0x1EAA, 0x00C2, 0x0303, 0, + 1, 0x1EAB, 0x00E2, 0x0303, 0, + 1, 0x1EAC, 0x1EA0, 0x0302, 0, + 1, 0x1EAD, 0x1EA1, 0x0302, 0, + 1, 0x1EAE, 0x0102, 0x0301, 0, + 1, 0x1EAF, 0x0103, 0x0301, 0, + 1, 0x1EB0, 0x0102, 0x0300, 0, + 1, 0x1EB1, 0x0103, 0x0300, 0, + 1, 0x1EB2, 0x0102, 0x0309, 0, + 1, 0x1EB3, 0x0103, 0x0309, 0, + 1, 0x1EB4, 0x0102, 0x0303, 0, + 1, 0x1EB5, 0x0103, 0x0303, 0, + 1, 0x1EB6, 0x1EA0, 0x0306, 0, + 1, 0x1EB7, 0x1EA1, 0x0306, 0, + 1, 0x1EB8, 0x0045, 0x0323, 0, + 1, 0x1EB9, 0x0065, 0x0323, 0, + 1, 0x1EBA, 0x0045, 0x0309, 0, + 1, 0x1EBB, 0x0065, 0x0309, 0, + 1, 0x1EBC, 0x0045, 0x0303, 0, + 1, 0x1EBD, 0x0065, 0x0303, 0, + 1, 0x1EBE, 0x00CA, 0x0301, 0, + 1, 0x1EBF, 0x00EA, 0x0301, 0, + 1, 0x1EC0, 0x00CA, 0x0300, 0, + 1, 0x1EC1, 0x00EA, 0x0300, 0, + 1, 0x1EC2, 0x00CA, 0x0309, 0, + 1, 0x1EC3, 0x00EA, 0x0309, 0, + 1, 0x1EC4, 0x00CA, 0x0303, 0, + 1, 0x1EC5, 0x00EA, 0x0303, 0, + 1, 0x1EC6, 0x1EB8, 0x0302, 0, + 1, 0x1EC7, 0x1EB9, 0x0302, 0, + 1, 0x1EC8, 0x0049, 0x0309, 0, + 1, 0x1EC9, 0x0069, 0x0309, 0, + 1, 0x1ECA, 0x0049, 0x0323, 0, + 1, 0x1ECB, 0x0069, 0x0323, 0, + 1, 0x1ECC, 0x004F, 0x0323, 0, + 1, 0x1ECD, 0x006F, 0x0323, 0, + 1, 0x1ECE, 0x004F, 0x0309, 0, + 1, 0x1ECF, 0x006F, 0x0309, 0, + 1, 0x1ED0, 0x00D4, 0x0301, 0, + 1, 0x1ED1, 0x00F4, 0x0301, 0, + 1, 0x1ED2, 0x00D4, 0x0300, 0, + 1, 0x1ED3, 0x00F4, 0x0300, 0, + 1, 0x1ED4, 0x00D4, 0x0309, 0, + 1, 0x1ED5, 0x00F4, 0x0309, 0, + 1, 0x1ED6, 0x00D4, 0x0303, 0, + 1, 0x1ED7, 0x00F4, 0x0303, 0, + 1, 0x1ED8, 0x1ECC, 0x0302, 0, + 1, 0x1ED9, 0x1ECD, 0x0302, 0, + 1, 0x1EDA, 0x01A0, 0x0301, 0, + 1, 0x1EDB, 0x01A1, 0x0301, 0, + 1, 0x1EDC, 0x01A0, 0x0300, 0, + 1, 0x1EDD, 0x01A1, 0x0300, 0, + 1, 0x1EDE, 0x01A0, 0x0309, 0, + 1, 0x1EDF, 0x01A1, 0x0309, 0, + 1, 0x1EE0, 0x01A0, 0x0303, 0, + 1, 0x1EE1, 0x01A1, 0x0303, 0, + 1, 0x1EE2, 0x01A0, 0x0323, 0, + 1, 0x1EE3, 0x01A1, 0x0323, 0, + 1, 0x1EE4, 0x0055, 0x0323, 0, + 1, 0x1EE5, 0x0075, 0x0323, 0, + 1, 0x1EE6, 0x0055, 0x0309, 0, + 1, 0x1EE7, 0x0075, 0x0309, 0, + 1, 0x1EE8, 0x01AF, 0x0301, 0, + 1, 0x1EE9, 0x01B0, 0x0301, 0, + 1, 0x1EEA, 0x01AF, 0x0300, 0, + 1, 0x1EEB, 0x01B0, 0x0300, 0, + 1, 0x1EEC, 0x01AF, 0x0309, 0, + 1, 0x1EED, 0x01B0, 0x0309, 0, + 1, 0x1EEE, 0x01AF, 0x0303, 0, + 1, 0x1EEF, 0x01B0, 0x0303, 0, + 1, 0x1EF0, 0x01AF, 0x0323, 0, + 1, 0x1EF1, 0x01B0, 0x0323, 0, + 1, 0x1EF2, 0x0059, 0x0300, 0, + 1, 0x1EF3, 0x0079, 0x0300, 0, + 1, 0x1EF4, 0x0059, 0x0323, 0, + 1, 0x1EF5, 0x0079, 0x0323, 0, + 1, 0x1EF6, 0x0059, 0x0309, 0, + 1, 0x1EF7, 0x0079, 0x0309, 0, + 1, 0x1EF8, 0x0059, 0x0303, 0, + 1, 0x1EF9, 0x0079, 0x0303, 0, + 1, 0x1F00, 0x03B1, 0x0313, 0, + 1, 0x1F01, 0x03B1, 0x0314, 0, + 1, 0x1F02, 0x1F00, 0x0300, 0, + 1, 0x1F03, 0x1F01, 0x0300, 0, + 1, 0x1F04, 0x1F00, 0x0301, 0, + 1, 0x1F05, 0x1F01, 0x0301, 0, + 1, 0x1F06, 0x1F00, 0x0342, 0, + 1, 0x1F07, 0x1F01, 0x0342, 0, + 1, 0x1F08, 0x0391, 0x0313, 0, + 1, 0x1F09, 0x0391, 0x0314, 0, + 1, 0x1F0A, 0x1F08, 0x0300, 0, + 1, 0x1F0B, 0x1F09, 0x0300, 0, + 1, 0x1F0C, 0x1F08, 0x0301, 0, + 1, 0x1F0D, 0x1F09, 0x0301, 0, + 1, 0x1F0E, 0x1F08, 0x0342, 0, + 1, 0x1F0F, 0x1F09, 0x0342, 0, + 1, 0x1F10, 0x03B5, 0x0313, 0, + 1, 0x1F11, 0x03B5, 0x0314, 0, + 1, 0x1F12, 0x1F10, 0x0300, 0, + 1, 0x1F13, 0x1F11, 0x0300, 0, + 1, 0x1F14, 0x1F10, 0x0301, 0, + 1, 0x1F15, 0x1F11, 0x0301, 0, + 1, 0x1F18, 0x0395, 0x0313, 0, + 1, 0x1F19, 0x0395, 0x0314, 0, + 1, 0x1F1A, 0x1F18, 0x0300, 0, + 1, 0x1F1B, 0x1F19, 0x0300, 0, + 1, 0x1F1C, 0x1F18, 0x0301, 0, + 1, 0x1F1D, 0x1F19, 0x0301, 0, + 1, 0x1F20, 0x03B7, 0x0313, 0, + 1, 0x1F21, 0x03B7, 0x0314, 0, + 1, 0x1F22, 0x1F20, 0x0300, 0, + 1, 0x1F23, 0x1F21, 0x0300, 0, + 1, 0x1F24, 0x1F20, 0x0301, 0, + 1, 0x1F25, 0x1F21, 0x0301, 0, + 1, 0x1F26, 0x1F20, 0x0342, 0, + 1, 0x1F27, 0x1F21, 0x0342, 0, + 1, 0x1F28, 0x0397, 0x0313, 0, + 1, 0x1F29, 0x0397, 0x0314, 0, + 1, 0x1F2A, 0x1F28, 0x0300, 0, + 1, 0x1F2B, 0x1F29, 0x0300, 0, + 1, 0x1F2C, 0x1F28, 0x0301, 0, + 1, 0x1F2D, 0x1F29, 0x0301, 0, + 1, 0x1F2E, 0x1F28, 0x0342, 0, + 1, 0x1F2F, 0x1F29, 0x0342, 0, + 1, 0x1F30, 0x03B9, 0x0313, 0, + 1, 0x1F31, 0x03B9, 0x0314, 0, + 1, 0x1F32, 0x1F30, 0x0300, 0, + 1, 0x1F33, 0x1F31, 0x0300, 0, + 1, 0x1F34, 0x1F30, 0x0301, 0, + 1, 0x1F35, 0x1F31, 0x0301, 0, + 1, 0x1F36, 0x1F30, 0x0342, 0, + 1, 0x1F37, 0x1F31, 0x0342, 0, + 1, 0x1F38, 0x0399, 0x0313, 0, + 1, 0x1F39, 0x0399, 0x0314, 0, + 1, 0x1F3A, 0x1F38, 0x0300, 0, + 1, 0x1F3B, 0x1F39, 0x0300, 0, + 1, 0x1F3C, 0x1F38, 0x0301, 0, + 1, 0x1F3D, 0x1F39, 0x0301, 0, + 1, 0x1F3E, 0x1F38, 0x0342, 0, + 1, 0x1F3F, 0x1F39, 0x0342, 0, + 1, 0x1F40, 0x03BF, 0x0313, 0, + 1, 0x1F41, 0x03BF, 0x0314, 0, + 1, 0x1F42, 0x1F40, 0x0300, 0, + 1, 0x1F43, 0x1F41, 0x0300, 0, + 1, 0x1F44, 0x1F40, 0x0301, 0, + 1, 0x1F45, 0x1F41, 0x0301, 0, + 1, 0x1F48, 0x039F, 0x0313, 0, + 1, 0x1F49, 0x039F, 0x0314, 0, + 1, 0x1F4A, 0x1F48, 0x0300, 0, + 1, 0x1F4B, 0x1F49, 0x0300, 0, + 1, 0x1F4C, 0x1F48, 0x0301, 0, + 1, 0x1F4D, 0x1F49, 0x0301, 0, + 1, 0x1F50, 0x03C5, 0x0313, 0, + 1, 0x1F51, 0x03C5, 0x0314, 0, + 1, 0x1F52, 0x1F50, 0x0300, 0, + 1, 0x1F53, 0x1F51, 0x0300, 0, + 1, 0x1F54, 0x1F50, 0x0301, 0, + 1, 0x1F55, 0x1F51, 0x0301, 0, + 1, 0x1F56, 0x1F50, 0x0342, 0, + 1, 0x1F57, 0x1F51, 0x0342, 0, + 1, 0x1F59, 0x03A5, 0x0314, 0, + 1, 0x1F5B, 0x1F59, 0x0300, 0, + 1, 0x1F5D, 0x1F59, 0x0301, 0, + 1, 0x1F5F, 0x1F59, 0x0342, 0, + 1, 0x1F60, 0x03C9, 0x0313, 0, + 1, 0x1F61, 0x03C9, 0x0314, 0, + 1, 0x1F62, 0x1F60, 0x0300, 0, + 1, 0x1F63, 0x1F61, 0x0300, 0, + 1, 0x1F64, 0x1F60, 0x0301, 0, + 1, 0x1F65, 0x1F61, 0x0301, 0, + 1, 0x1F66, 0x1F60, 0x0342, 0, + 1, 0x1F67, 0x1F61, 0x0342, 0, + 1, 0x1F68, 0x03A9, 0x0313, 0, + 1, 0x1F69, 0x03A9, 0x0314, 0, + 1, 0x1F6A, 0x1F68, 0x0300, 0, + 1, 0x1F6B, 0x1F69, 0x0300, 0, + 1, 0x1F6C, 0x1F68, 0x0301, 0, + 1, 0x1F6D, 0x1F69, 0x0301, 0, + 1, 0x1F6E, 0x1F68, 0x0342, 0, + 1, 0x1F6F, 0x1F69, 0x0342, 0, + 1, 0x1F70, 0x03B1, 0x0300, 0, + 1, 0x1F71, 0x03AC, 0, + 1, 0x1F72, 0x03B5, 0x0300, 0, + 1, 0x1F73, 0x03AD, 0, + 1, 0x1F74, 0x03B7, 0x0300, 0, + 1, 0x1F75, 0x03AE, 0, + 1, 0x1F76, 0x03B9, 0x0300, 0, + 1, 0x1F77, 0x03AF, 0, + 1, 0x1F78, 0x03BF, 0x0300, 0, + 1, 0x1F79, 0x03CC, 0, + 1, 0x1F7A, 0x03C5, 0x0300, 0, + 1, 0x1F7B, 0x03CD, 0, + 1, 0x1F7C, 0x03C9, 0x0300, 0, + 1, 0x1F7D, 0x03CE, 0, + 1, 0x1F80, 0x1F00, 0x0345, 0, + 1, 0x1F81, 0x1F01, 0x0345, 0, + 1, 0x1F82, 0x1F02, 0x0345, 0, + 1, 0x1F83, 0x1F03, 0x0345, 0, + 1, 0x1F84, 0x1F04, 0x0345, 0, + 1, 0x1F85, 0x1F05, 0x0345, 0, + 1, 0x1F86, 0x1F06, 0x0345, 0, + 1, 0x1F87, 0x1F07, 0x0345, 0, + 1, 0x1F88, 0x1F08, 0x0345, 0, + 1, 0x1F89, 0x1F09, 0x0345, 0, + 1, 0x1F8A, 0x1F0A, 0x0345, 0, + 1, 0x1F8B, 0x1F0B, 0x0345, 0, + 1, 0x1F8C, 0x1F0C, 0x0345, 0, + 1, 0x1F8D, 0x1F0D, 0x0345, 0, + 1, 0x1F8E, 0x1F0E, 0x0345, 0, + 1, 0x1F8F, 0x1F0F, 0x0345, 0, + 1, 0x1F90, 0x1F20, 0x0345, 0, + 1, 0x1F91, 0x1F21, 0x0345, 0, + 1, 0x1F92, 0x1F22, 0x0345, 0, + 1, 0x1F93, 0x1F23, 0x0345, 0, + 1, 0x1F94, 0x1F24, 0x0345, 0, + 1, 0x1F95, 0x1F25, 0x0345, 0, + 1, 0x1F96, 0x1F26, 0x0345, 0, + 1, 0x1F97, 0x1F27, 0x0345, 0, + 1, 0x1F98, 0x1F28, 0x0345, 0, + 1, 0x1F99, 0x1F29, 0x0345, 0, + 1, 0x1F9A, 0x1F2A, 0x0345, 0, + 1, 0x1F9B, 0x1F2B, 0x0345, 0, + 1, 0x1F9C, 0x1F2C, 0x0345, 0, + 1, 0x1F9D, 0x1F2D, 0x0345, 0, + 1, 0x1F9E, 0x1F2E, 0x0345, 0, + 1, 0x1F9F, 0x1F2F, 0x0345, 0, + 1, 0x1FA0, 0x1F60, 0x0345, 0, + 1, 0x1FA1, 0x1F61, 0x0345, 0, + 1, 0x1FA2, 0x1F62, 0x0345, 0, + 1, 0x1FA3, 0x1F63, 0x0345, 0, + 1, 0x1FA4, 0x1F64, 0x0345, 0, + 1, 0x1FA5, 0x1F65, 0x0345, 0, + 1, 0x1FA6, 0x1F66, 0x0345, 0, + 1, 0x1FA7, 0x1F67, 0x0345, 0, + 1, 0x1FA8, 0x1F68, 0x0345, 0, + 1, 0x1FA9, 0x1F69, 0x0345, 0, + 1, 0x1FAA, 0x1F6A, 0x0345, 0, + 1, 0x1FAB, 0x1F6B, 0x0345, 0, + 1, 0x1FAC, 0x1F6C, 0x0345, 0, + 1, 0x1FAD, 0x1F6D, 0x0345, 0, + 1, 0x1FAE, 0x1F6E, 0x0345, 0, + 1, 0x1FAF, 0x1F6F, 0x0345, 0, + 1, 0x1FB0, 0x03B1, 0x0306, 0, + 1, 0x1FB1, 0x03B1, 0x0304, 0, + 1, 0x1FB2, 0x1F70, 0x0345, 0, + 1, 0x1FB3, 0x03B1, 0x0345, 0, + 1, 0x1FB4, 0x03AC, 0x0345, 0, + 1, 0x1FB6, 0x03B1, 0x0342, 0, + 1, 0x1FB7, 0x1FB6, 0x0345, 0, + 1, 0x1FB8, 0x0391, 0x0306, 0, + 1, 0x1FB9, 0x0391, 0x0304, 0, + 1, 0x1FBA, 0x0391, 0x0300, 0, + 1, 0x1FBB, 0x0386, 0, + 1, 0x1FBC, 0x0391, 0x0345, 0, + 16, 0x1FBD, 0x0020, 0x0313, 0, + 1, 0x1FBE, 0x03B9, 0, + 16, 0x1FBF, 0x0020, 0x0313, 0, + 16, 0x1FC0, 0x0020, 0x0342, 0, + 1, 0x1FC1, 0x00A8, 0x0342, 0, + 1, 0x1FC2, 0x1F74, 0x0345, 0, + 1, 0x1FC3, 0x03B7, 0x0345, 0, + 1, 0x1FC4, 0x03AE, 0x0345, 0, + 1, 0x1FC6, 0x03B7, 0x0342, 0, + 1, 0x1FC7, 0x1FC6, 0x0345, 0, + 1, 0x1FC8, 0x0395, 0x0300, 0, + 1, 0x1FC9, 0x0388, 0, + 1, 0x1FCA, 0x0397, 0x0300, 0, + 1, 0x1FCB, 0x0389, 0, + 1, 0x1FCC, 0x0397, 0x0345, 0, + 1, 0x1FCD, 0x1FBF, 0x0300, 0, + 1, 0x1FCE, 0x1FBF, 0x0301, 0, + 1, 0x1FCF, 0x1FBF, 0x0342, 0, + 1, 0x1FD0, 0x03B9, 0x0306, 0, + 1, 0x1FD1, 0x03B9, 0x0304, 0, + 1, 0x1FD2, 0x03CA, 0x0300, 0, + 1, 0x1FD3, 0x0390, 0, + 1, 0x1FD6, 0x03B9, 0x0342, 0, + 1, 0x1FD7, 0x03CA, 0x0342, 0, + 1, 0x1FD8, 0x0399, 0x0306, 0, + 1, 0x1FD9, 0x0399, 0x0304, 0, + 1, 0x1FDA, 0x0399, 0x0300, 0, + 1, 0x1FDB, 0x038A, 0, + 1, 0x1FDD, 0x1FFE, 0x0300, 0, + 1, 0x1FDE, 0x1FFE, 0x0301, 0, + 1, 0x1FDF, 0x1FFE, 0x0342, 0, + 1, 0x1FE0, 0x03C5, 0x0306, 0, + 1, 0x1FE1, 0x03C5, 0x0304, 0, + 1, 0x1FE2, 0x03CB, 0x0300, 0, + 1, 0x1FE3, 0x03B0, 0, + 1, 0x1FE4, 0x03C1, 0x0313, 0, + 1, 0x1FE5, 0x03C1, 0x0314, 0, + 1, 0x1FE6, 0x03C5, 0x0342, 0, + 1, 0x1FE7, 0x03CB, 0x0342, 0, + 1, 0x1FE8, 0x03A5, 0x0306, 0, + 1, 0x1FE9, 0x03A5, 0x0304, 0, + 1, 0x1FEA, 0x03A5, 0x0300, 0, + 1, 0x1FEB, 0x038E, 0, + 1, 0x1FEC, 0x03A1, 0x0314, 0, + 1, 0x1FED, 0x00A8, 0x0300, 0, + 1, 0x1FEE, 0x0385, 0, + 1, 0x1FEF, 0x0060, 0, + 1, 0x1FF2, 0x1F7C, 0x0345, 0, + 1, 0x1FF3, 0x03C9, 0x0345, 0, + 1, 0x1FF4, 0x03CE, 0x0345, 0, + 1, 0x1FF6, 0x03C9, 0x0342, 0, + 1, 0x1FF7, 0x1FF6, 0x0345, 0, + 1, 0x1FF8, 0x039F, 0x0300, 0, + 1, 0x1FF9, 0x038C, 0, + 1, 0x1FFA, 0x03A9, 0x0300, 0, + 1, 0x1FFB, 0x038F, 0, + 1, 0x1FFC, 0x03A9, 0x0345, 0, + 1, 0x1FFD, 0x00B4, 0, + 16, 0x1FFE, 0x0020, 0x0314, 0, + 1, 0x2000, 0x2002, 0, + 1, 0x2001, 0x2003, 0, + 16, 0x2002, 0x0020, 0, + 16, 0x2003, 0x0020, 0, + 16, 0x2004, 0x0020, 0, + 16, 0x2005, 0x0020, 0, + 16, 0x2006, 0x0020, 0, + 3, 0x2007, 0x0020, 0, + 16, 0x2008, 0x0020, 0, + 16, 0x2009, 0x0020, 0, + 16, 0x200A, 0x0020, 0, + 3, 0x2011, 0x2010, 0, + 16, 0x2017, 0x0020, 0x0333, 0, + 16, 0x2024, 0x002E, 0, + 16, 0x2025, 0x002E, 0x002E, 0, + 16, 0x2026, 0x002E, 0x002E, 0x002E, 0, + 3, 0x202F, 0x0020, 0, + 16, 0x2033, 0x2032, 0x2032, 0, + 16, 0x2034, 0x2032, 0x2032, 0x2032, 0, + 16, 0x2036, 0x2035, 0x2035, 0, + 16, 0x2037, 0x2035, 0x2035, 0x2035, 0, + 16, 0x203C, 0x0021, 0x0021, 0, + 16, 0x203E, 0x0020, 0x0305, 0, + 16, 0x2048, 0x003F, 0x0021, 0, + 16, 0x2049, 0x0021, 0x003F, 0, + 9, 0x2070, 0x0030, 0, + 9, 0x2074, 0x0034, 0, + 9, 0x2075, 0x0035, 0, + 9, 0x2076, 0x0036, 0, + 9, 0x2077, 0x0037, 0, + 9, 0x2078, 0x0038, 0, + 9, 0x2079, 0x0039, 0, + 9, 0x207A, 0x002B, 0, + 9, 0x207B, 0x2212, 0, + 9, 0x207C, 0x003D, 0, + 9, 0x207D, 0x0028, 0, + 9, 0x207E, 0x0029, 0, + 9, 0x207F, 0x006E, 0, + 10, 0x2080, 0x0030, 0, + 10, 0x2081, 0x0031, 0, + 10, 0x2082, 0x0032, 0, + 10, 0x2083, 0x0033, 0, + 10, 0x2084, 0x0034, 0, + 10, 0x2085, 0x0035, 0, + 10, 0x2086, 0x0036, 0, + 10, 0x2087, 0x0037, 0, + 10, 0x2088, 0x0038, 0, + 10, 0x2089, 0x0039, 0, + 10, 0x208A, 0x002B, 0, + 10, 0x208B, 0x2212, 0, + 10, 0x208C, 0x003D, 0, + 10, 0x208D, 0x0028, 0, + 10, 0x208E, 0x0029, 0, + 16, 0x20A8, 0x0052, 0x0073, 0, + 16, 0x2100, 0x0061, 0x002F, 0x0063, 0, + 16, 0x2101, 0x0061, 0x002F, 0x0073, 0, + 2, 0x2102, 0x0043, 0, + 16, 0x2103, 0x00B0, 0x0043, 0, + 16, 0x2105, 0x0063, 0x002F, 0x006F, 0, + 16, 0x2106, 0x0063, 0x002F, 0x0075, 0, + 16, 0x2107, 0x0190, 0, + 16, 0x2109, 0x00B0, 0x0046, 0, + 2, 0x210A, 0x0067, 0, + 2, 0x210B, 0x0048, 0, + 2, 0x210C, 0x0048, 0, + 2, 0x210D, 0x0048, 0, + 2, 0x210E, 0x0068, 0, + 2, 0x210F, 0x0127, 0, + 2, 0x2110, 0x0049, 0, + 2, 0x2111, 0x0049, 0, + 2, 0x2112, 0x004C, 0, + 2, 0x2113, 0x006C, 0, + 2, 0x2115, 0x004E, 0, + 16, 0x2116, 0x004E, 0x006F, 0, + 2, 0x2119, 0x0050, 0, + 2, 0x211A, 0x0051, 0, + 2, 0x211B, 0x0052, 0, + 2, 0x211C, 0x0052, 0, + 2, 0x211D, 0x0052, 0, + 9, 0x2120, 0x0053, 0x004D, 0, + 16, 0x2121, 0x0054, 0x0045, 0x004C, 0, + 9, 0x2122, 0x0054, 0x004D, 0, + 2, 0x2124, 0x005A, 0, + 1, 0x2126, 0x03A9, 0, + 2, 0x2128, 0x005A, 0, + 1, 0x212A, 0x004B, 0, + 1, 0x212B, 0x00C5, 0, + 2, 0x212C, 0x0042, 0, + 2, 0x212D, 0x0043, 0, + 2, 0x212F, 0x0065, 0, + 2, 0x2130, 0x0045, 0, + 2, 0x2131, 0x0046, 0, + 2, 0x2133, 0x004D, 0, + 2, 0x2134, 0x006F, 0, + 16, 0x2135, 0x05D0, 0, + 16, 0x2136, 0x05D1, 0, + 16, 0x2137, 0x05D2, 0, + 16, 0x2138, 0x05D3, 0, + 2, 0x2139, 0x0069, 0, + 17, 0x2153, 0x0031, 0x2044, 0x0033, 0, + 17, 0x2154, 0x0032, 0x2044, 0x0033, 0, + 17, 0x2155, 0x0031, 0x2044, 0x0035, 0, + 17, 0x2156, 0x0032, 0x2044, 0x0035, 0, + 17, 0x2157, 0x0033, 0x2044, 0x0035, 0, + 17, 0x2158, 0x0034, 0x2044, 0x0035, 0, + 17, 0x2159, 0x0031, 0x2044, 0x0036, 0, + 17, 0x215A, 0x0035, 0x2044, 0x0036, 0, + 17, 0x215B, 0x0031, 0x2044, 0x0038, 0, + 17, 0x215C, 0x0033, 0x2044, 0x0038, 0, + 17, 0x215D, 0x0035, 0x2044, 0x0038, 0, + 17, 0x215E, 0x0037, 0x2044, 0x0038, 0, + 17, 0x215F, 0x0031, 0x2044, 0, + 16, 0x2160, 0x0049, 0, + 16, 0x2161, 0x0049, 0x0049, 0, + 16, 0x2162, 0x0049, 0x0049, 0x0049, 0, + 16, 0x2163, 0x0049, 0x0056, 0, + 16, 0x2164, 0x0056, 0, + 16, 0x2165, 0x0056, 0x0049, 0, + 16, 0x2166, 0x0056, 0x0049, 0x0049, 0, + 16, 0x2167, 0x0056, 0x0049, 0x0049, 0x0049, 0, + 16, 0x2168, 0x0049, 0x0058, 0, + 16, 0x2169, 0x0058, 0, + 16, 0x216A, 0x0058, 0x0049, 0, + 16, 0x216B, 0x0058, 0x0049, 0x0049, 0, + 16, 0x216C, 0x004C, 0, + 16, 0x216D, 0x0043, 0, + 16, 0x216E, 0x0044, 0, + 16, 0x216F, 0x004D, 0, + 16, 0x2170, 0x0069, 0, + 16, 0x2171, 0x0069, 0x0069, 0, + 16, 0x2172, 0x0069, 0x0069, 0x0069, 0, + 16, 0x2173, 0x0069, 0x0076, 0, + 16, 0x2174, 0x0076, 0, + 16, 0x2175, 0x0076, 0x0069, 0, + 16, 0x2176, 0x0076, 0x0069, 0x0069, 0, + 16, 0x2177, 0x0076, 0x0069, 0x0069, 0x0069, 0, + 16, 0x2178, 0x0069, 0x0078, 0, + 16, 0x2179, 0x0078, 0, + 16, 0x217A, 0x0078, 0x0069, 0, + 16, 0x217B, 0x0078, 0x0069, 0x0069, 0, + 16, 0x217C, 0x006C, 0, + 16, 0x217D, 0x0063, 0, + 16, 0x217E, 0x0064, 0, + 16, 0x217F, 0x006D, 0, + 1, 0x219A, 0x2190, 0x0338, 0, + 1, 0x219B, 0x2192, 0x0338, 0, + 1, 0x21AE, 0x2194, 0x0338, 0, + 1, 0x21CD, 0x21D0, 0x0338, 0, + 1, 0x21CE, 0x21D4, 0x0338, 0, + 1, 0x21CF, 0x21D2, 0x0338, 0, + 1, 0x2204, 0x2203, 0x0338, 0, + 1, 0x2209, 0x2208, 0x0338, 0, + 1, 0x220C, 0x220B, 0x0338, 0, + 1, 0x2224, 0x2223, 0x0338, 0, + 1, 0x2226, 0x2225, 0x0338, 0, + 16, 0x222C, 0x222B, 0x222B, 0, + 16, 0x222D, 0x222B, 0x222B, 0x222B, 0, + 16, 0x222F, 0x222E, 0x222E, 0, + 16, 0x2230, 0x222E, 0x222E, 0x222E, 0, + 1, 0x2241, 0x223C, 0x0338, 0, + 1, 0x2244, 0x2243, 0x0338, 0, + 1, 0x2247, 0x2245, 0x0338, 0, + 1, 0x2249, 0x2248, 0x0338, 0, + 1, 0x2260, 0x003D, 0x0338, 0, + 1, 0x2262, 0x2261, 0x0338, 0, + 1, 0x226D, 0x224D, 0x0338, 0, + 1, 0x226E, 0x003C, 0x0338, 0, + 1, 0x226F, 0x003E, 0x0338, 0, + 1, 0x2270, 0x2264, 0x0338, 0, + 1, 0x2271, 0x2265, 0x0338, 0, + 1, 0x2274, 0x2272, 0x0338, 0, + 1, 0x2275, 0x2273, 0x0338, 0, + 1, 0x2278, 0x2276, 0x0338, 0, + 1, 0x2279, 0x2277, 0x0338, 0, + 1, 0x2280, 0x227A, 0x0338, 0, + 1, 0x2281, 0x227B, 0x0338, 0, + 1, 0x2284, 0x2282, 0x0338, 0, + 1, 0x2285, 0x2283, 0x0338, 0, + 1, 0x2288, 0x2286, 0x0338, 0, + 1, 0x2289, 0x2287, 0x0338, 0, + 1, 0x22AC, 0x22A2, 0x0338, 0, + 1, 0x22AD, 0x22A8, 0x0338, 0, + 1, 0x22AE, 0x22A9, 0x0338, 0, + 1, 0x22AF, 0x22AB, 0x0338, 0, + 1, 0x22E0, 0x227C, 0x0338, 0, + 1, 0x22E1, 0x227D, 0x0338, 0, + 1, 0x22E2, 0x2291, 0x0338, 0, + 1, 0x22E3, 0x2292, 0x0338, 0, + 1, 0x22EA, 0x22B2, 0x0338, 0, + 1, 0x22EB, 0x22B3, 0x0338, 0, + 1, 0x22EC, 0x22B4, 0x0338, 0, + 1, 0x22ED, 0x22B5, 0x0338, 0, + 1, 0x2329, 0x3008, 0, + 1, 0x232A, 0x3009, 0, + 8, 0x2460, 0x0031, 0, + 8, 0x2461, 0x0032, 0, + 8, 0x2462, 0x0033, 0, + 8, 0x2463, 0x0034, 0, + 8, 0x2464, 0x0035, 0, + 8, 0x2465, 0x0036, 0, + 8, 0x2466, 0x0037, 0, + 8, 0x2467, 0x0038, 0, + 8, 0x2468, 0x0039, 0, + 8, 0x2469, 0x0031, 0x0030, 0, + 8, 0x246A, 0x0031, 0x0031, 0, + 8, 0x246B, 0x0031, 0x0032, 0, + 8, 0x246C, 0x0031, 0x0033, 0, + 8, 0x246D, 0x0031, 0x0034, 0, + 8, 0x246E, 0x0031, 0x0035, 0, + 8, 0x246F, 0x0031, 0x0036, 0, + 8, 0x2470, 0x0031, 0x0037, 0, + 8, 0x2471, 0x0031, 0x0038, 0, + 8, 0x2472, 0x0031, 0x0039, 0, + 8, 0x2473, 0x0032, 0x0030, 0, + 16, 0x2474, 0x0028, 0x0031, 0x0029, 0, + 16, 0x2475, 0x0028, 0x0032, 0x0029, 0, + 16, 0x2476, 0x0028, 0x0033, 0x0029, 0, + 16, 0x2477, 0x0028, 0x0034, 0x0029, 0, + 16, 0x2478, 0x0028, 0x0035, 0x0029, 0, + 16, 0x2479, 0x0028, 0x0036, 0x0029, 0, + 16, 0x247A, 0x0028, 0x0037, 0x0029, 0, + 16, 0x247B, 0x0028, 0x0038, 0x0029, 0, + 16, 0x247C, 0x0028, 0x0039, 0x0029, 0, + 16, 0x247D, 0x0028, 0x0031, 0x0030, 0x0029, 0, + 16, 0x247E, 0x0028, 0x0031, 0x0031, 0x0029, 0, + 16, 0x247F, 0x0028, 0x0031, 0x0032, 0x0029, 0, + 16, 0x2480, 0x0028, 0x0031, 0x0033, 0x0029, 0, + 16, 0x2481, 0x0028, 0x0031, 0x0034, 0x0029, 0, + 16, 0x2482, 0x0028, 0x0031, 0x0035, 0x0029, 0, + 16, 0x2483, 0x0028, 0x0031, 0x0036, 0x0029, 0, + 16, 0x2484, 0x0028, 0x0031, 0x0037, 0x0029, 0, + 16, 0x2485, 0x0028, 0x0031, 0x0038, 0x0029, 0, + 16, 0x2486, 0x0028, 0x0031, 0x0039, 0x0029, 0, + 16, 0x2487, 0x0028, 0x0032, 0x0030, 0x0029, 0, + 16, 0x2488, 0x0031, 0x002E, 0, + 16, 0x2489, 0x0032, 0x002E, 0, + 16, 0x248A, 0x0033, 0x002E, 0, + 16, 0x248B, 0x0034, 0x002E, 0, + 16, 0x248C, 0x0035, 0x002E, 0, + 16, 0x248D, 0x0036, 0x002E, 0, + 16, 0x248E, 0x0037, 0x002E, 0, + 16, 0x248F, 0x0038, 0x002E, 0, + 16, 0x2490, 0x0039, 0x002E, 0, + 16, 0x2491, 0x0031, 0x0030, 0x002E, 0, + 16, 0x2492, 0x0031, 0x0031, 0x002E, 0, + 16, 0x2493, 0x0031, 0x0032, 0x002E, 0, + 16, 0x2494, 0x0031, 0x0033, 0x002E, 0, + 16, 0x2495, 0x0031, 0x0034, 0x002E, 0, + 16, 0x2496, 0x0031, 0x0035, 0x002E, 0, + 16, 0x2497, 0x0031, 0x0036, 0x002E, 0, + 16, 0x2498, 0x0031, 0x0037, 0x002E, 0, + 16, 0x2499, 0x0031, 0x0038, 0x002E, 0, + 16, 0x249A, 0x0031, 0x0039, 0x002E, 0, + 16, 0x249B, 0x0032, 0x0030, 0x002E, 0, + 16, 0x249C, 0x0028, 0x0061, 0x0029, 0, + 16, 0x249D, 0x0028, 0x0062, 0x0029, 0, + 16, 0x249E, 0x0028, 0x0063, 0x0029, 0, + 16, 0x249F, 0x0028, 0x0064, 0x0029, 0, + 16, 0x24A0, 0x0028, 0x0065, 0x0029, 0, + 16, 0x24A1, 0x0028, 0x0066, 0x0029, 0, + 16, 0x24A2, 0x0028, 0x0067, 0x0029, 0, + 16, 0x24A3, 0x0028, 0x0068, 0x0029, 0, + 16, 0x24A4, 0x0028, 0x0069, 0x0029, 0, + 16, 0x24A5, 0x0028, 0x006A, 0x0029, 0, + 16, 0x24A6, 0x0028, 0x006B, 0x0029, 0, + 16, 0x24A7, 0x0028, 0x006C, 0x0029, 0, + 16, 0x24A8, 0x0028, 0x006D, 0x0029, 0, + 16, 0x24A9, 0x0028, 0x006E, 0x0029, 0, + 16, 0x24AA, 0x0028, 0x006F, 0x0029, 0, + 16, 0x24AB, 0x0028, 0x0070, 0x0029, 0, + 16, 0x24AC, 0x0028, 0x0071, 0x0029, 0, + 16, 0x24AD, 0x0028, 0x0072, 0x0029, 0, + 16, 0x24AE, 0x0028, 0x0073, 0x0029, 0, + 16, 0x24AF, 0x0028, 0x0074, 0x0029, 0, + 16, 0x24B0, 0x0028, 0x0075, 0x0029, 0, + 16, 0x24B1, 0x0028, 0x0076, 0x0029, 0, + 16, 0x24B2, 0x0028, 0x0077, 0x0029, 0, + 16, 0x24B3, 0x0028, 0x0078, 0x0029, 0, + 16, 0x24B4, 0x0028, 0x0079, 0x0029, 0, + 16, 0x24B5, 0x0028, 0x007A, 0x0029, 0, + 8, 0x24B6, 0x0041, 0, + 8, 0x24B7, 0x0042, 0, + 8, 0x24B8, 0x0043, 0, + 8, 0x24B9, 0x0044, 0, + 8, 0x24BA, 0x0045, 0, + 8, 0x24BB, 0x0046, 0, + 8, 0x24BC, 0x0047, 0, + 8, 0x24BD, 0x0048, 0, + 8, 0x24BE, 0x0049, 0, + 8, 0x24BF, 0x004A, 0, + 8, 0x24C0, 0x004B, 0, + 8, 0x24C1, 0x004C, 0, + 8, 0x24C2, 0x004D, 0, + 8, 0x24C3, 0x004E, 0, + 8, 0x24C4, 0x004F, 0, + 8, 0x24C5, 0x0050, 0, + 8, 0x24C6, 0x0051, 0, + 8, 0x24C7, 0x0052, 0, + 8, 0x24C8, 0x0053, 0, + 8, 0x24C9, 0x0054, 0, + 8, 0x24CA, 0x0055, 0, + 8, 0x24CB, 0x0056, 0, + 8, 0x24CC, 0x0057, 0, + 8, 0x24CD, 0x0058, 0, + 8, 0x24CE, 0x0059, 0, + 8, 0x24CF, 0x005A, 0, + 8, 0x24D0, 0x0061, 0, + 8, 0x24D1, 0x0062, 0, + 8, 0x24D2, 0x0063, 0, + 8, 0x24D3, 0x0064, 0, + 8, 0x24D4, 0x0065, 0, + 8, 0x24D5, 0x0066, 0, + 8, 0x24D6, 0x0067, 0, + 8, 0x24D7, 0x0068, 0, + 8, 0x24D8, 0x0069, 0, + 8, 0x24D9, 0x006A, 0, + 8, 0x24DA, 0x006B, 0, + 8, 0x24DB, 0x006C, 0, + 8, 0x24DC, 0x006D, 0, + 8, 0x24DD, 0x006E, 0, + 8, 0x24DE, 0x006F, 0, + 8, 0x24DF, 0x0070, 0, + 8, 0x24E0, 0x0071, 0, + 8, 0x24E1, 0x0072, 0, + 8, 0x24E2, 0x0073, 0, + 8, 0x24E3, 0x0074, 0, + 8, 0x24E4, 0x0075, 0, + 8, 0x24E5, 0x0076, 0, + 8, 0x24E6, 0x0077, 0, + 8, 0x24E7, 0x0078, 0, + 8, 0x24E8, 0x0079, 0, + 8, 0x24E9, 0x007A, 0, + 8, 0x24EA, 0x0030, 0, + 16, 0x2E9F, 0x6BCD, 0, + 16, 0x2EF3, 0x9F9F, 0, + 16, 0x2F00, 0x4E00, 0, + 16, 0x2F01, 0x4E28, 0, + 16, 0x2F02, 0x4E36, 0, + 16, 0x2F03, 0x4E3F, 0, + 16, 0x2F04, 0x4E59, 0, + 16, 0x2F05, 0x4E85, 0, + 16, 0x2F06, 0x4E8C, 0, + 16, 0x2F07, 0x4EA0, 0, + 16, 0x2F08, 0x4EBA, 0, + 16, 0x2F09, 0x513F, 0, + 16, 0x2F0A, 0x5165, 0, + 16, 0x2F0B, 0x516B, 0, + 16, 0x2F0C, 0x5182, 0, + 16, 0x2F0D, 0x5196, 0, + 16, 0x2F0E, 0x51AB, 0, + 16, 0x2F0F, 0x51E0, 0, + 16, 0x2F10, 0x51F5, 0, + 16, 0x2F11, 0x5200, 0, + 16, 0x2F12, 0x529B, 0, + 16, 0x2F13, 0x52F9, 0, + 16, 0x2F14, 0x5315, 0, + 16, 0x2F15, 0x531A, 0, + 16, 0x2F16, 0x5338, 0, + 16, 0x2F17, 0x5341, 0, + 16, 0x2F18, 0x535C, 0, + 16, 0x2F19, 0x5369, 0, + 16, 0x2F1A, 0x5382, 0, + 16, 0x2F1B, 0x53B6, 0, + 16, 0x2F1C, 0x53C8, 0, + 16, 0x2F1D, 0x53E3, 0, + 16, 0x2F1E, 0x56D7, 0, + 16, 0x2F1F, 0x571F, 0, + 16, 0x2F20, 0x58EB, 0, + 16, 0x2F21, 0x5902, 0, + 16, 0x2F22, 0x590A, 0, + 16, 0x2F23, 0x5915, 0, + 16, 0x2F24, 0x5927, 0, + 16, 0x2F25, 0x5973, 0, + 16, 0x2F26, 0x5B50, 0, + 16, 0x2F27, 0x5B80, 0, + 16, 0x2F28, 0x5BF8, 0, + 16, 0x2F29, 0x5C0F, 0, + 16, 0x2F2A, 0x5C22, 0, + 16, 0x2F2B, 0x5C38, 0, + 16, 0x2F2C, 0x5C6E, 0, + 16, 0x2F2D, 0x5C71, 0, + 16, 0x2F2E, 0x5DDB, 0, + 16, 0x2F2F, 0x5DE5, 0, + 16, 0x2F30, 0x5DF1, 0, + 16, 0x2F31, 0x5DFE, 0, + 16, 0x2F32, 0x5E72, 0, + 16, 0x2F33, 0x5E7A, 0, + 16, 0x2F34, 0x5E7F, 0, + 16, 0x2F35, 0x5EF4, 0, + 16, 0x2F36, 0x5EFE, 0, + 16, 0x2F37, 0x5F0B, 0, + 16, 0x2F38, 0x5F13, 0, + 16, 0x2F39, 0x5F50, 0, + 16, 0x2F3A, 0x5F61, 0, + 16, 0x2F3B, 0x5F73, 0, + 16, 0x2F3C, 0x5FC3, 0, + 16, 0x2F3D, 0x6208, 0, + 16, 0x2F3E, 0x6236, 0, + 16, 0x2F3F, 0x624B, 0, + 16, 0x2F40, 0x652F, 0, + 16, 0x2F41, 0x6534, 0, + 16, 0x2F42, 0x6587, 0, + 16, 0x2F43, 0x6597, 0, + 16, 0x2F44, 0x65A4, 0, + 16, 0x2F45, 0x65B9, 0, + 16, 0x2F46, 0x65E0, 0, + 16, 0x2F47, 0x65E5, 0, + 16, 0x2F48, 0x66F0, 0, + 16, 0x2F49, 0x6708, 0, + 16, 0x2F4A, 0x6728, 0, + 16, 0x2F4B, 0x6B20, 0, + 16, 0x2F4C, 0x6B62, 0, + 16, 0x2F4D, 0x6B79, 0, + 16, 0x2F4E, 0x6BB3, 0, + 16, 0x2F4F, 0x6BCB, 0, + 16, 0x2F50, 0x6BD4, 0, + 16, 0x2F51, 0x6BDB, 0, + 16, 0x2F52, 0x6C0F, 0, + 16, 0x2F53, 0x6C14, 0, + 16, 0x2F54, 0x6C34, 0, + 16, 0x2F55, 0x706B, 0, + 16, 0x2F56, 0x722A, 0, + 16, 0x2F57, 0x7236, 0, + 16, 0x2F58, 0x723B, 0, + 16, 0x2F59, 0x723F, 0, + 16, 0x2F5A, 0x7247, 0, + 16, 0x2F5B, 0x7259, 0, + 16, 0x2F5C, 0x725B, 0, + 16, 0x2F5D, 0x72AC, 0, + 16, 0x2F5E, 0x7384, 0, + 16, 0x2F5F, 0x7389, 0, + 16, 0x2F60, 0x74DC, 0, + 16, 0x2F61, 0x74E6, 0, + 16, 0x2F62, 0x7518, 0, + 16, 0x2F63, 0x751F, 0, + 16, 0x2F64, 0x7528, 0, + 16, 0x2F65, 0x7530, 0, + 16, 0x2F66, 0x758B, 0, + 16, 0x2F67, 0x7592, 0, + 16, 0x2F68, 0x7676, 0, + 16, 0x2F69, 0x767D, 0, + 16, 0x2F6A, 0x76AE, 0, + 16, 0x2F6B, 0x76BF, 0, + 16, 0x2F6C, 0x76EE, 0, + 16, 0x2F6D, 0x77DB, 0, + 16, 0x2F6E, 0x77E2, 0, + 16, 0x2F6F, 0x77F3, 0, + 16, 0x2F70, 0x793A, 0, + 16, 0x2F71, 0x79B8, 0, + 16, 0x2F72, 0x79BE, 0, + 16, 0x2F73, 0x7A74, 0, + 16, 0x2F74, 0x7ACB, 0, + 16, 0x2F75, 0x7AF9, 0, + 16, 0x2F76, 0x7C73, 0, + 16, 0x2F77, 0x7CF8, 0, + 16, 0x2F78, 0x7F36, 0, + 16, 0x2F79, 0x7F51, 0, + 16, 0x2F7A, 0x7F8A, 0, + 16, 0x2F7B, 0x7FBD, 0, + 16, 0x2F7C, 0x8001, 0, + 16, 0x2F7D, 0x800C, 0, + 16, 0x2F7E, 0x8012, 0, + 16, 0x2F7F, 0x8033, 0, + 16, 0x2F80, 0x807F, 0, + 16, 0x2F81, 0x8089, 0, + 16, 0x2F82, 0x81E3, 0, + 16, 0x2F83, 0x81EA, 0, + 16, 0x2F84, 0x81F3, 0, + 16, 0x2F85, 0x81FC, 0, + 16, 0x2F86, 0x820C, 0, + 16, 0x2F87, 0x821B, 0, + 16, 0x2F88, 0x821F, 0, + 16, 0x2F89, 0x826E, 0, + 16, 0x2F8A, 0x8272, 0, + 16, 0x2F8B, 0x8278, 0, + 16, 0x2F8C, 0x864D, 0, + 16, 0x2F8D, 0x866B, 0, + 16, 0x2F8E, 0x8840, 0, + 16, 0x2F8F, 0x884C, 0, + 16, 0x2F90, 0x8863, 0, + 16, 0x2F91, 0x897E, 0, + 16, 0x2F92, 0x898B, 0, + 16, 0x2F93, 0x89D2, 0, + 16, 0x2F94, 0x8A00, 0, + 16, 0x2F95, 0x8C37, 0, + 16, 0x2F96, 0x8C46, 0, + 16, 0x2F97, 0x8C55, 0, + 16, 0x2F98, 0x8C78, 0, + 16, 0x2F99, 0x8C9D, 0, + 16, 0x2F9A, 0x8D64, 0, + 16, 0x2F9B, 0x8D70, 0, + 16, 0x2F9C, 0x8DB3, 0, + 16, 0x2F9D, 0x8EAB, 0, + 16, 0x2F9E, 0x8ECA, 0, + 16, 0x2F9F, 0x8F9B, 0, + 16, 0x2FA0, 0x8FB0, 0, + 16, 0x2FA1, 0x8FB5, 0, + 16, 0x2FA2, 0x9091, 0, + 16, 0x2FA3, 0x9149, 0, + 16, 0x2FA4, 0x91C6, 0, + 16, 0x2FA5, 0x91CC, 0, + 16, 0x2FA6, 0x91D1, 0, + 16, 0x2FA7, 0x9577, 0, + 16, 0x2FA8, 0x9580, 0, + 16, 0x2FA9, 0x961C, 0, + 16, 0x2FAA, 0x96B6, 0, + 16, 0x2FAB, 0x96B9, 0, + 16, 0x2FAC, 0x96E8, 0, + 16, 0x2FAD, 0x9751, 0, + 16, 0x2FAE, 0x975E, 0, + 16, 0x2FAF, 0x9762, 0, + 16, 0x2FB0, 0x9769, 0, + 16, 0x2FB1, 0x97CB, 0, + 16, 0x2FB2, 0x97ED, 0, + 16, 0x2FB3, 0x97F3, 0, + 16, 0x2FB4, 0x9801, 0, + 16, 0x2FB5, 0x98A8, 0, + 16, 0x2FB6, 0x98DB, 0, + 16, 0x2FB7, 0x98DF, 0, + 16, 0x2FB8, 0x9996, 0, + 16, 0x2FB9, 0x9999, 0, + 16, 0x2FBA, 0x99AC, 0, + 16, 0x2FBB, 0x9AA8, 0, + 16, 0x2FBC, 0x9AD8, 0, + 16, 0x2FBD, 0x9ADF, 0, + 16, 0x2FBE, 0x9B25, 0, + 16, 0x2FBF, 0x9B2F, 0, + 16, 0x2FC0, 0x9B32, 0, + 16, 0x2FC1, 0x9B3C, 0, + 16, 0x2FC2, 0x9B5A, 0, + 16, 0x2FC3, 0x9CE5, 0, + 16, 0x2FC4, 0x9E75, 0, + 16, 0x2FC5, 0x9E7F, 0, + 16, 0x2FC6, 0x9EA5, 0, + 16, 0x2FC7, 0x9EBB, 0, + 16, 0x2FC8, 0x9EC3, 0, + 16, 0x2FC9, 0x9ECD, 0, + 16, 0x2FCA, 0x9ED1, 0, + 16, 0x2FCB, 0x9EF9, 0, + 16, 0x2FCC, 0x9EFD, 0, + 16, 0x2FCD, 0x9F0E, 0, + 16, 0x2FCE, 0x9F13, 0, + 16, 0x2FCF, 0x9F20, 0, + 16, 0x2FD0, 0x9F3B, 0, + 16, 0x2FD1, 0x9F4A, 0, + 16, 0x2FD2, 0x9F52, 0, + 16, 0x2FD3, 0x9F8D, 0, + 16, 0x2FD4, 0x9F9C, 0, + 16, 0x2FD5, 0x9FA0, 0, + 12, 0x3000, 0x0020, 0, + 16, 0x3036, 0x3012, 0, + 16, 0x3038, 0x5341, 0, + 16, 0x3039, 0x5344, 0, + 16, 0x303A, 0x5345, 0, + 1, 0x304C, 0x304B, 0x3099, 0, + 1, 0x304E, 0x304D, 0x3099, 0, + 1, 0x3050, 0x304F, 0x3099, 0, + 1, 0x3052, 0x3051, 0x3099, 0, + 1, 0x3054, 0x3053, 0x3099, 0, + 1, 0x3056, 0x3055, 0x3099, 0, + 1, 0x3058, 0x3057, 0x3099, 0, + 1, 0x305A, 0x3059, 0x3099, 0, + 1, 0x305C, 0x305B, 0x3099, 0, + 1, 0x305E, 0x305D, 0x3099, 0, + 1, 0x3060, 0x305F, 0x3099, 0, + 1, 0x3062, 0x3061, 0x3099, 0, + 1, 0x3065, 0x3064, 0x3099, 0, + 1, 0x3067, 0x3066, 0x3099, 0, + 1, 0x3069, 0x3068, 0x3099, 0, + 1, 0x3070, 0x306F, 0x3099, 0, + 1, 0x3071, 0x306F, 0x309A, 0, + 1, 0x3073, 0x3072, 0x3099, 0, + 1, 0x3074, 0x3072, 0x309A, 0, + 1, 0x3076, 0x3075, 0x3099, 0, + 1, 0x3077, 0x3075, 0x309A, 0, + 1, 0x3079, 0x3078, 0x3099, 0, + 1, 0x307A, 0x3078, 0x309A, 0, + 1, 0x307C, 0x307B, 0x3099, 0, + 1, 0x307D, 0x307B, 0x309A, 0, + 1, 0x3094, 0x3046, 0x3099, 0, + 16, 0x309B, 0x0020, 0x3099, 0, + 16, 0x309C, 0x0020, 0x309A, 0, + 1, 0x309E, 0x309D, 0x3099, 0, + 1, 0x30AC, 0x30AB, 0x3099, 0, + 1, 0x30AE, 0x30AD, 0x3099, 0, + 1, 0x30B0, 0x30AF, 0x3099, 0, + 1, 0x30B2, 0x30B1, 0x3099, 0, + 1, 0x30B4, 0x30B3, 0x3099, 0, + 1, 0x30B6, 0x30B5, 0x3099, 0, + 1, 0x30B8, 0x30B7, 0x3099, 0, + 1, 0x30BA, 0x30B9, 0x3099, 0, + 1, 0x30BC, 0x30BB, 0x3099, 0, + 1, 0x30BE, 0x30BD, 0x3099, 0, + 1, 0x30C0, 0x30BF, 0x3099, 0, + 1, 0x30C2, 0x30C1, 0x3099, 0, + 1, 0x30C5, 0x30C4, 0x3099, 0, + 1, 0x30C7, 0x30C6, 0x3099, 0, + 1, 0x30C9, 0x30C8, 0x3099, 0, + 1, 0x30D0, 0x30CF, 0x3099, 0, + 1, 0x30D1, 0x30CF, 0x309A, 0, + 1, 0x30D3, 0x30D2, 0x3099, 0, + 1, 0x30D4, 0x30D2, 0x309A, 0, + 1, 0x30D6, 0x30D5, 0x3099, 0, + 1, 0x30D7, 0x30D5, 0x309A, 0, + 1, 0x30D9, 0x30D8, 0x3099, 0, + 1, 0x30DA, 0x30D8, 0x309A, 0, + 1, 0x30DC, 0x30DB, 0x3099, 0, + 1, 0x30DD, 0x30DB, 0x309A, 0, + 1, 0x30F4, 0x30A6, 0x3099, 0, + 1, 0x30F7, 0x30EF, 0x3099, 0, + 1, 0x30F8, 0x30F0, 0x3099, 0, + 1, 0x30F9, 0x30F1, 0x3099, 0, + 1, 0x30FA, 0x30F2, 0x3099, 0, + 1, 0x30FE, 0x30FD, 0x3099, 0, + 16, 0x3131, 0x1100, 0, + 16, 0x3132, 0x1101, 0, + 16, 0x3133, 0x11AA, 0, + 16, 0x3134, 0x1102, 0, + 16, 0x3135, 0x11AC, 0, + 16, 0x3136, 0x11AD, 0, + 16, 0x3137, 0x1103, 0, + 16, 0x3138, 0x1104, 0, + 16, 0x3139, 0x1105, 0, + 16, 0x313A, 0x11B0, 0, + 16, 0x313B, 0x11B1, 0, + 16, 0x313C, 0x11B2, 0, + 16, 0x313D, 0x11B3, 0, + 16, 0x313E, 0x11B4, 0, + 16, 0x313F, 0x11B5, 0, + 16, 0x3140, 0x111A, 0, + 16, 0x3141, 0x1106, 0, + 16, 0x3142, 0x1107, 0, + 16, 0x3143, 0x1108, 0, + 16, 0x3144, 0x1121, 0, + 16, 0x3145, 0x1109, 0, + 16, 0x3146, 0x110A, 0, + 16, 0x3147, 0x110B, 0, + 16, 0x3148, 0x110C, 0, + 16, 0x3149, 0x110D, 0, + 16, 0x314A, 0x110E, 0, + 16, 0x314B, 0x110F, 0, + 16, 0x314C, 0x1110, 0, + 16, 0x314D, 0x1111, 0, + 16, 0x314E, 0x1112, 0, + 16, 0x314F, 0x1161, 0, + 16, 0x3150, 0x1162, 0, + 16, 0x3151, 0x1163, 0, + 16, 0x3152, 0x1164, 0, + 16, 0x3153, 0x1165, 0, + 16, 0x3154, 0x1166, 0, + 16, 0x3155, 0x1167, 0, + 16, 0x3156, 0x1168, 0, + 16, 0x3157, 0x1169, 0, + 16, 0x3158, 0x116A, 0, + 16, 0x3159, 0x116B, 0, + 16, 0x315A, 0x116C, 0, + 16, 0x315B, 0x116D, 0, + 16, 0x315C, 0x116E, 0, + 16, 0x315D, 0x116F, 0, + 16, 0x315E, 0x1170, 0, + 16, 0x315F, 0x1171, 0, + 16, 0x3160, 0x1172, 0, + 16, 0x3161, 0x1173, 0, + 16, 0x3162, 0x1174, 0, + 16, 0x3163, 0x1175, 0, + 16, 0x3164, 0x1160, 0, + 16, 0x3165, 0x1114, 0, + 16, 0x3166, 0x1115, 0, + 16, 0x3167, 0x11C7, 0, + 16, 0x3168, 0x11C8, 0, + 16, 0x3169, 0x11CC, 0, + 16, 0x316A, 0x11CE, 0, + 16, 0x316B, 0x11D3, 0, + 16, 0x316C, 0x11D7, 0, + 16, 0x316D, 0x11D9, 0, + 16, 0x316E, 0x111C, 0, + 16, 0x316F, 0x11DD, 0, + 16, 0x3170, 0x11DF, 0, + 16, 0x3171, 0x111D, 0, + 16, 0x3172, 0x111E, 0, + 16, 0x3173, 0x1120, 0, + 16, 0x3174, 0x1122, 0, + 16, 0x3175, 0x1123, 0, + 16, 0x3176, 0x1127, 0, + 16, 0x3177, 0x1129, 0, + 16, 0x3178, 0x112B, 0, + 16, 0x3179, 0x112C, 0, + 16, 0x317A, 0x112D, 0, + 16, 0x317B, 0x112E, 0, + 16, 0x317C, 0x112F, 0, + 16, 0x317D, 0x1132, 0, + 16, 0x317E, 0x1136, 0, + 16, 0x317F, 0x1140, 0, + 16, 0x3180, 0x1147, 0, + 16, 0x3181, 0x114C, 0, + 16, 0x3182, 0x11F1, 0, + 16, 0x3183, 0x11F2, 0, + 16, 0x3184, 0x1157, 0, + 16, 0x3185, 0x1158, 0, + 16, 0x3186, 0x1159, 0, + 16, 0x3187, 0x1184, 0, + 16, 0x3188, 0x1185, 0, + 16, 0x3189, 0x1188, 0, + 16, 0x318A, 0x1191, 0, + 16, 0x318B, 0x1192, 0, + 16, 0x318C, 0x1194, 0, + 16, 0x318D, 0x119E, 0, + 16, 0x318E, 0x11A1, 0, + 9, 0x3192, 0x4E00, 0, + 9, 0x3193, 0x4E8C, 0, + 9, 0x3194, 0x4E09, 0, + 9, 0x3195, 0x56DB, 0, + 9, 0x3196, 0x4E0A, 0, + 9, 0x3197, 0x4E2D, 0, + 9, 0x3198, 0x4E0B, 0, + 9, 0x3199, 0x7532, 0, + 9, 0x319A, 0x4E59, 0, + 9, 0x319B, 0x4E19, 0, + 9, 0x319C, 0x4E01, 0, + 9, 0x319D, 0x5929, 0, + 9, 0x319E, 0x5730, 0, + 9, 0x319F, 0x4EBA, 0, + 16, 0x3200, 0x0028, 0x1100, 0x0029, 0, + 16, 0x3201, 0x0028, 0x1102, 0x0029, 0, + 16, 0x3202, 0x0028, 0x1103, 0x0029, 0, + 16, 0x3203, 0x0028, 0x1105, 0x0029, 0, + 16, 0x3204, 0x0028, 0x1106, 0x0029, 0, + 16, 0x3205, 0x0028, 0x1107, 0x0029, 0, + 16, 0x3206, 0x0028, 0x1109, 0x0029, 0, + 16, 0x3207, 0x0028, 0x110B, 0x0029, 0, + 16, 0x3208, 0x0028, 0x110C, 0x0029, 0, + 16, 0x3209, 0x0028, 0x110E, 0x0029, 0, + 16, 0x320A, 0x0028, 0x110F, 0x0029, 0, + 16, 0x320B, 0x0028, 0x1110, 0x0029, 0, + 16, 0x320C, 0x0028, 0x1111, 0x0029, 0, + 16, 0x320D, 0x0028, 0x1112, 0x0029, 0, + 16, 0x320E, 0x0028, 0x1100, 0x1161, 0x0029, 0, + 16, 0x320F, 0x0028, 0x1102, 0x1161, 0x0029, 0, + 16, 0x3210, 0x0028, 0x1103, 0x1161, 0x0029, 0, + 16, 0x3211, 0x0028, 0x1105, 0x1161, 0x0029, 0, + 16, 0x3212, 0x0028, 0x1106, 0x1161, 0x0029, 0, + 16, 0x3213, 0x0028, 0x1107, 0x1161, 0x0029, 0, + 16, 0x3214, 0x0028, 0x1109, 0x1161, 0x0029, 0, + 16, 0x3215, 0x0028, 0x110B, 0x1161, 0x0029, 0, + 16, 0x3216, 0x0028, 0x110C, 0x1161, 0x0029, 0, + 16, 0x3217, 0x0028, 0x110E, 0x1161, 0x0029, 0, + 16, 0x3218, 0x0028, 0x110F, 0x1161, 0x0029, 0, + 16, 0x3219, 0x0028, 0x1110, 0x1161, 0x0029, 0, + 16, 0x321A, 0x0028, 0x1111, 0x1161, 0x0029, 0, + 16, 0x321B, 0x0028, 0x1112, 0x1161, 0x0029, 0, + 16, 0x321C, 0x0028, 0x110C, 0x116E, 0x0029, 0, + 16, 0x3220, 0x0028, 0x4E00, 0x0029, 0, + 16, 0x3221, 0x0028, 0x4E8C, 0x0029, 0, + 16, 0x3222, 0x0028, 0x4E09, 0x0029, 0, + 16, 0x3223, 0x0028, 0x56DB, 0x0029, 0, + 16, 0x3224, 0x0028, 0x4E94, 0x0029, 0, + 16, 0x3225, 0x0028, 0x516D, 0x0029, 0, + 16, 0x3226, 0x0028, 0x4E03, 0x0029, 0, + 16, 0x3227, 0x0028, 0x516B, 0x0029, 0, + 16, 0x3228, 0x0028, 0x4E5D, 0x0029, 0, + 16, 0x3229, 0x0028, 0x5341, 0x0029, 0, + 16, 0x322A, 0x0028, 0x6708, 0x0029, 0, + 16, 0x322B, 0x0028, 0x706B, 0x0029, 0, + 16, 0x322C, 0x0028, 0x6C34, 0x0029, 0, + 16, 0x322D, 0x0028, 0x6728, 0x0029, 0, + 16, 0x322E, 0x0028, 0x91D1, 0x0029, 0, + 16, 0x322F, 0x0028, 0x571F, 0x0029, 0, + 16, 0x3230, 0x0028, 0x65E5, 0x0029, 0, + 16, 0x3231, 0x0028, 0x682A, 0x0029, 0, + 16, 0x3232, 0x0028, 0x6709, 0x0029, 0, + 16, 0x3233, 0x0028, 0x793E, 0x0029, 0, + 16, 0x3234, 0x0028, 0x540D, 0x0029, 0, + 16, 0x3235, 0x0028, 0x7279, 0x0029, 0, + 16, 0x3236, 0x0028, 0x8CA1, 0x0029, 0, + 16, 0x3237, 0x0028, 0x795D, 0x0029, 0, + 16, 0x3238, 0x0028, 0x52B4, 0x0029, 0, + 16, 0x3239, 0x0028, 0x4EE3, 0x0029, 0, + 16, 0x323A, 0x0028, 0x547C, 0x0029, 0, + 16, 0x323B, 0x0028, 0x5B66, 0x0029, 0, + 16, 0x323C, 0x0028, 0x76E3, 0x0029, 0, + 16, 0x323D, 0x0028, 0x4F01, 0x0029, 0, + 16, 0x323E, 0x0028, 0x8CC7, 0x0029, 0, + 16, 0x323F, 0x0028, 0x5354, 0x0029, 0, + 16, 0x3240, 0x0028, 0x796D, 0x0029, 0, + 16, 0x3241, 0x0028, 0x4F11, 0x0029, 0, + 16, 0x3242, 0x0028, 0x81EA, 0x0029, 0, + 16, 0x3243, 0x0028, 0x81F3, 0x0029, 0, + 8, 0x3260, 0x1100, 0, + 8, 0x3261, 0x1102, 0, + 8, 0x3262, 0x1103, 0, + 8, 0x3263, 0x1105, 0, + 8, 0x3264, 0x1106, 0, + 8, 0x3265, 0x1107, 0, + 8, 0x3266, 0x1109, 0, + 8, 0x3267, 0x110B, 0, + 8, 0x3268, 0x110C, 0, + 8, 0x3269, 0x110E, 0, + 8, 0x326A, 0x110F, 0, + 8, 0x326B, 0x1110, 0, + 8, 0x326C, 0x1111, 0, + 8, 0x326D, 0x1112, 0, + 8, 0x326E, 0x1100, 0x1161, 0, + 8, 0x326F, 0x1102, 0x1161, 0, + 8, 0x3270, 0x1103, 0x1161, 0, + 8, 0x3271, 0x1105, 0x1161, 0, + 8, 0x3272, 0x1106, 0x1161, 0, + 8, 0x3273, 0x1107, 0x1161, 0, + 8, 0x3274, 0x1109, 0x1161, 0, + 8, 0x3275, 0x110B, 0x1161, 0, + 8, 0x3276, 0x110C, 0x1161, 0, + 8, 0x3277, 0x110E, 0x1161, 0, + 8, 0x3278, 0x110F, 0x1161, 0, + 8, 0x3279, 0x1110, 0x1161, 0, + 8, 0x327A, 0x1111, 0x1161, 0, + 8, 0x327B, 0x1112, 0x1161, 0, + 8, 0x3280, 0x4E00, 0, + 8, 0x3281, 0x4E8C, 0, + 8, 0x3282, 0x4E09, 0, + 8, 0x3283, 0x56DB, 0, + 8, 0x3284, 0x4E94, 0, + 8, 0x3285, 0x516D, 0, + 8, 0x3286, 0x4E03, 0, + 8, 0x3287, 0x516B, 0, + 8, 0x3288, 0x4E5D, 0, + 8, 0x3289, 0x5341, 0, + 8, 0x328A, 0x6708, 0, + 8, 0x328B, 0x706B, 0, + 8, 0x328C, 0x6C34, 0, + 8, 0x328D, 0x6728, 0, + 8, 0x328E, 0x91D1, 0, + 8, 0x328F, 0x571F, 0, + 8, 0x3290, 0x65E5, 0, + 8, 0x3291, 0x682A, 0, + 8, 0x3292, 0x6709, 0, + 8, 0x3293, 0x793E, 0, + 8, 0x3294, 0x540D, 0, + 8, 0x3295, 0x7279, 0, + 8, 0x3296, 0x8CA1, 0, + 8, 0x3297, 0x795D, 0, + 8, 0x3298, 0x52B4, 0, + 8, 0x3299, 0x79D8, 0, + 8, 0x329A, 0x7537, 0, + 8, 0x329B, 0x5973, 0, + 8, 0x329C, 0x9069, 0, + 8, 0x329D, 0x512A, 0, + 8, 0x329E, 0x5370, 0, + 8, 0x329F, 0x6CE8, 0, + 8, 0x32A0, 0x9805, 0, + 8, 0x32A1, 0x4F11, 0, + 8, 0x32A2, 0x5199, 0, + 8, 0x32A3, 0x6B63, 0, + 8, 0x32A4, 0x4E0A, 0, + 8, 0x32A5, 0x4E2D, 0, + 8, 0x32A6, 0x4E0B, 0, + 8, 0x32A7, 0x5DE6, 0, + 8, 0x32A8, 0x53F3, 0, + 8, 0x32A9, 0x533B, 0, + 8, 0x32AA, 0x5B97, 0, + 8, 0x32AB, 0x5B66, 0, + 8, 0x32AC, 0x76E3, 0, + 8, 0x32AD, 0x4F01, 0, + 8, 0x32AE, 0x8CC7, 0, + 8, 0x32AF, 0x5354, 0, + 8, 0x32B0, 0x591C, 0, + 16, 0x32C0, 0x0031, 0x6708, 0, + 16, 0x32C1, 0x0032, 0x6708, 0, + 16, 0x32C2, 0x0033, 0x6708, 0, + 16, 0x32C3, 0x0034, 0x6708, 0, + 16, 0x32C4, 0x0035, 0x6708, 0, + 16, 0x32C5, 0x0036, 0x6708, 0, + 16, 0x32C6, 0x0037, 0x6708, 0, + 16, 0x32C7, 0x0038, 0x6708, 0, + 16, 0x32C8, 0x0039, 0x6708, 0, + 16, 0x32C9, 0x0031, 0x0030, 0x6708, 0, + 16, 0x32CA, 0x0031, 0x0031, 0x6708, 0, + 16, 0x32CB, 0x0031, 0x0032, 0x6708, 0, + 8, 0x32D0, 0x30A2, 0, + 8, 0x32D1, 0x30A4, 0, + 8, 0x32D2, 0x30A6, 0, + 8, 0x32D3, 0x30A8, 0, + 8, 0x32D4, 0x30AA, 0, + 8, 0x32D5, 0x30AB, 0, + 8, 0x32D6, 0x30AD, 0, + 8, 0x32D7, 0x30AF, 0, + 8, 0x32D8, 0x30B1, 0, + 8, 0x32D9, 0x30B3, 0, + 8, 0x32DA, 0x30B5, 0, + 8, 0x32DB, 0x30B7, 0, + 8, 0x32DC, 0x30B9, 0, + 8, 0x32DD, 0x30BB, 0, + 8, 0x32DE, 0x30BD, 0, + 8, 0x32DF, 0x30BF, 0, + 8, 0x32E0, 0x30C1, 0, + 8, 0x32E1, 0x30C4, 0, + 8, 0x32E2, 0x30C6, 0, + 8, 0x32E3, 0x30C8, 0, + 8, 0x32E4, 0x30CA, 0, + 8, 0x32E5, 0x30CB, 0, + 8, 0x32E6, 0x30CC, 0, + 8, 0x32E7, 0x30CD, 0, + 8, 0x32E8, 0x30CE, 0, + 8, 0x32E9, 0x30CF, 0, + 8, 0x32EA, 0x30D2, 0, + 8, 0x32EB, 0x30D5, 0, + 8, 0x32EC, 0x30D8, 0, + 8, 0x32ED, 0x30DB, 0, + 8, 0x32EE, 0x30DE, 0, + 8, 0x32EF, 0x30DF, 0, + 8, 0x32F0, 0x30E0, 0, + 8, 0x32F1, 0x30E1, 0, + 8, 0x32F2, 0x30E2, 0, + 8, 0x32F3, 0x30E4, 0, + 8, 0x32F4, 0x30E6, 0, + 8, 0x32F5, 0x30E8, 0, + 8, 0x32F6, 0x30E9, 0, + 8, 0x32F7, 0x30EA, 0, + 8, 0x32F8, 0x30EB, 0, + 8, 0x32F9, 0x30EC, 0, + 8, 0x32FA, 0x30ED, 0, + 8, 0x32FB, 0x30EF, 0, + 8, 0x32FC, 0x30F0, 0, + 8, 0x32FD, 0x30F1, 0, + 8, 0x32FE, 0x30F2, 0, + 15, 0x3300, 0x30A2, 0x30D1, 0x30FC, 0x30C8, 0, + 15, 0x3301, 0x30A2, 0x30EB, 0x30D5, 0x30A1, 0, + 15, 0x3302, 0x30A2, 0x30F3, 0x30DA, 0x30A2, 0, + 15, 0x3303, 0x30A2, 0x30FC, 0x30EB, 0, + 15, 0x3304, 0x30A4, 0x30CB, 0x30F3, 0x30B0, 0, + 15, 0x3305, 0x30A4, 0x30F3, 0x30C1, 0, + 15, 0x3306, 0x30A6, 0x30A9, 0x30F3, 0, + 15, 0x3307, 0x30A8, 0x30B9, 0x30AF, 0x30FC, 0x30C9, 0, + 15, 0x3308, 0x30A8, 0x30FC, 0x30AB, 0x30FC, 0, + 15, 0x3309, 0x30AA, 0x30F3, 0x30B9, 0, + 15, 0x330A, 0x30AA, 0x30FC, 0x30E0, 0, + 15, 0x330B, 0x30AB, 0x30A4, 0x30EA, 0, + 15, 0x330C, 0x30AB, 0x30E9, 0x30C3, 0x30C8, 0, + 15, 0x330D, 0x30AB, 0x30ED, 0x30EA, 0x30FC, 0, + 15, 0x330E, 0x30AC, 0x30ED, 0x30F3, 0, + 15, 0x330F, 0x30AC, 0x30F3, 0x30DE, 0, + 15, 0x3310, 0x30AE, 0x30AC, 0, + 15, 0x3311, 0x30AE, 0x30CB, 0x30FC, 0, + 15, 0x3312, 0x30AD, 0x30E5, 0x30EA, 0x30FC, 0, + 15, 0x3313, 0x30AE, 0x30EB, 0x30C0, 0x30FC, 0, + 15, 0x3314, 0x30AD, 0x30ED, 0, + 15, 0x3315, 0x30AD, 0x30ED, 0x30B0, 0x30E9, 0x30E0, 0, + 15, 0x3316, 0x30AD, 0x30ED, 0x30E1, 0x30FC, 0x30C8, 0x30EB, 0, + 15, 0x3317, 0x30AD, 0x30ED, 0x30EF, 0x30C3, 0x30C8, 0, + 15, 0x3318, 0x30B0, 0x30E9, 0x30E0, 0, + 15, 0x3319, 0x30B0, 0x30E9, 0x30E0, 0x30C8, 0x30F3, 0, + 15, 0x331A, 0x30AF, 0x30EB, 0x30BC, 0x30A4, 0x30ED, 0, + 15, 0x331B, 0x30AF, 0x30ED, 0x30FC, 0x30CD, 0, + 15, 0x331C, 0x30B1, 0x30FC, 0x30B9, 0, + 15, 0x331D, 0x30B3, 0x30EB, 0x30CA, 0, + 15, 0x331E, 0x30B3, 0x30FC, 0x30DD, 0, + 15, 0x331F, 0x30B5, 0x30A4, 0x30AF, 0x30EB, 0, + 15, 0x3320, 0x30B5, 0x30F3, 0x30C1, 0x30FC, 0x30E0, 0, + 15, 0x3321, 0x30B7, 0x30EA, 0x30F3, 0x30B0, 0, + 15, 0x3322, 0x30BB, 0x30F3, 0x30C1, 0, + 15, 0x3323, 0x30BB, 0x30F3, 0x30C8, 0, + 15, 0x3324, 0x30C0, 0x30FC, 0x30B9, 0, + 15, 0x3325, 0x30C7, 0x30B7, 0, + 15, 0x3326, 0x30C9, 0x30EB, 0, + 15, 0x3327, 0x30C8, 0x30F3, 0, + 15, 0x3328, 0x30CA, 0x30CE, 0, + 15, 0x3329, 0x30CE, 0x30C3, 0x30C8, 0, + 15, 0x332A, 0x30CF, 0x30A4, 0x30C4, 0, + 15, 0x332B, 0x30D1, 0x30FC, 0x30BB, 0x30F3, 0x30C8, 0, + 15, 0x332C, 0x30D1, 0x30FC, 0x30C4, 0, + 15, 0x332D, 0x30D0, 0x30FC, 0x30EC, 0x30EB, 0, + 15, 0x332E, 0x30D4, 0x30A2, 0x30B9, 0x30C8, 0x30EB, 0, + 15, 0x332F, 0x30D4, 0x30AF, 0x30EB, 0, + 15, 0x3330, 0x30D4, 0x30B3, 0, + 15, 0x3331, 0x30D3, 0x30EB, 0, + 15, 0x3332, 0x30D5, 0x30A1, 0x30E9, 0x30C3, 0x30C9, 0, + 15, 0x3333, 0x30D5, 0x30A3, 0x30FC, 0x30C8, 0, + 15, 0x3334, 0x30D6, 0x30C3, 0x30B7, 0x30A7, 0x30EB, 0, + 15, 0x3335, 0x30D5, 0x30E9, 0x30F3, 0, + 15, 0x3336, 0x30D8, 0x30AF, 0x30BF, 0x30FC, 0x30EB, 0, + 15, 0x3337, 0x30DA, 0x30BD, 0, + 15, 0x3338, 0x30DA, 0x30CB, 0x30D2, 0, + 15, 0x3339, 0x30D8, 0x30EB, 0x30C4, 0, + 15, 0x333A, 0x30DA, 0x30F3, 0x30B9, 0, + 15, 0x333B, 0x30DA, 0x30FC, 0x30B8, 0, + 15, 0x333C, 0x30D9, 0x30FC, 0x30BF, 0, + 15, 0x333D, 0x30DD, 0x30A4, 0x30F3, 0x30C8, 0, + 15, 0x333E, 0x30DC, 0x30EB, 0x30C8, 0, + 15, 0x333F, 0x30DB, 0x30F3, 0, + 15, 0x3340, 0x30DD, 0x30F3, 0x30C9, 0, + 15, 0x3341, 0x30DB, 0x30FC, 0x30EB, 0, + 15, 0x3342, 0x30DB, 0x30FC, 0x30F3, 0, + 15, 0x3343, 0x30DE, 0x30A4, 0x30AF, 0x30ED, 0, + 15, 0x3344, 0x30DE, 0x30A4, 0x30EB, 0, + 15, 0x3345, 0x30DE, 0x30C3, 0x30CF, 0, + 15, 0x3346, 0x30DE, 0x30EB, 0x30AF, 0, + 15, 0x3347, 0x30DE, 0x30F3, 0x30B7, 0x30E7, 0x30F3, 0, + 15, 0x3348, 0x30DF, 0x30AF, 0x30ED, 0x30F3, 0, + 15, 0x3349, 0x30DF, 0x30EA, 0, + 15, 0x334A, 0x30DF, 0x30EA, 0x30D0, 0x30FC, 0x30EB, 0, + 15, 0x334B, 0x30E1, 0x30AC, 0, + 15, 0x334C, 0x30E1, 0x30AC, 0x30C8, 0x30F3, 0, + 15, 0x334D, 0x30E1, 0x30FC, 0x30C8, 0x30EB, 0, + 15, 0x334E, 0x30E4, 0x30FC, 0x30C9, 0, + 15, 0x334F, 0x30E4, 0x30FC, 0x30EB, 0, + 15, 0x3350, 0x30E6, 0x30A2, 0x30F3, 0, + 15, 0x3351, 0x30EA, 0x30C3, 0x30C8, 0x30EB, 0, + 15, 0x3352, 0x30EA, 0x30E9, 0, + 15, 0x3353, 0x30EB, 0x30D4, 0x30FC, 0, + 15, 0x3354, 0x30EB, 0x30FC, 0x30D6, 0x30EB, 0, + 15, 0x3355, 0x30EC, 0x30E0, 0, + 15, 0x3356, 0x30EC, 0x30F3, 0x30C8, 0x30B2, 0x30F3, 0, + 15, 0x3357, 0x30EF, 0x30C3, 0x30C8, 0, + 16, 0x3358, 0x0030, 0x70B9, 0, + 16, 0x3359, 0x0031, 0x70B9, 0, + 16, 0x335A, 0x0032, 0x70B9, 0, + 16, 0x335B, 0x0033, 0x70B9, 0, + 16, 0x335C, 0x0034, 0x70B9, 0, + 16, 0x335D, 0x0035, 0x70B9, 0, + 16, 0x335E, 0x0036, 0x70B9, 0, + 16, 0x335F, 0x0037, 0x70B9, 0, + 16, 0x3360, 0x0038, 0x70B9, 0, + 16, 0x3361, 0x0039, 0x70B9, 0, + 16, 0x3362, 0x0031, 0x0030, 0x70B9, 0, + 16, 0x3363, 0x0031, 0x0031, 0x70B9, 0, + 16, 0x3364, 0x0031, 0x0032, 0x70B9, 0, + 16, 0x3365, 0x0031, 0x0033, 0x70B9, 0, + 16, 0x3366, 0x0031, 0x0034, 0x70B9, 0, + 16, 0x3367, 0x0031, 0x0035, 0x70B9, 0, + 16, 0x3368, 0x0031, 0x0036, 0x70B9, 0, + 16, 0x3369, 0x0031, 0x0037, 0x70B9, 0, + 16, 0x336A, 0x0031, 0x0038, 0x70B9, 0, + 16, 0x336B, 0x0031, 0x0039, 0x70B9, 0, + 16, 0x336C, 0x0032, 0x0030, 0x70B9, 0, + 16, 0x336D, 0x0032, 0x0031, 0x70B9, 0, + 16, 0x336E, 0x0032, 0x0032, 0x70B9, 0, + 16, 0x336F, 0x0032, 0x0033, 0x70B9, 0, + 16, 0x3370, 0x0032, 0x0034, 0x70B9, 0, + 15, 0x3371, 0x0068, 0x0050, 0x0061, 0, + 15, 0x3372, 0x0064, 0x0061, 0, + 15, 0x3373, 0x0041, 0x0055, 0, + 15, 0x3374, 0x0062, 0x0061, 0x0072, 0, + 15, 0x3375, 0x006F, 0x0056, 0, + 15, 0x3376, 0x0070, 0x0063, 0, + 15, 0x337B, 0x5E73, 0x6210, 0, + 15, 0x337C, 0x662D, 0x548C, 0, + 15, 0x337D, 0x5927, 0x6B63, 0, + 15, 0x337E, 0x660E, 0x6CBB, 0, + 15, 0x337F, 0x682A, 0x5F0F, 0x4F1A, 0x793E, 0, + 15, 0x3380, 0x0070, 0x0041, 0, + 15, 0x3381, 0x006E, 0x0041, 0, + 15, 0x3382, 0x03BC, 0x0041, 0, + 15, 0x3383, 0x006D, 0x0041, 0, + 15, 0x3384, 0x006B, 0x0041, 0, + 15, 0x3385, 0x004B, 0x0042, 0, + 15, 0x3386, 0x004D, 0x0042, 0, + 15, 0x3387, 0x0047, 0x0042, 0, + 15, 0x3388, 0x0063, 0x0061, 0x006C, 0, + 15, 0x3389, 0x006B, 0x0063, 0x0061, 0x006C, 0, + 15, 0x338A, 0x0070, 0x0046, 0, + 15, 0x338B, 0x006E, 0x0046, 0, + 15, 0x338C, 0x03BC, 0x0046, 0, + 15, 0x338D, 0x03BC, 0x0067, 0, + 15, 0x338E, 0x006D, 0x0067, 0, + 15, 0x338F, 0x006B, 0x0067, 0, + 15, 0x3390, 0x0048, 0x007A, 0, + 15, 0x3391, 0x006B, 0x0048, 0x007A, 0, + 15, 0x3392, 0x004D, 0x0048, 0x007A, 0, + 15, 0x3393, 0x0047, 0x0048, 0x007A, 0, + 15, 0x3394, 0x0054, 0x0048, 0x007A, 0, + 15, 0x3395, 0x03BC, 0x2113, 0, + 15, 0x3396, 0x006D, 0x2113, 0, + 15, 0x3397, 0x0064, 0x2113, 0, + 15, 0x3398, 0x006B, 0x2113, 0, + 15, 0x3399, 0x0066, 0x006D, 0, + 15, 0x339A, 0x006E, 0x006D, 0, + 15, 0x339B, 0x03BC, 0x006D, 0, + 15, 0x339C, 0x006D, 0x006D, 0, + 15, 0x339D, 0x0063, 0x006D, 0, + 15, 0x339E, 0x006B, 0x006D, 0, + 15, 0x339F, 0x006D, 0x006D, 0x00B2, 0, + 15, 0x33A0, 0x0063, 0x006D, 0x00B2, 0, + 15, 0x33A1, 0x006D, 0x00B2, 0, + 15, 0x33A2, 0x006B, 0x006D, 0x00B2, 0, + 15, 0x33A3, 0x006D, 0x006D, 0x00B3, 0, + 15, 0x33A4, 0x0063, 0x006D, 0x00B3, 0, + 15, 0x33A5, 0x006D, 0x00B3, 0, + 15, 0x33A6, 0x006B, 0x006D, 0x00B3, 0, + 15, 0x33A7, 0x006D, 0x2215, 0x0073, 0, + 15, 0x33A8, 0x006D, 0x2215, 0x0073, 0x00B2, 0, + 15, 0x33A9, 0x0050, 0x0061, 0, + 15, 0x33AA, 0x006B, 0x0050, 0x0061, 0, + 15, 0x33AB, 0x004D, 0x0050, 0x0061, 0, + 15, 0x33AC, 0x0047, 0x0050, 0x0061, 0, + 15, 0x33AD, 0x0072, 0x0061, 0x0064, 0, + 15, 0x33AE, 0x0072, 0x0061, 0x0064, 0x2215, 0x0073, 0, + 15, 0x33AF, 0x0072, 0x0061, 0x0064, 0x2215, 0x0073, 0x00B2, 0, + 15, 0x33B0, 0x0070, 0x0073, 0, + 15, 0x33B1, 0x006E, 0x0073, 0, + 15, 0x33B2, 0x03BC, 0x0073, 0, + 15, 0x33B3, 0x006D, 0x0073, 0, + 15, 0x33B4, 0x0070, 0x0056, 0, + 15, 0x33B5, 0x006E, 0x0056, 0, + 15, 0x33B6, 0x03BC, 0x0056, 0, + 15, 0x33B7, 0x006D, 0x0056, 0, + 15, 0x33B8, 0x006B, 0x0056, 0, + 15, 0x33B9, 0x004D, 0x0056, 0, + 15, 0x33BA, 0x0070, 0x0057, 0, + 15, 0x33BB, 0x006E, 0x0057, 0, + 15, 0x33BC, 0x03BC, 0x0057, 0, + 15, 0x33BD, 0x006D, 0x0057, 0, + 15, 0x33BE, 0x006B, 0x0057, 0, + 15, 0x33BF, 0x004D, 0x0057, 0, + 15, 0x33C0, 0x006B, 0x03A9, 0, + 15, 0x33C1, 0x004D, 0x03A9, 0, + 15, 0x33C2, 0x0061, 0x002E, 0x006D, 0x002E, 0, + 15, 0x33C3, 0x0042, 0x0071, 0, + 15, 0x33C4, 0x0063, 0x0063, 0, + 15, 0x33C5, 0x0063, 0x0064, 0, + 15, 0x33C6, 0x0043, 0x2215, 0x006B, 0x0067, 0, + 15, 0x33C7, 0x0043, 0x006F, 0x002E, 0, + 15, 0x33C8, 0x0064, 0x0042, 0, + 15, 0x33C9, 0x0047, 0x0079, 0, + 15, 0x33CA, 0x0068, 0x0061, 0, + 15, 0x33CB, 0x0048, 0x0050, 0, + 15, 0x33CC, 0x0069, 0x006E, 0, + 15, 0x33CD, 0x004B, 0x004B, 0, + 15, 0x33CE, 0x004B, 0x004D, 0, + 15, 0x33CF, 0x006B, 0x0074, 0, + 15, 0x33D0, 0x006C, 0x006D, 0, + 15, 0x33D1, 0x006C, 0x006E, 0, + 15, 0x33D2, 0x006C, 0x006F, 0x0067, 0, + 15, 0x33D3, 0x006C, 0x0078, 0, + 15, 0x33D4, 0x006D, 0x0062, 0, + 15, 0x33D5, 0x006D, 0x0069, 0x006C, 0, + 15, 0x33D6, 0x006D, 0x006F, 0x006C, 0, + 15, 0x33D7, 0x0050, 0x0048, 0, + 15, 0x33D8, 0x0070, 0x002E, 0x006D, 0x002E, 0, + 15, 0x33D9, 0x0050, 0x0050, 0x004D, 0, + 15, 0x33DA, 0x0050, 0x0052, 0, + 15, 0x33DB, 0x0073, 0x0072, 0, + 15, 0x33DC, 0x0053, 0x0076, 0, + 15, 0x33DD, 0x0057, 0x0062, 0, + 16, 0x33E0, 0x0031, 0x65E5, 0, + 16, 0x33E1, 0x0032, 0x65E5, 0, + 16, 0x33E2, 0x0033, 0x65E5, 0, + 16, 0x33E3, 0x0034, 0x65E5, 0, + 16, 0x33E4, 0x0035, 0x65E5, 0, + 16, 0x33E5, 0x0036, 0x65E5, 0, + 16, 0x33E6, 0x0037, 0x65E5, 0, + 16, 0x33E7, 0x0038, 0x65E5, 0, + 16, 0x33E8, 0x0039, 0x65E5, 0, + 16, 0x33E9, 0x0031, 0x0030, 0x65E5, 0, + 16, 0x33EA, 0x0031, 0x0031, 0x65E5, 0, + 16, 0x33EB, 0x0031, 0x0032, 0x65E5, 0, + 16, 0x33EC, 0x0031, 0x0033, 0x65E5, 0, + 16, 0x33ED, 0x0031, 0x0034, 0x65E5, 0, + 16, 0x33EE, 0x0031, 0x0035, 0x65E5, 0, + 16, 0x33EF, 0x0031, 0x0036, 0x65E5, 0, + 16, 0x33F0, 0x0031, 0x0037, 0x65E5, 0, + 16, 0x33F1, 0x0031, 0x0038, 0x65E5, 0, + 16, 0x33F2, 0x0031, 0x0039, 0x65E5, 0, + 16, 0x33F3, 0x0032, 0x0030, 0x65E5, 0, + 16, 0x33F4, 0x0032, 0x0031, 0x65E5, 0, + 16, 0x33F5, 0x0032, 0x0032, 0x65E5, 0, + 16, 0x33F6, 0x0032, 0x0033, 0x65E5, 0, + 16, 0x33F7, 0x0032, 0x0034, 0x65E5, 0, + 16, 0x33F8, 0x0032, 0x0035, 0x65E5, 0, + 16, 0x33F9, 0x0032, 0x0036, 0x65E5, 0, + 16, 0x33FA, 0x0032, 0x0037, 0x65E5, 0, + 16, 0x33FB, 0x0032, 0x0038, 0x65E5, 0, + 16, 0x33FC, 0x0032, 0x0039, 0x65E5, 0, + 16, 0x33FD, 0x0033, 0x0030, 0x65E5, 0, + 16, 0x33FE, 0x0033, 0x0031, 0x65E5, 0, + 1, 0xF900, 0x8C48, 0, + 1, 0xF901, 0x66F4, 0, + 1, 0xF902, 0x8ECA, 0, + 1, 0xF903, 0x8CC8, 0, + 1, 0xF904, 0x6ED1, 0, + 1, 0xF905, 0x4E32, 0, + 1, 0xF906, 0x53E5, 0, + 1, 0xF907, 0x9F9C, 0, + 1, 0xF908, 0x9F9C, 0, + 1, 0xF909, 0x5951, 0, + 1, 0xF90A, 0x91D1, 0, + 1, 0xF90B, 0x5587, 0, + 1, 0xF90C, 0x5948, 0, + 1, 0xF90D, 0x61F6, 0, + 1, 0xF90E, 0x7669, 0, + 1, 0xF90F, 0x7F85, 0, + 1, 0xF910, 0x863F, 0, + 1, 0xF911, 0x87BA, 0, + 1, 0xF912, 0x88F8, 0, + 1, 0xF913, 0x908F, 0, + 1, 0xF914, 0x6A02, 0, + 1, 0xF915, 0x6D1B, 0, + 1, 0xF916, 0x70D9, 0, + 1, 0xF917, 0x73DE, 0, + 1, 0xF918, 0x843D, 0, + 1, 0xF919, 0x916A, 0, + 1, 0xF91A, 0x99F1, 0, + 1, 0xF91B, 0x4E82, 0, + 1, 0xF91C, 0x5375, 0, + 1, 0xF91D, 0x6B04, 0, + 1, 0xF91E, 0x721B, 0, + 1, 0xF91F, 0x862D, 0, + 1, 0xF920, 0x9E1E, 0, + 1, 0xF921, 0x5D50, 0, + 1, 0xF922, 0x6FEB, 0, + 1, 0xF923, 0x85CD, 0, + 1, 0xF924, 0x8964, 0, + 1, 0xF925, 0x62C9, 0, + 1, 0xF926, 0x81D8, 0, + 1, 0xF927, 0x881F, 0, + 1, 0xF928, 0x5ECA, 0, + 1, 0xF929, 0x6717, 0, + 1, 0xF92A, 0x6D6A, 0, + 1, 0xF92B, 0x72FC, 0, + 1, 0xF92C, 0x90CE, 0, + 1, 0xF92D, 0x4F86, 0, + 1, 0xF92E, 0x51B7, 0, + 1, 0xF92F, 0x52DE, 0, + 1, 0xF930, 0x64C4, 0, + 1, 0xF931, 0x6AD3, 0, + 1, 0xF932, 0x7210, 0, + 1, 0xF933, 0x76E7, 0, + 1, 0xF934, 0x8001, 0, + 1, 0xF935, 0x8606, 0, + 1, 0xF936, 0x865C, 0, + 1, 0xF937, 0x8DEF, 0, + 1, 0xF938, 0x9732, 0, + 1, 0xF939, 0x9B6F, 0, + 1, 0xF93A, 0x9DFA, 0, + 1, 0xF93B, 0x788C, 0, + 1, 0xF93C, 0x797F, 0, + 1, 0xF93D, 0x7DA0, 0, + 1, 0xF93E, 0x83C9, 0, + 1, 0xF93F, 0x9304, 0, + 1, 0xF940, 0x9E7F, 0, + 1, 0xF941, 0x8AD6, 0, + 1, 0xF942, 0x58DF, 0, + 1, 0xF943, 0x5F04, 0, + 1, 0xF944, 0x7C60, 0, + 1, 0xF945, 0x807E, 0, + 1, 0xF946, 0x7262, 0, + 1, 0xF947, 0x78CA, 0, + 1, 0xF948, 0x8CC2, 0, + 1, 0xF949, 0x96F7, 0, + 1, 0xF94A, 0x58D8, 0, + 1, 0xF94B, 0x5C62, 0, + 1, 0xF94C, 0x6A13, 0, + 1, 0xF94D, 0x6DDA, 0, + 1, 0xF94E, 0x6F0F, 0, + 1, 0xF94F, 0x7D2F, 0, + 1, 0xF950, 0x7E37, 0, + 1, 0xF951, 0x96FB, 0, + 1, 0xF952, 0x52D2, 0, + 1, 0xF953, 0x808B, 0, + 1, 0xF954, 0x51DC, 0, + 1, 0xF955, 0x51CC, 0, + 1, 0xF956, 0x7A1C, 0, + 1, 0xF957, 0x7DBE, 0, + 1, 0xF958, 0x83F1, 0, + 1, 0xF959, 0x9675, 0, + 1, 0xF95A, 0x8B80, 0, + 1, 0xF95B, 0x62CF, 0, + 1, 0xF95C, 0x6A02, 0, + 1, 0xF95D, 0x8AFE, 0, + 1, 0xF95E, 0x4E39, 0, + 1, 0xF95F, 0x5BE7, 0, + 1, 0xF960, 0x6012, 0, + 1, 0xF961, 0x7387, 0, + 1, 0xF962, 0x7570, 0, + 1, 0xF963, 0x5317, 0, + 1, 0xF964, 0x78FB, 0, + 1, 0xF965, 0x4FBF, 0, + 1, 0xF966, 0x5FA9, 0, + 1, 0xF967, 0x4E0D, 0, + 1, 0xF968, 0x6CCC, 0, + 1, 0xF969, 0x6578, 0, + 1, 0xF96A, 0x7D22, 0, + 1, 0xF96B, 0x53C3, 0, + 1, 0xF96C, 0x585E, 0, + 1, 0xF96D, 0x7701, 0, + 1, 0xF96E, 0x8449, 0, + 1, 0xF96F, 0x8AAA, 0, + 1, 0xF970, 0x6BBA, 0, + 1, 0xF971, 0x8FB0, 0, + 1, 0xF972, 0x6C88, 0, + 1, 0xF973, 0x62FE, 0, + 1, 0xF974, 0x82E5, 0, + 1, 0xF975, 0x63A0, 0, + 1, 0xF976, 0x7565, 0, + 1, 0xF977, 0x4EAE, 0, + 1, 0xF978, 0x5169, 0, + 1, 0xF979, 0x51C9, 0, + 1, 0xF97A, 0x6881, 0, + 1, 0xF97B, 0x7CE7, 0, + 1, 0xF97C, 0x826F, 0, + 1, 0xF97D, 0x8AD2, 0, + 1, 0xF97E, 0x91CF, 0, + 1, 0xF97F, 0x52F5, 0, + 1, 0xF980, 0x5442, 0, + 1, 0xF981, 0x5973, 0, + 1, 0xF982, 0x5EEC, 0, + 1, 0xF983, 0x65C5, 0, + 1, 0xF984, 0x6FFE, 0, + 1, 0xF985, 0x792A, 0, + 1, 0xF986, 0x95AD, 0, + 1, 0xF987, 0x9A6A, 0, + 1, 0xF988, 0x9E97, 0, + 1, 0xF989, 0x9ECE, 0, + 1, 0xF98A, 0x529B, 0, + 1, 0xF98B, 0x66C6, 0, + 1, 0xF98C, 0x6B77, 0, + 1, 0xF98D, 0x8F62, 0, + 1, 0xF98E, 0x5E74, 0, + 1, 0xF98F, 0x6190, 0, + 1, 0xF990, 0x6200, 0, + 1, 0xF991, 0x649A, 0, + 1, 0xF992, 0x6F23, 0, + 1, 0xF993, 0x7149, 0, + 1, 0xF994, 0x7489, 0, + 1, 0xF995, 0x79CA, 0, + 1, 0xF996, 0x7DF4, 0, + 1, 0xF997, 0x806F, 0, + 1, 0xF998, 0x8F26, 0, + 1, 0xF999, 0x84EE, 0, + 1, 0xF99A, 0x9023, 0, + 1, 0xF99B, 0x934A, 0, + 1, 0xF99C, 0x5217, 0, + 1, 0xF99D, 0x52A3, 0, + 1, 0xF99E, 0x54BD, 0, + 1, 0xF99F, 0x70C8, 0, + 1, 0xF9A0, 0x88C2, 0, + 1, 0xF9A1, 0x8AAA, 0, + 1, 0xF9A2, 0x5EC9, 0, + 1, 0xF9A3, 0x5FF5, 0, + 1, 0xF9A4, 0x637B, 0, + 1, 0xF9A5, 0x6BAE, 0, + 1, 0xF9A6, 0x7C3E, 0, + 1, 0xF9A7, 0x7375, 0, + 1, 0xF9A8, 0x4EE4, 0, + 1, 0xF9A9, 0x56F9, 0, + 1, 0xF9AA, 0x5BE7, 0, + 1, 0xF9AB, 0x5DBA, 0, + 1, 0xF9AC, 0x601C, 0, + 1, 0xF9AD, 0x73B2, 0, + 1, 0xF9AE, 0x7469, 0, + 1, 0xF9AF, 0x7F9A, 0, + 1, 0xF9B0, 0x8046, 0, + 1, 0xF9B1, 0x9234, 0, + 1, 0xF9B2, 0x96F6, 0, + 1, 0xF9B3, 0x9748, 0, + 1, 0xF9B4, 0x9818, 0, + 1, 0xF9B5, 0x4F8B, 0, + 1, 0xF9B6, 0x79AE, 0, + 1, 0xF9B7, 0x91B4, 0, + 1, 0xF9B8, 0x96B8, 0, + 1, 0xF9B9, 0x60E1, 0, + 1, 0xF9BA, 0x4E86, 0, + 1, 0xF9BB, 0x50DA, 0, + 1, 0xF9BC, 0x5BEE, 0, + 1, 0xF9BD, 0x5C3F, 0, + 1, 0xF9BE, 0x6599, 0, + 1, 0xF9BF, 0x6A02, 0, + 1, 0xF9C0, 0x71CE, 0, + 1, 0xF9C1, 0x7642, 0, + 1, 0xF9C2, 0x84FC, 0, + 1, 0xF9C3, 0x907C, 0, + 1, 0xF9C4, 0x9F8D, 0, + 1, 0xF9C5, 0x6688, 0, + 1, 0xF9C6, 0x962E, 0, + 1, 0xF9C7, 0x5289, 0, + 1, 0xF9C8, 0x677B, 0, + 1, 0xF9C9, 0x67F3, 0, + 1, 0xF9CA, 0x6D41, 0, + 1, 0xF9CB, 0x6E9C, 0, + 1, 0xF9CC, 0x7409, 0, + 1, 0xF9CD, 0x7559, 0, + 1, 0xF9CE, 0x786B, 0, + 1, 0xF9CF, 0x7D10, 0, + 1, 0xF9D0, 0x985E, 0, + 1, 0xF9D1, 0x516D, 0, + 1, 0xF9D2, 0x622E, 0, + 1, 0xF9D3, 0x9678, 0, + 1, 0xF9D4, 0x502B, 0, + 1, 0xF9D5, 0x5D19, 0, + 1, 0xF9D6, 0x6DEA, 0, + 1, 0xF9D7, 0x8F2A, 0, + 1, 0xF9D8, 0x5F8B, 0, + 1, 0xF9D9, 0x6144, 0, + 1, 0xF9DA, 0x6817, 0, + 1, 0xF9DB, 0x7387, 0, + 1, 0xF9DC, 0x9686, 0, + 1, 0xF9DD, 0x5229, 0, + 1, 0xF9DE, 0x540F, 0, + 1, 0xF9DF, 0x5C65, 0, + 1, 0xF9E0, 0x6613, 0, + 1, 0xF9E1, 0x674E, 0, + 1, 0xF9E2, 0x68A8, 0, + 1, 0xF9E3, 0x6CE5, 0, + 1, 0xF9E4, 0x7406, 0, + 1, 0xF9E5, 0x75E2, 0, + 1, 0xF9E6, 0x7F79, 0, + 1, 0xF9E7, 0x88CF, 0, + 1, 0xF9E8, 0x88E1, 0, + 1, 0xF9E9, 0x91CC, 0, + 1, 0xF9EA, 0x96E2, 0, + 1, 0xF9EB, 0x533F, 0, + 1, 0xF9EC, 0x6EBA, 0, + 1, 0xF9ED, 0x541D, 0, + 1, 0xF9EE, 0x71D0, 0, + 1, 0xF9EF, 0x7498, 0, + 1, 0xF9F0, 0x85FA, 0, + 1, 0xF9F1, 0x96A3, 0, + 1, 0xF9F2, 0x9C57, 0, + 1, 0xF9F3, 0x9E9F, 0, + 1, 0xF9F4, 0x6797, 0, + 1, 0xF9F5, 0x6DCB, 0, + 1, 0xF9F6, 0x81E8, 0, + 1, 0xF9F7, 0x7ACB, 0, + 1, 0xF9F8, 0x7B20, 0, + 1, 0xF9F9, 0x7C92, 0, + 1, 0xF9FA, 0x72C0, 0, + 1, 0xF9FB, 0x7099, 0, + 1, 0xF9FC, 0x8B58, 0, + 1, 0xF9FD, 0x4EC0, 0, + 1, 0xF9FE, 0x8336, 0, + 1, 0xF9FF, 0x523A, 0, + 1, 0xFA00, 0x5207, 0, + 1, 0xFA01, 0x5EA6, 0, + 1, 0xFA02, 0x62D3, 0, + 1, 0xFA03, 0x7CD6, 0, + 1, 0xFA04, 0x5B85, 0, + 1, 0xFA05, 0x6D1E, 0, + 1, 0xFA06, 0x66B4, 0, + 1, 0xFA07, 0x8F3B, 0, + 1, 0xFA08, 0x884C, 0, + 1, 0xFA09, 0x964D, 0, + 1, 0xFA0A, 0x898B, 0, + 1, 0xFA0B, 0x5ED3, 0, + 1, 0xFA0C, 0x5140, 0, + 1, 0xFA0D, 0x55C0, 0, + 1, 0xFA10, 0x585A, 0, + 1, 0xFA12, 0x6674, 0, + 1, 0xFA15, 0x51DE, 0, + 1, 0xFA16, 0x732A, 0, + 1, 0xFA17, 0x76CA, 0, + 1, 0xFA18, 0x793C, 0, + 1, 0xFA19, 0x795E, 0, + 1, 0xFA1A, 0x7965, 0, + 1, 0xFA1B, 0x798F, 0, + 1, 0xFA1C, 0x9756, 0, + 1, 0xFA1D, 0x7CBE, 0, + 1, 0xFA1E, 0x7FBD, 0, + 1, 0xFA20, 0x8612, 0, + 1, 0xFA22, 0x8AF8, 0, + 1, 0xFA25, 0x9038, 0, + 1, 0xFA26, 0x90FD, 0, + 1, 0xFA2A, 0x98EF, 0, + 1, 0xFA2B, 0x98FC, 0, + 1, 0xFA2C, 0x9928, 0, + 1, 0xFA2D, 0x9DB4, 0, + 16, 0xFB00, 0x0066, 0x0066, 0, + 16, 0xFB01, 0x0066, 0x0069, 0, + 16, 0xFB02, 0x0066, 0x006C, 0, + 16, 0xFB03, 0x0066, 0x0066, 0x0069, 0, + 16, 0xFB04, 0x0066, 0x0066, 0x006C, 0, + 16, 0xFB05, 0x017F, 0x0074, 0, + 16, 0xFB06, 0x0073, 0x0074, 0, + 16, 0xFB13, 0x0574, 0x0576, 0, + 16, 0xFB14, 0x0574, 0x0565, 0, + 16, 0xFB15, 0x0574, 0x056B, 0, + 16, 0xFB16, 0x057E, 0x0576, 0, + 16, 0xFB17, 0x0574, 0x056D, 0, + 1, 0xFB1D, 0x05D9, 0x05B4, 0, + 1, 0xFB1F, 0x05F2, 0x05B7, 0, + 2, 0xFB20, 0x05E2, 0, + 2, 0xFB21, 0x05D0, 0, + 2, 0xFB22, 0x05D3, 0, + 2, 0xFB23, 0x05D4, 0, + 2, 0xFB24, 0x05DB, 0, + 2, 0xFB25, 0x05DC, 0, + 2, 0xFB26, 0x05DD, 0, + 2, 0xFB27, 0x05E8, 0, + 2, 0xFB28, 0x05EA, 0, + 2, 0xFB29, 0x002B, 0, + 1, 0xFB2A, 0x05E9, 0x05C1, 0, + 1, 0xFB2B, 0x05E9, 0x05C2, 0, + 1, 0xFB2C, 0xFB49, 0x05C1, 0, + 1, 0xFB2D, 0xFB49, 0x05C2, 0, + 1, 0xFB2E, 0x05D0, 0x05B7, 0, + 1, 0xFB2F, 0x05D0, 0x05B8, 0, + 1, 0xFB30, 0x05D0, 0x05BC, 0, + 1, 0xFB31, 0x05D1, 0x05BC, 0, + 1, 0xFB32, 0x05D2, 0x05BC, 0, + 1, 0xFB33, 0x05D3, 0x05BC, 0, + 1, 0xFB34, 0x05D4, 0x05BC, 0, + 1, 0xFB35, 0x05D5, 0x05BC, 0, + 1, 0xFB36, 0x05D6, 0x05BC, 0, + 1, 0xFB38, 0x05D8, 0x05BC, 0, + 1, 0xFB39, 0x05D9, 0x05BC, 0, + 1, 0xFB3A, 0x05DA, 0x05BC, 0, + 1, 0xFB3B, 0x05DB, 0x05BC, 0, + 1, 0xFB3C, 0x05DC, 0x05BC, 0, + 1, 0xFB3E, 0x05DE, 0x05BC, 0, + 1, 0xFB40, 0x05E0, 0x05BC, 0, + 1, 0xFB41, 0x05E1, 0x05BC, 0, + 1, 0xFB43, 0x05E3, 0x05BC, 0, + 1, 0xFB44, 0x05E4, 0x05BC, 0, + 1, 0xFB46, 0x05E6, 0x05BC, 0, + 1, 0xFB47, 0x05E7, 0x05BC, 0, + 1, 0xFB48, 0x05E8, 0x05BC, 0, + 1, 0xFB49, 0x05E9, 0x05BC, 0, + 1, 0xFB4A, 0x05EA, 0x05BC, 0, + 1, 0xFB4B, 0x05D5, 0x05B9, 0, + 1, 0xFB4C, 0x05D1, 0x05BF, 0, + 1, 0xFB4D, 0x05DB, 0x05BF, 0, + 1, 0xFB4E, 0x05E4, 0x05BF, 0, + 16, 0xFB4F, 0x05D0, 0x05DC, 0, + 7, 0xFB50, 0x0671, 0, + 6, 0xFB51, 0x0671, 0, + 7, 0xFB52, 0x067B, 0, + 6, 0xFB53, 0x067B, 0, + 4, 0xFB54, 0x067B, 0, + 5, 0xFB55, 0x067B, 0, + 7, 0xFB56, 0x067E, 0, + 6, 0xFB57, 0x067E, 0, + 4, 0xFB58, 0x067E, 0, + 5, 0xFB59, 0x067E, 0, + 7, 0xFB5A, 0x0680, 0, + 6, 0xFB5B, 0x0680, 0, + 4, 0xFB5C, 0x0680, 0, + 5, 0xFB5D, 0x0680, 0, + 7, 0xFB5E, 0x067A, 0, + 6, 0xFB5F, 0x067A, 0, + 4, 0xFB60, 0x067A, 0, + 5, 0xFB61, 0x067A, 0, + 7, 0xFB62, 0x067F, 0, + 6, 0xFB63, 0x067F, 0, + 4, 0xFB64, 0x067F, 0, + 5, 0xFB65, 0x067F, 0, + 7, 0xFB66, 0x0679, 0, + 6, 0xFB67, 0x0679, 0, + 4, 0xFB68, 0x0679, 0, + 5, 0xFB69, 0x0679, 0, + 7, 0xFB6A, 0x06A4, 0, + 6, 0xFB6B, 0x06A4, 0, + 4, 0xFB6C, 0x06A4, 0, + 5, 0xFB6D, 0x06A4, 0, + 7, 0xFB6E, 0x06A6, 0, + 6, 0xFB6F, 0x06A6, 0, + 4, 0xFB70, 0x06A6, 0, + 5, 0xFB71, 0x06A6, 0, + 7, 0xFB72, 0x0684, 0, + 6, 0xFB73, 0x0684, 0, + 4, 0xFB74, 0x0684, 0, + 5, 0xFB75, 0x0684, 0, + 7, 0xFB76, 0x0683, 0, + 6, 0xFB77, 0x0683, 0, + 4, 0xFB78, 0x0683, 0, + 5, 0xFB79, 0x0683, 0, + 7, 0xFB7A, 0x0686, 0, + 6, 0xFB7B, 0x0686, 0, + 4, 0xFB7C, 0x0686, 0, + 5, 0xFB7D, 0x0686, 0, + 7, 0xFB7E, 0x0687, 0, + 6, 0xFB7F, 0x0687, 0, + 4, 0xFB80, 0x0687, 0, + 5, 0xFB81, 0x0687, 0, + 7, 0xFB82, 0x068D, 0, + 6, 0xFB83, 0x068D, 0, + 7, 0xFB84, 0x068C, 0, + 6, 0xFB85, 0x068C, 0, + 7, 0xFB86, 0x068E, 0, + 6, 0xFB87, 0x068E, 0, + 7, 0xFB88, 0x0688, 0, + 6, 0xFB89, 0x0688, 0, + 7, 0xFB8A, 0x0698, 0, + 6, 0xFB8B, 0x0698, 0, + 7, 0xFB8C, 0x0691, 0, + 6, 0xFB8D, 0x0691, 0, + 7, 0xFB8E, 0x06A9, 0, + 6, 0xFB8F, 0x06A9, 0, + 4, 0xFB90, 0x06A9, 0, + 5, 0xFB91, 0x06A9, 0, + 7, 0xFB92, 0x06AF, 0, + 6, 0xFB93, 0x06AF, 0, + 4, 0xFB94, 0x06AF, 0, + 5, 0xFB95, 0x06AF, 0, + 7, 0xFB96, 0x06B3, 0, + 6, 0xFB97, 0x06B3, 0, + 4, 0xFB98, 0x06B3, 0, + 5, 0xFB99, 0x06B3, 0, + 7, 0xFB9A, 0x06B1, 0, + 6, 0xFB9B, 0x06B1, 0, + 4, 0xFB9C, 0x06B1, 0, + 5, 0xFB9D, 0x06B1, 0, + 7, 0xFB9E, 0x06BA, 0, + 6, 0xFB9F, 0x06BA, 0, + 7, 0xFBA0, 0x06BB, 0, + 6, 0xFBA1, 0x06BB, 0, + 4, 0xFBA2, 0x06BB, 0, + 5, 0xFBA3, 0x06BB, 0, + 7, 0xFBA4, 0x06C0, 0, + 6, 0xFBA5, 0x06C0, 0, + 7, 0xFBA6, 0x06C1, 0, + 6, 0xFBA7, 0x06C1, 0, + 4, 0xFBA8, 0x06C1, 0, + 5, 0xFBA9, 0x06C1, 0, + 7, 0xFBAA, 0x06BE, 0, + 6, 0xFBAB, 0x06BE, 0, + 4, 0xFBAC, 0x06BE, 0, + 5, 0xFBAD, 0x06BE, 0, + 7, 0xFBAE, 0x06D2, 0, + 6, 0xFBAF, 0x06D2, 0, + 7, 0xFBB0, 0x06D3, 0, + 6, 0xFBB1, 0x06D3, 0, + 7, 0xFBD3, 0x06AD, 0, + 6, 0xFBD4, 0x06AD, 0, + 4, 0xFBD5, 0x06AD, 0, + 5, 0xFBD6, 0x06AD, 0, + 7, 0xFBD7, 0x06C7, 0, + 6, 0xFBD8, 0x06C7, 0, + 7, 0xFBD9, 0x06C6, 0, + 6, 0xFBDA, 0x06C6, 0, + 7, 0xFBDB, 0x06C8, 0, + 6, 0xFBDC, 0x06C8, 0, + 7, 0xFBDD, 0x0677, 0, + 7, 0xFBDE, 0x06CB, 0, + 6, 0xFBDF, 0x06CB, 0, + 7, 0xFBE0, 0x06C5, 0, + 6, 0xFBE1, 0x06C5, 0, + 7, 0xFBE2, 0x06C9, 0, + 6, 0xFBE3, 0x06C9, 0, + 7, 0xFBE4, 0x06D0, 0, + 6, 0xFBE5, 0x06D0, 0, + 4, 0xFBE6, 0x06D0, 0, + 5, 0xFBE7, 0x06D0, 0, + 4, 0xFBE8, 0x0649, 0, + 5, 0xFBE9, 0x0649, 0, + 7, 0xFBEA, 0x0626, 0x0627, 0, + 6, 0xFBEB, 0x0626, 0x0627, 0, + 7, 0xFBEC, 0x0626, 0x06D5, 0, + 6, 0xFBED, 0x0626, 0x06D5, 0, + 7, 0xFBEE, 0x0626, 0x0648, 0, + 6, 0xFBEF, 0x0626, 0x0648, 0, + 7, 0xFBF0, 0x0626, 0x06C7, 0, + 6, 0xFBF1, 0x0626, 0x06C7, 0, + 7, 0xFBF2, 0x0626, 0x06C6, 0, + 6, 0xFBF3, 0x0626, 0x06C6, 0, + 7, 0xFBF4, 0x0626, 0x06C8, 0, + 6, 0xFBF5, 0x0626, 0x06C8, 0, + 7, 0xFBF6, 0x0626, 0x06D0, 0, + 6, 0xFBF7, 0x0626, 0x06D0, 0, + 4, 0xFBF8, 0x0626, 0x06D0, 0, + 7, 0xFBF9, 0x0626, 0x0649, 0, + 6, 0xFBFA, 0x0626, 0x0649, 0, + 4, 0xFBFB, 0x0626, 0x0649, 0, + 7, 0xFBFC, 0x06CC, 0, + 6, 0xFBFD, 0x06CC, 0, + 4, 0xFBFE, 0x06CC, 0, + 5, 0xFBFF, 0x06CC, 0, + 7, 0xFC00, 0x0626, 0x062C, 0, + 7, 0xFC01, 0x0626, 0x062D, 0, + 7, 0xFC02, 0x0626, 0x0645, 0, + 7, 0xFC03, 0x0626, 0x0649, 0, + 7, 0xFC04, 0x0626, 0x064A, 0, + 7, 0xFC05, 0x0628, 0x062C, 0, + 7, 0xFC06, 0x0628, 0x062D, 0, + 7, 0xFC07, 0x0628, 0x062E, 0, + 7, 0xFC08, 0x0628, 0x0645, 0, + 7, 0xFC09, 0x0628, 0x0649, 0, + 7, 0xFC0A, 0x0628, 0x064A, 0, + 7, 0xFC0B, 0x062A, 0x062C, 0, + 7, 0xFC0C, 0x062A, 0x062D, 0, + 7, 0xFC0D, 0x062A, 0x062E, 0, + 7, 0xFC0E, 0x062A, 0x0645, 0, + 7, 0xFC0F, 0x062A, 0x0649, 0, + 7, 0xFC10, 0x062A, 0x064A, 0, + 7, 0xFC11, 0x062B, 0x062C, 0, + 7, 0xFC12, 0x062B, 0x0645, 0, + 7, 0xFC13, 0x062B, 0x0649, 0, + 7, 0xFC14, 0x062B, 0x064A, 0, + 7, 0xFC15, 0x062C, 0x062D, 0, + 7, 0xFC16, 0x062C, 0x0645, 0, + 7, 0xFC17, 0x062D, 0x062C, 0, + 7, 0xFC18, 0x062D, 0x0645, 0, + 7, 0xFC19, 0x062E, 0x062C, 0, + 7, 0xFC1A, 0x062E, 0x062D, 0, + 7, 0xFC1B, 0x062E, 0x0645, 0, + 7, 0xFC1C, 0x0633, 0x062C, 0, + 7, 0xFC1D, 0x0633, 0x062D, 0, + 7, 0xFC1E, 0x0633, 0x062E, 0, + 7, 0xFC1F, 0x0633, 0x0645, 0, + 7, 0xFC20, 0x0635, 0x062D, 0, + 7, 0xFC21, 0x0635, 0x0645, 0, + 7, 0xFC22, 0x0636, 0x062C, 0, + 7, 0xFC23, 0x0636, 0x062D, 0, + 7, 0xFC24, 0x0636, 0x062E, 0, + 7, 0xFC25, 0x0636, 0x0645, 0, + 7, 0xFC26, 0x0637, 0x062D, 0, + 7, 0xFC27, 0x0637, 0x0645, 0, + 7, 0xFC28, 0x0638, 0x0645, 0, + 7, 0xFC29, 0x0639, 0x062C, 0, + 7, 0xFC2A, 0x0639, 0x0645, 0, + 7, 0xFC2B, 0x063A, 0x062C, 0, + 7, 0xFC2C, 0x063A, 0x0645, 0, + 7, 0xFC2D, 0x0641, 0x062C, 0, + 7, 0xFC2E, 0x0641, 0x062D, 0, + 7, 0xFC2F, 0x0641, 0x062E, 0, + 7, 0xFC30, 0x0641, 0x0645, 0, + 7, 0xFC31, 0x0641, 0x0649, 0, + 7, 0xFC32, 0x0641, 0x064A, 0, + 7, 0xFC33, 0x0642, 0x062D, 0, + 7, 0xFC34, 0x0642, 0x0645, 0, + 7, 0xFC35, 0x0642, 0x0649, 0, + 7, 0xFC36, 0x0642, 0x064A, 0, + 7, 0xFC37, 0x0643, 0x0627, 0, + 7, 0xFC38, 0x0643, 0x062C, 0, + 7, 0xFC39, 0x0643, 0x062D, 0, + 7, 0xFC3A, 0x0643, 0x062E, 0, + 7, 0xFC3B, 0x0643, 0x0644, 0, + 7, 0xFC3C, 0x0643, 0x0645, 0, + 7, 0xFC3D, 0x0643, 0x0649, 0, + 7, 0xFC3E, 0x0643, 0x064A, 0, + 7, 0xFC3F, 0x0644, 0x062C, 0, + 7, 0xFC40, 0x0644, 0x062D, 0, + 7, 0xFC41, 0x0644, 0x062E, 0, + 7, 0xFC42, 0x0644, 0x0645, 0, + 7, 0xFC43, 0x0644, 0x0649, 0, + 7, 0xFC44, 0x0644, 0x064A, 0, + 7, 0xFC45, 0x0645, 0x062C, 0, + 7, 0xFC46, 0x0645, 0x062D, 0, + 7, 0xFC47, 0x0645, 0x062E, 0, + 7, 0xFC48, 0x0645, 0x0645, 0, + 7, 0xFC49, 0x0645, 0x0649, 0, + 7, 0xFC4A, 0x0645, 0x064A, 0, + 7, 0xFC4B, 0x0646, 0x062C, 0, + 7, 0xFC4C, 0x0646, 0x062D, 0, + 7, 0xFC4D, 0x0646, 0x062E, 0, + 7, 0xFC4E, 0x0646, 0x0645, 0, + 7, 0xFC4F, 0x0646, 0x0649, 0, + 7, 0xFC50, 0x0646, 0x064A, 0, + 7, 0xFC51, 0x0647, 0x062C, 0, + 7, 0xFC52, 0x0647, 0x0645, 0, + 7, 0xFC53, 0x0647, 0x0649, 0, + 7, 0xFC54, 0x0647, 0x064A, 0, + 7, 0xFC55, 0x064A, 0x062C, 0, + 7, 0xFC56, 0x064A, 0x062D, 0, + 7, 0xFC57, 0x064A, 0x062E, 0, + 7, 0xFC58, 0x064A, 0x0645, 0, + 7, 0xFC59, 0x064A, 0x0649, 0, + 7, 0xFC5A, 0x064A, 0x064A, 0, + 7, 0xFC5B, 0x0630, 0x0670, 0, + 7, 0xFC5C, 0x0631, 0x0670, 0, + 7, 0xFC5D, 0x0649, 0x0670, 0, + 7, 0xFC5E, 0x0020, 0x064C, 0x0651, 0, + 7, 0xFC5F, 0x0020, 0x064D, 0x0651, 0, + 7, 0xFC60, 0x0020, 0x064E, 0x0651, 0, + 7, 0xFC61, 0x0020, 0x064F, 0x0651, 0, + 7, 0xFC62, 0x0020, 0x0650, 0x0651, 0, + 7, 0xFC63, 0x0020, 0x0651, 0x0670, 0, + 6, 0xFC64, 0x0626, 0x0631, 0, + 6, 0xFC65, 0x0626, 0x0632, 0, + 6, 0xFC66, 0x0626, 0x0645, 0, + 6, 0xFC67, 0x0626, 0x0646, 0, + 6, 0xFC68, 0x0626, 0x0649, 0, + 6, 0xFC69, 0x0626, 0x064A, 0, + 6, 0xFC6A, 0x0628, 0x0631, 0, + 6, 0xFC6B, 0x0628, 0x0632, 0, + 6, 0xFC6C, 0x0628, 0x0645, 0, + 6, 0xFC6D, 0x0628, 0x0646, 0, + 6, 0xFC6E, 0x0628, 0x0649, 0, + 6, 0xFC6F, 0x0628, 0x064A, 0, + 6, 0xFC70, 0x062A, 0x0631, 0, + 6, 0xFC71, 0x062A, 0x0632, 0, + 6, 0xFC72, 0x062A, 0x0645, 0, + 6, 0xFC73, 0x062A, 0x0646, 0, + 6, 0xFC74, 0x062A, 0x0649, 0, + 6, 0xFC75, 0x062A, 0x064A, 0, + 6, 0xFC76, 0x062B, 0x0631, 0, + 6, 0xFC77, 0x062B, 0x0632, 0, + 6, 0xFC78, 0x062B, 0x0645, 0, + 6, 0xFC79, 0x062B, 0x0646, 0, + 6, 0xFC7A, 0x062B, 0x0649, 0, + 6, 0xFC7B, 0x062B, 0x064A, 0, + 6, 0xFC7C, 0x0641, 0x0649, 0, + 6, 0xFC7D, 0x0641, 0x064A, 0, + 6, 0xFC7E, 0x0642, 0x0649, 0, + 6, 0xFC7F, 0x0642, 0x064A, 0, + 6, 0xFC80, 0x0643, 0x0627, 0, + 6, 0xFC81, 0x0643, 0x0644, 0, + 6, 0xFC82, 0x0643, 0x0645, 0, + 6, 0xFC83, 0x0643, 0x0649, 0, + 6, 0xFC84, 0x0643, 0x064A, 0, + 6, 0xFC85, 0x0644, 0x0645, 0, + 6, 0xFC86, 0x0644, 0x0649, 0, + 6, 0xFC87, 0x0644, 0x064A, 0, + 6, 0xFC88, 0x0645, 0x0627, 0, + 6, 0xFC89, 0x0645, 0x0645, 0, + 6, 0xFC8A, 0x0646, 0x0631, 0, + 6, 0xFC8B, 0x0646, 0x0632, 0, + 6, 0xFC8C, 0x0646, 0x0645, 0, + 6, 0xFC8D, 0x0646, 0x0646, 0, + 6, 0xFC8E, 0x0646, 0x0649, 0, + 6, 0xFC8F, 0x0646, 0x064A, 0, + 6, 0xFC90, 0x0649, 0x0670, 0, + 6, 0xFC91, 0x064A, 0x0631, 0, + 6, 0xFC92, 0x064A, 0x0632, 0, + 6, 0xFC93, 0x064A, 0x0645, 0, + 6, 0xFC94, 0x064A, 0x0646, 0, + 6, 0xFC95, 0x064A, 0x0649, 0, + 6, 0xFC96, 0x064A, 0x064A, 0, + 4, 0xFC97, 0x0626, 0x062C, 0, + 4, 0xFC98, 0x0626, 0x062D, 0, + 4, 0xFC99, 0x0626, 0x062E, 0, + 4, 0xFC9A, 0x0626, 0x0645, 0, + 4, 0xFC9B, 0x0626, 0x0647, 0, + 4, 0xFC9C, 0x0628, 0x062C, 0, + 4, 0xFC9D, 0x0628, 0x062D, 0, + 4, 0xFC9E, 0x0628, 0x062E, 0, + 4, 0xFC9F, 0x0628, 0x0645, 0, + 4, 0xFCA0, 0x0628, 0x0647, 0, + 4, 0xFCA1, 0x062A, 0x062C, 0, + 4, 0xFCA2, 0x062A, 0x062D, 0, + 4, 0xFCA3, 0x062A, 0x062E, 0, + 4, 0xFCA4, 0x062A, 0x0645, 0, + 4, 0xFCA5, 0x062A, 0x0647, 0, + 4, 0xFCA6, 0x062B, 0x0645, 0, + 4, 0xFCA7, 0x062C, 0x062D, 0, + 4, 0xFCA8, 0x062C, 0x0645, 0, + 4, 0xFCA9, 0x062D, 0x062C, 0, + 4, 0xFCAA, 0x062D, 0x0645, 0, + 4, 0xFCAB, 0x062E, 0x062C, 0, + 4, 0xFCAC, 0x062E, 0x0645, 0, + 4, 0xFCAD, 0x0633, 0x062C, 0, + 4, 0xFCAE, 0x0633, 0x062D, 0, + 4, 0xFCAF, 0x0633, 0x062E, 0, + 4, 0xFCB0, 0x0633, 0x0645, 0, + 4, 0xFCB1, 0x0635, 0x062D, 0, + 4, 0xFCB2, 0x0635, 0x062E, 0, + 4, 0xFCB3, 0x0635, 0x0645, 0, + 4, 0xFCB4, 0x0636, 0x062C, 0, + 4, 0xFCB5, 0x0636, 0x062D, 0, + 4, 0xFCB6, 0x0636, 0x062E, 0, + 4, 0xFCB7, 0x0636, 0x0645, 0, + 4, 0xFCB8, 0x0637, 0x062D, 0, + 4, 0xFCB9, 0x0638, 0x0645, 0, + 4, 0xFCBA, 0x0639, 0x062C, 0, + 4, 0xFCBB, 0x0639, 0x0645, 0, + 4, 0xFCBC, 0x063A, 0x062C, 0, + 4, 0xFCBD, 0x063A, 0x0645, 0, + 4, 0xFCBE, 0x0641, 0x062C, 0, + 4, 0xFCBF, 0x0641, 0x062D, 0, + 4, 0xFCC0, 0x0641, 0x062E, 0, + 4, 0xFCC1, 0x0641, 0x0645, 0, + 4, 0xFCC2, 0x0642, 0x062D, 0, + 4, 0xFCC3, 0x0642, 0x0645, 0, + 4, 0xFCC4, 0x0643, 0x062C, 0, + 4, 0xFCC5, 0x0643, 0x062D, 0, + 4, 0xFCC6, 0x0643, 0x062E, 0, + 4, 0xFCC7, 0x0643, 0x0644, 0, + 4, 0xFCC8, 0x0643, 0x0645, 0, + 4, 0xFCC9, 0x0644, 0x062C, 0, + 4, 0xFCCA, 0x0644, 0x062D, 0, + 4, 0xFCCB, 0x0644, 0x062E, 0, + 4, 0xFCCC, 0x0644, 0x0645, 0, + 4, 0xFCCD, 0x0644, 0x0647, 0, + 4, 0xFCCE, 0x0645, 0x062C, 0, + 4, 0xFCCF, 0x0645, 0x062D, 0, + 4, 0xFCD0, 0x0645, 0x062E, 0, + 4, 0xFCD1, 0x0645, 0x0645, 0, + 4, 0xFCD2, 0x0646, 0x062C, 0, + 4, 0xFCD3, 0x0646, 0x062D, 0, + 4, 0xFCD4, 0x0646, 0x062E, 0, + 4, 0xFCD5, 0x0646, 0x0645, 0, + 4, 0xFCD6, 0x0646, 0x0647, 0, + 4, 0xFCD7, 0x0647, 0x062C, 0, + 4, 0xFCD8, 0x0647, 0x0645, 0, + 4, 0xFCD9, 0x0647, 0x0670, 0, + 4, 0xFCDA, 0x064A, 0x062C, 0, + 4, 0xFCDB, 0x064A, 0x062D, 0, + 4, 0xFCDC, 0x064A, 0x062E, 0, + 4, 0xFCDD, 0x064A, 0x0645, 0, + 4, 0xFCDE, 0x064A, 0x0647, 0, + 5, 0xFCDF, 0x0626, 0x0645, 0, + 5, 0xFCE0, 0x0626, 0x0647, 0, + 5, 0xFCE1, 0x0628, 0x0645, 0, + 5, 0xFCE2, 0x0628, 0x0647, 0, + 5, 0xFCE3, 0x062A, 0x0645, 0, + 5, 0xFCE4, 0x062A, 0x0647, 0, + 5, 0xFCE5, 0x062B, 0x0645, 0, + 5, 0xFCE6, 0x062B, 0x0647, 0, + 5, 0xFCE7, 0x0633, 0x0645, 0, + 5, 0xFCE8, 0x0633, 0x0647, 0, + 5, 0xFCE9, 0x0634, 0x0645, 0, + 5, 0xFCEA, 0x0634, 0x0647, 0, + 5, 0xFCEB, 0x0643, 0x0644, 0, + 5, 0xFCEC, 0x0643, 0x0645, 0, + 5, 0xFCED, 0x0644, 0x0645, 0, + 5, 0xFCEE, 0x0646, 0x0645, 0, + 5, 0xFCEF, 0x0646, 0x0647, 0, + 5, 0xFCF0, 0x064A, 0x0645, 0, + 5, 0xFCF1, 0x064A, 0x0647, 0, + 5, 0xFCF2, 0x0640, 0x064E, 0x0651, 0, + 5, 0xFCF3, 0x0640, 0x064F, 0x0651, 0, + 5, 0xFCF4, 0x0640, 0x0650, 0x0651, 0, + 7, 0xFCF5, 0x0637, 0x0649, 0, + 7, 0xFCF6, 0x0637, 0x064A, 0, + 7, 0xFCF7, 0x0639, 0x0649, 0, + 7, 0xFCF8, 0x0639, 0x064A, 0, + 7, 0xFCF9, 0x063A, 0x0649, 0, + 7, 0xFCFA, 0x063A, 0x064A, 0, + 7, 0xFCFB, 0x0633, 0x0649, 0, + 7, 0xFCFC, 0x0633, 0x064A, 0, + 7, 0xFCFD, 0x0634, 0x0649, 0, + 7, 0xFCFE, 0x0634, 0x064A, 0, + 7, 0xFCFF, 0x062D, 0x0649, 0, + 7, 0xFD00, 0x062D, 0x064A, 0, + 7, 0xFD01, 0x062C, 0x0649, 0, + 7, 0xFD02, 0x062C, 0x064A, 0, + 7, 0xFD03, 0x062E, 0x0649, 0, + 7, 0xFD04, 0x062E, 0x064A, 0, + 7, 0xFD05, 0x0635, 0x0649, 0, + 7, 0xFD06, 0x0635, 0x064A, 0, + 7, 0xFD07, 0x0636, 0x0649, 0, + 7, 0xFD08, 0x0636, 0x064A, 0, + 7, 0xFD09, 0x0634, 0x062C, 0, + 7, 0xFD0A, 0x0634, 0x062D, 0, + 7, 0xFD0B, 0x0634, 0x062E, 0, + 7, 0xFD0C, 0x0634, 0x0645, 0, + 7, 0xFD0D, 0x0634, 0x0631, 0, + 7, 0xFD0E, 0x0633, 0x0631, 0, + 7, 0xFD0F, 0x0635, 0x0631, 0, + 7, 0xFD10, 0x0636, 0x0631, 0, + 6, 0xFD11, 0x0637, 0x0649, 0, + 6, 0xFD12, 0x0637, 0x064A, 0, + 6, 0xFD13, 0x0639, 0x0649, 0, + 6, 0xFD14, 0x0639, 0x064A, 0, + 6, 0xFD15, 0x063A, 0x0649, 0, + 6, 0xFD16, 0x063A, 0x064A, 0, + 6, 0xFD17, 0x0633, 0x0649, 0, + 6, 0xFD18, 0x0633, 0x064A, 0, + 6, 0xFD19, 0x0634, 0x0649, 0, + 6, 0xFD1A, 0x0634, 0x064A, 0, + 6, 0xFD1B, 0x062D, 0x0649, 0, + 6, 0xFD1C, 0x062D, 0x064A, 0, + 6, 0xFD1D, 0x062C, 0x0649, 0, + 6, 0xFD1E, 0x062C, 0x064A, 0, + 6, 0xFD1F, 0x062E, 0x0649, 0, + 6, 0xFD20, 0x062E, 0x064A, 0, + 6, 0xFD21, 0x0635, 0x0649, 0, + 6, 0xFD22, 0x0635, 0x064A, 0, + 6, 0xFD23, 0x0636, 0x0649, 0, + 6, 0xFD24, 0x0636, 0x064A, 0, + 6, 0xFD25, 0x0634, 0x062C, 0, + 6, 0xFD26, 0x0634, 0x062D, 0, + 6, 0xFD27, 0x0634, 0x062E, 0, + 6, 0xFD28, 0x0634, 0x0645, 0, + 6, 0xFD29, 0x0634, 0x0631, 0, + 6, 0xFD2A, 0x0633, 0x0631, 0, + 6, 0xFD2B, 0x0635, 0x0631, 0, + 6, 0xFD2C, 0x0636, 0x0631, 0, + 4, 0xFD2D, 0x0634, 0x062C, 0, + 4, 0xFD2E, 0x0634, 0x062D, 0, + 4, 0xFD2F, 0x0634, 0x062E, 0, + 4, 0xFD30, 0x0634, 0x0645, 0, + 4, 0xFD31, 0x0633, 0x0647, 0, + 4, 0xFD32, 0x0634, 0x0647, 0, + 4, 0xFD33, 0x0637, 0x0645, 0, + 5, 0xFD34, 0x0633, 0x062C, 0, + 5, 0xFD35, 0x0633, 0x062D, 0, + 5, 0xFD36, 0x0633, 0x062E, 0, + 5, 0xFD37, 0x0634, 0x062C, 0, + 5, 0xFD38, 0x0634, 0x062D, 0, + 5, 0xFD39, 0x0634, 0x062E, 0, + 5, 0xFD3A, 0x0637, 0x0645, 0, + 5, 0xFD3B, 0x0638, 0x0645, 0, + 6, 0xFD3C, 0x0627, 0x064B, 0, + 7, 0xFD3D, 0x0627, 0x064B, 0, + 4, 0xFD50, 0x062A, 0x062C, 0x0645, 0, + 6, 0xFD51, 0x062A, 0x062D, 0x062C, 0, + 4, 0xFD52, 0x062A, 0x062D, 0x062C, 0, + 4, 0xFD53, 0x062A, 0x062D, 0x0645, 0, + 4, 0xFD54, 0x062A, 0x062E, 0x0645, 0, + 4, 0xFD55, 0x062A, 0x0645, 0x062C, 0, + 4, 0xFD56, 0x062A, 0x0645, 0x062D, 0, + 4, 0xFD57, 0x062A, 0x0645, 0x062E, 0, + 6, 0xFD58, 0x062C, 0x0645, 0x062D, 0, + 4, 0xFD59, 0x062C, 0x0645, 0x062D, 0, + 6, 0xFD5A, 0x062D, 0x0645, 0x064A, 0, + 6, 0xFD5B, 0x062D, 0x0645, 0x0649, 0, + 4, 0xFD5C, 0x0633, 0x062D, 0x062C, 0, + 4, 0xFD5D, 0x0633, 0x062C, 0x062D, 0, + 6, 0xFD5E, 0x0633, 0x062C, 0x0649, 0, + 6, 0xFD5F, 0x0633, 0x0645, 0x062D, 0, + 4, 0xFD60, 0x0633, 0x0645, 0x062D, 0, + 4, 0xFD61, 0x0633, 0x0645, 0x062C, 0, + 6, 0xFD62, 0x0633, 0x0645, 0x0645, 0, + 4, 0xFD63, 0x0633, 0x0645, 0x0645, 0, + 6, 0xFD64, 0x0635, 0x062D, 0x062D, 0, + 4, 0xFD65, 0x0635, 0x062D, 0x062D, 0, + 6, 0xFD66, 0x0635, 0x0645, 0x0645, 0, + 6, 0xFD67, 0x0634, 0x062D, 0x0645, 0, + 4, 0xFD68, 0x0634, 0x062D, 0x0645, 0, + 6, 0xFD69, 0x0634, 0x062C, 0x064A, 0, + 6, 0xFD6A, 0x0634, 0x0645, 0x062E, 0, + 4, 0xFD6B, 0x0634, 0x0645, 0x062E, 0, + 6, 0xFD6C, 0x0634, 0x0645, 0x0645, 0, + 4, 0xFD6D, 0x0634, 0x0645, 0x0645, 0, + 6, 0xFD6E, 0x0636, 0x062D, 0x0649, 0, + 6, 0xFD6F, 0x0636, 0x062E, 0x0645, 0, + 4, 0xFD70, 0x0636, 0x062E, 0x0645, 0, + 6, 0xFD71, 0x0637, 0x0645, 0x062D, 0, + 4, 0xFD72, 0x0637, 0x0645, 0x062D, 0, + 4, 0xFD73, 0x0637, 0x0645, 0x0645, 0, + 6, 0xFD74, 0x0637, 0x0645, 0x064A, 0, + 6, 0xFD75, 0x0639, 0x062C, 0x0645, 0, + 6, 0xFD76, 0x0639, 0x0645, 0x0645, 0, + 4, 0xFD77, 0x0639, 0x0645, 0x0645, 0, + 6, 0xFD78, 0x0639, 0x0645, 0x0649, 0, + 6, 0xFD79, 0x063A, 0x0645, 0x0645, 0, + 6, 0xFD7A, 0x063A, 0x0645, 0x064A, 0, + 6, 0xFD7B, 0x063A, 0x0645, 0x0649, 0, + 6, 0xFD7C, 0x0641, 0x062E, 0x0645, 0, + 4, 0xFD7D, 0x0641, 0x062E, 0x0645, 0, + 6, 0xFD7E, 0x0642, 0x0645, 0x062D, 0, + 6, 0xFD7F, 0x0642, 0x0645, 0x0645, 0, + 6, 0xFD80, 0x0644, 0x062D, 0x0645, 0, + 6, 0xFD81, 0x0644, 0x062D, 0x064A, 0, + 6, 0xFD82, 0x0644, 0x062D, 0x0649, 0, + 4, 0xFD83, 0x0644, 0x062C, 0x062C, 0, + 6, 0xFD84, 0x0644, 0x062C, 0x062C, 0, + 6, 0xFD85, 0x0644, 0x062E, 0x0645, 0, + 4, 0xFD86, 0x0644, 0x062E, 0x0645, 0, + 6, 0xFD87, 0x0644, 0x0645, 0x062D, 0, + 4, 0xFD88, 0x0644, 0x0645, 0x062D, 0, + 4, 0xFD89, 0x0645, 0x062D, 0x062C, 0, + 4, 0xFD8A, 0x0645, 0x062D, 0x0645, 0, + 6, 0xFD8B, 0x0645, 0x062D, 0x064A, 0, + 4, 0xFD8C, 0x0645, 0x062C, 0x062D, 0, + 4, 0xFD8D, 0x0645, 0x062C, 0x0645, 0, + 4, 0xFD8E, 0x0645, 0x062E, 0x062C, 0, + 4, 0xFD8F, 0x0645, 0x062E, 0x0645, 0, + 4, 0xFD92, 0x0645, 0x062C, 0x062E, 0, + 4, 0xFD93, 0x0647, 0x0645, 0x062C, 0, + 4, 0xFD94, 0x0647, 0x0645, 0x0645, 0, + 4, 0xFD95, 0x0646, 0x062D, 0x0645, 0, + 6, 0xFD96, 0x0646, 0x062D, 0x0649, 0, + 6, 0xFD97, 0x0646, 0x062C, 0x0645, 0, + 4, 0xFD98, 0x0646, 0x062C, 0x0645, 0, + 6, 0xFD99, 0x0646, 0x062C, 0x0649, 0, + 6, 0xFD9A, 0x0646, 0x0645, 0x064A, 0, + 6, 0xFD9B, 0x0646, 0x0645, 0x0649, 0, + 6, 0xFD9C, 0x064A, 0x0645, 0x0645, 0, + 4, 0xFD9D, 0x064A, 0x0645, 0x0645, 0, + 6, 0xFD9E, 0x0628, 0x062E, 0x064A, 0, + 6, 0xFD9F, 0x062A, 0x062C, 0x064A, 0, + 6, 0xFDA0, 0x062A, 0x062C, 0x0649, 0, + 6, 0xFDA1, 0x062A, 0x062E, 0x064A, 0, + 6, 0xFDA2, 0x062A, 0x062E, 0x0649, 0, + 6, 0xFDA3, 0x062A, 0x0645, 0x064A, 0, + 6, 0xFDA4, 0x062A, 0x0645, 0x0649, 0, + 6, 0xFDA5, 0x062C, 0x0645, 0x064A, 0, + 6, 0xFDA6, 0x062C, 0x062D, 0x0649, 0, + 6, 0xFDA7, 0x062C, 0x0645, 0x0649, 0, + 6, 0xFDA8, 0x0633, 0x062E, 0x0649, 0, + 6, 0xFDA9, 0x0635, 0x062D, 0x064A, 0, + 6, 0xFDAA, 0x0634, 0x062D, 0x064A, 0, + 6, 0xFDAB, 0x0636, 0x062D, 0x064A, 0, + 6, 0xFDAC, 0x0644, 0x062C, 0x064A, 0, + 6, 0xFDAD, 0x0644, 0x0645, 0x064A, 0, + 6, 0xFDAE, 0x064A, 0x062D, 0x064A, 0, + 6, 0xFDAF, 0x064A, 0x062C, 0x064A, 0, + 6, 0xFDB0, 0x064A, 0x0645, 0x064A, 0, + 6, 0xFDB1, 0x0645, 0x0645, 0x064A, 0, + 6, 0xFDB2, 0x0642, 0x0645, 0x064A, 0, + 6, 0xFDB3, 0x0646, 0x062D, 0x064A, 0, + 4, 0xFDB4, 0x0642, 0x0645, 0x062D, 0, + 4, 0xFDB5, 0x0644, 0x062D, 0x0645, 0, + 6, 0xFDB6, 0x0639, 0x0645, 0x064A, 0, + 6, 0xFDB7, 0x0643, 0x0645, 0x064A, 0, + 4, 0xFDB8, 0x0646, 0x062C, 0x062D, 0, + 6, 0xFDB9, 0x0645, 0x062E, 0x064A, 0, + 4, 0xFDBA, 0x0644, 0x062C, 0x0645, 0, + 6, 0xFDBB, 0x0643, 0x0645, 0x0645, 0, + 6, 0xFDBC, 0x0644, 0x062C, 0x0645, 0, + 6, 0xFDBD, 0x0646, 0x062C, 0x062D, 0, + 6, 0xFDBE, 0x062C, 0x062D, 0x064A, 0, + 6, 0xFDBF, 0x062D, 0x062C, 0x064A, 0, + 6, 0xFDC0, 0x0645, 0x062C, 0x064A, 0, + 6, 0xFDC1, 0x0641, 0x0645, 0x064A, 0, + 6, 0xFDC2, 0x0628, 0x062D, 0x064A, 0, + 4, 0xFDC3, 0x0643, 0x0645, 0x0645, 0, + 4, 0xFDC4, 0x0639, 0x062C, 0x0645, 0, + 4, 0xFDC5, 0x0635, 0x0645, 0x0645, 0, + 6, 0xFDC6, 0x0633, 0x062E, 0x064A, 0, + 6, 0xFDC7, 0x0646, 0x062C, 0x064A, 0, + 7, 0xFDF0, 0x0635, 0x0644, 0x06D2, 0, + 7, 0xFDF1, 0x0642, 0x0644, 0x06D2, 0, + 7, 0xFDF2, 0x0627, 0x0644, 0x0644, 0x0647, 0, + 7, 0xFDF3, 0x0627, 0x0643, 0x0628, 0x0631, 0, + 7, 0xFDF4, 0x0645, 0x062D, 0x0645, 0x062F, 0, + 7, 0xFDF5, 0x0635, 0x0644, 0x0639, 0x0645, 0, + 7, 0xFDF6, 0x0631, 0x0633, 0x0648, 0x0644, 0, + 7, 0xFDF7, 0x0639, 0x0644, 0x064A, 0x0647, 0, + 7, 0xFDF8, 0x0648, 0x0633, 0x0644, 0x0645, 0, + 7, 0xFDF9, 0x0635, 0x0644, 0x0649, 0, + 7, 0xFDFA, 0x0635, 0x0644, 0x0649, 0x0020, 0x0627, 0x0644, 0x0644, 0x0647, 0x0020, 0x0639, 0x0644, 0x064A, 0x0647, 0x0020, 0x0648, 0x0633, 0x0644, 0x0645, 0, + 7, 0xFDFB, 0x062C, 0x0644, 0x0020, 0x062C, 0x0644, 0x0627, 0x0644, 0x0647, 0, + 11, 0xFE30, 0x2025, 0, + 11, 0xFE31, 0x2014, 0, + 11, 0xFE32, 0x2013, 0, + 11, 0xFE33, 0x005F, 0, + 11, 0xFE34, 0x005F, 0, + 11, 0xFE35, 0x0028, 0, + 11, 0xFE36, 0x0029, 0, + 11, 0xFE37, 0x007B, 0, + 11, 0xFE38, 0x007D, 0, + 11, 0xFE39, 0x3014, 0, + 11, 0xFE3A, 0x3015, 0, + 11, 0xFE3B, 0x3010, 0, + 11, 0xFE3C, 0x3011, 0, + 11, 0xFE3D, 0x300A, 0, + 11, 0xFE3E, 0x300B, 0, + 11, 0xFE3F, 0x3008, 0, + 11, 0xFE40, 0x3009, 0, + 11, 0xFE41, 0x300C, 0, + 11, 0xFE42, 0x300D, 0, + 11, 0xFE43, 0x300E, 0, + 11, 0xFE44, 0x300F, 0, + 16, 0xFE49, 0x203E, 0, + 16, 0xFE4A, 0x203E, 0, + 16, 0xFE4B, 0x203E, 0, + 16, 0xFE4C, 0x203E, 0, + 16, 0xFE4D, 0x005F, 0, + 16, 0xFE4E, 0x005F, 0, + 16, 0xFE4F, 0x005F, 0, + 14, 0xFE50, 0x002C, 0, + 14, 0xFE51, 0x3001, 0, + 14, 0xFE52, 0x002E, 0, + 14, 0xFE54, 0x003B, 0, + 14, 0xFE55, 0x003A, 0, + 14, 0xFE56, 0x003F, 0, + 14, 0xFE57, 0x0021, 0, + 14, 0xFE58, 0x2014, 0, + 14, 0xFE59, 0x0028, 0, + 14, 0xFE5A, 0x0029, 0, + 14, 0xFE5B, 0x007B, 0, + 14, 0xFE5C, 0x007D, 0, + 14, 0xFE5D, 0x3014, 0, + 14, 0xFE5E, 0x3015, 0, + 14, 0xFE5F, 0x0023, 0, + 14, 0xFE60, 0x0026, 0, + 14, 0xFE61, 0x002A, 0, + 14, 0xFE62, 0x002B, 0, + 14, 0xFE63, 0x002D, 0, + 14, 0xFE64, 0x003C, 0, + 14, 0xFE65, 0x003E, 0, + 14, 0xFE66, 0x003D, 0, + 14, 0xFE68, 0x005C, 0, + 14, 0xFE69, 0x0024, 0, + 14, 0xFE6A, 0x0025, 0, + 14, 0xFE6B, 0x0040, 0, + 7, 0xFE70, 0x0020, 0x064B, 0, + 5, 0xFE71, 0x0640, 0x064B, 0, + 7, 0xFE72, 0x0020, 0x064C, 0, + 7, 0xFE74, 0x0020, 0x064D, 0, + 7, 0xFE76, 0x0020, 0x064E, 0, + 5, 0xFE77, 0x0640, 0x064E, 0, + 7, 0xFE78, 0x0020, 0x064F, 0, + 5, 0xFE79, 0x0640, 0x064F, 0, + 7, 0xFE7A, 0x0020, 0x0650, 0, + 5, 0xFE7B, 0x0640, 0x0650, 0, + 7, 0xFE7C, 0x0020, 0x0651, 0, + 5, 0xFE7D, 0x0640, 0x0651, 0, + 7, 0xFE7E, 0x0020, 0x0652, 0, + 5, 0xFE7F, 0x0640, 0x0652, 0, + 7, 0xFE80, 0x0621, 0, + 7, 0xFE81, 0x0622, 0, + 6, 0xFE82, 0x0622, 0, + 7, 0xFE83, 0x0623, 0, + 6, 0xFE84, 0x0623, 0, + 7, 0xFE85, 0x0624, 0, + 6, 0xFE86, 0x0624, 0, + 7, 0xFE87, 0x0625, 0, + 6, 0xFE88, 0x0625, 0, + 7, 0xFE89, 0x0626, 0, + 6, 0xFE8A, 0x0626, 0, + 4, 0xFE8B, 0x0626, 0, + 5, 0xFE8C, 0x0626, 0, + 7, 0xFE8D, 0x0627, 0, + 6, 0xFE8E, 0x0627, 0, + 7, 0xFE8F, 0x0628, 0, + 6, 0xFE90, 0x0628, 0, + 4, 0xFE91, 0x0628, 0, + 5, 0xFE92, 0x0628, 0, + 7, 0xFE93, 0x0629, 0, + 6, 0xFE94, 0x0629, 0, + 7, 0xFE95, 0x062A, 0, + 6, 0xFE96, 0x062A, 0, + 4, 0xFE97, 0x062A, 0, + 5, 0xFE98, 0x062A, 0, + 7, 0xFE99, 0x062B, 0, + 6, 0xFE9A, 0x062B, 0, + 4, 0xFE9B, 0x062B, 0, + 5, 0xFE9C, 0x062B, 0, + 7, 0xFE9D, 0x062C, 0, + 6, 0xFE9E, 0x062C, 0, + 4, 0xFE9F, 0x062C, 0, + 5, 0xFEA0, 0x062C, 0, + 7, 0xFEA1, 0x062D, 0, + 6, 0xFEA2, 0x062D, 0, + 4, 0xFEA3, 0x062D, 0, + 5, 0xFEA4, 0x062D, 0, + 7, 0xFEA5, 0x062E, 0, + 6, 0xFEA6, 0x062E, 0, + 4, 0xFEA7, 0x062E, 0, + 5, 0xFEA8, 0x062E, 0, + 7, 0xFEA9, 0x062F, 0, + 6, 0xFEAA, 0x062F, 0, + 7, 0xFEAB, 0x0630, 0, + 6, 0xFEAC, 0x0630, 0, + 7, 0xFEAD, 0x0631, 0, + 6, 0xFEAE, 0x0631, 0, + 7, 0xFEAF, 0x0632, 0, + 6, 0xFEB0, 0x0632, 0, + 7, 0xFEB1, 0x0633, 0, + 6, 0xFEB2, 0x0633, 0, + 4, 0xFEB3, 0x0633, 0, + 5, 0xFEB4, 0x0633, 0, + 7, 0xFEB5, 0x0634, 0, + 6, 0xFEB6, 0x0634, 0, + 4, 0xFEB7, 0x0634, 0, + 5, 0xFEB8, 0x0634, 0, + 7, 0xFEB9, 0x0635, 0, + 6, 0xFEBA, 0x0635, 0, + 4, 0xFEBB, 0x0635, 0, + 5, 0xFEBC, 0x0635, 0, + 7, 0xFEBD, 0x0636, 0, + 6, 0xFEBE, 0x0636, 0, + 4, 0xFEBF, 0x0636, 0, + 5, 0xFEC0, 0x0636, 0, + 7, 0xFEC1, 0x0637, 0, + 6, 0xFEC2, 0x0637, 0, + 4, 0xFEC3, 0x0637, 0, + 5, 0xFEC4, 0x0637, 0, + 7, 0xFEC5, 0x0638, 0, + 6, 0xFEC6, 0x0638, 0, + 4, 0xFEC7, 0x0638, 0, + 5, 0xFEC8, 0x0638, 0, + 7, 0xFEC9, 0x0639, 0, + 6, 0xFECA, 0x0639, 0, + 4, 0xFECB, 0x0639, 0, + 5, 0xFECC, 0x0639, 0, + 7, 0xFECD, 0x063A, 0, + 6, 0xFECE, 0x063A, 0, + 4, 0xFECF, 0x063A, 0, + 5, 0xFED0, 0x063A, 0, + 7, 0xFED1, 0x0641, 0, + 6, 0xFED2, 0x0641, 0, + 4, 0xFED3, 0x0641, 0, + 5, 0xFED4, 0x0641, 0, + 7, 0xFED5, 0x0642, 0, + 6, 0xFED6, 0x0642, 0, + 4, 0xFED7, 0x0642, 0, + 5, 0xFED8, 0x0642, 0, + 7, 0xFED9, 0x0643, 0, + 6, 0xFEDA, 0x0643, 0, + 4, 0xFEDB, 0x0643, 0, + 5, 0xFEDC, 0x0643, 0, + 7, 0xFEDD, 0x0644, 0, + 6, 0xFEDE, 0x0644, 0, + 4, 0xFEDF, 0x0644, 0, + 5, 0xFEE0, 0x0644, 0, + 7, 0xFEE1, 0x0645, 0, + 6, 0xFEE2, 0x0645, 0, + 4, 0xFEE3, 0x0645, 0, + 5, 0xFEE4, 0x0645, 0, + 7, 0xFEE5, 0x0646, 0, + 6, 0xFEE6, 0x0646, 0, + 4, 0xFEE7, 0x0646, 0, + 5, 0xFEE8, 0x0646, 0, + 7, 0xFEE9, 0x0647, 0, + 6, 0xFEEA, 0x0647, 0, + 4, 0xFEEB, 0x0647, 0, + 5, 0xFEEC, 0x0647, 0, + 7, 0xFEED, 0x0648, 0, + 6, 0xFEEE, 0x0648, 0, + 7, 0xFEEF, 0x0649, 0, + 6, 0xFEF0, 0x0649, 0, + 7, 0xFEF1, 0x064A, 0, + 6, 0xFEF2, 0x064A, 0, + 4, 0xFEF3, 0x064A, 0, + 5, 0xFEF4, 0x064A, 0, + 7, 0xFEF5, 0x0644, 0x0622, 0, + 6, 0xFEF6, 0x0644, 0x0622, 0, + 7, 0xFEF7, 0x0644, 0x0623, 0, + 6, 0xFEF8, 0x0644, 0x0623, 0, + 7, 0xFEF9, 0x0644, 0x0625, 0, + 6, 0xFEFA, 0x0644, 0x0625, 0, + 7, 0xFEFB, 0x0644, 0x0627, 0, + 6, 0xFEFC, 0x0644, 0x0627, 0, + 12, 0xFF01, 0x0021, 0, + 12, 0xFF02, 0x0022, 0, + 12, 0xFF03, 0x0023, 0, + 12, 0xFF04, 0x0024, 0, + 12, 0xFF05, 0x0025, 0, + 12, 0xFF06, 0x0026, 0, + 12, 0xFF07, 0x0027, 0, + 12, 0xFF08, 0x0028, 0, + 12, 0xFF09, 0x0029, 0, + 12, 0xFF0A, 0x002A, 0, + 12, 0xFF0B, 0x002B, 0, + 12, 0xFF0C, 0x002C, 0, + 12, 0xFF0D, 0x002D, 0, + 12, 0xFF0E, 0x002E, 0, + 12, 0xFF0F, 0x002F, 0, + 12, 0xFF10, 0x0030, 0, + 12, 0xFF11, 0x0031, 0, + 12, 0xFF12, 0x0032, 0, + 12, 0xFF13, 0x0033, 0, + 12, 0xFF14, 0x0034, 0, + 12, 0xFF15, 0x0035, 0, + 12, 0xFF16, 0x0036, 0, + 12, 0xFF17, 0x0037, 0, + 12, 0xFF18, 0x0038, 0, + 12, 0xFF19, 0x0039, 0, + 12, 0xFF1A, 0x003A, 0, + 12, 0xFF1B, 0x003B, 0, + 12, 0xFF1C, 0x003C, 0, + 12, 0xFF1D, 0x003D, 0, + 12, 0xFF1E, 0x003E, 0, + 12, 0xFF1F, 0x003F, 0, + 12, 0xFF20, 0x0040, 0, + 12, 0xFF21, 0x0041, 0, + 12, 0xFF22, 0x0042, 0, + 12, 0xFF23, 0x0043, 0, + 12, 0xFF24, 0x0044, 0, + 12, 0xFF25, 0x0045, 0, + 12, 0xFF26, 0x0046, 0, + 12, 0xFF27, 0x0047, 0, + 12, 0xFF28, 0x0048, 0, + 12, 0xFF29, 0x0049, 0, + 12, 0xFF2A, 0x004A, 0, + 12, 0xFF2B, 0x004B, 0, + 12, 0xFF2C, 0x004C, 0, + 12, 0xFF2D, 0x004D, 0, + 12, 0xFF2E, 0x004E, 0, + 12, 0xFF2F, 0x004F, 0, + 12, 0xFF30, 0x0050, 0, + 12, 0xFF31, 0x0051, 0, + 12, 0xFF32, 0x0052, 0, + 12, 0xFF33, 0x0053, 0, + 12, 0xFF34, 0x0054, 0, + 12, 0xFF35, 0x0055, 0, + 12, 0xFF36, 0x0056, 0, + 12, 0xFF37, 0x0057, 0, + 12, 0xFF38, 0x0058, 0, + 12, 0xFF39, 0x0059, 0, + 12, 0xFF3A, 0x005A, 0, + 12, 0xFF3B, 0x005B, 0, + 12, 0xFF3C, 0x005C, 0, + 12, 0xFF3D, 0x005D, 0, + 12, 0xFF3E, 0x005E, 0, + 12, 0xFF3F, 0x005F, 0, + 12, 0xFF40, 0x0060, 0, + 12, 0xFF41, 0x0061, 0, + 12, 0xFF42, 0x0062, 0, + 12, 0xFF43, 0x0063, 0, + 12, 0xFF44, 0x0064, 0, + 12, 0xFF45, 0x0065, 0, + 12, 0xFF46, 0x0066, 0, + 12, 0xFF47, 0x0067, 0, + 12, 0xFF48, 0x0068, 0, + 12, 0xFF49, 0x0069, 0, + 12, 0xFF4A, 0x006A, 0, + 12, 0xFF4B, 0x006B, 0, + 12, 0xFF4C, 0x006C, 0, + 12, 0xFF4D, 0x006D, 0, + 12, 0xFF4E, 0x006E, 0, + 12, 0xFF4F, 0x006F, 0, + 12, 0xFF50, 0x0070, 0, + 12, 0xFF51, 0x0071, 0, + 12, 0xFF52, 0x0072, 0, + 12, 0xFF53, 0x0073, 0, + 12, 0xFF54, 0x0074, 0, + 12, 0xFF55, 0x0075, 0, + 12, 0xFF56, 0x0076, 0, + 12, 0xFF57, 0x0077, 0, + 12, 0xFF58, 0x0078, 0, + 12, 0xFF59, 0x0079, 0, + 12, 0xFF5A, 0x007A, 0, + 12, 0xFF5B, 0x007B, 0, + 12, 0xFF5C, 0x007C, 0, + 12, 0xFF5D, 0x007D, 0, + 12, 0xFF5E, 0x007E, 0, + 13, 0xFF61, 0x3002, 0, + 13, 0xFF62, 0x300C, 0, + 13, 0xFF63, 0x300D, 0, + 13, 0xFF64, 0x3001, 0, + 13, 0xFF65, 0x30FB, 0, + 13, 0xFF66, 0x30F2, 0, + 13, 0xFF67, 0x30A1, 0, + 13, 0xFF68, 0x30A3, 0, + 13, 0xFF69, 0x30A5, 0, + 13, 0xFF6A, 0x30A7, 0, + 13, 0xFF6B, 0x30A9, 0, + 13, 0xFF6C, 0x30E3, 0, + 13, 0xFF6D, 0x30E5, 0, + 13, 0xFF6E, 0x30E7, 0, + 13, 0xFF6F, 0x30C3, 0, + 13, 0xFF70, 0x30FC, 0, + 13, 0xFF71, 0x30A2, 0, + 13, 0xFF72, 0x30A4, 0, + 13, 0xFF73, 0x30A6, 0, + 13, 0xFF74, 0x30A8, 0, + 13, 0xFF75, 0x30AA, 0, + 13, 0xFF76, 0x30AB, 0, + 13, 0xFF77, 0x30AD, 0, + 13, 0xFF78, 0x30AF, 0, + 13, 0xFF79, 0x30B1, 0, + 13, 0xFF7A, 0x30B3, 0, + 13, 0xFF7B, 0x30B5, 0, + 13, 0xFF7C, 0x30B7, 0, + 13, 0xFF7D, 0x30B9, 0, + 13, 0xFF7E, 0x30BB, 0, + 13, 0xFF7F, 0x30BD, 0, + 13, 0xFF80, 0x30BF, 0, + 13, 0xFF81, 0x30C1, 0, + 13, 0xFF82, 0x30C4, 0, + 13, 0xFF83, 0x30C6, 0, + 13, 0xFF84, 0x30C8, 0, + 13, 0xFF85, 0x30CA, 0, + 13, 0xFF86, 0x30CB, 0, + 13, 0xFF87, 0x30CC, 0, + 13, 0xFF88, 0x30CD, 0, + 13, 0xFF89, 0x30CE, 0, + 13, 0xFF8A, 0x30CF, 0, + 13, 0xFF8B, 0x30D2, 0, + 13, 0xFF8C, 0x30D5, 0, + 13, 0xFF8D, 0x30D8, 0, + 13, 0xFF8E, 0x30DB, 0, + 13, 0xFF8F, 0x30DE, 0, + 13, 0xFF90, 0x30DF, 0, + 13, 0xFF91, 0x30E0, 0, + 13, 0xFF92, 0x30E1, 0, + 13, 0xFF93, 0x30E2, 0, + 13, 0xFF94, 0x30E4, 0, + 13, 0xFF95, 0x30E6, 0, + 13, 0xFF96, 0x30E8, 0, + 13, 0xFF97, 0x30E9, 0, + 13, 0xFF98, 0x30EA, 0, + 13, 0xFF99, 0x30EB, 0, + 13, 0xFF9A, 0x30EC, 0, + 13, 0xFF9B, 0x30ED, 0, + 13, 0xFF9C, 0x30EF, 0, + 13, 0xFF9D, 0x30F3, 0, + 13, 0xFF9E, 0x3099, 0, + 13, 0xFF9F, 0x309A, 0, + 13, 0xFFA0, 0x3164, 0, + 13, 0xFFA1, 0x3131, 0, + 13, 0xFFA2, 0x3132, 0, + 13, 0xFFA3, 0x3133, 0, + 13, 0xFFA4, 0x3134, 0, + 13, 0xFFA5, 0x3135, 0, + 13, 0xFFA6, 0x3136, 0, + 13, 0xFFA7, 0x3137, 0, + 13, 0xFFA8, 0x3138, 0, + 13, 0xFFA9, 0x3139, 0, + 13, 0xFFAA, 0x313A, 0, + 13, 0xFFAB, 0x313B, 0, + 13, 0xFFAC, 0x313C, 0, + 13, 0xFFAD, 0x313D, 0, + 13, 0xFFAE, 0x313E, 0, + 13, 0xFFAF, 0x313F, 0, + 13, 0xFFB0, 0x3140, 0, + 13, 0xFFB1, 0x3141, 0, + 13, 0xFFB2, 0x3142, 0, + 13, 0xFFB3, 0x3143, 0, + 13, 0xFFB4, 0x3144, 0, + 13, 0xFFB5, 0x3145, 0, + 13, 0xFFB6, 0x3146, 0, + 13, 0xFFB7, 0x3147, 0, + 13, 0xFFB8, 0x3148, 0, + 13, 0xFFB9, 0x3149, 0, + 13, 0xFFBA, 0x314A, 0, + 13, 0xFFBB, 0x314B, 0, + 13, 0xFFBC, 0x314C, 0, + 13, 0xFFBD, 0x314D, 0, + 13, 0xFFBE, 0x314E, 0, + 13, 0xFFC2, 0x314F, 0, + 13, 0xFFC3, 0x3150, 0, + 13, 0xFFC4, 0x3151, 0, + 13, 0xFFC5, 0x3152, 0, + 13, 0xFFC6, 0x3153, 0, + 13, 0xFFC7, 0x3154, 0, + 13, 0xFFCA, 0x3155, 0, + 13, 0xFFCB, 0x3156, 0, + 13, 0xFFCC, 0x3157, 0, + 13, 0xFFCD, 0x3158, 0, + 13, 0xFFCE, 0x3159, 0, + 13, 0xFFCF, 0x315A, 0, + 13, 0xFFD2, 0x315B, 0, + 13, 0xFFD3, 0x315C, 0, + 13, 0xFFD4, 0x315D, 0, + 13, 0xFFD5, 0x315E, 0, + 13, 0xFFD6, 0x315F, 0, + 13, 0xFFD7, 0x3160, 0, + 13, 0xFFDA, 0x3161, 0, + 13, 0xFFDB, 0x3162, 0, + 13, 0xFFDC, 0x3163, 0, + 12, 0xFFE0, 0x00A2, 0, + 12, 0xFFE1, 0x00A3, 0, + 12, 0xFFE2, 0x00AC, 0, + 12, 0xFFE3, 0x00AF, 0, + 12, 0xFFE4, 0x00A6, 0, + 12, 0xFFE5, 0x00A5, 0, + 12, 0xFFE6, 0x20A9, 0, + 13, 0xFFE8, 0x2502, 0, + 13, 0xFFE9, 0x2190, 0, + 13, 0xFFEA, 0x2191, 0, + 13, 0xFFEB, 0x2192, 0, + 13, 0xFFEC, 0x2193, 0, + 13, 0xFFED, 0x25A0, 0, + 13, 0xFFEE, 0x25CB, 0, + +}; + +static const Q_UINT16 di_00[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 5, 0, 10, 0, 0, 0, 0, 14, + 0, 0, 19, 23, 27, 32, 0, 0, + 36, 41, 45, 0, 49, 55, 61, 0, + 67, 72, 77, 82, 87, 92, 0, 97, + 102, 107, 112, 117, 122, 127, 132, 137, + 0, 142, 147, 152, 157, 162, 167, 0, + 0, 172, 177, 182, 187, 192, 0, 0, + 197, 202, 207, 212, 217, 222, 0, 227, + 232, 237, 242, 247, 252, 257, 262, 267, + 0, 272, 277, 282, 287, 292, 297, 0, + 0, 302, 307, 312, 317, 322, 0, 327, +}; + +static const Q_UINT16 di_01[] = { + 332, 337, 342, 347, 352, 357, 362, 367, + 372, 377, 382, 387, 392, 397, 402, 407, + 0, 0, 412, 417, 422, 427, 432, 437, + 442, 447, 452, 457, 462, 467, 472, 477, + 482, 487, 492, 497, 502, 507, 0, 0, + 512, 517, 522, 527, 532, 537, 542, 547, + 552, 0, 557, 562, 567, 572, 577, 582, + 0, 587, 592, 597, 602, 607, 612, 617, + 622, 0, 0, 627, 632, 637, 642, 647, + 652, 657, 0, 0, 662, 667, 672, 677, + 682, 687, 0, 0, 692, 697, 702, 707, + 712, 717, 722, 727, 732, 737, 742, 747, + 752, 757, 762, 767, 772, 777, 0, 0, + 782, 787, 792, 797, 802, 807, 812, 817, + 822, 827, 832, 837, 842, 847, 852, 857, + 862, 867, 872, 877, 882, 887, 892, 897, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 901, 906, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 911, + 916, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 921, 926, 931, 936, + 941, 946, 951, 956, 961, 966, 971, 976, + 981, 986, 991, 996, 1001, 1006, 1011, 1016, + 1021, 1026, 1031, 1036, 1041, 0, 1046, 1051, + 1056, 1061, 1066, 1071, 0, 0, 1076, 1081, + 1086, 1091, 1096, 1101, 1106, 1111, 1116, 1121, + 1126, 1131, 1136, 1141, 1146, 1151, 0, 0, + 1156, 1161, 1166, 1171, 1176, 1181, 1186, 1191, +}; + +static const Q_UINT16 di_02[] = { + 1196, 1201, 1206, 1211, 1216, 1221, 1226, 1231, + 1236, 1241, 1246, 1251, 1256, 1261, 1266, 1271, + 1276, 1281, 1286, 1291, 1296, 1301, 1306, 1311, + 1316, 1321, 1326, 1331, 0, 0, 1336, 1341, + 0, 0, 0, 0, 0, 0, 1346, 1351, + 1356, 1361, 1366, 1371, 1376, 1381, 1386, 1391, + 1396, 1401, 1406, 1411, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1416, 1420, 1424, 1428, 1432, 1436, 1440, 1444, + 1448, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1452, 1457, 1462, 1467, 1472, 1477, 0, 0, + 1482, 1486, 1490, 1494, 1498, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 di_03[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1502, 1506, 0, 1510, 1514, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1519, 0, 0, 0, + 0, 0, 1523, 0, 0, 0, 1528, 0, + 0, 0, 0, 0, 1532, 1537, 1542, 1547, + 1551, 1556, 1561, 0, 1566, 0, 1571, 1576, + 1581, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1586, 1591, 1596, 1601, 1606, 1611, + 1616, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1621, 1626, 1631, 1636, 1641, 0, + 1646, 1650, 1654, 1658, 1663, 1668, 1672, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1676, 1680, 1684, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 di_04[] = { + 1688, 1693, 0, 1698, 0, 0, 0, 1703, + 0, 0, 0, 0, 1708, 1713, 1718, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1723, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1728, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1733, 1738, 0, 1743, 0, 0, 0, 1748, + 0, 0, 0, 0, 1753, 1758, 1763, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1768, 1773, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1778, 1783, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1788, 1793, 1798, 1803, 0, 0, 1808, 1813, + 0, 0, 1818, 1823, 1828, 1833, 1838, 1843, + 0, 0, 1848, 1853, 1858, 1863, 1868, 1873, + 0, 0, 1878, 1883, 1888, 1893, 1898, 1903, + 1908, 1913, 1918, 1923, 1928, 1933, 0, 0, + 1938, 1943, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 di_05[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1948, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 di_06[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1953, 1958, 1963, 1968, 1973, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1978, 1983, 1988, + 1993, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1998, 0, 2003, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 2008, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 di_07[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 di_09[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 2013, 0, 0, 0, 0, 0, 0, + 0, 2018, 0, 0, 2023, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 2028, 2033, 2038, 2043, 2048, 2053, 2058, 2063, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 2068, 2073, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 2078, 2083, 0, 2088, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 di_0A[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 2093, 0, 0, 2098, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 2103, 2108, 2113, 0, 0, 2118, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 di_0B[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 2123, 0, 0, 2128, 2133, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 2138, 2143, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 2148, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 2153, 2158, 2163, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 di_0C[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 2168, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 2173, 0, 0, 0, 0, 0, 0, 2178, + 2183, 0, 2188, 2193, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 di_0D[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 2198, 2203, 2208, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 2213, 0, 2218, 2223, 2228, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 di_0E[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 2233, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 2238, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 2243, 2248, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 di_0F[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 2253, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 2257, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 2262, 0, 0, + 0, 0, 2267, 0, 0, 0, 0, 2272, + 0, 0, 0, 0, 2277, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 2282, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 2287, 0, 2292, 2297, 2302, + 2307, 2312, 0, 0, 0, 0, 0, 0, + 0, 2317, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 2322, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 2327, 0, 0, + 0, 0, 2332, 0, 0, 0, 0, 2337, + 0, 0, 0, 0, 2342, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 2347, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 di_10[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 2352, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 di_1E[] = { + 2357, 2362, 2367, 2372, 2377, 2382, 2387, 2392, + 2397, 2402, 2407, 2412, 2417, 2422, 2427, 2432, + 2437, 2442, 2447, 2452, 2457, 2462, 2467, 2472, + 2477, 2482, 2487, 2492, 2497, 2502, 2507, 2512, + 2517, 2522, 2527, 2532, 2537, 2542, 2547, 2552, + 2557, 2562, 2567, 2572, 2577, 2582, 2587, 2592, + 2597, 2602, 2607, 2612, 2617, 2622, 2627, 2632, + 2637, 2642, 2647, 2652, 2657, 2662, 2667, 2672, + 2677, 2682, 2687, 2692, 2697, 2702, 2707, 2712, + 2717, 2722, 2727, 2732, 2737, 2742, 2747, 2752, + 2757, 2762, 2767, 2772, 2777, 2782, 2787, 2792, + 2797, 2802, 2807, 2812, 2817, 2822, 2827, 2832, + 2837, 2842, 2847, 2852, 2857, 2862, 2867, 2872, + 2877, 2882, 2887, 2892, 2897, 2902, 2907, 2912, + 2917, 2922, 2927, 2932, 2937, 2942, 2947, 2952, + 2957, 2962, 2967, 2972, 2977, 2982, 2987, 2992, + 2997, 3002, 3007, 3012, 3017, 3022, 3027, 3032, + 3037, 3042, 3047, 3052, 3057, 3062, 3067, 3072, + 3077, 3082, 3087, 3092, 3097, 3102, 3107, 3112, + 3117, 3122, 3127, 3132, 0, 0, 0, 0, + 3137, 3142, 3147, 3152, 3157, 3162, 3167, 3172, + 3177, 3182, 3187, 3192, 3197, 3202, 3207, 3212, + 3217, 3222, 3227, 3232, 3237, 3242, 3247, 3252, + 3257, 3262, 3267, 3272, 3277, 3282, 3287, 3292, + 3297, 3302, 3307, 3312, 3317, 3322, 3327, 3332, + 3337, 3342, 3347, 3352, 3357, 3362, 3367, 3372, + 3377, 3382, 3387, 3392, 3397, 3402, 3407, 3412, + 3417, 3422, 3427, 3432, 3437, 3442, 3447, 3452, + 3457, 3462, 3467, 3472, 3477, 3482, 3487, 3492, + 3497, 3502, 3507, 3512, 3517, 3522, 3527, 3532, + 3537, 3542, 3547, 3552, 3557, 3562, 3567, 3572, + 3577, 3582, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 di_1F[] = { + 3587, 3592, 3597, 3602, 3607, 3612, 3617, 3622, + 3627, 3632, 3637, 3642, 3647, 3652, 3657, 3662, + 3667, 3672, 3677, 3682, 3687, 3692, 0, 0, + 3697, 3702, 3707, 3712, 3717, 3722, 0, 0, + 3727, 3732, 3737, 3742, 3747, 3752, 3757, 3762, + 3767, 3772, 3777, 3782, 3787, 3792, 3797, 3802, + 3807, 3812, 3817, 3822, 3827, 3832, 3837, 3842, + 3847, 3852, 3857, 3862, 3867, 3872, 3877, 3882, + 3887, 3892, 3897, 3902, 3907, 3912, 0, 0, + 3917, 3922, 3927, 3932, 3937, 3942, 0, 0, + 3947, 3952, 3957, 3962, 3967, 3972, 3977, 3982, + 0, 3987, 0, 3992, 0, 3997, 0, 4002, + 4007, 4012, 4017, 4022, 4027, 4032, 4037, 4042, + 4047, 4052, 4057, 4062, 4067, 4072, 4077, 4082, + 4087, 4092, 4096, 4101, 4105, 4110, 4114, 4119, + 4123, 4128, 4132, 4137, 4141, 4146, 0, 0, + 4150, 4155, 4160, 4165, 4170, 4175, 4180, 4185, + 4190, 4195, 4200, 4205, 4210, 4215, 4220, 4225, + 4230, 4235, 4240, 4245, 4250, 4255, 4260, 4265, + 4270, 4275, 4280, 4285, 4290, 4295, 4300, 4305, + 4310, 4315, 4320, 4325, 4330, 4335, 4340, 4345, + 4350, 4355, 4360, 4365, 4370, 4375, 4380, 4385, + 4390, 4395, 4400, 4405, 4410, 0, 4415, 4420, + 4425, 4430, 4435, 4440, 4444, 4449, 4454, 4458, + 4463, 4468, 4473, 4478, 4483, 0, 4488, 4493, + 4498, 4503, 4507, 4512, 4516, 4521, 4526, 4531, + 4536, 4541, 4546, 4551, 0, 0, 4555, 4560, + 4565, 4570, 4575, 4580, 0, 4584, 4589, 4594, + 4599, 4604, 4609, 4614, 4618, 4623, 4628, 4633, + 4638, 4643, 4648, 4653, 4657, 4662, 4667, 4671, + 0, 0, 4675, 4680, 4685, 0, 4690, 4695, + 4700, 4705, 4709, 4714, 4718, 4723, 4727, 0, +}; + +static const Q_UINT16 di_20[] = { + 4732, 4736, 4740, 4744, 4748, 4752, 4756, 4760, + 4764, 4768, 4772, 0, 0, 0, 0, 0, + 0, 4776, 0, 0, 0, 0, 0, 4780, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 4785, 4789, 4794, 0, + 0, 0, 0, 0, 0, 0, 0, 4800, + 0, 0, 0, 4804, 4809, 0, 4815, 4820, + 0, 0, 0, 0, 4826, 0, 4831, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 4836, 4841, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 4846, 0, 0, 0, 4850, 4854, 4858, 4862, + 4866, 4870, 4874, 4878, 4882, 4886, 4890, 4894, + 4898, 4902, 4906, 4910, 4914, 4918, 4922, 4926, + 4930, 4934, 4938, 4942, 4946, 4950, 4954, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 4958, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 di_21[] = { + 4963, 4969, 4975, 4979, 0, 4984, 4990, 4996, + 0, 5000, 5005, 5009, 5013, 5017, 5021, 5025, + 5029, 5033, 5037, 5041, 0, 5045, 5049, 0, + 0, 5054, 5058, 5062, 5066, 5070, 0, 0, + 5074, 5079, 5085, 0, 5090, 0, 5094, 0, + 5098, 0, 5102, 5106, 5110, 5114, 0, 5118, + 5122, 5126, 0, 5130, 5134, 5138, 5142, 5146, + 5150, 5154, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 5158, 5164, 5170, 5176, 5182, + 5188, 5194, 5200, 5206, 5212, 5218, 5224, 5230, + 5235, 5239, 5244, 5250, 5255, 5259, 5264, 5270, + 5277, 5282, 5286, 5291, 5297, 5301, 5305, 5309, + 5313, 5317, 5322, 5328, 5333, 5337, 5342, 5348, + 5355, 5360, 5364, 5369, 5375, 5379, 5383, 5387, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 5391, 5396, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 5401, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 5406, 5411, 5416, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 di_22[] = { + 0, 0, 0, 0, 5421, 0, 0, 0, + 0, 5426, 0, 0, 5431, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 5436, 0, 5441, 0, + 0, 0, 0, 0, 5446, 5451, 0, 5457, + 5462, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 5468, 0, 0, 5473, 0, 0, 5478, + 0, 5483, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 5488, 0, 5493, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 5498, 5503, 5508, + 5513, 5518, 0, 0, 5523, 5528, 0, 0, + 5533, 5538, 0, 0, 0, 0, 0, 0, + 5543, 5548, 0, 0, 5553, 5558, 0, 0, + 5563, 5568, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 5573, 5578, 5583, 5588, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 5593, 5598, 5603, 5608, 0, 0, 0, 0, + 0, 0, 5613, 5618, 5623, 5628, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 di_23[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 5633, 5637, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 di_24[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 5641, 5645, 5649, 5653, 5657, 5661, 5665, 5669, + 5673, 5677, 5682, 5687, 5692, 5697, 5702, 5707, + 5712, 5717, 5722, 5727, 5732, 5738, 5744, 5750, + 5756, 5762, 5768, 5774, 5780, 5786, 5793, 5800, + 5807, 5814, 5821, 5828, 5835, 5842, 5849, 5856, + 5863, 5868, 5873, 5878, 5883, 5888, 5893, 5898, + 5903, 5908, 5914, 5920, 5926, 5932, 5938, 5944, + 5950, 5956, 5962, 5968, 5974, 5980, 5986, 5992, + 5998, 6004, 6010, 6016, 6022, 6028, 6034, 6040, + 6046, 6052, 6058, 6064, 6070, 6076, 6082, 6088, + 6094, 6100, 6106, 6112, 6118, 6124, 6130, 6134, + 6138, 6142, 6146, 6150, 6154, 6158, 6162, 6166, + 6170, 6174, 6178, 6182, 6186, 6190, 6194, 6198, + 6202, 6206, 6210, 6214, 6218, 6222, 6226, 6230, + 6234, 6238, 6242, 6246, 6250, 6254, 6258, 6262, + 6266, 6270, 6274, 6278, 6282, 6286, 6290, 6294, + 6298, 6302, 6306, 6310, 6314, 6318, 6322, 6326, + 6330, 6334, 6338, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 di_2E[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 6342, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 6346, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 di_2F[] = { + 6350, 6354, 6358, 6362, 6366, 6370, 6374, 6378, + 6382, 6386, 6390, 6394, 6398, 6402, 6406, 6410, + 6414, 6418, 6422, 6426, 6430, 6434, 6438, 6442, + 6446, 6450, 6454, 6458, 6462, 6466, 6470, 6474, + 6478, 6482, 6486, 6490, 6494, 6498, 6502, 6506, + 6510, 6514, 6518, 6522, 6526, 6530, 6534, 6538, + 6542, 6546, 6550, 6554, 6558, 6562, 6566, 6570, + 6574, 6578, 6582, 6586, 6590, 6594, 6598, 6602, + 6606, 6610, 6614, 6618, 6622, 6626, 6630, 6634, + 6638, 6642, 6646, 6650, 6654, 6658, 6662, 6666, + 6670, 6674, 6678, 6682, 6686, 6690, 6694, 6698, + 6702, 6706, 6710, 6714, 6718, 6722, 6726, 6730, + 6734, 6738, 6742, 6746, 6750, 6754, 6758, 6762, + 6766, 6770, 6774, 6778, 6782, 6786, 6790, 6794, + 6798, 6802, 6806, 6810, 6814, 6818, 6822, 6826, + 6830, 6834, 6838, 6842, 6846, 6850, 6854, 6858, + 6862, 6866, 6870, 6874, 6878, 6882, 6886, 6890, + 6894, 6898, 6902, 6906, 6910, 6914, 6918, 6922, + 6926, 6930, 6934, 6938, 6942, 6946, 6950, 6954, + 6958, 6962, 6966, 6970, 6974, 6978, 6982, 6986, + 6990, 6994, 6998, 7002, 7006, 7010, 7014, 7018, + 7022, 7026, 7030, 7034, 7038, 7042, 7046, 7050, + 7054, 7058, 7062, 7066, 7070, 7074, 7078, 7082, + 7086, 7090, 7094, 7098, 7102, 7106, 7110, 7114, + 7118, 7122, 7126, 7130, 7134, 7138, 7142, 7146, + 7150, 7154, 7158, 7162, 7166, 7170, 7174, 7178, + 7182, 7186, 7190, 7194, 7198, 7202, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 di_30[] = { + 7206, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 7210, 0, + 7214, 7218, 7222, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 7226, 0, 7231, 0, + 7236, 0, 7241, 0, 7246, 0, 7251, 0, + 7256, 0, 7261, 0, 7266, 0, 7271, 0, + 7276, 0, 7281, 0, 0, 7286, 0, 7291, + 0, 7296, 0, 0, 0, 0, 0, 0, + 7301, 7306, 0, 7311, 7316, 0, 7321, 7326, + 0, 7331, 7336, 0, 7341, 7346, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 7351, 0, 0, 0, + 0, 0, 0, 7356, 7361, 0, 7366, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 7371, 0, 7376, 0, + 7381, 0, 7386, 0, 7391, 0, 7396, 0, + 7401, 0, 7406, 0, 7411, 0, 7416, 0, + 7421, 0, 7426, 0, 0, 7431, 0, 7436, + 0, 7441, 0, 0, 0, 0, 0, 0, + 7446, 7451, 0, 7456, 7461, 0, 7466, 7471, + 0, 7476, 7481, 0, 7486, 7491, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 7496, 0, 0, 7501, + 7506, 7511, 7516, 0, 0, 0, 7521, 0, +}; + +static const Q_UINT16 di_31[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 7526, 7530, 7534, 7538, 7542, 7546, 7550, + 7554, 7558, 7562, 7566, 7570, 7574, 7578, 7582, + 7586, 7590, 7594, 7598, 7602, 7606, 7610, 7614, + 7618, 7622, 7626, 7630, 7634, 7638, 7642, 7646, + 7650, 7654, 7658, 7662, 7666, 7670, 7674, 7678, + 7682, 7686, 7690, 7694, 7698, 7702, 7706, 7710, + 7714, 7718, 7722, 7726, 7730, 7734, 7738, 7742, + 7746, 7750, 7754, 7758, 7762, 7766, 7770, 7774, + 7778, 7782, 7786, 7790, 7794, 7798, 7802, 7806, + 7810, 7814, 7818, 7822, 7826, 7830, 7834, 7838, + 7842, 7846, 7850, 7854, 7858, 7862, 7866, 7870, + 7874, 7878, 7882, 7886, 7890, 7894, 7898, 0, + 0, 0, 7902, 7906, 7910, 7914, 7918, 7922, + 7926, 7930, 7934, 7938, 7942, 7946, 7950, 7954, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 di_32[] = { + 7958, 7964, 7970, 7976, 7982, 7988, 7994, 8000, + 8006, 8012, 8018, 8024, 8030, 8036, 8042, 8049, + 8056, 8063, 8070, 8077, 8084, 8091, 8098, 8105, + 8112, 8119, 8126, 8133, 8140, 0, 0, 0, + 8147, 8153, 8159, 8165, 8171, 8177, 8183, 8189, + 8195, 8201, 8207, 8213, 8219, 8225, 8231, 8237, + 8243, 8249, 8255, 8261, 8267, 8273, 8279, 8285, + 8291, 8297, 8303, 8309, 8315, 8321, 8327, 8333, + 8339, 8345, 8351, 8357, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 8363, 8367, 8371, 8375, 8379, 8383, 8387, 8391, + 8395, 8399, 8403, 8407, 8411, 8415, 8419, 8424, + 8429, 8434, 8439, 8444, 8449, 8454, 8459, 8464, + 8469, 8474, 8479, 8484, 0, 0, 0, 0, + 8489, 8493, 8497, 8501, 8505, 8509, 8513, 8517, + 8521, 8525, 8529, 8533, 8537, 8541, 8545, 8549, + 8553, 8557, 8561, 8565, 8569, 8573, 8577, 8581, + 8585, 8589, 8593, 8597, 8601, 8605, 8609, 8613, + 8617, 8621, 8625, 8629, 8633, 8637, 8641, 8645, + 8649, 8653, 8657, 8661, 8665, 8669, 8673, 8677, + 8681, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 8685, 8690, 8695, 8700, 8705, 8710, 8715, 8720, + 8725, 8730, 8736, 8742, 0, 0, 0, 0, + 8748, 8752, 8756, 8760, 8764, 8768, 8772, 8776, + 8780, 8784, 8788, 8792, 8796, 8800, 8804, 8808, + 8812, 8816, 8820, 8824, 8828, 8832, 8836, 8840, + 8844, 8848, 8852, 8856, 8860, 8864, 8868, 8872, + 8876, 8880, 8884, 8888, 8892, 8896, 8900, 8904, + 8908, 8912, 8916, 8920, 8924, 8928, 8932, 0, +}; + +static const Q_UINT16 di_33[] = { + 8936, 8943, 8950, 8957, 8963, 8970, 8976, 8982, + 8990, 8997, 9003, 9009, 9015, 9022, 9029, 9035, + 9041, 9046, 9052, 9059, 9066, 9071, 9079, 9088, + 9096, 9102, 9110, 9118, 9125, 9131, 9137, 9143, + 9150, 9158, 9165, 9171, 9177, 9183, 9188, 9193, + 9198, 9203, 9209, 9215, 9223, 9229, 9236, 9244, + 9250, 9255, 9260, 9268, 9275, 9283, 9289, 9297, + 9302, 9308, 9314, 9320, 9326, 9332, 9339, 9345, + 9350, 9356, 9362, 9368, 9375, 9381, 9387, 9393, + 9401, 9408, 9413, 9421, 9426, 9433, 9440, 9446, + 9452, 9458, 9465, 9470, 9476, 9483, 9488, 9496, + 9502, 9507, 9512, 9517, 9522, 9527, 9532, 9537, + 9542, 9547, 9552, 9558, 9564, 9570, 9576, 9582, + 9588, 9594, 9600, 9606, 9612, 9618, 9624, 9630, + 9636, 9642, 9648, 9653, 9658, 9664, 9669, 0, + 0, 0, 0, 9674, 9679, 9684, 9689, 9694, + 9701, 9706, 9711, 9716, 9721, 9726, 9731, 9736, + 9741, 9747, 9754, 9759, 9764, 9769, 9774, 9779, + 9784, 9789, 9795, 9801, 9807, 9813, 9818, 9823, + 9828, 9833, 9838, 9843, 9848, 9853, 9858, 9863, + 9869, 9875, 9880, 9886, 9892, 9898, 9903, 9909, + 9915, 9922, 9927, 9933, 9939, 9945, 9951, 9959, + 9968, 9973, 9978, 9983, 9988, 9993, 9998, 10003, + 10008, 10013, 10018, 10023, 10028, 10033, 10038, 10043, + 10048, 10053, 10058, 10065, 10070, 10075, 10080, 10087, + 10093, 10098, 10103, 10108, 10113, 10118, 10123, 10128, + 10133, 10138, 10143, 10149, 10154, 10159, 10165, 10171, + 10176, 10183, 10189, 10194, 10199, 10204, 0, 0, + 10209, 10214, 10219, 10224, 10229, 10234, 10239, 10244, + 10249, 10254, 10260, 10266, 10272, 10278, 10284, 10290, + 10296, 10302, 10308, 10314, 10320, 10326, 10332, 10338, + 10344, 10350, 10356, 10362, 10368, 10374, 10380, 0, +}; + +static const Q_UINT16 di_F9[] = { + 10386, 10390, 10394, 10398, 10402, 10406, 10410, 10414, + 10418, 10422, 10426, 10430, 10434, 10438, 10442, 10446, + 10450, 10454, 10458, 10462, 10466, 10470, 10474, 10478, + 10482, 10486, 10490, 10494, 10498, 10502, 10506, 10510, + 10514, 10518, 10522, 10526, 10530, 10534, 10538, 10542, + 10546, 10550, 10554, 10558, 10562, 10566, 10570, 10574, + 10578, 10582, 10586, 10590, 10594, 10598, 10602, 10606, + 10610, 10614, 10618, 10622, 10626, 10630, 10634, 10638, + 10642, 10646, 10650, 10654, 10658, 10662, 10666, 10670, + 10674, 10678, 10682, 10686, 10690, 10694, 10698, 10702, + 10706, 10710, 10714, 10718, 10722, 10726, 10730, 10734, + 10738, 10742, 10746, 10750, 10754, 10758, 10762, 10766, + 10770, 10774, 10778, 10782, 10786, 10790, 10794, 10798, + 10802, 10806, 10810, 10814, 10818, 10822, 10826, 10830, + 10834, 10838, 10842, 10846, 10850, 10854, 10858, 10862, + 10866, 10870, 10874, 10878, 10882, 10886, 10890, 10894, + 10898, 10902, 10906, 10910, 10914, 10918, 10922, 10926, + 10930, 10934, 10938, 10942, 10946, 10950, 10954, 10958, + 10962, 10966, 10970, 10974, 10978, 10982, 10986, 10990, + 10994, 10998, 11002, 11006, 11010, 11014, 11018, 11022, + 11026, 11030, 11034, 11038, 11042, 11046, 11050, 11054, + 11058, 11062, 11066, 11070, 11074, 11078, 11082, 11086, + 11090, 11094, 11098, 11102, 11106, 11110, 11114, 11118, + 11122, 11126, 11130, 11134, 11138, 11142, 11146, 11150, + 11154, 11158, 11162, 11166, 11170, 11174, 11178, 11182, + 11186, 11190, 11194, 11198, 11202, 11206, 11210, 11214, + 11218, 11222, 11226, 11230, 11234, 11238, 11242, 11246, + 11250, 11254, 11258, 11262, 11266, 11270, 11274, 11278, + 11282, 11286, 11290, 11294, 11298, 11302, 11306, 11310, + 11314, 11318, 11322, 11326, 11330, 11334, 11338, 11342, + 11346, 11350, 11354, 11358, 11362, 11366, 11370, 11374, + 11378, 11382, 11386, 11390, 11394, 11398, 11402, 11406, +}; + +static const Q_UINT16 di_FA[] = { + 11410, 11414, 11418, 11422, 11426, 11430, 11434, 11438, + 11442, 11446, 11450, 11454, 11458, 11462, 0, 0, + 11466, 0, 11470, 0, 0, 11474, 11478, 11482, + 11486, 11490, 11494, 11498, 11502, 11506, 11510, 0, + 11514, 0, 11518, 0, 0, 11522, 11526, 0, + 0, 0, 11530, 11534, 11538, 11542, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 di_FB[] = { + 11546, 11551, 11556, 11561, 11567, 11573, 11578, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 11583, 11588, 11593, 11598, 11603, + 0, 0, 0, 0, 0, 11608, 0, 11613, + 11618, 11622, 11626, 11630, 11634, 11638, 11642, 11646, + 11650, 11654, 11658, 11663, 11668, 11673, 11678, 11683, + 11688, 11693, 11698, 11703, 11708, 11713, 11718, 0, + 11723, 11728, 11733, 11738, 11743, 0, 11748, 0, + 11753, 11758, 0, 11763, 11768, 0, 11773, 11778, + 11783, 11788, 11793, 11798, 11803, 11808, 11813, 11818, + 11823, 11827, 11831, 11835, 11839, 11843, 11847, 11851, + 11855, 11859, 11863, 11867, 11871, 11875, 11879, 11883, + 11887, 11891, 11895, 11899, 11903, 11907, 11911, 11915, + 11919, 11923, 11927, 11931, 11935, 11939, 11943, 11947, + 11951, 11955, 11959, 11963, 11967, 11971, 11975, 11979, + 11983, 11987, 11991, 11995, 11999, 12003, 12007, 12011, + 12015, 12019, 12023, 12027, 12031, 12035, 12039, 12043, + 12047, 12051, 12055, 12059, 12063, 12067, 12071, 12075, + 12079, 12083, 12087, 12091, 12095, 12099, 12103, 12107, + 12111, 12115, 12119, 12123, 12127, 12131, 12135, 12139, + 12143, 12147, 12151, 12155, 12159, 12163, 12167, 12171, + 12175, 12179, 12183, 12187, 12191, 12195, 12199, 12203, + 12207, 12211, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 12215, 12219, 12223, 12227, 12231, + 12235, 12239, 12243, 12247, 12251, 12255, 12259, 12263, + 12267, 12271, 12275, 12279, 12283, 12287, 12291, 12295, + 12299, 12303, 12307, 12312, 12317, 12322, 12327, 12332, + 12337, 12342, 12347, 12352, 12357, 12362, 12367, 12372, + 12377, 12382, 12387, 12392, 12397, 12401, 12405, 12409, +}; + +static const Q_UINT16 di_FC[] = { + 12413, 12418, 12423, 12428, 12433, 12438, 12443, 12448, + 12453, 12458, 12463, 12468, 12473, 12478, 12483, 12488, + 12493, 12498, 12503, 12508, 12513, 12518, 12523, 12528, + 12533, 12538, 12543, 12548, 12553, 12558, 12563, 12568, + 12573, 12578, 12583, 12588, 12593, 12598, 12603, 12608, + 12613, 12618, 12623, 12628, 12633, 12638, 12643, 12648, + 12653, 12658, 12663, 12668, 12673, 12678, 12683, 12688, + 12693, 12698, 12703, 12708, 12713, 12718, 12723, 12728, + 12733, 12738, 12743, 12748, 12753, 12758, 12763, 12768, + 12773, 12778, 12783, 12788, 12793, 12798, 12803, 12808, + 12813, 12818, 12823, 12828, 12833, 12838, 12843, 12848, + 12853, 12858, 12863, 12868, 12873, 12878, 12883, 12889, + 12895, 12901, 12907, 12913, 12919, 12924, 12929, 12934, + 12939, 12944, 12949, 12954, 12959, 12964, 12969, 12974, + 12979, 12984, 12989, 12994, 12999, 13004, 13009, 13014, + 13019, 13024, 13029, 13034, 13039, 13044, 13049, 13054, + 13059, 13064, 13069, 13074, 13079, 13084, 13089, 13094, + 13099, 13104, 13109, 13114, 13119, 13124, 13129, 13134, + 13139, 13144, 13149, 13154, 13159, 13164, 13169, 13174, + 13179, 13184, 13189, 13194, 13199, 13204, 13209, 13214, + 13219, 13224, 13229, 13234, 13239, 13244, 13249, 13254, + 13259, 13264, 13269, 13274, 13279, 13284, 13289, 13294, + 13299, 13304, 13309, 13314, 13319, 13324, 13329, 13334, + 13339, 13344, 13349, 13354, 13359, 13364, 13369, 13374, + 13379, 13384, 13389, 13394, 13399, 13404, 13409, 13414, + 13419, 13424, 13429, 13434, 13439, 13444, 13449, 13454, + 13459, 13464, 13469, 13474, 13479, 13484, 13489, 13494, + 13499, 13504, 13509, 13514, 13519, 13524, 13529, 13534, + 13539, 13544, 13549, 13554, 13559, 13564, 13569, 13574, + 13579, 13584, 13589, 13594, 13599, 13604, 13609, 13614, + 13619, 13624, 13629, 13635, 13641, 13647, 13652, 13657, + 13662, 13667, 13672, 13677, 13682, 13687, 13692, 13697, +}; + +static const Q_UINT16 di_FD[] = { + 13702, 13707, 13712, 13717, 13722, 13727, 13732, 13737, + 13742, 13747, 13752, 13757, 13762, 13767, 13772, 13777, + 13782, 13787, 13792, 13797, 13802, 13807, 13812, 13817, + 13822, 13827, 13832, 13837, 13842, 13847, 13852, 13857, + 13862, 13867, 13872, 13877, 13882, 13887, 13892, 13897, + 13902, 13907, 13912, 13917, 13922, 13927, 13932, 13937, + 13942, 13947, 13952, 13957, 13962, 13967, 13972, 13977, + 13982, 13987, 13992, 13997, 14002, 14007, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 14012, 14018, 14024, 14030, 14036, 14042, 14048, 14054, + 14060, 14066, 14072, 14078, 14084, 14090, 14096, 14102, + 14108, 14114, 14120, 14126, 14132, 14138, 14144, 14150, + 14156, 14162, 14168, 14174, 14180, 14186, 14192, 14198, + 14204, 14210, 14216, 14222, 14228, 14234, 14240, 14246, + 14252, 14258, 14264, 14270, 14276, 14282, 14288, 14294, + 14300, 14306, 14312, 14318, 14324, 14330, 14336, 14342, + 14348, 14354, 14360, 14366, 14372, 14378, 14384, 14390, + 0, 0, 14396, 14402, 14408, 14414, 14420, 14426, + 14432, 14438, 14444, 14450, 14456, 14462, 14468, 14474, + 14480, 14486, 14492, 14498, 14504, 14510, 14516, 14522, + 14528, 14534, 14540, 14546, 14552, 14558, 14564, 14570, + 14576, 14582, 14588, 14594, 14600, 14606, 14612, 14618, + 14624, 14630, 14636, 14642, 14648, 14654, 14660, 14666, + 14672, 14678, 14684, 14690, 14696, 14702, 14708, 14714, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 14720, 14726, 14732, 14739, 14746, 14753, 14760, 14767, + 14774, 14781, 14787, 14808, 0, 0, 0, 0, +}; + +static const Q_UINT16 di_FE[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 14819, 14823, 14827, 14831, 14835, 14839, 14843, 14847, + 14851, 14855, 14859, 14863, 14867, 14871, 14875, 14879, + 14883, 14887, 14891, 14895, 14899, 0, 0, 0, + 0, 14903, 14907, 14911, 14915, 14919, 14923, 14927, + 14931, 14935, 14939, 0, 14943, 14947, 14951, 14955, + 14959, 14963, 14967, 14971, 14975, 14979, 14983, 14987, + 14991, 14995, 14999, 15003, 15007, 15011, 15015, 0, + 15019, 15023, 15027, 15031, 0, 0, 0, 0, + 15035, 15040, 15045, 0, 15050, 0, 15055, 15060, + 15065, 15070, 15075, 15080, 15085, 15090, 15095, 15100, + 15105, 15109, 15113, 15117, 15121, 15125, 15129, 15133, + 15137, 15141, 15145, 15149, 15153, 15157, 15161, 15165, + 15169, 15173, 15177, 15181, 15185, 15189, 15193, 15197, + 15201, 15205, 15209, 15213, 15217, 15221, 15225, 15229, + 15233, 15237, 15241, 15245, 15249, 15253, 15257, 15261, + 15265, 15269, 15273, 15277, 15281, 15285, 15289, 15293, + 15297, 15301, 15305, 15309, 15313, 15317, 15321, 15325, + 15329, 15333, 15337, 15341, 15345, 15349, 15353, 15357, + 15361, 15365, 15369, 15373, 15377, 15381, 15385, 15389, + 15393, 15397, 15401, 15405, 15409, 15413, 15417, 15421, + 15425, 15429, 15433, 15437, 15441, 15445, 15449, 15453, + 15457, 15461, 15465, 15469, 15473, 15477, 15481, 15485, + 15489, 15493, 15497, 15501, 15505, 15509, 15513, 15517, + 15521, 15525, 15529, 15533, 15537, 15541, 15545, 15549, + 15553, 15557, 15561, 15565, 15569, 15573, 15578, 15583, + 15588, 15593, 15598, 15603, 15608, 0, 0, 0, +}; + +static const Q_UINT16 di_FF[] = { + 0, 15613, 15617, 15621, 15625, 15629, 15633, 15637, + 15641, 15645, 15649, 15653, 15657, 15661, 15665, 15669, + 15673, 15677, 15681, 15685, 15689, 15693, 15697, 15701, + 15705, 15709, 15713, 15717, 15721, 15725, 15729, 15733, + 15737, 15741, 15745, 15749, 15753, 15757, 15761, 15765, + 15769, 15773, 15777, 15781, 15785, 15789, 15793, 15797, + 15801, 15805, 15809, 15813, 15817, 15821, 15825, 15829, + 15833, 15837, 15841, 15845, 15849, 15853, 15857, 15861, + 15865, 15869, 15873, 15877, 15881, 15885, 15889, 15893, + 15897, 15901, 15905, 15909, 15913, 15917, 15921, 15925, + 15929, 15933, 15937, 15941, 15945, 15949, 15953, 15957, + 15961, 15965, 15969, 15973, 15977, 15981, 15985, 0, + 0, 15989, 15993, 15997, 16001, 16005, 16009, 16013, + 16017, 16021, 16025, 16029, 16033, 16037, 16041, 16045, + 16049, 16053, 16057, 16061, 16065, 16069, 16073, 16077, + 16081, 16085, 16089, 16093, 16097, 16101, 16105, 16109, + 16113, 16117, 16121, 16125, 16129, 16133, 16137, 16141, + 16145, 16149, 16153, 16157, 16161, 16165, 16169, 16173, + 16177, 16181, 16185, 16189, 16193, 16197, 16201, 16205, + 16209, 16213, 16217, 16221, 16225, 16229, 16233, 16237, + 16241, 16245, 16249, 16253, 16257, 16261, 16265, 16269, + 16273, 16277, 16281, 16285, 16289, 16293, 16297, 16301, + 16305, 16309, 16313, 16317, 16321, 16325, 16329, 16333, + 16337, 16341, 16345, 16349, 16353, 16357, 16361, 0, + 0, 0, 16365, 16369, 16373, 16377, 16381, 16385, + 0, 0, 16389, 16393, 16397, 16401, 16405, 16409, + 0, 0, 16413, 16417, 16421, 16425, 16429, 16433, + 0, 0, 16437, 16441, 16445, 0, 0, 0, + 16449, 16453, 16457, 16461, 16465, 16469, 16473, 0, + 16477, 16481, 16485, 16489, 16493, 16497, 16501, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 * const decomposition_info[256] = { + di_00, di_01, di_02, di_03, di_04, di_05, di_06, di_07, + di_07, di_09, di_0A, di_0B, di_0C, di_0D, di_0E, di_0F, + di_10, di_07, di_07, di_07, di_07, di_07, di_07, di_07, + di_07, di_07, di_07, di_07, di_07, di_07, di_1E, di_1F, + di_20, di_21, di_22, di_23, di_24, di_07, di_07, di_07, + di_07, di_07, di_07, di_07, di_07, di_07, di_2E, di_2F, + di_30, di_31, di_32, di_33, di_07, di_07, di_07, di_07, + di_07, di_07, di_07, di_07, di_07, di_07, di_07, di_07, + di_07, di_07, di_07, di_07, di_07, di_07, di_07, di_07, + di_07, di_07, di_07, di_07, di_07, di_07, di_07, di_07, + di_07, di_07, di_07, di_07, di_07, di_07, di_07, di_07, + di_07, di_07, di_07, di_07, di_07, di_07, di_07, di_07, + di_07, di_07, di_07, di_07, di_07, di_07, di_07, di_07, + di_07, di_07, di_07, di_07, di_07, di_07, di_07, di_07, + di_07, di_07, di_07, di_07, di_07, di_07, di_07, di_07, + di_07, di_07, di_07, di_07, di_07, di_07, di_07, di_07, + di_07, di_07, di_07, di_07, di_07, di_07, di_07, di_07, + di_07, di_07, di_07, di_07, di_07, di_07, di_07, di_07, + di_07, di_07, di_07, di_07, di_07, di_07, di_07, di_07, + di_07, di_07, di_07, di_07, di_07, di_07, di_07, di_07, + di_07, di_07, di_07, di_07, di_07, di_07, di_07, di_07, + di_07, di_07, di_07, di_07, di_07, di_07, di_07, di_07, + di_07, di_07, di_07, di_07, di_07, di_07, di_07, di_07, + di_07, di_07, di_07, di_07, di_07, di_07, di_07, di_07, + di_07, di_07, di_07, di_07, di_07, di_07, di_07, di_07, + di_07, di_07, di_07, di_07, di_07, di_07, di_07, di_07, + di_07, di_07, di_07, di_07, di_07, di_07, di_07, di_07, + di_07, di_07, di_07, di_07, di_07, di_07, di_07, di_07, + di_07, di_07, di_07, di_07, di_07, di_07, di_07, di_07, + di_07, di_07, di_07, di_07, di_07, di_07, di_07, di_07, + di_07, di_07, di_07, di_07, di_07, di_07, di_07, di_07, + di_07, di_F9, di_FA, di_FB, di_FC, di_FD, di_FE, di_FF, +}; +// 68080 bytes + +static const Q_UINT16 ligature_map [] = { + 0, + 12883, 12889, 12895, 12901, 12907, 12913, 15035, 15045, 15050, 15055, 15065, 15075, 15085, 15095, 0, + 5503, 0, + 5488, 0, + 5508, 0, + 67, 72, 77, 82, 87, 92, 332, 342, 352, 966, 1196, 1206, 1346, 2357, 3137, 3147, 0, + 2367, 2377, 2387, 0, + 97, 362, 372, 382, 392, 0, + 402, 2407, 2417, 2427, 2437, 2447, 0, + 102, 107, 112, 117, 412, 422, 432, 442, 452, 1216, 1226, 1356, 2477, 2487, 3257, 3267, 3277, 0, + 2507, 0, + 462, 472, 482, 492, 1076, 1146, 2517, 0, + 502, 1336, 2527, 2537, 2547, 2557, 2567, 0, + 122, 127, 132, 137, 512, 522, 532, 542, 552, 976, 1236, 1246, 2577, 3337, 3347, 0, + 567, 0, + 577, 1086, 2597, 2607, 2617, 0, + 587, 597, 607, 2627, 2647, 2657, 0, + 2667, 2677, 2687, 0, + 142, 627, 637, 647, 1156, 2697, 2707, 2717, 2727, 0, + 147, 152, 157, 162, 167, 662, 672, 682, 901, 986, 1096, 1256, 1266, 1386, 3357, 3367, 0, + 2777, 2787, 0, + 692, 702, 712, 1276, 1286, 2797, 2807, 2827, 0, + 722, 732, 742, 752, 1316, 2837, 2847, 0, + 762, 772, 1326, 2887, 2897, 2907, 2917, 0, + 172, 177, 182, 187, 782, 792, 802, 812, 822, 832, 911, 996, 1296, 1306, 2927, 2937, 2947, 3477, 3487, 0, + 2977, 2987, 0, + 842, 2997, 3007, 3017, 3027, 3037, 0, + 3047, 3057, 0, + 192, 852, 862, 1406, 3067, 3547, 3557, 3567, 3577, 0, + 867, 877, 887, 3077, 3087, 3097, 0, + 197, 202, 207, 212, 217, 222, 337, 347, 357, 971, 1201, 1211, 1351, 2362, 3142, 3152, 0, + 2372, 2382, 2392, 0, + 227, 367, 377, 387, 397, 0, + 407, 2412, 2422, 2432, 2442, 2452, 0, + 232, 237, 242, 247, 417, 427, 437, 447, 457, 1221, 1231, 1361, 2482, 2492, 3262, 3272, 3282, 0, + 2512, 0, + 467, 477, 487, 497, 1081, 1151, 2522, 0, + 507, 1341, 2532, 2542, 2552, 2562, 2572, 3107, 0, + 252, 257, 262, 267, 517, 527, 537, 547, 981, 1241, 1251, 2582, 3342, 3352, 0, + 572, 1126, 0, + 582, 1091, 2602, 2612, 2622, 0, + 592, 602, 612, 2632, 2652, 2662, 0, + 2672, 2682, 2692, 0, + 272, 632, 642, 652, 1161, 2702, 2712, 2722, 2732, 0, + 277, 282, 287, 292, 297, 667, 677, 687, 906, 991, 1101, 1261, 1271, 1391, 3362, 3372, 0, + 2782, 2792, 0, + 697, 707, 717, 1281, 1291, 2802, 2812, 2832, 0, + 727, 737, 747, 757, 1321, 2842, 2852, 0, + 767, 777, 1331, 2892, 2902, 2912, 2922, 3112, 0, + 302, 307, 312, 317, 787, 797, 807, 817, 827, 837, 916, 1001, 1301, 1311, 2932, 2942, 2952, 3482, 3492, 0, + 2982, 2992, 0, + 847, 3002, 3012, 3022, 3032, 3042, 3117, 0, + 3052, 3062, 0, + 322, 327, 857, 1411, 3072, 3122, 3552, 3562, 3572, 3582, 0, + 872, 882, 892, 3082, 3092, 3102, 0, + 1537, 4468, 4662, 0, + 3157, 3167, 3177, 3187, 0, + 1046, 0, + 1166, 0, + 1066, 1176, 0, + 2397, 0, + 3287, 3297, 3307, 3317, 0, + 2587, 0, + 3377, 3387, 3397, 3407, 0, + 1376, 2737, 2747, 0, + 1366, 0, + 1186, 0, + 1006, 1016, 1026, 1036, 0, + 3162, 3172, 3182, 3192, 0, + 1051, 0, + 1171, 0, + 1071, 1181, 0, + 2402, 0, + 3292, 3302, 3312, 3322, 0, + 2592, 0, + 3382, 3392, 3402, 3412, 0, + 1381, 2742, 2752, 0, + 1371, 0, + 1191, 0, + 1011, 1021, 1031, 1041, 0, + 3207, 3217, 3227, 3237, 0, + 3212, 3222, 3232, 3242, 0, + 2457, 2467, 0, + 2462, 2472, 0, + 2757, 2767, 0, + 2762, 2772, 0, + 2857, 0, + 2862, 0, + 2867, 0, + 2872, 0, + 2957, 0, + 2962, 0, + 2967, 0, + 2972, 0, + 3132, 0, + 3427, 3437, 3447, 3457, 3467, 0, + 3432, 3442, 3452, 3462, 3472, 0, + 3497, 3507, 3517, 3527, 3537, 0, + 3502, 3512, 3522, 3532, 3542, 0, + 1116, 0, + 1106, 0, + 1111, 0, + 1056, 0, + 1061, 0, + 2497, 0, + 2502, 0, + 1396, 0, + 1401, 0, + 1121, 0, + 1514, 0, + 1542, 3627, 3632, 4425, 4430, 4435, 4444, 0, + 1551, 3697, 3702, 4498, 0, + 1556, 3767, 3772, 4507, 4516, 0, + 1561, 1586, 3847, 3852, 4565, 4570, 4575, 0, + 1566, 3917, 3922, 4700, 0, + 4657, 0, + 1571, 1591, 3987, 4638, 4643, 4648, 0, + 1576, 4047, 4052, 4709, 4718, 0, + 4410, 0, + 4483, 0, + 1596, 3587, 3592, 4087, 4390, 4395, 4405, 4415, 0, + 1601, 3667, 3672, 4096, 0, + 1606, 3727, 3732, 4105, 4478, 4488, 0, + 1611, 1621, 3807, 3812, 4114, 4536, 4541, 4555, 0, + 1631, 3887, 3892, 4123, 0, + 4618, 4623, 0, + 1626, 1636, 3947, 3952, 4132, 4599, 4604, 4628, 0, + 1641, 4007, 4012, 4141, 4680, 4690, 0, + 1581, 4546, 4560, 0, + 1616, 4609, 4633, 0, + 4685, 0, + 1658, 1663, 0, + 1703, 0, + 1788, 1798, 0, + 1698, 0, + 1688, 1693, 1808, 0, + 1778, 1828, 0, + 1838, 0, + 1713, 1723, 1848, 1858, 0, + 1708, 0, + 1868, 0, + 1718, 1898, 1908, 1918, 0, + 1928, 0, + 1938, 0, + 1888, 0, + 1793, 1803, 0, + 1743, 0, + 1733, 1738, 1813, 0, + 1783, 1833, 0, + 1843, 0, + 1728, 1758, 1853, 1863, 0, + 1753, 0, + 1873, 0, + 1763, 1903, 1913, 1923, 0, + 1933, 0, + 1943, 0, + 1893, 0, + 1748, 0, + 1768, 0, + 1773, 0, + 1818, 0, + 1823, 0, + 1878, 0, + 1883, 0, + 11678, 11683, 11688, 0, + 11693, 11803, 0, + 11698, 0, + 11703, 0, + 11708, 0, + 11713, 11798, 0, + 11718, 0, + 11723, 0, + 11608, 11728, 0, + 11733, 0, + 11738, 11808, 0, + 11743, 0, + 11748, 0, + 11753, 0, + 11758, 0, + 11763, 0, + 11768, 11813, 0, + 11773, 0, + 11778, 0, + 11783, 0, + 11658, 11663, 11788, 0, + 11793, 0, + 11613, 0, + 15105, 0, + 15109, 15113, 0, + 15117, 15121, 0, + 15125, 15129, 0, + 15133, 15137, 0, + 12307, 12312, 12317, 12322, 12327, 12332, 12337, 12342, 12347, 12352, 12357, 12362, 12367, 12372, 12377, 12382, 12387, 12392, 12413, 12418, 12423, 12428, 12433, 12919, 12924, 12929, 12934, 12939, 12944, 13174, 13179, 13184, 13189, 13194, 13534, 13539, 15141, 15145, 15149, 15153, 0, + 14732, 14739, 1958, 1968, 14007, 14002, 1953, 15157, 15161, 0, + 14468, 14684, 12448, 12453, 12458, 12463, 12949, 12954, 12959, 12964, 12969, 12974, 13199, 13204, 13209, 13214, 13219, 13544, 13549, 12438, 12443, 15165, 15169, 15173, 15177, 0, + 15181, 15185, 0, + 14012, 14018, 14024, 14030, 14036, 14042, 14048, 14054, 14474, 14480, 14486, 14492, 14498, 14504, 13229, 13234, 13239, 13244, 13559, 13554, 12468, 12473, 12478, 12483, 12488, 12493, 12979, 12984, 12989, 12994, 12999, 13004, 13224, 15189, 15193, 15197, 15201, 0, + 12498, 12503, 12508, 12513, 13009, 13014, 13019, 13024, 13029, 13034, 13249, 13564, 13569, 15205, 15209, 15213, 15217, 0, + 14808, 14660, 14060, 14066, 14510, 14516, 14522, 12518, 12523, 13254, 13259, 13707, 13712, 13847, 13852, 15221, 15225, 15229, 15233, 0, + 14072, 14078, 14666, 13264, 13269, 13697, 13702, 13842, 13837, 12528, 12533, 15237, 15241, 15245, 15249, 0, + 12538, 12543, 12548, 13274, 13279, 13717, 13722, 13857, 13862, 15253, 15257, 15261, 15265, 0, + 15269, 15273, 0, + 12868, 15277, 15281, 0, + 14760, 12873, 15285, 15289, 0, + 15293, 15297, 0, + 14084, 14090, 14096, 14102, 14108, 14114, 14120, 14126, 14528, 14708, 13677, 13682, 13772, 13817, 13822, 13912, 13947, 13962, 13967, 13972, 12553, 12558, 12563, 12568, 13284, 13289, 13294, 13299, 13574, 13579, 15301, 15305, 15309, 15313, 0, + 14150, 14156, 14162, 14168, 14174, 14180, 14186, 14540, 13767, 13827, 13832, 13887, 13892, 13897, 13902, 13907, 13927, 13932, 13937, 13942, 13952, 13977, 13982, 13987, 13584, 13589, 13687, 13692, 13747, 13752, 13757, 13762, 15317, 15321, 15325, 15329, 0, + 14787, 14753, 14781, 14138, 14132, 14144, 14534, 14702, 14720, 12573, 12578, 13304, 13309, 13314, 13727, 13732, 13777, 13872, 13917, 13867, 15333, 15337, 15341, 15345, 0, + 14192, 14198, 14204, 14546, 13319, 13324, 13329, 13334, 13737, 13742, 13782, 13877, 13882, 13922, 12583, 12588, 12593, 12598, 15349, 15353, 15357, 15361, 0, + 14210, 14216, 14222, 14228, 13647, 13652, 13787, 13792, 13992, 13957, 12603, 12608, 13339, 15365, 15369, 15373, 15377, 0, + 12613, 13344, 13997, 15381, 15385, 15389, 15393, 0, + 14767, 14696, 14234, 14240, 14246, 14252, 14612, 12618, 12623, 13349, 13354, 13657, 13662, 13797, 13802, 15397, 15401, 15405, 15409, 0, + 14258, 14264, 14270, 13359, 13364, 13667, 13672, 13812, 13807, 12628, 12633, 15413, 15417, 15421, 15425, 0, + 13629, 13635, 13641, 15040, 15060, 15070, 15080, 15090, 15100, 0, + 14276, 14282, 14678, 12653, 12658, 12663, 13039, 13044, 13369, 13374, 13379, 13384, 12638, 12643, 12648, 15429, 15433, 15437, 15441, 0, + 14600, 14726, 14294, 14288, 14588, 12668, 12673, 12678, 12683, 13049, 13054, 13389, 13394, 15445, 15449, 15453, 15457, 0, + 14618, 14642, 14690, 12703, 12708, 12713, 12718, 12723, 13059, 13064, 13069, 13074, 13079, 13399, 13404, 13409, 13414, 13419, 13594, 13599, 12688, 12693, 12698, 15461, 15465, 15469, 15473, 0, + 14648, 14300, 14306, 14312, 14318, 14324, 14330, 14336, 14342, 14348, 14552, 14558, 14606, 14636, 12728, 12733, 12738, 12743, 12748, 12753, 13084, 13089, 13094, 13424, 13429, 13434, 13439, 13444, 13604, 15573, 15578, 15583, 15588, 15593, 15598, 15603, 15608, 15477, 15481, 15485, 15489, 0, + 14746, 14354, 14360, 14366, 14372, 14378, 14384, 14390, 14396, 14582, 14630, 14672, 12758, 12763, 12768, 12773, 12778, 12783, 13099, 13104, 13449, 13454, 13459, 13464, 15493, 15497, 15501, 15505, 0, + 14414, 14420, 14426, 14432, 14438, 14444, 14450, 14594, 14624, 14654, 14714, 13134, 13469, 13474, 13479, 13484, 13489, 13609, 13614, 12788, 12793, 12798, 12803, 12808, 12813, 13109, 13114, 13119, 13124, 13129, 15509, 15513, 15517, 15521, 0, + 14402, 14408, 12823, 12828, 12833, 13494, 13504, 13499, 12818, 15525, 15529, 15533, 15537, 0, + 14774, 1963, 15541, 15545, 0, + 12878, 13139, 12299, 12303, 15549, 15553, 0, + 14456, 14462, 14564, 14570, 14576, 12858, 12863, 13144, 13149, 13154, 13159, 13164, 13169, 13509, 13514, 13519, 13524, 13529, 13619, 13624, 1973, 12838, 12843, 12848, 12853, 15557, 15561, 15565, 15569, 0, + 11823, 11827, 0, + 12255, 0, + 11911, 11915, 11919, 11923, 0, + 11879, 11883, 11887, 11891, 0, + 11831, 11835, 11839, 11843, 0, + 11847, 11851, 11855, 11859, 0, + 11895, 11899, 11903, 11907, 0, + 11863, 11867, 11871, 11875, 0, + 11975, 11979, 11983, 11987, 0, + 11959, 11963, 11967, 11971, 0, + 11991, 11995, 11999, 12003, 0, + 12007, 12011, 12015, 12019, 0, + 12047, 12051, 0, + 12031, 12035, 0, + 12023, 12027, 0, + 12039, 12043, 0, + 12063, 12067, 0, + 12055, 12059, 0, + 11927, 11931, 11935, 11939, 0, + 11943, 11947, 11951, 11955, 0, + 12071, 12075, 12079, 12083, 0, + 12215, 12219, 12223, 12227, 0, + 12087, 12091, 12095, 12099, 0, + 12119, 12123, 12127, 12131, 0, + 12103, 12107, 12111, 12115, 0, + 12135, 12139, 0, + 12143, 12147, 12151, 12155, 0, + 12183, 12187, 12191, 12195, 0, + 12159, 12163, 0, + 2003, 12167, 12171, 12175, 12179, 0, + 12267, 12271, 0, + 12239, 12243, 0, + 12231, 12235, 0, + 12247, 12251, 0, + 12275, 12279, 0, + 12259, 12263, 0, + 12397, 12401, 12405, 12409, 0, + 12283, 12287, 12291, 12295, 0, + 2008, 12199, 12203, 0, + 12207, 12211, 0, + 1998, 0, + 2028, 0, + 2033, 0, + 2038, 0, + 2043, 0, + 2048, 0, + 2053, 0, + 2013, 0, + 2058, 0, + 2063, 0, + 2018, 0, + 2023, 0, + 2078, 0, + 2083, 0, + 2088, 0, + 2068, 2073, 0, + 2103, 0, + 2108, 0, + 2113, 0, + 2118, 0, + 2093, 0, + 2098, 0, + 2138, 0, + 2143, 0, + 2123, 2128, 2133, 0, + 2148, 0, + 2153, 2163, 0, + 2158, 0, + 2168, 0, + 2173, 0, + 2178, 2183, 2188, 0, + 2193, 0, + 2198, 2208, 0, + 2203, 0, + 2213, 2218, 2228, 0, + 2223, 0, + 2282, 0, + 2257, 0, + 2262, 0, + 2267, 0, + 2272, 0, + 2277, 0, + 2287, 2292, 2317, 0, + 2347, 0, + 2322, 0, + 2327, 0, + 2332, 0, + 2337, 0, + 2342, 0, + 2297, 0, + 2307, 0, + 2352, 0, + 2637, 0, + 2642, 0, + 2817, 0, + 2822, 0, + 2877, 0, + 2882, 0, + 3197, 3247, 0, + 3202, 3252, 0, + 3327, 0, + 3332, 0, + 3417, 0, + 3422, 0, + 3597, 3607, 3617, 4150, 0, + 3602, 3612, 3622, 4155, 0, + 4160, 0, + 4165, 0, + 4170, 0, + 4175, 0, + 4180, 0, + 4185, 0, + 3637, 3647, 3657, 4190, 0, + 3642, 3652, 3662, 4195, 0, + 4200, 0, + 4205, 0, + 4210, 0, + 4215, 0, + 4220, 0, + 4225, 0, + 3677, 3687, 0, + 3682, 3692, 0, + 3707, 3717, 0, + 3712, 3722, 0, + 3737, 3747, 3757, 4230, 0, + 3742, 3752, 3762, 4235, 0, + 4240, 0, + 4245, 0, + 4250, 0, + 4255, 0, + 4260, 0, + 4265, 0, + 3777, 3787, 3797, 4270, 0, + 3782, 3792, 3802, 4275, 0, + 4280, 0, + 4285, 0, + 4290, 0, + 4295, 0, + 4300, 0, + 4305, 0, + 3817, 3827, 3837, 0, + 3822, 3832, 3842, 0, + 3857, 3867, 3877, 0, + 3862, 3872, 3882, 0, + 3897, 3907, 0, + 3902, 3912, 0, + 3927, 3937, 0, + 3932, 3942, 0, + 3957, 3967, 3977, 0, + 3962, 3972, 3982, 0, + 3992, 3997, 4002, 0, + 4017, 4027, 4037, 4310, 0, + 4022, 4032, 4042, 4315, 0, + 4320, 0, + 4325, 0, + 4330, 0, + 4335, 0, + 4340, 0, + 4345, 0, + 4057, 4067, 4077, 4350, 0, + 4062, 4072, 4082, 4355, 0, + 4360, 0, + 4365, 0, + 4370, 0, + 4375, 0, + 4380, 0, + 4385, 0, + 4400, 0, + 4473, 0, + 4675, 0, + 4420, 0, + 4521, 4526, 4531, 0, + 4493, 0, + 4695, 0, + 4584, 4589, 4594, 0, + 5391, 0, + 5396, 0, + 5401, 0, + 5406, 0, + 5416, 0, + 5411, 0, + 5421, 0, + 5426, 0, + 5431, 0, + 5436, 0, + 5441, 0, + 5468, 0, + 5473, 0, + 5478, 0, + 5483, 0, + 5498, 0, + 5493, 0, + 5513, 0, + 5518, 0, + 5523, 0, + 5528, 0, + 5533, 0, + 5538, 0, + 5543, 0, + 5548, 0, + 5593, 0, + 5598, 0, + 5553, 0, + 5558, 0, + 5563, 0, + 5568, 0, + 5603, 0, + 5608, 0, + 5573, 0, + 5578, 0, + 5583, 0, + 5588, 0, + 5613, 0, + 5618, 0, + 5623, 0, + 5628, 0, + 7351, 0, + 7226, 0, + 7231, 0, + 7236, 0, + 7241, 0, + 7246, 0, + 7251, 0, + 7256, 0, + 7261, 0, + 7266, 0, + 7271, 0, + 7276, 0, + 7281, 0, + 7286, 0, + 7291, 0, + 7296, 0, + 7301, 7306, 0, + 7311, 7316, 0, + 7321, 7326, 0, + 7331, 7336, 0, + 7341, 7346, 0, + 7366, 0, + 7496, 0, + 7371, 0, + 7376, 0, + 7381, 0, + 7386, 0, + 7391, 0, + 7396, 0, + 7401, 0, + 7406, 0, + 7411, 0, + 7416, 0, + 7421, 0, + 7426, 0, + 7431, 0, + 7436, 0, + 7441, 0, + 7446, 7451, 0, + 7456, 7461, 0, + 7466, 7471, 0, + 7476, 7481, 0, + 7486, 7491, 0, + 7501, 0, + 7506, 0, + 7511, 0, + 7516, 0, + 7521, 0, + 11668, 11673, 0, + +}; + +static const Q_UINT16 li_00[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 16, 18, 20, 0, + 0, 22, 39, 43, 49, 56, 74, 76, + 84, 92, 108, 110, 116, 123, 127, 137, + 154, 0, 157, 166, 174, 182, 202, 205, + 212, 215, 225, 0, 0, 0, 0, 0, + 0, 232, 249, 253, 259, 266, 284, 286, + 294, 303, 318, 321, 327, 334, 338, 348, + 365, 0, 368, 377, 385, 394, 414, 417, + 425, 428, 439, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 446, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 450, 0, 455, 457, 459, 462, + 0, 0, 464, 0, 0, 0, 0, 469, + 0, 0, 0, 0, 471, 476, 480, 0, + 482, 0, 0, 0, 484, 0, 0, 0, + 0, 0, 489, 0, 494, 496, 498, 501, + 0, 0, 503, 0, 0, 0, 0, 508, + 0, 0, 0, 0, 510, 515, 519, 0, + 521, 0, 0, 0, 523, 0, 0, 0, +}; + +static const Q_UINT16 li_01[] = { + 0, 0, 528, 533, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 538, 541, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 544, 547, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 550, 552, 0, 0, 0, 0, + 554, 556, 0, 0, 0, 0, 0, 0, + 558, 560, 562, 564, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 566, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 568, 574, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 580, + 586, 0, 0, 0, 0, 0, 0, 592, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 594, 596, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 li_02[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 598, 600, + 602, 604, 0, 0, 0, 0, 606, 608, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 610, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 li_03[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 612, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 614, 0, 0, 0, 622, 0, 627, + 0, 633, 0, 0, 0, 0, 0, 641, + 0, 646, 0, 0, 0, 648, 0, 0, + 0, 655, 0, 0, 661, 0, 663, 0, + 0, 665, 0, 0, 0, 674, 0, 679, + 0, 686, 0, 0, 0, 0, 0, 695, + 0, 700, 0, 0, 0, 703, 0, 0, + 0, 712, 719, 723, 0, 0, 727, 0, + 0, 0, 729, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 li_04[] = { + 0, 0, 0, 0, 0, 0, 732, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 734, 0, 0, 737, 0, 739, 743, 746, + 748, 0, 753, 0, 0, 0, 755, 0, + 0, 0, 0, 757, 0, 0, 0, 762, + 0, 0, 0, 764, 0, 766, 0, 0, + 768, 0, 0, 771, 0, 773, 777, 780, + 782, 0, 787, 0, 0, 0, 789, 0, + 0, 0, 0, 791, 0, 0, 0, 796, + 0, 0, 0, 798, 0, 800, 0, 0, + 0, 0, 0, 0, 0, 0, 802, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 804, 806, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 808, 810, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 812, 814, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 li_05[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 816, 820, 823, 825, 827, 829, 832, 0, + 834, 836, 839, 841, 844, 0, 846, 0, + 848, 850, 0, 852, 854, 0, 857, 859, + 861, 863, 867, 0, 0, 0, 0, 0, + 0, 0, 869, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 li_06[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 871, 873, 876, 879, 882, 885, 926, + 936, 962, 965, 1003, 1021, 1041, 1057, 1071, + 1074, 1078, 1083, 1086, 1121, 1158, 1183, 1206, + 1224, 1232, 1252, 0, 0, 0, 0, 0, + 1268, 1278, 1298, 1316, 1344, 1386, 1415, 1450, + 1464, 1469, 1476, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1506, 0, 0, 0, 0, 0, 1509, + 0, 1511, 1516, 1521, 0, 0, 1526, 1531, + 1536, 0, 0, 1541, 1546, 0, 1551, 1556, + 1561, 0, 0, 0, 1564, 1567, 1570, 0, + 0, 1573, 0, 0, 0, 0, 0, 0, + 1576, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1579, 0, 1584, 0, + 0, 1589, 0, 0, 0, 1594, 0, 1599, + 0, 1604, 0, 1609, 0, 0, 0, 0, + 0, 0, 1614, 1617, 0, 0, 1622, 0, + 1627, 1630, 0, 0, 0, 1636, 1639, 1642, + 1645, 1648, 0, 1651, 1654, 0, 0, 0, + 1659, 0, 1664, 1668, 0, 1671, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 li_07[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 li_09[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1673, 1675, 1677, + 0, 0, 0, 0, 1679, 0, 0, 0, + 0, 1681, 1683, 0, 0, 0, 0, 0, + 1685, 0, 0, 1687, 0, 0, 0, 1689, + 1691, 0, 0, 1693, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1695, 1697, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1699, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1701, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 li_0A[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1704, 1706, + 0, 0, 0, 0, 1708, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1710, 0, 0, 0, 0, + 0, 0, 1712, 0, 0, 0, 0, 0, + 1714, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 li_0B[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1716, 1718, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1720, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1724, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1726, 1729, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 li_0C[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1731, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1733, + 0, 0, 0, 0, 0, 0, 1735, 0, + 0, 0, 1739, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 li_0D[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1741, 1744, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1746, 0, 0, 1750, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 li_0F[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1752, 0, 1754, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1756, 0, 0, 0, + 0, 1758, 0, 0, 0, 0, 1760, 0, + 0, 0, 0, 1762, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1764, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1768, 0, 1770, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1772, 0, 0, 0, + 0, 1774, 0, 0, 0, 0, 1776, 0, + 0, 0, 0, 1778, 0, 0, 0, 0, + 0, 0, 1780, 1782, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 li_10[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1784, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 li_1E[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1786, 1788, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1790, 1792, 0, 0, 0, 0, + 0, 0, 1794, 1796, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1798, 1801, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1804, 1806, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1808, 1810, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 li_1F[] = { + 1812, 1817, 1822, 1824, 1826, 1828, 1830, 1832, + 1834, 1839, 1844, 1846, 1848, 1850, 1852, 1854, + 1856, 1859, 0, 0, 0, 0, 0, 0, + 1862, 1865, 0, 0, 0, 0, 0, 0, + 1868, 1873, 1878, 1880, 1882, 1884, 1886, 1888, + 1890, 1895, 1900, 1902, 1904, 1906, 1908, 1910, + 1912, 1916, 0, 0, 0, 0, 0, 0, + 1920, 1924, 0, 0, 0, 0, 0, 0, + 1928, 1931, 0, 0, 0, 0, 0, 0, + 1934, 1937, 0, 0, 0, 0, 0, 0, + 1940, 1944, 0, 0, 0, 0, 0, 0, + 0, 1948, 0, 0, 0, 0, 0, 0, + 1952, 1957, 1962, 1964, 1966, 1968, 1970, 1972, + 1974, 1979, 1984, 1986, 1988, 1990, 1992, 1994, + 1996, 0, 0, 0, 1998, 0, 0, 0, + 0, 0, 0, 0, 2000, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 2002, 0, + 0, 0, 0, 0, 0, 0, 0, 2004, + 0, 0, 0, 0, 0, 0, 2008, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 2010, 0, + 0, 0, 0, 0, 0, 0, 2012, 0, +}; + +static const Q_UINT16 li_21[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 2016, 0, 2018, 0, 2020, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 2022, 0, 2024, 0, 2026, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 li_22[] = { + 0, 0, 0, 2028, 0, 0, 0, 0, + 2030, 0, 0, 2032, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 2034, 0, 2036, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 2038, 0, 0, 0, + 0, 0, 0, 2040, 0, 2042, 0, 0, + 2044, 0, 0, 0, 0, 2046, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 2048, 0, 0, 2050, 2052, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 2054, 2056, 0, 0, 2058, 2060, + 0, 0, 2062, 2064, 2066, 2068, 0, 0, + 0, 0, 2070, 2072, 0, 0, 2074, 2076, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 2078, 2080, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 2082, 0, 0, 0, 0, 0, + 2084, 2086, 0, 2088, 0, 0, 0, 0, + 0, 0, 2090, 2092, 2094, 2096, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 li_30[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 2098, 0, + 0, 0, 0, 2100, 0, 2102, 0, 2104, + 0, 2106, 0, 2108, 0, 2110, 0, 2112, + 0, 2114, 0, 2116, 0, 2118, 0, 2120, + 0, 2122, 0, 0, 2124, 0, 2126, 0, + 2128, 0, 0, 0, 0, 0, 0, 2130, + 0, 0, 2133, 0, 0, 2136, 0, 0, + 2139, 0, 0, 2142, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 2145, 0, 0, + 0, 0, 0, 0, 0, 0, 2147, 0, + 0, 0, 0, 2149, 0, 2151, 0, 2153, + 0, 2155, 0, 2157, 0, 2159, 0, 2161, + 0, 2163, 0, 2165, 0, 2167, 0, 2169, + 0, 2171, 0, 0, 2173, 0, 2175, 0, + 2177, 0, 0, 0, 0, 0, 0, 2179, + 0, 0, 2182, 0, 0, 2185, 0, 0, + 2188, 0, 0, 2191, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 2194, + 2196, 2198, 2200, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 2202, 0, 0, +}; + +static const Q_UINT16 li_FB[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 2204, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 * const ligature_info[256] = { + li_00, li_01, li_02, li_03, li_04, li_05, li_06, li_07, + li_07, li_09, li_0A, li_0B, li_0C, li_0D, li_07, li_0F, + li_10, li_07, li_07, li_07, li_07, li_07, li_07, li_07, + li_07, li_07, li_07, li_07, li_07, li_07, li_1E, li_1F, + li_07, li_21, li_22, li_07, li_07, li_07, li_07, li_07, + li_07, li_07, li_07, li_07, li_07, li_07, li_07, li_07, + li_30, li_07, li_07, li_07, li_07, li_07, li_07, li_07, + li_07, li_07, li_07, li_07, li_07, li_07, li_07, li_07, + li_07, li_07, li_07, li_07, li_07, li_07, li_07, li_07, + li_07, li_07, li_07, li_07, li_07, li_07, li_07, li_07, + li_07, li_07, li_07, li_07, li_07, li_07, li_07, li_07, + li_07, li_07, li_07, li_07, li_07, li_07, li_07, li_07, + li_07, li_07, li_07, li_07, li_07, li_07, li_07, li_07, + li_07, li_07, li_07, li_07, li_07, li_07, li_07, li_07, + li_07, li_07, li_07, li_07, li_07, li_07, li_07, li_07, + li_07, li_07, li_07, li_07, li_07, li_07, li_07, li_07, + li_07, li_07, li_07, li_07, li_07, li_07, li_07, li_07, + li_07, li_07, li_07, li_07, li_07, li_07, li_07, li_07, + li_07, li_07, li_07, li_07, li_07, li_07, li_07, li_07, + li_07, li_07, li_07, li_07, li_07, li_07, li_07, li_07, + li_07, li_07, li_07, li_07, li_07, li_07, li_07, li_07, + li_07, li_07, li_07, li_07, li_07, li_07, li_07, li_07, + li_07, li_07, li_07, li_07, li_07, li_07, li_07, li_07, + li_07, li_07, li_07, li_07, li_07, li_07, li_07, li_07, + li_07, li_07, li_07, li_07, li_07, li_07, li_07, li_07, + li_07, li_07, li_07, li_07, li_07, li_07, li_07, li_07, + li_07, li_07, li_07, li_07, li_07, li_07, li_07, li_07, + li_07, li_07, li_07, li_07, li_07, li_07, li_07, li_07, + li_07, li_07, li_07, li_07, li_07, li_07, li_07, li_07, + li_07, li_07, li_07, li_07, li_07, li_07, li_07, li_07, + li_07, li_07, li_07, li_07, li_07, li_07, li_07, li_07, + li_07, li_07, li_07, li_FB, li_07, li_07, li_07, li_07, +}; +// 16188 bytes + +static const Q_UINT8 dir_00[] = { + 18, 18, 18, 18, 18, 18, 18, 18, + 18, 8, 7, 8, 9, 7, 18, 18, + 18, 18, 18, 18, 18, 18, 18, 18, + 18, 18, 18, 18, 7, 7, 7, 8, + 9, 10, 10, 4, 4, 4, 10, 10, + 138, 138, 10, 4, 6, 4, 6, 3, + 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 6, 10, 138, 10, 138, 10, + 10, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 138, 10, 138, 10, 10, + 10, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 138, 10, 138, 10, 18, + 18, 18, 18, 18, 18, 7, 18, 18, + 18, 18, 18, 18, 18, 18, 18, 18, + 18, 18, 18, 18, 18, 18, 18, 18, + 18, 18, 18, 18, 18, 18, 18, 18, + 6, 10, 4, 4, 4, 4, 10, 10, + 10, 10, 0, 138, 10, 10, 10, 10, + 4, 4, 2, 2, 10, 0, 10, 10, + 10, 2, 0, 138, 10, 10, 10, 10, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 10, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 10, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 dir_01[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 dir_02[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 10, 10, 0, 0, 0, 0, 0, + 0, 0, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 0, 0, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 0, 0, 0, 0, 0, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 dir_03[] = { + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 17, 17, 17, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 10, 10, 0, 0, + 0, 0, 0, 0, 0, 0, 10, 0, + 0, 0, 0, 0, 10, 10, 0, 10, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 dir_04[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 17, 17, 17, 17, 0, + 17, 17, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 dir_05[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 10, 0, 0, 0, 0, 0, + 0, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 0, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 0, 17, 17, 17, 1, 17, + 1, 17, 17, 1, 17, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 dir_06[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 6, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 13, 0, 0, 0, 13, + 0, 13, 77, 77, 77, 77, 45, 77, + 45, 77, 45, 45, 45, 45, 45, 77, + 77, 77, 77, 45, 45, 45, 45, 45, + 45, 45, 45, 0, 0, 0, 0, 0, + 109, 45, 45, 45, 45, 45, 45, 45, + 77, 77, 45, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 4, 5, 5, 13, 0, 0, + 17, 13, 77, 77, 13, 77, 77, 77, + 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, + 77, 45, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 45, 77, 45, 77, + 45, 45, 77, 77, 13, 13, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 13, 13, 17, + 17, 10, 17, 17, 17, 17, 0, 0, + 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 45, 45, 45, 13, 13, 0, +}; + +static const Q_UINT8 dir_07[] = { + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 0, 18, + 77, 17, 45, 45, 45, 77, 77, 77, + 77, 77, 45, 45, 45, 45, 77, 45, + 45, 45, 45, 45, 45, 45, 45, 45, + 77, 45, 77, 45, 77, 0, 0, 0, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 dir_09[] = { + 0, 17, 17, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 17, 0, 0, 0, + 0, 17, 17, 17, 17, 17, 17, 17, + 17, 0, 0, 0, 0, 17, 0, 0, + 0, 17, 17, 17, 17, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 17, 17, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 17, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 17, 0, 0, 0, + 0, 17, 17, 17, 17, 0, 0, 0, + 0, 0, 0, 0, 0, 17, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 17, 17, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 4, 4, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 dir_0A[] = { + 0, 0, 17, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 17, 0, 0, 0, + 0, 17, 17, 0, 0, 0, 0, 17, + 17, 0, 0, 17, 17, 17, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 17, 17, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 17, 17, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 17, 0, 0, 0, + 0, 17, 17, 17, 17, 17, 0, 17, + 17, 0, 0, 0, 0, 17, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 dir_0B[] = { + 0, 17, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 17, 0, 0, 17, + 0, 17, 17, 17, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 17, 0, 0, + 0, 0, 0, 0, 0, 0, 17, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 17, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 17, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 17, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 dir_0C[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 17, 17, + 17, 0, 0, 0, 0, 0, 17, 17, + 17, 0, 17, 17, 17, 17, 0, 0, + 0, 0, 0, 0, 0, 17, 17, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 17, + 0, 0, 0, 0, 0, 0, 17, 0, + 0, 0, 0, 0, 17, 17, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 dir_0D[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 17, 17, 17, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 17, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 17, 0, 0, 0, 0, 0, + 0, 0, 17, 17, 17, 0, 17, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 dir_0E[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 17, 0, 0, 17, 17, 17, 17, + 17, 17, 17, 0, 0, 0, 0, 4, + 0, 0, 0, 0, 0, 0, 0, 17, + 17, 17, 17, 17, 17, 17, 17, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 17, 0, 0, 17, 17, 17, 17, + 17, 17, 0, 17, 17, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 17, 17, 17, 17, 17, 17, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 dir_0F[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 17, 17, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 17, 0, 17, + 0, 17, 10, 10, 10, 10, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 0, + 17, 17, 17, 17, 17, 0, 17, 17, + 0, 0, 0, 0, 0, 0, 0, 0, + 17, 17, 17, 17, 17, 17, 17, 17, + 0, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 17, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 dir_10[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 17, 17, 17, + 17, 0, 17, 0, 0, 0, 17, 17, + 0, 17, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 17, 17, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 dir_16[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 9, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 10, 10, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 dir_17[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 17, + 17, 17, 17, 17, 17, 17, 0, 0, + 0, 0, 0, 0, 0, 0, 17, 0, + 0, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 0, 0, 0, 0, + 0, 0, 0, 4, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 dir_18[] = { + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 18, 18, 18, 18, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 17, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 dir_1F[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 10, 0, 10, + 10, 10, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 10, 10, 10, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 10, 10, 10, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 10, 10, 10, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 10, 10, 0, +}; + +static const Q_UINT8 dir_20[] = { + 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 18, 18, 18, 0, 1, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 9, 7, 11, 14, 16, 12, 15, 9, + 4, 4, 4, 4, 4, 10, 10, 10, + 10, 138, 138, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 138, 138, 0, + 10, 10, 10, 10, 10, 10, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 18, 18, 18, 18, 18, 18, + 2, 0, 0, 0, 2, 2, 2, 2, + 2, 2, 4, 4, 10, 138, 138, 0, + 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 4, 4, 10, 138, 138, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 dir_21[] = { + 10, 10, 0, 10, 10, 10, 10, 0, + 10, 10, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 10, 0, 10, 10, + 10, 0, 0, 0, 0, 0, 10, 10, + 10, 10, 10, 10, 0, 10, 0, 10, + 0, 10, 0, 0, 0, 0, 4, 0, + 0, 0, 10, 0, 0, 0, 0, 0, + 0, 0, 10, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 dir_22[] = { + 10, 138, 138, 138, 138, 10, 10, 10, + 138, 138, 138, 138, 138, 138, 10, 10, + 10, 138, 4, 4, 10, 138, 138, 10, + 10, 10, 138, 138, 138, 138, 10, 138, + 138, 138, 138, 10, 138, 10, 138, 10, + 10, 10, 10, 138, 138, 138, 138, 138, + 138, 138, 138, 138, 10, 10, 10, 10, + 10, 138, 10, 138, 138, 138, 138, 138, + 138, 138, 138, 138, 138, 138, 138, 138, + 138, 138, 138, 138, 138, 10, 10, 10, + 10, 10, 138, 138, 138, 138, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 138, + 138, 10, 138, 10, 138, 138, 138, 138, + 138, 138, 138, 138, 10, 10, 138, 138, + 138, 138, 138, 138, 138, 138, 138, 138, + 138, 138, 138, 138, 138, 138, 138, 138, + 138, 138, 138, 138, 138, 138, 138, 138, + 138, 138, 138, 138, 138, 10, 10, 138, + 138, 138, 138, 10, 10, 10, 10, 10, + 138, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 138, 138, 10, 10, 138, 138, + 138, 138, 138, 138, 138, 138, 138, 138, + 138, 138, 138, 138, 138, 138, 138, 138, + 138, 10, 10, 10, 10, 10, 138, 138, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 138, 138, 138, 138, 138, 10, 10, + 138, 138, 10, 10, 10, 10, 138, 138, + 138, 138, 138, 138, 138, 138, 138, 138, + 138, 138, 138, 138, 138, 138, 138, 138, + 138, 138, 138, 138, 138, 138, 10, 10, + 138, 138, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 dir_23[] = { + 10, 10, 10, 10, 10, 10, 10, 10, + 138, 138, 138, 138, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 138, 138, 10, 10, 10, 10, 10, 10, + 10, 138, 138, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 10, 0, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 0, 10, 10, + 10, 10, 10, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 dir_24[] = { + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 2, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 dir_25[] = { + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 dir_26[] = { + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 0, 0, 0, 0, + 0, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 dir_27[] = { + 0, 10, 10, 10, 10, 0, 10, 10, + 10, 10, 0, 0, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 0, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 0, 10, 0, 10, + 10, 10, 10, 0, 0, 0, 10, 0, + 10, 10, 10, 10, 10, 10, 10, 0, + 0, 10, 10, 10, 10, 10, 10, 10, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 0, 0, 0, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 0, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 dir_28[] = { + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, +}; + +static const Q_UINT8 dir_2E[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 0, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 dir_2F[] = { + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 0, 0, 0, 0, +}; + +static const Q_UINT8 dir_30[] = { + 9, 10, 10, 10, 10, 0, 0, 0, + 138, 138, 138, 138, 138, 138, 138, 138, + 138, 138, 10, 10, 138, 138, 138, 138, + 138, 138, 138, 138, 10, 10, 10, 10, + 10, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 17, 17, 17, 17, 17, 17, + 10, 0, 0, 0, 0, 0, 10, 10, + 0, 0, 0, 0, 0, 0, 10, 10, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 17, 17, 10, 10, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 10, 0, 0, 0, 0, +}; + +static const Q_UINT8 dir_A4[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 0, 0, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 0, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 0, 10, 10, 10, 0, 10, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 dir_FB[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 17, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 4, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 0, + 1, 1, 1, 1, 1, 0, 1, 0, + 1, 1, 0, 1, 1, 0, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, +}; + +static const Q_UINT8 dir_FC[] = { + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, +}; + +static const Q_UINT8 dir_FD[] = { + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 10, 10, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 0, 0, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 0, 0, 0, 0, +}; + +static const Q_UINT8 dir_FE[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 17, 17, 17, 17, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 0, 0, 0, + 0, 10, 10, 10, 10, 10, 10, 10, + 6, 10, 6, 0, 10, 6, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 4, + 10, 10, 4, 4, 10, 10, 10, 0, + 10, 4, 4, 10, 0, 0, 0, 0, + 13, 13, 13, 0, 13, 0, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 0, 0, 18, +}; + +static const Q_UINT8 dir_FF[] = { + 0, 10, 10, 4, 4, 4, 10, 10, + 10, 10, 10, 4, 6, 4, 6, 3, + 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 6, 10, 10, 10, 10, 10, + 10, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 10, 10, 10, 10, 10, + 10, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 10, 10, 10, 10, 0, + 0, 10, 10, 10, 10, 10, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 4, 4, 10, 10, 10, 4, 4, 0, + 10, 10, 10, 10, 10, 10, 10, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 18, 18, 18, 10, 10, 0, 0, +}; + +static const Q_UINT8 * const direction_info[256] = { + dir_00, dir_01, dir_02, dir_03, dir_04, dir_05, dir_06, dir_07, + dir_01, dir_09, dir_0A, dir_0B, dir_0C, dir_0D, dir_0E, dir_0F, + dir_10, dir_01, dir_01, dir_01, dir_01, dir_01, dir_16, dir_17, + dir_18, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_1F, + dir_20, dir_21, dir_22, dir_23, dir_24, dir_25, dir_26, dir_27, + dir_28, dir_01, dir_01, dir_01, dir_01, dir_01, dir_2E, dir_2F, + dir_30, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, + dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, + dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, + dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, + dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, + dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, + dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, + dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, + dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, + dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, + dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, + dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, + dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, + dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, + dir_01, dir_01, dir_01, dir_01, dir_A4, dir_01, dir_01, dir_01, + dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, + dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, + dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, + dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, + dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, + dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, + dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, + dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, + dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, + dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, + dir_01, dir_01, dir_01, dir_FB, dir_FC, dir_FD, dir_FE, dir_FF, +}; +// 26940 bytes + +#endif + +// END OF GENERATED DATA + +// This is generated too. Script? + +#ifndef QT_NO_UNICODETABLES + +static const Q_UINT16 case_0 [] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, + 0x78, 0x79, 0x7a, 0, 0, 0, 0, 0, + 0, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, + 0x58, 0x59, 0x5a, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0x0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0x0, 0, 0, + 0, 0, 0x0, 0, 0, 0, 0, 0, + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0, + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0x0, + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, + 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0, + 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0x178, +}; + +static const Q_UINT16 case_1 [] = { + 0x101, 0x100, 0x103, 0x102, 0x105, 0x104, 0x107, 0x106, + 0x109, 0x108, 0x10b, 0x10a, 0x10d, 0x10c, 0x10f, 0x10e, + 0x111, 0x110, 0x113, 0x112, 0x115, 0x114, 0x117, 0x116, + 0x119, 0x118, 0x11b, 0x11a, 0x11d, 0x11c, 0x11f, 0x11e, + 0x121, 0x120, 0x123, 0x122, 0x125, 0x124, 0x127, 0x126, + 0x129, 0x128, 0x12b, 0x12a, 0x12d, 0x12c, 0x12f, 0x12e, + 0x69, 0x49, 0x133, 0x132, 0x135, 0x134, 0x137, 0x136, + 0x0, 0x13a, 0x139, 0x13c, 0x13b, 0x13e, 0x13d, 0x140, + 0x13f, 0x142, 0x141, 0x144, 0x143, 0x146, 0x145, 0x148, + 0x147, 0x0, 0x14b, 0x14a, 0x14d, 0x14c, 0x14f, 0x14e, + 0x151, 0x150, 0x153, 0x152, 0x155, 0x154, 0x157, 0x156, + 0x159, 0x158, 0x15b, 0x15a, 0x15d, 0x15c, 0x15f, 0x15e, + 0x161, 0x160, 0x163, 0x162, 0x165, 0x164, 0x167, 0x166, + 0x169, 0x168, 0x16b, 0x16a, 0x16d, 0x16c, 0x16f, 0x16e, + 0x171, 0x170, 0x173, 0x172, 0x175, 0x174, 0x177, 0x176, + 0xff, 0x17a, 0x179, 0x17c, 0x17b, 0x17e, 0x17d, 0x53, + 0x0, 0x253, 0x183, 0x182, 0x185, 0x184, 0x254, 0x188, + 0x187, 0x256, 0x257, 0x18c, 0x18b, 0x0, 0x1dd, 0x259, + 0x25b, 0x192, 0x191, 0x260, 0x263, 0x3d9, 0x269, 0x268, + 0x199, 0x198, 0x51, 0x0, 0x26f, 0x272, 0x0, 0x275, + 0x1a1, 0x1a0, 0x1a3, 0x1a2, 0x1a5, 0x1a4, 0x280, 0x1a8, + 0x1a7, 0x283, 0, 0x0, 0x1ad, 0x1ac, 0x288, 0x1b0, + 0x1af, 0x28a, 0x28b, 0x1b4, 0x1b3, 0x1b6, 0x1b5, 0x292, + 0x1b9, 0x1b8, 0x0, 0, 0x1bd, 0x1bc, 0, 0, + 0, 0, 0, 0, 0x1c6, 0, 0x1c4, 0x1c9, + 0, 0x1c7, 0x1cc, 0, 0x1ca, 0x1ce, 0x1cd, 0x1d0, + 0x1cf, 0x1d2, 0x1d1, 0x1d4, 0x1d3, 0x1d6, 0x1d5, 0x1d8, + 0x1d7, 0x1da, 0x1d9, 0x1dc, 0x1db, 0x18e, 0x1df, 0x1de, + 0x1e1, 0x1e0, 0x1e3, 0x1e2, 0x1e5, 0x1e4, 0x1e7, 0x1e6, + 0x1e9, 0x1e8, 0x1eb, 0x1ea, 0x1ed, 0x1ec, 0x1ef, 0x1ee, + 0x0, 0x1f3, 0, 0x1f1, 0x1f5, 0x1f4, 0, 0, + 0, 0, 0x1fb, 0x1fa, 0x1fd, 0x1fc, 0x1ff, 0x1fe, +}; + +static const Q_UINT16 case_2 [] = { + 0x201, 0x200, 0x203, 0x202, 0x205, 0x204, 0x207, 0x206, + 0x209, 0x208, 0x20b, 0x20a, 0x20d, 0x20c, 0x20f, 0x20e, + 0x211, 0x210, 0x213, 0x212, 0x215, 0x214, 0x217, 0x216, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0x0, 0x0, 0x0, 0x181, 0x186, 0x0, 0x189, 0x18a, + 0x0, 0x18f, 0x0, 0x190, 0x0, 0x0, 0x0, 0x0, + 0x193, 0x0, 0x0, 0x194, 0x0, 0x0, 0x631, 0x579, + 0x197, 0x196, 0x0, 0x0, 0x0, 0x0, 0x0, 0x19c, + 0x0, 0x0, 0x19d, 0x0, 0x0, 0x19f, 0x0, 0x0, + 0x0, 0x0, 0x7e1, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x1a6, 0x0, 0x0, 0x1a9, 0x0, 0x0, 0x0, 0x0, + 0x1ae, 0x0, 0x1b1, 0x1b2, 0x0, 0xa21, 0x971, 0x0, + 0x0, 0x0, 0x1b7, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 case_3 [] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0x3ac, 0, + 0x3ad, 0x3ae, 0x3af, 0, 0x3cc, 0, 0x3cd, 0x3ce, + 0x0, 0x3b1, 0x3b2, 0x3b3, 0x3b4, 0x3b5, 0x3b6, 0x3b7, + 0x3b8, 0x3b9, 0x3ba, 0x3bb, 0x3bc, 0x3bd, 0x3be, 0x3bf, + 0x3c0, 0x3c1, 0, 0x3c3, 0x3c4, 0x3c5, 0x3c6, 0x3c7, + 0x3c8, 0x3c9, 0x3ca, 0x3cb, 0x386, 0x388, 0x389, 0x38a, + 0x0, 0x391, 0x392, 0x393, 0x394, 0x395, 0x396, 0x397, + 0x398, 0x399, 0x39a, 0x39b, 0x39c, 0x39d, 0x39e, 0x39f, + 0x3a0, 0x3a1, 0x3a3, 0x3a3, 0x3a4, 0x3a5, 0x3a6, 0x3a7, + 0x3a8, 0x3a9, 0x3aa, 0x3ab, 0x38c, 0x38e, 0x38f, 0, + 0x392, 0x398, 0x0, 0x0, 0x0, 0x3a6, 0x3a0, 0, + 0, 0, 0x0, 0, 0x0, 0, 0x0, 0, + 0x0, 0, 0x3e3, 0x3e2, 0x3e5, 0x3e4, 0x3e7, 0x3e6, + 0x3e9, 0x3e8, 0x3eb, 0x3ea, 0x3ed, 0x3ec, 0x3ef, 0x3ee, + 0x39a, 0x3a1, 0x3a3, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 case_4 [] = { + 0, 0x451, 0x452, 0x453, 0x454, 0x455, 0x456, 0x457, + 0x458, 0x459, 0x45a, 0x45b, 0x45c, 0, 0x45e, 0x45f, + 0x430, 0x431, 0x432, 0x433, 0x434, 0x435, 0x436, 0x437, + 0x438, 0x439, 0x43a, 0x43b, 0x43c, 0x43d, 0x43e, 0x43f, + 0x440, 0x441, 0x442, 0x443, 0x444, 0x445, 0x446, 0x447, + 0x448, 0x449, 0x44a, 0x44b, 0x44c, 0x44d, 0x44e, 0x44f, + 0x410, 0x411, 0x412, 0x413, 0x414, 0x415, 0x416, 0x417, + 0x418, 0x419, 0x41a, 0x41b, 0x41c, 0x41d, 0x41e, 0x41f, + 0x420, 0x421, 0x422, 0x423, 0x424, 0x425, 0x426, 0x427, + 0x428, 0x429, 0x42a, 0x42b, 0x42c, 0x42d, 0x42e, 0x42f, + 0, 0x401, 0x402, 0x403, 0x404, 0x405, 0x406, 0x407, + 0x408, 0x409, 0x40a, 0x40b, 0x40c, 0, 0x40e, 0x40f, + 0x461, 0x460, 0x463, 0x462, 0x465, 0x464, 0x467, 0x466, + 0x469, 0x468, 0x46b, 0x46a, 0x46d, 0x46c, 0x46f, 0x46e, + 0x471, 0x470, 0x473, 0x472, 0x475, 0x474, 0x477, 0x476, + 0x479, 0x478, 0x47b, 0x47a, 0x47d, 0x47c, 0x47f, 0x47e, + 0x481, 0x480, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0x491, 0x490, 0x493, 0x492, 0x495, 0x494, 0x497, 0x496, + 0x499, 0x498, 0x49b, 0x49a, 0x49d, 0x49c, 0x49f, 0x49e, + 0x4a1, 0x4a0, 0x4a3, 0x4a2, 0x4a5, 0x4a4, 0x4a7, 0x4a6, + 0x4a9, 0x4a8, 0x4ab, 0x4aa, 0x4ad, 0x4ac, 0x4af, 0x4ae, + 0x4b1, 0x4b0, 0x4b3, 0x4b2, 0x4b5, 0x4b4, 0x4b7, 0x4b6, + 0x4b9, 0x4b8, 0x4bb, 0x4ba, 0x4bd, 0x4bc, 0x4bf, 0x4be, + 0, 0x4c2, 0x4c1, 0x4c4, 0x4c3, 0, 0, 0x4c8, + 0x4c7, 0, 0, 0x4cc, 0x4cb, 0, 0, 0, + 0x4d1, 0x4d0, 0x4d3, 0x4d2, 0x4d5, 0x4d4, 0x4d7, 0x4d6, + 0x4d9, 0x4d8, 0x4db, 0x4da, 0x4dd, 0x4dc, 0x4df, 0x4de, + 0x4e1, 0x4e0, 0x4e3, 0x4e2, 0x4e5, 0x4e4, 0x4e7, 0x4e6, + 0x4e9, 0x4e8, 0x4eb, 0x4ea, 0, 0, 0x4ef, 0x4ee, + 0x4f1, 0x4f0, 0x4f3, 0x4f2, 0x4f5, 0x4f4, 0, 0, + 0x4f9, 0x4f8, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 case_5 [] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0x561, 0x562, 0x563, 0x564, 0x565, 0x566, 0x567, + 0x568, 0x569, 0x56a, 0x56b, 0x56c, 0x56d, 0x56e, 0x56f, + 0x570, 0x571, 0x572, 0x573, 0x574, 0x575, 0x576, 0x577, + 0x578, 0x579, 0x57a, 0x57b, 0x57c, 0x57d, 0x57e, 0x57f, + 0x580, 0x581, 0x582, 0x583, 0x584, 0x585, 0x586, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0x531, 0x532, 0x533, 0x534, 0x535, 0x536, 0x537, + 0x538, 0x539, 0x53a, 0x53b, 0x53c, 0x53d, 0x53e, 0x53f, + 0x540, 0x541, 0x542, 0x543, 0x544, 0x545, 0x546, 0x547, + 0x548, 0x549, 0x54a, 0x54b, 0x54c, 0x54d, 0x54e, 0x54f, + 0x550, 0x551, 0x552, 0x553, 0x554, 0x555, 0x556, 0x0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 case_10 [] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0x10d0, 0x10d1, 0x10d2, 0x10d3, 0x10d4, 0x10d5, 0x10d6, 0x10d7, + 0x10d8, 0x10d9, 0x10da, 0x10db, 0x10dc, 0x10dd, 0x10de, 0x10df, + 0x10e0, 0x10e1, 0x10e2, 0x10e3, 0x10e4, 0x10e5, 0x10e6, 0x10e7, + 0x10e8, 0x10e9, 0x10ea, 0x10eb, 0x10ec, 0x10ed, 0x10ee, 0x10ef, + 0x10f0, 0x10f1, 0x10f2, 0x10f3, 0x10f4, 0x10f5, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 case_1e [] = { + 0x1e01, 0x1e00, 0x1e03, 0x1e02, 0x1e05, 0x1e04, 0x1e07, 0x1e06, + 0x1e09, 0x1e08, 0x1e0b, 0x1e0a, 0x1e0d, 0x1e0c, 0x1e0f, 0x1e0e, + 0x1e11, 0x1e10, 0x1e13, 0x1e12, 0x1e15, 0x1e14, 0x1e17, 0x1e16, + 0x1e19, 0x1e18, 0x1e1b, 0x1e1a, 0x1e1d, 0x1e1c, 0x1e1f, 0x1e1e, + 0x1e21, 0x1e20, 0x1e23, 0x1e22, 0x1e25, 0x1e24, 0x1e27, 0x1e26, + 0x1e29, 0x1e28, 0x1e2b, 0x1e2a, 0x1e2d, 0x1e2c, 0x1e2f, 0x1e2e, + 0x1e31, 0x1e30, 0x1e33, 0x1e32, 0x1e35, 0x1e34, 0x1e37, 0x1e36, + 0x1e39, 0x1e38, 0x1e3b, 0x1e3a, 0x1e3d, 0x1e3c, 0x1e3f, 0x1e3e, + 0x1e41, 0x1e40, 0x1e43, 0x1e42, 0x1e45, 0x1e44, 0x1e47, 0x1e46, + 0x1e49, 0x1e48, 0x1e4b, 0x1e4a, 0x1e4d, 0x1e4c, 0x1e4f, 0x1e4e, + 0x1e51, 0x1e50, 0x1e53, 0x1e52, 0x1e55, 0x1e54, 0x1e57, 0x1e56, + 0x1e59, 0x1e58, 0x1e5b, 0x1e5a, 0x1e5d, 0x1e5c, 0x1e5f, 0x1e5e, + 0x1e61, 0x1e60, 0x1e63, 0x1e62, 0x1e65, 0x1e64, 0x1e67, 0x1e66, + 0x1e69, 0x1e68, 0x1e6b, 0x1e6a, 0x1e6d, 0x1e6c, 0x1e6f, 0x1e6e, + 0x1e71, 0x1e70, 0x1e73, 0x1e72, 0x1e75, 0x1e74, 0x1e77, 0x1e76, + 0x1e79, 0x1e78, 0x1e7b, 0x1e7a, 0x1e7d, 0x1e7c, 0x1e7f, 0x1e7e, + 0x1e81, 0x1e80, 0x1e83, 0x1e82, 0x1e85, 0x1e84, 0x1e87, 0x1e86, + 0x1e89, 0x1e88, 0x1e8b, 0x1e8a, 0x1e8d, 0x1e8c, 0x1e8f, 0x1e8e, + 0x1e91, 0x1e90, 0x1e93, 0x1e92, 0x1e95, 0x1e94, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x1e60, 0, 0, 0, 0, + 0x1ea1, 0x1ea0, 0x1ea3, 0x1ea2, 0x1ea5, 0x1ea4, 0x1ea7, 0x1ea6, + 0x1ea9, 0x1ea8, 0x1eab, 0x1eaa, 0x1ead, 0x1eac, 0x1eaf, 0x1eae, + 0x1eb1, 0x1eb0, 0x1eb3, 0x1eb2, 0x1eb5, 0x1eb4, 0x1eb7, 0x1eb6, + 0x1eb9, 0x1eb8, 0x1ebb, 0x1eba, 0x1ebd, 0x1ebc, 0x1ebf, 0x1ebe, + 0x1ec1, 0x1ec0, 0x1ec3, 0x1ec2, 0x1ec5, 0x1ec4, 0x1ec7, 0x1ec6, + 0x1ec9, 0x1ec8, 0x1ecb, 0x1eca, 0x1ecd, 0x1ecc, 0x1ecf, 0x1ece, + 0x1ed1, 0x1ed0, 0x1ed3, 0x1ed2, 0x1ed5, 0x1ed4, 0x1ed7, 0x1ed6, + 0x1ed9, 0x1ed8, 0x1edb, 0x1eda, 0x1edd, 0x1edc, 0x1edf, 0x1ede, + 0x1ee1, 0x1ee0, 0x1ee3, 0x1ee2, 0x1ee5, 0x1ee4, 0x1ee7, 0x1ee6, + 0x1ee9, 0x1ee8, 0x1eeb, 0x1eea, 0x1eed, 0x1eec, 0x1eef, 0x1eee, + 0x1ef1, 0x1ef0, 0x1ef3, 0x1ef2, 0x1ef5, 0x1ef4, 0x1ef7, 0x1ef6, + 0x1ef9, 0x1ef8, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 case_1f [] = { + 0x1f08, 0x1f09, 0x1f0a, 0x1f0b, 0x1f0c, 0x1f0d, 0x1f0e, 0x1f0f, + 0x1f00, 0x1f01, 0x1f02, 0x1f03, 0x1f04, 0x1f05, 0x1f06, 0x1f07, + 0x1f18, 0x1f19, 0x1f1a, 0x1f1b, 0x1f1c, 0x1f1d, 0, 0, + 0x1f10, 0x1f11, 0x1f12, 0x1f13, 0x1f14, 0x1f15, 0, 0, + 0x1f28, 0x1f29, 0x1f2a, 0x1f2b, 0x1f2c, 0x1f2d, 0x1f2e, 0x1f2f, + 0x1f20, 0x1f21, 0x1f22, 0x1f23, 0x1f24, 0x1f25, 0x1f26, 0x1f27, + 0x1f38, 0x1f39, 0x1f3a, 0x1f3b, 0x1f3c, 0x1f3d, 0x1f3e, 0x1f3f, + 0x1f30, 0x1f31, 0x1f32, 0x1f33, 0x1f34, 0x1f35, 0x1f36, 0x1f37, + 0x1f48, 0x1f49, 0x1f4a, 0x1f4b, 0x1f4c, 0x1f4d, 0, 0, + 0x1f40, 0x1f41, 0x1f42, 0x1f43, 0x1f44, 0x1f45, 0, 0, + 0x0, 0x1f59, 0x0, 0x1f5b, 0x0, 0x1f5d, 0x0, 0x1f5f, + 0, 0x1f51, 0, 0x1f53, 0, 0x1f55, 0, 0x1f57, + 0x1f68, 0x1f69, 0x1f6a, 0x1f6b, 0x1f6c, 0x1f6d, 0x1f6e, 0x1f6f, + 0x1f60, 0x1f61, 0x1f62, 0x1f63, 0x1f64, 0x1f65, 0x1f66, 0x1f67, + 0x1fba, 0x1fbb, 0x1fc8, 0x1fc9, 0x1fca, 0x1fcb, 0x1fda, 0x1fdb, + 0x1ff8, 0x1ff9, 0x1fea, 0x1feb, 0x1ffa, 0x1ffb, 0, 0, + 0x1f88, 0x1f89, 0x1f8a, 0x1f8b, 0x1f8c, 0x1f8d, 0x1f8e, 0x1f8f, + 0x1f80, 0x1f81, 0x1f82, 0x1f83, 0x1f84, 0x1f85, 0x1f86, 0x1f87, + 0x1f98, 0x1f99, 0x1f9a, 0x1f9b, 0x1f9c, 0x1f9d, 0x1f9e, 0x1f9f, + 0x1f90, 0x1f91, 0x1f92, 0x1f93, 0x1f94, 0x1f95, 0x1f96, 0x1f97, + 0x1fa8, 0x1fa9, 0x1faa, 0x1fab, 0x1fac, 0x1fad, 0x1fae, 0x1faf, + 0x1fa0, 0x1fa1, 0x1fa2, 0x1fa3, 0x1fa4, 0x1fa5, 0x1fa6, 0x1fa7, + 0x1fb8, 0x1fb9, 0x0, 0x1fbc, 0x0, 0, 0x0, 0x0, + 0x1fb0, 0x1fb1, 0x1f70, 0x1f71, 0x1fb3, 0, 0x399, 0, + 0, 0, 0x0, 0x1fcc, 0x0, 0, 0x0, 0x0, + 0x1f72, 0x1f73, 0x1f74, 0x1f75, 0x1fc3, 0, 0, 0, + 0x1fd8, 0x1fd9, 0x0, 0x0, 0, 0, 0x0, 0x0, + 0x1fd0, 0x1fd1, 0x1f76, 0x1f77, 0, 0, 0, 0, + 0x1fe8, 0x1fe9, 0x0, 0x0, 0x0, 0x1fec, 0x0, 0x0, + 0x1fe0, 0x1fe1, 0x1f7a, 0x1f7b, 0x1fe5, 0, 0, 0, + 0, 0, 0x0, 0x1ffc, 0x0, 0, 0x0, 0x0, + 0x1f78, 0x1f79, 0x1f7c, 0x1f7d, 0x1ff3, 0, 0, 0, +}; + +static const Q_UINT16 case_20 [] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0x0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 case_21 [] = { + 0, 0, 0x0, 0, 0, 0, 0, 0x0, + 0, 0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0, 0x0, 0, 0, + 0x761, 0x0, 0x0, 0x0, 0x0, 0x0, 0, 0, + 0, 0, 0, 0, 0x0, 0, 0x0, 0, + 0x0, 0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0, 0x0, 0x0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 case_fb [] = { + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 case_ff [] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0xff41, 0xff42, 0xff43, 0xff44, 0xff45, 0xff46, 0xff47, + 0xff48, 0xff49, 0xff4a, 0xff4b, 0xff4c, 0xff4d, 0xff4e, 0xff4f, + 0xff50, 0xff51, 0xff52, 0xff53, 0xff54, 0xff55, 0xff56, 0xff57, + 0xff58, 0xff59, 0xff5a, 0, 0, 0, 0, 0, + 0, 0xff21, 0xff22, 0xff23, 0xff24, 0xff25, 0xff26, 0xff27, + 0xff28, 0xff29, 0xff2a, 0xff2b, 0xff2c, 0xff2d, 0xff2e, 0xff2f, + 0xff30, 0xff31, 0xff32, 0xff33, 0xff34, 0xff35, 0xff36, 0xff37, + 0xff38, 0xff39, 0xff3a, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 * const case_info[256] = { + + case_0, case_1, case_2, case_3, case_4, case_5, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + case_10, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, case_1e, case_1f, + case_20, case_21, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, case_fb, 0, 0, 0, case_ff, +}; + +static const Q_INT8 num_0 [] = { + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 2, 3, -1, -1, -1, -1, + -1, 1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, +}; + +static const Q_INT8 num_6 [] = { + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, -1, -1, -1, -1, -1, -1, +}; + +static const Q_INT8 num_9 [] = { + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 0, 1, + 2, 3, 4, 5, 6, 7, 8, 9, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 0, 1, + 2, 3, 4, 5, 6, 7, 8, 9, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, +}; + +static const Q_INT8 num_b [] = { + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 0, 1, + 2, 3, 4, 5, 6, 7, 8, 9, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 1, + 2, 3, 4, 5, 6, 7, 8, 9, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, +}; + +static const Q_INT8 num_d [] = { + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 0, 1, + 2, 3, 4, 5, 6, 7, 8, 9, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, +}; + +static const Q_INT8 num_e [] = { + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, +}; + +static const Q_INT8 num_f [] = { + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, +}; + +static const Q_INT8 num_20 [] = { + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + 0, -1, -1, -1, 4, 5, 6, 7, + 8, 9, -1, -1, -1, -1, -1, -1, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, +}; + +static const Q_INT8 num_ff [] = { + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, +}; + +static const Q_INT8 * const decimal_info[256] = { + num_0, 0, 0, 0, 0, 0, num_6, 0, + 0, num_9, num_9, num_b, num_9, num_d, num_e, num_f, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + num_20, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, num_ff, +}; + +static const Q_UINT16 symmetricPairs[] = { + 0x0028, 0x0029, 0x0029, 0x0028, 0x003C, 0x003E, 0x003E, 0x003C, + 0x005B, 0x005D, 0x005D, 0x005B, 0x007B, 0x007D, 0x007D, 0x007B, + 0x2045, 0x2046, 0x2046, 0x2045, 0x207D, 0x207E, 0x207E, 0x207D, + 0x208D, 0x208E, 0x208E, 0x208D, 0x3008, 0x3009, 0x3009, 0x3008, + 0x300A, 0x300B, 0x300B, 0x300A, 0x300C, 0x300D, 0x300D, 0x300C, + 0x300E, 0x300F, 0x300F, 0x300E, 0x3010, 0x3011, 0x3011, 0x3010, + 0x3014, 0x3015, 0x3015, 0x3014, 0x3016, 0x3017, 0x3017, 0x3016, + 0x3018, 0x3019, 0x3019, 0x3018, 0x301A, 0x301B, 0x301B, 0x301A, + 0xFD3E, 0xFD3F, 0xFD3F, 0xFD3E, 0xFE59, 0xFE5A, 0xFE5A, 0xFE59, + 0xFE5B, 0xFE5C, 0xFE5C, 0xFE5B, 0xFE5D, 0xFE5E, 0xFE5E, 0xFE5D, + 0xFF08, 0xFF09, 0xFF09, 0xFF08, 0xFF3B, 0xFF3D, 0xFF3D, 0xFF3B, + 0xFF5B, 0xFF5D, 0xFF5D, 0xFF5B, 0xFF62, 0xFF63, 0xFF63, 0xFF62, +}; + +static int symmetricPairsSize = + sizeof(symmetricPairs)/sizeof(symmetricPairs[0]); + +/* + * ---------------------------------------------------------------------- + * End of unicode tables + * ---------------------------------------------------------------------- + */ + +#endif + + +static int ucstrcmp( const QString &as, const QString &bs ) +{ + const QChar *a = as.unicode(); + const QChar *b = bs.unicode(); + if ( a == b ) + return 0; + if ( a == 0 ) + return 1; + if ( b == 0 ) + return -1; + int l=QMIN(as.length(),bs.length()); + while ( l-- && *a == *b ) + a++,b++; + if ( l==-1 ) + return ( as.length()-bs.length() ); + return a->unicode() - b->unicode(); +} + +static int ucstrncmp( const QChar *a, const QChar *b, int l ) +{ + while ( l-- && *a == *b ) + a++,b++; + if ( l==-1 ) + return 0; + return a->unicode() - b->unicode(); +} + +static int ucstrnicmp( const QChar *a, const QChar *b, int l ) +{ + while ( l-- && a->lower() == b->lower() ) + a++,b++; + if ( l==-1 ) + return 0; + QChar al = a->lower(); + QChar bl = b->lower(); + return al.unicode() - bl.unicode(); +} + +// NOT REVISED +/*! \class QCharRef qstring.h + \brief The QCharRef class is a helper class for QString. + + It provides the ability to work on characters in a QString in a natural + fashion. + + When you get an object of type QCharRef, you can assign to it, which + will operate on the string from which you got it. That is its whole + purpose in life. It becomes invalid once further modifications are + made to the string: If you want to keep it, copy it into a QChar. + + Most of the QChar member functions also exist in QCharRef. However, + they are not explicitly documented here. + + \sa QString::operator[]() QString::at() QChar +*/ + +/*! \class QChar qstring.h + +\brief The QChar class provides a light-weight Unicode character. + +Unicode characters are (so far) 16-bit entities without any markup or +structure. This class represents such an entity. It is rather +light-weight, so it can be used everywhere. Most compilers treat it +approximately like "short int". (In a few years, it may be necessary +to make QChar 32-bit, once more than 65536 Unicode code points have +been defined and come into use.) + +QChar provides a full complement of testing/classification functions, +conversion to and from other formats, from composed to decomposed +unicode, and will try to compare and case-convert if you ask it to. + +The classification functions include functions like those in ctype.h, +but operating on the full range of unicode characters. They all +return TRUE if the character is a certain type of character, and FALSE +otherwise. + +These functions are: isNull() (returns TRUE if the character is +U+0000), isPrint() (TRUE if the character is any sort of printable +character, including whitespace), isPunct() (any sort of punctation), +isMark() (Unicode Marks), isLetter (letters), isNumber() (any sort of +numeric characters), isLetterOrNumber(), and isDigit() (decimal digits). +All of these are wrappers around category(), which returns the +unicode-defined category of each character. + +QChar further provides direction(), which indicates the "natural" +writing direction of this character, joining(), which indicates how +this character joins with its neighbors (needed mostly for Arabic) +and finally mirrored(), which indicates whether this character needs +to be mirrored when it is printed in its unnatural writing +direction. + +Composed Unicode characters (like å) can be converted to +decomposed Unicode ("a" followed by "ring above") using +decomposition(). + +In Unicode, comparison is not necessarily possible, and case +conversion is at best very hard. Unicode, covering the "entire" +globe, also includes a globe-sized collection of case and sorting +problems. Qt tries, but not very hard: operator== and friends will do +comparison based purely on the numeric Unicode value (code point) of +the characters, and upper() and lower() will do case changes when the +character has a well-defined upper/lower-case equivalent. There is no +provision for locale-dependent case folding rules or comparison: These +functions are meant to be fast, so they can be used unambiguously in +data structures. + +The conversion functions include unicode() (to a scalar), latin1() (to +scalar, but converts all non-Latin1 characters to 0), row() (gives the +Unicode row), cell() (gives the unicode cell), digitValue() (gives the +integer value of any of the numerous digit characters), and a host of +constructors. + +\sa QString QCharRef \link unicode.html About Unicode \endlink +*/ + +/*! \enum QChar::Category + +This enum maps the Unicode character categories. The currently known +categories are: <ul> + +<li> \c NoCategory - used when Qt is dazed and confused and cannot +make sense of anything. + +<li> \c Mark_NonSpacing - (Mn) - + +<li> \c Mark_SpacingCombining - (Mc) - + +<li> \c Mark_Enclosing - (Me) - + +<li> \c Number_DecimalDigit - (Nd) - + +<li> \c Number_Letter - (Nl) - + +<li> \c Number_Other - (No) - + +<li> \c Separator_Space - (Zs) - + +<li> \c Separator_Line - (Zl) - + +<li> \c Separator_Paragraph - (Zp) - + +<li> \c Other_Control - (Cc) - + +<li> \c Other_Format - (Cf) - + +<li> \c Other_Surrogate - (Cs) - + +<li> \c Other_PrivateUse - (Co) - + +<li> \c Other_NotAssigned - (Cn) - + +<li> \c Letter_Uppercase - (Lu) - + +<li> \c Letter_Lowercase - (Ll) - + +<li> \c Letter_Titlecase - (Lt) - + +<li> \c Letter_Modifier - (Lm) - + +<li> \c Letter_Other - (Lo) - + +<li> \c Punctuation_Connector - (Pc) - + +<li> \c Punctuation_Dask - (Pd) - + +<li> \c Punctuation_Open - (Ps) - + +<li> \c Punctuation_Close - (Pe) - + +<li> \c Punctuation_InitialQuote - (Pi) - + +<li> \c Punctuation_FinalQuote - (Pf) - + +<li> \c Punctuation_Other - (Po) - + +<li> \c Symbol_Math - (Sm) - + +<li> \c Symbol_Currency - (Sc) - + +<li> \c Symbol_Modifier - (Sk) - + +<li> \c Symbol_Other - (So) - + +</ul> +*/ + +/*! \enum QChar::Direction + + This enum type defines the Unicode direction attributes. + See <a href="http://www.unicode.org">the Unicode Standard</a> + for a description of the values. + + In order to conform to C/C++ naming conventions "Dir" is + prepended to the codes used in The Unicode Standard. +*/ + +/*! \enum QChar::Decomposition + + This enum type defines the Unicode decomposition attributes. + See <a href="http://www.unicode.org">the Unicode Standard</a> + for a description of the values. +*/ + +/*! \enum QChar::Joining + + This enum type defines the Unicode decomposition attributes. + See <a href="http://www.unicode.org">the Unicode Standard</a> + for a description of the values. +*/ + + + +/*! \fn QChar::QChar() + +Constructs a null QChar (one that isNull()). +*/ + + +/*! \fn QChar::QChar( char c ) + +Constructs a QChar corresponding to ASCII/Latin1 character \a c. +*/ + + +/*! \fn QChar::QChar( uchar c ) + +Constructs a QChar corresponding to ASCII/Latin1 character \a c. +*/ + + +/*! \fn QChar::QChar( uchar c, uchar r ) + +Constructs a QChar for Unicode cell \a c in row \a r. +*/ + + +/*! \fn QChar::QChar( const QChar& c ) + +Constructs a copy of \a c. This is a deep copy, if such a +light-weight object can be said to have deep copies. +*/ + + +/*! \fn QChar::QChar( ushort rc ) + +Constructs a QChar for the character with Unicode code point \a rc. +*/ + + +/*! \fn QChar::QChar( short rc ) + +Constructs a QChar for the character with Unicode code point \a rc. +*/ + + +/*! \fn QChar::QChar( uint rc ) + +Constructs a QChar for the character with Unicode code point \a rc. +*/ + + +/*! \fn QChar::QChar( int rc ) + +Constructs a QChar for the character with Unicode code point \a rc. +*/ + + +/*! \fn bool QChar::networkOrdered () + + Returns TRUE if this character is in network byte order (MSB first), + and FALSE if it is not. This is a platform-dependent property, so + we strongly advise against using this function in portable code. +*/ + + +/*! + \fn bool QChar::isNull() const + Returns TRUE if the characters is the unicode character 0x0000, + ie. ASCII NUL. +*/ + +/*! + \fn uchar QChar::cell () const + Returns the cell (least significant byte) of the Unicode character. +*/ +/*! + \fn uchar QChar::row () const + Returns the row (most significant byte) of the Unicode character. +*/ +/*! + \fn uchar& QChar::cell () + Returns a reference to the cell (least significant byte) of the Unicode character. +*/ +/*! + \fn uchar& QChar::row () + Returns a reference to the row (most significant byte) of the Unicode character. +*/ + +/*! + Returns whether the character is a printable character. This is + any character not of category Cc or Cn. Note that this gives no indication + of whether the character is available in some font. +*/ +bool QChar::isPrint() const +{ + Category c = category(); + return !(c == Other_Control || c == Other_NotAssigned); +} + +/*! + Returns whether the character is a separator + character (Separator_* categories). +*/ +bool QChar::isSpace() const +{ + if( !row() ) + if( cell() >= 9 && cell() <=13 ) return TRUE; + Category c = category(); + return c >= Separator_Space && c <= Separator_Paragraph; +} + +/*! + Returns whether the character is a mark (Mark_* categories). +*/ +bool QChar::isMark() const +{ + Category c = category(); + return c >= Mark_NonSpacing && c <= Mark_Enclosing; +} + +/*! + Returns whether the character is punctuation (Punctuation_* categories). +*/ +bool QChar::isPunct() const +{ + Category c = category(); + return (c >= Punctuation_Connector && c <= Punctuation_Other); +} + +/*! + Returns whether the character is a letter (Letter_* categories). +*/ +bool QChar::isLetter() const +{ + Category c = category(); + return (c >= Letter_Uppercase && c <= Letter_Other); +} + +/*! + Returns whether the character is a number (of any sort - Number_* categories). + + \sa isDigit() +*/ +bool QChar::isNumber() const +{ + Category c = category(); + return c >= Number_DecimalDigit && c <= Number_Other; +} + +/*! + Returns whether the character is a letter or number (Letter_* or Number_* categories). +*/ +bool QChar::isLetterOrNumber() const +{ + Category c = category(); + return (c >= Letter_Uppercase && c <= Letter_Other) + || (c >= Number_DecimalDigit && c <= Number_Other); +} + + +/*! + Returns whether the character is a decimal digit (Number_DecimalDigit). + */ +bool QChar::isDigit() const +{ + return (category() == Number_DecimalDigit); +} + +/*! + Returns the numeric value of the digit, or -1 if the character is not + a digit. +*/ +int QChar::digitValue() const +{ +#ifndef QT_NO_UNICODETABLES + const Q_INT8 *dec_row = decimal_info[row()]; + if( !dec_row ) + return -1; + return decimal_info[row()][cell()]; +#else + // ##### just latin1 + if ( rw != 0 || cl < '0' || cl > '9' ) + return -1; + else + return cl - '0'; +#endif +} + +/*! + Returns the character category. + + \sa Category +*/ +QChar::Category QChar::category() const +{ +#ifndef QT_NO_UNICODETABLES + return (Category)(unicode_info[row()][cell()]); +#else +// ### just ASCII + if ( rw == 0 ) { + return (Category)(ui_00[cell()]); + } + return Letter_Uppercase; //####### +#endif +} + +/*! + Returns the characters directionality. + + \sa Direction +*/ +QChar::Direction QChar::direction() const +{ +#ifndef QT_NO_UNICODETABLES + const Q_UINT8 *rowp = direction_info[row()]; + if(!rowp) return QChar::DirL; + return (Direction) ( *(rowp+cell()) &0x1f ); +#else + return DirL; +#endif +} + +/*! + This function is not supported (it may change to use Unicode + character classes). + + Returns information about the joining properties of the + character (needed for arabic). +*/ +QChar::Joining QChar::joining() const +{ +#ifndef QT_NO_UNICODETABLES + const Q_UINT8 *rowp = direction_info[row()]; + if ( !rowp ) + return QChar::OtherJoining; + return (Joining) ((*(rowp+cell()) >> 5) &0x3); +#else + return OtherJoining; +#endif +} + + +/*! + Returns whether the character is a mirrored character (one that + should be reversed if the text direction is reversed). +*/ +bool QChar::mirrored() const +{ +#ifndef QT_NO_UNICODETABLES + const Q_UINT8 *rowp = direction_info[row()]; + if ( !rowp ) + return FALSE; + return *(rowp+cell())>128; +#else + return FALSE; +#endif +} + +/*! + Returns the mirrored char if this character is a mirrored char, the char + itself otherwise +*/ +QChar QChar::mirroredChar() const +{ +#ifndef QT_NO_UNICODETABLES + if(!mirrored()) return *this; + + int i; + int c = unicode(); + for (i = 0; i < symmetricPairsSize; i += 2) { + if (symmetricPairs[i] == c) + return symmetricPairs[i+1]; + } + return 0; +#else + return *this; +#endif +} + +/*! + Decomposes a character into its parts. Returns QString::null if + no decomposition exists. +*/ +QString QChar::decomposition() const +{ +#ifndef QT_NO_UNICODETABLES + const Q_UINT16 *r = decomposition_info[row()]; + if(!r) return QString::null; + + Q_UINT16 pos = r[cell()]; + if(!pos) return QString::null; + pos+=2; + + QString s; + Q_UINT16 c; + while((c = decomposition_map[pos++]) != 0) s += QChar(c); + + return s; +#else + return null; +#endif +} + +/*! + Returns the tag defining the composition of the character. + Returns QChar::Single if no decomposition exists. +*/ +QChar::Decomposition QChar::decompositionTag() const +{ +#ifndef QT_NO_UNICODETABLES + const Q_UINT16 *r = decomposition_info[row()]; + if(!r) return QChar::Single; + + Q_UINT16 pos = r[cell()]; + if(!pos) return QChar::Single; + + return (QChar::Decomposition) decomposition_map[pos]; +#else + return Single; // ########### FIX eg. just latin1 +#endif +} + +/*! + Returns the lowercase equivalent if the character is uppercase, + or the character itself otherwise. +*/ +QChar QChar::lower() const +{ +#ifndef QT_NO_UNICODETABLES + if(category() != Letter_Uppercase) return *this; + Q_UINT16 lower = *(case_info[row()]+cell()); + if(lower == 0) return *this; + return lower; +#else + if (row()) + return *this; + else + return QChar(tolower(latin1())); +#endif +} + +/*! + Returns the uppercase equivalent if the character is lowercase, + or the character itself otherwise. +*/ +QChar QChar::upper() const +{ +#ifndef QT_NO_UNICODETABLES + if(category() != Letter_Lowercase) return *this; + Q_UINT16 upper = *(case_info[row()]+cell()); + if(upper == 0) return *this; + return upper; +#else + if (row()) + return *this; + else + return QChar(toupper(latin1())); +#endif +} + +/*! + \fn QChar::operator char() const + + Returns the Latin1 character equivalent to the QChar, + or 0. This is mainly useful for non-internationalized software. + + \sa unicode() +*/ + +/*! + \fn ushort QChar::unicode() const + + Returns the numeric Unicode value equal to the QChar. Normally, you + should use QChar objects as they are equivalent, but for some low-level + tasks (eg. indexing into an array of Unicode information), this function + is useful. +*/ + +/***************************************************************************** + Documentation of QChar related functions + *****************************************************************************/ + +/*! + \fn int operator==( QChar c1, QChar c2 ) + \relates QChar + + Returns TRUE if \a c1 and \a c2 are the same Unicode character. +*/ + +/*! + \fn int operator==( char ch, QChar c ) + \relates QChar + + Returns TRUE if \a c is the ASCII/Latin1 character \a ch. +*/ + +/*! + \fn int operator==( QChar c, char ch ) + \relates QChar + + Returns TRUE if \a c is the ASCII/Latin1 character \a ch. +*/ + +/*! + \fn int operator!=( QChar c1, QChar c2 ) + \relates QChar + + Returns TRUE if \a c1 and \a c2 are not the same Unicode character. +*/ + +/*! + \fn int operator!=( char ch, QChar c ) + \relates QChar + + Returns TRUE if \a c is not the ASCII/Latin1 character \a ch. +*/ + +/*! + \fn int operator!=( QChar c, char ch ) + \relates QChar + + Returns TRUE if \a c is not the ASCII/Latin1 character \a ch. +*/ + +/*! + \fn int operator<=( QChar c1, QChar c2 ) + \relates QChar + + Returns TRUE if the numeric Unicode value of \a c1 is less than that + of \a c2, or they are the same Unicode character. +*/ + +/*! + \fn int operator<=( QChar c, char ch ) + \relates QChar + + Returns TRUE if the numeric Unicode value of \a c is less than or + equal to that of the ASCII/Latin1 character \a ch. +*/ + +/*! + \fn int operator<=( char ch, QChar c ) + \relates QChar + + Returns TRUE if the numeric Unicode value of the ASCII/Latin1 + character \a ch is less than or equal to that of \a c. +*/ + +/*! + \fn int operator>=( QChar c1, QChar c2 ) + \relates QChar + + Returns TRUE if the numeric Unicode value of \a c1 is greater than that + of \a c2, or they are the same Unicode character. +*/ + +/*! + \fn int operator>=( QChar c, char ch ) + \relates QChar + + Returns TRUE if the numeric Unicode value of \a c is greater than or + equal to that of the ASCII/Latin1 character \a ch. +*/ + +/*! + \fn int operator>=( char ch, QChar c ) + \relates QChar + + Returns TRUE if the numeric Unicode value of the ASCII/Latin1 + character \a ch is greater than or equal to that of \a c. +*/ + +/*! + \fn int operator<( QChar c1, QChar c2 ) + \relates QChar + + Returns TRUE if the numeric Unicode value of \a c1 is less than that + of \a c2. +*/ + +/*! + \fn int operator<( QChar c, char ch ) + \relates QChar + + Returns TRUE if the numeric Unicode value of \a c is less than that + of the ASCII/Latin1 character \a ch. +*/ + +/*! + \fn int operator<( char ch, QChar c ) + \relates QChar + + Returns TRUE if the numeric Unicode value of the ASCII/Latin1 + character \a ch is less than that of \a c. +*/ + +/*! + \fn int operator>( QChar c1, QChar c2 ) + \relates QChar + + Returns TRUE if the numeric Unicode value of \a c1 is greater than + that of \a c2. +*/ + +/*! + \fn int operator>( QChar c, char ch ) + \relates QChar + + Returns TRUE if the numeric Unicode value of \a c is greater than + that of the ASCII/Latin1 character \a ch. +*/ + +/*! + \fn int operator>( char ch, QChar c ) + \relates QChar + + Returns TRUE if the numeric Unicode value of the ASCII/Latin1 + character \a ch is greater than that of \a c. +*/ + +#ifndef QT_NO_UNICODETABLES + +// small class used internally in QString::Compose() +class QLigature +{ +public: + QLigature( QChar c ); + + Q_UINT16 first() { cur = ligatures; return cur ? *cur : 0; } + Q_UINT16 next() { return cur && *cur ? *(cur++) : 0; } + Q_UINT16 current() { return cur ? *cur : 0; } + + int match(QString & str, unsigned int index); + QChar head(); + QChar::Decomposition tag(); + +private: + Q_UINT16 *ligatures; + Q_UINT16 *cur; +}; + +QLigature::QLigature( QChar c ) +{ + const Q_UINT16 *r = ligature_info[c.row()]; + if( !r ) + ligatures = 0; + else + { + const Q_UINT16 pos = r[c.cell()]; + ligatures = (Q_UINT16 *)&(ligature_map[pos]); + } + cur = ligatures; +} + +QChar QLigature::head() +{ + if(current()) + return QChar(decomposition_map[current()+1]); + + return QChar::null; +} + +QChar::Decomposition QLigature::tag() +{ + if(current()) + return (QChar::Decomposition) decomposition_map[current()]; + + return QChar::Canonical; +} + +int QLigature::match(QString & str, unsigned int index) +{ + unsigned int i=index; + + if(!current()) return 0; + + Q_UINT16 lig = current() + 2; + Q_UINT16 ch; + + while ((i < str.length()) && (ch = decomposition_map[lig])) { + if (str[(int)i] != QChar(ch)) + return 0; + i++; lig++; + } + + if (!decomposition_map[lig]) + { + return i-index; + } + return 0; +} + +#endif + +// this function is just used in QString::compose() +static inline bool format(QChar::Decomposition tag, QString & str, + int index, int len) +{ + unsigned int l = index + len; + unsigned int r = index; + + bool left = FALSE, right = FALSE; + + left = ((l < str.length()) && + ((str[(int)l].joining() == QChar::Dual) || + (str[(int)l].joining() == QChar::Right))); + if (r > 0) { + r--; + //printf("joining(right) = %d\n", str[(int)r].joining()); + right = (str[(int)r].joining() == QChar::Dual); + } + + + switch (tag) { + case QChar::Medial: + return (left & right); + case QChar::Initial: + return (left && !right); + case QChar::Final: + return (right);// && !left); + case QChar::Isolated: + default: + return (!right && !left); + } +} // format() + +/* + QString::compose() and visual() were developed by Gordon Tisher + <tisher@uniserve.ca>, with input from Lars Knoll <knoll@mpi-hd.mpg.de>, + who developed the unicode data tables. +*/ +/*! + Note that this function is not supported in Qt 2.0, and is merely + for experimental and illustrative purposes. It is mainly of interest + to those experimenting with Arabic and other composition-rich texts. + + Applies possible ligatures to a QString, useful when composition-rich + text requires rendering with glyph-poor fonts, but also + makes compositions such as QChar(0x0041) ('A') and QChar(0x0308) + (Unicode accent diaresis) giving QChar(0x00c4) (German A Umlaut). +*/ +void QString::compose() +{ +#ifndef QT_NO_UNICODETABLES + unsigned int index=0, len; + unsigned int cindex = 0; + + QChar code, head; + + QArray<QChar> dia; + + QString composed = *this; + + while (index < length()) { + code = at(index); + //printf("\n\nligature for 0x%x:\n", code.unicode()); + QLigature ligature(code); + ligature.first(); + while(ligature.current()) { + if ((len = ligature.match(*this, index)) != 0) { + head = ligature.head(); + unsigned short code = head.unicode(); + // we exclude Arabic presentation forms A and a few + // other ligatures, which are undefined in most fonts + if(!(code > 0xfb50 && code < 0xfe80) && + !(code > 0xfb00 && code < 0xfb2a)) { + // joining info is only needed for arabic + if (format(ligature.tag(), *this, index, len)) { + //printf("using ligature 0x%x, len=%d\n",code,len); + // replace letter + composed.replace(cindex, len, QChar(head)); + index += len-1; + // we continue searching in case we have a final + // form because medial ones are preferred. + if ( len != 1 || ligature.tag() !=QChar::Final ) + break; + } + } + } + ligature.next(); + } + cindex++; + index++; + } + *this = composed; +#endif +} + +static QChar LRM ((ushort)0x200e); +static QChar RLM ((ushort)0x200f); +static QChar LRE ((ushort)0x202a); +static QChar RLE ((ushort)0x202b); +static QChar RLO ((ushort)0x202e); +static QChar LRO ((ushort)0x202d); +static QChar PDF ((ushort)0x202c); + +#if 0 +static inline bool is_arabic(unsigned short x) { + return (((x >= 0x0600) && (x <= 0x07bf)) || + ((x >= 0xfb50) && (x <= 0xfdff)) || + ((x >= 0xfe70) && (x <= 0xfeff))); +} +#endif + +static inline bool is_neutral(unsigned short dir) { + return ((dir == QChar::DirB) || + (dir == QChar::DirS) || + (dir == QChar::DirWS) || + (dir == QChar::DirON) || + (dir == QChar::DirNSM)); +} + +/*! + This function returns the basic directionality of the string (QChar::DirR for + right to left and QChar::DirL for left to right). Useful to find the right + alignment. + */ +QChar::Direction QString::basicDirection() +{ +#ifndef QT_NO_UNICODETABLES + // find base direction + unsigned int pos = 0; + while ((pos < length()) && + (at(pos) != RLE) && + (at(pos) != LRE) && + (at(pos) != RLO) && + (at(pos) != LRO) && + (at(pos).direction() > 1) && + (at(pos).direction() != QChar::DirAL)) // not R and not L + pos++; + + if ((at(pos).direction() == QChar::DirR) || + (at(pos).direction() == QChar::DirAL) || + (at(pos) == RLE) || + (at(pos) == RLO)) + return QChar::DirR; +#endif + + return QChar::DirL; +} + +#ifndef QT_NO_UNICODETABLES +// reverses part of the QChar array to get visual ordering +// called from QString::visual() +// +static unsigned int reverse( QString &chars, unsigned char *level, + unsigned int a, unsigned int b) +{ + unsigned int c = a; + unsigned char lev = level[c]; + + while ((c < b) && (level[c] >= lev)) { + if (level[c] > lev) + c = reverse(chars, level, c, b); + c++; + } + + if (lev > 0) { + QChar temp; + unsigned int d = a, e = c-1; + while (d < e) { + temp = chars[(int)d]; + chars[(int)d] = chars[(int)e]; + chars[(int)e] = temp; + + d++; e--; + } + } + + return c; +} + +// small class used for the ordering algorithm in QString::visual() +class QBidiState { +public: + unsigned char level; + signed char override; + + QBidiState(unsigned char l, signed char o) : level(l), override(o) {}; +}; + +// matrix for resolving neutral types + +#define NEG1 (QChar::Direction)(-1) + +static QChar::Direction resolv[5][5] = +{ + { NEG1, QChar::DirR, QChar::DirL, QChar::DirEN, QChar::DirAN }, + { QChar::DirR, QChar::DirR, NEG1, QChar::DirR, QChar::DirR }, + { QChar::DirL, NEG1, QChar::DirL, QChar::DirL, NEG1 }, + { QChar::DirEN, QChar::DirR, QChar::DirL, QChar::DirEN, QChar::DirR }, + { QChar::DirAN, QChar::DirR, NEG1, NEG1, QChar::DirAN } +}; + +#endif + +/*! + This function returns the QString ordered visually. Useful for + painting the string or when transforming to a visually ordered + encoding. +*/ +QString QString::visual(int index, int len) +{ +#ifndef QT_NO_UNICODETABLES + // #### This needs much more optimizing - it is called for + // #### every text operation. + + unsigned char *level; + QChar::Direction *dir; + unsigned char base = 0; + + unsigned int l = length(); + + // check bounds + if (len == -1) + len = length()-index; + if ((uint)index > l) + return QString::null; + + // find base direction + unsigned int pos = 0; + while ((pos < length()) && + (at(pos) != RLE) && + (at(pos) != LRE) && + (at(pos) != RLO) && + (at(pos) != LRO) && + (at(pos).direction() > 1) && + (at(pos).direction() != QChar::DirAL) + ) // not R and not L + pos++; + + if ((pos < length()) && + ((at(pos).direction() == QChar::DirR) || + (at(pos).direction() == QChar::DirAL) || + (at(pos) == RLE) || + (at(pos) == RLO))) + base = 1; + + // is there any BiDi char at all? + if ( base == 0 && pos == l ) { + return mid(index, len); + } + + + level = new uchar[l]; + dir = new QChar::Direction[l]; + + // explicit override pass + //unsigned int code_count = 0; + + QStack<QBidiState> stack; + stack.setAutoDelete(TRUE); + + unsigned char clevel = base; + signed char override = -1; + + for (pos = 0; pos < l; pos++) { + + if (at(pos) == RLE) { + //code_count++; + stack.push(new QBidiState(clevel, override)); + if (clevel < 254) + clevel += 1 + clevel % 2; + override = -1; + } + else if (at(pos) == LRE) { + //code_count++; + stack.push(new QBidiState(clevel, override)); + if (clevel < 254) + clevel += 2 - clevel % 2; + override = -1; + } + else if (at(pos) == RLO) { + //code_count++; + stack.push(new QBidiState(clevel, override)); + if (clevel < 254) + clevel += 1 + clevel % 2; + override = QChar::DirR; + } + else if (at(pos) == LRO) { + //code_count++; + stack.push(new QBidiState(clevel, override)); + if (clevel < 254) + clevel += 2 - clevel % 2; + override = QChar::DirL; + } + else if (at(pos) == PDF) { + //code_count++; + if (!stack.isEmpty()) { + override = stack.top()->override; + clevel = stack.top()->level; + stack.remove(); + } + } + + // TODO: catch block separators (newlines, paras, etc.) + + level[pos] = clevel; + if (override != -1) + dir[pos] = (QChar::Direction) override; + else + dir[pos] = at(pos).direction(); + } + + // weak type pass + for (pos = 0; pos < l; pos++) { + + int i; + + switch (at(pos).direction()) { + case QChar::DirEN: + i = pos-1; + while ((i >= 0) && + !(at(i).direction() == QChar::DirAN) && + !(at(i).direction() == QChar::DirAL) && + !(at(i).direction() == QChar::DirB)) + i--; + + if ((i >= 0) && + ((at(i).direction() == QChar::DirAN) || + (at(i).direction() == QChar::DirAL))) + dir[pos] = QChar::DirAN; + + break; + case QChar::DirES: + case QChar::DirCS: + if ((pos > 0) && (pos < l-1) && + (dir[pos-1] == dir[pos+1])) + dir[pos] = dir[pos-1]; + else + dir[pos] = QChar::DirON; + + break; + case QChar::DirET: + if (((pos > 0) && (dir[pos-1] == QChar::DirEN)) || + ((pos < l-1) && (dir[pos+1] == QChar::DirEN))) + dir[pos] = QChar::DirEN; + else + dir[pos] = QChar::DirON; + + break; + case QChar::DirAL: + dir[pos] = QChar::DirR; + break; + default: + break; + } + } + + // neutral type pass + for (pos = 0; pos < l; pos++) { + QChar::Direction left,right; // declaring l here shadowed previous l + + if (is_neutral(dir[pos])) { + if (pos > 0) + left = dir[pos-1]; + else + left = (base == 0 ? QChar::DirL : QChar::DirR); + + int i = pos; + + while ((i < (int)l-1) && is_neutral(dir[i+1])) + i++; + + if (i < (int)l-1) + right = dir[i+1]; + else + right = (base == 0 ? QChar::DirL : QChar::DirR); + + for (int j=pos; j <= i; j++) { + int a = 1, b = 1; + while ((a < 5) && (left != resolv[0][a])) + a++; + while ((b < 5) && (right != resolv[0][b])) + b++; + if ((a == 5) || (b == 5)) + dir[j] = (base == 0 ? QChar::DirL : QChar::DirR); + else + dir[j] = resolv[a][b]; + + if (dir[j] == (QChar::Direction)(-1)) + dir[j] = (base == 0 ? QChar::DirL : QChar::DirR); + } + } + } + + // implicit level pass + QChar::Direction prec = (base == 0 ? QChar::DirL : QChar::DirR); + + for (pos = 0; pos < l; pos++) { + if (level[pos] % 2) { + switch (dir[pos]) { + case QChar::DirL: + case QChar::DirAN: + case QChar::DirEN: + level[pos] += 1; + break; + default: + break; + } + } else { + switch (dir[pos]) { + case QChar::DirL: + // do nothing + break; + case QChar::DirR: + level[pos] += 1; + break; + case QChar::DirEN: + if (prec == QChar::DirL) + continue; + // fall through + case QChar::DirAN: + level[pos] += 2; + break; + default: + break; + } + } + + prec = dir[pos]; + } + + // now do the work! + QString ret(*this); + reverse(ret, level, index, index+len); + + delete [] level; + delete [] dir; + + return ret; +#else + return mid(index,len); +#endif +} + + + +// These macros are used for efficient allocation of QChar strings. +// IMPORTANT! If you change these, make sure you also change the +// "delete unicode" statement in ~QStringData() in qstring.h correspondingly! + +#define QT_ALLOC_QCHAR_VEC( N ) (QChar*) new char[ sizeof(QChar)*( N ) ] +#define QT_DELETE_QCHAR_VEC( P ) delete[] ((char*)( P )) + + +/*! + This utility function converts the 8-bit string + \a ba to Unicode, returning the result. + + The caller is responsible for deleting the return value with delete[]. +*/ + +QChar* QString::asciiToUnicode( const QByteArray& ba, uint* len ) +{ + if ( ba.isNull() ) { + *len = 0; + return 0; + } + int l = 0; + while ( l < (int)ba.size() && ba[l] ) + l++; + char* str = ba.data(); + QChar *uc = new QChar[ l ]; // Can't use macro, since function is public + QChar *result = uc; + if ( len ) + *len = l; + while (l--) + *uc++ = *str++; + return result; +} + +static QChar* internalAsciiToUnicode( const QByteArray& ba, uint* len ) +{ + if ( ba.isNull() ) { + *len = 0; + return 0; + } + int l = 0; + while ( l < (int)ba.size() && ba[l] ) + l++; + char* str = ba.data(); + QChar *uc = QT_ALLOC_QCHAR_VEC( l ); + QChar *result = uc; + if ( len ) + *len = l; + while (l--) + *uc++ = *str++; + return result; +} + +/*! + This utility function converts the NUL-terminated 8-bit string + \a str to Unicode, returning the result and setting \a len to + the length of the Unicode string. + + The caller is responsible for deleting the return value with delete[]. +*/ + +QChar* QString::asciiToUnicode( const char *str, uint* len, uint maxlen ) +{ + QChar* result = 0; + uint l = 0; + if ( str ) { + if ( maxlen != (uint)-1 ) { + while ( l < maxlen && str[l] ) + l++; + } else { + // Faster? + l = qstrlen(str); + } + QChar *uc = new QChar[ l ]; // Can't use macro since function is public + result = uc; + uint i = l; + while ( i-- ) + *uc++ = *str++; + } + if ( len ) + *len = l; + return result; +} + +static QChar* internalAsciiToUnicode( const char *str, uint* len, + uint maxlen = (uint)-1 ) +{ + QChar* result = 0; + uint l = 0; + if ( str ) { + if ( maxlen != (uint)-1 ) { + while ( l < maxlen && str[l] ) + l++; + } else { + // Faster? + l = qstrlen(str); + } + QChar *uc = QT_ALLOC_QCHAR_VEC( l ); + result = uc; + uint i = l; + while ( i-- ) + *uc++ = *str++; + } + if ( len ) + *len = l; + return result; +} + +/*! + This utility function converts \a l 16-bit characters from + \a uc to ASCII, returning a NUL-terminated string. + + The caller is responsible for deleting the string with delete[]. +*/ +char* QString::unicodeToAscii(const QChar *uc, uint l) +{ + if (!uc) { + return 0; + } + char *a = new char[l+1]; + char *result = a; + while (l--) + *a++ = *uc++; + *a = '\0'; + return result; +} + +static uint computeNewMax( uint len ) +{ + if (len >= 0x80000000) + return len; + + uint newMax = 4; + while ( newMax < len ) + newMax *= 2; + // try to save some memory + if ( newMax >= 1024 * 1024 && len <= newMax - (newMax >> 2) ) + newMax -= newMax >> 2; + return newMax; +} + +/*! + Returns the QString as a zero terminated array of unsigned shorts + if the string is not null; otherwise returns zero. + + The result remains valid so long as one unmodified + copy of the source string exists. + */ +const unsigned short *QString::ucs2() const +{ + if ( ! d->unicode ) + return 0; + unsigned int len = d->len; + if ( d->maxl < len + 1 ) { + // detach, grow or shrink + uint newMax = computeNewMax( len + 1 ); + QChar* nd = QT_ALLOC_QCHAR_VEC( newMax ); + if ( nd ) { + if ( d->unicode ) + memcpy( nd, d->unicode, sizeof(QChar)*len ); + ((QString *)this)->deref(); + ((QString *)this)->d = new QStringData( nd, len, newMax ); + } + } + d->unicode[len] = 0; + return (unsigned short *) d->unicode; +} + +/*! + Constructs a string that is a deep copy of \a str, interpreted as a + UCS2 encoded, zero terminated, Unicode string. + + If \a str is 0, then a null string is created. + \sa isNull() + */ +QString QString::fromUcs2( const unsigned short *str ) +{ + if ( !str ) { + return QString::null; + } else { + int length = 0; + while ( str[length] != 0 ) + length++; + QChar* uc = QT_ALLOC_QCHAR_VEC( length ); + memcpy( uc, str, length*sizeof(QChar) ); + return QString( new QStringData( uc, length, length ), TRUE ); + } +} + + +/***************************************************************************** + QString member functions + *****************************************************************************/ + +/*! + \class QString qstring.h + + \brief The QString class provides an abstraction of Unicode text and + the classic C null-terminated char array (<var>char*</var>). + + \ingroup tools + \ingroup shared + + QString uses \link shclass.html implicit sharing\endlink, and so it + is very efficient and easy to use. + + In all QString methods that take <var>const char*</var> parameters, + the <var>const char*</var> is interpreted as a classic C-style + 0-terminated ASCII string. It is legal for the <var>const + char*</var> parameter to be 0. The results are undefined if the + <var>const char*</var> string is not 0-terminated. Functions that + copy classic C strings into a QString will not copy the terminating + 0-character. The QChar array of the QString (as returned by + unicode()) is not terminated by a null. + + A QString that has not been assigned to anything is \a null, i.e. both + the length and data pointer is 0. A QString that references the empty + string ("", a single '\0' char) is \a empty. Both null and empty + QStrings are legal parameters to the methods. Assigning <var>const char + * 0</var> to QString gives a null QString. + + Note that if you find that you are mixing usage of QCString, QString, + and QByteArray, this causes lots of unnecessary copying and might + indicate that the true nature of the data you are dealing with is + uncertain. If the data is NUL-terminated 8-bit data, use QCString; + if it is unterminated (ie. contains NULs) 8-bit data, use QByteArray; + if it is text, use QString. + + \sa QChar \link shclass.html Shared classes\endlink +*/ + +Q_EXPORT QStringData *QString::shared_null = 0; +//QT_STATIC_CONST_IMPL QString QString::null; +QT_STATIC_CONST_IMPL QChar QChar::null; +QT_STATIC_CONST_IMPL QChar QChar::replacement((ushort)0xfffd); +QT_STATIC_CONST_IMPL QChar QChar::byteOrderMark((ushort)0xfeff); +QT_STATIC_CONST_IMPL QChar QChar::byteOrderSwapped((ushort)0xfffe); +QT_STATIC_CONST_IMPL QChar QChar::nbsp((ushort)0x00a0); + +#if defined(_CC_MSVC_) && _MSC_VER <= 1300 +const QString::Null QString::null; +#else +const QString::Null QString::null = { }; +#endif + + +QStringData* QString::makeSharedNull() +{ + return shared_null=new QStringData; +} + +// Uncomment this to get some useful statistics. +// #define Q2HELPER(x) x + +#ifdef Q2HELPER +static int stat_construct_charstar=0; +static int stat_construct_charstar_size=0; +static int stat_construct_null=0; +static int stat_construct_int=0; +static int stat_construct_int_size=0; +static int stat_construct_ba=0; +static int stat_get_ascii=0; +static int stat_get_ascii_size=0; +static int stat_copy_on_write=0; +static int stat_copy_on_write_size=0; +static int stat_fast_copy=0; +Q_EXPORT void qt_qstring_stats() +{ + qDebug("construct_charstar = %d (%d chars)", stat_construct_charstar, stat_construct_charstar_size); + qDebug("construct_null = %d", stat_construct_null); + qDebug("construct_int = %d (%d chars)", stat_construct_int, stat_construct_int_size); + qDebug("construct_ba = %d", stat_construct_ba); + qDebug("get_ascii = %d (%d chars)", stat_get_ascii, stat_get_ascii_size); + qDebug("copy_on_write = %d (%d chars)", stat_copy_on_write, stat_copy_on_write_size); + qDebug("fast_copy = %d", stat_fast_copy); +} +#else +#define Q2HELPER(x) +#endif + +/*! + \fn QString::QString() + + Constructs a null string. + \sa isNull() +*/ + +/*! + Constructs a string containing the one character \a ch. +*/ +QString::QString( QChar ch ) +{ + d = new QStringData( QT_ALLOC_QCHAR_VEC( 1 ), 1, 1 ); + d->unicode[0] = ch; +} + +/*! + Constructs an implicitly-shared copy of \a s. +*/ +QString::QString( const QString &s ) : + d(s.d) +{ + Q2HELPER(stat_fast_copy++) + d->ref(); +} + +/*! + Private function. + + Constructs a string with preallocated space for \a size characters. + + The string is empty. + + \sa isNull() +*/ + +QString::QString( int size, bool /*dummy*/ ) +{ + if ( size ) { + Q2HELPER(stat_construct_int++) + int l = size; + Q2HELPER(stat_construct_int_size+=l) + QChar* uc = QT_ALLOC_QCHAR_VEC( l ); + d = new QStringData( uc, 0, l ); + } else { + Q2HELPER(stat_construct_null++) + d = shared_null ? shared_null : (shared_null=new QStringData); + d->ref(); + } +} + +/*! + Constructs a string that is a deep copy of \a ba interpreted as + a classic C string. +*/ + +QString::QString( const QByteArray& ba ) +{ + Q2HELPER(stat_construct_ba++) + uint l; + QChar *uc = internalAsciiToUnicode(ba,&l); + d = new QStringData(uc,l,l); +} + +QString::QString( const QCString& ba ) +{ + //Q2HELPER(stat_construct_ba++) + //uint l; + //QChar *uc = internalAsciiToUnicode(ba,&l); + //d = new QStringData(uc,l,l); + Q2HELPER(stat_fast_copy++) + QString s = QString::fromUtf8(ba.data(),ba.length()); + d = s.d; + d->ref(); +} + +/*! + Constructs a string that is a deep copy of the + first \a length QChar in the array \a unicode. + + If \a unicode and \a length are 0, a null string is created. + + If only \a unicode is 0, the string is empty, but has + \a length characters of space preallocated - QString expands + automatically anyway, but this may speed some cases up a little. + + \sa isNull() +*/ + +QString::QString( const QChar* unicode, uint length ) +{ + if ( !unicode && !length ) { + d = shared_null ? shared_null : makeSharedNull(); + d->ref(); + } else { + QChar* uc = QT_ALLOC_QCHAR_VEC( length ); + if ( unicode ) + memcpy(uc, unicode, length*sizeof(QChar)); + d = new QStringData(uc,unicode ? length : 0,length); + } +} + +/*! + Constructs a string that is a deep copy of \a str, interpreted as a + classic C string. + + If \a str is 0 a null string is created. + + This is a cast constructor, but it is perfectly safe: converting a Latin1 + const char* to QString preserves all the information. + You can disable this constructor by + defining QT_NO_CAST_ASCII when you compile your applications. + You can also make QString objects by using setLatin1()/fromLatin1(), or + fromLocal8Bit(), fromUtf8(), or whatever encoding is appropriate for + the 8-bit data you have. + + \sa isNull() +*/ + +QString::QString( const char *str ) +{ + //Q2HELPER(stat_construct_charstar++) + //uint l; + //QChar *uc = internalAsciiToUnicode(str,&l); + //Q2HELPER(stat_construct_charstar_size+=l) + //d = new QStringData(uc,l,l); + Q2HELPER(stat_fast_copy++) + QString s = QString::fromUtf8(str); + d = s.d; + d->ref(); +} + + +/*! \fn QString::~QString() + +Destroys the string and frees the "real" string, if this was the last +copy of that string. +*/ + + +/*! + Deallocates any space reserved solely by this QString. +*/ + +void QString::real_detach() +{ + setLength( length() ); +} + +void QString::deref() +{ + if ( d->deref() ) { + if ( d == shared_null ) + shared_null = 0; + delete d; + d = 0; // helps debugging + } +} + +void QStringData::deleteSelf() +{ + delete this; +} + +/*! + \fn QString& QString::operator=( QChar c ) + Sets the string to contain just the single character \a c. +*/ + +/*! + \fn QString& QString::operator=( char c ) + Sets the string to contain just the single character \a c. +*/ + +/*! + Assigns a shallow copy of \a s to this string and returns a + reference to this string. +*/ +QString &QString::operator=( const QString &s ) +{ + Q2HELPER(stat_fast_copy++) + s.d->ref(); + deref(); + d = s.d; + return *this; +} + +/*! + Assigns a deep copy of \a cs, interpreted as a classic C string, to + this string and returns a reference to this string. +*/ +QString &QString::operator=( const QCString& cs ) +{ + return setLatin1(cs); +} + + +/*! + Assigns a deep copy of \a str, interpreted as a classic C string, + to this string and returns a reference to this string. + + If \a str is 0 a null string is created. + + \sa isNull() +*/ +QString &QString::operator=( const char *str ) +{ + return setLatin1(str); +} + + +/*! + \fn bool QString::isNull() const + + Returns TRUE if the string is null. + A null string is also an empty string. + + Example: + \code + QString a; // a.unicode() == 0, a.length() == 0 + QString b = ""; // b.unicode() == "", b.length() == 0 + a.isNull(); // TRUE, because a.unicode() == 0 + a.isEmpty(); // TRUE, because a.length() == 0 + b.isNull(); // FALSE, because b.unicode() != 0 + b.isEmpty(); // TRUE, because b.length() == 0 + \endcode + + \sa isEmpty(), length() +*/ + +/*! + \fn bool QString::isEmpty() const + + Returns TRUE if the string is empty, i.e. if length() == 0. + An empty string is not always a null string. + + See example in isNull(). + + \sa isNull(), length() +*/ + +/*! + \fn uint QString::length() const + + Returns the length of the string. + + Null strings and empty strings have zero length. + + \sa isNull(), isEmpty() +*/ + +/*! + Truncates the string at position \a newLen if newLen is less than the + current length . Otherwise, nothing happens. + + Example: + \code + QString s = "truncate this string"; + s.truncate( 5 ); // s == "trunc" + \endcode + + In Qt 1.x, it was possible to "truncate" a string to a longer + length. This is no longer possible. + +*/ + +void QString::truncate( uint newLen ) +{ + if ( newLen < d->len ) + setLength( newLen ); +} + +/*### Make this public in 3.0 + Ensures that at least \a newLen characters are allocated, and + sets the length to \a newLen. This function always detaches the + string from other references to the same data. Any new space + allocated is \e not defined. + + If \a newLen is 0, this string becomes empty, unless this string is + null, in which case it remains null. + + \sa truncate(), isNull(), isEmpty() +*/ + +void QString::setLength( uint newLen ) +{ + if ( d->count != 1 || newLen > d->maxl || // detach, grow, or + ( newLen*4 < d->maxl && d->maxl > 4 ) ) { // shrink + Q2HELPER(stat_copy_on_write++) + Q2HELPER(stat_copy_on_write_size+=d->len) + uint newMax = 4; + while ( newMax < newLen ) + newMax *= 2; + QChar* nd = QT_ALLOC_QCHAR_VEC( newMax ); + uint len = QMIN( d->len, newLen ); + if ( d->unicode ) + memcpy( nd, d->unicode, sizeof(QChar)*len ); + deref(); + d = new QStringData( nd, newLen, newMax ); + } else { + d->len = newLen; + d->dirtyascii = 1; + } +} + +/*! Returns a string equal to this one, but with the lowest-numbered + occurrence of \c %i (for a positive integer i) replaced by \a a. + + \code + label.setText( tr("Rename %1 to %2?").arg(oldName).arg(newName) ); + \endcode + + \a fieldwidth is the minimum amount of space \a a is padded to. A + positive value produces right-aligned text, while a negative value + produces left aligned text. + + \warning Using arg() for constructing "real" sentences + programmatically is likely to lead to translation problems. + Inserting objects like numbers or file names is fairly safe. + + \warning Relying on spaces to create alignment is prone to lead to + translation problems. + + If there is no \c %i pattern, a warning message (qWarning()) is + printed and the text as appended at the end of the string. This is + error recovery and should not occur in correct code. + + \sa QObject::tr() +*/ +QString QString::arg(const QString& a, int fieldwidth) const +{ + int pos, len; + QString r = *this; + + if ( !findArg( pos, len ) ) { + qWarning( "QString::arg(): Argument missing: %s, %s", + (const char *)this, (const char *)a ); + // Make sure the text at least appears SOMEWHERE + r += ' '; + pos = r.length(); + len = 0; + } + + r.replace( pos, len, a ); + if ( fieldwidth < 0 ) { + QString s; + while ( (uint)-fieldwidth > a.length() ) { + s += ' '; + fieldwidth++; + } + r.insert( pos + a.length(), s ); + } else if ( fieldwidth ) { + QString s; + while ( (uint)fieldwidth > a.length() ) { + s += ' '; + fieldwidth--; + } + r.insert( pos, s ); + } + + return r; +} + + +/*! \overload + + \a a is expressed in to \a base notation, which is decimal by + default and must be in the range 2-36 inclusive. +*/ +QString QString::arg(long a, int fieldwidth, int base) const +{ + return arg( QString::number( a, base ), fieldwidth ); +} + +/*! \overload + + \a a is expressed in to \a base notation, which is decimal by + default and must be in the range 2-36 inclusive. +*/ +QString QString::arg(ulong a, int fieldwidth, int base) const +{ + return arg( QString::number( a, base ), fieldwidth ); +} + +/*! + \overload QString QString::arg(int a, int fieldwidth, int base) const + + \a a is expressed in to \a base notation, which is decimal by + default and must be in the range 2-36 inclusive. + +*/ + +/*! + \overload QString QString::arg(uint a, int fieldwidth, int base) const + + \a a is expressed in to \a base notation, which is decimal by + default and must be in the range 2-36 inclusive. +*/ + +/*! + \overload QString QString::arg(short a, int fieldwidth, int base) const + + \a a is expressed in to \a base notation, which is decimal by + default and must be in the range 2-36 inclusive. +*/ + +/*! + \overload QString QString::arg(ushort a, int fieldwidth, int base) const + + \a a is expressed in to \a base notation, which is decimal by + default and must be in the range 2-36 inclusive. +*/ + + +/*! \overload + + \a a is assumed to be in the Latin1 character set. +*/ +QString QString::arg(char a, int fieldwidth) const +{ + QString c; + c += a; + return arg( c, fieldwidth ); +} + +/*! \overload +*/ +QString QString::arg(QChar a, int fieldwidth) const +{ + QString c; + c += a; + return arg( c, fieldwidth ); +} + +/*! \overload + + \a is formatted according to the \a fmt format specified, which is + 'g' by default and can be any of 'f', 'F', 'e', 'E', 'g' or 'G', all + of which have the same meaning as for sprintf(). \a prec determines + the precision, just as for number() and sprintf(). +*/ +QString QString::arg(double a, int fieldwidth, char fmt, int prec) const +{ + return arg( QString::number( a, fmt, prec ), fieldwidth ); +} + + +/*! + Just 1-digit arguments. +*/ +bool QString::findArg(int& pos, int& len) const +{ + char lowest=0; + for (uint i=0; i<length(); i++) { + if ( at(i) == '%' && i+1<length() ) { + char dig = at(i+1); + if ( dig >= '0' && dig <= '9' ) { + if ( !lowest || dig < lowest ) { + lowest = dig; + pos = i; + len = 2; + } + } + } + } + return lowest != 0; +} + +/*! + Safely builds a formatted string from a format string and an + arbitrary list of arguments. The format string supports all + the escape sequences of printf() in the standard C library. + + The %s escape sequence expects a utf8() encoded string. + The format string \e cformat is expected to be in latin1. If you need a unicode + format string, use QString::arg() instead. For typesafe + string building, with full Unicode support, you can use QTextOStream + like this: + + \code + QString str; + QString s = ...; + int x = ...; + QTextOStream(&str) << s << " : " << x; + \endcode + + For \link QObject::tr() translations,\endlink especially if the + strings contains more than one escape sequence, you should consider + using the arg() function instead. This allows the order of the + replacements to be controlled by the translator, and has Unicode + support. + + \sa arg() +*/ + +QString &QString::sprintf( const char* cformat, ... ) +{ + va_list ap; + va_start( ap, cformat ); + + if ( !cformat || !*cformat ) { + // Qt 1.x compat + *this = QString::fromLatin1( "" ); + return *this; + } + QString format = QString::fromLatin1( cformat ); + + static QRegExp *escape = 0; + if (!escape) + escape = new QRegExp( "%#?0?-? ?\\+?'?[0-9*]*\\.?[0-9*]*h?l?L?q?Z?" ); + + QString result; + uint last = 0; + + int len = 0; + int pos; + while ( 1 ) { + pos = escape->match( cformat, last, &len ); + // Non-escaped text + if ( pos > (int)last ) + result += format.mid(last,pos-last); + if ( pos < 0 ) { + // The rest + if ( last < format.length() ) + result += format.mid(last); + break; + } + last = pos + len + 1; + + // Escape + QString f = format.mid( pos, len ); + uint width, decimals; + int params = 0; + int wpos = f.find('*'); + if ( wpos >= 0 ) { + params++; + width = va_arg( ap, int ); + if ( f.find('*', wpos + 1) >= 0 ) { + decimals = va_arg( ap, int ); + params++; + } else { + decimals = 0; + } + } else { + decimals = width = 0; + } + QString replacement; + if ( format[pos+len] == 's' || + format[pos+len] == 'S' || + format[pos+len] == 'c' ) + { + bool rightjust = ( f.find('-') < 0 ); + // Yes, %-5s really means left adjust in sprintf + + if ( wpos < 0 ) { + QRegExp num( "[0-9]+" ); + QRegExp dot( "\\." ); + int nlen; + int p = num.match( f.data(), 0, &nlen ); + int q = dot.match( f.data(), 0 ); + if ( q < 0 || (p < q && p >= 0) ) + width = f.mid( p, nlen ).toInt(); + if ( q >= 0 ) { + p = num.match( f.data(), q ); + // "decimals" is used to specify string truncation + if ( p >= 0 ) + decimals = f.mid( p, nlen ).toInt(); + } + } + + if ( format[pos+len] == 's' ) { +#ifndef QT_NO_TEXTCODEC + QString s = QString::fromUtf8(va_arg(ap, char*)); +#else + QString s = QString::fromLatin1(va_arg(ap, char*)); +#endif + if ( decimals <= 0 ) + replacement = s; + else + replacement = s.left(decimals); + } else { + int ch = va_arg(ap, int); + replacement = QChar((ushort)ch); + } + if ( replacement.length() < width ) { + replacement = rightjust + ? replacement.rightJustify(width) + : replacement.leftJustify(width); + } + } else if ( format[pos+len] == '%' ) { + replacement = '%'; + } else if ( format[pos+len] == 'n' ) { + int* n = va_arg(ap, int*); + *n = result.length(); + } else { + char in[64], out[330] = ""; + strncpy(in,f.latin1(),63); + char fch = format[pos+len].latin1(); + in[f.length()] = fch; + switch ( fch ) { + case 'd': case 'i': case 'o': case 'u': case 'x': case 'X': { + int value = va_arg(ap, int); + switch (params) { + case 0: ::sprintf( out, in, value ); break; + case 1: ::sprintf( out, in, width, value ); break; + case 2: ::sprintf( out, in, width, decimals, value ); break; + } + } break; + case 'e': case 'E': case 'f': case 'g': case 'G': { + double value = va_arg(ap, double); + switch (params) { + case 0: ::sprintf( out, in, value ); break; + case 1: ::sprintf( out, in, width, value ); break; + case 2: ::sprintf( out, in, width, decimals, value ); break; + } + } break; + case 'p': { + void* value = va_arg(ap, void*); + switch (params) { + case 0: ::sprintf( out, in, value ); break; + case 1: ::sprintf( out, in, width, value ); break; + case 2: ::sprintf( out, in, width, decimals, value ); break; + } + } break; + } + replacement = QString::fromLatin1(out); + } + result += replacement; + } + *this = result; + + va_end( ap ); + return *this; +} + +/*! + Fills the string with \a len characters of value \a c. + + If \a len is negative, the current string length is used. +*/ + +void QString::fill( QChar c, int len ) +{ + if ( len < 0 ) + len = length(); + if ( len == 0 ) { + *this = ""; + } else { + deref(); + QChar * nd = QT_ALLOC_QCHAR_VEC( len ); + d = new QStringData(nd,len,len); + while (len--) *nd++ = c; + } +} + + +/*! + \fn QString QString::copy() const + + \obsolete + + Returns a deep copy of this string. + + Doing this is redundant in Qt 2.x, since QString is implicitly + shared, and so will automatically be deeply copied as necessary. +*/ + +/*! + Finds the first occurrence of the character \a c, starting at + position \a index. If \a index is -1, the search starts at the + last character; if -2, at the next to last character; etc. + + The search is case sensitive if \a cs is TRUE, or case insensitive + if \a cs is FALSE. + + Returns the position of \a c, or -1 if \a c could not be found. +*/ + +int QString::find( QChar c, int index, bool cs ) const +{ + if ( index < 0 ) + index += length(); + if ( (uint)index >= length() ) // index outside string + return -1; + register const QChar *uc; + uc = unicode()+index; + int n = length()-index; + if ( cs ) { + while ( n-- && *uc != c ) + uc++; + } else { + c = c.lower(); + while ( n-- && uc->lower() != c ) + uc++; + } + if ( uint(uc - unicode()) >= length() ) + return -1; + return (int)(uc - unicode()); +} + +/*! + Finds the first occurrence of the string \a str, starting at position + \a index. If \a index is -1, the search starts at the last character; + if -2, at the next to last character; etc. + + The search is case sensitive if \a cs is TRUE, or case insensitive if + \a cs is FALSE. + + Returns the position of \a str, or -1 if \a str could not be found. +*/ + +int QString::find( const QString& str, int index, bool cs ) const +{ + /* + We use some weird hashing for efficiency's sake. Instead of + comparing strings, we compare the hash value of str with that of + a part of this QString. Only if that matches, we call ucstrncmp + or ucstrnicmp. + + The hash value of a string is the sum of the cells of its + QChars. + */ + if ( index < 0 ) + index += length(); + int lstr = str.length(); + int lthis = length() - index; + if ( (uint)lthis > length() ) + return -1; + int delta = lthis - lstr; + if ( delta < 0 ) + return -1; + + const QChar *uthis = unicode() + index; + const QChar *ustr = str.unicode(); + uint hthis = 0; + uint hstr = 0; + int i; + if ( cs ) { + for ( i = 0; i < lstr; i++ ) { + hthis += uthis[i].cell(); + hstr += ustr[i].cell(); + } + i = 0; + while ( TRUE ) { + if ( hthis == hstr && ucstrncmp(uthis + i, ustr, lstr) == 0 ) + return index + i; + if ( i == delta ) + return -1; + hthis += uthis[i + lstr].cell(); + hthis -= uthis[i].cell(); + i++; + } + } else { + for ( i = 0; i < lstr; i++ ) { + hthis += uthis[i].lower().cell(); + hstr += ustr[i].lower().cell(); + } + i = 0; + while ( TRUE ) { + if ( hthis == hstr && ucstrnicmp(uthis + i, ustr, lstr) == 0 ) + return index + i; + if ( i == delta ) + return -1; + hthis += uthis[i + lstr].lower().cell(); + hthis -= uthis[i].lower().cell(); + i++; + } + } +#if defined(Q_SPURIOUS_NON_VOID_WARNING) + return -1; +#endif +} + +/*! + \fn int QString::findRev( const char* str, int index ) const + + Equivalent to findRev(QString(str), index). +*/ + +/*! + \fn int QString::find( const char* str, int index ) const + + Equivalent to find(QString(str), index). +*/ + +/*! + Finds the first occurrence of the character \a c, starting at + position \a index and searching backwards. If \a index is -1, + the search starts at the last character; if -2, at the next to + last character; etc. + + The search is case sensitive if \a cs is TRUE, or case insensitive if \a + cs is FALSE. + + Returns the position of \a c, or -1 if \a c could not be found. +*/ + +int QString::findRev( QChar c, int index, bool cs ) const +{ + QString t( c ); + return findRev( t, index, cs ); +} + +/*! + Finds the first occurrence of the string \a str, starting at + position \a index and searching backwards. If \a index is -1, + the search starts at the last character; -2, at the next to last + character; etc. + + The search is case sensitive if \a cs is TRUE, or case insensitive if \e + cs is FALSE. + + Returns the position of \a str, or -1 if \a str could not be found. +*/ + +int QString::findRev( const QString& str, int index, bool cs ) const +{ + /* + See QString::find() for explanations. + */ + int lthis = length(); + if ( index < 0 ) + index += lthis; + + int lstr = str.length(); + int delta = lthis - lstr; + if ( index < 0 || index > lthis || delta < 0 ) + return -1; + if ( index > delta ) + index = delta; + + const QChar *uthis = unicode(); + const QChar *ustr = str.unicode(); + uint hthis = 0; + uint hstr = 0; + int i; + if ( cs ) { + for ( i = 0; i < lstr; i++ ) { + hthis += uthis[index + i].cell(); + hstr += ustr[i].cell(); + } + i = index; + while ( TRUE ) { + if ( hthis == hstr && ucstrncmp(uthis + i, ustr, lstr) == 0 ) + return i; + if ( i == 0 ) + return -1; + i--; + hthis -= uthis[i + lstr].cell(); + hthis += uthis[i].cell(); + } + } else { + for ( i = 0; i < lstr; i++ ) { + hthis += uthis[index + i].lower().cell(); + hstr += ustr[i].lower().cell(); + } + i = index; + while ( TRUE ) { + if ( hthis == hstr && ucstrnicmp(uthis + i, ustr, lstr) == 0 ) + return i; + if ( i == 0 ) + return -1; + i--; + hthis -= uthis[i + lstr].lower().cell(); + hthis += uthis[i].lower().cell(); + } + } +#if defined(Q_SPURIOUS_NON_VOID_WARNING) + return -1; +#endif +} + + +/*! + Returns the number of times the character \a c occurs in the string. + + The match is case sensitive if \a cs is TRUE, or case insensitive if \a cs + is FALSE. +*/ + +int QString::contains( QChar c, bool cs ) const +{ + int count = 0; + const QChar *uc = unicode(); + if ( !uc ) + return 0; + int n = length(); + if ( cs ) { // case sensitive + while ( n-- ) + if ( *uc++ == c ) + count++; + } else { // case insensitive + c = c.lower(); + while ( n-- ) { + if ( uc->lower() == c ) + count++; + uc++; + } + } + return count; +} + +/*! + \overload +*/ +int QString::contains( const char* str, bool cs ) const +{ + return contains(QString(str),cs); +} + +/*! + \overload int QString::contains (char c, bool cs) const +*/ + +/*! + \overload int QString::find (char c, int index, bool cs) const + +*/ + +/*! + \overload int QString::findRev (char c, int index, bool cs) const + +*/ + +/*! + Returns the number of times \a str occurs in the string. + + The match is case sensitive if \a cs is TRUE, or case insensitive if \e + cs is FALSE. + + This function counts overlapping substrings, for example, "banana" + contains two occurrences of "ana". + + \sa findRev() +*/ + +int QString::contains( const QString &str, bool cs ) const +{ + int count = 0; + const QChar *uc = unicode(); + if ( !uc ) + return 0; + int len = str.length(); + int n = length(); + while ( n-- ) { // counts overlapping strings + // ### Doesn't account for length of this - searches over "end" + if ( cs ) { + if ( ucstrncmp( uc, str.unicode(), len ) == 0 ) + count++; + } else { + if ( ucstrnicmp(uc, str.unicode(), len) == 0 ) + count++; + } + uc++; + } + return count; +} + +/*! + Returns a substring that contains the \a len leftmost characters + of the string. + + The whole string is returned if \a len exceeds the length of the + string. + + + Example: + \code + QString s = "Pineapple"; + QString t = s.left( 4 ); // t == "Pine" + \endcode + + \sa right(), mid(), isEmpty() +*/ + +QString QString::left( uint len ) const +{ + if ( isEmpty() ) { + return QString(); + } else if ( len == 0 ) { // ## just for 1.x compat: + return QString::fromLatin1(""); + } else if ( len > length() ) { + return *this; + } else { + QString s( len, TRUE ); + memcpy( s.d->unicode, d->unicode, len*sizeof(QChar) ); + s.d->len = len; + return s; + } +} + +/*! + Returns a substring that contains the \a len rightmost characters + of the string. + + The whole string is returned if \a len exceeds the length of the + string. + + Example: + \code + QString s = "Pineapple"; + QString t = s.right( 5 ); // t == "apple" + \endcode + + \sa left(), mid(), isEmpty() +*/ + +QString QString::right( uint len ) const +{ + if ( isEmpty() ) { + return QString(); + } else if ( len == 0 ) { // ## just for 1.x compat: + return QString::fromLatin1(""); + } else { + uint l = length(); + if ( len > l ) + len = l; + QString s( len, TRUE ); + memcpy( s.d->unicode, d->unicode+(l-len), len*sizeof(QChar) ); + s.d->len = len; + return s; + } +} + +/*! + Returns a substring that contains the \a len characters of this + string, starting at position \a index. + + Returns a null string if the string is empty or \a index is out + of range. Returns the whole string from \a index if \a index+len exceeds + the length of the string. + + Example: + \code + QString s = "Five pineapples"; + QString t = s.mid( 5, 4 ); // t == "pine" + \endcode + + \sa left(), right() +*/ + +QString QString::mid( uint index, uint len ) const +{ + uint slen = length(); + if ( isEmpty() || index >= slen ) { + return QString(); + } else if ( len == 0 ) { // ## just for 1.x compat: + return QString::fromLatin1(""); + } else { + if ( len > slen-index ) + len = slen - index; + if ( index == 0 && len == length() ) + return *this; + register const QChar *p = unicode()+index; + QString s( len, TRUE ); + memcpy( s.d->unicode, p, len*sizeof(QChar) ); + s.d->len = len; + return s; + } +} + +/*! + Returns a string of length \a width that contains this + string and padded by the \a fill character. + + If the length of the string exceeds \a width and \a truncate is FALSE, + then the returned string is a copy of the string. + If the length of the string exceeds \a width and \a truncate is TRUE, + then the returned string is a left(\a width). + + Example: + \code + QString s("apple"); + QString t = s.leftJustify(8, '.'); // t == "apple..." + \endcode + + \sa rightJustify() +*/ + +QString QString::leftJustify( uint width, QChar fill, bool truncate ) const +{ + QString result; + int len = length(); + int padlen = width - len; + if ( padlen > 0 ) { + result.setLength(len+padlen); + if ( len ) + memcpy( result.d->unicode, unicode(), sizeof(QChar)*len ); + QChar* uc = result.d->unicode + len; + while (padlen--) + *uc++ = fill; + } else { + if ( truncate ) + result = left( width ); + else + result = *this; + } + return result; +} + +/*! + Returns a string of length \a width that contains pad + characters followed by the string. + + If the length of the string exceeds \a width and \a truncate is FALSE, + then the returned string is a copy of the string. + If the length of the string exceeds \a width and \a truncate is TRUE, + then the returned string is a left(\a width). + + Example: + \code + QString s("pie"); + QString t = s.rightJustify(8, '.'); // t == ".....pie" + \endcode + + \sa leftJustify() +*/ + +QString QString::rightJustify( uint width, QChar fill, bool truncate ) const +{ + QString result; + int len = length(); + int padlen = width - len; + if ( padlen > 0 ) { + result.setLength( len+padlen ); + QChar* uc = result.d->unicode; + while (padlen--) + *uc++ = fill; + if ( len ) + memcpy( uc, unicode(), sizeof(QChar)*len ); + } else { + if ( truncate ) + result = left( width ); + else + result = *this; + } + return result; +} + +/*! + Returns a new string that is the string converted to lower case. + + Example: + \code + QString s("TeX"); + QString t = s.lower(); // t == "tex" + \endcode + + \sa upper() +*/ + +QString QString::lower() const +{ + QString s(*this); + int l=length(); + if ( l ) { + s.real_detach(); // could do this only when we find a change + register QChar *p=s.d->unicode; + if ( p ) { + while ( l-- ) { + *p = p->lower(); + p++; + } + } + } + return s; +} + +/*! + Returns a new string that is the string converted to upper case. + + Example: + \code + QString s("TeX"); + QString t = s.upper(); // t == "TEX" + \endcode + + \sa lower() +*/ + +QString QString::upper() const +{ + QString s(*this); + int l=length(); + if ( l ) { + s.real_detach(); // could do this only when we find a change + register QChar *p=s.d->unicode; + if ( p ) { + while ( l-- ) { + *p = p->upper(); + p++; + } + } + } + return s; +} + + +/*! + Returns a new string that has white space removed from the start and the end. + + White space means any character for which QChar::isSpace() returns + TRUE. This includes ASCII characters 9 (TAB), 10 (LF), 11 (VT), 12 + (FF), 13 (CR), and 32 (Space). + + Example: + \code + QString s = " space "; + QString t = s.stripWhiteSpace(); // t == "space" + \endcode + + \sa simplifyWhiteSpace() +*/ + +QString QString::stripWhiteSpace() const +{ + if ( isEmpty() ) // nothing to do + return *this; + if ( !at(0).isSpace() && !at(length()-1).isSpace() ) + return *this; + + register const QChar *s = unicode(); + QString result = fromLatin1(""); + + int start = 0; + int end = length() - 1; + while ( start<=end && s[start].isSpace() ) // skip white space from start + start++; + if ( start > end ) { // only white space + return result; + } + while ( end && s[end].isSpace() ) // skip white space from end + end--; + int l = end - start + 1; + result.setLength( l ); + if ( l ) + memcpy( result.d->unicode, &s[start], sizeof(QChar)*l ); + return result; +} + + +/*! + Returns a new string that has white space removed from the start and the end, + plus any sequence of internal white space replaced with a single space + (ASCII 32). + + White space means any character for which QChar::isSpace() returns + TRUE. This includes ASCII characters 9 (TAB), 10 (LF), 11 (VT), 12 + (FF), 13 (CR), and 32 (Space). + + \code + QString s = " lots\t of\nwhite space "; + QString t = s.simplifyWhiteSpace(); // t == "lots of white space" + \endcode + + \sa stripWhiteSpace() +*/ + +QString QString::simplifyWhiteSpace() const +{ + if ( isEmpty() ) // nothing to do + return *this; + QString result; + result.setLength( length() ); + const QChar *from = unicode(); + const QChar *fromend = from+length(); + int outc=0; + QChar *to = result.d->unicode; + while ( TRUE ) { + while ( from!=fromend && from->isSpace() ) + from++; + while ( from!=fromend && !from->isSpace() ) + to[outc++] = *from++; + if ( from!=fromend ) + to[outc++] = ' '; + else + break; + } + if ( outc > 0 && to[outc-1] == ' ' ) + outc--; + result.truncate( outc ); + return result; +} + + +/*! + Insert \a s into the string before position \a index. + + If \a index is beyond the end of the string, the string is extended with + spaces (ASCII 32) to length \a index and \a s is then appended. + + \code + QString s = "I like fish"; + s.insert( 2, "don't "); // s == "I don't like fish" + s = "x"; + s.insert( 3, "yz" ); // s == "x yz" + \endcode +*/ + +QString &QString::insert( uint index, const QString &s ) +{ + // the sub function takes care of &s == this case. + return insert( index, s.unicode(), s.length() ); +} + +/*! + Insert \a len units of QChar data from \a s into the string before + position \a index. +*/ + +QString &QString::insert( uint index, const QChar* s, uint len ) +{ + if ( len == 0 ) + return *this; + uint olen = length(); + int nlen = olen + len; + + int df = s - d->unicode; // ### pointer subtraction, cast down to int + if ( df >= 0 && (uint)df < d->maxl ) { + // Part of me - take a copy. + QChar *tmp = QT_ALLOC_QCHAR_VEC( len ); + memcpy(tmp,s,len*sizeof(QChar)); + insert(index,tmp,len); + QT_DELETE_QCHAR_VEC( tmp ); + return *this; + } + + if ( index >= olen ) { // insert after end of string + setLength( len+index ); + int n = index-olen; + QChar* uc = d->unicode+olen; + while (n--) + *uc++ = ' '; + memcpy( d->unicode+index, s, sizeof(QChar)*len ); + } else { // normal insert + setLength( nlen ); + memmove( d->unicode+index+len, unicode()+index, + sizeof(QChar)*(olen-index) ); + memcpy( d->unicode+index, s, sizeof(QChar)*len ); + } + return *this; +} + +/*! + Insert \a c into the string at (before) position \a index and returns + a reference to the string. + + If \a index is beyond the end of the string, the string is extended with + spaces (ASCII 32) to length \a index and \a c is then appended. + + Example: + \code + QString s = "Ys"; + s.insert( 1, 'e' ); // s == "Yes" + s.insert( 3, '!'); // s == "Yes!" + \endcode + + \sa remove(), replace() +*/ + +QString &QString::insert( uint index, QChar c ) // insert char +{ + QString s( c ); + return insert( index, s ); +} + +/*! + \overload QString& QString::insert( uint index, char c ) +*/ + +/*! + \fn QString &QString::prepend( const QString &s ) + + Prepend \a s to the string. Equivalent to insert(0,s). + + \sa insert() +*/ + +/*! + \fn QString& QString::prepend( char ch ) + Prepends \a ch to the string and returns a reference to the result. + + \sa insert() + */ + +/*! + \fn QString& QString::prepend( QChar ch ) + Prepends \a ch to the string and returns a reference to the result. + + \sa insert() + */ + + +/*! + Removes \a len characters starting at position \a index from the + string and returns a reference to the string. + + If \a index is too big, nothing happens. If \a index is valid, but + \a len is too large, the rest of the string is removed. + + \code + QString s = "Montreal"; + s.remove( 1, 4 ); + // s == "Meal" + \endcode + + \sa insert(), replace() +*/ + +QString &QString::remove( uint index, uint len ) +{ + uint olen = length(); + if ( index + len >= olen ) { // range problems + if ( index < olen ) { // index ok + setLength( index ); + } + } else if ( len != 0 ) { + real_detach(); + memmove( d->unicode+index, d->unicode+index+len, + sizeof(QChar)*(olen-index-len) ); + setLength( olen-len ); + } + return *this; +} + +/*! + Replaces \a len characters starting at position \a index from the + string with \a s, and returns a reference to the string. + + If \a index is too big, nothing is deleted and \a s is inserted at the + end of the string. If \a index is valid, but \a len is too large, \e + str replaces the rest of the string. + + \code + QString s = "Say yes!"; + s.replace( 4, 3, "NO" ); // s == "Say NO!" + \endcode + + \sa insert(), remove() +*/ + +QString &QString::replace( uint index, uint len, const QString &s ) +{ + return replace( index, len, s.unicode(), s.length() ); +} + + +/*! + Replaces \a len characters starting at position \a index by + \a slen units ot QChar data from \a s, and returns a reference to the string. + + \sa insert(), remove() +*/ + +QString &QString::replace( uint index, uint len, const QChar* s, uint slen ) +{ + if ( len == slen && index + len <= length() ) { + // Optimized common case: replace without size change + real_detach(); + memcpy( d->unicode+index, s, len*sizeof(QChar) ); + } else { + int df = s - d->unicode; // ### pointer subtraction, cast down to int + if ( df >= 0 && (uint)df < d->maxl ) { + // Part of me - take a copy. + QChar *tmp = QT_ALLOC_QCHAR_VEC( slen ); + memcpy(tmp,s,slen*sizeof(QChar)); + replace(index,len,tmp,slen); + QT_DELETE_QCHAR_VEC( tmp ); + return *this; + } + + remove( index, len ); + insert( index, s, slen ); + } + return *this; +} + + + +/*! + Finds the first occurrence of the regular expression \a rx, starting at + position \a index. If \a index is -1, the search starts at the last + character; if -2, at the next to last character; etc. + + Returns the position of the next match, or -1 if \a rx was not found. + + \sa findRev() replace() contains() +*/ + +int QString::find( const QRegExp &rx, int index ) const +{ + if ( index < 0 ) + index += length(); + return rx.match( data(), index ); +} + +/*! + Finds the first occurrence of the regular expression \a rx, starting at + position \a index and searching backwards. If \a index is -1, the + search starts at the last character; if -2, at the next to last + character; etc. + + Returns the position of the next match (backwards), or -1 if \a rx was not + found. + + \sa find() +*/ + +int QString::findRev( const QRegExp &rx, int index ) const +{ + if ( index < 0 ) // neg index ==> start from end + index += length(); + if ( (uint)index > length() ) // bad index + return -1; + while( index >= 0 ) { + if ( rx.match( data(), index ) == index ) + return index; + index--; + } + return -1; +} + +/*! + Counts the number of overlapping occurrences of \a rx in the string. + + Example: + \code + QString s = "banana and panama"; + QRegExp r = QRegExp("a[nm]a", TRUE, FALSE); + s.contains( r ); // 4 matches + \endcode + + \sa find() findRev() +*/ + +int QString::contains( const QRegExp &rx ) const +{ + if ( isEmpty() ) + return rx.match( data() ) < 0 ? 0 : 1; + int count = 0; + int index = -1; + int len = length(); + while ( index < len-1 ) { // count overlapping matches + index = rx.match( data(), index+1 ); + if ( index < 0 ) + break; + count++; + } + return count; +} + + +/*! + Replaces every occurrence of \a rx in the string with \a str. + Returns a reference to the string. + + Examples: + \code + QString s = "banana"; + s.replace( QRegExp("a.*a"), "" ); // becomes "b" + + QString s = "banana"; + s.replace( QRegExp("^[bn]a"), " " ); // becomes " nana" + + QString s = "banana"; + s.replace( QRegExp("^[bn]a"), "" ); // NOTE! becomes "" + \endcode + + \sa find() findRev() +*/ + +QString &QString::replace( const QRegExp &rx, const QString &str ) +{ + if ( isEmpty() ) + return *this; + int index = 0; + int slen = str.length(); + int len; + while ( index < (int)length() ) { + index = rx.match( data(), index, &len, FALSE ); + if ( index >= 0 ) { + replace( index, len, str ); + index += slen; + if ( !len ) + break; // Avoid infinite loop on 0-length matches, e.g. [a-z]* + } + else + break; + } + return *this; +} + +static bool +ok_in_base( QChar c, int base ) +{ + if ( base <= 10 ) + return c.isDigit() && c.digitValue() < base; + else + return c.isDigit() || (c >= 'a' && c < char('a'+base-10)) + || (c >= 'A' && c < char('A'+base-10)); +} + +/*! + Returns the string converted to a <code>long</code> value. + + If \a ok is non-null, \a *ok is set to TRUE if there are no + conceivable errors, and FALSE if the string is not a number at all, or if + it has trailing garbage. +*/ + +long QString::toLong( bool *ok, int base ) const +{ + const QChar *p = unicode(); + long val=0; + int l = length(); + const long max_mult = INT_MAX / base; + bool is_ok = FALSE; + int neg = 0; + if ( !p ) + goto bye; + while ( l && p->isSpace() ) // skip leading space + l--,p++; + if ( l && *p == '-' ) { + l--; + p++; + neg = 1; + } else if ( *p == '+' ) { + l--; + p++; + } + + // NOTE: toULong() code is similar + if ( !l || !ok_in_base(*p,base) ) + goto bye; + while ( l && ok_in_base(*p,base) ) { + l--; + int dv; + if ( p->isDigit() ) { + dv = p->digitValue(); + } else { + if ( *p >= 'a' && *p <= 'z' ) + dv = *p - 'a' + 10; + else + dv = *p - 'A' + 10; + } + if ( val > max_mult || (val == max_mult && dv > (INT_MAX%base)+neg) ) + goto bye; + val = base*val + dv; + p++; + } + if ( neg ) + val = -val; + while ( l && p->isSpace() ) // skip trailing space + l--,p++; + if ( !l ) + is_ok = TRUE; +bye: + if ( ok ) + *ok = is_ok; + return is_ok ? val : 0; +} + +/*! + Returns the string converted to an <code>unsigned long</code> + value. + + If \a ok is non-null, \a *ok is set to TRUE if there are no + conceivable errors, and FALSE if the string is not a number at all, + or if it has trailing garbage. +*/ + +ulong QString::toULong( bool *ok, int base ) const +{ + const QChar *p = unicode(); + ulong val=0; + int l = length(); + const ulong max_mult = 429496729; // UINT_MAX/10, rounded down + bool is_ok = FALSE; + if ( !p ) + goto bye; + while ( l && p->isSpace() ) // skip leading space + l--,p++; + if ( *p == '+' ) + l--,p++; + + // NOTE: toLong() code is similar + if ( !l || !ok_in_base(*p,base) ) + goto bye; + while ( l && ok_in_base(*p,base) ) { + l--; + uint dv; + if ( p->isDigit() ) { + dv = p->digitValue(); + } else { + if ( *p >= 'a' && *p <= 'z' ) + dv = *p - 'a' + 10; + else + dv = *p - 'A' + 10; + } + if ( val > max_mult || (val == max_mult && dv > (UINT_MAX%base)) ) + goto bye; + val = base*val + dv; + p++; + } + + while ( l && p->isSpace() ) // skip trailing space + l--,p++; + if ( !l ) + is_ok = TRUE; +bye: + if ( ok ) + *ok = is_ok; + return is_ok ? val : 0; +} + +/*! + Returns the string converted to a <code>short</code> value. + + If \a ok is non-null, \a *ok is set to TRUE if there are no + conceivable errors, and FALSE if the string is not a number at all, or if + it has trailing garbage. +*/ + +short QString::toShort( bool *ok, int base ) const +{ + long v = toLong( ok, base ); + if ( ok && *ok && (v < -32768 || v > 32767) ) { + *ok = FALSE; + v = 0; + } + return (short)v; +} + +/*! + Returns the string converted to an <code>unsigned short</code> value. + + If \a ok is non-null, \a *ok is set to TRUE if there are no + conceivable errors, and FALSE if the string is not a number at all, or if + it has trailing garbage. +*/ + +ushort QString::toUShort( bool *ok, int base ) const +{ + ulong v = toULong( ok, base ); + if ( ok && *ok && (v > 65535) ) { + *ok = FALSE; + v = 0; + } + return (ushort)v; +} + + +/*! + Returns the string converted to a <code>int</code> value. + + \code + QString str("FF"); + bool ok; + int hex = str.toInt( &ok, 16 ); // will return 255, and ok set to TRUE + int dec = str.toInt( &ok, 10 ); // will return 0, and ok set to FALSE + \endcode + + If \a ok is non-null, \a *ok is set to TRUE if there are no + conceivable errors, and FALSE if the string is not a number at all, + or if it has trailing garbage. +*/ + +int QString::toInt( bool *ok, int base ) const +{ + return (int)toLong( ok, base ); +} + +/*! + Returns the string converted to an <code>unsigned int</code> value. + + If \a ok is non-null, \a *ok is set to TRUE if there are no + conceivable errors, and FALSE if the string is not a number at all, + or if it has trailing garbage. +*/ + +uint QString::toUInt( bool *ok, int base ) const +{ + return (uint)toULong( ok, base ); +} + +/*! + Returns the string converted to a <code>double</code> value. + + If \a ok is non-null, \a *ok is set to TRUE if there are no conceivable + errors, and FALSE if the string is not a number at all, or if it has + trailing garbage. +*/ + +double QString::toDouble( bool *ok ) const +{ + char *end; + + QCString a = latin1(); + // Just latin1() is not sufficient, since U0131 would look like '1'. + for (uint i=0; i<d->len; i++) + if ( d->unicode[i].row() ) + a[(int)i]='z'; + + double val = strtod( a.data() ? a.data() : "", &end ); + if ( ok ) + *ok = ( a && *a && ( end == 0 || *end == '\0' ) ); + return val; +} + +/*! + Returns the string converted to a <code>float</code> value. + + If \a ok is non-null, \a *ok is set to TRUE if there are no + conceivable errors, and FALSE if the string is not a number at all, + or if it has trailing garbage. +*/ + +float QString::toFloat( bool *ok ) const +{ + return (float)toDouble( ok ); +} + + +/*! + Sets the string to the printed value of \a n and returns a + reference to the string. + + The value is converted to \a base notation (default is decimal). + The base must be a value from 2 to 36. +*/ + +QString &QString::setNum( long n, int base ) +{ +#if defined(CHECK_RANGE) + if ( base < 2 || base > 36 ) { + qWarning( "QString::setNum: Invalid base %d", base ); + base = 10; + } +#endif + char charbuf[65*sizeof(QChar)]; + QChar *buf = (QChar*)charbuf; + QChar *p = &buf[64]; + int len = 0; + bool neg; + if ( n < 0 ) { + neg = TRUE; + if ( n == INT_MIN ) { + // Cannot always negate this special case + QString s1, s2; + s1.setNum(n/base); + s2.setNum((-(n+base))%base); + *this = s1 + s2; + return *this; + } + n = -n; + } else { + neg = FALSE; + } + do { + *--p = "0123456789abcdefghijklmnopqrstuvwxyz"[((int)(n%base))]; + n /= base; + len++; + } while ( n ); + if ( neg ) { + *--p = '-'; + len++; + } + return setUnicode( p, len ); +} + +/*! + Sets the string to the printed unsigned value of \a n and + returns a reference to the string. + + The value is converted to \a base notation (default is decimal). + The base must be a value from 2 to 36. +*/ + +QString &QString::setNum( ulong n, int base ) +{ +#if defined(CHECK_RANGE) + if ( base < 2 || base > 36 ) { + qWarning( "QString::setNum: Invalid base %d", base ); + base = 10; + } +#endif + char charbuf[65*sizeof(QChar)]; + QChar *buf = (QChar*)charbuf; + QChar *p = &buf[64]; + int len = 0; + do { + *--p = "0123456789abcdefghijklmnopqrstuvwxyz"[((int)(n%base))]; + n /= base; + len++; + } while ( n ); + return setUnicode(p,len); +} + +/*! + \fn QString &QString::setNum( int n, int base ) + Sets the string to the printed value of \a n and returns a reference + to the string. +*/ + +/*! + \fn QString &QString::setNum( uint n, int base ) + Sets the string to the printed unsigned value of \a n and returns a + reference to the string. +*/ + +/*! + \fn QString &QString::setNum( short n, int base ) + Sets the string to the printed value of \a n and returns a reference + to the string. +*/ + +/*! + \fn QString &QString::setNum( ushort n, int base ) + Sets the string to the printed unsigned value of \a n and returns a + reference to the string. +*/ + +/*! Sets the string to the printed value of \a n, formatted in the \a f + format with \a prec precision, and returns a reference to the + string. + + \a f can be 'f', 'F', 'e', 'E', 'g' or 'G', all of which have the + same meaning as for sprintf(). +*/ + +QString &QString::setNum( double n, char f, int prec ) +{ +#if defined(CHECK_RANGE) + if ( !(f=='f' || f=='F' || f=='e' || f=='E' || f=='g' || f=='G') ) { + qWarning( "QString::setNum: Invalid format char '%c'", f ); + f = 'f'; + } +#endif + char format[20]; + char buf[120]; // enough for 99 precision? + char *fs = format; // generate format string + *fs++ = '%'; // "%.<prec>l<f>" + if ( prec >= 0 ) { + if ( prec > 99 ) // buf big enough for precision? + prec = 99; + *fs++ = '.'; + if ( prec >= 10 ) { + *fs++ = prec / 10 + '0'; + *fs++ = prec % 10 + '0'; + } else { + *fs++ = prec + '0'; + } + } + *fs++ = 'l'; + *fs++ = f; + *fs = '\0'; + ::sprintf( buf, format, n ); + return setLatin1(buf); +} + +/*! + \overload QString &QString::setNum( float n, char f, int prec ) +*/ + + +/*! + A convenience factory function that returns a string representation + of the number \a n. + + \sa setNum() + */ +QString QString::number( long n, int base ) +{ + QString s; + s.setNum( n, base ); + return s; +} + +/*! + A convenience factory function that returns a string representation + of the number \a n. + + \sa setNum() + */ +QString QString::number( ulong n, int base ) +{ + QString s; + s.setNum( n, base ); + return s; +} + +/*! + A convenience factory function that returns a string representation + of the number \a n. + + \sa setNum() + */ +QString QString::number( int n, int base ) +{ + QString s; + s.setNum( n, base ); + return s; +} + +/*! + A convenience factory function that returns a string representation + of the number \a n. + + \sa setNum() + */ +QString QString::number( uint n, int base ) +{ + QString s; + s.setNum( n, base ); + return s; +} + +/*! + This static function returns the printed value of \a n, formatted in the + \a f format with \a prec precision. + + \a f can be 'f', 'F', 'e', 'E', 'g' or 'G', all of which have the + same meaning as for sprintf(). + + \sa setNum() + */ +QString QString::number( double n, char f, int prec ) +{ + QString s; + s.setNum( n, f, prec ); + return s; +} + + +/*! \obsolete + + Sets the character at position \a index to \a c and expands the + string if necessary, filling with spaces. + + This method is redundant in Qt 2.x, because operator[] will expand + the string as necessary. +*/ + +void QString::setExpand( uint index, QChar c ) +{ + int spaces = index - d->len; + at(index) = c; + while (spaces-->0) + d->unicode[--index]=' '; +} + + +/*! + \fn const char* QString::data() const + + \obsolete + + Returns a pointer to a 0-terminated classic C string. + + In Qt 1.x, this returned a char* allowing direct manipulation of the + string as a sequence of bytes. In Qt 2.x where QString is a Unicode + string, char* conversion constructs a temporary string, and hence + direct character operations are meaningless. +*/ + +/*! + \fn bool QString::operator!() const + Returns TRUE if it is a null string, otherwise FALSE. Thus + you can write: + +\code + QString name = getName(); + if ( !name ) + name = "Rodney"; +\endcode + + Note that if you say: + +\code + QString name = getName(); + if ( name ) + doSomethingWith(name); +\endcode + + Then this will call <tt>operator const char*()</tt>, which will do what + you want, but rather inefficiently - you may wish to define the macro + QT_NO_ASCII_CAST when writing code which you wish to strictly remain + Unicode-clean. + + When you want the above semantics, use <tt>!isNull()</tt> + or even <tt>!!</tt>: + +\code + QString name = getName(); + if ( !!name ) + doSomethingWith(name); +\endcode +*/ + + +/*! + \fn QString& QString::append( const QString& str ) + Appends \a str to the string and returns a reference to the result. + Equivalent to operator+=(). + */ + +/*! + \fn QString& QString::append( char ch ) + Appends \a ch to the string and returns a reference to the result. + Equivalent to operator+=(). + */ + +/*! + \fn QString& QString::append( QChar ch ) + Appends \a ch to the string and returns a reference to the result. + Equivalent to operator+=(). + */ + +/*! + Appends \a str to the string and returns a reference to the string. +*/ +QString& QString::operator+=( const QString &str ) +{ + uint len1 = length(); + uint len2 = str.length(); + if ( len2 ) { + setLength(len1+len2); + memcpy( d->unicode+len1, str.unicode(), sizeof(QChar)*len2 ); + } else if ( isNull() && !str.isNull() ) { // ## just for 1.x compat: + *this = fromLatin1(""); + } + return *this; +} + +/*! + Appends \a c to the string and returns a reference to the string. +*/ + +QString &QString::operator+=( QChar c ) +{ + setLength(length()+1); + d->unicode[length()-1] = c; + return *this; +} + +/*! + Appends \a c to the string and returns a reference to the string. +*/ + +QString &QString::operator+=( char c ) +{ + setLength(length()+1); + d->unicode[length()-1] = c; + return *this; +} + + + +/*! \fn char QChar::latin1() const + + Returns a latin-1 copy of this character, if this character is in + the latin-1 character set. If not, this function returns 0. +*/ + + +/*! + Returns a Latin-1 representation of the string. Note that the returned + value is undefined if the string contains non-Latin-1 characters. If you + want to convert strings into formats other than Unicode, see the + QTextCodec classes. + + This function is mainly useful for boot-strapping legacy code to + use Unicode. + + The result remains valid so long as one unmodified + copy of the source string exists. + + \sa utf8(), local8Bit() +*/ +const char* QString::latin1() const +{ + if ( d->ascii ) { + if ( d->dirtyascii ) + delete [] d->ascii; + else + return d->ascii; + } + Q2HELPER(stat_get_ascii++) + Q2HELPER(stat_get_ascii_size+=d->len) + static QTextCodec* codec = QTextCodec::codecForMib(106); + if (codec) // we use utf8 coding also for latin1 if possible + { + QCString utf8str(codec->fromUnicode(*this)); + d->ascii = new char[utf8str.length()+1]; + if (utf8str.isEmpty()) + { + d->ascii[0]='\0'; // make empty string + } + else // copy string + { + qstrcpy(d->ascii,utf8str.data()); + } + } + else // fall back to latin1 + { + d->ascii = unicodeToAscii( d->unicode, d->len ); + } + QCString utf8str(utf8()); + d->dirtyascii = 0; + return d->ascii; +} + +/*! \obsolete + + This functions simply calls latin1() and returns the result. +*/ +const char* QString::ascii() const +{ + return latin1(); +} + +#ifndef QT_NO_TEXTCODEC +/*! + Returns the string encoded in UTF8 format. + + See QTextCodec for more diverse coding/decoding of Unicode strings. + + \sa QString::fromUtf8(), local8Bit(), latin1() +*/ +QCString QString::utf8() const +{ + static QTextCodec* codec = QTextCodec::codecForMib(106); + return codec + ? codec->fromUnicode(*this) + : QCString(latin1()); +} + +/*! + Returns the unicode string decoded from the + first \a len bytes of \a utf8. If \a len is -1 (the default), the + length of \a utf8 is used. If trailing partial characters are in + \a utf8, they are ignored. + + See QTextCodec for more diverse coding/decoding of Unicode strings. +*/ +QString QString::fromUtf8(const char* utf8, int len) +{ + static QTextCodec* codec = QTextCodec::codecForMib(106); + if ( len < 0 ) len = qstrlen(utf8); + return codec + ? codec->toUnicode(utf8, len) + : QString::fromLatin1(utf8, len); +} +#endif // QT_NO_TEXTCODEC +/*! + Creates a QString from Latin1 text. This is the same as the + QString(const char*) constructor, but you can make that constructor + invisible if you compile with the define QT_NO_CAST_ASCII, in which + case you can explicitly create a QString from Latin-1 text using + this function. +*/ +QString QString::fromLatin1(const char* chars, int len) +{ + uint l; + QChar *uc; + if ( len < 0 ) { + uc = internalAsciiToUnicode(chars,&l); + } else { + uc = internalAsciiToUnicode(chars,&l,len); + } + return QString(new QStringData(uc,l,l), TRUE); +} + +/*! + \fn const QChar* QString::unicode() const + + Returns the Unicode representation of the string. The result + remains valid until the string is modified. +*/ + +/*! + Returns the string encoded in a locale-specific format. On X11, this + is the QTextCodec::codecForLocale(). On Windows, it is a system-defined + encoding. + + See QTextCodec for more diverse coding/decoding of Unicode strings. + + \sa QString::fromLocal8Bit(), latin1(), utf8() +*/ + + +QCString QString::local8Bit() const +{ +#ifdef QT_NO_TEXTCODEC + return latin1(); +#else +#ifdef _WS_X11_ + static QTextCodec* codec = QTextCodec::codecForLocale(); + return codec + ? codec->fromUnicode(*this) + : QCString(latin1()); +#endif +#ifdef _WS_MAC_ + static QTextCodec* codec = QTextCodec::codecForLocale(); + return codec + ? codec->fromUnicode(*this) + : QCString(latin1()); +#endif +#ifdef _WS_WIN_ + return qt_winQString2MB( *this ); +#endif +#ifdef _WS_QWS_ + return utf8(); // ##### if there is ANY 8 bit format supported? +#endif +#endif +} + +/*! + Returns the unicode string decoded from the + first \a len bytes of \a local8Bit. If \a len is -1 (the default), the + length of \a local8Bit is used. If trailing partial characters are in + \a local8Bit, they are ignored. + + \a local8Bit is assumed to be encoded in a locale-specific format. + + See QTextCodec for more diverse coding/decoding of Unicode strings. +*/ +QString QString::fromLocal8Bit(const char* local8Bit, int len) +{ +#ifdef QT_NO_TEXTCODEC + return fromLatin1( local8Bit, len ); +#else + + if ( !local8Bit ) + return QString::null; +#ifdef _WS_X11_ + static QTextCodec* codec = QTextCodec::codecForLocale(); + if ( len < 0 ) len = qstrlen(local8Bit); + return codec + ? codec->toUnicode(local8Bit, len) + : QString::fromLatin1(local8Bit,len); +#endif +#ifdef _WS_MAC_ + static QTextCodec* codec = QTextCodec::codecForLocale(); + if ( len < 0 ) len = qstrlen(local8Bit); + return codec + ? codec->toUnicode(local8Bit, len) + : QString::fromLatin1(local8Bit,len); +#endif +// Should this be OS_WIN32? +#ifdef _WS_WIN_ + if ( len >= 0 ) { + QCString s(local8Bit,len+1); + return qt_winMB2QString(s); + } + return qt_winMB2QString( local8Bit ); +#endif +#ifdef _WS_QWS_ + return fromUtf8(local8Bit,len); +#endif +#endif // QT_NO_TEXTCODEC +} + +/*! + \fn QString::operator const char *() const + + Returns latin1(). Be sure to see the warnings documented there. + Note that for new code which you wish to be strictly Unicode-clean, + you can define the macro QT_NO_ASCII_CAST when compiling your code + to hide this function so that automatic casts are not done. This + has the added advantage that you catch the programming error + described under operator!(). +*/ + +/*! + \fn QChar QString::at( uint ) const + + Returns the character at \a i, or 0 if \a i is beyond the length + of the string. + + Note: If this QString is not const or const&, the non-const at() + will be used instead, which will expand the string if \a i is beyond + the length of the string. +*/ + +/*! + \fn QChar QString::constref(uint i) const + Equivalent to at(i), this returns the QChar at \a i by value. + + \sa ref() +*/ + +/*! + \fn QChar& QString::ref(uint i) + Returns the QChar at \a i by reference. + + \sa constref() +*/ + +/*! + \fn QChar QString::operator[](int) const + + Returns the character at \a i, or QChar::null if \a i is beyond the + length of the string. + + Note: If this QString is not const or const&, the non-const operator[] + will be used instead, which will expand the string if \a i is beyond + the length of the string. +*/ + +/*! + \fn QCharRef QString::operator[](int) + + Returns an object that references the character at \a i. + This reference + can then be assigned to, or otherwise used immediately, but + becomes invalid once further modifications are made to the string. + The QCharRef internal class can be used much like a constant QChar, but + if you assign to it, you change the original string (which enlarges + and detaches itself). You will get compilation errors if you try to + use the result as anything but a QChar. +*/ + +/*! + \fn QCharRef QString::at( uint i ) + Returns a reference to the character at \a i, expanding + the string with QChar::null if necessary. The resulting reference + can then be assigned to, or otherwise used immediately, but + becomes invalid once further modifications are made to the string. +*/ + +/*! + Internal chunk of code to handle the + uncommon cases of at() above. +*/ +void QString::subat( uint i ) +{ + uint olen = d->len; + if ( i >= olen ) { + setLength( i+1 ); // i is index; i+1 is needed length + for ( uint j=olen; j<=i; j++ ) + d->unicode[j] = QChar::null; + } else { + // Just be sure to detach + real_detach(); + } +} + + +/*! + Resizes the string to \a len unicode characters and copies \a unicode + into the string. If \a unicode is null, nothing is copied, but the + string is resized to \a len anyway. If \a len is zero, the string + becomes a \link isNull() null\endlink string. + + \sa setLatin1(), isNull() +*/ + +QString& QString::setUnicode( const QChar *unicode, uint len ) +{ + if ( len == 0 ) { // set to null string + if ( d != shared_null ) { // beware of nullstring being set to nullstring + deref(); + d = shared_null ? shared_null : makeSharedNull(); + d->ref(); + } + } else if ( d->count != 1 || len > d->maxl || + ( len*4 < d->maxl && d->maxl > 4 ) ) { // detach, grown or shrink + Q2HELPER(stat_copy_on_write++) + Q2HELPER(stat_copy_on_write_size+=d->len) + uint newMax = 4; + while ( newMax < len ) + newMax *= 2; + QChar* nd = QT_ALLOC_QCHAR_VEC( newMax ); + if ( unicode ) + memcpy( nd, unicode, sizeof(QChar)*len ); + deref(); + d = new QStringData( nd, len, newMax ); + } else { + d->len = len; + d->dirtyascii = 1; + if ( unicode ) + memcpy( d->unicode, unicode, sizeof(QChar)*len ); + } + return *this; +} + +/*! + Resizes the string to \a len unicode characters and copies + \a unicode_as_ushorts into the string (on some X11 client + platforms this will involve a byte-swapping pass). + + If \a unicode is null, nothing is copied, but the + string is resized to \a len anyway. If \a len is zero, the string + becomes a \link isNull() null\endlink string. + + \sa setLatin1(), isNull() +*/ +QString& QString::setUnicodeCodes( const ushort* unicode_as_ushorts, uint len ) +{ + setUnicode((const QChar*)unicode_as_ushorts, len); + QChar t(0x1234); + if ( unicode_as_ushorts && *((ushort*)&t) == 0x3412 ) { + // Need to byteswap + char* b = (char*)d->unicode; + while ( len-- ) { + char c = b[0]; + b[0] = b[1]; + b[1] = c; + b += sizeof(QChar); + } + } + return *this; +} + + +/*! + Sets this string to \a str, interpreted as a classic Latin 1 C string. + If the \a len argument is negative (default), it is set to strlen(str). + + If \a str is 0 a null string is created. If \a str is "" an empty + string is created. + + \sa isNull(), isEmpty() +*/ + +QString &QString::setLatin1( const char *str, int len ) +{ + if ( str == 0 ) + return setUnicode(0,0); + if ( len < 0 ) + len = qstrlen(str); + if ( len == 0 ) { // won't make a null string + deref(); + uint l; + QChar *uc = internalAsciiToUnicode(str,&l); + d = new QStringData(uc,l,l); + } else { + setUnicode( 0, len ); // resize but not copy + QChar *p = d->unicode; + while ( len-- ) + *p++ = *str++; + } + return *this; +} + + +/*! + \fn int QString::compare (const QString & s1, const QString & s2) + + Compare \a s1 to \a s2 returning an integer less than, equal to, or + greater than zero if s1 is, respectively, lexically less than, equal to, + or greater than s2. +*/ + +/*! + Compares this string to \a s, returning an integer less than, equal to, or + greater than zero if it is, respectively, lexically less than, equal to, + or greater than \a s. +*/ +int QString::compare( const QString& s ) const +{ + return ucstrcmp(*this,s); +} + +bool operator==( const QString &s1, const QString &s2 ) +{ + return (s1.length() == s2.length()) && s1.isNull() == s2.isNull() && + (memcmp((char*)s1.unicode(),(char*)s2.unicode(), + s1.length()*sizeof(QChar)) ==0); +} + +bool operator!=( const QString &s1, const QString &s2 ) +{ return !(s1==s2); } + +bool operator<( const QString &s1, const QString &s2 ) +{ return ucstrcmp(s1,s2) < 0; } + +bool operator<=( const QString &s1, const QString &s2 ) +{ return ucstrcmp(s1,s2) <= 0; } + +bool operator>( const QString &s1, const QString &s2 ) +{ return ucstrcmp(s1,s2) > 0; } + +bool operator>=( const QString &s1, const QString &s2 ) +{ return ucstrcmp(s1,s2) >= 0; } + + +bool operator==( const QString &s1, const char *s2 ) +{ return s1==QString(s2); } + +bool operator==( const char *s1, const QString &s2 ) +{ return QString(s1)==s2; } + +bool operator!=( const QString &s1, const char *s2 ) +{ return !(s1==s2); } + +bool operator!=( const char *s1, const QString &s2 ) +{ return !(s1==s2); } + +bool operator<( const QString &s1, const char *s2 ) +{ return ucstrcmp(s1,s2) < 0; } + +bool operator<( const char *s1, const QString &s2 ) +{ return ucstrcmp(s1,s2) < 0; } + +bool operator<=( const QString &s1, const char *s2 ) +{ return ucstrcmp(s1,s2) <= 0; } + +bool operator<=( const char *s1, const QString &s2 ) +{ return ucstrcmp(s1,s2) <= 0; } + +bool operator>( const QString &s1, const char *s2 ) +{ return ucstrcmp(s1,s2) > 0; } + +bool operator>( const char *s1, const QString &s2 ) +{ return ucstrcmp(s1,s2) > 0; } + +bool operator>=( const QString &s1, const char *s2 ) +{ return ucstrcmp(s1,s2) >= 0; } + +bool operator>=( const char *s1, const QString &s2 ) +{ return ucstrcmp(s1,s2) >= 0; } + + +/***************************************************************************** + Documentation for QString related functions + *****************************************************************************/ + +/*! + \fn bool operator==( const QString &s1, const QString &s2 ) + \relates QString + Returns TRUE if the two strings are equal, or FALSE if they are different. + A null string is different from an empty, non-null string. + + Equivalent to <code>qstrcmp(s1,s2) == 0</code>. +*/ + +/*! + \fn bool operator==( const QString &s1, const char *s2 ) + \relates QString + Returns TRUE if the two strings are equal, or FALSE if they are different. + + Equivalent to <code>qstrcmp(s1,s2) == 0</code>. +*/ + +/*! + \fn bool operator==( const char *s1, const QString &s2 ) + \relates QString + Returns TRUE if the two strings are equal, or FALSE if they are different. + + Equivalent to <code>qstrcmp(s1,s2) == 0</code>. +*/ + +/*! + \fn bool operator!=( const QString &s1, const QString &s2 ) + \relates QString + Returns TRUE if the two strings are different, or FALSE if they are equal. + + Equivalent to <code>qstrcmp(s1,s2) != 0</code>. +*/ + +/*! + \fn bool operator!=( const QString &s1, const char *s2 ) + \relates QString + Returns TRUE if the two strings are different, or FALSE if they are equal. + + Equivalent to <code>qstrcmp(s1,s2) != 0</code>. +*/ + +/*! + \fn bool operator!=( const char *s1, const QString &s2 ) + \relates QString + Returns TRUE if the two strings are different, or FALSE if they are equal. + + Equivalent to <code>qstrcmp(s1,s2) != 0</code>. +*/ + +/*! + \fn bool operator<( const QString &s1, const char *s2 ) + \relates QString + Returns TRUE if \a s1 is alphabetically less than \a s2, otherwise FALSE. + + Equivalent to <code>qstrcmp(s1,s2) \< 0</code>. +*/ + +/*! + \fn bool operator<( const char *s1, const QString &s2 ) + \relates QString + Returns TRUE if \a s1 is alphabetically less than \a s2, otherwise FALSE. + + Equivalent to <code>qstrcmp(s1,s2) \< 0</code>. +*/ + +/*! + \fn bool operator<=( const QString &s1, const char *s2 ) + \relates QString + Returns TRUE if \a s1 is alphabetically less than or equal to \a s2, + otherwise FALSE. + + Equivalent to <code>qstrcmp(s1,s2) \<= 0</code>. +*/ + +/*! + \fn bool operator<=( const char *s1, const QString &s2 ) + \relates QString + Returns TRUE if \a s1 is alphabetically less than or equal to \a s2, + otherwise FALSE. + + Equivalent to <code>qstrcmp(s1,s2) \<= 0</code>. +*/ + +/*! + \fn bool operator>( const QString &s1, const char *s2 ) + \relates QString + Returns TRUE if \a s1 is alphabetically greater than \a s2, otherwise FALSE. + + Equivalent to <code>qstrcmp(s1,s2) \> 0</code>. +*/ + +/*! + \fn bool operator>( const char *s1, const QString &s2 ) + \relates QString + Returns TRUE if \a s1 is alphabetically greater than \a s2, otherwise FALSE. + + Equivalent to <code>qstrcmp(s1,s2) \> 0</code>. +*/ + +/*! + \fn bool operator>=( const QString &s1, const char *s2 ) + \relates QString + Returns TRUE if \a s1 is alphabetically greater than or equal to \a s2, + otherwise FALSE. + + Equivalent to <code>qstrcmp(s1,s2) \>= 0</code>. +*/ + +/*! + \fn bool operator>=( const char *s1, const QString &s2 ) + \relates QString + Returns TRUE if \a s1 is alphabetically greater than or equal to \a s2, + otherwise FALSE. + + Equivalent to <code>qstrcmp(s1,s2) \>= 0</code>. +*/ + +/*! + \fn QString operator+( const QString &s1, const QString &s2 ) + \relates QString + Returns the concatenated string of s1 and s2. +*/ + +/*! + \fn QString operator+( const QString &s1, const char *s2 ) + \relates QString + Returns the concatenated string of s1 and s2. +*/ + +/*! + \fn QString operator+( const char *s1, const QString &s2 ) + \relates QString + Returns the concatenated string of s1 and s2. +*/ + +/*! + \fn QString operator+( const QString &s, char c ) + \relates QString + Returns the concatenated string of s and c. +*/ + +/*! + \fn QString operator+( char c, const QString &s ) + \relates QString + Returns the concatenated string of c and s. +*/ + + +/***************************************************************************** + QString stream functions + *****************************************************************************/ +#ifndef QT_NO_DATASTREAM +/*! + \relates QString + Writes a string to the stream. + + \sa \link datastreamformat.html Format of the QDataStream operators \endlink +*/ + +QDataStream &operator<<( QDataStream &s, const QString &str ) +{ + if ( s.version() == 1 ) { + QCString l( str.latin1() ); + s << l; + } + else { + const char* ub = (const char*)str.unicode(); + if ( ub || s.version() < 3 ) { + if ( QChar::networkOrdered() == + (s.byteOrder()==QDataStream::BigEndian) ) { + s.writeBytes( ub, sizeof(QChar)*str.length() ); + } else { + static const uint auto_size = 1024; + char t[auto_size]; + char *b; + if ( str.length()*sizeof(QChar) > auto_size ) { + b = new char[str.length()*sizeof(QChar)]; + } else { + b = t; + } + int l = str.length(); + char *c=b; + while ( l-- ) { + *c++ = ub[1]; + *c++ = ub[0]; + ub+=sizeof(QChar); + } + s.writeBytes( b, sizeof(QChar)*str.length() ); + if ( str.length()*sizeof(QChar) > auto_size ) + delete [] b; + } + } else { + // write null marker + s << (Q_UINT32)0xffffffff; + } + } + return s; +} + +/*! + \relates QString + Reads a string from the stream. + + \sa \link datastreamformat.html Format of the QDataStream operators \endlink +*/ + +QDataStream &operator>>( QDataStream &s, QString &str ) +{ +#ifdef QT_QSTRING_UCS_4 +#if defined(_CC_GNU_) +#warning "operator>> not working properly" +#endif +#endif + if ( s.version() == 1 ) { + QCString l; + s >> l; + str = QString( l ); + } + else { + Q_UINT32 bytes; + s >> bytes; // read size of string + if ( bytes == 0xffffffff ) { // null string + str = QString::null; + } else if ( bytes > 0 ) { // not empty + str.setLength( bytes/2 ); + char* b = (char*)str.d->unicode; + s.readRawBytes( b, bytes ); + if ( QChar::networkOrdered() != + (s.byteOrder()==QDataStream::BigEndian) ) { + bytes /= 2; + while ( bytes-- ) { + char c = b[0]; + b[0] = b[1]; + b[1] = c; + b += 2; + } + } + } else { + str = ""; + } + } + return s; +} +#endif // QT_NO_DATASTREAM + +/***************************************************************************** + QConstString member functions + *****************************************************************************/ + +/*! + \class QConstString qstring.h + \brief A QString which uses constant Unicode data. + + In order to minimize copying, highly optimized applications can use + QConstString to provide a QString-compatible object from existing + Unicode data. It is then the user's responsibility to make sure + that the Unicode data must exist for the entire lifetime of the + QConstString object. +*/ + +/*! + Constructs a QConstString that uses the first \a length Unicode + characters in the array \a unicode. Any attempt to modify + copies of the string will cause it to create a copy of the + data, thus it remains forever unmodified. + + Note that \a unicode is \e not \e copied. The caller \e must be + able to guarantee that \a unicode will not be deleted or + modified. Since that is generally not the case with \c const strings + (they are references), this constructor demands a non-const pointer + even though it never modifies \a unicode. +*/ +QConstString::QConstString( QChar* unicode, uint length ) : + QString(new QStringData(unicode, length, length),TRUE) +{ +} + +/*! + Destroys the QConstString, creating a copy of the data if + other strings are still using it. +*/ +QConstString::~QConstString() +{ + if ( d->count > 1 ) { + QChar* cp = QT_ALLOC_QCHAR_VEC( d->len ); + memcpy( cp, d->unicode, d->len*sizeof(QChar) ); + d->unicode = cp; + } else { + d->unicode = 0; + } + + // The original d->unicode is now unlinked. +} + +/*! + \fn const QString& QConstString::string() const + + Returns a constant string referencing the data passed during + construction. +*/ + +/*! + Returns whether the strings starts with \a s, or not. + */ +bool QString::startsWith( const QString& s ) const +{ + for ( int i =0; i < (int) s.length(); i++ ) { + if ( i >= (int) length() || d->unicode[i] != s[i] ) + return FALSE; + } + return TRUE; +} + + + +#if defined(_OS_WIN32_) + +#include <windows.h> + +/*! + Returns a static Windows TCHAR* from a QString, possibly adding NUL. + + The lifetime of the return value is until the next call to this function. +*/ +const void* qt_winTchar(const QString& str_in, bool addnul) +{ + // So that the return value lives long enough. + static QString str; + str = str_in; + +#ifdef UNICODE + static uint buflen = 256; + static TCHAR *buf = new TCHAR[buflen]; + + const QChar* uc = str.unicode(); + +#define EXTEND if (str.length() > buflen) { delete buf; buf = new TCHAR[buflen=str.length()+1]; } + +#if defined(_WS_X11_) || defined(_OS_WIN32_BYTESWAP_) + EXTEND + for ( int i=str.length(); i--; ) + buf[i] = uc[i].row() << 8 | uc[i].cell(); + if ( addnul ) + buf[str.length()] = 0; +#else + // Same endianness of TCHAR + if ( addnul ) { + EXTEND + memcpy(buf,uc,sizeof(TCHAR)*str.length()); + buf[str.length()] = 0; + } else { + return uc; + } +#endif + return buf; +#undef EXTEND + +#else + return str.latin1(); +#endif +} + +/*! + Makes a new null terminated Windows TCHAR* from a QString. +*/ +void* qt_winTchar_new(const QString& str) +{ + TCHAR* result = new TCHAR[str.length()+1]; + memcpy(result, qt_winTchar(str,FALSE), sizeof(TCHAR)*str.length()); + result[str.length()] = 0; + return result; +} + +/*! + Makes a QString from a Windows TCHAR*. +*/ +QString qt_winQString(void* tc) +{ +#ifdef UNICODE + + int len=0; + while ( ((TCHAR*)tc)[len] ) + len++; +#if defined(_WS_X11_) || defined(_OS_WIN32_BYTESWAP_) + QString r; + for ( int i=0; i<len; i++ ) + r += QChar(((TCHAR*)tc)[i]&0xff,((TCHAR*)tc)[i]>>8); + return r; +#else + // Same endianness of TCHAR + return QString((QChar*)tc,len); +#endif +#undef EXTEND +#else + return (TCHAR*)tc; +#endif +} + +QCString qt_winQString2MB( const QString& s, int uclen ) +{ + if ( uclen < 0 ) + uclen = s.length(); + if ( uclen == 0 ) + return QCString(); + BOOL used_def; + int bufSize=4096; + QCString mb(bufSize); + int len; + while ( !(len=WideCharToMultiByte(CP_ACP, 0, (const WCHAR*)s.unicode(), uclen, + mb.data(), bufSize-1, 0, &used_def)) ) + { + int r = GetLastError(); + if ( r == ERROR_INSUFFICIENT_BUFFER ) { + bufSize=1+WideCharToMultiByte( CP_ACP, 0, + (const WCHAR*)s.unicode(), uclen, + 0, 0, 0, &used_def); + mb.resize(bufSize); + // and try again... + } else { + // Fail. + qWarning("WideCharToMultiByte cannot convert multibyte text (error %d): %s (UTF8)", + r, s.utf8().data()); + break; + } + } + mb[len]='\0'; + return mb; +} + +// WATCH OUT: mblen must include the NUL (or just use -1) +QString qt_winMB2QString( const char* mb, int mblen ) +{ + if ( !mb || !mblen ) + return QString::null; + const int wclen_auto = 4096; + WCHAR wc_auto[wclen_auto]; + int wclen = wclen_auto; + WCHAR *wc = wc_auto; + int len; + while ( !(len=MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, + mb, mblen, wc, wclen )) ) + { + int r = GetLastError(); + if ( r == ERROR_INSUFFICIENT_BUFFER ) { + if ( wc != wc_auto ) { + qWarning("Size changed in MultiByteToWideChar"); + break; + } else { + wclen = MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, + mb, mblen, 0, 0 ); + wc = new WCHAR[wclen]; + // and try again... + } + } else { + // Fail. + qWarning("MultiByteToWideChar cannot convert multibyte text"); + break; + } + } + if ( len <= 0 ) + return QString::null; + QString s( (QChar*)wc, len-1 ); // len-1: we don't want terminator + if ( wc != wc_auto ) + delete [] wc; + return s; +} + + +#endif // _OS_WIN32_ diff --git a/trunk/qtools/qstring.h b/trunk/qtools/qstring.h new file mode 100644 index 0000000..0dd6352 --- /dev/null +++ b/trunk/qtools/qstring.h @@ -0,0 +1,833 @@ +/**************************************************************************** +** +** +** Definition of the QString class, and related Unicode +** functions. +** +** Created : 920609 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QSTRING_H +#define QSTRING_H + +#ifndef QT_H +#include "qcstring.h" +#endif // QT_H + + +/***************************************************************************** + QString class + *****************************************************************************/ + +class QRegExp; +class QString; +class QCharRef; + +class Q_EXPORT Q_PACKED QChar { +public: + QChar(); + QChar( char c ); + QChar( uchar c ); + QChar( uchar c, uchar r ); + QChar( const QChar& c ); + QChar( ushort rc ); + QChar( short rc ); + QChar( uint rc ); + QChar( int rc ); + + QT_STATIC_CONST QChar null; // 0000 + QT_STATIC_CONST QChar replacement; // FFFD + QT_STATIC_CONST QChar byteOrderMark; // FEFF + QT_STATIC_CONST QChar byteOrderSwapped; // FFFE + QT_STATIC_CONST QChar nbsp; // 00A0 + + // Unicode information + + enum Category + { + NoCategory, + + Mark_NonSpacing, // Mn + Mark_SpacingCombining, // Mc + Mark_Enclosing, // Me + + Number_DecimalDigit, // Nd + Number_Letter, // Nl + Number_Other, // No + + Separator_Space, // Zs + Separator_Line, // Zl + Separator_Paragraph, // Zp + + Other_Control, // Cc + Other_Format, // Cf + Other_Surrogate, // Cs + Other_PrivateUse, // Co + Other_NotAssigned, // Cn + + Letter_Uppercase, // Lu + Letter_Lowercase, // Ll + Letter_Titlecase, // Lt + Letter_Modifier, // Lm + Letter_Other, // Lo + + Punctuation_Connector, // Pc + Punctuation_Dask, // Pd + Punctuation_Open, // Ps + Punctuation_Close, // Pe + Punctuation_InitialQuote, // Pi + Punctuation_FinalQuote, // Pf + Punctuation_Other, // Po + + Symbol_Math, // Sm + Symbol_Currency, // Sc + Symbol_Modifier, // Sk + Symbol_Other // So + }; + + enum Direction + { + DirL, DirR, DirEN, DirES, DirET, DirAN, DirCS, DirB, DirS, DirWS, DirON, + DirLRE, DirLRO, DirAL, DirRLE, DirRLO, DirPDF, DirNSM, DirBN + }; + + enum Decomposition + { + Single, Canonical, Font, NoBreak, Initial, Medial, + Final, Isolated, Circle, Super, Sub, Vertical, + Wide, Narrow, Small, Square, Compat, Fraction + }; + + enum Joining + { + OtherJoining, Dual, Right, Center + }; + + // ****** WHEN ADDING FUNCTIONS, CONSIDER ADDING TO QCharRef TOO + + int digitValue() const; + QChar lower() const; + QChar upper() const; + + Category category() const; + Direction direction() const; + Joining joining() const; + bool mirrored() const; + QChar mirroredChar() const; + QString decomposition() const; + Decomposition decompositionTag() const; + + char latin1() const { return rw ? 0 : cl; } + ushort unicode() const { return (rw << 8) | cl; } +#ifndef QT_NO_CAST_ASCII + // like all ifdef'd code this is undocumented + operator char() const { return latin1(); } +#endif + + bool isNull() const { return unicode()==0; } + bool isPrint() const; + bool isPunct() const; + bool isSpace() const; + bool isMark() const; + bool isLetter() const; + bool isNumber() const; + bool isLetterOrNumber() const; + bool isDigit() const; + + uchar& cell() { return cl; } + uchar& row() { return rw; } + uchar cell() const { return cl; } + uchar row() const { return rw; } + + static bool networkOrdered() { return (int)net_ordered == 1; } + + friend inline int operator==( char ch, QChar c ); + friend inline int operator==( QChar c, char ch ); + friend inline int operator==( QChar c1, QChar c2 ); + friend inline int operator!=( QChar c1, QChar c2 ); + friend inline int operator!=( char ch, QChar c ); + friend inline int operator!=( QChar c, char ch ); + friend inline int operator<=( QChar c, char ch ); + friend inline int operator<=( char ch, QChar c ); + friend inline int operator<=( QChar c1, QChar c2 ); + +private: +#if defined(_WS_X11_) || defined(_OS_WIN32_BYTESWAP_) || defined( _WS_QWS_ ) + // XChar2b on X11, ushort on _OS_WIN32_BYTESWAP_ + //### QWS must be defined on a platform by platform basis + uchar rw; + uchar cl; +#if defined(QT_QSTRING_UCS_4) + ushort grp; +#endif + enum { net_ordered = 1 }; +#else + // ushort on _OS_WIN32_ + uchar cl; + uchar rw; +#if defined(QT_QSTRING_UCS_4) + ushort grp; +#endif + enum { net_ordered = 0 }; +#endif +}; + +inline QChar::QChar() +{ + rw = 0; cl = 0; +#ifdef QT_QSTRING_UCS_4 + grp = 0; +#endif +} +inline QChar::QChar( char c ) +{ + rw = 0; cl = (uchar)c; +#ifdef QT_QSTRING_UCS_4 + grp = 0; +#endif +} +inline QChar::QChar( uchar c ) +{ + rw = 0; cl = c; +#ifdef QT_QSTRING_UCS_4 + grp = 0; +#endif +} +inline QChar::QChar( uchar c, uchar r ) +{ + rw = r; cl = c; +#ifdef QT_QSTRING_UCS_4 + grp = 0; +#endif +} +inline QChar::QChar( const QChar& c ) +{ + rw = c.rw; cl = c.cl; +#ifdef QT_QSTRING_UCS_4 + grp = 0; +#endif +} +inline QChar::QChar( ushort rc ) +{ + rw = (uchar)((rc>>8)&0xff); cl = (uchar)(rc&0xff); +#ifdef QT_QSTRING_UCS_4 + grp = 0; +#endif +} +inline QChar::QChar( short rc ) +{ + rw = (uchar)((rc>>8)&0xff); cl = (uchar)(rc&0xff); +#ifdef QT_QSTRING_UCS_4 + grp = 0; +#endif +} +inline QChar::QChar( uint rc ) +{ + rw = (uchar)((rc>>8)&0xff); cl = (uchar)(rc&0xff); +#ifdef QT_QSTRING_UCS_4 + grp = 0; +#endif +} +inline QChar::QChar( int rc ) +{ + rw = (uchar)((rc>>8)&0xff); cl = (uchar)(rc&0xff); +#ifdef QT_QSTRING_UCS_4 + grp = 0; +#endif +} + + +inline int operator==( char ch, QChar c ) +{ + return ch == c.cl && !c.rw; +} + +inline int operator==( QChar c, char ch ) +{ + return ch == c.cl && !c.rw; +} + +inline int operator==( QChar c1, QChar c2 ) +{ + return c1.cl == c2.cl + && c1.rw == c2.rw; +} + +inline int operator!=( QChar c1, QChar c2 ) +{ + return c1.cl != c2.cl + || c1.rw != c2.rw; +} + +inline int operator!=( char ch, QChar c ) +{ + return ch != c.cl || c.rw; +} + +inline int operator!=( QChar c, char ch ) +{ + return ch != c.cl || c.rw; +} + +inline int operator<=( QChar c, char ch ) +{ + return !(ch < c.cl || c.rw); +} + +inline int operator<=( char ch, QChar c ) +{ + return ch <= c.cl || c.rw; +} + +inline int operator<=( QChar c1, QChar c2 ) +{ + return c1.rw > c2.rw + ? FALSE + : c1.rw < c2.rw + ? TRUE + : c1.cl <= c2.cl; +} + +inline int operator>=( QChar c, char ch ) { return ch <= c; } +inline int operator>=( char ch, QChar c ) { return c <= ch; } +inline int operator>=( QChar c1, QChar c2 ) { return c2 <= c1; } +inline int operator<( QChar c, char ch ) { return !(ch<=c); } +inline int operator<( char ch, QChar c ) { return !(c<=ch); } +inline int operator<( QChar c1, QChar c2 ) { return !(c2<=c1); } +inline int operator>( QChar c, char ch ) { return !(ch>=c); } +inline int operator>( char ch, QChar c ) { return !(c>=ch); } +inline int operator>( QChar c1, QChar c2 ) { return !(c2>=c1); } + +// internal +struct Q_EXPORT QStringData : public QShared { + QStringData() : + unicode(0), ascii(0), len(0), maxl(0), dirtyascii(0) { ref(); } + QStringData(QChar *u, uint l, uint m) : + unicode(u), ascii(0), len(l), maxl(m), dirtyascii(0) { } + + ~QStringData() { if ( unicode ) delete[] ((char*)unicode); + if ( ascii ) delete[] ascii; } + + void deleteSelf(); + QChar *unicode; + char *ascii; + uint len; + uint maxl:30; + uint dirtyascii:1; +}; + + +class Q_EXPORT QString +{ +public: + QString(); // make null string + QString( QChar ); // one-char string + QString( const QString & ); // impl-shared copy + QString( const QByteArray& ); // deep copy + QString( const QCString& ); // deep copy + QString( const QChar* unicode, uint length ); // deep copy +#ifndef QT_NO_CAST_ASCII + QString( const char *str ); // deep copy +#endif + ~QString(); + + QString &operator=( const QString & ); // impl-shared copy +#ifndef QT_NO_CAST_ASCII + QString &operator=( const char * ); // deep copy +#endif + QString &operator=( const QCString& ); // deep copy + QString &operator=( QChar c ); + QString &operator=( char c ); + + //QT_STATIC_CONST QString null; + //bool isNull() const; + + struct Null { }; + static const Null null; + inline QString(const Null &): d(shared_null) { d->ref(); } + inline QString &operator=(const Null &) { *this = QString(); return *this; } + inline bool isNull() const { return d == shared_null; } + + bool isEmpty() const; + uint length() const; + void truncate( uint pos ); + +#if QT_VERSION >= 300 +#error "fill() Should return *this, or QChar constructor should take count=1" +#endif + void fill( QChar c, int len = -1 ); + + QString copy() const; + + QString arg(long a, int fieldwidth=0, int base=10) const; + QString arg(ulong a, int fieldwidth=0, int base=10) const; + QString arg(int a, int fieldwidth=0, int base=10) const; + QString arg(uint a, int fieldwidth=0, int base=10) const; + QString arg(short a, int fieldwidth=0, int base=10) const; + QString arg(ushort a, int fieldwidth=0, int base=10) const; + QString arg(char a, int fieldwidth=0) const; + QString arg(QChar a, int fieldwidth=0) const; + QString arg(const QString& a, int fieldwidth=0) const; + QString arg(double a, int fieldwidth=0, char fmt='g', int prec=-1) const; + + QString &sprintf( const char* format, ... ) +#if defined(_CC_GNU_) && !defined(__INSURE__) + __attribute__ ((format (printf, 2, 3))) +#endif + ; + + int find( QChar c, int index=0, bool cs=TRUE ) const; + int find( char c, int index=0, bool cs=TRUE ) const; + int find( const QString &str, int index=0, bool cs=TRUE ) const; + int find( const QRegExp &, int index=0 ) const; +#ifndef QT_NO_CAST_ASCII + int find( const char* str, int index=0 ) const; +#endif + int findRev( QChar c, int index=-1, bool cs=TRUE) const; + int findRev( char c, int index=-1, bool cs=TRUE) const; + int findRev( const QString &str, int index=-1, bool cs=TRUE) const; + int findRev( const QRegExp &, int index=-1 ) const; +#ifndef QT_NO_CAST_ASCII + int findRev( const char* str, int index=-1 ) const; +#endif + int contains( QChar c, bool cs=TRUE ) const; + int contains( char c, bool cs=TRUE ) const + { return contains(QChar(c), cs); } +#ifndef QT_NO_CAST_ASCII + int contains( const char* str, bool cs=TRUE ) const; +#endif + int contains( const QString &str, bool cs=TRUE ) const; + int contains( const QRegExp & ) const; + + QString left( uint len ) const; + QString right( uint len ) const; + QString mid( uint index, uint len=0xffffffff) const; + + QString leftJustify( uint width, QChar fill=' ', bool trunc=FALSE)const; + QString rightJustify( uint width, QChar fill=' ',bool trunc=FALSE)const; + + QString lower() const; + QString upper() const; + + QString stripWhiteSpace() const; + QString simplifyWhiteSpace() const; + + QString &insert( uint index, const QString & ); + QString &insert( uint index, const QChar*, uint len ); + QString &insert( uint index, QChar ); + QString &insert( uint index, char c ) { return insert(index,QChar(c)); } + QString &append( char ); + QString &append( QChar ); + QString &append( const QString & ); + QString &prepend( char ); + QString &prepend( QChar ); + QString &prepend( const QString & ); + QString &remove( uint index, uint len ); + QString &replace( uint index, uint len, const QString & ); + QString &replace( uint index, uint len, const QChar*, uint clen ); + QString &replace( const QRegExp &, const QString & ); + + short toShort( bool *ok=0, int base=10 ) const; + ushort toUShort( bool *ok=0, int base=10 ) const; + int toInt( bool *ok=0, int base=10 ) const; + uint toUInt( bool *ok=0, int base=10 ) const; + long toLong( bool *ok=0, int base=10 ) const; + ulong toULong( bool *ok=0, int base=10 ) const; + float toFloat( bool *ok=0 ) const; + double toDouble( bool *ok=0 ) const; + + QString &setNum( short, int base=10 ); + QString &setNum( ushort, int base=10 ); + QString &setNum( int, int base=10 ); + QString &setNum( uint, int base=10 ); + QString &setNum( long, int base=10 ); + QString &setNum( ulong, int base=10 ); + QString &setNum( float, char f='g', int prec=6 ); + QString &setNum( double, char f='g', int prec=6 ); + + static QString number( long, int base=10 ); + static QString number( ulong, int base=10); + static QString number( int, int base=10 ); + static QString number( uint, int base=10); + static QString number( double, char f='g', int prec=6 ); + + void setExpand( uint index, QChar c ); + + QString &operator+=( const QString &str ); + QString &operator+=( QChar c ); + QString &operator+=( char c ); + + // Your compiler is smart enough to use the const one if it can. + QChar at( uint i ) const + { return i<d->len ? d->unicode[i] : QChar::null; } + QChar operator[]( int i ) const { return at((uint)i); } + QCharRef at( uint i ); + QCharRef operator[]( int i ); + + QChar constref(uint i) const + { return at(i); } + QChar& ref(uint i) + { // Optimized for easy-inlining by simple compilers. + if (d->count!=1 || i>=d->len) + subat(i); + d->dirtyascii=1; + return d->unicode[i]; + } + + const QChar* unicode() const { return d->unicode; } + const char* ascii() const; + const char* latin1() const; + static QString fromLatin1(const char*, int len=-1); + const unsigned short *ucs2() const; + static QString fromUcs2( const unsigned short *ucs2 ); +#ifndef QT_NO_TEXTCODEC + QCString utf8() const; + static QString fromUtf8(const char*, int len=-1); +#endif + QCString local8Bit() const; + static QString fromLocal8Bit(const char*, int len=-1); + bool operator!() const; +#ifndef QT_NO_ASCII_CAST + operator const char *() const { return latin1(); } +#endif + + QString &setUnicode( const QChar* unicode, uint len ); + QString &setUnicodeCodes( const ushort* unicode_as_ushorts, uint len ); + QString &setLatin1( const char*, int len=-1 ); + + int compare( const QString& s ) const; + static int compare( const QString& s1, const QString& s2 ) + { return s1.compare(s2); } + +#ifndef QT_NO_DATASTREAM + friend Q_EXPORT QDataStream &operator>>( QDataStream &, QString & ); +#endif + // new functions for BiDi + void compose(); + QChar::Direction basicDirection(); + QString visual(int index = 0, int len = -1); + +#ifndef QT_NO_COMPAT + const char* data() const { return latin1(); } +#endif + + bool startsWith( const QString& ) const; + +private: + QString( int size, bool dummy ); // allocate size incl. \0 + + void deref(); + void real_detach(); + void setLength( uint pos ); + void subat( uint ); + bool findArg(int& pos, int& len) const; + + static QChar* asciiToUnicode( const char*, uint * len, uint maxlen=(uint)-1 ); + static QChar* asciiToUnicode( const QByteArray&, uint * len ); + static char* unicodeToAscii( const QChar*, uint len ); + + QStringData *d; + static QStringData* shared_null; + static QStringData* makeSharedNull(); + + friend class QConstString; + QString(QStringData* dd, bool /*dummy*/) : d(dd) { } +}; + +class Q_EXPORT QCharRef { + friend class QString; + QString& s; + uint p; + QCharRef(QString* str, uint pos) : s(*str), p(pos) { } + +public: + // Most QChar operations repeated here... + + // all this is not documented: We just say "like QChar" and let it be. +#if 1 + ushort unicode() const { return s.constref(p).unicode(); } + char latin1() const { return s.constref(p).latin1(); } + + // An operator= for each QChar cast constructor... + QCharRef operator=(char c ) { s.ref(p)=c; return *this; } + QCharRef operator=(uchar c ) { s.ref(p)=c; return *this; } + QCharRef operator=(QChar c ) { s.ref(p)=c; return *this; } + QCharRef operator=(const QCharRef& c ) { s.ref(p)=c.unicode(); return *this; } + QCharRef operator=(ushort rc ) { s.ref(p)=rc; return *this; } + QCharRef operator=(short rc ) { s.ref(p)=rc; return *this; } + QCharRef operator=(uint rc ) { s.ref(p)=rc; return *this; } + QCharRef operator=(int rc ) { s.ref(p)=rc; return *this; } + + operator QChar () const { return s.constref(p); } + + // each function... + bool isNull() const { return unicode()==0; } + bool isPrint() const { return s.constref(p).isPrint(); } + bool isPunct() const { return s.constref(p).isPunct(); } + bool isSpace() const { return s.constref(p).isSpace(); } + bool isMark() const { return s.constref(p).isMark(); } + bool isLetter() const { return s.constref(p).isLetter(); } + bool isNumber() const { return s.constref(p).isNumber(); } + bool isLetterOrNumber() { return s.constref(p).isLetterOrNumber(); } + bool isDigit() const { return s.constref(p).isDigit(); } + + int digitValue() const { return s.constref(p).digitValue(); } + QChar lower() { return s.constref(p).lower(); } + QChar upper() { return s.constref(p).upper(); } + + QChar::Category category() const { return s.constref(p).category(); } + QChar::Direction direction() const { return s.constref(p).direction(); } + QChar::Joining joining() const { return s.constref(p).joining(); } + bool mirrored() const { return s.constref(p).mirrored(); } + QChar mirroredChar() const { return s.constref(p).mirroredChar(); } + QString decomposition() const { return s.constref(p).decomposition(); } + QChar::Decomposition decompositionTag() const { return s.constref(p).decompositionTag(); } + + // Not the non-const ones of these. + uchar cell() const { return s.constref(p).cell(); } + uchar row() const { return s.constref(p).row(); } +#endif +}; + +inline QCharRef QString::at( uint i ) { return QCharRef(this,i); } +inline QCharRef QString::operator[]( int i ) { return at((uint)i); } + + +class Q_EXPORT QConstString : private QString { +public: + QConstString( QChar* unicode, uint length ); + ~QConstString(); + const QString& string() const { return *this; } +}; + + +/***************************************************************************** + QString stream functions + *****************************************************************************/ +#ifndef QT_NO_DATASTREAM +Q_EXPORT QDataStream &operator<<( QDataStream &, const QString & ); +Q_EXPORT QDataStream &operator>>( QDataStream &, QString & ); +#endif + +/***************************************************************************** + QString inline functions + *****************************************************************************/ + +// These two move code into makeSharedNull() and deletesData() +// to improve cache-coherence (and reduce code bloat), while +// keeping the common cases fast. +// +// No safe way to pre-init shared_null on ALL compilers/linkers. +inline QString::QString() : + d(shared_null ? shared_null : makeSharedNull()) +{ + d->ref(); +} +// +inline QString::~QString() +{ + if ( d->deref() ) { + if ( d == shared_null ) + shared_null = 0; + d->deleteSelf(); + } +} + +inline QString &QString::operator=( QChar c ) +{ return *this = QString(c); } + +inline QString &QString::operator=( char c ) +{ return *this = QString(QChar(c)); } + +//inline bool QString::isNull() const +//{ return unicode() == 0; } + +inline bool QString::operator!() const +{ return isNull(); } + +inline uint QString::length() const +{ return d->len; } + +inline bool QString::isEmpty() const +{ return length() == 0; } + +inline QString QString::copy() const +{ return QString( *this ); } + +inline QString &QString::prepend( const QString & s ) +{ return insert(0,s); } + +inline QString &QString::prepend( QChar c ) +{ return insert(0,c); } + +inline QString &QString::prepend( char c ) +{ return insert(0,c); } + +inline QString &QString::append( const QString & s ) +{ return operator+=(s); } + +inline QString &QString::append( QChar c ) +{ return operator+=(c); } + +inline QString &QString::append( char c ) +{ return operator+=(c); } + +inline QString &QString::setNum( short n, int base ) +{ return setNum((long)n, base); } + +inline QString &QString::setNum( ushort n, int base ) +{ return setNum((ulong)n, base); } + +inline QString &QString::setNum( int n, int base ) +{ return setNum((long)n, base); } + +inline QString &QString::setNum( uint n, int base ) +{ return setNum((ulong)n, base); } + +inline QString &QString::setNum( float n, char f, int prec ) +{ return setNum((double)n,f,prec); } + +inline QString QString::arg(int a, int fieldwidth, int base) const +{ return arg((long)a, fieldwidth, base); } + +inline QString QString::arg(uint a, int fieldwidth, int base) const +{ return arg((ulong)a, fieldwidth, base); } + +inline QString QString::arg(short a, int fieldwidth, int base) const +{ return arg((long)a, fieldwidth, base); } + +inline QString QString::arg(ushort a, int fieldwidth, int base) const +{ return arg((ulong)a, fieldwidth, base); } + +inline int QString::find( char c, int index, bool cs ) const +{ return find(QChar(c), index, cs); } + +inline int QString::findRev( char c, int index, bool cs) const +{ return findRev( QChar(c), index, cs ); } + + +#ifndef QT_NO_CAST_ASCII +inline int QString::find( const char* str, int index ) const +{ return find(QString::fromLatin1(str), index); } + +inline int QString::findRev( const char* str, int index ) const +{ return findRev(QString::fromLatin1(str), index); } +#endif + + +/***************************************************************************** + QString non-member operators + *****************************************************************************/ + +Q_EXPORT bool operator!=( const QString &s1, const QString &s2 ); +Q_EXPORT bool operator<( const QString &s1, const QString &s2 ); +Q_EXPORT bool operator<=( const QString &s1, const QString &s2 ); +Q_EXPORT bool operator==( const QString &s1, const QString &s2 ); +Q_EXPORT bool operator>( const QString &s1, const QString &s2 ); +Q_EXPORT bool operator>=( const QString &s1, const QString &s2 ); +#ifndef QT_NO_CAST_ASCII +Q_EXPORT bool operator!=( const QString &s1, const char *s2 ); +Q_EXPORT bool operator<( const QString &s1, const char *s2 ); +Q_EXPORT bool operator<=( const QString &s1, const char *s2 ); +Q_EXPORT bool operator==( const QString &s1, const char *s2 ); +Q_EXPORT bool operator>( const QString &s1, const char *s2 ); +Q_EXPORT bool operator>=( const QString &s1, const char *s2 ); +Q_EXPORT bool operator!=( const char *s1, const QString &s2 ); +Q_EXPORT bool operator<( const char *s1, const QString &s2 ); +Q_EXPORT bool operator<=( const char *s1, const QString &s2 ); +Q_EXPORT bool operator==( const char *s1, const QString &s2 ); +//Q_EXPORT bool operator>( const char *s1, const QString &s2 ); // MSVC++ +Q_EXPORT bool operator>=( const char *s1, const QString &s2 ); +#endif + +Q_EXPORT inline QString operator+( const QString &s1, const QString &s2 ) +{ + QString tmp( s1 ); + tmp += s2; + return tmp; +} + +#ifndef QT_NO_CAST_ASCII +Q_EXPORT inline QString operator+( const QString &s1, const char *s2 ) +{ + QString tmp( s1 ); + tmp += QString::fromLatin1(s2); + return tmp; +} + +Q_EXPORT inline QString operator+( const char *s1, const QString &s2 ) +{ + QString tmp = QString::fromLatin1( s1 ); + tmp += s2; + return tmp; +} +#endif + +Q_EXPORT inline QString operator+( const QString &s1, QChar c2 ) +{ + QString tmp( s1 ); + tmp += c2; + return tmp; +} + +Q_EXPORT inline QString operator+( const QString &s1, char c2 ) +{ + QString tmp( s1 ); + tmp += c2; + return tmp; +} + +Q_EXPORT inline QString operator+( QChar c1, const QString &s2 ) +{ + QString tmp; + tmp += c1; + tmp += s2; + return tmp; +} + +Q_EXPORT inline QString operator+( char c1, const QString &s2 ) +{ + QString tmp; + tmp += c1; + tmp += s2; + return tmp; +} + +#if defined(_OS_WIN32_) +extern Q_EXPORT QString qt_winQString(void*); +extern Q_EXPORT const void* qt_winTchar(const QString& str, bool addnul); +extern Q_EXPORT void* qt_winTchar_new(const QString& str); +extern Q_EXPORT QCString qt_winQString2MB( const QString& s, int len=-1 ); +extern Q_EXPORT QString qt_winMB2QString( const char* mb, int len=-1 ); +#endif + +#endif // QSTRING_H diff --git a/trunk/qtools/qstringlist.cpp b/trunk/qtools/qstringlist.cpp new file mode 100644 index 0000000..7696340 --- /dev/null +++ b/trunk/qtools/qstringlist.cpp @@ -0,0 +1,307 @@ +/**************************************************************************** +** +** +** Implementation of QStringList +** +** Created : 990406 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "qstringlist.h" + +#ifndef QT_NO_STRINGLIST +#include "qstrlist.h" +#include "qdatastream.h" +#include "qtl.h" + +// NOT REVISED +/*! + \class QStringList qstringlist.h + \brief A list of strings. + + \ingroup qtl + \ingroup tools + \ingroup shared + + QStringList is basically a QValueList of QString objects. As opposed + to QStrList, that stores pointers to characters, QStringList deals + with real QString objects. It is the class of choice whenever you + work with unicode strings. + + Like QString itself, QStringList objects are implicit shared. + Passing them around as value-parameters is both fast and safe. + + Example: + \code + QStringList list; + + // three different ways of appending values: + list.append( "Torben"); + list += "Warwick"; + list << "Matthias" << "Arnt" << "Paul"; + + // sort the list, Arnt's now first + list.sort(); + + // print it out + for ( QStringList::Iterator it = list.begin(); it != list.end(); ++it ) { + printf( "%s \n", (*it).latin1() ); + } + \endcode + + Convenience methods such as sort(), split(), join() and grep() make + working with QStringList easy. +*/ + +/*! + \fn QStringList::QStringList() + Creates an empty list. +*/ + +/*! \fn QStringList::QStringList( const QStringList& l ) + Creates a copy of the list. This function is very fast since + QStringList is implicit shared. However, for the programmer this + is the same as a deep copy. If this list or the original one or some + other list referencing the same shared data is modified, then the + modifying list makes a copy first. +*/ + +/*! + \fn QStringList::QStringList (const QString & i) + Constructs a string list consisting of the single string \a i. + To make longer lists easily, use: + \code + QString s1,s2,s3; + ... + QStringList mylist = QStringList() << s1 << s2 << s3; + \endcode +*/ + +/*! + \fn QStringList::QStringList (const char* i) + Constructs a string list consisting of the single latin-1 string \a i. +*/ + +/*! \fn QStringList::QStringList( const QValueList<QString>& l ) + + Constructs a new string list that is a copy of \a l. +*/ + +/*! + Sorts the list of strings in ascending order. + + Sorting is very fast. It uses the Qt Template Library's + efficient HeapSort implementation that operates in O(n*log n). +*/ +void QStringList::sort() +{ + qHeapSort(*this); +} + +/*! + Splits the string \a str using \a sep as separator. Returns the + list of strings. If \a allowEmptyEntries is TRUE, also empty + entries are inserted into the list, else not. So if you have + a string 'abc..d.e.', a list which contains 'abc', 'd', and 'e' + would be returned if \a allowEmptyEntries is FALSE, but + a list containing 'abc', '', 'd', 'e' and '' would be returned if + \a allowEmptyEntries is TRUE. + If \a str doesn't contain \a sep, a stringlist + with one item, which is the same as \a str, is returned. + + \sa join() +*/ + +QStringList QStringList::split( const QChar &sep, const QString &str, bool allowEmptyEntries ) +{ + return split( QString( sep ), str, allowEmptyEntries ); +} + +/*! + Splits the string \a str using \a sep as separator. Returns the + list of strings. If \a allowEmptyEntries is TRUE, also empty + entries are inserted into the list, else not. So if you have + a string 'abc..d.e.', a list which contains 'abc', 'd', and 'e' + would be returned if \a allowEmptyEntries is FALSE, but + a list containing 'abc', '', 'd', 'e' and '' would be returned if + \a allowEmptyEntries is TRUE. + If \a str doesn't contain \a sep, a stringlist + with one item, which is the same as \a str, is returned. + + \sa join() +*/ + +QStringList QStringList::split( const QString &sep, const QString &str, bool allowEmptyEntries ) +{ + QStringList lst; + + int j = 0; + int i = str.find( sep, j ); + + while ( i != -1 ) { + if ( str.mid( j, i - j ).length() > 0 ) + lst << str.mid( j, i - j ); + else if ( allowEmptyEntries ) + lst << QString::null; + j = i + sep.length(); + i = str.find( sep, j ); + } + + int l = str.length() - 1; + if ( str.mid( j, l - j + 1 ).length() > 0 ) + lst << str.mid( j, l - j + 1 ); + else if ( allowEmptyEntries ) + lst << QString::null; + + return lst; +} + +QStringList QStringList::split( const QCString &sep, const QCString &str, bool allowEmptyEntries ) +{ + return split(QString(sep.data()),QString(str.data()),allowEmptyEntries); +} + +/*! + Splits the string \a str using the regular expression \a sep as separator. Returns the + list of strings. If \a allowEmptyEntries is TRUE, also empty + entries are inserted into the list, else not. So if you have + a string 'abc..d.e.', a list which contains 'abc', 'd', and 'e' + would be returned if \a allowEmptyEntries is FALSE, but + a list containing 'abc', '', 'd', 'e' and '' would be returned if + \a allowEmptyEntries is TRUE. + If \a str doesn't contain \a sep, a stringlist + with one item, which is the same as \a str, is returned. + + \sa join() +*/ + +QStringList QStringList::split( const QRegExp &sep, const QString &str, bool allowEmptyEntries ) +{ + QStringList lst; + + int j = 0; + int len = 0; + int i = sep.match( str.data(), j, &len ); + + while ( i != -1 ) { + if ( str.mid( j, i - j ).length() > 0 ) + lst << str.mid( j, i - j ); + else if ( allowEmptyEntries ) + lst << QString::null; + j = i + len; + i = sep.match( str.data(), j, &len ); + } + + int l = str.length() - 1; + if ( str.mid( j, l - j + 1 ).length() > 0 ) + lst << str.mid( j, l - j + 1 ); + else if ( allowEmptyEntries ) + lst << QString::null; + + return lst; +} + +/*! + Returns a list of all strings containing the substring \a str. + + If \a cs is TRUE, the grep is done case sensitively, else not. +*/ + +QStringList QStringList::grep( const QString &str, bool cs ) const +{ + QStringList res; + for ( QStringList::ConstIterator it = begin(); it != end(); ++it ) + if ( (*it).contains( str, cs ) ) + res << *it; + + return res; +} + +/*! + Returns a list of all strings containing a substring that matches + the regular expression \a expr. +*/ + +QStringList QStringList::grep( const QRegExp &expr ) const +{ + QStringList res; + for ( QStringList::ConstIterator it = begin(); it != end(); ++it ) + if ( (*it).contains( expr ) ) + res << *it; + + return res; +} + +/*! + Joins the stringlist into a single string with each element + separated by \a sep. + + \sa split() +*/ +QString QStringList::join( const QString &sep ) const +{ + QString res; + bool alredy = FALSE; + for ( QStringList::ConstIterator it = begin(); it != end(); ++it ) { + if ( alredy ) + res += sep; + alredy = TRUE; + res += *it; + } + + return res; +} + +#ifndef QT_NO_DATASTREAM +Q_EXPORT QDataStream &operator>>( QDataStream & s, QStringList& l ) +{ + return s >> (QValueList<QString>&)l; +} + +Q_EXPORT QDataStream &operator<<( QDataStream & s, const QStringList& l ) +{ + return s << (const QValueList<QString>&)l; +} +#endif + +/*! + Converts from a QStrList (ASCII) to a QStringList (Unicode). +*/ +QStringList QStringList::fromStrList(const QStrList& ascii) +{ + QStringList res; + const char * s; + for ( QStrListIterator it(ascii); (s=it.current()); ++it ) + res << s; + return res; +} + +#endif //QT_NO_STRINGLIST diff --git a/trunk/qtools/qstringlist.h b/trunk/qtools/qstringlist.h new file mode 100644 index 0000000..3f9fbb2 --- /dev/null +++ b/trunk/qtools/qstringlist.h @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** +** Definition of QStringList class +** +** Created : 990406 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QSTRINGLIST_H +#define QSTRINGLIST_H + +#ifndef QT_H +#include "qvaluelist.h" +#include "qstring.h" +#include "qregexp.h" +#endif // QT_H + +#ifndef QT_NO_STRINGLIST + +class QStrList; + +class Q_EXPORT QStringList : public QValueList<QString> +{ +public: + QStringList() { } + QStringList( const QStringList& l ) : QValueList<QString>(l) { } + QStringList( const QValueList<QString>& l ) : QValueList<QString>(l) { } + QStringList( const QString& i ) { append(i); } +#ifndef QT_NO_CAST_ASCII + QStringList( const char* i ) { append(i); } +#endif + + static QStringList fromStrList(const QStrList&); + + void sort(); + + static QStringList split( const QString &sep, const QString &str, bool allowEmptyEntries = FALSE ); + static QStringList split( const QCString &sep, const QCString &str, bool allowEmptyEntries = FALSE ); + static QStringList split( const QChar &sep, const QString &str, bool allowEmptyEntries = FALSE ); + static QStringList split( const QRegExp &sep, const QString &str, bool allowEmptyEntries = FALSE ); + QString join( const QString &sep ) const; + + QStringList grep( const QString &str, bool cs = TRUE ) const; + QStringList grep( const QRegExp &expr ) const; +}; + +#ifndef QT_NO_DATASTREAM +class QDataStream; +extern Q_EXPORT QDataStream &operator>>( QDataStream &, QStringList& ); +extern Q_EXPORT QDataStream &operator<<( QDataStream &, const QStringList& ); +#endif +#endif // QT_NO_STRINGLIST +#endif // QSTRINGLIST_H diff --git a/trunk/qtools/qstrlist.doc b/trunk/qtools/qstrlist.doc new file mode 100644 index 0000000..751c6c2 --- /dev/null +++ b/trunk/qtools/qstrlist.doc @@ -0,0 +1,5 @@ +/**************************************************************************** +** +*****************************************************************************/ + +//typedef QListIterator<char> QStrListIterator; diff --git a/trunk/qtools/qstrlist.h b/trunk/qtools/qstrlist.h new file mode 100644 index 0000000..c6a1864 --- /dev/null +++ b/trunk/qtools/qstrlist.h @@ -0,0 +1,109 @@ +/**************************************************************************** +** +** +** Definition of QStrList, QStrIList and QStrListIterator classes +** +** Created : 920730 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QSTRLIST_H +#define QSTRLIST_H + +#ifndef QT_H +#include "qstring.h" +#include "qlist.h" +#include "qdatastream.h" +#endif // QT_H + + +#if defined(Q_TEMPLATEDLL) +template class Q_EXPORT QList<char>; +template class Q_EXPORT QListIterator<char>; +#endif + +typedef QList<char> QStrListBase; +typedef QListIterator<char> QStrListIterator; + + +class Q_EXPORT QStrList : public QStrListBase +{ +public: + QStrList( bool deepCopies=TRUE ) { dc = deepCopies; del_item = deepCopies; } + QStrList( const QStrList & ); + ~QStrList() { clear(); } + QStrList& operator=( const QStrList & ); + +private: + QCollection::Item newItem( QCollection::Item d ) { return dc ? qstrdup( (const char*)d ) : d; } + void deleteItem( QCollection::Item d ) { if ( del_item ) delete[] (char*)d; } + int compareItems( QCollection::Item s1, QCollection::Item s2 ) { return qstrcmp((const char*)s1, + (const char*)s2); } +#ifndef QT_NO_DATASTREAM + QDataStream &read( QDataStream &s, QCollection::Item &d ) + { s >> (char *&)d; return s; } + QDataStream &write( QDataStream &s, QCollection::Item d ) const + { return s << (const char *)d; } +#endif + bool dc; +}; + + +class Q_EXPORT QStrIList : public QStrList // case insensitive string list +{ +public: + QStrIList( bool deepCopies=TRUE ) : QStrList( deepCopies ) {} + ~QStrIList() { clear(); } +private: + int compareItems( QCollection::Item s1, QCollection::Item s2 ) + { return qstricmp((const char*)s1, + (const char*)s2); } +}; + + +inline QStrList & QStrList::operator=( const QStrList &strList ) +{ + clear(); + dc = strList.dc; + del_item = dc; + QStrListBase::operator=(strList); + return *this; +} + +inline QStrList::QStrList( const QStrList &strList ) + : QStrListBase( strList ) +{ + dc = FALSE; + operator=(strList); +} + + +#endif // QSTRLIST_H diff --git a/trunk/qtools/qstrvec.h b/trunk/qtools/qstrvec.h new file mode 100644 index 0000000..15d3abb --- /dev/null +++ b/trunk/qtools/qstrvec.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** +** Definition of QStrVec and QStrIVec classes +** +** Created : 931203 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QSTRVEC_H +#define QSTRVEC_H + +#ifndef QT_H +#include "qstring.h" +#include "qvector.h" +#include "qdatastream.h" +#endif // QT_H + + +#if defined(Q_TEMPLATEDLL) +template class Q_EXPORT QVector<char> +#endif + +typedef QVector<char> QStrVecBase; + + +class Q_EXPORT QStrVec : public QStrVecBase +{ +public: + QStrVec() { dc = TRUE; } + QStrVec( uint size, bool deepc = TRUE ) : QStrVecBase(size) {dc=deepc;} + ~QStrVec() { clear(); } +private: + Item newItem( Item d ) { return dc ? qstrdup( (const char*)d ) : d; } + void deleteItem( Item d ) { if ( dc ) delete[] (char*)d; } + int compareItems( Item s1, Item s2 ) + { return qstrcmp((const char*)s1, + (const char*)s2); } +#ifndef QT_NO_DATASTREAM + QDataStream &read( QDataStream &s, Item &d ) + { s >> (char *&)d; return s; } + QDataStream &write( QDataStream &s, Item d ) const + { return s << (const char*)d; } +#endif + bool dc; +}; + + +class Q_EXPORT QStrIVec : public QStrVec // case insensitive string vec +{ +public: + QStrIVec() {} + QStrIVec( uint size, bool dc = TRUE ) : QStrVec( size, dc ) {} + ~QStrIVec() { clear(); } +private: + int compareItems( Item s1, Item s2 ) + { return qstricmp((const char*)s1, + (const char*)s2); } +}; + + +#endif // QSTRVEC_H diff --git a/trunk/qtools/qtextcodec.cpp b/trunk/qtools/qtextcodec.cpp new file mode 100644 index 0000000..4eb8ba5 --- /dev/null +++ b/trunk/qtools/qtextcodec.cpp @@ -0,0 +1,2071 @@ +/**************************************************************************** +** +** +** Implementation of QTextCodec class +** +** Created : 981015 +** +** Copyright (C)1998-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "qtextcodec.h" +#ifndef QT_NO_TEXTCODEC + +#include "qlist.h" +#ifndef QT_NO_CODECS +#include "qutfcodec.h" +//#include "qgbkcodec.h" +//#include "qeucjpcodec.h" +//#include "qjiscodec.h" +//#include "qsjiscodec.h" +//#include "qeuckrcodec.h" +//#include "qbig5codec.h" +//#include "qrtlcodec.h" +//#include "qtsciicodec.h" +#endif + +#include "qfile.h" +#include "qstrlist.h" +#include "qstring.h" + +#include <stdlib.h> +#include <ctype.h> +#include <locale.h> + + +static QList<QTextCodec> * all = 0; +static bool destroying_is_ok; // starts out as 0 + +/*! Deletes all the created codecs. + + \warning Do not call this function. + + QApplication calls this just before exiting, to delete any + QTextCodec objects that may be lying around. Since various other + classes hold pointers to QTextCodec objects, it is not safe to call + this function earlier. + + If you are using the utility classes (like QString) but not using + QApplication, calling this function at the very end of your + application can be helpful to chasing down memory leaks, as + QTextCodec objects will not show up. +*/ + +void QTextCodec::deleteAllCodecs() +{ + if ( !all ) + return; + + destroying_is_ok = TRUE; + QList<QTextCodec> * ball = all; + all = 0; + ball->clear(); + delete ball; + destroying_is_ok = FALSE; +} + + +static void setupBuiltinCodecs(); + + +static void realSetup() +{ +#if defined(CHECK_STATE) + if ( destroying_is_ok ) + qWarning( "creating new codec during codec cleanup" ); +#endif + all = new QList<QTextCodec>; + all->setAutoDelete( TRUE ); + setupBuiltinCodecs(); +} + + +static inline void setup() +{ + if ( !all ) + realSetup(); +} + + +class QTextStatelessEncoder: public QTextEncoder { + const QTextCodec* codec; +public: + QTextStatelessEncoder(const QTextCodec*); + QCString fromUnicode(const QString& uc, int& lenInOut); +}; + + +class QTextStatelessDecoder : public QTextDecoder { + const QTextCodec* codec; +public: + QTextStatelessDecoder(const QTextCodec*); + QString toUnicode(const char* chars, int len); +}; + +QTextStatelessEncoder::QTextStatelessEncoder(const QTextCodec* c) : + codec(c) +{ +} + + +QCString QTextStatelessEncoder::fromUnicode(const QString& uc, int& lenInOut) +{ + return codec->fromUnicode(uc,lenInOut); +} + + +QTextStatelessDecoder::QTextStatelessDecoder(const QTextCodec* c) : + codec(c) +{ +} + + +QString QTextStatelessDecoder::toUnicode(const char* chars, int len) +{ + return codec->toUnicode(chars,len); +} + + + +// NOT REVISED +/*! + \class QTextCodec qtextcodec.h + \brief Provides conversion between text encodings. + + By making objects of subclasses of QTextCodec, support for + new text encodings can be added to Qt. + + The abstract virtual functions describe the encoder to the + system and the coder is used as required in the different + text file formats supported QTextStream and, under X11 for the + locale-specific character input and output (under Windows NT + codecs are not needed for GUI I/O since the system works + with Unicode already, and Windows 95/98 has built-in convertors + for the 8-bit local encoding). + + More recently created QTextCodec objects take precedence + over earlier ones. + + To add support for another 8-bit encoding to Qt, make a subclass + or QTextCodec and implement at least the following methods: + <dl> + <dt>\c const char* name() const + <dd>Return the official name for the encoding. + <dt>\c int mibEnum() const + <dd>Return the MIB enum for the encoding if it is listed in the + <a href=ftp://ftp.isi.edu/in-notes/iana/assignments/character-sets> + IANA character-sets encoding file</a>. + </dl> + If the encoding is multi-byte then it will have "state"; that is, + the interpretation of some bytes will be dependent on some preceding + bytes. For such an encoding, you will need to implement + <dl> + <dt> \c QTextDecoder* makeDecoder() const + <dd>Return a QTextDecoder that remembers incomplete multibyte + sequence prefixes or other required state. + </dl> + If the encoding does \e not require state, you should implement: + <dl> + <dt> \c QString toUnicode(const char* chars, int len) const + <dd>Converts \e len characters from \e chars to Unicode. + </dl> + The base QTextCodec class has default implementations of the above + two functions, <i>but they are mutually recursive</i>, so you must + re-implement at least one of them, or both for improved efficiency. + + For conversion from Unicode to 8-bit encodings, it is rarely necessary + to maintain state. However, two functions similar to the two above + are used for encoding: + <dl> + <dt> \c QTextEncoder* makeEncoder() const + <dd>Return a QTextDecoder. + <dt> \c QCString fromUnicode(const QString& uc, int& lenInOut ) const; + <dd>Converts \e lenInOut characters (of type QChar) from the start + of the string \a uc, returning a QCString result, and also returning + the \link QCString::length() length\endlink + of the result in lenInOut. + </dl> + Again, these are mutually recursive so only one needs to be implemented, + or both if better efficiency is possible. + + Finally, you must implement: + <dl> + <dt> \c int heuristicContentMatch(const char* chars, int len) const + <dd>Gives a value indicating how likely it is that \e len characters + from \e chars are in the encoding. + </dl> + A good model for this function is the + QWindowsLocalCodec::heuristicContentMatch function found in the Qt sources. + + A QTextCodec subclass might have improved performance if you also + re-implement: + <dl> + <dt> \c bool canEncode( QChar ) const + <dd>Test if a Unicode character can be encoded. + <dt> \c bool canEncode( const QString& ) const + <dd>Test if a string of Unicode characters can be encoded. + <dt> \c int heuristicNameMatch(const char* hint) const + <dd>Test if a possibly non-standard name is referring to the codec. + </dl> +*/ + + +/*! + Constructs a QTextCodec, making it of highest precedence. + The QTextCodec should always be constructed on the heap + (with new), and once constructed it becomes the responsibility + of Qt to delete it (which is done at QApplication destruction). +*/ +QTextCodec::QTextCodec() +{ + setup(); + all->insert(0,this); +} + + +/*! + Destructs the QTextCodec. Note that you should not delete + codecs yourself - once created they become the responsibility + of Qt to delete. +*/ +QTextCodec::~QTextCodec() +{ + if ( !destroying_is_ok ) + qWarning("QTextCodec::~QTextCodec() called by application"); + if ( all ) + all->remove( this ); +} + + +/*! + Returns a value indicating how likely this decoder is + for decoding some format that has the given name. + + A good match returns a positive number around + the length of the string. A bad match is negative. + + The default implementation calls simpleHeuristicNameMatch() + with the name of the codec. +*/ +int QTextCodec::heuristicNameMatch(const char* hint) const +{ + return simpleHeuristicNameMatch(name(),hint); +} + + +// returns a string cotnaining the letters and numbers from input, +// with a space separating run of a character class. e.g. "iso8859-1" +// becomes "iso 8859 1" +static QString lettersAndNumbers( const char * input ) +{ + QString result; + QChar c; + + while( input && *input ) { + c = *input; + if ( c.isLetter() || c.isNumber() ) + result += c.lower(); + if ( input[1] ) { + // add space at character class transition, except + // transition from upper-case to lower-case letter + QChar n( input[1] ); + if ( c.isLetter() && n.isLetter() ) { + if ( c == c.lower() && n == n.upper() ) + result += ' '; + } else if ( c.category() != n.category() ) { + result += ' '; + } + } + input++; + } + return result.simplifyWhiteSpace(); +} + +/*! + A simple utility function for heuristicNameMatch() - it + does some very minor character-skipping + so that almost-exact matches score high. +*/ +int QTextCodec::simpleHeuristicNameMatch(const char* name, const char* hint) +{ + // if they're the same, return a perfect score. + if ( name && hint && qstrcmp( name, hint ) == 0 ) + return qstrlen( hint ); + + // if the letters and numbers are the same, we have an "almost" + // perfect match. + QString h( lettersAndNumbers( hint ) ); + QString n( lettersAndNumbers( name ) ); + if ( h == n ) + return qstrlen( hint )-1; + + if ( h.stripWhiteSpace() == n.stripWhiteSpace() ) + return qstrlen( hint )-2; + + // could do some more here, but I don't think it's worth it + + return 0; +} + + +/*! + Returns the QTextCodec \a i places from the more recently + inserted, or NULL if there is no such QTextCodec. Thus, + codecForIndex(0) returns the most recently created QTextCodec. +*/ +QTextCodec* QTextCodec::codecForIndex(int i) +{ + setup(); + return (uint)i >= all->count() ? 0 : all->at(i); +} + + +/*! + Returns the QTextCodec which matches the + \link QTextCodec::mibEnum() MIBenum\endlink \a mib. +*/ +QTextCodec* QTextCodec::codecForMib(int mib) +{ + setup(); + QListIterator<QTextCodec> i(*all); + QTextCodec* result; + for ( ; (result=i); ++i ) { + if ( result->mibEnum()==mib ) + break; + } + return result; +} + + + + + +#ifdef _OS_WIN32_ +class QWindowsLocalCodec: public QTextCodec +{ +public: + QWindowsLocalCodec(); + ~QWindowsLocalCodec(); + + QString toUnicode(const char* chars, int len) const; + QCString fromUnicode(const QString& uc, int& lenInOut ) const; + + const char* name() const; + int mibEnum() const; + + int heuristicContentMatch(const char* chars, int len) const; +}; + +QWindowsLocalCodec::QWindowsLocalCodec() +{ +} + +QWindowsLocalCodec::~QWindowsLocalCodec() +{ +} + + +QString QWindowsLocalCodec::toUnicode(const char* chars, int len) const +{ + if ( len == 1 && chars ) { // Optimization; avoids allocation + char c[2]; + c[0] = *chars; + c[1] = 0; + return qt_winMB2QString( c, 2 ); + } + if ( len < 0 ) + return qt_winMB2QString( chars ); + QCString s(chars,len+1); + return qt_winMB2QString(s); +} + +QCString QWindowsLocalCodec::fromUnicode(const QString& uc, int& lenInOut ) const +{ + QCString r = qt_winQString2MB( uc, lenInOut ); + lenInOut = r.length(); + return r; +} + + +const char* QWindowsLocalCodec::name() const +{ + return "System"; +} + +int QWindowsLocalCodec::mibEnum() const +{ + return 0; +} + + +int QWindowsLocalCodec::heuristicContentMatch(const char* chars, int len) const +{ + // ### Not a bad default implementation? + QString t = toUnicode(chars,len); + int l = t.length(); + QCString mb = fromUnicode(t,l); + int i=0; + while ( i < len ) + if ( chars[i] == mb[i] ) + i++; + return i; +} + +#else + +/* locale names mostly copied from XFree86 */ +static const char * const iso8859_2locales[] = { + "croatian", "cs", "cs_CS", "cs_CZ","cz", "cz_CZ", "czech", "hr", + "hr_HR", "hu", "hu_HU", "hungarian", "pl", "pl_PL", "polish", "ro", + "ro_RO", "rumanian", "serbocroatian", "sh", "sh_SP", "sh_YU", "sk", + "sk_SK", "sl", "sl_CS", "sl_SI", "slovak", "slovene", "sr_SP", 0 }; + +static const char * const iso8859_3locales[] = { + "eo", 0 }; + +static const char * const iso8859_4locales[] = { + "ee", "ee_EE", "lt", "lt_LT", "lv", "lv_LV", 0 }; + +static const char * const iso8859_5locales[] = { + "bg", "bg_BG", "bulgarian", "mk", "mk_MK", + "sp", "sp_YU", 0 }; + +static const char * const iso8859_6locales[] = { + "ar_AA", "ar_SA", "arabic", 0 }; + +static const char * const iso8859_7locales[] = { + "el", "el_GR", "greek", 0 }; + +static const char * const iso8859_8locales[] = { + "hebrew", "he", "he_IL", "iw", "iw_IL", 0 }; + +static const char * const iso8859_9locales[] = { + "tr", "tr_TR", "turkish", 0 }; + +static const char * const iso8859_15locales[] = { + "fr", "fi", "french", "finnish", "et", "et_EE", 0 }; + +static const char * const koi8_ulocales[] = { + "uk", "uk_UA", "ru_UA", "ukrainian", 0 }; + +static const char * const tis_620locales[] = { + "th", "th_TH", "thai", 0 }; + + +static bool try_locale_list( const char * const locale[], const char * lang ) +{ + int i; + for( i=0; locale[i] && qstrcmp(locale[i], lang); i++ ) + { } + return locale[i] != 0; +} + +// For the probably_koi8_locales we have to look. the standard says +// these are 8859-5, but almsot all Russion users uses KOI8-R and +// incorrectly set $LANG to ru_RU. We'll check tolower() to see what +// tolower() thinks ru_RU means. + +// If you read the history, it seems that many Russians blame ISO and +// Peristroika for the confusion. +// +// The real bug is that some programs break if the user specifies +// ru_RU.KOI8-R. + +static const char * const probably_koi8_rlocales[] = { + "ru", "ru_SU", "ru_RU", "russian", 0 }; + +// this means ANY of these locale aliases. if they're aliases for +// different locales, the code breaks. +static QTextCodec * ru_RU_codec = 0; + +static QTextCodec * ru_RU_hack( const char * i ) { + if ( ! ru_RU_codec ) { + QCString origlocale = setlocale( LC_CTYPE, i ); + // unicode koi8r latin5 name + // 0x044E 0xC0 0xEE CYRILLIC SMALL LETTER YU + // 0x042E 0xE0 0xCE CYRILLIC CAPITAL LETTER YU + int latin5 = tolower( 0xCE ); + int koi8r = tolower( 0xE0 ); + if ( koi8r == 0xC0 && latin5 != 0xEE ) { + ru_RU_codec = QTextCodec::codecForName( "KOI8-R" ); + } else if ( koi8r != 0xC0 && latin5 == 0xEE ) { + ru_RU_codec = QTextCodec::codecForName( "ISO 8859-5" ); + } else { + // something else again... let's assume... *throws dice* + ru_RU_codec = QTextCodec::codecForName( "KOI8-R" ); + qWarning( "QTextCodec: using KOI8-R, probe failed (%02x %02x %s)", + koi8r, latin5, i ); + } + setlocale( LC_CTYPE, origlocale.data() ); + } + return ru_RU_codec; +} + +#endif + +static QTextCodec * localeMapper = 0; + +void qt_set_locale_codec( QTextCodec *codec ) +{ + localeMapper = codec; +} + +/*! Returns a pointer to the codec most suitable for this locale. */ + +QTextCodec* QTextCodec::codecForLocale() +{ + if ( localeMapper ) + return localeMapper; + + setup(); + +#ifdef _OS_WIN32_ + localeMapper = new QWindowsLocalCodec; +#else + // Very poorly defined and followed standards causes lots of code + // to try to get all the cases... + + char * lang = qstrdup( getenv("LANG") ); + + char * p = lang ? strchr( lang, '.' ) : 0; + if ( !p || *p != '.' ) { + // Some versions of setlocale return encoding, others not. + char *ctype = qstrdup( setlocale( LC_CTYPE, 0 ) ); + // Some Linux distributions have broken locales which will return + // "C" for LC_CTYPE + if ( qstrcmp( ctype, "C" ) == 0 ) { + delete [] ctype; + } else { + if ( lang ) + delete [] lang; + lang = ctype; + p = lang ? strchr( lang, '.' ) : 0; + } + } + + if( p && *p == '.' ) { + // if there is an encoding and we don't know it, we return 0 + // User knows what they are doing. Codecs will believe them. + localeMapper = codecForName( lang ); + if ( !localeMapper ) { + // Use or codec disagree. + localeMapper = codecForName( p+1 ); + } + } + if ( !localeMapper || !(p && *p == '.') ) { + // if there is none, we default to 8859-1 + // We could perhaps default to 8859-15. + if ( try_locale_list( iso8859_2locales, lang ) ) + localeMapper = codecForName( "ISO 8859-2" ); + else if ( try_locale_list( iso8859_3locales, lang ) ) + localeMapper = codecForName( "ISO 8859-3" ); + else if ( try_locale_list( iso8859_4locales, lang ) ) + localeMapper = codecForName( "ISO 8859-4" ); + else if ( try_locale_list( iso8859_5locales, lang ) ) + localeMapper = codecForName( "ISO 8859-5" ); + else if ( try_locale_list( iso8859_6locales, lang ) ) + localeMapper = codecForName( "ISO 8859-6-I" ); + else if ( try_locale_list( iso8859_7locales, lang ) ) + localeMapper = codecForName( "ISO 8859-7" ); + else if ( try_locale_list( iso8859_8locales, lang ) ) + localeMapper = codecForName( "ISO 8859-8-I" ); + else if ( try_locale_list( iso8859_9locales, lang ) ) + localeMapper = codecForName( "ISO 8859-9" ); + else if ( try_locale_list( iso8859_15locales, lang ) ) + localeMapper = codecForName( "ISO 8859-15" ); + else if ( try_locale_list( tis_620locales, lang ) ) + localeMapper = codecForName( "ISO 8859-11" ); + else if ( try_locale_list( koi8_ulocales, lang ) ) + localeMapper = codecForName( "KOI8-U" ); + else if ( try_locale_list( probably_koi8_rlocales, lang ) ) + localeMapper = ru_RU_hack( lang ); + else if (!lang || !(localeMapper = codecForName(lang) )) + localeMapper = codecForName( "ISO 8859-1" ); + } + delete[] lang; +#endif + + return localeMapper; +} + + +/*! + Searches all installed QTextCodec objects, returning the one + which best matches given name. Returns NULL if no codec has + a match closeness above \a accuracy. + + \sa heuristicNameMatch() +*/ +QTextCodec* QTextCodec::codecForName(const char* hint, int accuracy) +{ + setup(); + QListIterator<QTextCodec> i(*all); + QTextCodec* result = 0; + int best=accuracy; + for ( QTextCodec* cursor; (cursor=i); ++i ) { + int s = cursor->heuristicNameMatch(hint); + if ( s > best ) { + best = s; + result = cursor; + } + } + return result; +} + + +/*! + Searches all installed QTextCodec objects, returning the one + which most recognizes the given content. May return 0. + + Note that this is often a poor choice, since character + encodings often use most of the available character sequences, + and so only by linguistic analysis could a true match be made. + + \sa heuristicContentMatch() +*/ +QTextCodec* QTextCodec::codecForContent(const char* chars, int len) +{ + setup(); + QListIterator<QTextCodec> i(*all); + QTextCodec* result = 0; + int best=0; + for ( QTextCodec* cursor; (cursor=i); ++i ) { + int s = cursor->heuristicContentMatch(chars,len); + if ( s > best ) { + best = s; + result = cursor; + } + } + return result; +} + + +/*! + \fn const char* QTextCodec::name() const + Subclasses of QTextCodec must reimplement this function. It returns + the name of the encoding supported by the subclass. When choosing + a name for an encoding, consider these points: + <ul> + <li>On X11, heuristicNameMatch( const char * hint ) + is used to test if a the QTextCodec + can convert between Unicode and the encoding of a font + with encoding \e hint, such as "iso8859-1" for Latin-1 fonts, + "koi8-r" for Russian KOI8 fonts. + The default algorithm of heuristicNameMatch() uses name(). + <li>Some applications may use this function to present + encodings to the end user. + </ul> +*/ + +/*! + \fn int QTextCodec::mibEnum() const + + Subclasses of QTextCodec must reimplement this function. It returns the + MIBenum (see + <a href="ftp://ftp.isi.edu/in-notes/iana/assignments/character-sets"> + the IANA character-sets encoding file</a> for more information). + It is important that each QTextCodec subclass return the correct unique + value for this function. +*/ + + +/*! + \fn int QTextCodec::heuristicContentMatch(const char* chars, int len) const + + Subclasses of QTextCodec must reimplement this function. It examines + the first \a len bytes of \a chars and returns a value indicating how + likely it is that the string is a prefix of text encoded in the + encoding of the subclass. Any negative return value indicates that the text + is detectably not in the encoding (eg. it contains undefined characters). + A return value of 0 indicates that the text should be decoded with this + codec rather than as ASCII, but there + is no particular evidence. The value should range up to \a len. Thus, + most decoders will return -1, 0, or -\a len. + + The characters are not null terminated. + + \sa codecForContent(). +*/ + + +/*! + Creates a QTextDecoder which stores enough state to decode chunks + of char* data to create chunks of Unicode data. The default implementation + creates a stateless decoder, which is sufficient for only the simplest + encodings where each byte corresponds to exactly one Unicode character. + + The caller is responsible for deleting the returned object. +*/ +QTextDecoder* QTextCodec::makeDecoder() const +{ + return new QTextStatelessDecoder(this); +} + + +/*! + Creates a QTextEncoder which stores enough state to encode chunks + of Unicode data as char* data. The default implementation + creates a stateless encoder, which is sufficient for only the simplest + encodings where each Unicode character corresponds to exactly one char. + + The caller is responsible for deleting the returned object. +*/ +QTextEncoder* QTextCodec::makeEncoder() const +{ + return new QTextStatelessEncoder(this); +} + + +/*! + Subclasses of QTextCodec must reimplement this function or + makeDecoder(). It converts the first \a len characters of \a chars + to Unicode. + + The default implementation makes a decoder with makeDecoder() and + converts the input with that. Note that the default makeDecoder() + implementation makes a decoder that simply calls + this function, hence subclasses \e must reimplement one function or + the other to avoid infinite recursion. +*/ +QString QTextCodec::toUnicode(const char* chars, int len) const +{ + QTextDecoder* i = makeDecoder(); + QString result = i->toUnicode(chars,len); + delete i; + return result; +} + + +/*! + Subclasses of QTextCodec must reimplement either this function or + makeEncoder(). It converts the first \a lenInOut characters of \a + uc from Unicode to the encoding of the subclass. If \a lenInOut + is negative or too large, the length of \a uc is used instead. + + The value returned is the property of the caller, which is + responsible for deleting it with "delete []". The length of the + resulting Unicode character sequence is returned in \a lenInOut. + + The default implementation makes an encoder with makeEncoder() and + converts the input with that. Note that the default makeEncoder() + implementation makes an encoder that simply calls + this function, hence subclasses \e must reimplement one function or + the other to avoid infinite recursion. +*/ + +QCString QTextCodec::fromUnicode(const QString& uc, int& lenInOut) const +{ + QTextEncoder* i = makeEncoder(); + QCString result = i->fromUnicode(uc, lenInOut); + delete i; + return result; +} + +/*! + \overload QCString QTextCodec::fromUnicode(const QString& uc) const +*/ +QCString QTextCodec::fromUnicode(const QString& uc) const +{ + int l = uc.length(); + return fromUnicode(uc,l); +} + +/*! + \overload QString QTextCodec::toUnicode(const QByteArray& a, int len) const +*/ +QString QTextCodec::toUnicode(const QByteArray& a, int len) const +{ + int l = a.size(); + if( l > 0 && a.data()[l - 1] == '\0' ) l--; + l = QMIN( l, len ); + return toUnicode( a.data(), l ); +} + +/*! + \overload QString QTextCodec::toUnicode(const QByteArray& a) const +*/ +QString QTextCodec::toUnicode(const QByteArray& a) const +{ + int l = a.size(); + if( l > 0 && a.data()[l - 1] == '\0' ) l--; + return toUnicode( a.data(), l ); +} + +/*! + \overload QString QTextCodec::toUnicode(const char* chars) const +*/ +QString QTextCodec::toUnicode(const char* chars) const +{ + return toUnicode(chars,qstrlen(chars)); +} + +/*! + Returns TRUE if the unicode character \a ch can be fully encoded + with this codec. The default implementation tests if the result of + toUnicode(fromUnicode(ch)) is the original \a ch. Subclasses may be + able to improve the efficiency. +*/ +bool QTextCodec::canEncode( QChar ch ) const +{ + return toUnicode(fromUnicode(ch)) == ch; +} + +/*! + Returns TRUE if the unicode string \a s can be fully encoded + with this codec. The default implementation tests if the result of + toUnicode(fromUnicode(s)) is the original \a s. Subclasses may be + able to improve the efficiency. +*/ +bool QTextCodec::canEncode( const QString& s ) const +{ + return toUnicode(fromUnicode(s)) == s; +} + + + +/*! + \class QTextEncoder qtextcodec.h + \brief State-based encoder + + A QTextEncoder converts Unicode into another format, remembering + any state that is required between calls. + + \sa QTextCodec::makeEncoder() +*/ + +/*! + Destructs the encoder. +*/ +QTextEncoder::~QTextEncoder() +{ +} +/*! + \fn QCString QTextEncoder::fromUnicode(const QString& uc, int& lenInOut) + + Converts \a lenInOut characters (not bytes) from \a uc, producing + a QCString. \a lenInOut will also be set to the + \link QCString::length() length\endlink of the result (in bytes). + + The encoder is free to record state to use when subsequent calls are + made to this function (for example, it might change modes with escape + sequences if needed during the encoding of one string, then assume that + mode applies when a subsequent call begins). +*/ + +/*! + \class QTextDecoder qtextcodec.h + \brief State-based decoder + + A QTextEncoder converts a text format into Unicode, remembering + any state that is required between calls. + + \sa QTextCodec::makeEncoder() +*/ + + +/*! + Destructs the decoder. +*/ +QTextDecoder::~QTextDecoder() +{ +} + +/*! + \fn QString QTextDecoder::toUnicode(const char* chars, int len) + + Converts the first \a len bytes at \a chars to Unicode, returning the + result. + + If not all characters are used (eg. only part of a multi-byte + encoding is at the end of the characters), the decoder remembers + enough state to continue with the next call to this function. +*/ + +#define CHAINED 0xffff + +struct QMultiByteUnicodeTable { + // If multibyte, ignore unicode and index into multibyte + // with the next character. + QMultiByteUnicodeTable() : unicode(0xfffd), multibyte(0) { } + + ~QMultiByteUnicodeTable() + { + if ( multibyte ) + delete [] multibyte; + } + + ushort unicode; + QMultiByteUnicodeTable* multibyte; +}; + +#ifndef QT_NO_CODECS +static int getByte(char* &cursor) +{ + int byte = 0; + if ( *cursor ) { + if ( cursor[1] == 'x' ) + byte = strtol(cursor+2,&cursor,16); + else if ( cursor[1] == 'd' ) + byte = strtol(cursor+2,&cursor,10); + else + byte = strtol(cursor+2,&cursor,8); + } + return byte&0xff; +} + +class QTextCodecFromIOD; + +class QTextCodecFromIODDecoder : public QTextDecoder { + const QTextCodecFromIOD* codec; + QMultiByteUnicodeTable* mb; +public: + QTextCodecFromIODDecoder(const QTextCodecFromIOD* c); + QString toUnicode(const char* chars, int len); +}; + +class QTextCodecFromIOD : public QTextCodec { + friend class QTextCodecFromIODDecoder; + + QCString n; + + // If from_unicode_page[row()][cell()] is 0 and from_unicode_page_multibyte, + // use from_unicode_page_multibyte[row()][cell()] as string. + char** from_unicode_page; + char*** from_unicode_page_multibyte; + char unkn; + + // Only one of these is used + ushort* to_unicode; + QMultiByteUnicodeTable* to_unicode_multibyte; + int max_bytes_per_char; + QStrList aliases; + + bool stateless() const { return !to_unicode_multibyte; } + +public: + QTextCodecFromIOD(QIODevice* iod) + { + from_unicode_page = 0; + to_unicode_multibyte = 0; + to_unicode = 0; + from_unicode_page_multibyte = 0; + max_bytes_per_char = 1; + + const int maxlen=100; + char line[maxlen]; + char esc='\\'; + char comm='%'; + bool incmap = FALSE; + while (iod->readLine(line,maxlen) > 0) { + if (0==qstrnicmp(line,"<code_set_name>",15)) + n = line+15; + else if (0==qstrnicmp(line,"<escape_char> ",14)) + esc = line[14]; + else if (0==qstrnicmp(line,"<comment_char> ",15)) + comm = line[15]; + else if (line[0]==comm && 0==qstrnicmp(line+1," alias ",7)) { + aliases.append(line+8); + } else if (0==qstrnicmp(line,"CHARMAP",7)) { + if (!from_unicode_page) { + from_unicode_page = new char*[256]; + for (int i=0; i<256; i++) + from_unicode_page[i]=0; + } + if (!to_unicode) { + to_unicode = new ushort[256]; + } + incmap = TRUE; + } else if (0==qstrnicmp(line,"END CHARMAP",11)) + break; + else if (incmap) { + char* cursor = line; + int byte=0,unicode=-1; + ushort* mb_unicode=0; + const int maxmb=8; // more -> we'll need to improve datastructures + char mb[maxmb+1]; + int nmb=0; + + while (*cursor) { + if (cursor[0]=='<' && cursor[1]=='U' && + cursor[2]>='0' && cursor[2]<='9' && + cursor[3]>='0' && cursor[3]<='9') { + + unicode = strtol(cursor+2,&cursor,16); + + } else if (*cursor==esc) { + + byte = getByte(cursor); + + if ( *cursor == esc ) { + if ( !to_unicode_multibyte ) { + to_unicode_multibyte = + new QMultiByteUnicodeTable[256]; + for (int i=0; i<256; i++) { + to_unicode_multibyte[i].unicode = + to_unicode[i]; + to_unicode_multibyte[i].multibyte = 0; + } + delete [] to_unicode; + to_unicode = 0; + } + QMultiByteUnicodeTable* mbut = + to_unicode_multibyte+byte; + mb[nmb++] = byte; + while ( nmb < maxmb && *cursor == esc ) { + // Always at least once + + mbut->unicode = CHAINED; + byte = getByte(cursor); + mb[nmb++] = byte; + if (!mbut->multibyte) { + mbut->multibyte = + new QMultiByteUnicodeTable[256]; + } + mbut = mbut->multibyte+byte; + mb_unicode = & mbut->unicode; + } + + if ( nmb > max_bytes_per_char ) + max_bytes_per_char = nmb; + } + } else { + cursor++; + } + } + + if (unicode >= 0 && unicode <= 0xffff) + { + QChar ch((ushort)unicode); + if (!from_unicode_page[ch.row()]) { + from_unicode_page[ch.row()] = new char[256]; + for (int i=0; i<256; i++) + from_unicode_page[ch.row()][i]=0; + } + if ( mb_unicode ) { + from_unicode_page[ch.row()][ch.cell()] = 0; + if (!from_unicode_page_multibyte) { + from_unicode_page_multibyte = new char**[256]; + for (int i=0; i<256; i++) + from_unicode_page_multibyte[i]=0; + } + if (!from_unicode_page_multibyte[ch.row()]) { + from_unicode_page_multibyte[ch.row()] = new char*[256]; + for (int i=0; i<256; i++) + from_unicode_page_multibyte[ch.row()][i] = 0; + } + mb[nmb++] = 0; + from_unicode_page_multibyte[ch.row()][ch.cell()] + = qstrdup(mb); + *mb_unicode = unicode; + } else { + from_unicode_page[ch.row()][ch.cell()] = (char)byte; + if ( to_unicode ) + to_unicode[byte] = unicode; + else + to_unicode_multibyte[byte].unicode = unicode; + } + } else { + } + } + } + n = n.stripWhiteSpace(); + + unkn = '?'; // ##### Might be a bad choice. + } + + ~QTextCodecFromIOD() + { + if ( from_unicode_page ) { + for (int i=0; i<256; i++) + if (from_unicode_page[i]) + delete [] from_unicode_page[i]; + } + if ( from_unicode_page_multibyte ) { + for (int i=0; i<256; i++) + if (from_unicode_page_multibyte[i]) + for (int j=0; j<256; j++) + if (from_unicode_page_multibyte[i][j]) + delete [] from_unicode_page_multibyte[i][j]; + } + if ( to_unicode ) + delete [] to_unicode; + if ( to_unicode_multibyte ) + delete [] to_unicode_multibyte; + } + + bool ok() const + { + return !!from_unicode_page; + } + + QTextDecoder* makeDecoder() const + { + if ( stateless() ) + return QTextCodec::makeDecoder(); + else + return new QTextCodecFromIODDecoder(this); + } + + const char* name() const + { + return n; + } + + int mibEnum() const + { + return 0; // #### Unknown. + } + + int heuristicContentMatch(const char*, int) const + { + return 0; + } + + int heuristicNameMatch(const char* hint) const + { + int bestr = QTextCodec::heuristicNameMatch(hint); + QStrListIterator it(aliases); + char* a; + while ((a=it.current())) { + ++it; + int r = simpleHeuristicNameMatch(a,hint); + if (r > bestr) + bestr = r; + } + return bestr; + } + + QString toUnicode(const char* chars, int len) const + { + const uchar* uchars = (const uchar*)chars; + QString result; + QMultiByteUnicodeTable* multibyte=to_unicode_multibyte; + if ( multibyte ) { + while (len--) { + QMultiByteUnicodeTable& mb = multibyte[*uchars]; + if ( mb.multibyte ) { + // Chained multi-byte + multibyte = mb.multibyte; + } else { + result += QChar(mb.unicode); + multibyte=to_unicode_multibyte; + } + uchars++; + } + } else { + while (len--) + result += QChar(to_unicode[*uchars++]); + } + return result; + } + + QCString fromUnicode(const QString& uc, int& lenInOut) const + { + if (lenInOut > (int)uc.length()) + lenInOut = uc.length(); + int rlen = lenInOut*max_bytes_per_char; + QCString rstr(rlen); + char* cursor = rstr.data(); + char* s=0; + int l = lenInOut; + int lout = 0; + for (int i=0; i<l; i++) { + QChar ch = uc[i]; + if ( ch == QChar::null ) { + // special + *cursor++ = 0; + } else if ( from_unicode_page[ch.row()] && + from_unicode_page[ch.row()][ch.cell()] ) + { + *cursor++ = from_unicode_page[ch.row()][ch.cell()]; + lout++; + } else if ( from_unicode_page_multibyte && + from_unicode_page_multibyte[ch.row()] && + (s=from_unicode_page_multibyte[ch.row()][ch.cell()]) ) + { + while (*s) { + *cursor++ = *s++; + lout++; + } + } else { + *cursor++ = unkn; + lout++; + } + } + *cursor = 0; + lenInOut = lout; + return rstr; + } +}; + +QTextCodecFromIODDecoder::QTextCodecFromIODDecoder(const QTextCodecFromIOD* c) : + codec(c) +{ + mb = codec->to_unicode_multibyte; +} + +QString QTextCodecFromIODDecoder::toUnicode(const char* chars, int len) +{ + const uchar* uchars = (const uchar*)chars; + QString result; + while (len--) { + QMultiByteUnicodeTable& t = mb[*uchars]; + if ( t.multibyte ) { + // Chained multi-byte + mb = t.multibyte; + } else { + if ( t.unicode ) + result += QChar(t.unicode); + mb=codec->to_unicode_multibyte; + } + uchars++; + } + return result; +} + +/*! + Reads a POSIX2 charmap definition from \a iod. + The parser recognizes the following lines: +<pre> + <code_set_name> <i>name</i> + <escape_char> <i>character</i> + % alias <i>alias</i> + CHARMAP + <<i>token</i>> /x<i>hexbyte</i> <U<i>unicode</i>> ... + <<i>token</i>> /d<i>decbyte</i> <U<i>unicode</i>> ... + <<i>token</i>> /<i>octbyte</i> <U<i>unicode</i>> ... + <<i>token</i>> /<i>any</i>/<i>any</i>... <U<i>unicode</i>> ... + END CHARMAP +</pre> + + The resulting QTextCodec is returned (and also added to the + global list of codecs). The name() of the result is taken + from the code_set_name. + + Note that a codec constructed in this way uses much more memory + and is slower than a hand-written QTextCodec subclass, since + tables in code are in memory shared by all applications simultaneously + using Qt. + + \sa loadCharmapFile() +*/ +QTextCodec* QTextCodec::loadCharmap(QIODevice* iod) +{ + QTextCodecFromIOD* r = new QTextCodecFromIOD(iod); + if ( !r->ok() ) { + delete r; + r = 0; + } + return r; +} + +/*! + A convenience function for loadCharmap(). +*/ +QTextCodec* QTextCodec::loadCharmapFile(QString filename) +{ + QFile f(filename); + if (f.open(IO_ReadOnly)) { + QTextCodecFromIOD* r = new QTextCodecFromIOD(&f); + if ( !r->ok() ) + delete r; + else + return r; + } + return 0; +} +#endif //QT_NO_CODECS + + +/*! + Returns a string representing the current language. +*/ + +const char* QTextCodec::locale() +{ + static QCString lang; + if ( lang.isEmpty() ) { + lang = getenv( "LANG" ); //########Windows?? + if ( lang.isEmpty() ) + lang = "C"; + } + return lang; +} + + + +#ifndef QT_NO_CODECS + +class QSimpleTextCodec: public QTextCodec +{ +public: + QSimpleTextCodec( int ); + ~QSimpleTextCodec(); + + QString toUnicode(const char* chars, int len) const; + QCString fromUnicode(const QString& uc, int& lenInOut ) const; + + const char* name() const; + int mibEnum() const; + + int heuristicContentMatch(const char* chars, int len) const; + + int heuristicNameMatch(const char* hint) const; + +private: + int forwardIndex; +}; + + +#define LAST_MIB 2259 + +static struct { + const char * cs; + int mib; + Q_UINT16 values[128]; +} unicodevalues[] = { + // from RFC 1489, ftp://ftp.isi.edu/in-notes/rfc1489.txt + { "KOI8-R", 2084, + { 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 } }, + // /**/ - The BULLET OPERATOR is confused. Some people think + // it should be 0x2022 (BULLET). + + // from RFC 2319, ftp://ftp.isi.edu/in-notes/rfc2319.txt + { "KOI8-U", 2088, + { 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, 0x0454, 0x2554, 0x0456, 0x0457, + 0x2557, 0x2558, 0x2559, 0x255A, 0x255B, 0x0491, 0x255D, 0x255E, + 0x255F, 0x2560, 0x2561, 0x0401, 0x0404, 0x2563, 0x0406, 0x0407, + 0x2566, 0x2567, 0x2568, 0x2569, 0x256A, 0x0490, 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 } }, + + // next bits generated from tables on the Unicode 2.0 CD. we can + // use these tables since this is part of the transition to using + // unicode everywhere in qt. + + // $ for A in 8 9 A B C D E F ; do for B in 0 1 2 3 4 5 6 7 8 9 A B C D E F ; do echo 0x${A}${B} 0xFFFD ; done ; done > /tmp/digits ; for a in 8859-* ; do ( awk '/^0x[89ABCDEF]/{ print $1, $2 }' < $a ; cat /tmp/digits ) | sort | uniq -w4 | cut -c6- | paste '-d ' - - - - - - - - | sed -e 's/ /, /g' -e 's/$/,/' -e '$ s/,$/} },/' -e '1 s/^/{ /' > ~/tmp/$a ; done + + // then I inserted the files manually. + { "ISO 8859-2", 5, + { 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, 0x0104, 0x02D8, 0x0141, 0x00A4, 0x013D, 0x015A, 0x00A7, + 0x00A8, 0x0160, 0x015E, 0x0164, 0x0179, 0x00AD, 0x017D, 0x017B, + 0x00B0, 0x0105, 0x02DB, 0x0142, 0x00B4, 0x013E, 0x015B, 0x02C7, + 0x00B8, 0x0161, 0x015F, 0x0165, 0x017A, 0x02DD, 0x017E, 0x017C, + 0x0154, 0x00C1, 0x00C2, 0x0102, 0x00C4, 0x0139, 0x0106, 0x00C7, + 0x010C, 0x00C9, 0x0118, 0x00CB, 0x011A, 0x00CD, 0x00CE, 0x010E, + 0x0110, 0x0143, 0x0147, 0x00D3, 0x00D4, 0x0150, 0x00D6, 0x00D7, + 0x0158, 0x016E, 0x00DA, 0x0170, 0x00DC, 0x00DD, 0x0162, 0x00DF, + 0x0155, 0x00E1, 0x00E2, 0x0103, 0x00E4, 0x013A, 0x0107, 0x00E7, + 0x010D, 0x00E9, 0x0119, 0x00EB, 0x011B, 0x00ED, 0x00EE, 0x010F, + 0x0111, 0x0144, 0x0148, 0x00F3, 0x00F4, 0x0151, 0x00F6, 0x00F7, + 0x0159, 0x016F, 0x00FA, 0x0171, 0x00FC, 0x00FD, 0x0163, 0x02D9} }, + { "ISO 8859-3", 6, + { 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, 0x0126, 0x02D8, 0x00A3, 0x00A4, 0xFFFD, 0x0124, 0x00A7, + 0x00A8, 0x0130, 0x015E, 0x011E, 0x0134, 0x00AD, 0xFFFD, 0x017B, + 0x00B0, 0x0127, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x0125, 0x00B7, + 0x00B8, 0x0131, 0x015F, 0x011F, 0x0135, 0x00BD, 0xFFFD, 0x017C, + 0x00C0, 0x00C1, 0x00C2, 0xFFFD, 0x00C4, 0x010A, 0x0108, 0x00C7, + 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, + 0xFFFD, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x0120, 0x00D6, 0x00D7, + 0x011C, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x016C, 0x015C, 0x00DF, + 0x00E0, 0x00E1, 0x00E2, 0xFFFD, 0x00E4, 0x010B, 0x0109, 0x00E7, + 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, + 0xFFFD, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x0121, 0x00F6, 0x00F7, + 0x011D, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x016D, 0x015D, 0x02D9} }, + { "ISO 8859-4", 7, + { 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, 0x0104, 0x0138, 0x0156, 0x00A4, 0x0128, 0x013B, 0x00A7, + 0x00A8, 0x0160, 0x0112, 0x0122, 0x0166, 0x00AD, 0x017D, 0x00AF, + 0x00B0, 0x0105, 0x02DB, 0x0157, 0x00B4, 0x0129, 0x013C, 0x02C7, + 0x00B8, 0x0161, 0x0113, 0x0123, 0x0167, 0x014A, 0x017E, 0x014B, + 0x0100, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x012E, + 0x010C, 0x00C9, 0x0118, 0x00CB, 0x0116, 0x00CD, 0x00CE, 0x012A, + 0x0110, 0x0145, 0x014C, 0x0136, 0x00D4, 0x00D5, 0x00D6, 0x00D7, + 0x00D8, 0x0172, 0x00DA, 0x00DB, 0x00DC, 0x0168, 0x016A, 0x00DF, + 0x0101, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x012F, + 0x010D, 0x00E9, 0x0119, 0x00EB, 0x0117, 0x00ED, 0x00EE, 0x012B, + 0x0111, 0x0146, 0x014D, 0x0137, 0x00F4, 0x00F5, 0x00F6, 0x00F7, + 0x00F8, 0x0173, 0x00FA, 0x00FB, 0x00FC, 0x0169, 0x016B, 0x02D9} }, + { "ISO 8859-5", 8, + { 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0406, 0x0407, + 0x0408, 0x0409, 0x040A, 0x040B, 0x040C, 0x00AD, 0x040E, 0x040F, + 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, + 0x2116, 0x0451, 0x0452, 0x0453, 0x0454, 0x0455, 0x0456, 0x0457, + 0x0458, 0x0459, 0x045A, 0x045B, 0x045C, 0x00A7, 0x045E, 0x045F} }, + { "ISO 8859-6-I", 82, + { 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, 0xFFFD, 0xFFFD, 0xFFFD, 0x00A4, 0xFFFD, 0xFFFD, 0xFFFD, + 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0x060C, 0x00AD, 0xFFFD, 0xFFFD, + 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, + 0xFFFD, 0xFFFD, 0xFFFD, 0x061B, 0xFFFD, 0xFFFD, 0xFFFD, 0x061F, + 0xFFFD, 0x0621, 0x0622, 0x0623, 0x0624, 0x0625, 0x0626, 0x0627, + 0x0628, 0x0629, 0x062A, 0x062B, 0x062C, 0x062D, 0x062E, 0x062F, + 0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x0636, 0x0637, + 0x0638, 0x0639, 0x063A, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, + 0x0640, 0x0641, 0x0642, 0x0643, 0x0644, 0x0645, 0x0646, 0x0647, + 0x0648, 0x0649, 0x064A, 0x064B, 0x064C, 0x064D, 0x064E, 0x064F, + 0x0650, 0x0651, 0x0652, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, + 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD} }, + { "ISO 8859-7", 10, + { 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, 0x2018, 0x2019, 0x00A3, 0xFFFD, 0xFFFD, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0xFFFD, 0x00AB, 0x00AC, 0x00AD, 0xFFFD, 0x2015, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x0384, 0x0385, 0x0386, 0x00B7, + 0x0388, 0x0389, 0x038A, 0x00BB, 0x038C, 0x00BD, 0x038E, 0x038F, + 0x0390, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, + 0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F, + 0x03A0, 0x03A1, 0xFFFD, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7, + 0x03A8, 0x03A9, 0x03AA, 0x03AB, 0x03AC, 0x03AD, 0x03AE, 0x03AF, + 0x03B0, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, + 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, + 0x03C0, 0x03C1, 0x03C2, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7, + 0x03C8, 0x03C9, 0x03CA, 0x03CB, 0x03CC, 0x03CD, 0x03CE, 0xFFFD} }, + { "ISO 8859-8-I", 85, + { 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, 0xFFFD, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x00D7, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x203E, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00B8, 0x00B9, 0x00F7, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0xFFFD, + 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, + 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, + 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, + 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0x2017, + 0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7, + 0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF, + 0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7, + 0x05E8, 0x05E9, 0x05EA, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD} }, + { "ISO 8859-9", 12, + { 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF, + 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, + 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, + 0x011E, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, + 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x0130, 0x015E, 0x00DF, + 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, + 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, + 0x011F, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, + 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x0131, 0x015F, 0x00FF} }, + { "ISO 8859-10", 13, + { 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, 0x0104, 0x0112, 0x0122, 0x012A, 0x0128, 0x0136, 0x00A7, + 0x013B, 0x0110, 0x0160, 0x0166, 0x017D, 0x00AD, 0x016A, 0x014A, + 0x00B0, 0x0105, 0x0113, 0x0123, 0x012B, 0x0129, 0x0137, 0x00B7, + 0x013C, 0x0111, 0x0161, 0x0167, 0x017E, 0x2015, 0x016B, 0x014B, + 0x0100, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x012E, + 0x010C, 0x00C9, 0x0118, 0x00CB, 0x0116, 0x00CD, 0x00CE, 0x00CF, + 0x00D0, 0x0145, 0x014C, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x0168, + 0x00D8, 0x0172, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF, + 0x0101, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x012F, + 0x010D, 0x00E9, 0x0119, 0x00EB, 0x0117, 0x00ED, 0x00EE, 0x00EF, + 0x00F0, 0x0146, 0x014D, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x0169, + 0x00F8, 0x0173, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x0138} }, + { "ISO 8859-13", 109, + { 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, 0x201D, 0x00A2, 0x00A3, 0x00A4, 0x201E, 0x00A6, 0x00A7, + 0x00D8, 0x00A9, 0x0156, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00C6, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x201C, 0x00B5, 0x00B6, 0x00B7, + 0x00F8, 0x00B9, 0x0157, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00E6, + 0x0104, 0x012E, 0x0100, 0x0106, 0x00C4, 0x00C5, 0x0118, 0x0112, + 0x010C, 0x00C9, 0x0179, 0x0116, 0x0122, 0x0136, 0x012A, 0x013B, + 0x0160, 0x0143, 0x0145, 0x00D3, 0x014C, 0x00D5, 0x00D6, 0x00D7, + 0x0172, 0x0141, 0x015A, 0x016A, 0x00DC, 0x017B, 0x017D, 0x00DF, + 0x0105, 0x012F, 0x0101, 0x0107, 0x00E4, 0x00E5, 0x0119, 0x0113, + 0x010D, 0x00E9, 0x017A, 0x0117, 0x0123, 0x0137, 0x012B, 0x013C, + 0x0161, 0x0144, 0x0146, 0x00F3, 0x014D, 0x00F5, 0x00F6, 0x00F7, + 0x0173, 0x0142, 0x015B, 0x016B, 0x00FC, 0x017C, 0x017E, 0x2019} }, + { "ISO 8859-14", 110, + { 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, 0x1E02, 0x1E03, 0x00A3, 0x010A, 0x010B, 0x1E0A, 0x00A7, + 0x1E80, 0x00A9, 0x1E82, 0x1E0B, 0x1EF2, 0x00AD, 0x00AE, 0x0178, + 0x1E1E, 0x1E1F, 0x0120, 0x0121, 0x1E40, 0x1E41, 0x00B6, 0x1E56, + 0x1E81, 0x1E57, 0x1E83, 0x1E60, 0x1EF3, 0x1E84, 0x1E85, 0x1E61, + 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, + 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, + 0x0174, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x1E6A, + 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x0176, 0x00DF, + 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, + 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, + 0x0175, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x1E6B, + 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x0177, 0x00FF} }, + { "ISO 8859-15", 111, + { 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x20AC, 0x00A5, 0x0160, 0x00A7, + 0x0161, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x017D, 0x00B5, 0x00B6, 0x00B7, + 0x017E, 0x00B9, 0x00BA, 0x00BB, 0x0152, 0x0153, 0x0178, 0x00BF, + 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, + 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, + 0x00D0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, + 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF, + 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, + 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, + 0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, + 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF} }, + + // next bits generated again from tables on the Unicode 3.0 CD. + + // $ for a in CP* ; do ( awk '/^0x[89ABCDEF]/{ print $1, $2 }' < $a ) | sort | sed -e 's/#UNDEF.*$/0xFFFD/' | cut -c6- | paste '-d ' - - - - - - - - | sed -e 's/ /, /g' -e 's/$/,/' -e '$ s/,$/} },/' -e '1 s/^/{ /' > ~/tmp/$a ; done + + { "CP 874", 0, //### what is the mib? + { 0x20AC, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0x2026, 0xFFFD, 0xFFFD, + 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, + 0xFFFD, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, + 0x00A0, 0x0E01, 0x0E02, 0x0E03, 0x0E04, 0x0E05, 0x0E06, 0x0E07, + 0x0E08, 0x0E09, 0x0E0A, 0x0E0B, 0x0E0C, 0x0E0D, 0x0E0E, 0x0E0F, + 0x0E10, 0x0E11, 0x0E12, 0x0E13, 0x0E14, 0x0E15, 0x0E16, 0x0E17, + 0x0E18, 0x0E19, 0x0E1A, 0x0E1B, 0x0E1C, 0x0E1D, 0x0E1E, 0x0E1F, + 0x0E20, 0x0E21, 0x0E22, 0x0E23, 0x0E24, 0x0E25, 0x0E26, 0x0E27, + 0x0E28, 0x0E29, 0x0E2A, 0x0E2B, 0x0E2C, 0x0E2D, 0x0E2E, 0x0E2F, + 0x0E30, 0x0E31, 0x0E32, 0x0E33, 0x0E34, 0x0E35, 0x0E36, 0x0E37, + 0x0E38, 0x0E39, 0x0E3A, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0x0E3F, + 0x0E40, 0x0E41, 0x0E42, 0x0E43, 0x0E44, 0x0E45, 0x0E46, 0x0E47, + 0x0E48, 0x0E49, 0x0E4A, 0x0E4B, 0x0E4C, 0x0E4D, 0x0E4E, 0x0E4F, + 0x0E50, 0x0E51, 0x0E52, 0x0E53, 0x0E54, 0x0E55, 0x0E56, 0x0E57, + 0x0E58, 0x0E59, 0x0E5A, 0x0E5B, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD} }, + { "CP 1250", 2250, + { 0x20AC, 0xFFFD, 0x201A, 0xFFFD, 0x201E, 0x2026, 0x2020, 0x2021, + 0xFFFD, 0x2030, 0x0160, 0x2039, 0x015A, 0x0164, 0x017D, 0x0179, + 0xFFFD, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0xFFFD, 0x2122, 0x0161, 0x203A, 0x015B, 0x0165, 0x017E, 0x017A, + 0x00A0, 0x02C7, 0x02D8, 0x0141, 0x00A4, 0x0104, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x015E, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x017B, + 0x00B0, 0x00B1, 0x02DB, 0x0142, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00B8, 0x0105, 0x015F, 0x00BB, 0x013D, 0x02DD, 0x013E, 0x017C, + 0x0154, 0x00C1, 0x00C2, 0x0102, 0x00C4, 0x0139, 0x0106, 0x00C7, + 0x010C, 0x00C9, 0x0118, 0x00CB, 0x011A, 0x00CD, 0x00CE, 0x010E, + 0x0110, 0x0143, 0x0147, 0x00D3, 0x00D4, 0x0150, 0x00D6, 0x00D7, + 0x0158, 0x016E, 0x00DA, 0x0170, 0x00DC, 0x00DD, 0x0162, 0x00DF, + 0x0155, 0x00E1, 0x00E2, 0x0103, 0x00E4, 0x013A, 0x0107, 0x00E7, + 0x010D, 0x00E9, 0x0119, 0x00EB, 0x011B, 0x00ED, 0x00EE, 0x010F, + 0x0111, 0x0144, 0x0148, 0x00F3, 0x00F4, 0x0151, 0x00F6, 0x00F7, + 0x0159, 0x016F, 0x00FA, 0x0171, 0x00FC, 0x00FD, 0x0163, 0x02D9} }, + { "CP 1251", 2251, + { 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} }, + { "CP 1252", 2252, + { 0x20AC, 0xFFFD, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, + 0x02C6, 0x2030, 0x0160, 0x2039, 0x0152, 0xFFFD, 0x017D, 0xFFFD, + 0xFFFD, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0x02DC, 0x2122, 0x0161, 0x203A, 0x0153, 0xFFFD, 0x017E, 0x0178, + 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF, + 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, + 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, + 0x00D0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, + 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF, + 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, + 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, + 0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, + 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF} }, + { "CP 1253", 2253, + { 0x20AC, 0xFFFD, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, + 0xFFFD, 0x2030, 0xFFFD, 0x2039, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, + 0xFFFD, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0xFFFD, 0x2122, 0xFFFD, 0x203A, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, + 0x00A0, 0x0385, 0x0386, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0xFFFD, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x2015, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x0384, 0x00B5, 0x00B6, 0x00B7, + 0x0388, 0x0389, 0x038A, 0x00BB, 0x038C, 0x00BD, 0x038E, 0x038F, + 0x0390, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, + 0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F, + 0x03A0, 0x03A1, 0xFFFD, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7, + 0x03A8, 0x03A9, 0x03AA, 0x03AB, 0x03AC, 0x03AD, 0x03AE, 0x03AF, + 0x03B0, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, + 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, + 0x03C0, 0x03C1, 0x03C2, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7, + 0x03C8, 0x03C9, 0x03CA, 0x03CB, 0x03CC, 0x03CD, 0x03CE, 0xFFFD} }, + { "CP 1254", 2254, + { 0x20AC, 0xFFFD, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, + 0x02C6, 0x2030, 0x0160, 0x2039, 0x0152, 0xFFFD, 0xFFFD, 0xFFFD, + 0xFFFD, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0x02DC, 0x2122, 0x0161, 0x203A, 0x0153, 0xFFFD, 0xFFFD, 0x0178, + 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF, + 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, + 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, + 0x011E, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, + 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x0130, 0x015E, 0x00DF, + 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, + 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, + 0x011F, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, + 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x0131, 0x015F, 0x00FF} }, + { "CP 1255", 2255, + { 0x20AC, 0xFFFD, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, + 0x02C6, 0x2030, 0xFFFD, 0x2039, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, + 0xFFFD, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0x02DC, 0x2122, 0xFFFD, 0x203A, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, + 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x20AA, 0x00A5, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x00D7, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00B8, 0x00B9, 0x00F7, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF, + 0x05B0, 0x05B1, 0x05B2, 0x05B3, 0x05B4, 0x05B5, 0x05B6, 0x05B7, + 0x05B8, 0x05B9, 0xFFFD, 0x05BB, 0x05BC, 0x05BD, 0x05BE, 0x05BF, + 0x05C0, 0x05C1, 0x05C2, 0x05C3, 0x05F0, 0x05F1, 0x05F2, 0x05F3, + 0x05F4, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, + 0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7, + 0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF, + 0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7, + 0x05E8, 0x05E9, 0x05EA, 0xFFFD, 0xFFFD, 0x200E, 0x200F, 0xFFFD} }, + { "CP 1256", 2256, + { 0x20AC, 0x067E, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, + 0x02C6, 0x2030, 0x0679, 0x2039, 0x0152, 0x0686, 0x0698, 0x0688, + 0x06AF, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0x06A9, 0x2122, 0x0691, 0x203A, 0x0153, 0x200C, 0x200D, 0x06BA, + 0x00A0, 0x060C, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x06BE, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00B8, 0x00B9, 0x061B, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x061F, + 0x06C1, 0x0621, 0x0622, 0x0623, 0x0624, 0x0625, 0x0626, 0x0627, + 0x0628, 0x0629, 0x062A, 0x062B, 0x062C, 0x062D, 0x062E, 0x062F, + 0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x0636, 0x00D7, + 0x0637, 0x0638, 0x0639, 0x063A, 0x0640, 0x0641, 0x0642, 0x0643, + 0x00E0, 0x0644, 0x00E2, 0x0645, 0x0646, 0x0647, 0x0648, 0x00E7, + 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x0649, 0x064A, 0x00EE, 0x00EF, + 0x064B, 0x064C, 0x064D, 0x064E, 0x00F4, 0x064F, 0x0650, 0x00F7, + 0x0651, 0x00F9, 0x0652, 0x00FB, 0x00FC, 0x200E, 0x200F, 0x06D2} }, + { "CP 1257", 2257, + { 0x20AC, 0xFFFD, 0x201A, 0xFFFD, 0x201E, 0x2026, 0x2020, 0x2021, + 0xFFFD, 0x2030, 0xFFFD, 0x2039, 0xFFFD, 0x00A8, 0x02C7, 0x00B8, + 0xFFFD, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0xFFFD, 0x2122, 0xFFFD, 0x203A, 0xFFFD, 0x00AF, 0x02DB, 0xFFFD, + 0x00A0, 0xFFFD, 0x00A2, 0x00A3, 0x00A4, 0xFFFD, 0x00A6, 0x00A7, + 0x00D8, 0x00A9, 0x0156, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00C6, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00F8, 0x00B9, 0x0157, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00E6, + 0x0104, 0x012E, 0x0100, 0x0106, 0x00C4, 0x00C5, 0x0118, 0x0112, + 0x010C, 0x00C9, 0x0179, 0x0116, 0x0122, 0x0136, 0x012A, 0x013B, + 0x0160, 0x0143, 0x0145, 0x00D3, 0x014C, 0x00D5, 0x00D6, 0x00D7, + 0x0172, 0x0141, 0x015A, 0x016A, 0x00DC, 0x017B, 0x017D, 0x00DF, + 0x0105, 0x012F, 0x0101, 0x0107, 0x00E4, 0x00E5, 0x0119, 0x0113, + 0x010D, 0x00E9, 0x017A, 0x0117, 0x0123, 0x0137, 0x012B, 0x013C, + 0x0161, 0x0144, 0x0146, 0x00F3, 0x014D, 0x00F5, 0x00F6, 0x00F7, + 0x0173, 0x0142, 0x015B, 0x016B, 0x00FC, 0x017C, 0x017E, 0x02D9} }, + { "CP 1258", 2258, + { 0x20AC, 0xFFFD, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, + 0x02C6, 0x2030, 0xFFFD, 0x2039, 0x0152, 0xFFFD, 0xFFFD, 0xFFFD, + 0xFFFD, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0x02DC, 0x2122, 0xFFFD, 0x203A, 0x0153, 0xFFFD, 0xFFFD, 0x0178, + 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF, + 0x00C0, 0x00C1, 0x00C2, 0x0102, 0x00C4, 0x00C5, 0x00C6, 0x00C7, + 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x0300, 0x00CD, 0x00CE, 0x00CF, + 0x0110, 0x00D1, 0x0309, 0x00D3, 0x00D4, 0x01A0, 0x00D6, 0x00D7, + 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x01AF, 0x0303, 0x00DF, + 0x00E0, 0x00E1, 0x00E2, 0x0103, 0x00E4, 0x00E5, 0x00E6, 0x00E7, + 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x0301, 0x00ED, 0x00EE, 0x00EF, + 0x0111, 0x00F1, 0x0323, 0x00F3, 0x00F4, 0x01A1, 0x00F6, 0x00F7, + 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x01B0, 0x20AB, 0x00FF} }, + + // this one is generated from the charmap file located in /usr/share/i18n/charmaps + // on most Linux distributions. The thai character set tis620 is byte by byte equivalent + // to iso8859-11, so we name it 8859-11 here, but recognise the name tis620 too. + + // $ for A in 8 9 A B C D E F ; do for B in 0 1 2 3 4 5 6 7 8 9 A B C D E F ; do echo x${A}${B} 0xFFFD ; done ; done > /tmp/digits ; ( cut -c25- < TIS-620 ; cat /tmp/digits ) | awk '/^x[89ABCDEF]/{ print $1, $2 }' | sed -e 's/<U/0x/' -e 's/>//' | sort | uniq -w4 | cut -c5- | paste '-d ' - - - - - - - - | sed -e 's/ /, /g' -e 's/$/,/' -e '$ s/,$/} },/' -e '1 s/^/{ /' > ~/tmp/tis-620 + { "ISO 8859-11", 2259, // Thai character set mib enum taken from tis620 (which is byte by byte equivalent) + { 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, + 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, + 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, + 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, + 0xFFFD, 0x0E01, 0x0E02, 0x0E03, 0x0E04, 0x0E05, 0x0E06, 0x0E07, + 0x0E08, 0x0E09, 0x0E0A, 0x0E0B, 0x0E0C, 0x0E0D, 0x0E0E, 0x0E0F, + 0x0E10, 0x0E11, 0x0E12, 0x0E13, 0x0E14, 0x0E15, 0x0E16, 0x0E17, + 0x0E18, 0x0E19, 0x0E1A, 0x0E1B, 0x0E1C, 0x0E1D, 0x0E1E, 0x0E1F, + 0x0E20, 0x0E21, 0x0E22, 0x0E23, 0x0E24, 0x0E25, 0x0E26, 0x0E27, + 0x0E28, 0x0E29, 0x0E2A, 0x0E2B, 0x0E2C, 0x0E2D, 0x0E2E, 0x0E2F, + 0x0E30, 0x0E31, 0x0E32, 0x0E33, 0x0E34, 0x0E35, 0x0E36, 0x0E37, + 0x0E38, 0x0E39, 0x0E3A, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0x0E3F, + 0x0E40, 0x0E41, 0x0E42, 0x0E43, 0x0E44, 0x0E45, 0x0E46, 0x0E47, + 0x0E48, 0x0E49, 0x0E4A, 0x0E4B, 0x0E4C, 0x0E4D, 0x0E4E, 0x0E4F, + 0x0E50, 0x0E51, 0x0E52, 0x0E53, 0x0E54, 0x0E55, 0x0E56, 0x0E57, + 0x0E58, 0x0E59, 0x0E5A, 0x0E5B, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD} }, + + // change LAST_MIB if you add more, and edit unicodevalues in + // kernel/qpsprinter.cpp too. +}; + + +static const QSimpleTextCodec * reverseOwner = 0; +static QArray<char> * reverseMap = 0; + + +QSimpleTextCodec::QSimpleTextCodec( int i ) + : QTextCodec(), forwardIndex( i ) +{ +} + + +QSimpleTextCodec::~QSimpleTextCodec() +{ + if ( reverseOwner == this ) { + delete reverseMap; + reverseMap = 0; + reverseOwner = 0; + } +} + +// what happens if strlen(chars)<len? what happens if !chars? if len<1? +QString QSimpleTextCodec::toUnicode(const char* chars, int len) const +{ + if(len <= 0) + return QString::null; + + int clen = qstrlen(chars); + len = QMIN(len, clen); // Note: NUL ends string + + QString r; + r.setUnicode(0, len); + QChar* uc = (QChar*)r.unicode(); // const_cast + const unsigned char * c = (const unsigned char *)chars; + for( int i=0; i<len; i++ ) { + if ( c[i] > 127 ) + uc[i] = unicodevalues[forwardIndex].values[c[i]-128]; + else + uc[i] = c[i]; + } + return r; +} + + +QCString QSimpleTextCodec::fromUnicode(const QString& uc, int& len ) const +{ + if ( reverseOwner != this ) { + int m = 0; + int i = 0; + while( i < 128 ) { + if ( unicodevalues[forwardIndex].values[i] > m && + unicodevalues[forwardIndex].values[i] < 0xfffd ) + m = unicodevalues[forwardIndex].values[i]; + i++; + } + m++; + if ( !reverseMap ) + reverseMap = new QArray<char>( m ); + if ( m > (int)(reverseMap->size()) ) + reverseMap->resize( m ); + for( i = 0; i < 128 && i < m; i++ ) + (*reverseMap)[i] = (char)i; + for( ;i < m; i++ ) + (*reverseMap)[i] = '?'; + for( i=128; i<256; i++ ) { + int u = unicodevalues[forwardIndex].values[i-128]; + if ( u < m ) + (*reverseMap)[u] = (char)(unsigned char)(i); + } + reverseOwner = this; + } + if ( len <0 || len > (int)uc.length() ) + len = uc.length(); + QCString r( len+1 ); + int i = len; + int u; + const QChar* ucp = uc.unicode(); + char* rp = r.data(); + char* rmp = reverseMap->data(); + int rmsize = (int) reverseMap->size(); + while( i-- ) + { + u = ucp->unicode(); + *rp++ = u < 128 ? u : (( u < rmsize ) ? (*(rmp+u)) : '?' ); + ucp++; + } + r[len] = 0; + return r; +} + + +const char* QSimpleTextCodec::name() const +{ + return unicodevalues[forwardIndex].cs; +} + + +int QSimpleTextCodec::mibEnum() const +{ + return unicodevalues[forwardIndex].mib; +} + +int QSimpleTextCodec::heuristicNameMatch(const char* hint) const +{ + if ( hint[0]=='k' ) { + // Help people with messy fonts + if ( QCString(hint) == "koi8-1" ) + return QTextCodec::heuristicNameMatch("koi8-r")-1; + if ( QCString(hint) == "koi8-ru" ) + return QTextCodec::heuristicNameMatch("koi8-r")-1; + } else if ( hint[0] == 't' && QCString(name()) == "ISO 8859-11" ) { + // 8859-11 and tis620 are byte by bute equivalent + int i = simpleHeuristicNameMatch("tis620-0", hint); + if( !i ) + i = simpleHeuristicNameMatch("tis-620", hint); + if( i ) return i; + } + return QTextCodec::heuristicNameMatch(hint); +} + +int QSimpleTextCodec::heuristicContentMatch(const char* chars, int len) const +{ + if ( len<1 || !chars ) + return -1; + int i = 0; + const uchar * c = (const unsigned char *)chars; + int r = 0; + while( i<len && c && *c ) { + if ( *c >= 128 ) { + if ( unicodevalues[forwardIndex].values[(*c)-128] == 0xfffd ) + return -1; + } + if ( (*c >= ' ' && *c < 127) || + *c == '\n' || *c == '\t' || *c == '\r' ) + r++; + i++; + c++; + } + if ( mibEnum()==4 ) + r+=1; + return r; +} + + +#endif // QT_NO_CODECS + +class QLatin1Codec: public QTextCodec +{ +public: + QLatin1Codec(); + ~QLatin1Codec(); + + QString toUnicode(const char* chars, int len) const; + QCString fromUnicode(const QString& uc, int& lenInOut ) const; + + const char* name() const; + int mibEnum() const; + + int heuristicContentMatch(const char* chars, int len) const; + + int heuristicNameMatch(const char* hint) const; + +private: + int forwardIndex; +}; + + +QLatin1Codec::QLatin1Codec() + : QTextCodec() +{ +} + + +QLatin1Codec::~QLatin1Codec() +{ +} + +// what happens if strlen(chars)<len? what happens if !chars? if len<1? +QString QLatin1Codec::toUnicode(const char* chars, int len) const +{ + if(len <= 0) + return QString::null; + + return QString::fromLatin1(chars, len); +} + + +QCString QLatin1Codec::fromUnicode(const QString& uc, int& len ) const +{ + if ( len <0 || len > (int)uc.length() ) + len = uc.length(); + QCString r( len+1 ); + int i = 0; + const QChar *ch = uc.unicode(); + while ( i < len ) { + r[i] = ch->row() ? '?' : ch->cell(); + i++; + ch++; + } + r[len] = 0; + return r; +} + + +const char* QLatin1Codec::name() const +{ + return "ISO 8859-1"; +} + + +int QLatin1Codec::mibEnum() const +{ + return 4; +} + +int QLatin1Codec::heuristicNameMatch(const char* hint) const +{ + return QTextCodec::heuristicNameMatch(hint); +} + +int QLatin1Codec::heuristicContentMatch(const char* chars, int len) const +{ + if ( len<1 || !chars ) + return -1; + int i = 0; + const uchar * c = (const unsigned char *)chars; + int r = 0; + while( i<len && c && *c ) { + if ( *c >= 0x80 && *c < 0xa0 ) + return -1; + if ( (*c >= ' ' && *c < 127) || + *c == '\n' || *c == '\t' || *c == '\r' ) + r++; + i++; + c++; + } + return r; +} + + +static void setupBuiltinCodecs() +{ + (void)new QLatin1Codec; + +#ifndef QT_NO_CODECS + int i = 0; + do { + (void)new QSimpleTextCodec( i ); + } while( unicodevalues[i++].mib != LAST_MIB ); + + //(void)new QEucJpCodec; + //(void)new QSjisCodec; + //(void)new QJisCodec; + //(void)new QEucKrCodec; + //(void)new QGbkCodec; + //(void)new QBig5Codec; + (void)new QUtf8Codec; + (void)new QUtf16Codec; + //(void)new QHebrewCodec; + //(void)new QArabicCodec; + //(void)new QTsciiCodec; +#endif // QT_NO_CODECS +} + +#endif // QT_NO_TEXTCODEC diff --git a/trunk/qtools/qtextcodec.h b/trunk/qtools/qtextcodec.h new file mode 100644 index 0000000..18ece20 --- /dev/null +++ b/trunk/qtools/qtextcodec.h @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** +** Definition of QTextCodec class +** +** Created : 981015 +** +** Copyright (C) 1998-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QTEXTCODEC_H +#define QTEXTCODEC_H + +#ifndef QT_H +#include "qstring.h" +#endif // QT_H + +#ifndef QT_NO_TEXTCODEC + +class QTextCodec; +class QIODevice; + +class Q_EXPORT QTextEncoder { +public: + virtual ~QTextEncoder(); + virtual QCString fromUnicode(const QString& uc, int& lenInOut) = 0; +}; + +class Q_EXPORT QTextDecoder { +public: + virtual ~QTextDecoder(); + virtual QString toUnicode(const char* chars, int len) = 0; +}; + +class Q_EXPORT QTextCodec { +public: + virtual ~QTextCodec(); + +#ifndef QT_NO_CODECS + static QTextCodec* loadCharmap(QIODevice*); + static QTextCodec* loadCharmapFile(QString filename); +#endif + static QTextCodec* codecForMib(int mib); + static QTextCodec* codecForName(const char* hint, int accuracy=0); + static QTextCodec* codecForContent(const char* chars, int len); + static QTextCodec* codecForIndex(int i); + static QTextCodec* codecForLocale(); + + static void deleteAllCodecs(); + + static const char* locale(); + + virtual const char* name() const = 0; + virtual int mibEnum() const = 0; + + virtual QTextDecoder* makeDecoder() const; + virtual QTextEncoder* makeEncoder() const; + + virtual QString toUnicode(const char* chars, int len) const; + virtual QCString fromUnicode(const QString& uc, int& lenInOut) const; + + QCString fromUnicode(const QString& uc) const; + QString toUnicode(const QByteArray&, int len) const; + QString toUnicode(const QByteArray&) const; + QString toUnicode(const char* chars) const; + virtual bool canEncode( QChar ) const; + virtual bool canEncode( const QString& ) const; + + virtual int heuristicContentMatch(const char* chars, int len) const = 0; + virtual int heuristicNameMatch(const char* hint) const; + +protected: + QTextCodec(); + static int simpleHeuristicNameMatch(const char* name, const char* hint); +}; +#endif // QT_NO_TEXTCODEC +#endif // QTEXTCODEC_H diff --git a/trunk/qtools/qtextstream.cpp b/trunk/qtools/qtextstream.cpp new file mode 100644 index 0000000..b12f86d --- /dev/null +++ b/trunk/qtools/qtextstream.cpp @@ -0,0 +1,2237 @@ +/**************************************************************************** +** +** +** Implementation of QTextStream class +** +** Created : 940922 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "qtextstream.h" + +#ifndef QT_NO_TEXTSTREAM +#include "qtextcodec.h" +#include "qregexp.h" +#include "qbuffer.h" +#include "qfile.h" +#include <stdio.h> +#include <ctype.h> +#include <stdlib.h> + +#if defined(_OS_WIN32_) +#include <windows.h> +#endif + +// NOT REVISED +/*! + \class QTextStream qtextstream.h + + \brief The QTextStream class provides basic functions for reading and + writing text using a QIODevice. + + \ingroup io + + \define endl + \define bin + \define oct + \define dec + \define hex + \define flush + \define ws + + The text stream class has a functional interface that is very + similar to that of the standard C++ iostream class. The difference + between iostream and QTextStream is that our stream operates on a + QIODevice, which is easily subclassed, while iostream operates on + FILE * pointers, which can not be subclassed. + + Qt provides several global functions similar to the ones in iostream: + <ul> + <li> \c bin sets the QTextStream to read/write binary numbers + <li> \c oct sets the QTextStream to read/write octal numbers + <li> \c dec sets the QTextStream to read/write decimal numbers + <li> \c hex sets the QTextStream to read/write hexadecimal numbers + <li> \c endl forces a line break + <li> \c flush forces the QIODevice to flush any buffered data + <li> \c ws eats any available white space (on input) + <li> \c reset resets the QTextStream to its default mode (see reset()). + </ul> + + \warning By default, QTextStream will automatically detect whether + integers in the stream are in decimal, octal, hexadecimal or binary + format when reading from the stream. In particular, a leading '0' + signifies octal, ie. the sequence "0100" will be interpreted as + 64. + + The QTextStream class reads and writes text and it is not + appropriate for dealing with binary data (but QDataStream is). + + By default output of Unicode text (ie. QString) is done using the + local 8-bit encoding. This can be changed using the setEncoding() + method. For input, the QTextStream will auto-detect standard + Unicode "byte order marked" text files, but otherwise the local + 8-bit encoding is used. + + \sa QDataStream +*/ + +/* + \class QTSManip qtextstream.h + + \brief The QTSManip class is an internal helper class for the + QTextStream. + + It is generally a very bad idea to use this class directly in + application programs. + + \internal + + This class makes it possible to give the QTextStream function objects + with arguments, like this: + \code + QTextStream cout( stdout, IO_WriteOnly ); + cout << setprecision( 8 ); // QTSManip used here! + cout << 3.14159265358979323846; + \endcode + + The setprecision() function returns a QTSManip object. + The QTSManip object contains a pointer to a member function in + QTextStream and an integer argument. + When serializing a QTSManip into a QTextStream, the function + is executed with the argument. +*/ + +/*! \fn QTSManip::QTSManip (QTSMFI m, int a) + + Constructs a QTSManip object which will call \a m (a member function + in QTextStream which accepts a single int) with argument \a a when + QTSManip::exec() is called. Used internally in e.g. endl: + + \code + s << "some text" << endl << "more text"; + \endcode +*/ + +/*! \fn void QTSManip::exec (QTextStream& s) + + Calls the member function specified in the constructor, for object + \a s. Used internally in e.g. endl: + + \code + s << "some text" << endl << "more text"; + \endcode +*/ + + +/***************************************************************************** + QTextStream member functions + *****************************************************************************/ + +#if defined(CHECK_STATE) +#undef CHECK_STREAM_PRECOND +#define CHECK_STREAM_PRECOND if ( !dev ) { \ + qWarning( "QTextStream: No device" ); \ + return *this; } +#else +#define CHECK_STREAM_PRECOND +#endif + + +#define I_SHORT 0x0010 +#define I_INT 0x0020 +#define I_LONG 0x0030 +#define I_TYPE_MASK 0x00f0 + +#define I_BASE_2 QTS::bin +#define I_BASE_8 QTS::oct +#define I_BASE_10 QTS::dec +#define I_BASE_16 QTS::hex +#define I_BASE_MASK (QTS::bin | QTS::oct | QTS::dec | QTS::hex) + +#define I_SIGNED 0x0100 +#define I_UNSIGNED 0x0200 +#define I_SIGN_MASK 0x0f00 + + +static const QChar QEOF = QChar((ushort)0xffff); //guaranteed not to be a character. + +const int QTextStream::basefield = I_BASE_MASK; +const int QTextStream::adjustfield = ( QTextStream::left | + QTextStream::right | + QTextStream::internal ); +const int QTextStream::floatfield = ( QTextStream::scientific | + QTextStream::fixed ); + + +class QTextStreamPrivate { +public: +#ifndef QT_NO_TEXTCODEC + QTextStreamPrivate() : decoder( 0 ), sourceType( NotSet ) {} + ~QTextStreamPrivate() { delete decoder; } + QTextDecoder *decoder; //??? +#else + QTextStreamPrivate() : sourceType( NotSet ) {} + ~QTextStreamPrivate() { } +#endif + QString ungetcBuf; + + enum SourceType { NotSet, IODevice, String, ByteArray, File }; + SourceType sourceType; +}; + + +// skips whitespace and returns the first non-whitespace character +QChar QTextStream::eat_ws() +{ + QChar c; + do { c = ts_getc(); } while ( c != QEOF && ts_isspace(c) ); + return c; +} + +void QTextStream::init() +{ + // ### ungetcBuf = QEOF; + dev = 0; // no device set + fstrm = owndev = FALSE; + mapper = 0; + d = new QTextStreamPrivate; + doUnicodeHeader = TRUE; //default to autodetect + latin1 = TRUE; // ### should use local? + internalOrder = QChar::networkOrdered(); //default to network order +} + +/*! + Constructs a data stream that has no IO device. +*/ + +QTextStream::QTextStream() +{ + init(); + setEncoding( Locale ); //### + reset(); + d->sourceType = QTextStreamPrivate::NotSet; +} + +/*! + Constructs a text stream that uses the IO device \a iod. +*/ + +QTextStream::QTextStream( QIODevice *iod ) +{ + init(); + setEncoding( Locale ); //### + dev = iod; // set device + reset(); + d->sourceType = QTextStreamPrivate::IODevice; +} + +// TODO: use special-case handling of this case in QTextStream, and +// simplify this class to only deal with QChar or QString data. +class QStringBuffer : public QIODevice { +public: + QStringBuffer( QString* str ); + ~QStringBuffer(); + bool open( int m ); + void close(); + void flush(); + uint size() const; + int at() const; + bool at( int pos ); + int readBlock( char *p, uint len ); + int writeBlock( const char *p, uint len ); + int getch(); + int putch( int ch ); + int ungetch( int ch ); +protected: + QString* s; + +private: // Disabled copy constructor and operator= + QStringBuffer( const QStringBuffer & ); + QStringBuffer &operator=( const QStringBuffer & ); +}; + + +QStringBuffer::QStringBuffer( QString* str ) +{ + s = str; +} + +QStringBuffer::~QStringBuffer() +{ +} + + +bool QStringBuffer::open( int m ) +{ + if ( !s ) { +#if defined(CHECK_STATE) + qWarning( "QStringBuffer::open: No string" ); +#endif + return FALSE; + } + if ( isOpen() ) { // buffer already open +#if defined(CHECK_STATE) + qWarning( "QStringBuffer::open: Buffer already open" ); +#endif + return FALSE; + } + setMode( m ); + if ( m & IO_Truncate ) { // truncate buffer + s->truncate( 0 ); + } + if ( m & IO_Append ) { // append to end of buffer + ioIndex = s->length()*sizeof(QChar); + } else { + ioIndex = 0; + } + setState( IO_Open ); + setStatus( 0 ); + return TRUE; +} + +void QStringBuffer::close() +{ + if ( isOpen() ) { + setFlags( IO_Direct ); + ioIndex = 0; + } +} + +void QStringBuffer::flush() +{ +} + +uint QStringBuffer::size() const +{ + return s ? s->length()*sizeof(QChar) : 0; +} + +int QStringBuffer::at() const +{ + return ioIndex; +} + +bool QStringBuffer::at( int pos ) +{ +#if defined(CHECK_STATE) + if ( !isOpen() ) { + qWarning( "QStringBuffer::at: Buffer is not open" ); + return FALSE; + } +#endif + if ( (uint)pos >= s->length()*2 ) { +#if defined(CHECK_RANGE) + qWarning( "QStringBuffer::at: Index %d out of range", pos ); +#endif + return FALSE; + } + ioIndex = pos; + return TRUE; +} + + +int QStringBuffer::readBlock( char *p, uint len ) +{ +#if defined(CHECK_STATE) + CHECK_PTR( p ); + if ( !isOpen() ) { // buffer not open + qWarning( "QStringBuffer::readBlock: Buffer not open" ); + return -1; + } + if ( !isReadable() ) { // reading not permitted + qWarning( "QStringBuffer::readBlock: Read operation not permitted" ); + return -1; + } +#endif + if ( (uint)ioIndex + len > s->length()*sizeof(QChar) ) { + // overflow + if ( (uint)ioIndex >= s->length()*sizeof(QChar) ) { + setStatus( IO_ReadError ); + return -1; + } else { + len = s->length()*2 - (uint)ioIndex; + } + } + memcpy( p, ((const char*)(s->unicode()))+ioIndex, len ); + ioIndex += len; + return len; +} + +int QStringBuffer::writeBlock( const char *p, uint len ) +{ +#if defined(CHECK_NULL) + if ( p == 0 && len != 0 ) + qWarning( "QStringBuffer::writeBlock: Null pointer error" ); +#endif +#if defined(CHECK_STATE) + if ( !isOpen() ) { // buffer not open + qWarning( "QStringBuffer::writeBlock: Buffer not open" ); + return -1; + } + if ( !isWritable() ) { // writing not permitted + qWarning( "QStringBuffer::writeBlock: Write operation not permitted" ); + return -1; + } + if ( ioIndex&1 ) { + qWarning( "QStringBuffer::writeBlock: non-even index - non Unicode" ); + return -1; + } + if ( len&1 ) { + qWarning( "QStringBuffer::writeBlock: non-even length - non Unicode" ); + return -1; + } +#endif + s->replace(ioIndex/2, len/2, (QChar*)p, len/2); + ioIndex += len; + return len; +} + +int QStringBuffer::getch() +{ +#if defined(CHECK_STATE) + if ( !isOpen() ) { // buffer not open + qWarning( "QStringBuffer::getch: Buffer not open" ); + return -1; + } + if ( !isReadable() ) { // reading not permitted + qWarning( "QStringBuffer::getch: Read operation not permitted" ); + return -1; + } +#endif + if ( (uint)ioIndex >= s->length()*2 ) { // overflow + setStatus( IO_ReadError ); + return -1; + } + return *((char*)s->unicode() + ioIndex++); +} + +int QStringBuffer::putch( int ch ) +{ + char c = ch; + if ( writeBlock(&c,1) < 0 ) + return -1; + else + return ch; +} + +int QStringBuffer::ungetch( int ch ) +{ +#if defined(CHECK_STATE) + if ( !isOpen() ) { // buffer not open + qWarning( "QStringBuffer::ungetch: Buffer not open" ); + return -1; + } + if ( !isReadable() ) { // reading not permitted + qWarning( "QStringBuffer::ungetch: Read operation not permitted" ); + return -1; + } +#endif + if ( ch != -1 ) { // something to do with eof + if ( ioIndex ) + ioIndex--; + else + ch = -1; + } + return ch; +} + + +/*! + Constructs a text stream that operates on a Unicode QString through an + internal device. + + If you set an encoding or codec with setEncoding() or setCodec(), this + setting is ignored for text streams that operate on QString. + + Example: + \code + QString str; + QTextStream ts( &str, IO_WriteOnly ); + ts << "pi = " << 3.14; // str == "pi = 3.14" + \endcode + + Writing data to the text stream will modify the contents of the string. + The string will be expanded when data is written beyond the end of the + string. Note that the string will not be truncated: + \code + QString str = "pi = 3.14"; + QTextStream ts( &str, IO_WriteOnly ); + ts << "2+2 = " << 2+2; // str == "2+2 = 414" + \endcode + + Note that since QString is Unicode, you should not use readRawBytes() + or writeRawBytes() on such a stream. +*/ + +QTextStream::QTextStream( QString* str, int filemode ) +{ + // TODO: optimize for this case as it becomes more common + // (see QStringBuffer above) + init(); + dev = new QStringBuffer( str ); + ((QStringBuffer *)dev)->open( filemode ); + owndev = TRUE; + setEncoding(RawUnicode); + reset(); + d->sourceType = QTextStreamPrivate::String; +} + +/*! \obsolete + + This constructor is equivalent to the constructor taking a QString* + parameter. +*/ + +QTextStream::QTextStream( QString& str, int filemode ) +{ + init(); + dev = new QStringBuffer( &str ); + ((QStringBuffer *)dev)->open( filemode ); + owndev = TRUE; + setEncoding(RawUnicode); + reset(); + d->sourceType = QTextStreamPrivate::String; +} + +/*! + Constructs a text stream that operates on a byte array through an + internal QBuffer device. + + Example: + \code + QByteArray array; + QTextStream ts( array, IO_WriteOnly ); + ts << "pi = " << 3.14 << '\0'; // array == "pi = 3.14" + \endcode + + Writing data to the text stream will modify the contents of the array. + The array will be expanded when data is written beyond the end of the + string. + + Same example, using a QBuffer: + \code + QByteArray array; + QBuffer buf( array ); + buf.open( IO_WriteOnly ); + QTextStream ts( &buf ); + ts << "pi = " << 3.14 << '\0'; // array == "pi = 3.14" + buf.close(); + \endcode +*/ + +QTextStream::QTextStream( QByteArray a, int mode ) +{ + init(); + dev = new QBuffer( a ); + ((QBuffer *)dev)->open( mode ); + owndev = TRUE; + setEncoding( Locale ); //### Locale??? + reset(); + d->sourceType = QTextStreamPrivate::ByteArray; +} + +/*! + Constructs a text stream that operates on an existing file handle \e fh + through an internal QFile device. + + Example: + \code + QTextStream cout( stdout, IO_WriteOnly ); + QTextStream cin ( stdin, IO_ReadOnly ); + QTextStream cerr( stderr, IO_WriteOnly ); + \endcode +*/ + +QTextStream::QTextStream( FILE *fh, int mode ) +{ + init(); + setEncoding( Locale ); //### + dev = new QFile; + ((QFile *)dev)->open( mode, fh ); + fstrm = owndev = TRUE; + reset(); + d->sourceType = QTextStreamPrivate::File; +} + +/*! + Destructs the text stream. + + The destructor does not affect the current IO device. +*/ + +QTextStream::~QTextStream() +{ + if ( owndev ) + delete dev; + delete d; +} + +/*! + Positions the read pointer at the first non-whitespace character. +*/ +void QTextStream::skipWhiteSpace() +{ + ts_ungetc( eat_ws() ); +} + + +/*! + \fn Encoding QTextStream::encoding() const + + Returns the encoding mode of the stream. + + \sa setEncoding() +*/ + +/*! + Tries to read len characters from the stream and stores them in \a buf. + Returns the number of characters really read. + Attention: There will no QEOF appended if the read reaches the end of + the file. EOF is reached when the return value does not equal \a len. +*/ +uint QTextStream::ts_getbuf( QChar* buf, uint len ) +{ + if( len<1 ) + return 0; + + uint rnum=0; // the number of QChars really read + + if ( d && d->ungetcBuf.length() ) { + while( rnum < len && rnum < d->ungetcBuf.length() ) { + buf[rnum] = d->ungetcBuf.constref(rnum); + rnum++; + } + d->ungetcBuf = d->ungetcBuf.mid( rnum ); + if ( rnum >= len ) + return rnum; + } + + // we use dev->ungetch() for one of the bytes of the unicode + // byte-order mark, but a local unget hack for the other byte: + int ungetHack = EOF; + + if ( doUnicodeHeader ) { + doUnicodeHeader = FALSE; //only at the top + int c1 = dev->getch(); + if ( c1 == EOF ) + return rnum; + int c2 = dev->getch(); + if ( c1 == 0xfe && c2 == 0xff ) { + mapper = 0; + latin1 = FALSE; + internalOrder = QChar::networkOrdered(); //network order + } else if ( c1 == 0xff && c2 == 0xfe ) { + mapper = 0; + latin1 = FALSE; + internalOrder = !QChar::networkOrdered(); //reverse network order + } else { + if ( c2 != EOF ) { + dev->ungetch( c2 ); + ungetHack = c1; + } else { + dev->ungetch( c1 ); + // note that a small possible bug might hide here + // here, if only the first byte of a file has made it + // so far, and that first byte is half of the + // byte-order mark, then the utfness will not be + // detected. whether or not this is a bug depends on + // taste. I can't really decide. + } + } + } + +#ifndef QT_NO_TEXTCODEC + if ( mapper ) { + bool shortRead = FALSE; + if ( !d->decoder ) + d->decoder = mapper->makeDecoder(); + while( rnum < len ) { + QString s; + bool readBlock = !( len == 1+rnum ); + while ( TRUE ) { + // for efficiency: normally read a whole block + if ( readBlock ) { + // guess buffersize; this may be wrong (too small or too + // big). But we can handle this (either iterate reading + // or use ungetcBuf). + // Note that this might cause problems for codecs where + // one byte can result in >1 Unicode Characters if bytes + // are written to the stream in the meantime (loss of + // synchronicity). + uint rlen = len - rnum; + char *cbuf = new char[ rlen ]; + if ( ungetHack != EOF ) { + rlen = 1+dev->readBlock( cbuf+1, rlen-1 ); + cbuf[0] = (char)ungetHack; + ungetHack = EOF; + } else { + rlen = dev->readBlock( cbuf, rlen ); + } + s += d->decoder->toUnicode( cbuf, rlen ); + delete[] cbuf; + // use buffered reading only for the first time, because we + // have to get the stream synchronous again (this is easier + // with single character reading) + readBlock = FALSE; + } + // get stream (and codec) in sync + int c; + if ( ungetHack == EOF ) { + c = dev->getch(); + } else { + c = ungetHack; + ungetHack = EOF; + } + if ( c == EOF ) { + shortRead = TRUE; + break; + } + char b = c; + uint lengthBefore = s.length(); + s += d->decoder->toUnicode( &b, 1 ); + if ( s.length() > lengthBefore ) + break; // it seems we are in sync now + } + uint i = 0; + while( rnum < len && i < s.length() ) + buf[rnum++] = s.constref(i++); + if ( s.length() > i ) + // could be = but append is clearer + d->ungetcBuf.append( s.mid( i ) ); + if ( shortRead ) + return rnum; + } + } else +#endif + if ( latin1 ) { + if ( len == 1+rnum ) { + // use this method for one character because it is more efficient + // (arnt doubts whether it makes a difference, but lets it stand) + int c = (ungetHack == EOF) ? dev->getch() : ungetHack; + if ( c != EOF ) + buf[rnum++] = (char)c; + } else { + if ( ungetHack != EOF ) { + buf[rnum++] = (char)ungetHack; + ungetHack = EOF; + } + char *cbuf = new char[len - rnum]; + while ( !dev->atEnd() && rnum < len ) { + uint rlen = len - rnum; + rlen = dev->readBlock( cbuf, rlen ); + uint i = 0; + while( i < rlen ) + buf[rnum++] = cbuf[i++]; + } + delete[] cbuf; + } + } else { // UCS-2 or UTF-16 + if ( len == 1+rnum ) { + int c1 = (ungetHack == EOF) ? dev->getch() : ungetHack; + if ( c1 == EOF ) + return rnum; + int c2 = dev->getch(); + if ( c2 == EOF ) + return rnum; + if ( isNetworkOrder() ) + buf[rnum++] = QChar( c2, c1 ); + else + buf[rnum++] = QChar( c1, c2 ); + } else { + char *cbuf = new char[ 2*( len - rnum ) ]; // for paranoids: overflow possible + while ( !dev->atEnd() && rnum < len ) { + uint rlen = 2 * ( len-rnum ); + if ( ungetHack != EOF ) { + rlen = 1+dev->readBlock( cbuf+1, rlen-1 ); + cbuf[0] = (char)ungetHack; + ungetHack = EOF; + } else { + rlen = dev->readBlock( cbuf, rlen ); + } + // We can't use an odd number of bytes, so put it back. But + // do it only if we are capable of reading more -- normally + // there should not be an odd number, but the file might be + // truncated or not in UTF-16... + if ( (rlen & 1) == 1 ) + if ( !dev->atEnd() ) + dev->ungetch( cbuf[--rlen] ); + uint i = 0; + if ( isNetworkOrder() ) { + while( i < rlen ) { + buf[rnum++] = QChar( cbuf[i+1], cbuf[i] ); + i+=2; + } + } else { + while( i < rlen ) { + buf[rnum++] = QChar( cbuf[i], cbuf[i+1] ); + i+=2; + } + } + } + delete[] cbuf; + } + } + return rnum; +} + + +/*! + Puts one character to the stream. +*/ +void QTextStream::ts_putc( QChar c ) +{ +#ifndef QT_NO_TEXTCODEC + if ( mapper ) { + int len = 1; + QString s = c; + QCString block = mapper->fromUnicode( s, len ); + dev->writeBlock( block, len ); + } else +#endif + if ( latin1 ) { + if( c.row() ) + dev->putch( '?' ); //######unknown character??? + else + dev->putch( c.cell() ); + } else { + if ( doUnicodeHeader ) { + doUnicodeHeader = FALSE; + ts_putc( QChar::byteOrderMark ); + } + if ( internalOrder ) { + dev->writeBlock( (char*)&c, sizeof(QChar) ); + } else if ( isNetworkOrder() ) { + dev->putch(c.row()); + dev->putch(c.cell()); + } else { + dev->putch(c.cell()); + dev->putch(c.row()); + } + } +} + +/*! + Puts one character to the stream. +*/ +void QTextStream::ts_putc(int ch) +{ + ts_putc(QChar((ushort)ch)); +} + +bool QTextStream::ts_isdigit(QChar c) +{ + return c.isDigit(); +} + +bool QTextStream::ts_isspace( QChar c ) +{ + return c.isSpace(); +} + +void QTextStream::ts_ungetc( QChar c ) +{ + if ( c.unicode() == 0xffff ) + return; + + d->ungetcBuf.prepend( c ); +} + + + +/*! + Reads \e len bytes from the stream into \e e s and returns a reference to + the stream. + + The buffer \e s must be preallocated. + + Note that no encoding is done by this function. + + \warning The behaviour of this function is undefined unless the + stream's encoding is set to Unicode or Latin1. + + \sa QIODevice::readBlock() +*/ + +QTextStream &QTextStream::readRawBytes( char *s, uint len ) +{ + dev->readBlock( s, len ); + return *this; +} + +/*! + Writes the \e len bytes from \e s to the stream and returns a reference to + the stream. + + Note that no encoding is done by this function. + + \sa QIODevice::writeBlock() +*/ + +QTextStream &QTextStream::writeRawBytes( const char* s, uint len ) +{ + dev->writeBlock( s, len ); + return *this; +} + + +QTextStream &QTextStream::writeBlock( const char* p, uint len ) +{ + if ( doUnicodeHeader ) { + doUnicodeHeader = FALSE; + if ( !mapper && !latin1 ) + ts_putc( QChar::byteOrderMark ); + } + //All QCStrings and const char* are defined to be in Latin1 + if ( !mapper && latin1 ) { + dev->writeBlock( p, len ); + } else if ( !mapper && internalOrder ) { + QChar *u = new QChar[len]; + for (uint i=0; i<len; i++) + u[i] = p[i]; + dev->writeBlock( (char*)u, len*sizeof(QChar) ); + delete [] u; + } else { + for (uint i=0; i<len; i++) + ts_putc( (uchar)p[i] ); + } + return *this; +} + +QTextStream &QTextStream::writeBlock( const QChar* p, uint len ) +{ + if ( !mapper && !latin1 && internalOrder ) { + if ( doUnicodeHeader ) { + doUnicodeHeader = FALSE; + ts_putc( QChar::byteOrderMark ); + } + dev->writeBlock( (char*)p, sizeof(QChar)*len ); + } else { + for (uint i=0; i<len; i++) + ts_putc( p[i] ); + } + return *this; +} + + + +/*! + Resets the text stream. + + <ul> + <li> All flags are set to 0. + <li> The field width is set to 0. + <li> The fill character is set to ' ' (space). + <li> The precision is set to 6. + </ul> + + \sa setf(), width(), fill(), precision() +*/ + +void QTextStream::reset() +{ + fflags = 0; + fwidth = 0; + fillchar = ' '; + fprec = 6; +} + + +/*! + \fn QIODevice *QTextStream::device() const + Returns the IO device currently set. + \sa setDevice(), unsetDevice() +*/ + +/*! + Sets the IO device to \a iod. + \sa device(), unsetDevice() +*/ + +void QTextStream::setDevice( QIODevice *iod ) +{ + if ( owndev ) { + delete dev; + owndev = FALSE; + } + dev = iod; + d->sourceType = QTextStreamPrivate::IODevice; +} + +/*! + Unsets the IO device. Equivalent to setDevice( 0 ). + \sa device(), setDevice() +*/ + +void QTextStream::unsetDevice() +{ + setDevice( 0 ); + d->sourceType = QTextStreamPrivate::NotSet; +} + +/*! + \fn bool QTextStream::atEnd() const + Returns TRUE if the IO device has reached the end position (end of + stream or file) or if there is no IO device set. + + Returns FALSE if the current position of the read/write head of the IO + device is somewhere before the end position. + + \sa QIODevice::atEnd() +*/ + +/*!\fn bool QTextStream::eof() const + + \obsolete + + This function has been renamed to atEnd(). + + \sa QIODevice::atEnd() +*/ + +/***************************************************************************** + QTextStream read functions + *****************************************************************************/ + + +/*! + Reads a \c char from the stream and returns a reference to the stream. + Note that whitespace is skipped. +*/ + +QTextStream &QTextStream::operator>>( char &c ) +{ + CHECK_STREAM_PRECOND + c = eat_ws(); + return *this; +} + +/*! + Reads a \c char from the stream and returns a reference to the stream. + Note that whitespace is \e not skipped. +*/ + +QTextStream &QTextStream::operator>>( QChar &c ) +{ + CHECK_STREAM_PRECOND + c = ts_getc(); + return *this; +} + + +ulong QTextStream::input_bin() +{ + ulong val = 0; + QChar ch = eat_ws(); + int dv = ch.digitValue(); + while ( dv == 0 || dv == 1 ) { + val = ( val << 1 ) + dv; + ch = ts_getc(); + dv = ch.digitValue(); + } + if ( ch != QEOF ) + ts_ungetc( ch ); + return val; +} + +ulong QTextStream::input_oct() +{ + ulong val = 0; + QChar ch = eat_ws(); + int dv = ch.digitValue(); + while ( dv >= 0 && dv <= 7 ) { + val = ( val << 3 ) + dv; + ch = ts_getc(); + dv = ch.digitValue(); + } + if ( dv == 8 || dv == 9 ) { + while ( ts_isdigit(ch) ) + ch = ts_getc(); + } + if ( ch != QEOF ) + ts_ungetc( ch ); + return val; +} + +ulong QTextStream::input_dec() +{ + ulong val = 0; + QChar ch = eat_ws(); + int dv = ch.digitValue(); + while ( ts_isdigit(ch) ) { + val = val * 10 + dv; + ch = ts_getc(); + dv = ch.digitValue(); + } + if ( ch != QEOF ) + ts_ungetc( ch ); + return val; +} + +ulong QTextStream::input_hex() +{ + ulong val = 0; + QChar ch = eat_ws(); + char c = ch; + while ( isxdigit(c) ) { + val <<= 4; + if ( ts_isdigit(c) ) + val += c - '0'; + else + val += 10 + tolower(c) - 'a'; + c = ch = ts_getc(); + } + if ( ch != QEOF ) + ts_ungetc( ch ); + return val; +} + +long QTextStream::input_int() +{ + long val; + QChar ch; + char c; + switch ( flags() & basefield ) { + case bin: + val = (long)input_bin(); + break; + case oct: + val = (long)input_oct(); + break; + case dec: + c = ch = eat_ws(); + if ( ch == QEOF ) { + val = 0; + } else { + if ( !(c == '-' || c == '+') ) + ts_ungetc( ch ); + if ( c == '-' ) { + ulong v = input_dec(); + if ( v ) { // ensure that LONG_MIN can be read + v--; + val = -((long)v) - 1; + } else { + val = 0; + } + } else { + val = (long)input_dec(); + } + } + break; + case hex: + val = (long)input_hex(); + break; + default: + val = 0; + c = ch = eat_ws(); + if ( c == '0' ) { // bin, oct or hex + c = ch = ts_getc(); + if ( tolower(c) == 'x' ) + val = (long)input_hex(); + else if ( tolower(c) == 'b' ) + val = (long)input_bin(); + else { // octal + ts_ungetc( ch ); + if ( c >= '0' && c <= '7' ) { + val = (long)input_oct(); + } else { + val = 0; + } + } + } else if ( ts_isdigit(ch) ) { + ts_ungetc( ch ); + val = (long)input_dec(); + } else if ( c == '-' || c == '+' ) { + ulong v = input_dec(); + if ( c == '-' ) { + if ( v ) { // ensure that LONG_MIN can be read + v--; + val = -((long)v) - 1; + } else { + val = 0; + } + } else { + val = (long)v; + } + } + } + return val; +} + +// +// We use a table-driven FSM to parse floating point numbers +// strtod() cannot be used directly since we're reading from a QIODevice +// + +double QTextStream::input_double() +{ + const int Init = 0; // states + const int Sign = 1; + const int Mantissa = 2; + const int Dot = 3; + const int Abscissa = 4; + const int ExpMark = 5; + const int ExpSign = 6; + const int Exponent = 7; + const int Done = 8; + + const int InputSign = 1; // input tokens + const int InputDigit = 2; + const int InputDot = 3; + const int InputExp = 4; + + static uchar table[8][5] = { + /* None InputSign InputDigit InputDot InputExp */ + { 0, Sign, Mantissa, Dot, 0, }, // Init + { 0, 0, Mantissa, Dot, 0, }, // Sign + { Done, Done, Mantissa, Dot, ExpMark,}, // Mantissa + { 0, 0, Abscissa, 0, 0, }, // Dot + { Done, Done, Abscissa, Done, ExpMark,}, // Abscissa + { 0, ExpSign, Exponent, 0, 0, }, // ExpMark + { 0, 0, Exponent, 0, 0, }, // ExpSign + { Done, Done, Exponent, Done, Done } // Exponent + }; + + int state = Init; // parse state + int input; // input token + + char buf[256]; + int i = 0; + QChar c = eat_ws(); + + while ( TRUE ) { + + switch ( c ) { + case '+': + case '-': + input = InputSign; + break; + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + input = InputDigit; + break; + case '.': + input = InputDot; + break; + case 'e': + case 'E': + input = InputExp; + break; + default: + input = 0; + break; + } + + state = table[state][input]; + + if ( state == 0 || state == Done || i > 250 ) { + if ( i > 250 ) { // ignore rest of digits + do { c = ts_getc(); } while ( c != QEOF && ts_isdigit(c) ); + } + if ( c != QEOF ) + ts_ungetc( c ); + buf[i] = '\0'; + char *end; + return strtod( buf, &end ); + } + + buf[i++] = c; + c = ts_getc(); + } + +#if !defined(_CC_EGG_) + return 0.0; +#endif +} + + +/*! + Reads a signed \c short integer from the stream and returns a reference to + the stream. See flags() for an explanation of expected input format. +*/ + +QTextStream &QTextStream::operator>>( signed short &i ) +{ + CHECK_STREAM_PRECOND + i = (signed short)input_int(); + return *this; +} + + +/*! + Reads an unsigned \c short integer from the stream and returns a reference to + the stream. See flags() for an explanation of expected input format. +*/ + +QTextStream &QTextStream::operator>>( unsigned short &i ) +{ + CHECK_STREAM_PRECOND + i = (unsigned short)input_int(); + return *this; +} + + +/*! + Reads a signed \c int from the stream and returns a reference to the + stream. See flags() for an explanation of expected input format. +*/ + +QTextStream &QTextStream::operator>>( signed int &i ) +{ + CHECK_STREAM_PRECOND + i = (signed int)input_int(); + return *this; +} + + +/*! + Reads an unsigned \c int from the stream and returns a reference to the + stream. See flags() for an explanation of expected input format. +*/ + +QTextStream &QTextStream::operator>>( unsigned int &i ) +{ + CHECK_STREAM_PRECOND + i = (unsigned int)input_int(); + return *this; +} + + +/*! + Reads a signed \c long int from the stream and returns a reference to the + stream. See flags() for an explanation of expected input format. +*/ + +QTextStream &QTextStream::operator>>( signed long &i ) +{ + CHECK_STREAM_PRECOND + i = (signed long)input_int(); + return *this; +} + + +/*! + Reads an unsigned \c long int from the stream and returns a reference to the + stream. See flags() for an explanation of expected input format. +*/ + +QTextStream &QTextStream::operator>>( unsigned long &i ) +{ + CHECK_STREAM_PRECOND + i = (unsigned long)input_int(); + return *this; +} + + +/*! + Reads a \c float from the stream and returns a reference to the stream. + See flags() for an explanation of expected input format. +*/ + +QTextStream &QTextStream::operator>>( float &f ) +{ + CHECK_STREAM_PRECOND + f = (float)input_double(); + return *this; +} + + +/*! + Reads a \c double from the stream and returns a reference to the stream. + See flags() for an explanation of expected input format. +*/ + +QTextStream &QTextStream::operator>>( double &f ) +{ + CHECK_STREAM_PRECOND + f = input_double(); + return *this; +} + + +/*! + Reads a word from the stream and returns a reference to the stream. +*/ + +QTextStream &QTextStream::operator>>( char *s ) +{ + CHECK_STREAM_PRECOND + int maxlen = width( 0 ); + QChar c = eat_ws(); + if ( !maxlen ) + maxlen = -1; + while ( c != QEOF ) { + if ( ts_isspace(c) || maxlen-- == 0 ) { + ts_ungetc( c ); + break; + } + *s++ = c; + c = ts_getc(); + } + + *s = '\0'; + return *this; +} + +/*! + Reads a word from the stream and returns a reference to the stream. +*/ + +QTextStream &QTextStream::operator>>( QString &str ) +{ + CHECK_STREAM_PRECOND + str=QString::fromLatin1(""); + QChar c = eat_ws(); + + while ( c != QEOF ) { + if ( ts_isspace(c) ) { + ts_ungetc( c ); + break; + } + str += c; + c = ts_getc(); + } + return *this; +} + +/*! + Reads a word from the stream and returns a reference to the stream. +*/ + +QTextStream &QTextStream::operator>>( QCString &str ) +{ + CHECK_STREAM_PRECOND + QCString *dynbuf = 0; + const int buflen = 256; + char buffer[buflen]; + char *s = buffer; + int i = 0; + QChar c = eat_ws(); + + while ( c != QEOF ) { + if ( ts_isspace(c) ) { + ts_ungetc( c ); + break; + } + if ( i >= buflen-1 ) { + if ( !dynbuf ) { // create dynamic buffer + dynbuf = new QCString(buflen*2); + memcpy( dynbuf->data(), s, i ); // copy old data + } else if ( i >= (int)dynbuf->size()-1 ) { + dynbuf->resize( dynbuf->size()*2 ); + } + s = dynbuf->data(); + } + s[i++] = c; + c = ts_getc(); + } + str.resize( i+1 ); + memcpy( str.data(), s, i ); + delete dynbuf; + return *this; +} + + +/*! + Reads a line from the stream and returns a string containing the text. + + The returned string does not contain any trailing newline or carriage + return. Note that this is different from QIODevice::readLine(), which + does not strip the newline at the end of the line. + + On EOF you will get a QString that is null. On reading an empty line the + returned QString is empty but not null. + + \sa QIODevice::readLine() +*/ + +QString QTextStream::readLine() +{ +#if defined(CHECK_STATE) + if ( !dev ) { + qWarning( "QTextStream::readLine: No device" ); + return QString::null; + } +#endif + QString result( "" ); + const int buf_size = 256; + QChar c[buf_size]; + int pos = 0; + + c[pos] = ts_getc(); + if ( c[pos] == QEOF ) + return QString::null; + + while ( c[pos] != QEOF && c[pos] != '\n' ) { + pos++; + if ( pos >= buf_size ) { + result += QString( c, pos ); + pos = 0; + } + c[pos] = ts_getc(); + } + result += QString( c, pos ); + + int len = (int)result.length(); + if ( len && result[len-1] == '\r' ) + result.truncate(len-1); // (if there are two \r, let one stay) + + return result; +} + + +/*! + Reads the entire stream and returns a string containing the text. + + \sa QIODevice::readLine() +*/ + +QString QTextStream::read() +{ +#if defined(CHECK_STATE) + if ( !dev ) { + qWarning( "QTextStream::read: No device" ); + return QString::null; + } +#endif + QString result; + const uint bufsize = 512; + QChar buf[bufsize]; + uint i, num, start; + bool skipped_cr = FALSE; + + while ( 1 ) { + num = ts_getbuf(buf,bufsize); + // do a s/\r\n/\n + start = 0; + for ( i=0; i<num; i++ ) { + if ( buf[i] == '\r' ) { + // Only skip single cr's preceding lf's + if ( skipped_cr ) { + result += buf[i]; + start++; + } else { + result += QString( &buf[start], i-start ); + start = i+1; + skipped_cr = TRUE; + } + } else { + if ( skipped_cr ) { + if ( buf[i] != '\n' ) { + // Should not have skipped it + result += '\r'; + } + skipped_cr = FALSE; + } + } + } + if ( start < num ) + result += QString( &buf[start], i-start ); + if ( num != bufsize ) // if ( EOF ) + break; + } + return result; +} + + + +/***************************************************************************** + QTextStream write functions + *****************************************************************************/ + +/*! + Writes a \c char to the stream and returns a reference to the stream. + + The character \a c is assumed to be Latin1 encoded independent of the Encoding set + for the QTextStream. +*/ +QTextStream &QTextStream::operator<<( QChar c ) +{ + CHECK_STREAM_PRECOND + ts_putc( c ); + return *this; +} + +/*! + Writes a \c char to the stream and returns a reference to the stream. +*/ +QTextStream &QTextStream::operator<<( char c ) +{ + CHECK_STREAM_PRECOND + unsigned char uc = (unsigned char) c; + ts_putc( uc ); + return *this; +} + +QTextStream &QTextStream::output_int( int format, ulong n, bool neg ) +{ + static char hexdigits_lower[] = "0123456789abcdef"; + static char hexdigits_upper[] = "0123456789ABCDEF"; + CHECK_STREAM_PRECOND + char buf[76]; + register char *p; + int len; + char *hexdigits; + + switch ( flags() & I_BASE_MASK ) { + + case I_BASE_2: // output binary number + switch ( format & I_TYPE_MASK ) { + case I_SHORT: len=16; break; + case I_INT: len=sizeof(int)*8; break; + case I_LONG: len=32; break; + default: len = 0; + } + p = &buf[74]; // go reverse order + *p = '\0'; + while ( len-- ) { + *--p = (char)(n&1) + '0'; + n >>= 1; + if ( !n ) + break; + } + if ( flags() & showbase ) { // show base + *--p = (flags() & uppercase) ? 'B' : 'b'; + *--p = '0'; + } + break; + + case I_BASE_8: // output octal number + p = &buf[74]; + *p = '\0'; + do { + *--p = (char)(n&7) + '0'; + n >>= 3; + } while ( n ); + if ( flags() & showbase ) + *--p = '0'; + break; + + case I_BASE_16: // output hexadecimal number + p = &buf[74]; + *p = '\0'; + hexdigits = (flags() & uppercase) ? + hexdigits_upper : hexdigits_lower; + do { + *--p = hexdigits[(int)n&0xf]; + n >>= 4; + } while ( n ); + if ( flags() & showbase ) { + *--p = (flags() & uppercase) ? 'X' : 'x'; + *--p = '0'; + } + break; + + default: // decimal base is default + p = &buf[74]; + *p = '\0'; + if ( neg ) + n = (ulong)(-(long)n); + do { + *--p = ((int)(n%10)) + '0'; + n /= 10; + } while ( n ); + if ( neg ) + *--p = '-'; + else if ( flags() & showpos ) + *--p = '+'; + if ( (flags() & internal) && fwidth && !ts_isdigit(*p) ) { + ts_putc( *p ); // special case for internal + ++p; // padding + fwidth--; + return *this << (const char*)p; + } + } + if ( fwidth ) { // adjustment required + if ( !(flags() & left) ) { // but NOT left adjustment + len = qstrlen(p); + int padlen = fwidth - len; + if ( padlen <= 0 ) { // no padding required + writeBlock( p, len ); + } else if ( padlen < (int)(p-buf) ) { // speeds up padding + memset( p-padlen, (char)fillchar, padlen ); + writeBlock( p-padlen, padlen+len ); + } + else // standard padding + *this << (const char*)p; + } + else + *this << (const char*)p; + fwidth = 0; // reset field width + } + else + writeBlock( p, qstrlen(p) ); + return *this; +} + + +/*! + Writes a \c short integer to the stream and returns a reference to + the stream. +*/ + +QTextStream &QTextStream::operator<<( signed short i ) +{ + return output_int( I_SHORT | I_SIGNED, i, i < 0 ); +} + + +/*! + Writes an \c unsigned \c short integer to the stream and returns a reference + to the stream. +*/ + +QTextStream &QTextStream::operator<<( unsigned short i ) +{ + return output_int( I_SHORT | I_UNSIGNED, i, FALSE ); +} + + +/*! + Writes an \c int to the stream and returns a reference to + the stream. +*/ + +QTextStream &QTextStream::operator<<( signed int i ) +{ + return output_int( I_INT | I_SIGNED, i, i < 0 ); +} + + +/*! + Writes an \c unsigned \c int to the stream and returns a reference to + the stream. +*/ + +QTextStream &QTextStream::operator<<( unsigned int i ) +{ + return output_int( I_INT | I_UNSIGNED, i, FALSE ); +} + + +/*! + Writes a \c long \c int to the stream and returns a reference to + the stream. +*/ + +QTextStream &QTextStream::operator<<( signed long i ) +{ + return output_int( I_LONG | I_SIGNED, i, i < 0 ); +} + + +/*! + Writes an \c unsigned \c long \c int to the stream and returns a reference to + the stream. +*/ + +QTextStream &QTextStream::operator<<( unsigned long i ) +{ + return output_int( I_LONG | I_UNSIGNED, i, FALSE ); +} + + +/*! + Writes a \c float to the stream and returns a reference to the stream. +*/ + +QTextStream &QTextStream::operator<<( float f ) +{ + return *this << (double)f; +} + + +/*! + Writes a \c double to the stream and returns a reference to the stream. +*/ + +QTextStream &QTextStream::operator<<( double f ) +{ + CHECK_STREAM_PRECOND + char buf[64]; + char f_char; + char format[16]; + if ( (flags()&floatfield) == fixed ) + f_char = 'f'; + else if ( (flags()&floatfield) == scientific ) + f_char = (flags() & uppercase) ? 'E' : 'e'; + else + f_char = (flags() & uppercase) ? 'G' : 'g'; + register char *fs = format; // generate format string + *fs++ = '%'; // "%.<prec>l<f_char>" + *fs++ = '.'; + int prec = precision(); + if ( prec > 99 ) + prec = 99; + if ( prec >= 10 ) { + *fs++ = prec / 10 + '0'; + *fs++ = prec % 10 + '0'; + } else { + *fs++ = prec + '0'; + } + *fs++ = 'l'; + *fs++ = f_char; + *fs = '\0'; + sprintf( buf, format, f ); // convert to text + if ( fwidth ) // padding + *this << (const char*)buf; + else // just write it + writeBlock( buf, qstrlen(buf) ); + return *this; +} + + +/*! + Writes a string to the stream and returns a reference to the stream. + + The string \a s is assumed to be Latin1 encoded independent of the Encoding set + for the QTextStream. +*/ + +QTextStream &QTextStream::operator<<( const char* s ) +{ + CHECK_STREAM_PRECOND + char padbuf[48]; + uint len = qstrlen( s ); // don't write null terminator + if ( fwidth ) { // field width set + int padlen = fwidth - len; + fwidth = 0; // reset width + if ( padlen > 0 ) { + char *ppad; + if ( padlen > 46 ) { // create extra big fill buffer + ppad = new char[padlen]; + CHECK_PTR( ppad ); + } else { + ppad = padbuf; + } + memset( ppad, (char)fillchar, padlen ); // fill with fillchar + if ( !(flags() & left) ) { + writeBlock( ppad, padlen ); + padlen = 0; + } + writeBlock( s, len ); + if ( padlen ) + writeBlock( ppad, padlen ); + if ( ppad != padbuf ) // delete extra big fill buf + delete[] ppad; + return *this; + } + } + writeBlock( s, len ); + return *this; +} + +/*! + Writes \a s to the stream and returns a reference to the stream. + + The string \a s is assumed to be Latin1 encoded independent of the Encoding set + for the QTextStream. +*/ + +QTextStream &QTextStream::operator<<( const QCString & s ) +{ + return operator<<(s.data()); +} + +/*! + Writes \a s to the stream and returns a reference to the stream. +*/ + +QTextStream &QTextStream::operator<<( const QString& s ) +{ + CHECK_STREAM_PRECOND + uint len = s.length(); + QString s1 = s; + if ( fwidth ) { // field width set + if ( !(flags() & left) ) { + s1 = s.rightJustify(fwidth, (char)fillchar); + } else { + s1 = s.leftJustify(fwidth, (char)fillchar); + } + fwidth = 0; // reset width + } + writeBlock( s1.unicode(), len ); + return *this; +} + + +/*! + Writes a pointer to the stream and returns a reference to the stream. + + The \e ptr is output as an unsigned long hexadecimal integer. +*/ + +QTextStream &QTextStream::operator<<( void *ptr ) +{ + int f = flags(); + setf( hex, basefield ); + setf( showbase ); + unsetf( uppercase ); + output_int( I_LONG | I_UNSIGNED, (ulong)ptr, FALSE ); + flags( f ); + return *this; +} + + +/*! + \fn int QTextStream::flags() const + Returns the current stream flags. The default value is 0. + + The meaning of the flags are: + <ul> + <li> \e skipws - Not currently used - whitespace always skipped + <li> \e left - Numeric fields are left-aligned + <li> \e right - Not currently used (by default numerics are right aligned) + <li> \e internal - Put any padding spaces between +/- and value + <li> \e bin - Output \e and input only in binary + <li> \e oct - Output \e and input only in octal + <li> \e dec - Output \e and input only in decimal + <li> \e hex - Output \e and input only in hexadecimal + <li> \e showbase - Annotate numeric outputs with 0b, 0, or 0x if in + \e bin, \e oct, or \e hex format + <li> \e showpoint - Not currently used + <li> \e uppercase - Use 0B and 0X rather than 0b and 0x + <li> \e showpos - Show + for positive numeric values + <li> \e scientific - Use scientific notation for floating point values + <li> \e fixed - Use fixed-point notation for floating point values + </ul> + + Note that unless \e bin, \e oct, \e dec, or \e hex is set, the input base is + octal if the value starts with 0, hexadecimal if it starts with 0x, binary + if the value starts with 0b, and decimal otherwise. + + \sa setf(), unsetf() +*/ + +/*! + \fn int QTextStream::flags( int f ) + Sets the stream flags to \e f. + Returns the previous stream flags. + + \sa setf(), unsetf(), flags() +*/ + +/*! + \fn int QTextStream::setf( int bits ) + Sets the stream flag bits \e bits. + Returns the previous stream flags. + + Equivalent to <code>flags( flags() | bits )</code>. + + \sa setf(), unsetf() +*/ + +/*! + \fn int QTextStream::setf( int bits, int mask ) + Sets the stream flag bits \e bits with a bit mask \e mask. + Returns the previous stream flags. + + Equivalent to <code>flags( (flags() & ~mask) | (bits & mask) )</code>. + + \sa setf(), unsetf() +*/ + +/*! + \fn int QTextStream::unsetf( int bits ) + Clears the stream flag bits \e bits. + Returns the previous stream flags. + + Equivalent to <code>flags( flags() & ~mask )</code>. + + \sa setf() +*/ + +/*! + \fn int QTextStream::width() const + Returns the field width. The default value is 0. +*/ + +/*! + \fn int QTextStream::width( int w ) + Sets the field width to \e w. Returns the previous field width. +*/ + +/*! + \fn int QTextStream::fill() const + Returns the fill character. The default value is ' ' (space). +*/ + +/*! + \fn int QTextStream::fill( int f ) + Sets the fill character to \e f. Returns the previous fill character. +*/ + +/*! + \fn int QTextStream::precision() const + Returns the precision. The default value is 6. +*/ + +/*! + \fn int QTextStream::precision( int p ) + Sets the precision to \e p. Returns the previous precision setting. +*/ + + + /***************************************************************************** + QTextStream manipulators + *****************************************************************************/ + +QTextStream &bin( QTextStream &s ) +{ + s.setf(QTS::bin,QTS::basefield); + return s; +} + +QTextStream &oct( QTextStream &s ) +{ + s.setf(QTS::oct,QTS::basefield); + return s; +} + +QTextStream &dec( QTextStream &s ) +{ + s.setf(QTS::dec,QTS::basefield); + return s; +} + +QTextStream &hex( QTextStream &s ) +{ + s.setf(QTS::hex,QTS::basefield); + return s; +} + +QTextStream &endl( QTextStream &s ) +{ + return s << '\n'; +} + +QTextStream &flush( QTextStream &s ) +{ + if ( s.device() ) + s.device()->flush(); + return s; +} + +QTextStream &ws( QTextStream &s ) +{ + s.skipWhiteSpace(); + return s; +} + +QTextStream &reset( QTextStream &s ) +{ + s.reset(); + return s; +} + + +/*! + \class QTextIStream qtextstream.h + \brief A convenience class for input streams. + + For simple tasks, code should be simple. Hence this + class is a shorthand to avoid passing the \e mode argument + to the normal QTextStream constructors. + + This makes it easy for example, to write things like this: +\code + QString data = "123 456"; + int a, b; + QTextIStream(&data) >> a >> b; +\endcode + + \sa QTextOStream +*/ + +/*! + \fn QTextIStream::QTextIStream( QString *s ) + + Constructs a stream to read from string \a s. +*/ +/*! + \fn QTextIStream::QTextIStream( QByteArray ba ) + + Constructs a stream to read from the array \a ba. +*/ +/*! + \fn QTextIStream::QTextIStream( FILE *f ) + + Constructs a stream to read from the file \a f. +*/ + + +/*! + \class QTextOStream qtextstream.h + \brief A convenience class for output streams. + + For simple tasks, code should be simple. Hence this + class is a shorthand to avoid passing the \e mode argument + to the normal QTextStream constructors. + + This makes it easy for example, to write things like this: +\code + QString result; + QTextOStream(&result) << "pi = " << 3.14; +\endcode +*/ + +/*! + \fn QTextOStream::QTextOStream( QString *s ) + + Constructs a stream to write to string \a s. +*/ +/*! + \fn QTextOStream::QTextOStream( QByteArray ba ) + + Constructs a stream to write to the array \a ba. +*/ +/*! + \fn QTextOStream::QTextOStream( FILE *f ) + + Constructs a stream to write to the file \a f. +*/ + + + +/*! + Sets the encoding of this stream to \a e, where \a e is one of: + <ul> + <li> \c Locale Using local file format (Latin1 if locale is not + set), but autodetecting Unicode(utf16) on input. + <li> \c Unicode Using Unicode(utf16) for input and output. Output + will be written in the order most efficient for the current platform + (i.e. the order used internally in QString). + <li> \c UnicodeUTF8 Using Unicode(utf8) for input and output. If you use it + for input it will autodetect utf16 and use it instead of utf8. + <li> \c Latin1 ISO-8859-1. Will not autodetect utf16. + <li> \c UnicodeNetworkOrder Using network order Unicode(utf16) for + input and output. Useful when reading Unicode data that does not + start with the byte order marker. + <li> \c UnicodeReverse Using reverse network order Unicode(utf16) + for input and output. Useful when reading Unicode data that does not + start with the byte order marker, or writing data that should be + read by buggy Windows applications. + <li> \c RawUnicode Like Unicode, but does not write the byte order + marker, nor does it autodetect the byte order. Only useful when + writing to non-persistent storage used by a single process. + </ul> + + \c Locale and all Unicode encodings, except \c RawUnicode, will look at + the first two bytes in a input stream to determine the byte order. The + initial byte order marker will be stripped off before data is read. + + Note that this function should be called before any data is read + to/written from the stream. + \sa setCodec() +*/ + +void QTextStream::setEncoding( Encoding e ) +{ + if ( d->sourceType == QTextStreamPrivate::String ) + return; // QString does not need any encoding + switch ( e ) { + case Unicode: + mapper = 0; + latin1 = FALSE; + doUnicodeHeader = TRUE; + internalOrder = TRUE; + break; + case UnicodeUTF8: +#ifndef QT_NO_CODECS + mapper = QTextCodec::codecForMib( 106 ); + latin1 = FALSE; + doUnicodeHeader = TRUE; + internalOrder = TRUE; +#else + mapper = 0; + latin1 = TRUE; + doUnicodeHeader = TRUE; +#endif + break; + case UnicodeNetworkOrder: + mapper = 0; + latin1 = FALSE; + doUnicodeHeader = TRUE; + internalOrder = QChar::networkOrdered(); + break; + case UnicodeReverse: + mapper = 0; + latin1 = FALSE; + doUnicodeHeader = TRUE; + internalOrder = !QChar::networkOrdered(); //reverse network ordered + break; + case RawUnicode: + mapper = 0; + latin1 = FALSE; + doUnicodeHeader = FALSE; + internalOrder = TRUE; + break; + case Locale: + latin1 = TRUE; // fallback to Latin 1 +#ifndef QT_NO_TEXTCODEC + mapper = QTextCodec::codecForLocale(); +#if defined(_OS_WIN32_) + if ( GetACP() == 1252 ) + mapper = 0; // Optimized latin1 processing +#endif + if ( mapper && mapper->mibEnum() == 4 ) +#endif + mapper = 0; // Optimized latin1 processing + doUnicodeHeader = TRUE; // If it reads as Unicode, accept it + break; + case Latin1: + mapper = 0; + doUnicodeHeader = FALSE; + latin1 = TRUE; + break; + } +} + + +#ifndef QT_NO_TEXTCODEC +/*! Sets the codec for this stream to \a codec. Will not try to + autodetect Unicode. + + Note that this function should be called before any data is read + to/written from the stream. + + \sa setEncoding() +*/ + +void QTextStream::setCodec( QTextCodec *codec ) +{ + if ( d->sourceType == QTextStreamPrivate::String ) + return; // QString does not need any codec + mapper = codec; + doUnicodeHeader = FALSE; +} +#endif + +#endif // QT_NO_TEXTSTREAM diff --git a/trunk/qtools/qtextstream.h b/trunk/qtools/qtextstream.h new file mode 100644 index 0000000..c5f5ba1 --- /dev/null +++ b/trunk/qtools/qtextstream.h @@ -0,0 +1,351 @@ +/**************************************************************************** +** +** +** Definition of QTextStream class +** +** Created : 940922 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QTEXTSTREAM_H +#define QTEXTSTREAM_H + +#ifndef QT_H +#include "qiodevice.h" +#include "qstring.h" +#include <stdio.h> +#endif // QT_H + +#ifndef QT_NO_TEXTSTREAM +class QTextCodec; +class QTextDecoder; + +class QTextStreamPrivate; + +class Q_EXPORT QTextStream // text stream class +{ +public: + enum Encoding { Locale, Latin1, Unicode, UnicodeNetworkOrder, + UnicodeReverse, RawUnicode, UnicodeUTF8 }; + + void setEncoding( Encoding ); +#ifndef QT_NO_TEXTCODEC + void setCodec( QTextCodec* ); +#endif + + // Encoding encoding() const { return cmode; } + + QTextStream(); + QTextStream( QIODevice * ); + QTextStream( QString*, int mode ); + QTextStream( QString&, int mode ); // obsolete + QTextStream( QByteArray, int mode ); + QTextStream( FILE *, int mode ); + virtual ~QTextStream(); + + QIODevice *device() const; + void setDevice( QIODevice * ); + void unsetDevice(); + + bool atEnd() const; + bool eof() const; + + QTextStream &operator>>( QChar & ); + QTextStream &operator>>( char & ); + QTextStream &operator>>( signed short & ); + QTextStream &operator>>( unsigned short & ); + QTextStream &operator>>( signed int & ); + QTextStream &operator>>( unsigned int & ); + QTextStream &operator>>( signed long & ); + QTextStream &operator>>( unsigned long & ); + QTextStream &operator>>( float & ); + QTextStream &operator>>( double & ); + QTextStream &operator>>( char * ); + QTextStream &operator>>( QString & ); + QTextStream &operator>>( QCString & ); + + QTextStream &operator<<( QChar ); + QTextStream &operator<<( char ); + QTextStream &operator<<( signed short ); + QTextStream &operator<<( unsigned short ); + QTextStream &operator<<( signed int ); + QTextStream &operator<<( unsigned int ); + QTextStream &operator<<( signed long ); + QTextStream &operator<<( unsigned long ); + QTextStream &operator<<( float ); + QTextStream &operator<<( double ); + QTextStream &operator<<( const char* ); + QTextStream &operator<<( const QString & ); + QTextStream &operator<<( const QCString & ); + QTextStream &operator<<( void * ); // any pointer + + QTextStream &readRawBytes( char *, uint len ); + QTextStream &writeRawBytes( const char* , uint len ); + + QString readLine(); + QString read(); + void skipWhiteSpace(); + + enum { + skipws = 0x0001, // skip whitespace on input + left = 0x0002, // left-adjust output + right = 0x0004, // right-adjust output + internal = 0x0008, // pad after sign + bin = 0x0010, // binary format integer + oct = 0x0020, // octal format integer + dec = 0x0040, // decimal format integer + hex = 0x0080, // hex format integer + showbase = 0x0100, // show base indicator + showpoint = 0x0200, // force decimal point (float) + uppercase = 0x0400, // upper-case hex output + showpos = 0x0800, // add '+' to positive integers + scientific= 0x1000, // scientific float output + fixed = 0x2000 // fixed float output + }; + + static const int basefield; // bin | oct | dec | hex + static const int adjustfield; // left | right | internal + static const int floatfield; // scientific | fixed + + int flags() const; + int flags( int f ); + int setf( int bits ); + int setf( int bits, int mask ); + int unsetf( int bits ); + + void reset(); + + int width() const; + int width( int ); + int fill() const; + int fill( int ); + int precision() const; + int precision( int ); + +private: + long input_int(); + void init(); + QTextStream &output_int( int, ulong, bool ); + QIODevice *dev; + bool isNetworkOrder() { return internalOrder == QChar::networkOrdered(); } + + int fflags; + int fwidth; + int fillchar; + int fprec; + bool fstrm; + bool owndev; + QTextCodec *mapper; + QTextStreamPrivate * d; + QChar ungetcBuf; + bool latin1; + bool internalOrder; + bool doUnicodeHeader; + void *reserved_ptr; + + QChar eat_ws(); + void ts_ungetc( QChar ); + QChar ts_getc(); + uint ts_getbuf( QChar*, uint ); + void ts_putc(int); + void ts_putc(QChar); + bool ts_isspace(QChar); + bool ts_isdigit(QChar); + ulong input_bin(); + ulong input_oct(); + ulong input_dec(); + ulong input_hex(); + double input_double(); + QTextStream &writeBlock( const char* p, uint len ); + QTextStream &writeBlock( const QChar* p, uint len ); + +private: // Disabled copy constructor and operator= +#if defined(Q_DISABLE_COPY) + QTextStream( const QTextStream & ); + QTextStream &operator=( const QTextStream & ); +#endif +}; + +typedef QTextStream QTS; + +class Q_EXPORT QTextIStream : public QTextStream { +public: + QTextIStream( QString* s ) : + QTextStream(s,IO_ReadOnly) { } + QTextIStream( QByteArray ba ) : + QTextStream(ba,IO_ReadOnly) { } + QTextIStream( FILE *f ) : + QTextStream(f,IO_ReadOnly) { } +}; + +class Q_EXPORT QTextOStream : public QTextStream { +public: + QTextOStream( QString* s ) : + QTextStream(s,IO_WriteOnly) { } + QTextOStream( QByteArray ba ) : + QTextStream(ba,IO_WriteOnly) { } + QTextOStream( FILE *f ) : + QTextStream(f,IO_WriteOnly) { } +}; + +/***************************************************************************** + QTextStream inline functions + *****************************************************************************/ + +inline QIODevice *QTextStream::device() const +{ return dev; } + +inline bool QTextStream::atEnd() const +{ return dev ? dev->atEnd() : FALSE; } + +inline bool QTextStream::eof() const +{ return atEnd(); } + +inline int QTextStream::flags() const +{ return fflags; } + +inline int QTextStream::flags( int f ) +{ int oldf = fflags; fflags = f; return oldf; } + +inline int QTextStream::setf( int bits ) +{ int oldf = fflags; fflags |= bits; return oldf; } + +inline int QTextStream::setf( int bits, int mask ) +{ int oldf = fflags; fflags = (fflags & ~mask) | (bits & mask); return oldf; } + +inline int QTextStream::unsetf( int bits ) +{ int oldf = fflags; fflags &= ~bits; return oldf; } + +inline int QTextStream::width() const +{ return fwidth; } + +inline int QTextStream::width( int w ) +{ int oldw = fwidth; fwidth = w; return oldw; } + +inline int QTextStream::fill() const +{ return fillchar; } + +inline int QTextStream::fill( int f ) +{ int oldc = fillchar; fillchar = f; return oldc; } + +inline int QTextStream::precision() const +{ return fprec; } + +inline int QTextStream::precision( int p ) +{ int oldp = fprec; fprec = p; return oldp; } + +/*! + Returns one character from the stream, or EOF. +*/ +inline QChar QTextStream::ts_getc() +{ QChar r; return ( ts_getbuf( &r,1 ) == 1 ? r : QChar((ushort)0xffff) ); } + +/***************************************************************************** + QTextStream manipulators + *****************************************************************************/ + +typedef QTextStream & (*QTSFUNC)(QTextStream &);// manipulator function +typedef int (QTextStream::*QTSMFI)(int); // manipulator w/int argument + +class Q_EXPORT QTSManip { // text stream manipulator +public: + QTSManip( QTSMFI m, int a ) { mf=m; arg=a; } + void exec( QTextStream &s ) { (s.*mf)(arg); } +private: + QTSMFI mf; // QTextStream member function + int arg; // member function argument +}; + +Q_EXPORT inline QTextStream &operator>>( QTextStream &s, QTSFUNC f ) +{ return (*f)( s ); } + +Q_EXPORT inline QTextStream &operator<<( QTextStream &s, QTSFUNC f ) +{ return (*f)( s ); } + +Q_EXPORT inline QTextStream &operator<<( QTextStream &s, QTSManip m ) +{ m.exec(s); return s; } + +Q_EXPORT QTextStream &bin( QTextStream &s ); // set bin notation +Q_EXPORT QTextStream &oct( QTextStream &s ); // set oct notation +Q_EXPORT QTextStream &dec( QTextStream &s ); // set dec notation +Q_EXPORT QTextStream &hex( QTextStream &s ); // set hex notation +Q_EXPORT QTextStream &endl( QTextStream &s ); // insert EOL ('\n') +Q_EXPORT QTextStream &flush( QTextStream &s ); // flush output +Q_EXPORT QTextStream &ws( QTextStream &s ); // eat whitespace on input +Q_EXPORT QTextStream &reset( QTextStream &s ); // set default flags + +Q_EXPORT inline QTSManip qSetW( int w ) +{ + QTSMFI func = &QTextStream::width; + return QTSManip(func,w); +} + +Q_EXPORT inline QTSManip qSetFill( int f ) +{ + QTSMFI func = &QTextStream::fill; + return QTSManip(func,f); +} + +Q_EXPORT inline QTSManip qSetPrecision( int p ) +{ + QTSMFI func = &QTextStream::precision; + return QTSManip(func,p); +} + + +#ifndef QT_ALTERNATE_QTSMANIP + +// These will go away in Qt 3.0, as they conflict with std libs +// +// If you get conflicts now, #define QT_ALTERNATE_QTSMANIP before +// including this file. + +Q_EXPORT inline QTSManip setw( int w ) +{ + QTSMFI func = &QTextStream::width; + return QTSManip(func,w); +} + +Q_EXPORT inline QTSManip setfill( int f ) +{ + QTSMFI func = &QTextStream::fill; + return QTSManip(func,f); +} + +Q_EXPORT inline QTSManip setprecision( int p ) +{ + QTSMFI func = &QTextStream::precision; + return QTSManip(func,p); +} +#endif + +#endif // QT_NO_TEXTSTREAM +#endif // QTEXTSTREAM_H diff --git a/trunk/qtools/qthread.cpp b/trunk/qtools/qthread.cpp new file mode 100644 index 0000000..db2a0de --- /dev/null +++ b/trunk/qtools/qthread.cpp @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qthread.h" +#include "qthread_p.h" + +QThread::QThread() + : d(new QThreadPrivate) +{ +} + +QThread::~QThread() +{ + QMutexLocker locker(&d->mutex); + if (d->running && !d->finished) + qWarning("QThread: Destroyed while thread is still running"); +} + +bool QThread::isFinished() const +{ + QMutexLocker locker(&d->mutex); + return d->finished; +} + +bool QThread::isRunning() const +{ + QMutexLocker locker(&d->mutex); + return d->running; +} + +void QThread::setStackSize(unsigned int stackSize) +{ + QMutexLocker locker(&d->mutex); + if (d->running) + { + qWarning("QThread: Cannot change stack size while thread is running!"); + return; + } + d->stackSize = stackSize; +} + +unsigned int QThread::stackSize() const +{ + QMutexLocker locker(&d->mutex); + return d->stackSize; +} + diff --git a/trunk/qtools/qthread.h b/trunk/qtools/qthread.h new file mode 100644 index 0000000..81868bd --- /dev/null +++ b/trunk/qtools/qthread.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTHREAD_H +#define QTHREAD_H + +class QThreadPrivate; + +class QThread +{ + public: + explicit QThread(); + virtual ~QThread(); + + bool isFinished() const; + bool isRunning() const; + + void start(); + void terminate(); + void wait(); + void setStackSize(unsigned int stackSize); + unsigned int stackSize() const; + static int idealThreadCount(); + +protected: + // events + virtual void started() {} + virtual void finished() {} + virtual void terminated() {} + + // main loop + virtual void run() {} + +private: + QThreadPrivate *d; + friend class QThreadPrivate; +}; + +#endif // QTHREAD_H diff --git a/trunk/qtools/qthread_p.h b/trunk/qtools/qthread_p.h new file mode 100644 index 0000000..87692aa --- /dev/null +++ b/trunk/qtools/qthread_p.h @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTHREAD_P_H +#define QTHREAD_P_H + +#include "qglobal.h" + +#if defined(_OS_UNIX_) || defined(_OS_MAC_) +#include <pthread.h> +#elif defined(_OS_WIN32_) +#include <windows.h> +#endif + +#include "qthread.h" +#include "qmutex.h" +#include "qwaitcondition.h" + +class QThreadPrivate +{ +public: + QThreadPrivate(); + ~QThreadPrivate(); + + mutable QMutex mutex; + + bool running; + bool finished; + bool terminated; + uint stackSize; + +#if defined(_OS_UNIX_) || defined(_OS_MAC_) + pthread_t thread_id; + QWaitCondition thread_done; + static void *start(void *arg); + static void finish(void *arg); +#elif defined(_OS_WIN32_) + HANDLE handle; + static unsigned int __stdcall start(void *); + static void finish(void *,bool lockAnyway=TRUE); + int waiters; +#else +#error "unsupported platform!" +#endif +}; + +#endif // QTHREAD_P_H diff --git a/trunk/qtools/qthread_unix.cpp b/trunk/qtools/qthread_unix.cpp new file mode 100644 index 0000000..5a7b788 --- /dev/null +++ b/trunk/qtools/qthread_unix.cpp @@ -0,0 +1,219 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qglobal.h" + +#if defined(_OS_HPUX_) +#include <sys/pstat.h> +#elif defined(_OS_MAC_) +#undef DEBUG +#include <CoreServices/CoreServices.h> +#elif defined(_OS_BSDI_) +#include <mach/mach_types.h> +#include <sys/systm.h> +#include <sys/types.h> +#include <sys/sysctl.h> +#endif +#include <unistd.h> +#include <stdio.h> + +#include "qthread.h" +#include "qthread_p.h" + + +/************************************************************************** + ** QThreadPrivate + *************************************************************************/ + +QThreadPrivate::QThreadPrivate() : + running(FALSE), finished(FALSE), terminated(FALSE), stackSize(0) +{ + thread_id = 0; +} + +QThreadPrivate::~QThreadPrivate() +{ +} + +void *QThreadPrivate::start(void *arg) +{ + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); + pthread_cleanup_push(QThreadPrivate::finish, arg); + + QThread *thr = reinterpret_cast<QThread *>(arg); + + thr->started(); + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); + pthread_testcancel(); + thr->run(); + + pthread_cleanup_pop(1); + return 0; +} + +void QThreadPrivate::finish(void *arg) +{ + QThread *thr = reinterpret_cast<QThread *>(arg); + QThreadPrivate *d = thr->d; + QMutexLocker locker(&d->mutex); + + d->running = FALSE; + d->finished = TRUE; + if (d->terminated) + thr->terminated(); + d->terminated = FALSE; + thr->finished(); + + d->thread_id = 0; + d->thread_done.wakeAll(); +} + + + + +/************************************************************************** + ** QThread + *************************************************************************/ + +void QThread::start() +{ + QMutexLocker locker(&d->mutex); + if (d->running) return; + + d->running = TRUE; + d->finished = FALSE; + + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED); + pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED); + if (d->stackSize>0) + { +#if defined(_POSIX_THREAD_ATTR_STACKSIZE) && (_POSIX_THREAD_ATTR_STACKSIZE-0>0) + pthread_attr_setstacksize(&attr,d->stackSize); +#endif + } + int code = pthread_create(&d->thread_id, &attr, QThreadPrivate::start, this); + pthread_attr_destroy(&attr); + + if (code) + { + qWarning("QThread::start: Thread creation error: %d", code); + + d->running = FALSE; + d->finished = FALSE; + d->thread_id = 0; + } +} + +void QThread::terminate() +{ + QMutexLocker locker(&d->mutex); + + if (!d->thread_id) return; + + int code = pthread_cancel(d->thread_id); + if (code) + { + qWarning("QThread::start: Thread termination error: %d", code); + } + else + { + d->terminated = TRUE; + } +} + +void QThread::wait() +{ + QMutexLocker locker(&d->mutex); + if (d->finished || !d->running) return; + + while (d->running) + { + d->thread_done.wait(locker.mutex()); + } +} + +#if defined(QT_LINUXBASE) && !defined(_SC_NPROCESSORS_ONLN) +// LSB doesn't define _SC_NPROCESSORS_ONLN. +# define _SC_NPROCESSORS_ONLN 84 +#endif + +int QThread::idealThreadCount() +{ + int cores = -1; +#if defined(_OS_MAC_) + // Mac OS X + cores = MPProcessorsScheduled(); +#elif defined(_OS_HPUX_) + // HP-UX + struct pst_dynamic psd; + if (pstat_getdynamic(&psd, sizeof(psd), 1, 0) == -1) + { + perror("pstat_getdynamic"); + cores = -1; + } + else + { + cores = (int)psd.psd_proc_cnt; + } +#elif defined(_OS_BSDI_) + // FreeBSD, OpenBSD, NetBSD, BSD/OS + size_t len = sizeof(cores); + int mib[2]; + mib[0] = CTL_HW; + mib[1] = HW_NCPU; + + if (sysctl(mib, 2, &cores, &len, NULL, 0) != 0) + { + perror("sysctl"); + cores = -1; + } +#elif defined(_OS_IRIX_) + // IRIX + cores = (int)sysconf(_SC_NPROC_ONLN); +#else + // the rest: Linux, Solaris, AIX, Tru64 + cores = (int)sysconf(_SC_NPROCESSORS_ONLN); +#endif + return cores; +} + diff --git a/trunk/qtools/qthread_win32.cpp b/trunk/qtools/qthread_win32.cpp new file mode 100644 index 0000000..2c62e93 --- /dev/null +++ b/trunk/qtools/qthread_win32.cpp @@ -0,0 +1,158 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qthread.h" +#include "qthread_p.h" + +/************************************************************************** + ** QThreadPrivate + *************************************************************************/ + +QThreadPrivate::QThreadPrivate() : + running(FALSE), finished(FALSE), terminated(FALSE), stackSize(0) +{ + handle = NULL; + waiters = 0; +} + +QThreadPrivate::~QThreadPrivate() +{ +} + +unsigned int __stdcall QThreadPrivate::start(void *arg) +{ + QThread *thr = reinterpret_cast<QThread *>(arg); + thr->started(); + thr->run(); + finish(arg); + return 0; +} + +void QThreadPrivate::finish(void *arg,bool lockAnyway) +{ + QThread *thr = reinterpret_cast<QThread *>(arg); + QThreadPrivate *d = thr->d; + + if (lockAnyway) d->mutex.lock(); + + d->running = FALSE; + d->finished = TRUE; + if (d->terminated) thr->terminated(); + d->terminated = FALSE; + thr->finished(); + + if (!d->waiters) + { + CloseHandle(d->handle); + d->handle = 0; + } + + if (lockAnyway) d->mutex.unlock(); +} + +/************************************************************************** + ** QThread + *************************************************************************/ + +void QThread::start() +{ + QMutexLocker locker(&d->mutex); + + if (d->running) return; + + d->running = TRUE; + d->finished = FALSE; + d->terminated = FALSE; + + d->handle = CreateThread(NULL,d->stackSize, + (LPTHREAD_START_ROUTINE)QThreadPrivate::start,this,0,NULL); + + if (!d->handle) + { + qWarning("QThread::start: Failed to create thread: errno=%d",errno); + d->running = FALSE; + d->finished = TRUE; + return; + } +} + +void QThread::terminate() +{ + QMutexLocker locker(&d->mutex); + if (!d->running) return; + TerminateThread(d->handle, 0); + d->terminated = TRUE; + QThreadPrivate::finish(this); +} + +void QThread::wait() +{ + QMutexLocker locker(&d->mutex); + if (d->finished || !d->running) return; + + ++d->waiters; + locker.mutex()->unlock(); + + WaitForSingleObject(d->handle,INFINITE); + + locker.mutex()->lock(); + --d->waiters; + if (!d->finished) // thread was terminated by someone else + { + d->terminated = TRUE; + QThreadPrivate::finish(this); + } + + if (d->finished && d->waiters) + { + CloseHandle(d->handle); + d->handle = 0; + } +} + +int QThread::idealThreadCount() +{ + SYSTEM_INFO sysinfo; + GetSystemInfo(&sysinfo); + return sysinfo.dwNumberOfProcessors; +} + + diff --git a/trunk/qtools/qtl.doc b/trunk/qtools/qtl.doc new file mode 100644 index 0000000..db5b994 --- /dev/null +++ b/trunk/qtools/qtl.doc @@ -0,0 +1,249 @@ +/**************************************************************************** +** +** +** Qt template library classes documentation +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +/*! +\page qtl.html + +\title Qt Template library + +Thq Qt Template Library is a set of templates within Qt dealing with +containers of objects. It provides a list of objects, a stack of +objects, a map (or dictionary) from one type to another, and +associated iterators and algorithms. + +Qt also contains similar classes that deal with pointers to objects; +\l QValueList vs. \l QList, etc. Compared to the pointer-based +templates, the QTL offers easy copying of the container, real support +for classes that e.g. require constructors, expand to much more object +code, can often be a bit faster, require that the objects stored can +be copied, and finally, have a worse record of compiler problems. + +Compared to the STL, the QTL contains only the most important features +of the STL, has more regular function naming, has no platform +differences, is often a little slower and often expands to less object +code. + + +If you can not make copies of the objects you want to store you are +better off with QCollection and friends. They were designed to handle +exactly that kind of pointer semantics. This applies for example to +all classes derived from \l QObject. A QObject does not have a copy +constructor, so using it as value is impossible. You may choose be +store pointers to QObjects in a QValueList, but using QList directly +seems to be the better choice for this kind of application +domain. QList, like all other QCollection based containers, provides +far more sanity checking than a speed-optimized value +based container. + +If you have objects that implement value semantics, use the Qt +template library. Value semantics require at least +<ul> +<li>a copy constructor, +<li>an assignment operator and +<li> a default constructor, i.e. a constructor that does not take +any arguments. +</ul> +Note that a fast copy constructor is absolutely crucial for a good +overall performance of the container, since many copy operations are +going to happen. + +Examples for value based classes are QRect, QPoint, QSize and all +simple C++ types like int, bool or double. + +The Qt template library is designed for speed. Especially iterators +are extremely fast. On the drawback side, less error checking is done +than in the QCollection based containers. A template library container +for example does not track associated iterators. This makes certain +validity checks, like on removing items, impossible to perform +automatically. + +<h2> Iterators </h2> + +The Qt template library deals with value objects, not with pointers. +For that reason, there is no other way of iterating over containers +than using iterators. This is no disadvantage as the size of an +iterator matches the size of a normal pointer - 32 or 64 bits +depending on your CPU architecture. + +To iterate over a container, use a loop like this: + +\code + typedef QValueList<int> List; + List l; + for( List::Iterator it = l.begin(); it != l.end(); ++it ) + printf("Number is %i\n",*it); +\endcode + +begin() returns the iterator pointing at the first element, while +end() returns an iterator that points \e after the last +element. end() marks an invalid position, it can never be +dereferenced. It's the break condition in any iteration, may it be +from begin() or fromLast(). For maximum speed, use increment or +decrement iterators with the prefix operator (++it, --it) instead of the the +postfix one (it++, it--), since the former is slightly faster. + +The same concept applies to the other container classes: + +\code + typedef QMap<QString,QString> Map; + Map map; + for( Map::Iterator it = map.begin(); it != map.end(); ++it ) + printf("Key=%s Data=%s\n", it.key().ascii(), it.data().ascii() ); + + typedef QArray<int> Array; + Array array; + for( Array::Iterator it = array.begin(); it != array.end(); ++it ) + printf("Data=%i\n", *it ); +\endcode + +There are two kind of iterators, the volatile iterator shown in the +examples above and a version that returns a const reference to its +current object, the ConstIterator. Const iterators are required +whenever the container itself is const, such as a member variable +inside a const function. Assigning a ConstIterator to a normal +Iterator is not allowed as it would violate const semantics. + +<h2> Algorithms </h2> + +The template library defines a number of algorithms that operate on +its containers: qHeapSort(), qBubbleSort(), qSwap() and +qCopy(). These algorithms are implemented as template functions. + +qHeapSort() and qBubbleSort() provide the well known sorting +algorithms. You can use them like this: + +\code + typedef QValueList<int> List; + List l; + l << 42 << 100 << 1234 << 12 << 8; + qHeapSort( l ); + + List l2; + l2 << 42 << 100 << 1234 << 12 << 8; + List::Iterator b = l2.find( 100 ); + List::Iterator e = l2.find( 8 ); + qHeapSort( b, e ); + + double arr[] = { 3.2, 5.6, 8.9 }; + qHeapSort( arr, arr + 3 ); +\endcode + +The first example sorts the entire list. The second one sorts all +elements enclosed in the two iterators, namely 100, 1234 and 12. The +third example shows that iterators act like pointers and can be +treated as such. + +Naturally, the sorting templates won't work with const iterators. + +Another utility is qSwap(). It exchanges the values of two variables: + +\code + QString second( "Einstein" ); + QString name( "Albert" ); + qSwap( second, name ); +\endcode + +Another template function is qCopy(). It copies a container or a slice +of it to an OutputIterator, in this case a QTextOStreamIterator: + +\code + typedef QValueList<int> List; + List l; + l << 100 << 200 << 300; + QTextOStream str( stdout ); + qCopy( l, QTextOStreamIterator( str ) ); +\endcode + +In addition, you can use any Qt template library iterator as the +OutputIterator. Just make sure that the right hand of the iterator has +as many elements present as you want to insert. The following example +illustrates this: + +\code + QStringList l1, l2; + l1 << "Weis" << "Ettrich" << "Arnt" << "Sue"; + l2 << "Torben" << "Matthias"; + qCopy( l2, l1.begin(); +\endcode + +At the end of this code fragment, the List l1 contains "Torben", +"Matthias", "Arnt" and "Sue", with the prior contents being +overwritten. Another flavor of qCopy() takes three arguments to make +it possible to copy a slice of a container: + +\code + typedef QValueList<int> List; + List l; + l << 42 << 100 << 1234 << 12 << 8; + List::Iterator b = l.find( 100 ); + List::Iterator e = l.find( 8 ); + QTextOStream str( stdout ); + qCopy( b, e, QTextOStreamIterator( str ) ); +\endcode + +If you write new algorithms, consider writing them as template +functions in order to make them usable with as many containers +possible. In the above example, you could just as easily print out a +standard C++ array with qCopy(): + +\code + int arr[] = { 100, 200, 300 }; + QTextOStream str( stdout ); + qCopy( arr, arr + 3, QTextOStreamIterator( str ) ); +\endcode + + +<h2> Streaming </h2> + +All mentioned containers can be serialized with the respective +streaming operators. Here is an example. + +\code + QDataStream str(...); + QValueList<QRect> l; + // ... fill the list here + str << l; +\endcode + +The container can be read in again with: + +\code + QValueList<QRect> l; + str >> l; +\endcode + +The same applies to QStringList, QValueStack and QMap. + +*/ diff --git a/trunk/qtools/qtl.h b/trunk/qtools/qtl.h new file mode 100644 index 0000000..bd72e7d --- /dev/null +++ b/trunk/qtools/qtl.h @@ -0,0 +1,223 @@ +/**************************************************************************** +** +** +** Definition of Qt template library classes +** +** Created : 990128 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ +#ifndef QTL_H +#define QTL_H + +#ifndef QT_H +#include "qtextstream.h" +#include "qstring.h" +#endif // QT_H + +#ifndef QT_NO_TEXTSTREAM +template <class T> +class QTextOStreamIterator +{ +protected: + QTextOStream& stream; + QString separator; + +public: + QTextOStreamIterator( QTextOStream& s) : stream( s ) {} + QTextOStreamIterator( QTextOStream& s, const QString& sep ) + : stream( s ), separator( sep ) {} + QTextOStreamIterator<T>& operator= ( const T& x ) { + stream << x; + if ( !separator.isEmpty() ) + stream << separator; + return *this; + } + QTextOStreamIterator<T>& operator*() { return *this; } + QTextOStreamIterator<T>& operator++() { return *this; } + QTextOStreamIterator<T>& operator++(int) { return *this; } +}; +#endif //QT_NO_TEXTSTREAM + +template <class InputIterator, class OutputIterator> +inline OutputIterator qCopy( InputIterator _begin, InputIterator _end, + OutputIterator _dest ) +{ + while( _begin != _end ) + *_dest++ = *_begin++; + return _dest; +} + + +template <class T> +inline void qSwap( T& _value1, T& _value2 ) +{ + T tmp = _value1; + _value1 = _value2; + _value2 = tmp; +} + + +template <class InputIterator> +inline void qBubbleSort( InputIterator b, InputIterator e ) +{ + // Goto last element; + InputIterator last = e; + --last; + // only one element or no elements ? + if ( last == b ) + return; + + // So we have at least two elements in here + while( b != last ) { + bool swapped = FALSE; + InputIterator swap_pos = b; + InputIterator x = e; + InputIterator y = x; + y--; + do { + --x; + --y; + if ( *x < *y ) { + swapped = TRUE; + qSwap( *x, *y ); + swap_pos = y; + } + } while( y != b ); + if ( !swapped ) + return; + b = swap_pos; + b++; + } +} + + +template <class Container> +inline void qBubbleSort( Container &c ) +{ + qBubbleSort( c.begin(), c.end() ); +} + + +template <class Value> +inline void qHeapSortPushDown( Value* heap, int first, int last ) +{ + int r = first; + while( r <= last/2 ) { + // Node r has only one child ? + if ( last == 2*r ) { + // Need for swapping ? + if ( heap[r] > heap[ 2*r ] ) + qSwap( heap[r], heap[ 2*r ] ); + // That's it ... + r = last; + } else { // Node has two children + if ( heap[r] > heap[ 2*r ] && heap[ 2*r ] <= heap[ 2*r+1 ] ) { + // Swap with left child + qSwap( heap[r], heap[ 2*r ] ); + r *= 2; + } else if ( heap[r] > heap[ 2*r+1 ] && + heap[ 2*r+1 ] < heap[ 2*r ] ) { + // Swap with right child + qSwap( heap[r], heap[ 2*r+1 ] ); + r = 2*r+1; + } else { + // We are done + r = last; + } + } + } +} + + +template <class InputIterator, class Value> +inline void qHeapSortHelper( InputIterator b, InputIterator e, Value, uint n ) +{ + // Create the heap + InputIterator insert = b; + Value* realheap = new Value[ n ]; + // Wow, what a fake. But I want the heap to be indexed as 1...n + Value* heap = realheap - 1; + int size = 0; + for( ; insert != e; ++insert ) { + heap[++size] = *insert; + int i = size; + while( i > 1 && heap[i] < heap[ i / 2 ] ) { + qSwap( heap[i], heap[ i / 2 ] ); + i /= 2; + } + } + + // Now do the sorting + for( uint i = n; i > 0; i-- ) { + *b++ = heap[1]; + if ( i > 1 ) { + heap[1] = heap[i]; + qHeapSortPushDown( heap, 1, (int)i - 1 ); + } + } + + delete[] realheap; +} + + +template <class InputIterator> +inline void qHeapSort( InputIterator b, InputIterator e ) +{ + // Empty ? + if ( b == e ) + return; + + // How many entries have to be sorted ? + InputIterator it = b; + uint n = 0; + while ( it != e ) { + ++n; + ++it; + } + + // The second last parameter is a hack to retrieve the value type + // Do the real sorting here + qHeapSortHelper( b, e, *b, n ); +} + + +template <class Container> +inline void qHeapSort( Container &c ) +{ + if ( c.isEmpty() ) + return; + + // The second last parameter is a hack to retrieve the value type + // Do the real sorting here + qHeapSortHelper( c.begin(), c.end(), *(c.begin()), c.count() ); +} + +#endif diff --git a/trunk/qtools/qtools.pro.in b/trunk/qtools/qtools.pro.in new file mode 100644 index 0000000..3eabed9 --- /dev/null +++ b/trunk/qtools/qtools.pro.in @@ -0,0 +1,102 @@ +TEMPLATE = lib +CONFIG = warn_on staticlib $extraopts +HEADERS = qarray.h \ + qbuffer.h \ + qcache.h \ + qgcache.h \ + qcollection.h \ + qconfig.h \ + qcstring.h \ + scstring.h \ + qdatastream.h \ + qdatetime.h \ + qdict.h \ + qdir.h \ + qfeatures.h \ + qfile.h \ + qfiledefs_p.h \ + qfileinfo.h \ + qgarray.h \ + qfeatures.h \ + qgdict.h \ + qgeneric.h \ + qglist.h \ + qglobal.h \ + qgstring.h \ + qgvector.h \ + qintdict.h \ + qiodevice.h \ + qlist.h \ + qptrdict.h \ + qqueue.h \ + qregexp.h \ + qshared.h \ + qsortedlist.h \ + qstack.h \ + qstring.h \ + qstringlist.h \ + qstrlist.h \ + qstrvec.h \ + qtextstream.h \ + qtl.h \ + qvaluelist.h \ + qvector.h \ + qxml.h \ + qvaluestack.h \ + qmap.h \ + qmodules.h \ + qthread.h \ + qthread_p.h \ + qmutex.h \ + qmutex_p.h \ + qutfcodec.h \ + qwaitcondition.h + +SOURCES = qbuffer.cpp \ + qcollection.cpp \ + scstring.cpp \ + qdatastream.cpp \ + qdatetime.cpp \ + qdir.cpp \ + qfile.cpp \ + qfileinfo.cpp \ + qgarray.cpp \ + qgcache.cpp \ + qgdict.cpp \ + qglist.cpp \ + qglobal.cpp \ + qgstring.cpp \ + qgvector.cpp \ + qiodevice.cpp \ + qregexp.cpp \ + qstring.cpp \ + qtextstream.cpp \ + qtextcodec.cpp \ + qstringlist.cpp \ + qxml.cpp \ + qmap.cpp \ + qthread.cpp \ + qmutex.cpp \ + qutfcodec.cpp + +unix:SOURCES += qfile_unix.cpp \ + qdir_unix.cpp \ + qfileinfo_unix.cpp \ + qthread_unix.cpp \ + qmutex_unix.cpp \ + qwaitcondition_unix.cpp + +win32:SOURCES += qfile_win32.cpp \ + qdir_win32.cpp \ + qfileinfo_win32.cpp \ + qthread_win32.cpp \ + qmutex_win32.cpp \ + qwaitcondition_win32.cpp + +INCLUDEPATH = . +#TMAKE_CXXFLAGS += -DQT_NO_CODECS -DQT_LITE_UNICODE +TMAKE_CXXFLAGS += -DQT_LITE_UNICODE +win32:TMAKE_CXXFLAGS += -DQT_NODLL +win32-g++:TMAKE_CXXFLAGS += -D__CYGWIN__ -DALL_STATIC +OBJECTS_DIR = ../objects +DESTDIR = ../lib diff --git a/trunk/qtools/qutfcodec.cpp b/trunk/qtools/qutfcodec.cpp new file mode 100644 index 0000000..b0caa76 --- /dev/null +++ b/trunk/qtools/qutfcodec.cpp @@ -0,0 +1,276 @@ +/**************************************************************************** +** +** +** Implementation of QEucCodec class +** +** Created : 981015 +** +** Copyright (C)1998-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "qutfcodec.h" + +#ifndef QT_NO_TEXTCODEC + +int QUtf8Codec::mibEnum() const +{ + return 106; +} + +QCString QUtf8Codec::fromUnicode(const QString& uc, int& len_in_out) const +{ + int l = QMIN((int)uc.length(),len_in_out); + int rlen = l*3+1; + QCString rstr(rlen); + uchar* cursor = (uchar*)rstr.data(); + for (int i=0; i<l; i++) { + QChar ch = uc[i]; + if ( !ch.row() && ch.cell() < 0x80 ) { + *cursor++ = ch.cell(); + } else { + uchar b = (ch.row() << 2) | (ch.cell() >> 6); + if ( ch.row() < 0x08 ) { + *cursor++ = 0xc0 | b; + } else { + *cursor++ = 0xe0 | (ch.row() >> 4); + *cursor++ = 0x80 | (b&0x3f); + } + *cursor++ = 0x80 | (ch.cell()&0x3f); + } + } + len_in_out = cursor - (uchar*)rstr.data(); + rstr.truncate(len_in_out); + return rstr; +} + +const char* QUtf8Codec::name() const +{ + return "UTF-8"; +} + +int QUtf8Codec::heuristicContentMatch(const char* chars, int len) const +{ + int score = 0; + for (int i=0; i<len; i++) { + uchar ch = chars[i]; + // No nulls allowed. + if ( !ch ) + return -1; + if ( ch < 128 ) { + // Inconclusive + score++; + } else if ( (ch&0xe0) == 0xc0 ) { + if ( i < len-1 ) { + uchar c2 = chars[++i]; + if ( (c2&0xc0) != 0x80 ) + return -1; + score+=3; + } + } else if ( (ch&0xf0) == 0xe0 ) { + if ( i < len-1 ) { + uchar c2 = chars[++i]; + if ( (c2&0xc0) != 0x80 ) { + return -1; +#if 0 + if ( i < len-1 ) { + uchar c3 = chars[++i]; + if ( (c3&0xc0) != 0x80 ) + return -1; + score+=3; + } +#endif + } + score+=2; + } + } + } + return score; +} + + + + +class QUtf8Decoder : public QTextDecoder { + ushort uc; + int need; +public: + QUtf8Decoder() : need(0) + { + } + + QString toUnicode(const char* chars, int len) + { + QString result; + for (int i=0; i<len; i++) { + uchar ch = chars[i]; + if (need) { + if ( (ch&0xc0) == 0x80 ) { + uc = (uc << 6) | (ch & 0x3f); + need--; + if ( !need ) { + result += QChar(uc); + } + } else { + // error + result += QChar::replacement; + need = 0; + } + } else { + if ( ch < 128 ) { + result += QChar(ch); + } else if ( (ch&0xe0) == 0xc0 ) { + uc = ch &0x1f; + need = 1; + } else if ( (ch&0xf0) == 0xe0 ) { + uc = ch &0x0f; + need = 2; + } + } + } + return result; + } +}; + +QTextDecoder* QUtf8Codec::makeDecoder() const +{ + return new QUtf8Decoder; +} + + + + + + +int QUtf16Codec::mibEnum() const +{ + return 1000; +} + +const char* QUtf16Codec::name() const +{ + return "ISO-10646-UCS-2"; +} + +int QUtf16Codec::heuristicContentMatch(const char* chars, int len) const +{ + uchar* uchars = (uchar*)chars; + if ( len >= 2 && ((uchars[0] == 0xff && uchars[1] == 0xfe) || + (uchars[1] == 0xff && uchars[0] == 0xfe)) ) + return len; + else + return 0; +} + + + + +class QUtf16Encoder : public QTextEncoder { + bool headerdone; +public: + QUtf16Encoder() : headerdone(FALSE) + { + } + + QCString fromUnicode(const QString& uc, int& len_in_out) + { + if ( headerdone ) { + len_in_out = uc.length()*sizeof(QChar); + QCString d(len_in_out); + memcpy(d.data(),uc.unicode(),len_in_out); + return d; + } else { + headerdone = TRUE; + len_in_out = (1+uc.length())*sizeof(QChar); + QCString d(len_in_out); + memcpy(d.data(),&QChar::byteOrderMark,sizeof(QChar)); + memcpy(d.data()+sizeof(QChar),uc.unicode(),uc.length()*sizeof(QChar)); + return d; + } + } +}; + +class QUtf16Decoder : public QTextDecoder { + uchar buf; + bool half; + bool swap; + bool headerdone; + +public: + QUtf16Decoder() : half(FALSE), swap(FALSE), headerdone(FALSE) + { + } + + QString toUnicode(const char* chars, int len) + { + QString r; + + while ( len-- ) { + if ( half ) { + QChar ch; + if ( swap ) { + ch.row() = *chars++; + ch.cell() = buf; + } else { + ch.row() = buf; + ch.cell() = *chars++; + } + if ( !headerdone ) { + if ( ch == QChar::byteOrderSwapped ) { + swap = !swap; + } else if ( ch == QChar::byteOrderMark ) { + // Ignore ZWNBSP + } else { + r += ch; + } + headerdone = TRUE; + } else + r += ch; + half = FALSE; + } else { + buf = *chars++; + half = TRUE; + } + } + + return r; + } +}; + +QTextDecoder* QUtf16Codec::makeDecoder() const +{ + return new QUtf16Decoder; +} + +QTextEncoder* QUtf16Codec::makeEncoder() const +{ + return new QUtf16Encoder; +} + +#endif // QT_NO_TEXTCODEC diff --git a/trunk/qtools/qutfcodec.h b/trunk/qtools/qutfcodec.h new file mode 100644 index 0000000..af864be --- /dev/null +++ b/trunk/qtools/qutfcodec.h @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** +** Definition of QEucCodec class +** +** Created : 981015 +** +** Copyright (C) 1998-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QUTFCODEC_H +#define QUTFCODEC_H + +#ifndef QT_H +#include "qtextcodec.h" +#endif // QT_H + +#ifndef QT_NO_TEXTCODEC + +class Q_EXPORT QUtf8Codec : public QTextCodec { +public: + virtual int mibEnum() const; + const char* name() const; + + QTextDecoder* makeDecoder() const; + + QCString fromUnicode(const QString& uc, int& len_in_out) const; + + int heuristicContentMatch(const char* chars, int len) const; +}; + +class Q_EXPORT QUtf16Codec : public QTextCodec { +public: + virtual int mibEnum() const; + const char* name() const; + + QTextDecoder* makeDecoder() const; + QTextEncoder* makeEncoder() const; + + int heuristicContentMatch(const char* chars, int len) const; +}; + +#endif //QT_NO_TEXTCODEC +#endif // QUTFCODEC_H diff --git a/trunk/qtools/qvaluelist.doc b/trunk/qtools/qvaluelist.doc new file mode 100644 index 0000000..e4621d5 --- /dev/null +++ b/trunk/qtools/qvaluelist.doc @@ -0,0 +1,772 @@ +/**************************************************************************** +** +** +** QValueList and QValueListIterator class documentation +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + + +/***************************************************************************** + QValueList documentation + *****************************************************************************/ + +/*! + \class QValueList qvaluelist.h + \brief The QValueList class is a value based template class that provides doubly linked lists. + + \ingroup qtl + \ingroup tools + \ingroup shared + + Define a template instance QValueList\<X\> to create a list of values which all + have the class X. Please notice that QValueList does not store pointers to the + members of the list. It holds a copy of every member. That is the reason why this + kind of classes are called "value based" while QList and QDict are "reference based". + + Some classes can not be used within a QValueList, for example everything + derived from QObject and thus all classes that implement widgets. + Only values can be used in a QValueList. To qualify as a value, the class + must provide + <ul> + <li>a copy constructor, + <li>an assignment operator and + <li> a default constructor, i.e. a constructor that does not take any arguments. + </ul> + + Note that C++ defaults to field-by-field assignment operators and + copy constructors if no explicit version is supplied. In many cases, + this is sufficient. + + Example: + \code + #include <qvaluelist.h> + #include <qstring.h> + #include <stdio.h> + + class Employee + { + public: + Employee(): s(0) {} + Employee( const QString& name, int salary ) + : n(name), s(salary) + {} + + QString name() const { return n; } + int salary() const { return s; } + void setSalary( int salary ) { s = salary; } + private: + QString n; + int s; + }; + + void main() + { + typedef QValueList<Employee> EmployeeList; + EmployeeList list; // list of Employee + + list.append( Employee("Bill", 50000) ); + list.append( Employee("Steve",80000) ); + list.append( Employee("Ron", 60000) ); + + Employee joe( "Joe", 50000 ); + list.append( joe ); + joe.setSalary( 4000 ); + + EmployeeList::Iterator it; + for( it = list.begin(); it != list.end(); ++it ) + printf( "%s earns %d\n", (*it).name().latin1(), (*it).salary().latin1() ); + } + \endcode + + Program output: + \code + Bill earns 50000 + Steve earns 80000 + Ron earns 60000 + Joe earns 50000 + \endcode + + As you can see, the latest changes to Joes salary did not affect the value + in the list because the list created a copy of Joes entry. + + There are three ways of finding items in the list. The first one is by using + the at() function. It returns an iterator. The advantages of + getting an iterator is that you can now move forward or backward from this + position by incrementing/decrementing the iterator. To get the amount of + items in the list call count(). Valid indices are 0..count(). + + The second way of accessing a list is with operator[]. That means you can address + it like an array. The return value is a reference to the value stored in the list. + There exist two versions of this operator. The first one is const and returns a + const reference to the value. The second on is non const and returns a non const + reference to the value. It is up to your compiler to choose the correct one. + + The third method is to use the functions begin() and end(). + With a simple for loop as shown in the example you can iterate over the complete list. + It is save to have multiple iterators at the same time. If some member of the list is + removed then only iterators pointing to the removed member become invalid. Inserting in + the list does not invalidate any iterator. For convenience the function last() returns + an iterator for the last and first() for the first element in the list. + + In addition you can search items in the list with the find() function. It exists in a const + and a non const version. It starts searching from the beginning of the list, but another + flavor of the find() function allows you to specify where searching should start. + If you just want to know wether a certain item is at least once in the list, then you + can use the contains() function. + + Since QValueList is value based there is no need to care about deleting elements in the + list. The list holds its own copies and will free them if the corresponding member or + the list itself is deleted. You can force the list to free all of its item with clear(). + + QValueList is implicitly shared. That means you can just make copies of the list + in time O(1). If multiple QValueList instances share the same data and one + is doing a modification of the lists data then this modifying instance makes a copy + and modifies its private copy. So it does not affect the other instances. + From a developers point of view you can think that a QValueList and a copy of this + list have nothing to do with each other. Developers may only notice that copying is + very fast. People known to a CPUs MMU architecture will know this pattern as "copy on write". + + There exist three functions to insert items in the list. append() + inserts an item at the end, prepend() inserts at the beginning + and insert() inserts in front of the position given by an iterator. + + Items can be removed from the list in two ways. The first is to pass an iterator to + the remove(). The other possibility is to pass a value to remove() which will + delete all members which match this value. + + Lists can be sorted with the algorithms provided by the <a + href="qtl.html">Qt Template Library</a>, for example with + qHeapSort(): + + Example: + \code + QValueList l; + l.append( 5 ); + l.append( 8 ); + l.append( 3 ); + l.append( 4 ); + qHeapSort( l ); + \endcode + + \sa QValueListIterator +*/ + + +/*! + \fn QValueList::QValueList() + Constructs an empty list. +*/ + +/*! + \fn QValueList::QValueList( const QValueList<T>& l ) + Constructs a copy of \e l. + + This operation costs O(1) time since QValueList is implicit shared. + The first instance applying modifications to a shared list will create + a copy which takes in turn O(n) time. However returning a QValueList from + a function is very fast. +*/ + +/*! + \fn QValueList::~QValueList() + Destroys the list. References to the values in the list and all iterators + of this list become invalidated. Since QValueList is highly tuned for performance + you wont see warnings if you use invalid iterators, + because it is impossible for + an iterator to check wether it is valid or not. +*/ + +/*! + \fn QValueList<T>& QValueList::operator= ( const QValueList<T>& l ) + Assigns \e l to this list and returns a reference to this list. + + All iterators of the current list become invalidated by this operation. + The cost of such an assignment is O(1) since QValueList is implicitly shared. +*/ + +/*! + \fn QValueList<T> QValueList::operator+ ( const QValueList<T>& l ) const + Creates a new list and fills it with the elements of this list. Then the + elements of \e l are appended. + + Returns the new list. +*/ + +/*! + \fn QValueList<T>& QValueList::operator+= ( const QValueList<T>& l ) + Adds \e list to this list. + + Returns a reference to this list. +*/ + +/*! + \fn bool QValueList::operator== ( const QValueList<T>& l ) const + Compares both lists. + + Returns TRUE if both list are equal. +*/ + +/*! + \fn bool QValueList::operator!= ( const QValueList<T>& l ) const + Compares both lists. + + Returns TRUE if both list are unequal. +*/ + +/*! + \fn QValueList<T>& QValueList::operator+= ( const T& x ) + Adds the value \e x to the end of the list. + + Returns a reference to the list. +*/ + +/*! + \fn QValueList<T>& QValueList::operator<< ( const T& x ) + Adds the value \e x to the end of the list. + + Returns a reference to the list. +*/ + +/*! + \fn const T& QValueList::operator[] ( uint i ) const + Returns a const reference to the item with index \e i in the list. + It is up to you to check wether this item really exists. You can do that easily + with the count() function. However this operator does not check wether \e i + is in range and will deliver undefined results if it does not exist. +*/ + +/*! + \fn T& QValueList::operator[] ( uint i ) + Returns a reference to the item with index \e i in the list. + It is up to you to check wether this item really exists. You can do that easily + with the count() function. However this operator does not check wether \e i + is in range and will deliver undefined results if it does not exist. + In contrast to the const operator[] you may manipulate the value returned by this + operator. +*/ + +/*! + \fn uint QValueList::count() const + Returns the number of items in the list. + \sa isEmpty() +*/ + +/*! + \fn bool QValueList::isEmpty() const + Returns TRUE if the list is empty, i.e. count() == 0. Returns FALSE + otherwise. + \sa count() +*/ + +/*! + \fn Iterator QValueList::insert( Iterator it, const T& x ) + Inserts the value \e x in front of the iterator \e it. + + Returns an iterator pointing at the inserted item. + + \sa append(), prepend() +*/ + +/*! + \fn Iterator QValueList::append( const T& x ) + Inserts the value \e x at the end of the list. + + Returns an iterator pointing at the inserted item. + + \sa insert(), prepend() +*/ + +/*! + \fn Iterator QValueList::prepend( const T& x ) + Inserts the value \e x at the beginning of the list. + + Returns an iterator pointing at the inserted item. + + \sa insert(), append() +*/ + +/*! + \fn Iterator QValueList::remove( Iterator it ) + Removes the item at position \e it in the list. + + Returns an iterator pointing to the item following the + removed on or end() if the last item was deleted. + + \sa clear() +*/ + +/*! + \fn void QValueList::remove( const T& x ) + Removes all items which have the value \e x. + + \sa clear() +*/ + +/*! + \fn void QValueList::clear() + Removes all items from the list. + + \sa remove() +*/ + +/*! + \fn Iterator QValueList::find( const T& x ) + Finds the first occurrence of \e x in the list. + + Returns end() if no item did match. +*/ + +/*! + \fn ConstIterator QValueList::find( const T& x ) const + Finds the first occurrence of \e x in the list. + + Returns end() if no item did match. +*/ + +/*! + \fn Iterator QValueList::find( Iterator it, const T& x ) + Finds the first occurrence of \e x in the list starting at + the position given by \e it. + + Returns end() if no item did match. +*/ + +/*! + \fn ConstIterator QValueList::find( ConstIterator it, const T& x ) const + Finds the first occurrence of \e x in the list starting at + the position given by \e it. + + Returns end() if no item did match. +*/ + +/*! + \fn uint QValueList::contains( const T& x ) const + Counts and returns the number of occurrences of the value \e x in the list. +*/ + +/*! + \fn int QValueList::findIndex( const T& x ) const + Returns the first index of the value \e x in the list or -1 if no such value + can be found in the list. +*/ + +/*! + \fn Iterator QValueList::at( uint i ) + Returns an iterator pointing to the item at position \e i in the list, or + end() if the index is out of range. +*/ + +/*! + \fn ConstIterator QValueList::at( uint i ) const + Returns an iterator pointing to the item at position \e i in the list, or + end() if the index is out of range. +*/ + +/*! + \fn T& QValueList::first() + Returns a reference to the first item in the list or the item + referenced by end() + if no such items exists. Please note that you may not change + the value the end() Iterator is pointing to. + + \sa begin(), last() +*/ + +/*! + \fn const T& QValueList::first() const + Returns a reference to the first item in the list or the item + referenced by end() if + no such items exists. + + \sa begin(), last() +*/ + +/*! + \fn Iterator QValueList::fromLast() + Returns an iterator pointing to the last element in the list or + end() if no such item exists. + + \sa last() +*/ + +/*! + \fn ConstIterator QValueList::fromLast() const + Returns an iterator pointing to the last element in the list or + end() if no such item exists. + + \sa last() +*/ + +/*! + \fn T& QValueList::last() + Returns a reference to the last item in the list or the item + referenced by end() if no + such item exists. Please note that you may not change + the value the end() Iterator is pointing to. + + \sa end(), first(), fromLast() +*/ + +/*! + \fn const T& QValueList::last() const + Returns a reference to the last item in the list or the item + referenced by end() if no such item exists. + + \sa end(), first(), fromLast() +*/ + +/*! + \fn Iterator QValueList::begin() + Returns an iterator pointing to the first element in the list. This + iterator equals end() if the list is empty; + \sa first(), end() +*/ + +/*! + \fn ConstIterator QValueList::begin() const + Returns an iterator pointing to the first element in the list. This + iterator equals end() if the list is empty; + \sa first(), end() +*/ + +/*! + \fn Iterator QValueList::end() + Returns an iterator pointing behind the last element in the list. This + iterator equals begin() if the list is empty. + + \sa last(), begin() +*/ + +/*! + \fn ConstIterator QValueList::end() const + Returns an iterator pointing behind the last element in the list. This + iterator equals begin() if the list is empty. + + \sa last(), begin() +*/ + +/*! + \fn void QValueList::detach() + If the list does not share its data with another QValueList instance, then nothing + happens, otherwise the function creates a new copy of this data and detaches + from the shared one. This function is called whenever the list is modified. + The implicit sharing mechanism is implemented this way. +*/ + +/*! + \fn QDataStream& operator>>( QDataStream& s, QValueList<T>& l ) + \relates QValueList + Reads a list from the stream. The type \e T stored in the list must implement + the streaming operator, too. +*/ + +/*! + \fn QDataStream& operator<<( QDataStream& s, const QValueList<T>& l ) + \relates QValueList + Writes a list to the stream. The type \e T stored in the list must implement + the streaming operator, too. +*/ + +/***************************************************************************** + QValueListIterator documentation + *****************************************************************************/ + +/*! + \class QValueListIterator qvaluelist.h + \brief The QValueListIterator class provides an iterator for QValueList. + + \ingroup qtl + \ingroup tools + + You can not create an iterator by yourself. Instead you have to + ask a list to give you one. An iterator has only the size of a pointer. + On 32 bit machines that means 4 bytes otherwise 8 bytes. That makes them + very fast. In fact they resemble the semantics of pointers as good as possible + and they are almost as fast as usual pointers. + + Example: + \code + #include <qvaluelist.h> + #include <qstring.h> + #include <stdio.h> + + class Employee + { + public: + Employee(): s(0) {} + Employee( const QString& name, int salary ) + : n(name), s(salary) + {} + + QString name() const { return n; } + int salary() const { return s; } + void setSalary( int salary ) { s = salary; } + private: + QString n; + int s; + }; + + void main() + { + typedef QValueList<Employee> EmployeeList; + EmployeeList list; // list of Employee + + list.append( Employee("Bill", 50000) ); + list.append( Employee("Steve",80000) ); + list.append( Employee("Ron", 60000) ); + + Employee joe( "Joe", 50000 ); + list.append( joe ); + joe.setSalary( 4000 ); + + EmployeeList::Iterator it; + for( it = list.begin(); it != list.end(); ++it ) + printf( "%s earns %d\n", (*it).name().latin1(), (*it).salary() ); + } + \endcode + + Program output: + \code + Bill earns 50000 + Steve earns 80000 + Ron earns 60000 + Joe earns 50000 + \endcode + + In contrast to QList there are no built in functions in QValueList to + traverse the list. The only way to do this is to use iterators. + QValueList is highly optimized for performance and memory usage. + On the other hand that means that you have to be a bit more careful + by what you are doing. QValueList does not know about all its iterators + and the iterators dont even know to which list they belong. That makes + things fast and slim but a bit dangerous because it is up to you to make + sure that iterators you are using are still valid. QListIterator will be able + to give warnings while QValueListIterator may end up in an undefined state. + + For every Iterator there is a ConstIterator. When accessing a QValueList + in a const environment or if the reference or pointer to the list is itself + const, then you have to use the ConstIterator. Its semantics are the same, + but it returns only const references to the item it points to. + + \sa QValueList, QValueListConstIterator +*/ + +/*! + \fn QValueListIterator::QValueListIterator() + Creates un uninitialized iterator. +*/ + +/*! + \fn QValueListIterator::QValueListIterator( NodePtr p ) + Internal function. +*/ + +/*! + \fn QValueListIterator::QValueListIterator( const QValueListIterator<T>& it ) + Constructs a copy of the iterator \e it. +*/ + +/*! + \fn QValueListIterator::~QValueListIterator() + Destroys the iterator. +*/ + +/* Unfortunately not with MSVC + \fn T *QValueListIterator::operator->() + Pointer operator. Returns a pointer to the current iterator item. + The great advantage of this operator is that you can treat the + iterator like a pointer. + + Example: + \code + QValueList<int>::Iterator it = list.begin(); + for( ; it != end(); ++it ) + it->show(); + \endcode +*/ + +/*! + \fn T& QValueListIterator::operator*() + Asterix operator. Returns a reference to the current iterator item. +*/ + +/*! + \fn const T& QValueListIterator::operator*() const + Asterix operator. Returns a reference to the current iterator item. +*/ + +/*! + \fn QValueListIterator<T>& QValueListIterator::operator++() + Prefix ++ makes the succeeding item current and returns + an iterator pointing to the new current item. + The iterator can not check wether it reached the end of the list. Incrementing + the iterator as returned by end() causes undefined results. +*/ + +/*! + \fn QValueListIterator<T> QValueListIterator::operator++(int) + Postfix ++ makes the succeeding item current and returns + an iterator pointing to the new current item. + The iterator can not check wether it reached the end of the list. Incrementing + the iterator as returned by end() causes undefined results. +*/ + +/*! + \fn QValueListIterator<T>& QValueListIterator::operator--() + Prefix -- makes the previous item current and returns + an iterator pointing to the new current item. + The iterator can not check wether it reached the beginning of the list. Decrementing + the iterator as returned by begin() causes undefined results. +*/ + +/*! + \fn QValueListIterator<T> QValueListIterator::operator--(int) + Postfix -- makes the previous item current and returns + an iterator pointing to the new current item. + The iterator can not check wether it reached the beginning of the list. Decrementing + the iterator as returned by begin() causes undefined results. +*/ + +/*! + \fn bool QValueListIterator::operator==( const QValueListIterator<T>& it ) const + Compares both iterators and returns TRUE if they point to the same item. +*/ + +/*! + \fn bool QValueListIterator::operator!=( const QValueListIterator<T>& it ) const + Compares both iterators and returns TRUE if they point to different items. +*/ + +/***************************************************************************** + QValueListConstIterator documentation + *****************************************************************************/ + +/*! + \class QValueListConstIterator qvaluelist.h + \brief The QValueListConstIterator class provides an iterator for QValueList. + + \ingroup qtl + \ingroup tools + + In contrast to QValueListIterator this class is used to iterate over a const + list. It does not allow to modify the values of the list since this would + break the const semantics. + + For more informations on QValueList iterators see QValueListIterator. + + \sa QValueListIterator, QValueList +*/ + +/*! + \fn QValueListConstIterator::QValueListConstIterator() + Creates un uninitialized iterator. +*/ + +/*! + \fn QValueListConstIterator::QValueListConstIterator( NodePtr p ) + Internal function. +*/ + +/*! + \fn QValueListConstIterator::QValueListConstIterator( const QValueListConstIterator<T>& it ) + Constructs a copy of the iterator \e it. +*/ + +/*! + \fn QValueListConstIterator::QValueListConstIterator( const QValueListIterator<T>& it ) + Constructs a copy of the iterator \e it. +*/ + +/*! + \fn QValueListConstIterator::~QValueListConstIterator() + Destroys the iterator. +*/ + +/* Unfortunately not with MSVC + \fn const T *QValueListConstIterator::operator->() + Pointer operator. Returns a pointer to the current iterator item. + The great advantage of this operator is that you can treat the + iterator like a pointer. + + Example: + \code + QValueList<int>::Iterator it = list.begin(); + for( ; it != end(); ++it ) + it->show(); + \endcode +*/ + +/*! + \fn const T& QValueListConstIterator::operator*() const + Asterix operator. Returns a reference to the current iterator item. +*/ + +/*! + \fn QValueListConstIterator<T>& QValueListConstIterator::operator++() + Prefix ++ makes the succeeding item current and returns + an iterator pointing to the new current item. + The iterator can not check wether it reached the end of the list. Incrementing + the iterator as returned by end() causes undefined results. +*/ + +/*! + \fn QValueListConstIterator<T> QValueListConstIterator::operator++(int) + Postfix ++ makes the succeeding item current and returns + an iterator pointing to the new current item. + The iterator can not check wether it reached the end of the list. Incrementing + the iterator as returned by end() causes undefined results. +*/ + +/*! + \fn QValueListConstIterator<T>& QValueListConstIterator::operator--() + Prefix -- makes the previous item current and returns + an iterator pointing to the new current item. + The iterator can not check wether it reached the beginning of the list. Decrementing + the iterator as returned by begin() causes undefined results. +*/ + +/*! + \fn QValueListConstIterator<T> QValueListConstIterator::operator--(int) + Postfix -- makes the previous item current and returns + an iterator pointing to the new current item. + The iterator can not check wether it reached the beginning of the list. Decrementing + the iterator as returned by begin() causes undefined results. +*/ + +/*! + \fn bool QValueListConstIterator::operator==( const QValueListConstIterator<T>& it ) const + Compares both iterators and returns TRUE if they point to the same item. +*/ + +/*! + \fn bool QValueListConstIterator::operator!=( const QValueListConstIterator<T>& it ) const + Compares both iterators and returns TRUE if they point to different items. +*/ diff --git a/trunk/qtools/qvaluelist.h b/trunk/qtools/qvaluelist.h new file mode 100644 index 0000000..a1014ed --- /dev/null +++ b/trunk/qtools/qvaluelist.h @@ -0,0 +1,449 @@ +/**************************************************************************** +** +** +** Definition of QValueList class +** +** Created : 990406 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QVALUELIST_H +#define QVALUELIST_H + +#ifndef QT_H +#include "qshared.h" +#include "qdatastream.h" +#endif // QT_H + +#if defined(_CC_MSVC_) +#pragma warning(disable:4284) // "return type for operator -> is not a UDT" +#endif + +template <class T> +class Q_EXPORT QValueListNode +{ +public: + QValueListNode( const T& t ) : data( t ) { } + QValueListNode() { } +#if defined(Q_TEMPLATEDLL) + // Workaround MS bug in memory de/allocation in DLL vs. EXE + virtual ~QValueListNode() { } +#endif + + QValueListNode<T>* next; + QValueListNode<T>* prev; + T data; +}; + +template<class T> +class Q_EXPORT QValueListIterator +{ + public: + /** + * Typedefs + */ + typedef QValueListNode<T>* NodePtr; + + /** + * Variables + */ + NodePtr node; + + /** + * Functions + */ + QValueListIterator() : node( 0 ) {} + QValueListIterator( NodePtr p ) : node( p ) {} + QValueListIterator( const QValueListIterator<T>& it ) : node( it.node ) {} + + bool operator==( const QValueListIterator<T>& it ) const { return node == it.node; } + bool operator!=( const QValueListIterator<T>& it ) const { return node != it.node; } + const T& operator*() const { return node->data; } + T& operator*() { return node->data; } + + // Compilers are too dumb to understand this for QValueList<int> + //T* operator->() const { return &(node->data); } + + QValueListIterator<T>& operator++() { + node = node->next; + return *this; + } + + QValueListIterator<T> operator++(int) { + QValueListIterator<T> tmp = *this; + node = node->next; + return tmp; + } + + QValueListIterator<T>& operator--() { + node = node->prev; + return *this; + } + + QValueListIterator<T> operator--(int) { + QValueListIterator<T> tmp = *this; + node = node->prev; + return tmp; + } +}; + +template<class T> +class Q_EXPORT QValueListConstIterator +{ + public: + /** + * Typedefs + */ + typedef QValueListNode<T>* NodePtr; + + /** + * Variables + */ + NodePtr node; + + /** + * Functions + */ + QValueListConstIterator() : node( 0 ) {} + QValueListConstIterator( NodePtr p ) : node( p ) {} + QValueListConstIterator( const QValueListConstIterator<T>& it ) : node( it.node ) {} + QValueListConstIterator( const QValueListIterator<T>& it ) : node( it.node ) {} + + bool operator==( const QValueListConstIterator<T>& it ) const { return node == it.node; } + bool operator!=( const QValueListConstIterator<T>& it ) const { return node != it.node; } + const T& operator*() const { return node->data; } + + // Compilers are too dumb to understand this for QValueList<int> + //const T* operator->() const { return &(node->data); } + + QValueListConstIterator<T>& operator++() { + node = node->next; + return *this; + } + + QValueListConstIterator<T> operator++(int) { + QValueListConstIterator<T> tmp = *this; + node = node->next; + return tmp; + } + + QValueListConstIterator<T>& operator--() { + node = node->prev; + return *this; + } + + QValueListConstIterator<T> operator--(int) { + QValueListConstIterator<T> tmp = *this; + node = node->prev; + return tmp; + } +}; + +template <class T> +class Q_EXPORT QValueListPrivate : public QShared +{ +public: + /** + * Typedefs + */ + typedef QValueListIterator<T> Iterator; + typedef QValueListConstIterator<T> ConstIterator; + typedef QValueListNode<T> Node; + typedef QValueListNode<T>* NodePtr; + + /** + * Functions + */ + QValueListPrivate() { node = new Node; node->next = node->prev = node; nodes = 0; } + QValueListPrivate( const QValueListPrivate<T>& _p ) : QShared() { + node = new Node; node->next = node->prev = node; nodes = 0; + Iterator b( _p.node->next ); + Iterator e( _p.node ); + Iterator i( node ); + while( b != e ) + insert( i, *b++ ); + } + + void derefAndDelete() // ### hack to get around hp-cc brain damage + { + if ( deref() ) + delete this; + } + +#if defined(Q_TEMPLATEDLL) + // Workaround MS bug in memory de/allocation in DLL vs. EXE + virtual +#endif + ~QValueListPrivate() { + NodePtr p = node->next; + while( p != node ) { + NodePtr x = p->next; + delete p; + p = x; + } + delete node; + } + + Iterator insert( Iterator it, const T& x ) { + NodePtr p = new Node( x ); + p->next = it.node; + p->prev = it.node->prev; + it.node->prev->next = p; + it.node->prev = p; + nodes++; + return p; + } + + Iterator remove( Iterator it ) { + ASSERT ( it.node != node ); + NodePtr next = it.node->next; + NodePtr prev = it.node->prev; + prev->next = next; + next->prev = prev; + delete it.node; + nodes--; + return Iterator( next ); + } + + NodePtr find( NodePtr start, const T& x ) const { + ConstIterator first( start ); + ConstIterator last( node ); + while( first != last) { + if ( *first == x ) + return first.node; + ++first; + } + return last.node; + } + + int findIndex( NodePtr start, const T& x ) const { + ConstIterator first( start ); + ConstIterator last( node ); + int pos = 0; + while( first != last) { + if ( *first == x ) + return pos; + ++first; + ++pos; + } + return -1; + } + + uint contains( const T& x ) const { + uint result = 0; + Iterator first = Iterator( node->next ); + Iterator last = Iterator( node ); + while( first != last) { + if ( *first == x ) + ++result; + ++first; + } + return result; + } + + void remove( const T& x ) { + Iterator first = Iterator( node->next ); + Iterator last = Iterator( node ); + while( first != last) { + if ( *first == x ) + first = remove( first ); + else + ++first; + } + } + + NodePtr at( uint i ) const { + ASSERT( i <= nodes ); + NodePtr p = node->next; + for( uint x = 0; x < i; ++x ) + p = p->next; + return p; + } + + void clear() { + nodes = 0; + NodePtr p = node->next; + while( p != node ) { + NodePtr next = p->next; + delete p; + p = next; + } + node->next = node->prev = node; + } + + NodePtr node; + uint nodes; +}; + +template <class T> +class Q_EXPORT QValueList +{ +public: + /** + * Typedefs + */ + typedef QValueListIterator<T> Iterator; + typedef QValueListConstIterator<T> ConstIterator; + typedef T ValueType; + + /** + * API + */ + QValueList() { sh = new QValueListPrivate<T>; } + QValueList( const QValueList<T>& l ) { sh = l.sh; sh->ref(); } + ~QValueList() { sh->derefAndDelete(); } + + QValueList<T>& operator= ( const QValueList<T>& l ) + { + l.sh->ref(); + sh->derefAndDelete(); + sh = l.sh; + return *this; + } + + QValueList<T> operator+ ( const QValueList<T>& l ) const + { + QValueList<T> l2( *this ); + for( ConstIterator it = l.begin(); it != l.end(); ++it ) + l2.append( *it ); + return l2; + } + + QValueList<T>& operator+= ( const QValueList<T>& l ) + { + for( ConstIterator it = l.begin(); it != l.end(); ++it ) + append( *it ); + return *this; + } + + bool operator== ( const QValueList<T>& l ) const + { + if ( count() != l.count() ) + return FALSE; + ConstIterator it2 = begin(); + ConstIterator it = l.begin(); + for( ; it != l.end(); ++it, ++it2 ) + if ( !( *it == *it2 ) ) + return FALSE; + return TRUE; + } + + bool operator!= ( const QValueList<T>& l ) const { return !( *this == l ); } + + Iterator begin() { detach(); return Iterator( sh->node->next ); } + ConstIterator begin() const { return ConstIterator( sh->node->next ); } + Iterator end() { detach(); return Iterator( sh->node ); } + ConstIterator end() const { return ConstIterator( sh->node ); } + Iterator fromLast() { detach(); return Iterator( sh->node->prev ); } + ConstIterator fromLast() const { return ConstIterator( sh->node->prev ); } + + bool isEmpty() const { return ( sh->nodes == 0 ); } + + Iterator insert( Iterator it, const T& x ) { detach(); return sh->insert( it, x ); } + + Iterator append( const T& x ) { detach(); return sh->insert( end(), x ); } + Iterator prepend( const T& x ) { detach(); return sh->insert( begin(), x ); } + + Iterator remove( Iterator it ) { detach(); return sh->remove( it ); } + void remove( const T& x ) { detach(); sh->remove( x ); } + + T& first() { detach(); return sh->node->next->data; } + const T& first() const { return sh->node->next->data; } + T& last() { detach(); return sh->node->prev->data; } + const T& last() const { return sh->node->prev->data; } + + T& operator[] ( uint i ) { detach(); return sh->at(i)->data; } + const T& operator[] ( uint i ) const { return sh->at(i)->data; } + Iterator at( uint i ) { detach(); return Iterator( sh->at(i) ); } + ConstIterator at( uint i ) const { return ConstIterator( sh->at(i) ); } + Iterator find ( const T& x ) { detach(); return Iterator( sh->find( sh->node->next, x) ); } + ConstIterator find ( const T& x ) const { return ConstIterator( sh->find( sh->node->next, x) ); } + Iterator find ( Iterator it, const T& x ) { detach(); return Iterator( sh->find( it.node, x ) ); } + ConstIterator find ( ConstIterator it, const T& x ) const { return ConstIterator( sh->find( it.node, x ) ); } + int findIndex( const T& x ) const { return sh->findIndex( sh->node->next, x) ; } + uint contains( const T& x ) const { return sh->contains( x ); } + + uint count() const { return sh->nodes; } + + void clear() { if ( sh->count == 1 ) sh->clear(); else { sh->deref(); sh = new QValueListPrivate<T>; } } + + + QValueList<T>& operator+= ( const T& x ) + { + append( x ); + return *this; + } + QValueList<T>& operator<< ( const T& x ) + { + append( x ); + return *this; + } + + +protected: + /** + * Helpers + */ + void detach() { if ( sh->count > 1 ) { sh->deref(); sh = new QValueListPrivate<T>( *sh ); } } + + /** + * Variables + */ + QValueListPrivate<T>* sh; +}; + +#ifndef QT_NO_DATASTREAM +template<class T> +inline QDataStream& operator>>( QDataStream& s, QValueList<T>& l ) +{ + l.clear(); + Q_UINT32 c; + s >> c; + for( Q_UINT32 i = 0; i < c; ++i ) + { + T t; + s >> t; + l.append( t ); + } + return s; +} + +template<class T> +inline QDataStream& operator<<( QDataStream& s, const QValueList<T>& l ) +{ + s << (Q_UINT32)l.count(); + QValueListConstIterator<T> it = l.begin(); + for( ; it != l.end(); ++it ) + s << *it; + return s; +} +#endif // QT_NO_DATASTREAM +#endif // QVALUELIST_H diff --git a/trunk/qtools/qvaluestack.h b/trunk/qtools/qvaluestack.h new file mode 100644 index 0000000..fe4462a --- /dev/null +++ b/trunk/qtools/qvaluestack.h @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** +** Definition of QValueStack class +** +** Created : 990925 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QVALUESTACK_H +#define QVALUESTACK_H + +#ifndef QT_H +#include "qvaluelist.h" +#endif // QT_H + + +template<class T> +class Q_EXPORT QValueStack : public QValueList<T> +{ +public: + QValueStack() {} + ~QValueStack() {} + void push( const T& d ) { QValueList<T>::append(d); } + T pop() + { + T elem( this->last() ); + if ( !this->isEmpty() ) + this->remove( this->fromLast() ); + return elem; + } + T& top() { return this->last(); } + const T& top() const { return this->last(); } +}; + +#endif diff --git a/trunk/qtools/qvector.doc b/trunk/qtools/qvector.doc new file mode 100644 index 0000000..2acf567 --- /dev/null +++ b/trunk/qtools/qvector.doc @@ -0,0 +1,344 @@ +/**************************************************************************** +** +** +** QVector class documentation +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + + +/***************************************************************************** + QVector documentation + *****************************************************************************/ + +// BEING REVISED: ettrich +/*! + \class QVector qvector.h + + \brief The QVector class is a template collection class that + provides a vector (array). + + \ingroup tools + + QVector is implemented as a template class. Define a template + instance QVector\<X\> to create a vector that contains pointers to + X, or X*. + + A vector is the same as an array. The main difference between + QVector and QArray is that QVector stores pointers to the elements, + while QArray stores the elements themselves (i.e. QArray is + value-based). + + Unless where otherwise stated, all functions that remove items from + the vector will also delete the element pointed to if auto-deletion + is enabled - see setAutoDelete(). By default, auto-deletion is + disabled. This behaviour can be changed in a subclass by + reimplementing the virtual method deleteItem(). + + Functions that compares items, e.g. find() and sort(), will do so + using the virtual function compareItems(). The default + implementation of this function will only compare the absolute + pointer values. Reimplement compareItems() in a subclass to get + searching and sorting based on the item contents. + + \sa \link collection.html Collection Classes\endlink, QArray +*/ + +/*! + \fn QVector::QVector() + + Constructs a null vector. + + \sa isNull() +*/ + +/*! + \fn QVector::QVector( uint size ) + + Constructs an vector with room for \a size items. Makes a null + vector if \a size == 0. + + All \a size positions in the vector are initialized to 0. + + \sa size(), resize(), isNull() +*/ + +/*! + \fn QVector::QVector( const QVector<type> &v ) + + Constructs a copy of \a v. Only the pointers are copied (i.e. shallow copy). +*/ + +/*! + \fn QVector::~QVector() + + Removes all items from the vector, and destroys the vector itself. + + \sa clear() +*/ + +/*! + \fn QVector<type> &QVector::operator=( const QVector<type> &v ) + + Assigns \a v to this vector and returns a reference to this vector. + + This vector is first cleared, then all the items from \a v is copied + into this vector. Only the pointers are copied (i.e. shallow copy). + + \sa clear() +*/ + +/*! + \fn type **QVector::data() const + Returns a pointer to the actual vector data, which is an array of type*. + + The vector is a null vector if data() == 0 (null pointer). + + \sa isNull() +*/ + +/*! + \fn uint QVector::size() const + + Returns the size of the vector, i.e. the number of vector + positions. This is also the maximum number of items the vector can + hold. + + The vector is a null vector if size() == 0. + + \sa isNull(), resize(), count() +*/ + +/*! + \fn uint QVector::count() const + + Returns the number of items in the vector. The vector is empty if + count() == 0. + + \sa isEmpty(), size() +*/ + +/*! + \fn bool QVector::isEmpty() const + + Returns TRUE if the vector is empty, i.e. count() == 0, otherwise FALSE. + + \sa count() +*/ + +/*! + \fn bool QVector::isNull() const + + Returns TRUE if the vector is null, otherwise FALSE. + + A null vector has size() == 0 and data() == 0. + + \sa size() +*/ + +/*! + \fn bool QVector::resize( uint size ) + Resizes (expands or shrinks) the vector to \a size elements. The array + becomes a null array if \a size == 0. + + Any items in position \a size or beyond in the vector are removed. + New positions are initialized 0. + + Returns TRUE if successful, or FALSE if the memory cannot be allocated. + + \sa size(), isNull() +*/ + +/*! + \fn bool QVector::insert( uint i, const type *d ) + + Sets position \a i in the vector to contain the item \a d. \a i must + be less than size(). Any previous element in position \a i is removed. + + \sa at() +*/ + +/*! + \fn bool QVector::remove( uint i ) + + Removes the item at position \a i in the vector, if there is one. + \a i must be less than size(). + + Returns TRUE unless \a i is out of range. + + \sa take(), at() +*/ + +/*! + \fn type* QVector::take( uint i ) + + Returns the item at position \a i in the vector, and removes that + item from the vector. \a i must be less than size(). If there is no + item at position \a i, 0 is returned. + + In contrast to remove(), this function does \e not call deleteItem() + for the removed item. + + \sa remove(), at() +*/ + +/*! + \fn void QVector::clear() + + Removes all items from the vector, and destroys the vector + itself. + + The vector becomes a null vector. + + \sa isNull() +*/ + +/*! + \fn bool QVector::fill( const type *d, int size ) + + Inserts item \a d in all positions in the vector. Any existing items + are removed. If \a d is 0, the vector becomes empty. + + If \a size >= 0, the vector is first resized to \a size. By default, + \a size is -1. + + Returns TRUE if successful, or FALSE if the memory cannot be allocated + (only if a resize has been requested). + + \sa resize(), insert(), isEmpty() +*/ + +/*! + \fn void QVector::sort() + + Sorts the items in ascending order. Any empty positions will be put + last. + + Compares items using the virtual function compareItems(). + + \sa bsearch() +*/ + +/*! + \fn int QVector::bsearch( const type* d ) const + + In a sorted array, finds the first occurrence of \a d using binary + search. For a sorted array, this is generally much faster than + find(), which does a linear search. + + Returns the position of \a d, or -1 if \a d could not be found. \a d + may not be 0. + + Compares items using the virtual function compareItems(). + + \sa sort(), find() +*/ + + +/*! + \fn int QVector::findRef( const type *d, uint i ) const + + Finds the first occurrence of the item pointer \a d in the vector, + using linear search. The search starts at position \a i, which must + be less than size(). \a i is by default 0; i.e. the search starts at + the start of the vector. + + Returns the position of \a d, or -1 if \a d could not be found. + + This function does \e not use compareItems() to compare items. + + \sa find(), bsearch() +*/ + +/*! + \fn int QVector::find( const type *d, uint i ) const + + Finds the first occurrence of item \a d in the vector, using linear + search. The search starts at position \a i, which must be less than + size(). \a i is by default 0; i.e. the search starts at the start of + the vector. + + Returns the position of \e v, or -1 if \e v could not be found. + + Compares items using the virtual function compareItems(). + + \sa findRef(), bsearch() +*/ + + +/*! + \fn uint QVector::containsRef( const type *d ) const + + Returns the number of occurrences of the item pointer \a d in the + vector. + + This function does \e not use compareItems() to compare items. + + \sa findRef() +*/ + +/*! + \fn uint QVector::contains( const type *d ) const + + Returns the number of occurrences of item \a d in the vector. + + Compares items using the virtual function compareItems(). + + \sa containsRef() +*/ + +/*! + \fn type *QVector::operator[]( int i ) const + + Returns the item at position \a i, or 0 if there is no item at + that position. \a i must be less than size(). + + Equivalent to at( \a i ). + + \sa at() +*/ + +/*! + \fn type *QVector::at( uint i ) const + + Returns the item at position \a i, or 0 if there is no item at + that position. \a i must be less than size(). +*/ + + +/*! + \fn void QVector::toList( QGList *list ) const + + Copies all items in this vector to the list \a list. First, \a list + is cleared, then all items are appended to \a list. + + \sa QList, QStack, QQueue +*/ + diff --git a/trunk/qtools/qvector.h b/trunk/qtools/qvector.h new file mode 100644 index 0000000..36f0be7 --- /dev/null +++ b/trunk/qtools/qvector.h @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** +** Definition of QVector template/macro class +** +** Created : 930907 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QVECTOR_H +#define QVECTOR_H + +#ifndef QT_H +#include "qgvector.h" +#endif // QT_H + + +template<class type> class QVector : public QGVector +{ +public: + QVector() {} + QVector( uint size ) : QGVector(size) {} + QVector( const QVector<type> &v ) : QGVector(v) {} + ~QVector() { clear(); } + QVector<type> &operator=(const QVector<type> &v) + { return (QVector<type>&)QGVector::operator=(v); } + type **data() const { return (type **)QGVector::data(); } + uint size() const { return QGVector::size(); } + uint count() const { return QGVector::count(); } + bool isEmpty() const { return QGVector::count() == 0; } + bool isNull() const { return QGVector::size() == 0; } + bool resize( uint size ) { return QGVector::resize(size); } + bool insert( uint i, const type *d){ return QGVector::insert(i,(Item)d); } + bool remove( uint i ) { return QGVector::remove(i); } + type *take( uint i ) { return (type *)QGVector::take(i); } + void clear() { QGVector::clear(); } + bool fill( const type *d, int size=-1 ) + { return QGVector::fill((Item)d,size);} + void sort() { QGVector::sort(); } + int bsearch( const type *d ) const{ return QGVector::bsearch((Item)d); } + int findRef( const type *d, uint i=0 ) const + { return QGVector::findRef((Item)d,i);} + int find( const type *d, uint i= 0 ) const + { return QGVector::find((Item)d,i); } + uint containsRef( const type *d ) const + { return QGVector::containsRef((Item)d); } + uint contains( const type *d ) const + { return QGVector::contains((Item)d); } + type *operator[]( int i ) const { return (type *)QGVector::at(i); } + type *at( uint i ) const { return (type *)QGVector::at(i); } + void toList( QGList *list ) const { QGVector::toList(list); } +private: + void deleteItem( Item d ) { if ( del_item ) delete (type *)d; } +}; + + +#endif // QVECTOR_H diff --git a/trunk/qtools/qwaitcondition.h b/trunk/qtools/qwaitcondition.h new file mode 100644 index 0000000..4d5b3bd --- /dev/null +++ b/trunk/qtools/qwaitcondition.h @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWAITCONDITION_H +#define QWAITCONDITION_H + +#include "qglobal.h" + +class QWaitConditionPrivate; +class QMutex; + +class QWaitCondition +{ +public: + QWaitCondition(); + ~QWaitCondition(); + + void wait(QMutex *mutex); + + void wakeOne(); + void wakeAll(); + +private: + QWaitCondition(const QWaitCondition &); + QWaitCondition &operator=(const QWaitCondition &); + + QWaitConditionPrivate * d; +}; + +#endif // QWAITCONDITION_H diff --git a/trunk/qtools/qwaitcondition_unix.cpp b/trunk/qtools/qwaitcondition_unix.cpp new file mode 100644 index 0000000..aa22a4b --- /dev/null +++ b/trunk/qtools/qwaitcondition_unix.cpp @@ -0,0 +1,133 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwaitcondition.h" +#include "qmutex.h" +#include <pthread.h> + +#define MIN(a,b) ((a)<(b)?(a):(b)) + +static void report_error(int code, const char *where, const char *what) +{ + if (code != 0) + qWarning("%s: %s failure: %d", where, what, code); +} + +struct QWaitConditionPrivate +{ + pthread_mutex_t mutex; + pthread_cond_t cond; + int waiters; + int wakeups; + + void wait() + { + int code; + for (;;) + { + code = pthread_cond_wait(&cond, &mutex); + if (code == 0 && wakeups == 0) + { + // many vendors warn of spurios wakeups from + // pthread_cond_wait(), especially after signal delivery, + // even though POSIX doesn't allow for it... sigh + continue; + } + break; + } + + --waiters; + if (code == 0) + { + --wakeups; + } + else + { + report_error(code, "QWaitCondition::wait()", "cv wait"); + } + report_error(pthread_mutex_unlock(&mutex), "QWaitCondition::wait()", "mutex unlock"); + } +}; + + +QWaitCondition::QWaitCondition() +{ + d = new QWaitConditionPrivate; + report_error(pthread_mutex_init(&d->mutex, NULL), "QWaitCondition", "mutex init"); + report_error(pthread_cond_init(&d->cond, NULL), "QWaitCondition", "cv init"); + d->waiters = d->wakeups = 0; +} + + +QWaitCondition::~QWaitCondition() +{ + report_error(pthread_cond_destroy(&d->cond), "QWaitCondition", "cv destroy"); + report_error(pthread_mutex_destroy(&d->mutex), "QWaitCondition", "mutex destroy"); + delete d; +} + +void QWaitCondition::wakeOne() +{ + report_error(pthread_mutex_lock(&d->mutex), "QWaitCondition::wakeOne()", "mutex lock"); + d->wakeups = MIN(d->wakeups + 1, d->waiters); + report_error(pthread_cond_signal(&d->cond), "QWaitCondition::wakeOne()", "cv signal"); + report_error(pthread_mutex_unlock(&d->mutex), "QWaitCondition::wakeOne()", "mutex unlock"); +} + +void QWaitCondition::wakeAll() +{ + report_error(pthread_mutex_lock(&d->mutex), "QWaitCondition::wakeAll()", "mutex lock"); + d->wakeups = d->waiters; + report_error(pthread_cond_broadcast(&d->cond), "QWaitCondition::wakeAll()", "cv broadcast"); + report_error(pthread_mutex_unlock(&d->mutex), "QWaitCondition::wakeAll()", "mutex unlock"); +} + +void QWaitCondition::wait(QMutex *mutex) +{ + if (!mutex) return; + + report_error(pthread_mutex_lock(&d->mutex), "QWaitCondition::wait()", "mutex lock"); + ++d->waiters; + mutex->unlock(); + d->wait(); + mutex->lock(); +} + diff --git a/trunk/qtools/qwaitcondition_win32.cpp b/trunk/qtools/qwaitcondition_win32.cpp new file mode 100644 index 0000000..77eb039 --- /dev/null +++ b/trunk/qtools/qwaitcondition_win32.cpp @@ -0,0 +1,186 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <windows.h> +#include "qwaitcondition.h" +#include "qmutex.h" +#include "qlist.h" + +//*********************************************************************** +// QWaitConditionPrivate +// ********************************************************************** + +class QWaitConditionEvent +{ +public: + QWaitConditionEvent() : priority(0), wokenUp(false) + { + event = CreateEvent(NULL, TRUE, FALSE, NULL); + } + ~QWaitConditionEvent() { CloseHandle(event); } + int priority; + bool wokenUp; + HANDLE event; +}; + +class EventQueue : public QList<QWaitConditionEvent> +{ + public: + EventQueue() { setAutoDelete(TRUE); } + ~EventQueue() {} +}; + +class QWaitConditionPrivate +{ +public: + QMutex mtx; + EventQueue queue; + EventQueue freeQueue; + + QWaitConditionEvent *pre(); + void wait(QWaitConditionEvent *wce); + void post(QWaitConditionEvent *wce); +}; + +QWaitConditionEvent *QWaitConditionPrivate::pre() +{ + mtx.lock(); + QWaitConditionEvent *wce = + freeQueue.isEmpty() ? new QWaitConditionEvent : freeQueue.take(0); + wce->priority = GetThreadPriority(GetCurrentThread()); + wce->wokenUp = FALSE; + + // insert 'wce' into the queue (sorted by priority) + uint index = 0; + for (; index < queue.count(); ++index) + { + QWaitConditionEvent *current = queue.at(index); + if (current->priority < wce->priority) + break; + } + queue.insert(index, wce); + mtx.unlock(); + + return wce; +} + +void QWaitConditionPrivate::wait(QWaitConditionEvent *wce) +{ + WaitForSingleObject(wce->event, INFINITE); +} + +void QWaitConditionPrivate::post(QWaitConditionEvent *wce) +{ + mtx.lock(); + + // remove 'wce' from the queue + int idx = queue.find(wce); + ASSERT(idx!=-1); + queue.take(idx); + ResetEvent(wce->event); + freeQueue.append(wce); + + // wakeups delivered after the timeout should be forwarded to the next waiter + if (wce->wokenUp && !queue.isEmpty()) + { + QWaitConditionEvent *other = queue.getFirst(); + SetEvent(other->event); + other->wokenUp = TRUE; + } + + mtx.unlock(); +} + +//*********************************************************************** +// QWaitCondition implementation +//*********************************************************************** + +QWaitCondition::QWaitCondition() +{ + d = new QWaitConditionPrivate; +} + +QWaitCondition::~QWaitCondition() +{ + if (!d->queue.isEmpty()) + { + qWarning("QWaitCondition: Destroyed while threads are still waiting"); + } + delete d; +} + +void QWaitCondition::wait(QMutex *mutex) +{ + if (!mutex) return; + + QWaitConditionEvent *wce = d->pre(); + mutex->unlock(); + d->wait(wce); + mutex->lock(); + d->post(wce); +} + +void QWaitCondition::wakeOne() +{ + // wake up the first waiting thread in the queue + QMutexLocker locker(&d->mtx); + for (uint i = 0; i < d->queue.count(); ++i) + { + QWaitConditionEvent *current = d->queue.at(i); + if (current->wokenUp) continue; + SetEvent(current->event); + current->wokenUp = TRUE; + break; + } +} + +void QWaitCondition::wakeAll() +{ + // wake up the all threads in the queue + QMutexLocker locker(&d->mtx); + for (uint i = 0; i < d->queue.count(); ++i) + { + QWaitConditionEvent *current = d->queue.at(i); + SetEvent(current->event); + current->wokenUp = TRUE; + } +} + diff --git a/trunk/qtools/qxml.cpp b/trunk/qtools/qxml.cpp new file mode 100644 index 0000000..ec21c1f --- /dev/null +++ b/trunk/qtools/qxml.cpp @@ -0,0 +1,6061 @@ +/**************************************************************************** +** +** +** Implementation of QXmlSimpleReader and related classes. +** +** Created : 000518 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the XML module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition licenses may use this +** file in accordance with the Qt Commercial License Agreement provided +** with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#define QT_XML_CPP +#include "qxml.h" +#include "qtextcodec.h" +#include "qbuffer.h" + +#ifndef QT_NO_XML +// NOT REVISED + +// Error strings for the XML reader +#define XMLERR_OK "no error occured" +#define XMLERR_TAGMISMATCH "tag mismatch" +#define XMLERR_UNEXPECTEDEOF "unexpected end of file" +#define XMLERR_FINISHEDPARSINGWHILENOTEOF "parsing is finished but end of file is not reached" +#define XMLERR_LETTEREXPECTED "letter is expected" +#define XMLERR_ERRORPARSINGELEMENT "error while parsing element" +#define XMLERR_ERRORPARSINGPROLOG "error while parsing prolog" +#define XMLERR_ERRORPARSINGMAINELEMENT "error while parsing main element" +#define XMLERR_ERRORPARSINGCONTENT "error while parsing content" +#define XMLERR_ERRORPARSINGNAME "error while parsing name" +#define XMLERR_ERRORPARSINGNMTOKEN "error while parsing Nmtoken" +#define XMLERR_ERRORPARSINGATTRIBUTE "error while parsing attribute" +#define XMLERR_ERRORPARSINGMISC "error while parsing misc" +#define XMLERR_ERRORPARSINGCHOICE "error while parsing choice or seq" +#define XMLERR_ERRORBYCONSUMER "error triggered by consumer" +#define XMLERR_UNEXPECTEDCHARACTER "unexpected character" +#define XMLERR_EQUALSIGNEXPECTED "expected '=' but not found" +#define XMLERR_QUOTATIONEXPECTED "expected \" or ' but not found" +#define XMLERR_ERRORPARSINGREFERENCE "error while parsing reference" +#define XMLERR_ERRORPARSINGPI "error while parsing processing instruction" +#define XMLERR_ERRORPARSINGATTLISTDECL "error while parsing attribute list declaration" +#define XMLERR_ERRORPARSINGATTTYPE "error while parsing attribute type declaration" +#define XMLERR_ERRORPARSINGATTVALUE "error while parsing attribute value declaration" +#define XMLERR_ERRORPARSINGELEMENTDECL "error while parsing element declaration" +#define XMLERR_ERRORPARSINGENTITYDECL "error while parsing entity declaration" +#define XMLERR_ERRORPARSINGNOTATIONDECL "error while parsing notation declaration" +#define XMLERR_ERRORPARSINGEXTERNALID "error while parsing external id" +#define XMLERR_ERRORPARSINGCOMMENT "error while parsing comment" +#define XMLERR_ERRORPARSINGENTITYVALUE "error while parsing entity value declaration" +#define XMLERR_CDSECTHEADEREXPECTED "expected the header for a cdata section" +#define XMLERR_MORETHANONEDOCTYPE "more than one document type definition" +#define XMLERR_ERRORPARSINGDOCTYPE "error while parsing document type definition" +#define XMLERR_INVALIDNAMEFORPI "invalid name for processing instruction" +#define XMLERR_VERSIONEXPECTED "version expected while reading the XML declaration" +#define XMLERR_EDECLORSDDECLEXPECTED "EDecl or SDDecl expected while reading the XML declaration" +#define XMLERR_SDDECLEXPECTED "SDDecl expected while reading the XML declaration" +#define XMLERR_WRONGVALUEFORSDECL "wrong value for standalone declaration" +#define XMLERR_UNPARSEDENTITYREFERENCE "unparsed entity reference in wrong context" +#define XMLERR_INTERNALGENERALENTITYINDTD "internal general entity reference not allowed in DTD" +#define XMLERR_EXTERNALGENERALENTITYINDTD "external parsed general entity reference not allowed in DTD" +#define XMLERR_EXTERNALGENERALENTITYINAV "external parsed general entity reference not allowed in attribute value" + + +// the constants for the lookup table +static const signed char cltWS = 0; // white space +static const signed char cltPer = 1; // % +static const signed char cltAmp = 2; // & +static const signed char cltGt = 3; // > +static const signed char cltLt = 4; // < +static const signed char cltSlash = 5; // / +static const signed char cltQm = 6; // ? +static const signed char cltEm = 7; // ! +static const signed char cltDash = 8; // - +static const signed char cltCB = 9; // ] +static const signed char cltOB = 10; // [ +static const signed char cltEq = 11; // = +static const signed char cltDq = 12; // " +static const signed char cltSq = 13; // ' +static const signed char cltUnknown = 14; + +// character lookup table +static const signed char charLookupTable[256]={ + cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x00 - 0x07 + cltUnknown, // 0x08 + cltWS, // 0x09 \t + cltWS, // 0x0A \n + cltUnknown, // 0x0B + cltUnknown, // 0x0C + cltWS, // 0x0D \r + cltUnknown, // 0x0E + cltUnknown, // 0x0F + cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x17 - 0x16 + cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x18 - 0x1F + cltWS, // 0x20 Space + cltEm, // 0x21 ! + cltDq, // 0x22 " + cltUnknown, // 0x23 + cltUnknown, // 0x24 + cltPer, // 0x25 % + cltAmp, // 0x26 & + cltSq, // 0x27 ' + cltUnknown, // 0x28 + cltUnknown, // 0x29 + cltUnknown, // 0x2A + cltUnknown, // 0x2B + cltUnknown, // 0x2C + cltDash, // 0x2D - + cltUnknown, // 0x2E + cltSlash, // 0x2F / + cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x30 - 0x37 + cltUnknown, // 0x38 + cltUnknown, // 0x39 + cltUnknown, // 0x3A + cltUnknown, // 0x3B + cltLt, // 0x3C < + cltEq, // 0x3D = + cltGt, // 0x3E > + cltQm, // 0x3F ? + cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x40 - 0x47 + cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x48 - 0x4F + cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x50 - 0x57 + cltUnknown, // 0x58 + cltUnknown, // 0x59 + cltUnknown, // 0x5A + cltOB, // 0x5B [ + cltUnknown, // 0x5C + cltCB, // 0x5D ] + cltUnknown, // 0x5E + cltUnknown, // 0x5F + cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x60 - 0x67 + cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x68 - 0x6F + cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x70 - 0x77 + cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x78 - 0x7F + cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x80 - 0x87 + cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x88 - 0x8F + cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x90 - 0x97 + cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x98 - 0x9F + cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0xA0 - 0xA7 + cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0xA8 - 0xAF + cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0xB0 - 0xB7 + cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0xB8 - 0xBF + cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0xC0 - 0xC7 + cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0xC8 - 0xCF + cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0xD0 - 0xD7 + cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0xD8 - 0xDF + cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0xE0 - 0xE7 + cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0xE8 - 0xEF + cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0xF0 - 0xF7 + cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown // 0xF8 - 0xFF +}; + + +class QXmlNamespaceSupportPrivate +{ +}; +class QXmlAttributesPrivate +{ +}; +class QXmlInputSourcePrivate +{ +}; +class QXmlParseExceptionPrivate +{ +}; +class QXmlLocatorPrivate +{ +}; +class QXmlDefaultHandlerPrivate +{ +}; + +#if defined(Q_FULL_TEMPLATE_INSTANTIATION) +bool operator==( const QMap<QString, QString>, const QMap<QString, QString> ) +{ + return FALSE; +} +#endif + +/*! + \class QXmlParseException qxml.h + \brief The QXmlParseException class is used to report errors with the + QXmlErrorHandler interface. + + \module XML + + \sa QXmlErrorHandler +*/ +/*! + \fn QXmlParseException::QXmlParseException( const QString& name, int c, int l, const QString& p, const QString& s ) + + Constructs a parse exception with the error string \a name in the column + \a c and line \a l for the public identifier \a p and the system identifier + \a s. +*/ +/*! + Returns the error message. +*/ +QString QXmlParseException::message() const +{ + return msg; +} +/*! + Returns the column number the error occured. +*/ +int QXmlParseException::columnNumber() const +{ + return column; +} +/*! + Returns the line number the error occured. +*/ +int QXmlParseException::lineNumber() const +{ + return line; +} +/*! + Returns the public identifier the error occured. +*/ +QString QXmlParseException::publicId() const +{ + return pub; +} +/*! + Returns the system identifier the error occured. +*/ +QString QXmlParseException::systemId() const +{ + return sys; +} + + +/*! + \class QXmlLocator qxml.h + \brief The QXmlLocator class provides the XML handler classes with + information about the actual parsing position. + + \module XML + + The reader reports a QXmlLocator to the content handler before he starts to + parse the document. This is done with the + QXmlContentHandler::setDocumentLocator() function. The handler classes can + now use this locator to get the actual position the reader is at. +*/ +/*! + \fn QXmlLocator::QXmlLocator( QXmlSimpleReader* parent ) + + Constructor. +*/ +/*! + \fn QXmlLocator::~QXmlLocator() + + Destructor. +*/ +/*! + Gets the column number (starting with 1) or -1 if there is no column number + available. +*/ +int QXmlLocator::columnNumber() +{ + return ( reader->columnNr == -1 ? -1 : reader->columnNr + 1 ); +} +/*! + Gets the line number (starting with 1) or -1 if there is no line number + available. +*/ +int QXmlLocator::lineNumber() +{ + return ( reader->lineNr == -1 ? -1 : reader->lineNr + 1 ); +} + + +/********************************************* + * + * QXmlNamespaceSupport + * + *********************************************/ + +/*! + \class QXmlNamespaceSupport qxml.h + \brief The QXmlNamespaceSupport class is a helper class for XML readers which + want to include namespace support. + + \module XML + + It provides some functions that makes it easy to handle namespaces. Its main + use is for subclasses of QXmlReader which want to provide namespace + support. + + See also the <a href="xml-sax.html#namespaces">namespace description</a>. +*/ + +/*! + Constructs a QXmlNamespaceSupport. +*/ +QXmlNamespaceSupport::QXmlNamespaceSupport() +{ + reset(); +} + +/*! + Destructs a QXmlNamespaceSupport. +*/ +QXmlNamespaceSupport::~QXmlNamespaceSupport() +{ +} + +/*! + This function declares a prefix in the current namespace context; the prefix + will remain in force until this context is popped, unless it is shadowed in a + descendant context. + + Note that there is an asymmetry in this library: while prefix() will not + return the default "" prefix, even if you have declared one; to check for a + default prefix, you have to look it up explicitly using uri(). This + asymmetry exists to make it easier to look up prefixes for attribute names, + where the default prefix is not allowed. +*/ +void QXmlNamespaceSupport::setPrefix( const QString& pre, const QString& uri ) +{ + if( pre.isNull() ) { + ns.insert( "", uri ); + } else { + ns.insert( pre, uri ); + } +} + +/*! + Returns one of the prefixes mapped to a namespace URI. + + If more than one prefix is currently mapped to the same URI, this function + will make an arbitrary selection; if you want all of the prefixes, use the + prefixes() function instead. + + Note: this will never return the empty (default) prefix; to check for a + default prefix, use the uri() function with an argument of "". +*/ +QString QXmlNamespaceSupport::prefix( const QString& uri ) const +{ + QMap<QString, QString>::ConstIterator itc, it = ns.begin(); + while ( (itc=it) != ns.end() ) { + ++it; + if ( itc.data() == uri && !itc.key().isEmpty() ) + return itc.key(); + } + return ""; +} + +/*! + Looks up a prefix in the current context and returns the currently-mapped + namespace URI. Use the empty string ("") for the default namespace. +*/ +QString QXmlNamespaceSupport::uri( const QString& prefix ) const +{ + const QString& returi = ns[ prefix ]; + return returi; +} + +/*! + Splits the name at the ':' and returns the prefix and the local name. +*/ +void QXmlNamespaceSupport::splitName( const QString& qname, + QString& prefix, QString& localname ) const +{ + uint pos; + // search the ':' + for( pos=0; pos<qname.length(); pos++ ) { + if ( qname.at(pos) == ':' ) + break; + } + // and split + prefix = qname.left( pos ); + localname = qname.mid( pos+1 ); +} + +/*! + Processes a raw XML 1.0 name in the current context by removing the prefix + and looking it up among the prefixes currently declared. + + First parameter is the raw XML 1.0 name to be processed. The second parameter + is a flag wheter the name is the name of an attribute (TRUE) or not (FALSE). + + The return values will be stored in the last two parameters as follows: + <ul> + <li> The namespace URI, or an empty string if none is in use. + <li> The local name (without prefix). + </ul> + + If the raw name has a prefix that has not been declared, then the return + value will be empty. + + Note that attribute names are processed differently than element names: an + unprefixed element name will received the default namespace (if any), while + an unprefixed element name will not +*/ +void QXmlNamespaceSupport::processName( const QString& qname, + bool isAttribute, + QString& nsuri, QString& localname ) const +{ + uint pos; + // search the ':' + for( pos=0; pos<qname.length(); pos++ ) { + if ( qname.at(pos) == ':' ) + break; + } + if ( pos < qname.length() ) { + // there was a ':' + nsuri = uri( qname.left( pos ) ); + localname = qname.mid( pos+1 ); + } else { + // there was no ':' + if ( isAttribute ) { + nsuri = ""; // attributes don't take default namespace + } else { + nsuri = uri( "" ); // get default namespace + } + localname = qname; + } +} + +/*! + Returns an enumeration of all prefixes currently declared. + + Note: if there is a default prefix, it will not be returned in this + enumeration; check for the default prefix using uri() with an argument + of "". +*/ +QStringList QXmlNamespaceSupport::prefixes() const +{ + QStringList list; + + QMap<QString, QString>::ConstIterator itc, it = ns.begin(); + while ( (itc=it) != ns.end() ) { + ++it; + if ( !itc.key().isEmpty() ) + list.append( itc.key() ); + } + return list; +} + +/*! + Returns a list of all prefixes currently declared for a URI. + + The xml: prefix will be included. If you want only one prefix that's + mapped to the namespace URI, and you don't care which one you get, use the + prefix() function instead. + + Note: the empty (default) prefix is never included in this enumeration; to + check for the presence of a default namespace, use uri() with an + argument of "". +*/ +QStringList QXmlNamespaceSupport::prefixes( const QString& uri ) const +{ + QStringList list; + + QMap<QString, QString>::ConstIterator itc, it = ns.begin(); + while ( (itc=it) != ns.end() ) { + ++it; + if ( itc.data() == uri && !itc.key().isEmpty() ) + list.append( itc.key() ); + } + return list; +} + +/*! + Starts a new namespace context. + + Normally, you should push a new context at the beginning of each XML element: + the new context will automatically inherit the declarations of its parent + context, but it will also keep track of which declarations were made within + this context. +*/ +void QXmlNamespaceSupport::pushContext() +{ + nsStack.push( ns ); +} + +/*! + Reverts to the previous namespace context. + + Normally, you should pop the context at the end of each XML element. After + popping the context, all namespace prefix mappings that were previously in + force are restored. +*/ +void QXmlNamespaceSupport::popContext() +{ + if( !nsStack.isEmpty() ) + ns = nsStack.pop(); +} + +/*! + Resets this namespace support object for reuse. +*/ +void QXmlNamespaceSupport::reset() +{ + nsStack.clear(); + ns.clear(); + ns.insert( "xml", "http://www.w3.org/XML/1998/namespace" ); // the XML namespace +} + + + +/********************************************* + * + * QXmlAttributes + * + *********************************************/ + +/*! + \class QXmlAttributes qxml.h + \brief The QXmlAttributes class provides XML attributes. + + \module XML + + If attributes are reported by QXmlContentHandler::startElement() this + class is used to pass the attribute values. It provides you with different + functions to access the attribute names and values. +*/ +/*! + \fn QXmlAttributes::QXmlAttributes() + + Constructs an empty attribute list. +*/ +/*! + \fn QXmlAttributes::~QXmlAttributes() + + Destructs attributes. +*/ + +/*! + Look up the index of an attribute by an XML 1.0 qualified name. + + Returns the index of the attribute (starting with 0) or -1 if it wasn't + found. + + See also the <a href="xml-sax.html#namespaces">namespace description</a>. +*/ +int QXmlAttributes::index( const QString& qName ) const +{ + return qnameList.findIndex( qName ); +} + +/*! + Looks up the index of an attribute by a namespace name. + + \a uri specifies the namespace URI, or the empty string if the name has no + namespace URI. \a localPart specifies the attribute's local name. + + Returns the index of the attribute (starting with 0) or -1 if it wasn't + found. + + See also the <a href="xml-sax.html#namespaces">namespace description</a>. +*/ +int QXmlAttributes::index( const QString& uri, const QString& localPart ) const +{ + uint count = uriList.count(); + for ( uint i=0; i<count; i++ ) { + if ( uriList[i] == uri && localnameList[i] == localPart ) + return i; + } + return -1; +} + +/*! + Returns the number of attributes in the list. +*/ +int QXmlAttributes::length() const +{ + return valueList.count(); +} + +/*! + Looks up an attribute's local name by index (starting with 0). + + See also the <a href="xml-sax.html#namespaces">namespace description</a>. +*/ +QString QXmlAttributes::localName( int index ) const +{ + return localnameList[index]; +} + +/*! + Looks up an attribute's XML 1.0 qualified name by index (starting with 0). + + See also the <a href="xml-sax.html#namespaces">namespace description</a>. +*/ +QString QXmlAttributes::qName( int index ) const +{ + return qnameList[index]; +} + +/*! + Looks up an attribute's namespace URI by index (starting with 0). + + See also the <a href="xml-sax.html#namespaces">namespace description</a>. +*/ +QString QXmlAttributes::uri( int index ) const +{ + return uriList[index]; +} + +/*! + Looks up an attribute's type by index (starting with 0). + + At the moment only 'CDATA' is returned. +*/ +QString QXmlAttributes::type( int ) const +{ + return "CDATA"; +} + +/*! + Looks up an attribute's type by XML 1.0 qualified name. + + At the moment only 'CDATA' is returned. +*/ +QString QXmlAttributes::type( const QString& ) const +{ + return "CDATA"; +} + +/*! + Looks up an attribute's type by namespace name. + + The first parameter specifies the namespace URI, or the empty string if + the name has no namespace URI. The second parameter specifies the + attribute's local name. + + At the moment only 'CDATA' is returned. +*/ +QString QXmlAttributes::type( const QString&, const QString& ) const +{ + return "CDATA"; +} + +/*! + Looks up an attribute's value by index (starting with 0). +*/ +QString QXmlAttributes::value( int index ) const +{ + return valueList[index]; +} + +/*! + Looks up an attribute's value by XML 1.0 qualified name. + + See also the <a href="xml-sax.html#namespaces">namespace description</a>. +*/ +QString QXmlAttributes::value( const QString& qName ) const +{ + int i = index( qName ); + if ( i == -1 ) + return QString::null; + return valueList[ i ]; +} + +/*! + Looks up an attribute's value by namespace name. + + \a uri specifies the namespace URI, or the empty string if the name has no + namespace URI. \a localName specifies the attribute's local name. + + See also the <a href="xml-sax.html#namespaces">namespace description</a>. +*/ +QString QXmlAttributes::value( const QString& uri, const QString& localName ) const +{ + int i = index( uri, localName ); + if ( i == -1 ) + return QString::null; + return valueList[ i ]; +} + + +/********************************************* + * + * QXmlInputSource + * + *********************************************/ + +/*! + \class QXmlInputSource qxml.h + \brief The QXmlInputSource class is the source where XML data is read from. + + \module XML + + All subclasses of QXmlReader read the input from this class. +*/ + +/*! + Returns all the data this input source contains. +*/ +const QString& QXmlInputSource::data() const +{ + return input; +} + +/*! + Constructs a input source which contains no data. +*/ +QXmlInputSource::QXmlInputSource( ) +{ + input = ""; +} + +/*! + Constructs a input source and get the data from the text stream. +*/ +QXmlInputSource::QXmlInputSource( QTextStream& stream ) +{ + QByteArray rawData; + if ( stream.device()->isDirectAccess() ) { + rawData = stream.device()->readAll(); + } else { + int nread = 0; + const int bufsize = 512; + while ( !stream.device()->atEnd() ) { + rawData.resize( nread + bufsize ); + nread += stream.device()->readBlock( rawData.data()+nread, bufsize ); + } + rawData.resize( nread ); + } + readInput( rawData ); +} + +/*! + Constructs a input source and get the data from a file. If the file cannot be + read the input source is empty. +*/ +QXmlInputSource::QXmlInputSource( QFile& file ) +{ + if ( !file.open(IO_ReadOnly) ) { + input = ""; + return; + } + QByteArray rawData = file.readAll(); + readInput( rawData ); + file.close(); +} + +/*! + Destructor. +*/ +QXmlInputSource::~QXmlInputSource() +{ +} + +/*! + Sets the data of the input source to \a dat. +*/ +void QXmlInputSource::setData( const QString& dat ) +{ + input = dat; +} + +/*! + Read the XML file from the byte array; try to recoginize the encoding. +*/ +// ### The input source should not do the encoding detection! +void QXmlInputSource::readInput( QByteArray& rawData ) +{ + QBuffer buf( rawData ); + buf.open( IO_ReadOnly ); + QTextStream *stream = new QTextStream( &buf ); + QChar tmp; + // assume UTF8 or UTF16 at first + stream->setEncoding( QTextStream::UnicodeUTF8 ); + input = ""; + // read the first 5 characters + for ( int i=0; i<5; i++ ) { + *stream >> tmp; + input += tmp; + } + // starts the document with an XML declaration? + if ( input == "<?xml" ) { + // read the whole XML declaration + do { + *stream >> tmp; + input += tmp; + } while( tmp != '>' ); + // and try to find out if there is an encoding + int pos = input.find( "encoding" ); + if ( pos != -1 ) { + QString encoding; + do { + pos++; + if ( pos > (int)input.length() ) + goto finished; + } while( input[pos] != '"' && input[pos] != '\'' ); + pos++; + while( input[pos] != '"' && input[pos] != '\'' ) { + encoding += input[pos]; + pos++; + if ( pos > (int)input.length() ) + goto finished; + } + delete stream; + stream = new QTextStream( &buf ); + stream->setCodec( QTextCodec::codecForName( encoding ) ); + buf.reset(); + input = ""; + } + } +finished: + input += stream->read(); + delete stream; + buf.close(); +} + + +/********************************************* + * + * QXmlDefaultHandler + * + *********************************************/ + +/*! + \class QXmlContentHandler qxml.h + \brief The QXmlContentHandler class provides an interface to report logical + content of XML data. + + \module XML + + If the application needs to be informed of basic parsing events, it + implements this interface and sets it with QXmlReader::setContentHandler(). + The reader reports basic document-related events like the start and end of + elements and character data through this interface. + + The order of events in this interface is very important, and mirrors the + order of information in the document itself. For example, all of an element's + content (character data, processing instructions, and/or subelements) will + appear, in order, between the startElement() event and the corresponding + endElement() event. + + The class QXmlDefaultHandler gives a default implementation for this + interface; subclassing from this class is very convenient if you want only be + informed of some parsing events. + + See also the <a href="xml.html#introSAX2">Introduction to SAX2</a>. + + \sa QXmlDTDHandler QXmlDeclHandler QXmlEntityResolver QXmlErrorHandler + QXmlLexicalHandler +*/ +/*! + \fn void QXmlContentHandler::setDocumentLocator( QXmlLocator* locator ) + + The reader calls this function before he starts parsing the document. The + argument \a locator is a pointer to a QXmlLocator which allows the + application to get the actual position of the parsing in the document. + + Do not destroy the \a locator; it is destroyed when the reader is destroyed + (do not use the \a locator after the reader got destroyed). +*/ +/*! + \fn bool QXmlContentHandler::startDocument() + + The reader calls this function when he starts parsing the document. + The reader will call this function only once before any other functions in + this class or in the QXmlDTDHandler class are called (except + QXmlContentHandler::setDocumentLocator()). + + If this function returns FALSE the reader will stop parsing and will report + an error. The reader will use the function errorString() to get the error + message that will be used for reporting the error. + + \sa endDocument() +*/ +/*! + \fn bool QXmlContentHandler::endDocument() + + The reader calls this function after he has finished the parsing. It + is only called once. It is the last function of all handler functions that is + called. It is called after the reader has read all input or has abandoned + parsing because of a fatal error. + + If this function returns FALSE the reader will stop parsing and will report + an error. The reader will use the function errorString() to get the error + message that will be used for reporting the error. + + \sa startDocument() +*/ +/*! + \fn bool QXmlContentHandler::startPrefixMapping( const QString& prefix, const QString& uri ) + + The reader calls this function to signal the begin of a prefix-URI + namespace mapping scope. This information is not necessary for normal + namespace processing since the reader automatically replaces prefixes for + element and attribute names. + + Note that startPrefixMapping and endPrefixMapping calls are not guaranteed to + be properly nested relative to each-other: all startPrefixMapping events will + occur before the corresponding startElement event, and all endPrefixMapping + events will occur after the corresponding endElement event, but their order + is not otherwise guaranteed. + + The argument \a prefix is the namespace prefix being declared and the + argument \a uri is the namespace URI the prefix is mapped to. + + If this function returns FALSE the reader will stop parsing and will report + an error. The reader will use the function errorString() to get the error + message that will be used for reporting the error. + + See also the <a href="xml-sax.html#namespaces">namespace description</a>. + + \sa endPrefixMapping() +*/ +/*! + \fn bool QXmlContentHandler::endPrefixMapping( const QString& prefix ) + + The reader calls this function to signal the end of a prefix mapping. + + If this function returns FALSE the reader will stop parsing and will report + an error. The reader will use the function errorString() to get the error + message that will be used for reporting the error. + + See also the <a href="xml-sax.html#namespaces">namespace description</a>. + + \sa startPrefixMapping() +*/ +/*! + \fn bool QXmlContentHandler::startElement( const QString& namespaceURI, const QString& localName, const QString& qName, const QXmlAttributes& atts ) + + The reader calls this function when he has parsed a start element tag. + + There will be a corresponding endElement() call when the corresponding end + element tag was read. The startElement() and endElement() calls are always + nested correctly. Empty element tags (e.g. <a/>) are reported by + startElement() directly followed by a call to endElement(). + + The attribute list provided will contain only attributes with explicit + values. The attribute list will contain attributes used for namespace + declaration (i.e. attributes starting with xmlns) only if the + namespace-prefix property of the reader is TRUE. + + The argument \a uri is the namespace URI, or the empty string if the element + has no namespace URI or if namespace processing is not being performed, \a + localName is the local name (without prefix), or the empty string if + namespace processing is not being performed, \a qName is the qualified name + (with prefix), or the empty string if qualified names are not available and + \a atts are the attributes attached to the element. If there are no + attributes, \a atts is an empty attributes object + + If this function returns FALSE the reader will stop parsing and will report + an error. The reader will use the function errorString() to get the error + message that will be used for reporting the error. + + See also the <a href="xml-sax.html#namespaces">namespace description</a>. + + \sa endElement() +*/ +/*! + \fn bool QXmlContentHandler::endElement( const QString& namespaceURI, const QString& localName, const QString& qName ) + + The reader calls this function when he has parsed an end element tag. + + If this function returns FALSE the reader will stop parsing and will report + an error. The reader will use the function errorString() to get the error + message that will be used for reporting the error. + + See also the <a href="xml-sax.html#namespaces">namespace description</a>. + + \sa startElement() +*/ +/*! + \fn bool QXmlContentHandler::characters( const QString& ch ) + + The reader calls this function when he has parsed a chunk of character + data (either normal character data or character data inside a CDATA section; + if you have to distinguish between those two types you have to use + QXmlLexicalHandler::startCDATA() and QXmlLexicalHandler::endCDATA() in + addition). + + Some readers will report whitespace in element content using the + ignorableWhitespace() function rather than this one (QXmlSimpleReader will + do it not though). + + A reader is allowed to report the character data of an element in more than + one chunk; e.g. a reader might want to report "a &lt; b" in three + characters() events ("a ", "<" and " b"). + + If this function returns FALSE the reader will stop parsing and will report + an error. The reader will use the function errorString() to get the error + message that will be used for reporting the error. +*/ +/*! + \fn bool QXmlContentHandler::ignorableWhitespace( const QString& ch ) + + Some readers may use this function to report each chunk of whitespace in + element content (QXmlSimpleReader does not though). + + If this function returns FALSE the reader will stop parsing and will report + an error. The reader will use the function errorString() to get the error + message that will be used for reporting the error. +*/ +/*! + \fn bool QXmlContentHandler::processingInstruction( const QString& target, const QString& data ) + + The reader calls this function when he has parsed a processing + instruction. + + \a target is the target name of the processing instruction and \a data is the + data of the processing instruction. + + If this function returns FALSE the reader will stop parsing and will report + an error. The reader will use the function errorString() to get the error + message that will be used for reporting the error. +*/ +/*! + \fn bool QXmlContentHandler::skippedEntity( const QString& name ) + + Some readers may skip entities if they have not seen the declarations (e.g. + because they are in an external DTD). If they do so they will report it by + calling this function. + + If this function returns FALSE the reader will stop parsing and will report + an error. The reader will use the function errorString() to get the error + message that will be used for reporting the error. +*/ +/*! + \fn QString QXmlContentHandler::errorString() + + The reader calls this function to get an error string if any of the handler + functions returns FALSE to him. +*/ + + +/*! + \class QXmlErrorHandler qxml.h + \brief The QXmlErrorHandler class provides an interface to report errors in + XML data. + + \module XML + + If the application is interested in reporting errors to the user or any other + customized error handling, you should subclass this class. + + You can set the error handler with QXmlReader::setErrorHandler(). + + See also the <a href="xml.html#introSAX2">Introduction to SAX2</a>. + + \sa QXmlDTDHandler QXmlDeclHandler QXmlContentHandler QXmlEntityResolver + QXmlLexicalHandler +*/ +/*! + \fn bool QXmlErrorHandler::warning( const QXmlParseException& exception ) + + A reader might use this function to report a warning. Warnings are conditions + that are not errors or fatal errors as defined by the XML 1.0 specification. + + If this function returns FALSE the reader will stop parsing and will report + an error. The reader will use the function errorString() to get the error + message that will be used for reporting the error. +*/ +/*! + \fn bool QXmlErrorHandler::error( const QXmlParseException& exception ) + + A reader might use this function to report a recoverable error. A recoverable + error corresponds to the definiton of "error" in section 1.2 of the XML 1.0 + specification. + + The reader must continue to provide normal parsing events after invoking this + function. + + If this function returns FALSE the reader will stop parsing and will report + an error. The reader will use the function errorString() to get the error + message that will be used for reporting the error. +*/ +/*! + \fn bool QXmlErrorHandler::fatalError( const QXmlParseException& exception ) + + A reader must use this function to report a non-recoverable error. + + If this function returns TRUE the reader might try to go on parsing and + reporting further errors; but no regular parsing events are reported. +*/ +/*! + \fn QString QXmlErrorHandler::errorString() + + The reader calls this function to get an error string if any of the handler + functions returns FALSE to him. +*/ + + +/*! + \class QXmlDTDHandler qxml.h + \brief The QXmlDTDHandler class provides an interface to report DTD content + of XML data. + + \module XML + + If an application needs information about notations and unparsed entities, + then the application implements this interface and registers an instance with + QXmlReader::setDTDHandler(). + + Note that this interface includes only those DTD events that the XML + recommendation requires processors to report: notation and unparsed entity + declarations. + + See also the <a href="xml.html#introSAX2">Introduction to SAX2</a>. + + \sa QXmlDeclHandler QXmlContentHandler QXmlEntityResolver QXmlErrorHandler + QXmlLexicalHandler +*/ +/*! + \fn bool QXmlDTDHandler::notationDecl( const QString& name, const QString& publicId, const QString& systemId ) + + The reader calls this function when he has parsed a notation + declaration. + + The argument \a name is the notation name, \a publicId is the notations's + public identifier and \a systemId is the notations's system identifier. + + If this function returns FALSE the reader will stop parsing and will report + an error. The reader will use the function errorString() to get the error + message that will be used for reporting the error. +*/ +/*! + \fn bool QXmlDTDHandler::unparsedEntityDecl( const QString& name, const QString& publicId, const QString& systemId, const QString& notationName ) + + The reader calls this function when he finds an unparsed entity declaration. + + The argument \a name is the unparsed entity's name, \a publicId is the + entity's public identifier, \a systemId is the entity's system identifier and + \a notation is the name of the associated notation. + + If this function returns FALSE the reader will stop parsing and will report + an error. The reader will use the function errorString() to get the error + message that will be used for reporting the error. +*/ +/*! + \fn QString QXmlDTDHandler::errorString() + + The reader calls this function to get an error string if any of the handler + functions returns FALSE to him. +*/ + + +/*! + \class QXmlEntityResolver qxml.h + \brief The QXmlEntityResolver class provides an interface to resolve extern + entities contained in XML data. + + \module XML + + If an application needs to implement customized handling for external + entities, it must implement this interface and register it with + QXmlReader::setEntityResolver(). + + See also the <a href="xml.html#introSAX2">Introduction to SAX2</a>. + + \sa QXmlDTDHandler QXmlDeclHandler QXmlContentHandler QXmlErrorHandler + QXmlLexicalHandler +*/ +/*! + \fn bool QXmlEntityResolver::resolveEntity( const QString& publicId, const QString& systemId, QXmlInputSource* ret ) + + The reader will call this function before he opens any external entity, + except the top-level document entity. The application may request the reader + to resolve the entity itself (\a ret is 0) or to use an entirely different + input source (\a ret points to the input source). + + The reader will delete the input source \a ret when he no longer needs it. So + you should allocate it on the heap with \c new. + + The argument \a publicId is the public identifier of the external entity, \a + systemId is the system identifier of the external entity and \a ret is the + return value of this function: if it is 0 the reader should resolve the + entity itself, if it is non-zero it must point to an input source which the + reader will use instead. + + If this function returns FALSE the reader will stop parsing and will report + an error. The reader will use the function errorString() to get the error + message that will be used for reporting the error. +*/ +/*! + \fn QString QXmlEntityResolver::errorString() + + The reader calls this function to get an error string if any of the handler + functions returns FALSE to him. +*/ + + +/*! + \class QXmlLexicalHandler qxml.h + \brief The QXmlLexicalHandler class provides an interface to report lexical + content of XML data. + + \module XML + + The events in the lexical handler apply to the entire document, not just to + the document element, and all lexical handler events appear between the + content handler's startDocument and endDocument events. + + You can set the lexical handler with QXmlReader::setLexicalHandler(). + + This interface is designed after the SAX2 extension LexicalHandler. The + functions startEntity() and endEntity() are not included though. + + See also the <a href="xml.html#introSAX2">Introduction to SAX2</a>. + + \sa QXmlDTDHandler QXmlDeclHandler QXmlContentHandler QXmlEntityResolver + QXmlErrorHandler +*/ +/*! + \fn bool QXmlLexicalHandler::startDTD( const QString& name, const QString& publicId, const QString& systemId ) + + The reader calls this function to report the start of a DTD declaration, if + any. + + All declarations reported through QXmlDTDHandler or QXmlDeclHandler appear + between the startDTD() and endDTD() calls. + + If this function returns FALSE the reader will stop parsing and will report + an error. The reader will use the function errorString() to get the error + message that will be used for reporting the error. + + \sa endDTD() +*/ +/*! + \fn bool QXmlLexicalHandler::endDTD() + + The reader calls this function to report the end of a DTD declaration, if + any. + + If this function returns FALSE the reader will stop parsing and will report + an error. The reader will use the function errorString() to get the error + message that will be used for reporting the error. + + \sa startDTD() +*/ +/*! + \fn bool QXmlLexicalHandler::startCDATA() + + The reader calls this function to report the start of a CDATA section. The + content of the CDATA section will be reported through the regular + QXmlContentHandler::characters(). This function is intended only to report + the boundary. + + If this function returns FALSE the reader will stop parsing and will report + an error. The reader will use the function errorString() to get the error + message that will be used for reporting the error. + + \sa endCDATA() +*/ +/*! + \fn bool QXmlLexicalHandler::endCDATA() + + The reader calls this function to report the end of a CDATA section. + + If this function returns FALSE the reader will stop parsing and will report + an error. The reader will use the function errorString() to get the error + message that will be used for reporting the error. + + \sa startCDATA() +*/ +/*! + \fn bool QXmlLexicalHandler::comment( const QString& ch ) + + The reader calls this function to report an XML comment anywhere in the + document. + + If this function returns FALSE the reader will stop parsing and will report + an error. The reader will use the function errorString() to get the error + message that will be used for reporting the error. +*/ +/*! + \fn QString QXmlLexicalHandler::errorString() + + The reader calls this function to get an error string if any of the handler + functions returns FALSE to him. +*/ + + +/*! + \class QXmlDeclHandler qxml.h + \brief The QXmlDeclHandler class provides an interface to report declaration + content of XML data. + + \module XML + + You can set the declaration handler with QXmlReader::setDeclHandler(). + + This interface is designed after the SAX2 extension DeclHandler. + + See also the <a href="xml.html#introSAX2">Introduction to SAX2</a>. + + \sa QXmlDTDHandler QXmlContentHandler QXmlEntityResolver QXmlErrorHandler + QXmlLexicalHandler +*/ +/*! + \fn bool QXmlDeclHandler::attributeDecl( const QString& eName, const QString& aName, const QString& type, const QString& valueDefault, const QString& value ) + + The reader calls this function to report an attribute type declaration. Only + the effective (first) declaration for an attribute will be reported. + + If this function returns FALSE the reader will stop parsing and will report + an error. The reader will use the function errorString() to get the error + message that will be used for reporting the error. +*/ +/*! + \fn bool QXmlDeclHandler::internalEntityDecl( const QString& name, const QString& value ) + + The reader calls this function to report an internal entity declaration. Only + the effective (first) declaration will be reported. + + If this function returns FALSE the reader will stop parsing and will report + an error. The reader will use the function errorString() to get the error + message that will be used for reporting the error. +*/ +/*! + \fn bool QXmlDeclHandler::externalEntityDecl( const QString& name, const QString& publicId, const QString& systemId ) + + The reader calls this function to report a parsed external entity + declaration. Only the effective (first) declaration for each entity will be + reported. + + If this function returns FALSE the reader will stop parsing and will report + an error. The reader will use the function errorString() to get the error + message that will be used for reporting the error. +*/ +/*! + \fn QString QXmlDeclHandler::errorString() + + The reader calls this function to get an error string if any of the handler + functions returns FALSE to him. +*/ + + +/*! + \class QXmlDefaultHandler qxml.h + \brief The QXmlDefaultHandler class provides a default implementation of all + XML handler classes. + + \module XML + + Very often you are only interested in parts of the things that that the + reader reports to you. This class simply implements a default behaviour of + the handler classes (most of the time: do nothing). Normally this is the + class you subclass for implementing your customized handler. + + See also the <a href="xml.html#introSAX2">Introduction to SAX2</a>. + + \sa QXmlDTDHandler QXmlDeclHandler QXmlContentHandler QXmlEntityResolver + QXmlErrorHandler QXmlLexicalHandler +*/ +/*! + \fn QXmlDefaultHandler::QXmlDefaultHandler() + + Constructor. +*/ +/*! + \fn QXmlDefaultHandler::~QXmlDefaultHandler() + + Destructor. +*/ + +/*! + Does nothing. +*/ +void QXmlDefaultHandler::setDocumentLocator( QXmlLocator* ) +{ +} + +/*! + Does nothing. +*/ +bool QXmlDefaultHandler::startDocument() +{ + return TRUE; +} + +/*! + Does nothing. +*/ +bool QXmlDefaultHandler::endDocument() +{ + return TRUE; +} + +/*! + Does nothing. +*/ +bool QXmlDefaultHandler::startPrefixMapping( const QString&, const QString& ) +{ + return TRUE; +} + +/*! + Does nothing. +*/ +bool QXmlDefaultHandler::endPrefixMapping( const QString& ) +{ + return TRUE; +} + +/*! + Does nothing. +*/ +bool QXmlDefaultHandler::startElement( const QString&, const QString&, + const QString&, const QXmlAttributes& ) +{ + return TRUE; +} + +/*! + Does nothing. +*/ +bool QXmlDefaultHandler::endElement( const QString&, const QString&, + const QString& ) +{ + return TRUE; +} + +/*! + Does nothing. +*/ +bool QXmlDefaultHandler::characters( const QString& ) +{ + return TRUE; +} + +/*! + Does nothing. +*/ +bool QXmlDefaultHandler::ignorableWhitespace( const QString& ) +{ + return TRUE; +} + +/*! + Does nothing. +*/ +bool QXmlDefaultHandler::processingInstruction( const QString&, + const QString& ) +{ + return TRUE; +} + +/*! + Does nothing. +*/ +bool QXmlDefaultHandler::skippedEntity( const QString& ) +{ + return TRUE; +} + +/*! + Does nothing. +*/ +bool QXmlDefaultHandler::warning( const QXmlParseException& ) +{ + return TRUE; +} + +/*! + Does nothing. +*/ +bool QXmlDefaultHandler::error( const QXmlParseException& ) +{ + return TRUE; +} + +/*! + Does nothing. +*/ +bool QXmlDefaultHandler::fatalError( const QXmlParseException& ) +{ + return TRUE; +} + +/*! + Does nothing. +*/ +bool QXmlDefaultHandler::notationDecl( const QString&, const QString&, + const QString& ) +{ + return TRUE; +} + +/*! + Does nothing. +*/ +bool QXmlDefaultHandler::unparsedEntityDecl( const QString&, const QString&, + const QString&, const QString& ) +{ + return TRUE; +} + +/*! + Always sets \a ret to 0, so that the reader will use the system identifier + provided in the XML document. +*/ +bool QXmlDefaultHandler::resolveEntity( const QString&, const QString&, + QXmlInputSource* &ret ) +{ + ret = 0; + return TRUE; +} + +/*! + Returns the default error string. +*/ +QString QXmlDefaultHandler::errorString() +{ + return QString( XMLERR_ERRORBYCONSUMER ); +} + +/*! + Does nothing. +*/ +bool QXmlDefaultHandler::startDTD( const QString&, const QString&, const QString& ) +{ + return TRUE; +} + +/*! + Does nothing. +*/ +bool QXmlDefaultHandler::endDTD() +{ + return TRUE; +} + +#if 0 +/*! + Does nothing. +*/ +bool QXmlDefaultHandler::startEntity( const QString& ) +{ + return TRUE; +} + +/*! + Does nothing. +*/ +bool QXmlDefaultHandler::endEntity( const QString& ) +{ + return TRUE; +} +#endif + +/*! + Does nothing. +*/ +bool QXmlDefaultHandler::startCDATA() +{ + return TRUE; +} + +/*! + Does nothing. +*/ +bool QXmlDefaultHandler::endCDATA() +{ + return TRUE; +} + +/*! + Does nothing. +*/ +bool QXmlDefaultHandler::comment( const QString& ) +{ + return TRUE; +} + +/*! + Does nothing. +*/ +bool QXmlDefaultHandler::attributeDecl( const QString&, const QString&, const QString&, const QString&, const QString& ) +{ + return TRUE; +} + +/*! + Does nothing. +*/ +bool QXmlDefaultHandler::internalEntityDecl( const QString&, const QString& ) +{ + return TRUE; +} + +/*! + Does nothing. +*/ +bool QXmlDefaultHandler::externalEntityDecl( const QString&, const QString&, const QString& ) +{ + return TRUE; +} + + +/********************************************* + * + * QXmlSimpleReaderPrivate + * + *********************************************/ + +class QXmlSimpleReaderPrivate +{ +private: + // constructor + QXmlSimpleReaderPrivate() + { } + + + // used for entity declarations + struct ExternParameterEntity + { + ExternParameterEntity( ) {} + ExternParameterEntity( const QString &p, const QString &s ) + : publicId(p), systemId(s) {} + QString publicId; + QString systemId; + }; + struct ExternEntity + { + ExternEntity( ) {} + ExternEntity( const QString &p, const QString &s, const QString &n ) + : publicId(p), systemId(s), notation(n) {} + QString publicId; + QString systemId; + QString notation; + }; + QMap<QString,ExternParameterEntity> externParameterEntities; + QMap<QString,QString> parameterEntities; + QMap<QString,ExternEntity> externEntities; + QMap<QString,QString> entities; + + // used for standalone declaration + enum Standalone { Yes, No, Unknown }; + + QString doctype; // only used for the doctype + QString xmlVersion; // only used to store the version information + QString encoding; // only used to store the encoding + Standalone standalone; // used to store the value of the standalone declaration + + QString publicId; // used by parseExternalID() to store the public ID + QString systemId; // used by parseExternalID() to store the system ID + QString attDeclEName; // use by parseAttlistDecl() + QString attDeclAName; // use by parseAttlistDecl() + + // flags for some features support + bool useNamespaces; + bool useNamespacePrefixes; + bool reportWhitespaceCharData; + + // used to build the attribute list + QXmlAttributes attList; + + // helper classes + QXmlLocator *locator; + QXmlNamespaceSupport namespaceSupport; + + // error string + QString error; + + // friend declarations + friend class QXmlSimpleReader; +}; + + +/********************************************* + * + * QXmlSimpleReader + * + *********************************************/ + +/*! + \class QXmlReader qxml.h + \brief The QXmlReader class provides an interface for XML readers (i.e. + parsers). + + \module XML + + This abstract class describes an interface for all XML readers in Qt. At the + moment there is only one implementation of a reader included in the XML + module of Qt (QXmlSimpleReader). In future releases there might be more + readers with different properties available (e.g. a validating parser). + + The design of the XML classes follow the + <a href="http://www.megginson.com/SAX/">SAX2 java interface</a>. + It was adopted to fit into the Qt naming conventions; so it should be very + easy for anybody who has worked with SAX2 to get started with the Qt XML + classes. + + All readers use the class QXmlInputSource to read the input document from. + Since you are normally interested in certain contents of the XML document, + the reader reports those contents through special handler classes + (QXmlDTDHandler, QXmlDeclHandler, QXmlContentHandler, QXmlEntityResolver, + QXmlErrorHandler and QXmlLexicalHandler). + + You have to subclass these classes. Since the handler classes describe only + interfaces you must implement all functions; there is a class + (QXmlDefaultHandler) to make this easier; it implements a default behaviour + (do nothing) for all functions. + + For getting started see also the + <a href="xml-sax.html#quickStart">Quick start</a>. + + \sa QXmlSimpleReader +*/ +/*! + \fn bool QXmlReader::feature( const QString& name, bool *ok ) const + + If the reader has the feature \a name, this function returns the value of the + feature. + + If the reader has not the feature \a name, the return value may be anything. + + If \a ok is not 0, then \a ok is set to TRUE if the reader has the feature + \a name, otherwise \a ok is set to FALSE. + + \sa setFeature() hasFeature() +*/ +/*! + \fn void QXmlReader::setFeature( const QString& name, bool value ) + + Sets the feature \a name to \a value. If the reader has not the feature \a + name, this value is ignored. + + \sa feature() hasFeature() +*/ +/*! + \fn bool QXmlReader::hasFeature( const QString& name ) const + + Returns \c TRUE if the reader has the feature \a name, otherwise FALSE. + + \sa feature() setFeature() +*/ +/*! + \fn void* QXmlReader::property( const QString& name, bool *ok ) const + + If the reader has the property \a name, this function returns the value of + the property. + + If the reader has not the property \a name, the return value is 0. + + If \a ok is not 0, then \a ok is set to TRUE if the reader has the property + \a name, otherwise \a ok is set to FALSE. + + \sa setProperty() hasProperty() +*/ +/*! + \fn void QXmlReader::setProperty( const QString& name, void* value ) + + Sets the property \a name to \a value. If the reader has not the property \a + name, this value is ignored. + + \sa property() hasProperty() +*/ +/*! + \fn bool QXmlReader::hasProperty( const QString& name ) const + + Returns TRUE if the reader has the property \a name, otherwise FALSE. + + \sa property() setProperty() +*/ +/*! + \fn void QXmlReader::setEntityResolver( QXmlEntityResolver* handler ) + + Sets the entity resolver to \a handler. + + \sa entityResolver() +*/ +/*! + \fn QXmlEntityResolver* QXmlReader::entityResolver() const + + Returns the entity resolver or 0 if none was set. + + \sa setEntityResolver() +*/ +/*! + \fn void QXmlReader::setDTDHandler( QXmlDTDHandler* handler ) + + Sets the DTD handler to \a handler. + + \sa DTDHandler() +*/ +/*! + \fn QXmlDTDHandler* QXmlReader::DTDHandler() const + + Returns the DTD handler or 0 if none was set. + + \sa setDTDHandler() +*/ +/*! + \fn void QXmlReader::setContentHandler( QXmlContentHandler* handler ) + + Sets the content handler to \a handler. + + \sa contentHandler() +*/ +/*! + \fn QXmlContentHandler* QXmlReader::contentHandler() const + + Returns the content handler or 0 if none was set. + + \sa setContentHandler() +*/ +/*! + \fn void QXmlReader::setErrorHandler( QXmlErrorHandler* handler ) + + Sets the error handler to \a handler. + + \sa errorHandler() +*/ +/*! + \fn QXmlErrorHandler* QXmlReader::errorHandler() const + + Returns the error handler or 0 if none was set + + \sa setErrorHandler() +*/ +/*! + \fn void QXmlReader::setLexicalHandler( QXmlLexicalHandler* handler ) + + Sets the lexical handler to \a handler. + + \sa lexicalHandler() +*/ +/*! + \fn QXmlLexicalHandler* QXmlReader::lexicalHandler() const + + Returns the lexical handler or 0 if none was set. + + \sa setLexicalHandler() +*/ +/*! + \fn void QXmlReader::setDeclHandler( QXmlDeclHandler* handler ) + + Sets the declaration handler to \a handler. + + \sa declHandler() +*/ +/*! + \fn QXmlDeclHandler* QXmlReader::declHandler() const + + Returns the declaration handler or 0 if none was set. + + \sa setDeclHandler() +*/ +/*! + \fn bool QXmlReader::parse( const QXmlInputSource& input ) + + Parses the XML document \a input. Returns TRUE if the parsing was successful, + otherwise FALSE. +*/ +/*! + \fn bool QXmlReader::parse( const QString& systemId ) + + Parses the XML document at the location \a systemId. Returns TRUE if the + parsing was successful, otherwise FALSE. +*/ + + +/*! + \class QXmlSimpleReader qxml.h + \brief The QXmlSimpleReader class provides an implementation of a simple XML + reader (i.e. parser). + + \module XML + + This XML reader is sufficient for simple parsing tasks. Here is a short list + of the properties of this reader: + <ul> + <li> well-formed parser + <li> does not parse any external entities + <li> can do namespace processing + </ul> + + For getting started see also the + <a href="xml-sax.html#quickStart">Quick start</a>. +*/ + +//guaranteed not to be a characater +const QChar QXmlSimpleReader::QEOF = QChar((ushort)0xffff); + +/*! + Constructs a simple XML reader. +*/ +QXmlSimpleReader::QXmlSimpleReader() +{ + d = new QXmlSimpleReaderPrivate(); + d->locator = new QXmlLocator( this ); + + entityRes = 0; + dtdHnd = 0; + contentHnd = 0; + errorHnd = 0; + lexicalHnd = 0; + declHnd = 0; + + // default feature settings + d->useNamespaces = TRUE; + d->useNamespacePrefixes = FALSE; + d->reportWhitespaceCharData = TRUE; +} + +/*! + Destroys a simple XML reader. +*/ +QXmlSimpleReader::~QXmlSimpleReader() +{ + delete d->locator; + delete d; +} + +/*! + Gets the state of a feature. + + \sa setFeature() hasFeature() +*/ +bool QXmlSimpleReader::feature( const QString& name, bool *ok ) const +{ + if ( ok != 0 ) + *ok = TRUE; + if ( name == "http://xml.org/sax/features/namespaces" ) { + return d->useNamespaces; + } else if ( name == "http://xml.org/sax/features/namespace-prefixes" ) { + return d->useNamespacePrefixes; + } else if ( name == "http://trolltech.com/xml/features/report-whitespace-only-CharData" ) { + return d->reportWhitespaceCharData; + } else { + qWarning( "Unknown feature %s", name.ascii() ); + if ( ok != 0 ) + *ok = FALSE; + } + return FALSE; +} + +/*! + Sets the state of a feature. + + Supported features are: + <ul> + <li> http://xml.org/sax/features/namespaces: + if this feature is TRUE, namespace processing is performed + <li> http://xml.org/sax/features/namespace-prefixes: + if this feature is TRUE, the the original prefixed names and attributes + used for namespace declarations are reported + <li> http://trolltech.com/xml/features/report-whitespace-only-CharData: + if this feature is TRUE, CharData that consists only of whitespace (and + no other characters) is not reported via + QXmlContentHandler::characters() + </ul> + + \sa feature() hasFeature() +*/ +void QXmlSimpleReader::setFeature( const QString& name, bool value ) +{ + if ( name == "http://xml.org/sax/features/namespaces" ) { + d->useNamespaces = value; + } else if ( name == "http://xml.org/sax/features/namespace-prefixes" ) { + d->useNamespacePrefixes = value; + } else if ( name == "http://trolltech.com/xml/features/report-whitespace-only-CharData" ) { + d->reportWhitespaceCharData = value; + } else { + qWarning( "Unknown feature %s", name.ascii() ); + } +} + +/*! + Returns TRUE if the class has a feature named \a feature, otherwise FALSE. + + \sa setFeature() feature() +*/ +bool QXmlSimpleReader::hasFeature( const QString& name ) const +{ + if ( name == "http://xml.org/sax/features/namespaces" || + name == "http://xml.org/sax/features/namespace-prefixes" || + name == "http://trolltech.com/xml/features/report-whitespace-only-CharData" ) { + return TRUE; + } else { + return FALSE; + } +} + +/*! + Returns 0 since this class does not support any properties. +*/ +void* QXmlSimpleReader::property( const QString&, bool *ok ) const +{ + if ( ok != 0 ) + *ok = FALSE; + return 0; +} + +/*! + Does nothing since this class does not support any properties. +*/ +void QXmlSimpleReader::setProperty( const QString&, void* ) +{ +} + +/*! + Returns FALSE since this class does not support any properties. +*/ +bool QXmlSimpleReader::hasProperty( const QString& ) const +{ + return FALSE; +} + +/*! \reimp */ +void QXmlSimpleReader::setEntityResolver( QXmlEntityResolver* handler ) +{ entityRes = handler; } + +/*! \reimp */ +QXmlEntityResolver* QXmlSimpleReader::entityResolver() const +{ return entityRes; } + +/*! \reimp */ +void QXmlSimpleReader::setDTDHandler( QXmlDTDHandler* handler ) +{ dtdHnd = handler; } + +/*! \reimp */ +QXmlDTDHandler* QXmlSimpleReader::DTDHandler() const +{ return dtdHnd; } + +/*! \reimp */ +void QXmlSimpleReader::setContentHandler( QXmlContentHandler* handler ) +{ contentHnd = handler; } + +/*! \reimp */ +QXmlContentHandler* QXmlSimpleReader::contentHandler() const +{ return contentHnd; } + +/*! \reimp */ +void QXmlSimpleReader::setErrorHandler( QXmlErrorHandler* handler ) +{ errorHnd = handler; } + +/*! \reimp */ +QXmlErrorHandler* QXmlSimpleReader::errorHandler() const +{ return errorHnd; } + +/*! \reimp */ +void QXmlSimpleReader::setLexicalHandler( QXmlLexicalHandler* handler ) +{ lexicalHnd = handler; } + +/*! \reimp */ +QXmlLexicalHandler* QXmlSimpleReader::lexicalHandler() const +{ return lexicalHnd; } + +/*! \reimp */ +void QXmlSimpleReader::setDeclHandler( QXmlDeclHandler* handler ) +{ declHnd = handler; } + +/*! \reimp */ +QXmlDeclHandler* QXmlSimpleReader::declHandler() const +{ return declHnd; } + + + +/*! \reimp */ +bool QXmlSimpleReader::parse( const QXmlInputSource& input ) +{ + init( input ); + // call the handler + if ( contentHnd ) { + contentHnd->setDocumentLocator( d->locator ); + if ( !contentHnd->startDocument() ) { + d->error = contentHnd->errorString(); + goto parseError; + } + } + // parse prolog + if ( !parseProlog() ) { + d->error = XMLERR_ERRORPARSINGPROLOG; + goto parseError; + } + // parse element + if ( !parseElement() ) { + d->error = XMLERR_ERRORPARSINGMAINELEMENT; + goto parseError; + } + // parse Misc* + while ( !atEnd() ) { + if ( !parseMisc() ) { + d->error = XMLERR_ERRORPARSINGMISC; + goto parseError; + } + } + // is stack empty? + if ( !tags.isEmpty() ) { + d->error = XMLERR_UNEXPECTEDEOF; + goto parseError; + } + // call the handler + if ( contentHnd ) { + if ( !contentHnd->endDocument() ) { + d->error = contentHnd->errorString(); + goto parseError; + } + } + + return TRUE; + + // error handling + +parseError: + reportParseError(); + tags.clear(); + return FALSE; +} + +/*! + Parses the prolog [22]. +*/ +bool QXmlSimpleReader::parseProlog() +{ + bool xmldecl_possible = TRUE; + bool doctype_read = FALSE; + + const signed char Init = 0; + const signed char EatWS = 1; // eat white spaces + const signed char Lt = 2; // '<' read + const signed char Em = 3; // '!' read + const signed char DocType = 4; // read doctype + const signed char Comment = 5; // read comment + const signed char PI = 6; // read PI + const signed char Done = 7; + + const signed char InpWs = 0; + const signed char InpLt = 1; // < + const signed char InpQm = 2; // ? + const signed char InpEm = 3; // ! + const signed char InpD = 4; // D + const signed char InpDash = 5; // - + const signed char InpUnknown = 6; + + // use some kind of state machine for parsing + static signed char table[7][7] = { + /* InpWs InpLt InpQm InpEm InpD InpDash InpUnknown */ + { EatWS, Lt, -1, -1, -1, -1, -1 }, // Init + { -1, Lt, -1, -1, -1, -1, -1 }, // EatWS + { -1, -1, PI, Em, Done, -1, Done }, // Lt + { -1, -1, -1, -1, DocType, Comment, -1 }, // Em + { EatWS, Lt, -1, -1, -1, -1, -1 }, // DocType + { EatWS, Lt, -1, -1, -1, -1, -1 }, // Comment + { EatWS, Lt, -1, -1, -1, -1, -1 } // PI + }; + signed char state = Init; + signed char input; + bool parseOk = TRUE; + + while ( TRUE ) { + + // read input + if ( atEnd() ) { + d->error = XMLERR_UNEXPECTEDEOF; + goto parseError; + } + if ( is_S(c) ) { + input = InpWs; + } else if ( c == '<' ) { + input = InpLt; + } else if ( c == '?' ) { + input = InpQm; + } else if ( c == '!' ) { + input = InpEm; + } else if ( c == 'D' ) { + input = InpD; + } else if ( c == '-' ) { + input = InpDash; + } else { + input = InpUnknown; + } + // get new state + state = table[state][input]; + + // in some cases do special actions depending on state + switch ( state ) { + case EatWS: + // XML declaration only on first position possible + xmldecl_possible = FALSE; + // eat white spaces + eat_ws(); + break; + case Lt: + // next character + next(); + break; + case Em: + // XML declaration only on first position possible + xmldecl_possible = FALSE; + // next character + next(); + break; + case DocType: + parseOk = parseDoctype(); + break; + case Comment: + parseOk = parseComment(); + break; + case PI: + parseOk = parsePI( xmldecl_possible ); + break; + } + // no input is read after this + switch ( state ) { + case DocType: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGPROLOG; + goto parseError; + } + if ( doctype_read ) { + d->error = XMLERR_MORETHANONEDOCTYPE; + goto parseError; + } else { + doctype_read = FALSE; + } + break; + case Comment: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGPROLOG; + goto parseError; + } + if ( lexicalHnd ) { + if ( !lexicalHnd->comment( string() ) ) { + d->error = lexicalHnd->errorString(); + goto parseError; + } + } + break; + case PI: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGPROLOG; + goto parseError; + } + // call the handler + if ( contentHnd ) { + if ( xmldecl_possible && !d->xmlVersion.isEmpty() ) { + QString value( "version = '" ); + value += d->xmlVersion; + value += "'"; + if ( !d->encoding.isEmpty() ) { + value += " encoding = '"; + value += d->encoding; + value += "'"; + } + if ( d->standalone == QXmlSimpleReaderPrivate::Yes ) { + value += " standalone = 'yes'"; + } else if ( d->standalone == QXmlSimpleReaderPrivate::No ) { + value += " standalone = 'no'"; + } + if ( !contentHnd->processingInstruction( "xml", value ) ) { + d->error = contentHnd->errorString(); + goto parseError; + } + } else { + if ( !contentHnd->processingInstruction( name(), string() ) ) { + d->error = contentHnd->errorString(); + goto parseError; + } + } + } + // XML declaration only on first position possible + xmldecl_possible = FALSE; + break; + case Done: + return TRUE; + case -1: + d->error = XMLERR_ERRORPARSINGELEMENT; + goto parseError; + } + + } + + return TRUE; + +parseError: + reportParseError(); + return FALSE; +} + +/*! + Parse an element [39]. + + Precondition: the opening '<' is already read. +*/ +bool QXmlSimpleReader::parseElement() +{ + static QString uri, lname, prefix; + static bool t; + + const signed char Init = 0; + const signed char ReadName = 1; + const signed char Ws1 = 2; + const signed char STagEnd = 3; + const signed char STagEnd2 = 4; + const signed char ETagBegin = 5; + const signed char ETagBegin2 = 6; + const signed char Ws2 = 7; + const signed char EmptyTag = 8; + const signed char Attribute = 9; + const signed char Ws3 = 10; + const signed char Done = 11; + + const signed char InpWs = 0; // whitespace + const signed char InpNameBe = 1; // is_NameBeginning() + const signed char InpGt = 2; // > + const signed char InpSlash = 3; // / + const signed char InpUnknown = 4; + + // use some kind of state machine for parsing + static signed char table[11][5] = { + /* InpWs InpNameBe InpGt InpSlash InpUnknown */ + { -1, ReadName, -1, -1, -1 }, // Init + { Ws1, Attribute, STagEnd, EmptyTag, -1 }, // ReadName + { -1, Attribute, STagEnd, EmptyTag, -1 }, // Ws1 + { STagEnd2, STagEnd2, STagEnd2, STagEnd2, STagEnd2 }, // STagEnd + { -1, -1, -1, ETagBegin, -1 }, // STagEnd2 + { -1, ETagBegin2, -1, -1, -1 }, // ETagBegin + { Ws2, -1, Done, -1, -1 }, // ETagBegin2 + { -1, -1, Done, -1, -1 }, // Ws2 + { -1, -1, Done, -1, -1 }, // EmptyTag + { Ws3, Attribute, STagEnd, EmptyTag, -1 }, // Attribute + { -1, Attribute, STagEnd, EmptyTag, -1 } // Ws3 + }; + signed char state = Init; + signed char input; + bool parseOk = TRUE; + + while ( TRUE ) { + + // read input + if ( atEnd() ) { + d->error = XMLERR_UNEXPECTEDEOF; + goto parseError; + } + if ( is_S(c) ) { + input = InpWs; + } else if ( is_NameBeginning(c) ) { + input = InpNameBe; + } else if ( c == '>' ) { + input = InpGt; + } else if ( c == '/' ) { + input = InpSlash; + } else { + input = InpUnknown; + } + // get new state +//qDebug( "%d -%d(%c)-> %d", state, input, c.latin1(), table[state][input] ); + state = table[state][input]; + + // in some cases do special actions depending on state + switch ( state ) { + case ReadName: + parseOk = parseName(); + break; + case Ws1: + case Ws2: + case Ws3: + eat_ws(); + break; + case STagEnd: + // call the handler + if ( contentHnd ) { + if ( d->useNamespaces ) { + d->namespaceSupport.processName( tags.top(), FALSE, uri, lname ); + t = contentHnd->startElement( uri, lname, tags.top(), d->attList ); + } else { + t = contentHnd->startElement( "", "", tags.top(), d->attList ); + } + if ( !t ) { + d->error = contentHnd->errorString(); + goto parseError; + } + } + next(); + break; + case STagEnd2: + parseOk = parseContent(); + break; + case ETagBegin: + next(); + break; + case ETagBegin2: + // get the name of the tag + parseOk = parseName(); + break; + case EmptyTag: + if ( tags.isEmpty() ) { + d->error = XMLERR_TAGMISMATCH; + goto parseError; + } + if ( !parseElementEmptyTag( t, uri, lname ) ) + goto parseError; + // next character + next(); + break; + case Attribute: + // get name and value of attribute + parseOk = parseAttribute(); + break; + case Done: + next(); + break; + } + // no input is read after this + switch ( state ) { + case ReadName: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGNAME; + goto parseError; + } + // store it on the stack + tags.push( name() ); + // empty the attributes + d->attList.qnameList.clear(); + d->attList.uriList.clear(); + d->attList.localnameList.clear(); + d->attList.valueList.clear(); + // namespace support? + if ( d->useNamespaces ) { + d->namespaceSupport.pushContext(); + } + break; + case STagEnd2: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGCONTENT; + goto parseError; + } + break; + case ETagBegin2: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGNAME; + goto parseError; + } + if ( !parseElementETagBegin2( uri, lname ) ) + goto parseError; + break; + case Attribute: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGATTRIBUTE; + goto parseError; + } + if ( !parseElementAttribute( prefix, uri, lname ) ) + goto parseError; + break; + case Done: + return TRUE; + case -1: + d->error = XMLERR_ERRORPARSINGELEMENT; + goto parseError; + } + + } + + return TRUE; + +parseError: + reportParseError(); + return FALSE; +} +/*! + Helper to break down the size of the code in the case statement. + Return FALSE on error, otherwise TRUE. +*/ +bool QXmlSimpleReader::parseElementEmptyTag( bool &t, QString &uri, QString &lname ) +{ + // pop the stack and call the handler + if ( contentHnd ) { + // report startElement first... + if ( d->useNamespaces ) { + d->namespaceSupport.processName( tags.top(), FALSE, uri, lname ); + t = contentHnd->startElement( uri, lname, tags.top(), d->attList ); + } else { + t = contentHnd->startElement( "", "", tags.top(), d->attList ); + } + if ( !t ) { + d->error = contentHnd->errorString(); + return FALSE; + } + // ... followed by endElement + if ( d->useNamespaces ) { + if ( !contentHnd->endElement( uri, lname,tags.pop() ) ) { + d->error = contentHnd->errorString(); + return FALSE; + } + } + else { + if ( !contentHnd->endElement( "","",tags.pop() ) ) { + d->error = contentHnd->errorString(); + return FALSE; + } + } + // namespace support? + if ( d->useNamespaces ) { + QStringList prefixesBefore, prefixesAfter; + if ( contentHnd ) { + prefixesBefore = d->namespaceSupport.prefixes(); + } + d->namespaceSupport.popContext(); + // call the handler for prefix mapping + if ( contentHnd ) { + prefixesAfter = d->namespaceSupport.prefixes(); + for ( QStringList::Iterator it = prefixesBefore.begin(); it != prefixesBefore.end(); ++it ) { + if ( prefixesAfter.contains(*it) == 0 ) { + if ( !contentHnd->endPrefixMapping( *it ) ) { + d->error = contentHnd->errorString(); + return FALSE; + } + } + } + } + } + } else { + tags.pop(); + } + return TRUE; +} +/*! + Helper to break down the size of the code in the case statement. + Return FALSE on error, otherwise TRUE. +*/ +bool QXmlSimpleReader::parseElementETagBegin2( QString &uri, QString &lname ) +{ + + // pop the stack and compare it with the name + if ( tags.pop() != name() ) { + d->error = XMLERR_TAGMISMATCH; + return FALSE; + } + // call the handler + if ( contentHnd ) { + if ( d->useNamespaces ) { + d->namespaceSupport.processName( name(), FALSE, uri, lname ); + if ( !contentHnd->endElement(uri,lname,name()) ) { + d->error = contentHnd->errorString(); + return FALSE; + } + } + else { + if ( !contentHnd->endElement("","",name()) ) { + d->error = contentHnd->errorString(); + return FALSE; + } + } + } + // namespace support? + if ( d->useNamespaces ) { + QStringList prefixesBefore, prefixesAfter; + if ( contentHnd ) { + prefixesBefore = d->namespaceSupport.prefixes(); + } + d->namespaceSupport.popContext(); + // call the handler for prefix mapping + if ( contentHnd ) { + prefixesAfter = d->namespaceSupport.prefixes(); + for ( QStringList::Iterator it = prefixesBefore.begin(); it != prefixesBefore.end(); ++it ) { + if ( prefixesAfter.contains(*it) == 0 ) { + if ( !contentHnd->endPrefixMapping( *it ) ) { + d->error = contentHnd->errorString(); + return FALSE; + } + } + } + } + } + return TRUE; +} +/*! + Helper to break down the size of the code in the case statement. + Return FALSE on error, otherwise TRUE. +*/ +bool QXmlSimpleReader::parseElementAttribute( QString &prefix, QString &uri, QString &lname ) +{ + // add the attribute to the list + if ( d->useNamespaces ) { + // is it a namespace declaration? + d->namespaceSupport.splitName( name(), prefix, lname ); + if ( prefix == "xmlns" ) { + // namespace declaration + d->namespaceSupport.setPrefix( lname, string() ); + if ( d->useNamespacePrefixes ) { + d->attList.qnameList.append( name() ); + d->attList.uriList.append( "" ); + d->attList.localnameList.append( "" ); + d->attList.valueList.append( string() ); + } + // call the handler for prefix mapping + if ( contentHnd ) { + if ( !contentHnd->startPrefixMapping( lname, string() ) ) { + d->error = contentHnd->errorString(); + return FALSE; + } + } + } else { + // no namespace delcaration + d->namespaceSupport.processName( name(), TRUE, uri, lname ); + d->attList.qnameList.append( name() ); + d->attList.uriList.append( uri ); + d->attList.localnameList.append( lname ); + d->attList.valueList.append( string() ); + } + } else { + // no namespace support + d->attList.qnameList.append( name() ); + d->attList.uriList.append( "" ); + d->attList.localnameList.append( "" ); + d->attList.valueList.append( string() ); + } + return TRUE; +} + +/*! + Parse a content [43]. + + A content is only used between tags. If a end tag is found the < is already + read and the head stand on the '/' of the end tag '</name>'. +*/ +bool QXmlSimpleReader::parseContent() +{ + bool charDataRead = FALSE; + + const signed char Init = 0; + const signed char ChD = 1; // CharData + const signed char ChD1 = 2; // CharData help state + const signed char ChD2 = 3; // CharData help state + const signed char Ref = 4; // Reference + const signed char Lt = 5; // '<' read + const signed char PI = 6; // PI + const signed char Elem = 7; // Element + const signed char Em = 8; // '!' read + const signed char Com = 9; // Comment + const signed char CDS = 10; // CDSect + const signed char CDS1 = 11; // read a CDSect + const signed char CDS2 = 12; // read a CDSect (help state) + const signed char CDS3 = 13; // read a CDSect (help state) + const signed char Done = 14; // finished reading content + + const signed char InpLt = 0; // < + const signed char InpGt = 1; // > + const signed char InpSlash = 2; // / + const signed char InpQMark = 3; // ? + const signed char InpEMark = 4; // ! + const signed char InpAmp = 5; // & + const signed char InpDash = 6; // - + const signed char InpOpenB = 7; // [ + const signed char InpCloseB = 8; // ] + const signed char InpUnknown = 9; + + static signed char mapCLT2FSMChar[] = { + InpUnknown, // white space + InpUnknown, // % + InpAmp, // & + InpGt, // > + InpLt, // < + InpSlash, // / + InpQMark, // ? + InpEMark, // ! + InpDash, // - + InpCloseB, // ] + InpOpenB, // [ + InpUnknown, // = + InpUnknown, // " + InpUnknown, // ' + InpUnknown // unknown + }; + + // use some kind of state machine for parsing + static signed char const table[14][10] = { + /* InpLt InpGt InpSlash InpQMark InpEMark InpAmp InpDash InpOpenB InpCloseB InpUnknown */ + { Lt, ChD, ChD, ChD, ChD, Ref, ChD, ChD, ChD1, ChD }, // Init + { Lt, ChD, ChD, ChD, ChD, Ref, ChD, ChD, ChD1, ChD }, // ChD + { Lt, ChD, ChD, ChD, ChD, Ref, ChD, ChD, ChD2, ChD }, // ChD1 + { Lt, -1, ChD, ChD, ChD, Ref, ChD, ChD, ChD2, ChD }, // ChD2 + { Lt, ChD, ChD, ChD, ChD, Ref, ChD, ChD, ChD, ChD }, // Ref (same as Init) + { -1, -1, Done, PI, Em, -1, -1, -1, -1, Elem }, // Lt + { Lt, ChD, ChD, ChD, ChD, Ref, ChD, ChD, ChD, ChD }, // PI (same as Init) + { Lt, ChD, ChD, ChD, ChD, Ref, ChD, ChD, ChD, ChD }, // Elem (same as Init) + { -1, -1, -1, -1, -1, -1, Com, CDS, -1, -1 }, // Em + { Lt, ChD, ChD, ChD, ChD, Ref, ChD, ChD, ChD, ChD }, // Com (same as Init) + { CDS1, CDS1, CDS1, CDS1, CDS1, CDS1, CDS1, CDS1, CDS2, CDS1 }, // CDS + { CDS1, CDS1, CDS1, CDS1, CDS1, CDS1, CDS1, CDS1, CDS2, CDS1 }, // CDS1 + { CDS1, CDS1, CDS1, CDS1, CDS1, CDS1, CDS1, CDS1, CDS3, CDS1 }, // CDS2 + { CDS1, Init, CDS1, CDS1, CDS1, CDS1, CDS1, CDS1, CDS3, CDS1 } // CDS3 + }; + signed char state = Init; + signed char input; + bool parseOk = TRUE; + + while ( TRUE ) { + + // get input (use lookup-table instead of nested ifs for performance + // reasons) + if ( atEnd() ) { + d->error = XMLERR_UNEXPECTEDEOF; + goto parseError; + } + if ( c.row() ) { + input = InpUnknown; + } else { + input = mapCLT2FSMChar[ charLookupTable[ c.cell() ] ]; + } + + // set state according to input + state = table[state][input]; + + // do some actions according to state + switch ( state ) { + case Init: + // next character + next(); + break; + case ChD: + // on first call: clear string + if ( !charDataRead ) { + charDataRead = TRUE; + stringClear(); + } + stringAddC(); + next(); + break; + case ChD1: + // on first call: clear string + if ( !charDataRead ) { + charDataRead = TRUE; + stringClear(); + } + stringAddC(); + next(); + break; + case ChD2: + stringAddC(); + next(); + break; + case Ref: + if ( !charDataRead) { + // reference may be CharData; so clear string to be safe + stringClear(); + parseOk = parseReference( charDataRead, InContent ); + } else { + bool tmp; + parseOk = parseReference( tmp, InContent ); + } + break; + case Lt: + // call the handler for CharData + if ( contentHnd ) { + if ( charDataRead ) { + if ( d->reportWhitespaceCharData || !string().simplifyWhiteSpace().isEmpty() ) { + if ( !contentHnd->characters( string() ) ) { + d->error = contentHnd->errorString(); + goto parseError; + } + } + } + } + charDataRead = FALSE; + // next character + next(); + break; + case PI: + parseOk = parsePI(); + break; + case Elem: + parseOk = parseElement(); + break; + case Em: + // next character + next(); + break; + case Com: + parseOk = parseComment(); + break; + case CDS: + parseOk = parseString( "[CDATA[" ); + break; + case CDS1: + // read one character and add it + stringAddC(); + next(); + break; + case CDS2: + // skip ']' + next(); + break; + case CDS3: + // skip ']'... + next(); + break; + } + // no input is read after this + switch ( state ) { + case Ref: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGREFERENCE; + goto parseError; + } + break; + case PI: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGPI; + goto parseError; + } + // call the handler + if ( contentHnd ) { + if ( !contentHnd->processingInstruction(name(),string()) ) { + d->error = contentHnd->errorString(); + goto parseError; + } + } + break; + case Elem: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGELEMENT; + goto parseError; + } + break; + case Com: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGCOMMENT; + goto parseError; + } + if ( lexicalHnd ) { + if ( !lexicalHnd->comment( string() ) ) { + d->error = lexicalHnd->errorString(); + goto parseError; + } + } + break; + case CDS: + if( !parseOk ) { + d->error = XMLERR_CDSECTHEADEREXPECTED; + goto parseError; + } + // empty string + stringClear(); + break; + case CDS2: + if (c != ']') { + stringAddC( ']' ); + } + break; + case CDS3: + // test if this skipping was legal + if ( c == '>' ) { + // the end of the CDSect + if ( lexicalHnd ) { + if ( !lexicalHnd->startCDATA() ) { + d->error = lexicalHnd->errorString(); + goto parseError; + } + } + if ( contentHnd ) { + if ( !contentHnd->characters( string() ) ) { + d->error = contentHnd->errorString(); + goto parseError; + } + } + if ( lexicalHnd ) { + if ( !lexicalHnd->endCDATA() ) { + d->error = lexicalHnd->errorString(); + goto parseError; + } + } + } else if (c == ']') { + // three or more ']' + stringAddC( ']' ); + } else { + // after ']]' comes another character + stringAddC( ']' ); + stringAddC( ']' ); + } + break; + case Done: + // call the handler for CharData + if ( contentHnd ) { + if ( charDataRead ) { + if ( d->reportWhitespaceCharData || !string().simplifyWhiteSpace().isEmpty() ) { + if ( !contentHnd->characters( string() ) ) { + d->error = contentHnd->errorString(); + goto parseError; + } + } + } + } + // Done + return TRUE; + case -1: + // Error + d->error = XMLERR_ERRORPARSINGCONTENT; + goto parseError; + } + + } + + return TRUE; + +parseError: + reportParseError(); + return FALSE; +} + +/*! + Parse Misc [27]. +*/ +bool QXmlSimpleReader::parseMisc() +{ + const signed char Init = 0; + const signed char Lt = 1; // '<' was read + const signed char Comment = 2; // read comment + const signed char eatWS = 3; // eat whitespaces + const signed char PI = 4; // read PI + const signed char Comment2 = 5; // read comment + + const signed char InpWs = 0; // S + const signed char InpLt = 1; // < + const signed char InpQm = 2; // ? + const signed char InpEm = 3; // ! + const signed char InpUnknown = 4; + + // use some kind of state machine for parsing + static signed char table[3][5] = { + /* InpWs InpLt InpQm InpEm InpUnknown */ + { eatWS, Lt, -1, -1, -1 }, // Init + { -1, -1, PI, Comment, -1 }, // Lt + { -1, -1, -1, -1, Comment2 } // Comment + }; + signed char state = Init; + signed char input; + bool parseOk = TRUE; + + while ( TRUE ) { + + // get input + if ( atEnd() ) { + d->error = XMLERR_UNEXPECTEDEOF; + goto parseError; + } + if ( is_S(c) ) { + input = InpWs; + } else if ( c == '<' ) { + input = InpLt; + } else if ( c == '?' ) { + input = InpQm; + } else if ( c == '!' ) { + input = InpEm; + } else { + input = InpUnknown; + } + + // set state according to input + state = table[state][input]; + + // do some actions according to state + switch ( state ) { + case eatWS: + eat_ws(); + break; + case Lt: + next(); + break; + case PI: + parseOk = parsePI(); + break; + case Comment: + next(); + break; + case Comment2: + parseOk = parseComment(); + break; + } + // no input is read after this + switch ( state ) { + case eatWS: + return TRUE; + case PI: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGPI; + goto parseError; + } + if ( contentHnd ) { + if ( !contentHnd->processingInstruction(name(),string()) ) { + d->error = contentHnd->errorString(); + goto parseError; + } + } + return TRUE; + case Comment2: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGCOMMENT; + goto parseError; + } + if ( lexicalHnd ) { + if ( !lexicalHnd->comment( string() ) ) { + d->error = lexicalHnd->errorString(); + goto parseError; + } + } + return TRUE; + case -1: + // Error + d->error = XMLERR_UNEXPECTEDCHARACTER; + goto parseError; + } + + } + + return TRUE; + +parseError: + reportParseError(); + return FALSE; +} + +/*! + Parse a processing instruction [16]. + + If xmldec is TRUE, it tries to parse a PI or a XML declaration [23]. + + Precondition: the beginning '<' of the PI is already read and the head stand + on the '?' of '<?'. + + If this funktion was successful, the head-position is on the first + character after the PI. +*/ +bool QXmlSimpleReader::parsePI( bool xmldecl ) +{ + const signed char Init = 0; + const signed char QmI = 1; // ? was read + const signed char Name = 2; // read Name + const signed char XMLDecl = 3; // read XMLDecl + const signed char Ws1 = 4; // eat ws after "xml" of XMLDecl + const signed char PI = 5; // read PI + const signed char Ws2 = 6; // eat ws after Name of PI + const signed char Version = 7; // read versionInfo + const signed char Ws3 = 8; // eat ws after versionInfo + const signed char EorSD = 9; // read EDecl or SDDecl + const signed char Ws4 = 10; // eat ws after EDecl or SDDecl + const signed char SD = 11; // read SDDecl + const signed char Ws5 = 12; // eat ws after SDDecl + const signed char ADone = 13; // almost done + const signed char Char = 14; // Char was read + const signed char Qm = 15; // Qm was read + const signed char Done = 16; // finished reading content + + const signed char InpWs = 0; // whitespace + const signed char InpNameBe = 1; // is_nameBeginning() + const signed char InpGt = 2; // > + const signed char InpQm = 3; // ? + const signed char InpUnknown = 4; + + // use some kind of state machine for parsing + static signed char table[16][5] = { + /* InpWs, InpNameBe InpGt InpQm InpUnknown */ + { -1, -1, -1, QmI, -1 }, // Init + { -1, Name, -1, -1, -1 }, // QmI + { -1, -1, -1, -1, -1 }, // Name (this state is left not through input) + { Ws1, -1, -1, -1, -1 }, // XMLDecl + { -1, Version, -1, -1, -1 }, // Ws1 + { Ws2, -1, -1, Qm, -1 }, // PI + { Char, Char, Char, Qm, Char }, // Ws2 + { Ws3, -1, -1, ADone, -1 }, // Version + { -1, EorSD, -1, ADone, -1 }, // Ws3 + { Ws4, -1, -1, ADone, -1 }, // EorSD + { -1, SD, -1, ADone, -1 }, // Ws4 + { Ws5, -1, -1, ADone, -1 }, // SD + { -1, -1, -1, ADone, -1 }, // Ws5 + { -1, -1, Done, -1, -1 }, // ADone + { Char, Char, Char, Qm, Char }, // Char + { Char, Char, Done, Qm, Char }, // Qm + }; + signed char state = Init; + signed char input; + bool parseOk = TRUE; + + while ( TRUE ) { + + // get input + if ( atEnd() ) { + d->error = XMLERR_UNEXPECTEDEOF; + goto parseError; + } + if ( is_S(c) ) { + input = InpWs; + } else if ( is_NameBeginning(c) ) { + input = InpNameBe; + } else if ( c == '>' ) { + input = InpGt; + } else if ( c == '?' ) { + input = InpQm; + } else { + input = InpUnknown; + } + + // set state according to input + state = table[state][input]; + + // do some actions according to state + switch ( state ) { + case QmI: + next(); + break; + case Name: + parseOk = parseName(); + break; + case Ws1: + case Ws2: + case Ws3: + case Ws4: + case Ws5: + eat_ws(); + break; + case Version: + parseOk = parseAttribute(); + break; + case EorSD: + parseOk = parseAttribute(); + break; + case SD: + // get the SDDecl (syntax like an attribute) + if ( d->standalone != QXmlSimpleReaderPrivate::Unknown ) { + // already parsed the standalone declaration + d->error = XMLERR_UNEXPECTEDCHARACTER; + goto parseError; + } + parseOk = parseAttribute(); + break; + case ADone: + next(); + break; + case Char: + stringAddC(); + next(); + break; + case Qm: + // skip the '?' + next(); + break; + case Done: + next(); + break; + } + // no input is read after this + switch ( state ) { + case Name: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGNAME; + goto parseError; + } + // test what name was read and determine the next state + // (not very beautiful, I admit) + if ( name().lower() == "xml" ) { + if ( xmldecl && name()=="xml" ) { + state = XMLDecl; + } else { + d->error = XMLERR_INVALIDNAMEFORPI; + goto parseError; + } + } else { + state = PI; + stringClear(); + } + break; + case Version: + // get version (syntax like an attribute) + if ( !parseOk ) { + d->error = XMLERR_VERSIONEXPECTED; + goto parseError; + } + if ( name() != "version" ) { + d->error = XMLERR_VERSIONEXPECTED; + goto parseError; + } + d->xmlVersion = string(); + break; + case EorSD: + // get the EDecl or SDDecl (syntax like an attribute) + if ( !parseOk ) { + d->error = XMLERR_EDECLORSDDECLEXPECTED; + goto parseError; + } + if ( name() == "standalone" ) { + if ( string()=="yes" ) { + d->standalone = QXmlSimpleReaderPrivate::Yes; + } else if ( string()=="no" ) { + d->standalone = QXmlSimpleReaderPrivate::No; + } else { + d->error = XMLERR_WRONGVALUEFORSDECL; + goto parseError; + } + } else if ( name() == "encoding" ) { + d->encoding = string(); + } else { + d->error = XMLERR_EDECLORSDDECLEXPECTED; + goto parseError; + } + break; + case SD: + if ( !parseOk ) { + d->error = XMLERR_SDDECLEXPECTED; + goto parseError; + } + if ( name() != "standalone" ) { + d->error = XMLERR_SDDECLEXPECTED; + goto parseError; + } + if ( string()=="yes" ) { + d->standalone = QXmlSimpleReaderPrivate::Yes; + } else if ( string()=="no" ) { + d->standalone = QXmlSimpleReaderPrivate::No; + } else { + d->error = XMLERR_WRONGVALUEFORSDECL; + goto parseError; + } + break; + case Qm: + // test if the skipping was legal + if ( c != '>' ) { + stringAddC( '?' ); + } + break; + case Done: + return TRUE; + case -1: + // Error + d->error = XMLERR_UNEXPECTEDCHARACTER; + goto parseError; + } + + } + + return TRUE; + +parseError: + reportParseError(); + return FALSE; +} + +/*! + Parse a document type definition (doctypedecl [28]). + + Precondition: the beginning '<!' of the doctype is already read the head + stands on the 'D' of '<!DOCTYPE'. + + If this funktion was successful, the head-position is on the first + character after the document type definition. +*/ +bool QXmlSimpleReader::parseDoctype() +{ + // some init-stuff + d->systemId = QString::null; + d->publicId = QString::null; + + const signed char Init = 0; + const signed char Doctype = 1; // read the doctype + const signed char Ws1 = 2; // eat_ws + const signed char Doctype2 = 3; // read the doctype, part 2 + const signed char Ws2 = 4; // eat_ws + const signed char Sys = 5; // read SYSTEM + const signed char Ws3 = 6; // eat_ws + const signed char MP = 7; // markupdecl or PEReference + const signed char PER = 8; // PERReference + const signed char Mup = 9; // markupdecl + const signed char Ws4 = 10; // eat_ws + const signed char MPE = 11; // end of markupdecl or PEReference + const signed char Done = 12; + + const signed char InpWs = 0; + const signed char InpD = 1; // 'D' + const signed char InpS = 2; // 'S' or 'P' + const signed char InpOB = 3; // [ + const signed char InpCB = 4; // ] + const signed char InpPer = 5; // % + const signed char InpGt = 6; // > + const signed char InpUnknown = 7; + + // use some kind of state machine for parsing + static signed char table[12][8] = { + /* InpWs, InpD InpS InpOB InpCB InpPer InpGt InpUnknown */ + { -1, Doctype, -1, -1, -1, -1, -1, -1 }, // Init + { Ws1, Doctype2, Doctype2, -1, -1, -1, -1, Doctype2 }, // Doctype + { -1, Doctype2, Doctype2, -1, -1, -1, -1, Doctype2 }, // Ws1 + { Ws2, -1, Sys, MP, -1, -1, Done, -1 }, // Doctype2 + { -1, -1, Sys, MP, -1, -1, Done, -1 }, // Ws2 + { Ws3, -1, -1, MP, -1, -1, Done, -1 }, // Sys + { -1, -1, -1, MP, -1, -1, Done, -1 }, // Ws3 + { -1, -1, -1, -1, MPE, PER, -1, Mup }, // MP + { Ws4, -1, -1, -1, MPE, PER, -1, Mup }, // PER + { Ws4, -1, -1, -1, MPE, PER, -1, Mup }, // Mup + { -1, -1, -1, -1, MPE, PER, -1, Mup }, // Ws4 + { -1, -1, -1, -1, -1, -1, Done, -1 } // MPE + }; + signed char state = Init; + signed char input; + bool parseOk = TRUE; + + while ( TRUE ) { + + // get input + if ( atEnd() ) { + d->error = XMLERR_UNEXPECTEDEOF; + goto parseError; + } + if ( is_S(c) ) { + input = InpWs; + } else if ( c == 'D' ) { + input = InpD; + } else if ( c == 'S' ) { + input = InpS; + } else if ( c == 'P' ) { + input = InpS; + } else if ( c == '[' ) { + input = InpOB; + } else if ( c == ']' ) { + input = InpCB; + } else if ( c == '%' ) { + input = InpPer; + } else if ( c == '>' ) { + input = InpGt; + } else { + input = InpUnknown; + } + + // set state according to input + state = table[state][input]; + + // do some actions according to state + switch ( state ) { + case Doctype: + parseOk = parseString( "DOCTYPE" ); + break; + case Ws1: + case Ws2: + case Ws3: + case Ws4: + eat_ws(); + break; + case Doctype2: + parseName(); + break; + case Sys: + parseOk = parseExternalID(); + break; + case MP: + next_eat_ws(); + break; + case PER: + parseOk = parsePEReference( InDTD ); + break; + case Mup: + parseOk = parseMarkupdecl(); + break; + case MPE: + next_eat_ws(); + break; + case Done: + if ( lexicalHnd ) { + if ( !lexicalHnd->endDTD() ) { + d->error = lexicalHnd->errorString(); + goto parseError; + } + } + next(); + break; + } + // no input is read after this + switch ( state ) { + case Doctype: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGDOCTYPE; + goto parseError; + } + if ( !is_S(c) ) { + d->error = XMLERR_ERRORPARSINGDOCTYPE; + goto parseError; + } + break; + case Doctype2: + d->doctype = name(); + if ( lexicalHnd ) { + if ( !lexicalHnd->startDTD( d->doctype, d->publicId, d->systemId ) ) { + d->error = lexicalHnd->errorString(); + goto parseError; + } + } + break; + case Sys: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGDOCTYPE; + goto parseError; + } + break; + case PER: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGDOCTYPE; + goto parseError; + } + break; + case Mup: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGDOCTYPE; + goto parseError; + } + break; + case Done: + return TRUE; + case -1: + // Error + d->error = XMLERR_ERRORPARSINGDOCTYPE; + goto parseError; + } + + } + + return TRUE; + +parseError: + reportParseError(); + return FALSE; +} + +/*! + Parse a ExternalID [75]. + + If allowPublicID is TRUE parse ExternalID [75] or PublicID [83]. +*/ +bool QXmlSimpleReader::parseExternalID( bool allowPublicID ) +{ + // some init-stuff + d->systemId = QString::null; + d->publicId = QString::null; + + const signed char Init = 0; + const signed char Sys = 1; // parse 'SYSTEM' + const signed char SysWS = 2; // parse the whitespace after 'SYSTEM' + const signed char SysSQ = 3; // parse SystemLiteral with ' + const signed char SysSQ2 = 4; // parse SystemLiteral with ' + const signed char SysDQ = 5; // parse SystemLiteral with " + const signed char SysDQ2 = 6; // parse SystemLiteral with " + const signed char Pub = 7; // parse 'PUBLIC' + const signed char PubWS = 8; // parse the whitespace after 'PUBLIC' + const signed char PubSQ = 9; // parse PubidLiteral with ' + const signed char PubSQ2 = 10; // parse PubidLiteral with ' + const signed char PubDQ = 11; // parse PubidLiteral with " + const signed char PubDQ2 = 12; // parse PubidLiteral with " + const signed char PubE = 13; // finished parsing the PubidLiteral + const signed char PubWS2 = 14; // parse the whitespace after the PubidLiteral + const signed char PDone = 15; // done if allowPublicID is TRUE + const signed char Done = 16; + + const signed char InpSQ = 0; // ' + const signed char InpDQ = 1; // " + const signed char InpS = 2; // S + const signed char InpP = 3; // P + const signed char InpWs = 4; // white space + const signed char InpUnknown = 5; + + // use some kind of state machine for parsing + static signed char table[15][6] = { + /* InpSQ InpDQ InpS InpP InpWs InpUnknown */ + { -1, -1, Sys, Pub, -1, -1 }, // Init + { -1, -1, -1, -1, SysWS, -1 }, // Sys + { SysSQ, SysDQ, -1, -1, -1, -1 }, // SysWS + { Done, SysSQ2, SysSQ2, SysSQ2, SysSQ2, SysSQ2 }, // SysSQ + { Done, SysSQ2, SysSQ2, SysSQ2, SysSQ2, SysSQ2 }, // SysSQ2 + { SysDQ2, Done, SysDQ2, SysDQ2, SysDQ2, SysDQ2 }, // SysDQ + { SysDQ2, Done, SysDQ2, SysDQ2, SysDQ2, SysDQ2 }, // SysDQ2 + { -1, -1, -1, -1, PubWS, -1 }, // Pub + { PubSQ, PubDQ, -1, -1, -1, -1 }, // PubWS + { PubE, -1, PubSQ2, PubSQ2, PubSQ2, PubSQ2 }, // PubSQ + { PubE, -1, PubSQ2, PubSQ2, PubSQ2, PubSQ2 }, // PubSQ2 + { -1, PubE, PubDQ2, PubDQ2, PubDQ2, PubDQ2 }, // PubDQ + { -1, PubE, PubDQ2, PubDQ2, PubDQ2, PubDQ2 }, // PubDQ2 + { PDone, PDone, PDone, PDone, PubWS2, PDone }, // PubE + { SysSQ, SysDQ, PDone, PDone, PDone, PDone } // PubWS2 + }; + signed char state = Init; + signed char input; + bool parseOk = TRUE; + + while ( TRUE ) { + + // get input + if ( atEnd() ) { + d->error = XMLERR_UNEXPECTEDEOF; + goto parseError; + } + if ( is_S(c) ) { + input = InpWs; + } else if ( c == '\'' ) { + input = InpSQ; + } else if ( c == '"' ) { + input = InpDQ; + } else if ( c == 'S' ) { + input = InpS; + } else if ( c == 'P' ) { + input = InpP; + } else { + input = InpUnknown; + } + + // set state according to input + state = table[state][input]; + + // do some actions according to state + switch ( state ) { + case Sys: + parseOk = parseString( "SYSTEM" ); + break; + case SysWS: + eat_ws(); + break; + case SysSQ: + case SysDQ: + stringClear(); + next(); + break; + case SysSQ2: + case SysDQ2: + stringAddC(); + next(); + break; + case Pub: + parseOk = parseString( "PUBLIC" ); + break; + case PubWS: + eat_ws(); + break; + case PubSQ: + case PubDQ: + stringClear(); + next(); + break; + case PubSQ2: + case PubDQ2: + stringAddC(); + next(); + break; + case PubE: + next(); + break; + case PubWS2: + d->publicId = string(); + eat_ws(); + break; + case Done: + d->systemId = string(); + next(); + break; + } + // no input is read after this + switch ( state ) { + case Sys: + if( !parseOk ) { + d->error = XMLERR_UNEXPECTEDCHARACTER; + goto parseError; + } + break; + case Pub: + if( !parseOk ) { + d->error = XMLERR_UNEXPECTEDCHARACTER; + goto parseError; + } + break; + case PDone: + if ( allowPublicID ) { + d->publicId = string(); + return TRUE; + } else { + d->error = XMLERR_UNEXPECTEDCHARACTER; + goto parseError; + } + break; + case Done: + return TRUE; + case -1: + // Error + d->error = XMLERR_UNEXPECTEDCHARACTER; + goto parseError; + } + + } + + return TRUE; + +parseError: + reportParseError(); + return FALSE; +} + +/*! + Parse a markupdecl [29]. +*/ +bool QXmlSimpleReader::parseMarkupdecl() +{ + const signed char Init = 0; + const signed char Lt = 1; // < was read + const signed char Em = 2; // ! was read + const signed char CE = 3; // E was read + const signed char Qm = 4; // ? was read + const signed char Dash = 5; // - was read + const signed char CA = 6; // A was read + const signed char CEL = 7; // EL was read + const signed char CEN = 8; // EN was read + const signed char CN = 9; // N was read + const signed char Done = 10; + + const signed char InpLt = 0; // < + const signed char InpQm = 1; // ? + const signed char InpEm = 2; // ! + const signed char InpDash = 3; // - + const signed char InpA = 4; // A + const signed char InpE = 5; // E + const signed char InpL = 6; // L + const signed char InpN = 7; // N + const signed char InpUnknown = 8; + + // use some kind of state machine for parsing + static signed char table[4][9] = { + /* InpLt InpQm InpEm InpDash InpA InpE InpL InpN InpUnknown */ + { Lt, -1, -1, -1, -1, -1, -1, -1, -1 }, // Init + { -1, Qm, Em, -1, -1, -1, -1, -1, -1 }, // Lt + { -1, -1, -1, Dash, CA, CE, -1, CN, -1 }, // Em + { -1, -1, -1, -1, -1, -1, CEL, CEN, -1 } // CE + }; + signed char state = Init; + signed char input; + bool parseOk = TRUE; + + while ( TRUE ) { + + // get input + if ( atEnd() ) { + d->error = XMLERR_UNEXPECTEDEOF; + goto parseError; + } + if ( c == '<' ) { + input = InpLt; + } else if ( c == '?' ) { + input = InpQm; + } else if ( c == '!' ) { + input = InpEm; + } else if ( c == '-' ) { + input = InpDash; + } else if ( c == 'A' ) { + input = InpA; + } else if ( c == 'E' ) { + input = InpE; + } else if ( c == 'L' ) { + input = InpL; + } else if ( c == 'N' ) { + input = InpN; + } else { + input = InpUnknown; + } + + // set state according to input + state = table[state][input]; + + // do some actions according to state + switch ( state ) { + case Lt: + next(); + break; + case Em: + next(); + break; + case CE: + next(); + break; + case Qm: + parseOk = parsePI(); + break; + case Dash: + parseOk = parseComment(); + break; + case CA: + parseOk = parseAttlistDecl(); + break; + case CEL: + parseOk = parseElementDecl(); + break; + case CEN: + parseOk = parseEntityDecl(); + break; + case CN: + parseOk = parseNotationDecl(); + break; + } + // no input is read after this + switch ( state ) { + case Qm: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGPI; + goto parseError; + } + if ( contentHnd ) { + if ( !contentHnd->processingInstruction(name(),string()) ) { + d->error = contentHnd->errorString(); + goto parseError; + } + } + return TRUE; + case Dash: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGCOMMENT; + goto parseError; + } + if ( lexicalHnd ) { + if ( !lexicalHnd->comment( string() ) ) { + d->error = lexicalHnd->errorString(); + goto parseError; + } + } + return TRUE; + case CA: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGATTLISTDECL; + goto parseError; + } + return TRUE; + case CEL: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGELEMENTDECL; + goto parseError; + } + return TRUE; + case CEN: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGENTITYDECL; + goto parseError; + } + return TRUE; + case CN: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGNOTATIONDECL; + goto parseError; + } + return TRUE; + case Done: + return TRUE; + case -1: + // Error + d->error = XMLERR_LETTEREXPECTED; + goto parseError; + } + + } + + return TRUE; + +parseError: + reportParseError(); + return FALSE; +} + +/*! + Parse a PEReference [69] +*/ +bool QXmlSimpleReader::parsePEReference( EntityRecognitionContext context ) +{ + const signed char Init = 0; + const signed char Next = 1; + const signed char Name = 2; + const signed char Done = 3; + + const signed char InpSemi = 0; // ; + const signed char InpPer = 1; // % + const signed char InpUnknown = 2; + + // use some kind of state machine for parsing + static signed char table[3][3] = { + /* InpSemi InpPer InpUnknown */ + { -1, Next, -1 }, // Init + { -1, -1, Name }, // Next + { Done, -1, -1 } // Name + }; + signed char state = Init; + signed char input; + bool parseOk = TRUE; + + while ( TRUE ) { + + // get input + if ( atEnd() ) { + d->error = XMLERR_UNEXPECTEDEOF; + goto parseError; + } + if ( c == ';' ) { + input = InpSemi; + } else if ( c == '%' ) { + input = InpPer; + } else { + input = InpUnknown; + } + + // set state according to input + state = table[state][input]; + + // do some actions according to state + switch ( state ) { + case Next: + next(); + break; + case Name: + parseOk = parseName( TRUE ); + break; + case Done: + next(); + break; + } + // no input is read after this + switch ( state ) { + case Name: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGNAME; + goto parseError; + } + if ( d->parameterEntities.find( ref() ) == d->parameterEntities.end() ) { + // ### skip it??? + if ( contentHnd ) { + if ( !contentHnd->skippedEntity( QString("%") + ref() ) ) { + d->error = contentHnd->errorString(); + goto parseError; + } + } + } else { + if ( context == InEntityValue ) { + // Included in literal + xmlRef = d->parameterEntities.find( ref() ) + .data().replace( QRegExp("\""), """ ).replace( QRegExp("'"), "'" ) + + xmlRef; + } else if ( context == InDTD ) { + // Included as PE + xmlRef = QString(" ") + + d->parameterEntities.find( ref() ).data() + + QString(" ") + xmlRef; + } + } + break; + case Done: + return TRUE; + case -1: + // Error + d->error = XMLERR_LETTEREXPECTED; + goto parseError; + } + + } + + return TRUE; + +parseError: + reportParseError(); + return FALSE; +} + +/*! + Parse a AttlistDecl [52]. + + Precondition: the beginning '<!' is already read and the head + stands on the 'A' of '<!ATTLIST' +*/ +bool QXmlSimpleReader::parseAttlistDecl() +{ + const signed char Init = 0; + const signed char Attlist = 1; // parse the string "ATTLIST" + const signed char Ws = 2; // whitespace read + const signed char Name = 3; // parse name + const signed char Ws1 = 4; // whitespace read + const signed char Attdef = 5; // parse the AttDef + const signed char Ws2 = 6; // whitespace read + const signed char Atttype = 7; // parse the AttType + const signed char Ws3 = 8; // whitespace read + const signed char DDecH = 9; // DefaultDecl with # + const signed char DefReq = 10; // parse the string "REQUIRED" + const signed char DefImp = 11; // parse the string "IMPLIED" + const signed char DefFix = 12; // parse the string "FIXED" + const signed char Attval = 13; // parse the AttValue + const signed char Ws4 = 14; // whitespace read + const signed char Done = 15; + + const signed char InpWs = 0; // white space + const signed char InpGt = 1; // > + const signed char InpHash = 2; // # + const signed char InpA = 3; // A + const signed char InpI = 4; // I + const signed char InpF = 5; // F + const signed char InpR = 6; // R + const signed char InpUnknown = 7; + + // use some kind of state machine for parsing + static signed char table[15][8] = { + /* InpWs InpGt InpHash InpA InpI InpF InpR InpUnknown */ + { -1, -1, -1, Attlist, -1, -1, -1, -1 }, // Init + { Ws, -1, -1, -1, -1, -1, -1, -1 }, // Attlist + { -1, -1, -1, Name, Name, Name, Name, Name }, // Ws + { Ws1, Done, Attdef, Attdef, Attdef, Attdef, Attdef, Attdef }, // Name + { -1, Done, Attdef, Attdef, Attdef, Attdef, Attdef, Attdef }, // Ws1 + { Ws2, -1, -1, -1, -1, -1, -1, -1 }, // Attdef + { -1, Atttype, Atttype, Atttype, Atttype, Atttype, Atttype, Atttype }, // Ws2 + { Ws3, -1, -1, -1, -1, -1, -1, -1 }, // Attype + { -1, Attval, DDecH, Attval, Attval, Attval, Attval, Attval }, // Ws3 + { -1, -1, -1, -1, DefImp, DefFix, DefReq, -1 }, // DDecH + { Ws4, Ws4, -1, -1, -1, -1, -1, -1 }, // DefReq + { Ws4, Ws4, -1, -1, -1, -1, -1, -1 }, // DefImp + { Ws3, -1, -1, -1, -1, -1, -1, -1 }, // DefFix + { Ws4, Ws4, -1, -1, -1, -1, -1, -1 }, // Attval + { -1, Done, Attdef, Attdef, Attdef, Attdef, Attdef, Attdef } // Ws4 + }; + signed char state = Init; + signed char input; + bool parseOk = TRUE; + + while ( TRUE ) { + + // get input + if ( atEnd() ) { + d->error = XMLERR_UNEXPECTEDEOF; + goto parseError; + } + if ( is_S(c) ) { + input = InpWs; + } else if ( c == '>' ) { + input = InpGt; + } else if ( c == '#' ) { + input = InpHash; + } else if ( c == 'A' ) { + input = InpA; + } else if ( c == 'I' ) { + input = InpI; + } else if ( c == 'F' ) { + input = InpF; + } else if ( c == 'R' ) { + input = InpR; + } else { + input = InpUnknown; + } + + // set state according to input + state = table[state][input]; + + // do some actions according to state + switch ( state ) { + case Attlist: + parseOk = parseString( "ATTLIST" ); + break; + case Ws: + case Ws1: + case Ws2: + case Ws3: + eat_ws(); + break; + case Name: + parseOk = parseName(); + break; + case Attdef: + parseOk = parseName(); + break; + case Atttype: + parseOk = parseAttType(); + break; + case DDecH: + next(); + break; + case DefReq: + parseOk = parseString( "REQUIRED" ); + break; + case DefImp: + parseOk = parseString( "IMPLIED" ); + break; + case DefFix: + parseOk = parseString( "FIXED" ); + break; + case Attval: + parseOk = parseAttValue(); + break; + case Ws4: + if ( declHnd ) { + // TODO: not all values are computed yet... + if ( !declHnd->attributeDecl( d->attDeclEName, d->attDeclAName, "", "", "" ) ) { + d->error = declHnd->errorString(); + goto parseError; + } + } + eat_ws(); + break; + case Done: + next(); + break; + } + // no input is read after this + switch ( state ) { + case Attlist: + if( !parseOk ) { + d->error = XMLERR_UNEXPECTEDCHARACTER; + goto parseError; + } + break; + case Name: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGNAME; + goto parseError; + } + d->attDeclEName = name(); + break; + case Attdef: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGNAME; + goto parseError; + } + d->attDeclAName = name(); + break; + case Atttype: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGATTTYPE; + goto parseError; + } + break; + case DefReq: + if( !parseOk ) { + d->error = XMLERR_UNEXPECTEDCHARACTER; + goto parseError; + } + break; + case DefImp: + if( !parseOk ) { + d->error = XMLERR_UNEXPECTEDCHARACTER; + goto parseError; + } + break; + case DefFix: + if( !parseOk ) { + d->error = XMLERR_UNEXPECTEDCHARACTER; + goto parseError; + } + break; + case Attval: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGATTVALUE; + goto parseError; + } + break; + case Done: + return TRUE; + case -1: + // Error + d->error = XMLERR_LETTEREXPECTED; + goto parseError; + } + + } + + return TRUE; + +parseError: + reportParseError(); + return FALSE; +} + +/*! + Parse a AttType [54] +*/ +bool QXmlSimpleReader::parseAttType() +{ + const signed char Init = 0; + const signed char ST = 1; // StringType + const signed char TTI = 2; // TokenizedType starting with 'I' + const signed char TTI2 = 3; // TokenizedType helpstate + const signed char TTI3 = 4; // TokenizedType helpstate + const signed char TTE = 5; // TokenizedType starting with 'E' + const signed char TTEY = 6; // TokenizedType starting with 'ENTITY' + const signed char TTEI = 7; // TokenizedType starting with 'ENTITI' + const signed char N = 8; // N read (TokenizedType or Notation) + const signed char TTNM = 9; // TokenizedType starting with 'NM' + const signed char TTNM2 = 10; // TokenizedType helpstate + const signed char NO = 11; // Notation + const signed char NO2 = 12; // Notation helpstate + const signed char NO3 = 13; // Notation helpstate + const signed char NOName = 14; // Notation, read name + const signed char NO4 = 15; // Notation helpstate + const signed char EN = 16; // Enumeration + const signed char ENNmt = 17; // Enumeration, read Nmtoken + const signed char EN2 = 18; // Enumeration helpstate + const signed char ADone = 19; // almost done (make next and accept) + const signed char Done = 20; + + const signed char InpWs = 0; // whitespace + const signed char InpOp = 1; // ( + const signed char InpCp = 2; // ) + const signed char InpPipe = 3; // | + const signed char InpC = 4; // C + const signed char InpE = 5; // E + const signed char InpI = 6; // I + const signed char InpM = 7; // M + const signed char InpN = 8; // N + const signed char InpO = 9; // O + const signed char InpR = 10; // R + const signed char InpS = 11; // S + const signed char InpY = 12; // Y + const signed char InpUnknown = 13; + + // use some kind of state machine for parsing + static signed char table[19][14] = { + /* InpWs InpOp InpCp InpPipe InpC InpE InpI InpM InpN InpO InpR InpS InpY InpUnknown */ + { -1, EN, -1, -1, ST, TTE, TTI, -1, N, -1, -1, -1, -1, -1 }, // Init + { Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done }, // ST + { Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, TTI2, Done, Done, Done }, // TTI + { Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, TTI3, Done, Done }, // TTI2 + { Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done }, // TTI3 + { -1, -1, -1, -1, -1, -1, TTEI, -1, -1, -1, -1, -1, TTEY, -1 }, // TTE + { Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done }, // TTEY + { Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done }, // TTEI + { -1, -1, -1, -1, -1, -1, -1, TTNM, -1, NO, -1, -1, -1, -1 }, // N + { Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, TTNM2, Done, Done }, // TTNM + { Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done }, // TTNM2 + { NO2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, // NO + { -1, NO3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, // NO2 + { NOName, NOName, NOName, NOName, NOName, NOName, NOName, NOName, NOName, NOName, NOName, NOName, NOName, NOName }, // NO3 + { NO4, -1, ADone, NO3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, // NOName + { -1, -1, ADone, NO3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, // NO4 + { -1, -1, ENNmt, -1, ENNmt, ENNmt, ENNmt, ENNmt, ENNmt, ENNmt, ENNmt, ENNmt, ENNmt, ENNmt }, // EN + { EN2, -1, ADone, EN, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, // ENNmt + { -1, -1, ADone, EN, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 } // EN2 + }; + signed char state = Init; + signed char input; + bool parseOk = TRUE; + + while ( TRUE ) { + + // get input + if ( atEnd() ) { + d->error = XMLERR_UNEXPECTEDEOF; + goto parseError; + } + if ( is_S(c) ) { + input = InpWs; + } else if ( c == '(' ) { + input = InpOp; + } else if ( c == ')' ) { + input = InpCp; + } else if ( c == '|' ) { + input = InpPipe; + } else if ( c == 'C' ) { + input = InpC; + } else if ( c == 'E' ) { + input = InpE; + } else if ( c == 'I' ) { + input = InpI; + } else if ( c == 'M' ) { + input = InpM; + } else if ( c == 'N' ) { + input = InpN; + } else if ( c == 'O' ) { + input = InpO; + } else if ( c == 'R' ) { + input = InpR; + } else if ( c == 'S' ) { + input = InpS; + } else if ( c == 'Y' ) { + input = InpY; + } else { + input = InpUnknown; + } + + // set state according to input + state = table[state][input]; + + // do some actions according to state + switch ( state ) { + case ST: + parseOk = parseString( "CDATA" ); + break; + case TTI: + parseOk = parseString( "ID" ); + break; + case TTI2: + parseOk = parseString( "REF" ); + break; + case TTI3: + next(); // S + break; + case TTE: + parseOk = parseString( "ENTIT" ); + break; + case TTEY: + next(); // Y + break; + case TTEI: + parseOk = parseString( "IES" ); + break; + case N: + next(); // N + break; + case TTNM: + parseOk = parseString( "MTOKEN" ); + break; + case TTNM2: + next(); // S + break; + case NO: + parseOk = parseString( "OTATION" ); + break; + case NO2: + eat_ws(); + break; + case NO3: + next_eat_ws(); + break; + case NOName: + parseOk = parseName(); + break; + case NO4: + eat_ws(); + break; + case EN: + next_eat_ws(); + break; + case ENNmt: + parseOk = parseNmtoken(); + break; + case EN2: + eat_ws(); + break; + case ADone: + next(); + break; + } + // no input is read after this + switch ( state ) { + case ST: + if( !parseOk ) { + d->error = XMLERR_UNEXPECTEDCHARACTER; + goto parseError; + } + break; + case TTI: + if( !parseOk ) { + d->error = XMLERR_UNEXPECTEDCHARACTER; + goto parseError; + } + break; + case TTI2: + if( !parseOk ) { + d->error = XMLERR_UNEXPECTEDCHARACTER; + goto parseError; + } + break; + case TTE: + if( !parseOk ) { + d->error = XMLERR_UNEXPECTEDCHARACTER; + goto parseError; + } + break; + case TTEI: + if( !parseOk ) { + d->error = XMLERR_UNEXPECTEDCHARACTER; + goto parseError; + } + break; + case TTNM: + if( !parseOk ) { + d->error = XMLERR_UNEXPECTEDCHARACTER; + goto parseError; + } + break; + case NO: + if( !parseOk ) { + d->error = XMLERR_UNEXPECTEDCHARACTER; + goto parseError; + } + break; + case NOName: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGNAME; + goto parseError; + } + break; + case ENNmt: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGNMTOKEN; + goto parseError; + } + break; + case ADone: + return TRUE; + case Done: + return TRUE; + case -1: + // Error + d->error = XMLERR_LETTEREXPECTED; + goto parseError; + } + + } + + return TRUE; + +parseError: + reportParseError(); + return FALSE; +} + +/*! + Parse a AttValue [10] + + Precondition: the head stands on the beginning " or ' + + If this function was successful, the head stands on the first + character after the closing " or ' and the value of the attribute + is in string(). +*/ +bool QXmlSimpleReader::parseAttValue() +{ + bool tmp; + + const signed char Init = 0; + const signed char Dq = 1; // double quotes were read + const signed char DqRef = 2; // read references in double quotes + const signed char DqC = 3; // signed character read in double quotes + const signed char Sq = 4; // single quotes were read + const signed char SqRef = 5; // read references in single quotes + const signed char SqC = 6; // signed character read in single quotes + const signed char Done = 7; + + const signed char InpDq = 0; // " + const signed char InpSq = 1; // ' + const signed char InpAmp = 2; // & + const signed char InpLt = 3; // < + const signed char InpUnknown = 4; + + // use some kind of state machine for parsing + static signed char table[7][5] = { + /* InpDq InpSq InpAmp InpLt InpUnknown */ + { Dq, Sq, -1, -1, -1 }, // Init + { Done, DqC, DqRef, -1, DqC }, // Dq + { Done, DqC, DqRef, -1, DqC }, // DqRef + { Done, DqC, DqRef, -1, DqC }, // DqC + { SqC, Done, SqRef, -1, SqC }, // Sq + { SqC, Done, SqRef, -1, SqC }, // SqRef + { SqC, Done, SqRef, -1, SqC } // SqRef + }; + signed char state = Init; + signed char input; + bool parseOk = TRUE; + + while ( TRUE ) { + + // get input + if ( atEnd() ) { + d->error = XMLERR_UNEXPECTEDEOF; + goto parseError; + } + if ( c == '"' ) { + input = InpDq; + } else if ( c == '\'' ) { + input = InpSq; + } else if ( c == '&' ) { + input = InpAmp; + } else if ( c == '<' ) { + input = InpLt; + } else { + input = InpUnknown; + } + + // set state according to input + state = table[state][input]; + + // do some actions according to state + switch ( state ) { + case Dq: + case Sq: + stringClear(); + next(); + break; + case DqRef: + case SqRef: + parseOk = parseReference( tmp, InAttributeValue ); + break; + case DqC: + case SqC: + stringAddC(); + next(); + break; + case Done: + next(); + break; + } + // no input is read after this + switch ( state ) { + case DqRef: + case SqRef: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGREFERENCE; + goto parseError; + } + break; + case Done: + return TRUE; + case -1: + // Error + d->error = XMLERR_UNEXPECTEDCHARACTER; + goto parseError; + } + + } + + return TRUE; + +parseError: + reportParseError(); + return FALSE; +} + +/*! + Parse a elementdecl [45]. + + Precondition: the beginning '<!E' is already read and the head + stands on the 'L' of '<!ELEMENT' +*/ +bool QXmlSimpleReader::parseElementDecl() +{ + const signed char Init = 0; + const signed char Elem = 1; // parse the beginning string + const signed char Ws1 = 2; // whitespace required + const signed char Nam = 3; // parse Name + const signed char Ws2 = 4; // whitespace required + const signed char Empty = 5; // read EMPTY + const signed char Any = 6; // read ANY + const signed char Cont = 7; // read contentspec (except ANY or EMPTY) + const signed char Mix = 8; // read Mixed + const signed char Mix2 = 9; // + const signed char Mix3 = 10; // + const signed char MixN1 = 11; // + const signed char MixN2 = 12; // + const signed char MixN3 = 13; // + const signed char MixN4 = 14; // + const signed char Cp = 15; // parse cp + const signed char Cp2 = 16; // + const signed char WsD = 17; // eat whitespace before Done + const signed char Done = 18; + + const signed char InpWs = 0; + const signed char InpGt = 1; // > + const signed char InpPipe = 2; // | + const signed char InpOp = 3; // ( + const signed char InpCp = 4; // ) + const signed char InpHash = 5; // # + const signed char InpQm = 6; // ? + const signed char InpAst = 7; // * + const signed char InpPlus = 8; // + + const signed char InpA = 9; // A + const signed char InpE = 10; // E + const signed char InpL = 11; // L + const signed char InpUnknown = 12; + + // use some kind of state machine for parsing + static signed char table[18][13] = { + /* InpWs InpGt InpPipe InpOp InpCp InpHash InpQm InpAst InpPlus InpA InpE InpL InpUnknown */ + { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, Elem, -1 }, // Init + { Ws1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, // Elem + { -1, -1, -1, -1, -1, -1, -1, -1, -1, Nam, Nam, Nam, Nam }, // Ws1 + { Ws2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, // Nam + { -1, -1, -1, Cont, -1, -1, -1, -1, -1, Any, Empty, -1, -1 }, // Ws2 + { WsD, Done, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, // Empty + { WsD, Done, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, // Any + { -1, -1, -1, Cp, Cp, Mix, -1, -1, -1, Cp, Cp, Cp, Cp }, // Cont + { Mix2, -1, MixN1, -1, Mix3, -1, -1, -1, -1, -1, -1, -1, -1 }, // Mix + { -1, -1, MixN1, -1, Mix3, -1, -1, -1, -1, -1, -1, -1, -1 }, // Mix2 + { WsD, Done, -1, -1, -1, -1, -1, WsD, -1, -1, -1, -1, -1 }, // Mix3 + { -1, -1, -1, -1, -1, -1, -1, -1, -1, MixN2, MixN2, MixN2, MixN2 }, // MixN1 + { MixN3, -1, MixN1, -1, MixN4, -1, -1, -1, -1, -1, -1, -1, -1 }, // MixN2 + { -1, -1, MixN1, -1, MixN4, -1, -1, -1, -1, -1, -1, -1, -1 }, // MixN3 + { -1, -1, -1, -1, -1, -1, -1, WsD, -1, -1, -1, -1, -1 }, // MixN4 + { WsD, Done, -1, -1, -1, -1, Cp2, Cp2, Cp2, -1, -1, -1, -1 }, // Cp + { WsD, Done, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, // Cp2 + { -1, Done, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 } // WsD + }; + signed char state = Init; + signed char input; + bool parseOk = TRUE; + + while ( TRUE ) { + + // read input + if ( atEnd() ) { + d->error = XMLERR_UNEXPECTEDEOF; + goto parseError; + } + if ( is_S(c) ) { + input = InpWs; + } else if ( c == '>' ) { + input = InpGt; + } else if ( c == '|' ) { + input = InpPipe; + } else if ( c == '(' ) { + input = InpOp; + } else if ( c == ')' ) { + input = InpCp; + } else if ( c == '#' ) { + input = InpHash; + } else if ( c == '?' ) { + input = InpQm; + } else if ( c == '*' ) { + input = InpAst; + } else if ( c == '+' ) { + input = InpPlus; + } else if ( c == 'A' ) { + input = InpA; + } else if ( c == 'E' ) { + input = InpE; + } else if ( c == 'L' ) { + input = InpL; + } else { + input = InpUnknown; + } + // get new state +//qDebug( "%d -%d(%c)-> %d", state, input, c.latin1(), table[state][input] ); + state = table[state][input]; + + // in some cases do special actions depending on state + switch ( state ) { + case Elem: + parseOk = parseString( "LEMENT" ); + break; + case Ws1: + eat_ws(); + break; + case Nam: + parseOk = parseName(); + break; + case Ws2: + eat_ws(); + break; + case Empty: + parseOk = parseString( "EMPTY" ); + break; + case Any: + parseOk = parseString( "ANY" ); + break; + case Cont: + next_eat_ws(); + break; + case Mix: + parseOk = parseString( "#PCDATA" ); + break; + case Mix2: + eat_ws(); + break; + case Mix3: + next(); + break; + case MixN1: + next_eat_ws(); + break; + case MixN2: + parseOk = parseName(); + break; + case MixN3: + eat_ws(); + break; + case MixN4: + next(); + break; + case Cp: + parseOk = parseChoiceSeq(); + break; + case Cp2: + next(); + break; + case WsD: + next_eat_ws(); + break; + case Done: + next(); + break; + } + // no input is read after this + switch ( state ) { + case Elem: + if( !parseOk ) { + d->error = XMLERR_UNEXPECTEDCHARACTER; + goto parseError; + } + break; + case Nam: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGNAME; + goto parseError; + } + break; + case Empty: + if( !parseOk ) { + d->error = XMLERR_UNEXPECTEDCHARACTER; + goto parseError; + } + break; + case Any: + if( !parseOk ) { + d->error = XMLERR_UNEXPECTEDCHARACTER; + goto parseError; + } + break; + case Mix: + if( !parseOk ) { + d->error = XMLERR_UNEXPECTEDCHARACTER; + goto parseError; + } + break; + case MixN2: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGNAME; + goto parseError; + } + break; + case Cp: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGCHOICE; + goto parseError; + } + break; + case Done: + return TRUE; + case -1: + d->error = XMLERR_UNEXPECTEDCHARACTER; + goto parseError; + } + + } + + return TRUE; + +parseError: + reportParseError(); + return FALSE; +} + +/*! + Parse a NotationDecl [82]. + + Precondition: the beginning '<!' is already read and the head + stands on the 'N' of '<!NOTATION' +*/ +bool QXmlSimpleReader::parseNotationDecl() +{ + const signed char Init = 0; + const signed char Not = 1; // read NOTATION + const signed char Ws1 = 2; // eat whitespaces + const signed char Nam = 3; // read Name + const signed char Ws2 = 4; // eat whitespaces + const signed char ExtID = 5; // parse ExternalID + const signed char Ws3 = 6; // eat whitespaces + const signed char Done = 7; + + const signed char InpWs = 0; + const signed char InpGt = 1; // > + const signed char InpN = 2; // N + const signed char InpUnknown = 3; + + // use some kind of state machine for parsing + static signed char table[7][4] = { + /* InpWs InpGt InpN InpUnknown */ + { -1, -1, Not, -1 }, // Init + { Ws1, -1, -1, -1 }, // Not + { -1, -1, Nam, Nam }, // Ws1 + { Ws2, Done, -1, -1 }, // Nam + { -1, Done, ExtID, ExtID }, // Ws2 + { Ws3, Done, -1, -1 }, // ExtID + { -1, Done, -1, -1 } // Ws3 + }; + signed char state = Init; + signed char input; + bool parseOk = TRUE; + + while ( TRUE ) { + + // get input + if ( atEnd() ) { + d->error = XMLERR_UNEXPECTEDEOF; + goto parseError; + } + if ( is_S(c) ) { + input = InpWs; + } else if ( c == '>' ) { + input = InpGt; + } else if ( c == 'N' ) { + input = InpN; + } else { + input = InpUnknown; + } + + // set state according to input + state = table[state][input]; + + // do some actions according to state + switch ( state ) { + case Not: + parseOk = parseString( "NOTATION" ); + break; + case Ws1: + eat_ws(); + break; + case Nam: + parseOk = parseName(); + break; + case Ws2: + eat_ws(); + break; + case ExtID: + parseOk = parseExternalID( TRUE ); + break; + case Ws3: + eat_ws(); + break; + case Done: + next(); + break; + } + // no input is read after this + switch ( state ) { + case Not: + if ( !parseOk ) { + d->error = XMLERR_UNEXPECTEDCHARACTER; + goto parseError; + } + break; + case Nam: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGNAME; + goto parseError; + } + break; + case ExtID: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGEXTERNALID; + goto parseError; + } + // call the handler + if ( dtdHnd ) { + if ( !dtdHnd->notationDecl( name(), d->publicId, d->systemId ) ) { + d->error = dtdHnd->errorString(); + goto parseError; + } + } + break; + case Done: + return TRUE; + case -1: + // Error + d->error = XMLERR_UNEXPECTEDCHARACTER; + goto parseError; + } + + } + + return TRUE; + +parseError: + reportParseError(); + return FALSE; +} + +/*! + Parse choice [49] or seq [50]. + + Precondition: the beginning '('S? is already read and the head + stands on the first non-whitespace character after it. +*/ +bool QXmlSimpleReader::parseChoiceSeq() +{ + const signed char Init = 0; + const signed char Ws1 = 1; // eat whitespace + const signed char CS_ = 2; // choice or set + const signed char Ws2 = 3; // eat whitespace + const signed char More = 4; // more cp to read + const signed char Name = 5; // read name + const signed char Done = 6; // + + const signed char InpWs = 0; // S + const signed char InpOp = 1; // ( + const signed char InpCp = 2; // ) + const signed char InpQm = 3; // ? + const signed char InpAst = 4; // * + const signed char InpPlus = 5; // + + const signed char InpPipe = 6; // | + const signed char InpComm = 7; // , + const signed char InpUnknown = 8; + + // use some kind of state machine for parsing + static signed char table[6][9] = { + /* InpWs InpOp InpCp InpQm InpAst InpPlus InpPipe InpComm InpUnknown */ + { -1, Ws1, -1, -1, -1, -1, -1, -1, Name }, // Init + { -1, CS_, -1, -1, -1, -1, -1, -1, CS_ }, // Ws1 + { Ws2, -1, Done, Ws2, Ws2, Ws2, More, More, -1 }, // CS_ + { -1, -1, Done, -1, -1, -1, More, More, -1 }, // Ws2 + { -1, Ws1, -1, -1, -1, -1, -1, -1, Name }, // More (same as Init) + { Ws2, -1, Done, Ws2, Ws2, Ws2, More, More, -1 } // Name (same as CS_) + }; + signed char state = Init; + signed char input; + bool parseOk = TRUE; + + while ( TRUE ) { + + // get input + if ( atEnd() ) { + d->error = XMLERR_UNEXPECTEDEOF; + goto parseError; + } + if ( is_S(c) ) { + input = InpWs; + } else if ( c == '(' ) { + input = InpOp; + } else if ( c == ')' ) { + input = InpCp; + } else if ( c == '?' ) { + input = InpQm; + } else if ( c == '*' ) { + input = InpAst; + } else if ( c == '+' ) { + input = InpPlus; + } else if ( c == '|' ) { + input = InpPipe; + } else if ( c == ',' ) { + input = InpComm; + } else { + input = InpUnknown; + } + + // set state according to input + state = table[state][input]; + + // do some actions according to state + switch ( state ) { + case Ws1: + next_eat_ws(); + break; + case CS_: + parseOk = parseChoiceSeq(); + break; + case Ws2: + next_eat_ws(); + break; + case More: + next_eat_ws(); + break; + case Name: + parseOk = parseName(); + break; + case Done: + next(); + break; + } + // no input is read after this + switch ( state ) { + case CS_: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGCHOICE; + goto parseError; + } + break; + case Name: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGNAME; + goto parseError; + } + break; + case Done: + return TRUE; + case -1: + // Error + d->error = XMLERR_UNEXPECTEDCHARACTER; + goto parseError; + } + + } + + return TRUE; + +parseError: + reportParseError(); + return FALSE; +} + +/*! + Parse a EntityDecl [70]. + + Precondition: the beginning '<!E' is already read and the head + stand on the 'N' of '<!ENTITY' +*/ +bool QXmlSimpleReader::parseEntityDecl() +{ + const signed char Init = 0; + const signed char Ent = 1; // parse "ENTITY" + const signed char Ws1 = 2; // white space read + const signed char Name = 3; // parse name + const signed char Ws2 = 4; // white space read + const signed char EValue = 5; // parse entity value + const signed char ExtID = 6; // parse ExternalID + const signed char Ws3 = 7; // white space read + const signed char Ndata = 8; // parse "NDATA" + const signed char Ws4 = 9; // white space read + const signed char NNam = 10; // parse name + const signed char PEDec = 11; // parse PEDecl + const signed char Ws6 = 12; // white space read + const signed char PENam = 13; // parse name + const signed char Ws7 = 14; // white space read + const signed char PEVal = 15; // parse entity value + const signed char PEEID = 16; // parse ExternalID + const signed char WsE = 17; // white space read + const signed char EDDone = 19; // done, but also report an external, unparsed entity decl + const signed char Done = 18; + + const signed char InpWs = 0; // white space + const signed char InpPer = 1; // % + const signed char InpQuot = 2; // " or ' + const signed char InpGt = 3; // > + const signed char InpN = 4; // N + const signed char InpUnknown = 5; + + // use some kind of state machine for parsing + static signed char table[18][6] = { + /* InpWs InpPer InpQuot InpGt InpN InpUnknown */ + { -1, -1, -1, -1, Ent, -1 }, // Init + { Ws1, -1, -1, -1, -1, -1 }, // Ent + { -1, PEDec, -1, -1, Name, Name }, // Ws1 + { Ws2, -1, -1, -1, -1, -1 }, // Name + { -1, -1, EValue, -1, -1, ExtID }, // Ws2 + { WsE, -1, -1, Done, -1, -1 }, // EValue + { Ws3, -1, -1, EDDone,-1, -1 }, // ExtID + { -1, -1, -1, EDDone,Ndata, -1 }, // Ws3 + { Ws4, -1, -1, -1, -1, -1 }, // Ndata + { -1, -1, -1, -1, NNam, NNam }, // Ws4 + { WsE, -1, -1, Done, -1, -1 }, // NNam + { Ws6, -1, -1, -1, -1, -1 }, // PEDec + { -1, -1, -1, -1, PENam, PENam }, // Ws6 + { Ws7, -1, -1, -1, -1, -1 }, // PENam + { -1, -1, PEVal, -1, -1, PEEID }, // Ws7 + { WsE, -1, -1, Done, -1, -1 }, // PEVal + { WsE, -1, -1, Done, -1, -1 }, // PEEID + { -1, -1, -1, Done, -1, -1 } // WsE + }; + signed char state = Init; + signed char input; + bool parseOk = TRUE; + + while ( TRUE ) { + + // get input + if ( atEnd() ) { + d->error = XMLERR_UNEXPECTEDEOF; + goto parseError; + } + if ( is_S(c) ) { + input = InpWs; + } else if ( c == '%' ) { + input = InpPer; + } else if ( c == '"' || c == '\'' ) { + input = InpQuot; + } else if ( c == '>' ) { + input = InpGt; + } else if ( c == 'N' ) { + input = InpN; + } else { + input = InpUnknown; + } + + // set state according to input + state = table[state][input]; + + // do some actions according to state + switch ( state ) { + case Ent: + parseOk = parseString( "NTITY" ); + break; + case Ws1: + eat_ws(); + break; + case Name: + parseOk = parseName(); + break; + case Ws2: + eat_ws(); + break; + case EValue: + parseOk = parseEntityValue(); + break; + case ExtID: + parseOk = parseExternalID(); + break; + case Ws3: + eat_ws(); + break; + case Ndata: + parseOk = parseString( "NDATA" ); + break; + case Ws4: + eat_ws(); + break; + case NNam: + parseOk = parseName( TRUE ); + break; + case PEDec: + next(); + break; + case Ws6: + eat_ws(); + break; + case PENam: + parseOk = parseName(); + break; + case Ws7: + eat_ws(); + break; + case PEVal: + parseOk = parseEntityValue(); + break; + case PEEID: + parseOk = parseExternalID(); + break; + case WsE: + eat_ws(); + break; + case EDDone: + next(); + break; + case Done: + next(); + break; + } + // no input is read after this + switch ( state ) { + case Ent: + if ( !parseOk ) { + d->error = XMLERR_UNEXPECTEDCHARACTER; + goto parseError; + } + break; + case Name: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGNAME; + goto parseError; + } + break; + case EValue: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGENTITYVALUE; + goto parseError; + } + if ( !entityExist( name() ) ) { + d->entities.insert( name(), string() ); + if ( declHnd ) { + if ( !declHnd->internalEntityDecl( name(), string() ) ) { + d->error = declHnd->errorString(); + goto parseError; + } + } + } + break; + case ExtID: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGEXTERNALID; + goto parseError; + } + break; + case Ndata: + if ( !parseOk ) { + d->error = XMLERR_UNEXPECTEDCHARACTER; + goto parseError; + } + break; + case NNam: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGNAME; + goto parseError; + } + if ( !entityExist( name() ) ) { + d->externEntities.insert( name(), QXmlSimpleReaderPrivate::ExternEntity( d->publicId, d->systemId, ref() ) ); + if ( dtdHnd ) { + if ( !dtdHnd->unparsedEntityDecl( name(), d->publicId, d->systemId, ref() ) ) { + d->error = declHnd->errorString(); + goto parseError; + } + } + } + break; + case PENam: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGNAME; + goto parseError; + } + break; + case PEVal: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGENTITYVALUE; + goto parseError; + } + if ( !entityExist( name() ) ) { + d->parameterEntities.insert( name(), string() ); + if ( declHnd ) { + if ( !declHnd->internalEntityDecl( QString("%")+name(), string() ) ) { + d->error = declHnd->errorString(); + goto parseError; + } + } + } + break; + case PEEID: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGEXTERNALID; + goto parseError; + } + if ( !entityExist( name() ) ) { + d->externParameterEntities.insert( name(), QXmlSimpleReaderPrivate::ExternParameterEntity( d->publicId, d->systemId ) ); + if ( declHnd ) { + if ( !declHnd->externalEntityDecl( QString("%")+name(), d->publicId, d->systemId ) ) { + d->error = declHnd->errorString(); + goto parseError; + } + } + } + break; + case EDDone: + if ( !entityExist( name() ) ) { + d->externEntities.insert( name(), QXmlSimpleReaderPrivate::ExternEntity( d->publicId, d->systemId, QString::null ) ); + if ( declHnd ) { + if ( !declHnd->externalEntityDecl( name(), d->publicId, d->systemId ) ) { + d->error = declHnd->errorString(); + goto parseError; + } + } + } + return TRUE; + case Done: + return TRUE; + case -1: + // Error + d->error = XMLERR_LETTEREXPECTED; + goto parseError; + } + + } + + return TRUE; + +parseError: + reportParseError(); + return FALSE; +} + +/*! + Parse a EntityValue [9] +*/ +bool QXmlSimpleReader::parseEntityValue() +{ + bool tmp; + + const signed char Init = 0; + const signed char Dq = 1; // EntityValue is double quoted + const signed char DqC = 2; // signed character + const signed char DqPER = 3; // PERefence + const signed char DqRef = 4; // Reference + const signed char Sq = 5; // EntityValue is double quoted + const signed char SqC = 6; // signed character + const signed char SqPER = 7; // PERefence + const signed char SqRef = 8; // Reference + const signed char Done = 9; + + const signed char InpDq = 0; // " + const signed char InpSq = 1; // ' + const signed char InpAmp = 2; // & + const signed char InpPer = 3; // % + const signed char InpUnknown = 4; + + // use some kind of state machine for parsing + static signed char table[9][5] = { + /* InpDq InpSq InpAmp InpPer InpUnknown */ + { Dq, Sq, -1, -1, -1 }, // Init + { Done, DqC, DqRef, DqPER, DqC }, // Dq + { Done, DqC, DqRef, DqPER, DqC }, // DqC + { Done, DqC, DqRef, DqPER, DqC }, // DqPER + { Done, DqC, DqRef, DqPER, DqC }, // DqRef + { SqC, Done, SqRef, SqPER, SqC }, // Sq + { SqC, Done, SqRef, SqPER, SqC }, // SqC + { SqC, Done, SqRef, SqPER, SqC }, // SqPER + { SqC, Done, SqRef, SqPER, SqC } // SqRef + }; + signed char state = Init; + signed char input; + bool parseOk = TRUE; + + while ( TRUE ) { + + // get input + if ( atEnd() ) { + d->error = XMLERR_UNEXPECTEDEOF; + goto parseError; + } + if ( c == '"' ) { + input = InpDq; + } else if ( c == '\'' ) { + input = InpSq; + } else if ( c == '&' ) { + input = InpAmp; + } else if ( c == '%' ) { + input = InpPer; + } else { + input = InpUnknown; + } + + // set state according to input + state = table[state][input]; + + // do some actions according to state + switch ( state ) { + case Dq: + case Sq: + stringClear(); + next(); + break; + case DqC: + case SqC: + stringAddC(); + next(); + break; + case DqPER: + case SqPER: + parseOk = parsePEReference( InEntityValue ); + break; + case DqRef: + case SqRef: + parseOk = parseReference( tmp, InEntityValue ); + break; + case Done: + next(); + break; + } + // no input is read after this + switch ( state ) { + case DqPER: + case SqPER: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGDOCTYPE; + goto parseError; + } + break; + case DqRef: + case SqRef: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGREFERENCE; + goto parseError; + } + break; + case Done: + return TRUE; + case -1: + // Error + d->error = XMLERR_LETTEREXPECTED; + goto parseError; + } + + } + + return TRUE; + +parseError: + reportParseError(); + return FALSE; +} + +/*! + Parse a comment [15]. + + Precondition: the beginning '<!' of the comment is already read and the head + stands on the first '-' of '<!--'. + + If this funktion was successful, the head-position is on the first + character after the comment. +*/ +bool QXmlSimpleReader::parseComment() +{ + const signed char Init = 0; + const signed char Dash1 = 1; // the first dash was read + const signed char Dash2 = 2; // the second dash was read + const signed char Com = 3; // read comment + const signed char Com2 = 4; // read comment (help state) + const signed char ComE = 5; // finished reading comment + const signed char Done = 6; + + const signed char InpDash = 0; // - + const signed char InpGt = 1; // > + const signed char InpUnknown = 2; + + // use some kind of state machine for parsing + static signed char table[6][3] = { + /* InpDash InpGt InpUnknown */ + { Dash1, -1, -1 }, // Init + { Dash2, -1, -1 }, // Dash1 + { Com2, Com, Com }, // Dash2 + { Com2, Com, Com }, // Com + { ComE, Com, Com }, // Com2 + { -1, Done, -1 } // ComE + }; + signed char state = Init; + signed char input; + + while ( TRUE ) { + + // get input + if ( atEnd() ) { + d->error = XMLERR_UNEXPECTEDEOF; + goto parseError; + } + if ( c == '-' ) { + input = InpDash; + } else if ( c == '>' ) { + input = InpGt; + } else { + input = InpUnknown; + } + + // set state according to input + state = table[state][input]; + + // do some actions according to state + switch ( state ) { + case Dash1: + next(); + break; + case Dash2: + next(); + break; + case Com: + stringAddC(); + next(); + break; + case Com2: + next(); + break; + case ComE: + next(); + break; + case Done: + next(); + break; + } + // no input is read after this + switch ( state ) { + case Dash2: + stringClear(); + break; + case Com2: + // if next character is not a dash than don't skip it + if ( c != '-' ) { + stringAddC( '-' ); + } + break; + case Done: + return TRUE; + case -1: + // Error + d->error = XMLERR_ERRORPARSINGCOMMENT; + goto parseError; + } + + } + + return TRUE; + +parseError: + reportParseError(); + return FALSE; +} + +/*! + Parse a Attribute [41]. + + Precondition: the head stands on the first character of the name of the + attribute (i.e. all whitespaces are already parsed). + + The head stand on the next character after the end quotes. The variable name + contains the name of the attribute and the variable string contains the value + of the attribute. +*/ +bool QXmlSimpleReader::parseAttribute() +{ + const signed char Init = 0; + const signed char PName = 1; // parse name + const signed char Ws = 2; // eat ws + const signed char Eq = 3; // the '=' was read + const signed char Quotes = 4; // " or ' were read + + const signed char InpNameBe = 0; + const signed char InpEq = 1; // = + const signed char InpDq = 2; // " + const signed char InpSq = 3; // ' + const signed char InpUnknown = 4; + + // use some kind of state machine for parsing + static signed char table[4][5] = { + /* InpNameBe InpEq InpDq InpSq InpUnknown */ + { PName, -1, -1, -1, -1 }, // Init + { -1, Eq, -1, -1, Ws }, // PName + { -1, Eq, -1, -1, -1 }, // Ws + { -1, -1, Quotes, Quotes, -1 } // Eq + }; + signed char state = Init; + signed char input; + bool parseOk = TRUE; + + while ( TRUE ) { + + // get input + if ( atEnd() ) { + d->error = XMLERR_UNEXPECTEDEOF; + goto parseError; + } + if ( is_NameBeginning(c) ) { + input = InpNameBe; + } else if ( c == '=' ) { + input = InpEq; + } else if ( c == '"' ) { + input = InpDq; + } else if ( c == '\'' ) { + input = InpSq; + } else { + input = InpUnknown; + } + + // set state according to input + state = table[state][input]; + + // do some actions according to state + switch ( state ) { + case PName: + parseOk = parseName(); + break; + case Ws: + eat_ws(); + break; + case Eq: + next_eat_ws(); + break; + case Quotes: + parseOk = parseAttValue(); + break; + } + // no input is read after this + switch ( state ) { + case PName: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGNAME; + goto parseError; + } + break; + case Quotes: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGATTVALUE; + goto parseError; + } + // Done + return TRUE; + case -1: + // Error + d->error = XMLERR_UNEXPECTEDCHARACTER; + goto parseError; + } + + } + + return TRUE; + +parseError: + reportParseError(); + return FALSE; +} + +/*! + Parse a Name [5] and store the name in name or ref (if useRef is TRUE). +*/ +bool QXmlSimpleReader::parseName( bool useRef ) +{ + const signed char Init = 0; + const signed char Name1 = 1; // parse first signed character of the name + const signed char Name = 2; // parse name + const signed char Done = 3; + + const signed char InpNameBe = 0; // name beginning signed characters + const signed char InpNameCh = 1; // NameChar without InpNameBe + const signed char InpUnknown = 2; + + // use some kind of state machine for parsing + static signed char table[3][3] = { + /* InpNameBe InpNameCh InpUnknown */ + { Name1, -1, -1 }, // Init + { Name, Name, Done }, // Name1 + { Name, Name, Done } // Name + }; + signed char state = Init; + signed char input; + + while ( TRUE ) { + + // get input + if ( atEnd() ) { + d->error = XMLERR_UNEXPECTEDEOF; + goto parseError; + } + if ( is_NameBeginning(c) ) { + input = InpNameBe; + } else if ( is_NameChar(c) ) { + input = InpNameCh; + } else { + input = InpUnknown; + } + + // set state according to input + state = table[state][input]; + + // do some actions according to state + switch ( state ) { + case Name1: + if ( useRef ) { + refClear(); + refAddC(); + } else { + nameClear(); + nameAddC(); + } + next(); + break; + case Name: + if ( useRef ) { + refAddC(); + } else { + nameAddC(); + } + next(); + break; + } + // no input is read after this + switch ( state ) { + case Done: + return TRUE; + case -1: + // Error + d->error = XMLERR_LETTEREXPECTED; + goto parseError; + } + + } + + return TRUE; + +parseError: + reportParseError(); + return FALSE; +} + +/*! + Parse a Nmtoken [7] and store the name in name. +*/ +bool QXmlSimpleReader::parseNmtoken() +{ + const signed char Init = 0; + const signed char NameF = 1; + const signed char Name = 2; + const signed char Done = 3; + + const signed char InpNameCh = 0; // NameChar without InpNameBe + const signed char InpUnknown = 1; + + // use some kind of state machine for parsing + static signed char table[3][2] = { + /* InpNameCh InpUnknown */ + { NameF, -1 }, // Init + { Name, Done }, // NameF + { Name, Done } // Name + }; + signed char state = Init; + signed char input; + + while ( TRUE ) { + + // get input + if ( atEnd() ) { + d->error = XMLERR_UNEXPECTEDEOF; + goto parseError; + } + if ( is_NameChar(c) ) { + input = InpNameCh; + } else { + input = InpUnknown; + } + + // set state according to input + state = table[state][input]; + + // do some actions according to state + switch ( state ) { + case NameF: + nameClear(); + nameAddC(); + next(); + break; + case Name: + nameAddC(); + next(); + break; + } + // no input is read after this + switch ( state ) { + case Done: + return TRUE; + case -1: + // Error + d->error = XMLERR_LETTEREXPECTED; + goto parseError; + } + + } + + return TRUE; + +parseError: + reportParseError(); + return FALSE; +} + +/*! + Parse a Reference [67]. + + charDataRead is set to TRUE if the reference must not be parsed. The + character(s) which the reference mapped to are appended to string. The + head stands on the first character after the reference. + + charDataRead is set to FALSE if the reference must be parsed. The + charachter(s) which the reference mapped to are inserted at the reference + position. The head stands on the first character of the replacement). +*/ +bool QXmlSimpleReader::parseReference( bool &charDataRead, EntityRecognitionContext context ) +{ + // temporary variables + uint tmp; + bool ok; + + const signed char Init = 0; + const signed char SRef = 1; // start of a reference + const signed char ChRef = 2; // parse CharRef + const signed char ChDec = 3; // parse CharRef decimal + const signed char ChHexS = 4; // start CharRef hexadecimal + const signed char ChHex = 5; // parse CharRef hexadecimal + const signed char Name = 6; // parse name + const signed char DoneD = 7; // done CharRef decimal + const signed char DoneH = 8; // done CharRef hexadecimal + const signed char DoneN = 9; // done EntityRef + + const signed char InpAmp = 0; // & + const signed char InpSemi = 1; // ; + const signed char InpHash = 2; // # + const signed char InpX = 3; // x + const signed char InpNum = 4; // 0-9 + const signed char InpHex = 5; // a-f A-F + const signed char InpUnknown = 6; + + // use some kind of state machine for parsing + static signed char table[8][7] = { + /* InpAmp InpSemi InpHash InpX InpNum InpHex InpUnknown */ + { SRef, -1, -1, -1, -1, -1, -1 }, // Init + { -1, -1, ChRef, Name, Name, Name, Name }, // SRef + { -1, -1, -1, ChHexS, ChDec, -1, -1 }, // ChRef + { -1, DoneD, -1, -1, ChDec, -1, -1 }, // ChDec + { -1, -1, -1, -1, ChHex, ChHex, -1 }, // ChHexS + { -1, DoneH, -1, -1, ChHex, ChHex, -1 }, // ChHex + { -1, DoneN, -1, -1, -1, -1, -1 } // Name + }; + signed char state = Init; + signed char input; + + while ( TRUE ) { + + // get input + if ( atEnd() ) { + d->error = XMLERR_UNEXPECTEDEOF; + goto parseError; + } + if ( c.row() ) { + input = InpUnknown; + } else if ( c.cell() == '&' ) { + input = InpAmp; + } else if ( c.cell() == ';' ) { + input = InpSemi; + } else if ( c.cell() == '#' ) { + input = InpHash; + } else if ( c.cell() == 'x' ) { + input = InpX; + } else if ( '0' <= c.cell() && c.cell() <= '9' ) { + input = InpNum; + } else if ( 'a' <= c.cell() && c.cell() <= 'f' ) { + input = InpHex; + } else if ( 'A' <= c.cell() && c.cell() <= 'F' ) { + input = InpHex; + } else { + input = InpUnknown; + } + + // set state according to input + state = table[state][input]; + + // do some actions according to state + switch ( state ) { + case SRef: + refClear(); + next(); + break; + case ChRef: + next(); + break; + case ChDec: + refAddC(); + next(); + break; + case ChHexS: + next(); + break; + case ChHex: + refAddC(); + next(); + break; + case Name: + // read the name into the ref + parseName( TRUE ); + break; + case DoneD: + tmp = ref().toUInt( &ok, 10 ); + if ( ok ) { + stringAddC( QChar(tmp) ); + } else { + d->error = XMLERR_ERRORPARSINGREFERENCE; + goto parseError; + } + charDataRead = TRUE; + next(); + break; + case DoneH: + tmp = ref().toUInt( &ok, 16 ); + if ( ok ) { + stringAddC( QChar(tmp) ); + } else { + d->error = XMLERR_ERRORPARSINGREFERENCE; + goto parseError; + } + charDataRead = TRUE; + next(); + break; + case DoneN: + if ( !processReference( charDataRead, context ) ) + goto parseError; + next(); + break; + } + // no input is read after this + switch ( state ) { + case DoneD: + return TRUE; + case DoneH: + return TRUE; + case DoneN: + return TRUE; + case -1: + // Error + d->error = XMLERR_ERRORPARSINGREFERENCE; + goto parseError; + } + + } + + return TRUE; + +parseError: + reportParseError(); + return FALSE; +} + +/*! + Helper function for parseReference() +*/ +bool QXmlSimpleReader::processReference( bool &charDataRead, EntityRecognitionContext context ) +{ + QString reference = ref(); + if ( reference == "amp" ) { + if ( context == InEntityValue ) { + // Bypassed + stringAddC( '&' ); stringAddC( 'a' ); stringAddC( 'm' ); stringAddC( 'p' ); stringAddC( ';' ); + } else { + // Included or Included in literal + stringAddC( '&' ); + } + charDataRead = TRUE; + } else if ( reference == "lt" ) { + if ( context == InEntityValue ) { + // Bypassed + stringAddC( '&' ); stringAddC( 'l' ); stringAddC( 't' ); stringAddC( ';' ); + } else { + // Included or Included in literal + stringAddC( '<' ); + } + charDataRead = TRUE; + } else if ( reference == "gt" ) { + if ( context == InEntityValue ) { + // Bypassed + stringAddC( '&' ); stringAddC( 'g' ); stringAddC( 't' ); stringAddC( ';' ); + } else { + // Included or Included in literal + stringAddC( '>' ); + } + charDataRead = TRUE; + } else if ( reference == "apos" ) { + if ( context == InEntityValue ) { + // Bypassed + stringAddC( '&' ); stringAddC( 'a' ); stringAddC( 'p' ); stringAddC( 'o' ); stringAddC( 's' ); stringAddC( ';' ); + } else { + // Included or Included in literal + stringAddC( '\'' ); + } + charDataRead = TRUE; + } else if ( reference == "quot" ) { + if ( context == InEntityValue ) { + // Bypassed + stringAddC( '&' ); stringAddC( 'q' ); stringAddC( 'u' ); stringAddC( 'o' ); stringAddC( 't' ); stringAddC( ';' ); + } else { + // Included or Included in literal + stringAddC( '"' ); + } + charDataRead = TRUE; + } else { + QMap<QString,QString>::Iterator it; + it = d->entities.find( reference ); + if ( it != d->entities.end() ) { + // "Internal General" + switch ( context ) { + case InContent: + // Included + xmlRef = it.data() + xmlRef; + charDataRead = FALSE; + break; + case InAttributeValue: + // Included in literal + xmlRef = it.data().replace( QRegExp("\""), """ ).replace( QRegExp("'"), "'" ) + + xmlRef; + charDataRead = FALSE; + break; + case InEntityValue: + { + // Bypassed + stringAddC( '&' ); + for ( int i=0; i<(int)reference.length(); i++ ) { + stringAddC( reference[i] ); + } + stringAddC( ';'); + charDataRead = TRUE; + } + break; + case InDTD: + // Forbidden + d->error = XMLERR_INTERNALGENERALENTITYINDTD; + charDataRead = FALSE; + break; + } + } else { + QMap<QString,QXmlSimpleReaderPrivate::ExternEntity>::Iterator itExtern; + itExtern = d->externEntities.find( reference ); + if ( itExtern == d->externEntities.end() ) { + // entity not declared + // ### check this case for conformance + if ( context == InEntityValue ) { + // Bypassed + stringAddC( '&' ); + for ( int i=0; i<(int)reference.length(); i++ ) { + stringAddC( reference[i] ); + } + stringAddC( ';'); + charDataRead = TRUE; + } else { + if ( contentHnd ) { + if ( !contentHnd->skippedEntity( reference ) ) { + d->error = contentHnd->errorString(); + return FALSE; // error + } + } + } + } else if ( (*itExtern).notation.isNull() ) { + // "External Parsed General" + switch ( context ) { + case InContent: + // Included if validating + if ( contentHnd ) { + if ( !contentHnd->skippedEntity( reference ) ) { + d->error = contentHnd->errorString(); + return FALSE; // error + } + } + charDataRead = FALSE; + break; + case InAttributeValue: + // Forbidden + d->error = XMLERR_EXTERNALGENERALENTITYINAV; + charDataRead = FALSE; + break; + case InEntityValue: + { + // Bypassed + stringAddC( '&' ); + for ( int i=0; i<(int)reference.length(); i++ ) { + stringAddC( reference[i] ); + } + stringAddC( ';'); + charDataRead = TRUE; + } + break; + case InDTD: + // Forbidden + d->error = XMLERR_EXTERNALGENERALENTITYINDTD; + charDataRead = FALSE; + break; + } + } else { + // "Unparsed" + // ### notify for "Occurs as Attribute Value" missing (but this is no refence, anyway) + // Forbidden + d->error = XMLERR_UNPARSEDENTITYREFERENCE; + charDataRead = FALSE; + return FALSE; // error + } + } + } + return TRUE; // no error +} + + +/*! + Parse over a simple string. + + After the string was successfully parsed, the head is on the first + character after the string. +*/ +bool QXmlSimpleReader::parseString( const QString& s ) +{ + signed char Done = s.length(); + + const signed char InpCharExpected = 0; // the character that was expected + const signed char InpUnknown = 1; + + signed char state = 0; // state in this function is the position in the string s + signed char input; + + while ( TRUE ) { + + // get input + if ( atEnd() ) { + d->error = XMLERR_UNEXPECTEDEOF; + goto parseError; + } + if ( c == s[(int)state] ) { + input = InpCharExpected; + } else { + input = InpUnknown; + } + + // set state according to input + if ( input == InpCharExpected ) { + state++; + } else { + // Error + d->error = XMLERR_UNEXPECTEDCHARACTER; + goto parseError; + } + + // do some actions according to state + next(); + // no input is read after this + if ( state == Done ) { + return TRUE; + } + + } + + return TRUE; + +parseError: + reportParseError(); + return FALSE; +} + + +/*! + Inits the data values. +*/ +void QXmlSimpleReader::init( const QXmlInputSource& i ) +{ + xml = i.data(); + xmlLength = xml.length(); + xmlRef = ""; + + d->externParameterEntities.clear(); + d->parameterEntities.clear(); + d->externEntities.clear(); + d->entities.clear(); + + tags.clear(); + + d->doctype = ""; + d->xmlVersion = ""; + d->encoding = ""; + d->standalone = QXmlSimpleReaderPrivate::Unknown; + + lineNr = 0; + columnNr = -1; + pos = 0; + next(); + d->error = XMLERR_OK; +} + +/*! + Returns TRUE if a entity with the name \a e exists, + otherwise returns FALSE. +*/ +bool QXmlSimpleReader::entityExist( const QString& e ) const +{ + if ( d->parameterEntities.find(e) == d->parameterEntities.end() && + d->externParameterEntities.find(e) == d->externParameterEntities.end() ) { + return FALSE; + } else { + return TRUE; + } +} + +void QXmlSimpleReader::reportParseError() +{ + if ( errorHnd ) + errorHnd->fatalError( QXmlParseException( d->error, columnNr+1, lineNr+1 ) ); +} + +#endif //QT_NO_XML diff --git a/trunk/qtools/qxml.h b/trunk/qtools/qxml.h new file mode 100644 index 0000000..0797b94 --- /dev/null +++ b/trunk/qtools/qxml.h @@ -0,0 +1,671 @@ +/**************************************************************************** +** +** +** Definition of QXmlSimpleReader and related classes. +** +** Created : 000518 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the XML module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition licenses may use this +** file in accordance with the Qt Commercial License Agreement provided +** with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QXML_H +#define QXML_H + +#include <qmodules.h> + +#if !defined(QT_MODULE_XML) +#define QM_EXPORT +#else +#define QM_EXPORT Q_EXPORT +#endif + +#ifndef QT_H +#include <qtextstream.h> +#include <qfile.h> +#include <qstring.h> +#include <qstringlist.h> +#include <qvaluestack.h> +#include <qmap.h> +#endif // QT_H + +#ifndef QT_NO_XML + +class QXmlNamespaceSupport; +class QXmlAttributes; +class QXmlContentHandler; +class QXmlDefaultHandler; +class QXmlDTDHandler; +class QXmlEntityResolver; +class QXmlErrorHandler; +class QXmlLexicalHandler; +class QXmlDeclHandler; +class QXmlInputSource; +class QXmlLocator; +class QXmlNamespaceSupport; +class QXmlParseException; + +class QXmlReader; +class QXmlSimpleReader; + +class QXmlSimpleReaderPrivate; +class QXmlNamespaceSupportPrivate; +class QXmlAttributesPrivate; +class QXmlInputSourcePrivate; +class QXmlParseExceptionPrivate; +class QXmlLocatorPrivate; +class QXmlDefaultHandlerPrivate; + + +// +// SAX Namespace Support +// + +#if defined(Q_TEMPLATEDLL) +// MOC_SKIP_BEGIN +template class QM_EXPORT QMap<QString, QString>; +template class QM_EXPORT QValueStack<QMap<QString, QString> >; +template class QM_EXPORT QValueStack<QString>; +// MOC_SKIP_END +#endif + +class QM_EXPORT QXmlNamespaceSupport +{ +public: + QXmlNamespaceSupport(); + ~QXmlNamespaceSupport(); + + void setPrefix( const QString&, const QString& ); + + QString prefix( const QString& ) const; + QString uri( const QString& ) const; + void splitName( const QString&, QString&, QString& ) const; + void processName( const QString&, bool, QString&, QString& ) const; + QStringList prefixes() const; + QStringList prefixes( const QString& ) const; + + void pushContext(); + void popContext(); + void reset(); +private: + QValueStack<QMap<QString, QString> > nsStack; + QMap<QString, QString> ns; + + QXmlNamespaceSupportPrivate *d; +}; + + +// +// SAX Attributes +// + +class QM_EXPORT QXmlAttributes +{ +public: + QXmlAttributes() {} + virtual ~QXmlAttributes() {} + + int index( const QString& qName ) const; + int index( const QString& uri, const QString& localPart ) const; + int length() const; + QString localName( int index ) const; + QString qName( int index ) const; + QString uri( int index ) const; + QString type( int index ) const; + QString type( const QString& qName ) const; + QString type( const QString& uri, const QString& localName ) const; + QString value( int index ) const; + QString value( const QString& qName ) const; + QString value( const QString& uri, const QString& localName ) const; + +private: + QStringList qnameList; + QStringList uriList; + QStringList localnameList; + QStringList valueList; + + QXmlAttributesPrivate *d; + + friend class QXmlSimpleReader; +}; + +// +// SAX Input Source +// + +class QM_EXPORT QXmlInputSource +{ +public: + QXmlInputSource(); + QXmlInputSource( QTextStream& stream ); + QXmlInputSource( QFile& file ); + virtual ~QXmlInputSource(); + + virtual const QString& data() const; + virtual void setData( const QString& d ); + +private: + void readInput( QByteArray& rawData ); + + QString input; + + QXmlInputSourcePrivate *d; +}; + +// +// SAX Exception Classes +// + +class QM_EXPORT QXmlParseException +{ +public: + QXmlParseException( const QString& name="", int c=-1, int l=-1, const QString& p="", const QString& s="" ) + : msg( name ), column( c ), line( l ), pub( p ), sys( s ) + { } + + int columnNumber() const; + int lineNumber() const; + QString publicId() const; + QString systemId() const; + QString message() const; + +private: + QString msg; + int column; + int line; + QString pub; + QString sys; + + QXmlParseExceptionPrivate *d; +}; + + +// +// XML Reader +// + +class QM_EXPORT QXmlReader +{ +public: + virtual ~QXmlReader() {} + virtual bool feature( const QString& name, bool *ok = 0 ) const = 0; + virtual void setFeature( const QString& name, bool value ) = 0; + virtual bool hasFeature( const QString& name ) const = 0; + virtual void* property( const QString& name, bool *ok = 0 ) const = 0; + virtual void setProperty( const QString& name, void* value ) = 0; + virtual bool hasProperty( const QString& name ) const = 0; + virtual void setEntityResolver( QXmlEntityResolver* handler ) = 0; + virtual QXmlEntityResolver* entityResolver() const = 0; + virtual void setDTDHandler( QXmlDTDHandler* handler ) = 0; + virtual QXmlDTDHandler* DTDHandler() const = 0; + virtual void setContentHandler( QXmlContentHandler* handler ) = 0; + virtual QXmlContentHandler* contentHandler() const = 0; + virtual void setErrorHandler( QXmlErrorHandler* handler ) = 0; + virtual QXmlErrorHandler* errorHandler() const = 0; + virtual void setLexicalHandler( QXmlLexicalHandler* handler ) = 0; + virtual QXmlLexicalHandler* lexicalHandler() const = 0; + virtual void setDeclHandler( QXmlDeclHandler* handler ) = 0; + virtual QXmlDeclHandler* declHandler() const = 0; + virtual bool parse( const QXmlInputSource& input ) = 0; +}; + +class QM_EXPORT QXmlSimpleReader : public QXmlReader +{ +public: + QXmlSimpleReader(); + virtual ~QXmlSimpleReader(); + + bool feature( const QString& name, bool *ok = 0 ) const; + void setFeature( const QString& name, bool value ); + bool hasFeature( const QString& name ) const; + + void* property( const QString& name, bool *ok = 0 ) const; + void setProperty( const QString& name, void* value ); + bool hasProperty( const QString& name ) const; + + void setEntityResolver( QXmlEntityResolver* handler ); + QXmlEntityResolver* entityResolver() const; + void setDTDHandler( QXmlDTDHandler* handler ); + QXmlDTDHandler* DTDHandler() const; + void setContentHandler( QXmlContentHandler* handler ); + QXmlContentHandler* contentHandler() const; + void setErrorHandler( QXmlErrorHandler* handler ); + QXmlErrorHandler* errorHandler() const; + void setLexicalHandler( QXmlLexicalHandler* handler ); + QXmlLexicalHandler* lexicalHandler() const; + void setDeclHandler( QXmlDeclHandler* handler ); + QXmlDeclHandler* declHandler() const; + + bool parse( const QXmlInputSource& input ); + +private: + // variables + QXmlContentHandler* contentHnd; + QXmlErrorHandler* errorHnd; + QXmlDTDHandler* dtdHnd; + QXmlEntityResolver* entityRes; + QXmlLexicalHandler* lexicalHnd; + QXmlDeclHandler* declHnd; + + QChar c; // the character at reading position + int lineNr; // number of line + int columnNr; // position in line + int pos; // position in string + + int namePos; + QChar nameArray[256]; // only used for names + QString nameValue; // only used for names + int refPos; + QChar refArray[256]; // only used for references + QString refValue; // only used for references + int stringPos; + QChar stringArray[256]; // used for any other strings that are parsed + QString stringValue; // used for any other strings that are parsed + + QString xml; + int xmlLength; + QString xmlRef; // used for parsing of entity references + + QValueStack<QString> tags; + + QXmlSimpleReaderPrivate* d; + + static const QChar QEOF; + + // inlines + virtual bool is_S( const QChar& ); + virtual bool is_Letter( const QChar& ); + virtual bool is_NameBeginning( const QChar& ); + virtual bool is_Digit( const QChar& ); + virtual bool is_CombiningChar( const QChar& ); + virtual bool is_Extender( const QChar& ); + virtual bool is_NameChar( const QChar& ); + + QString& string(); + void stringClear(); + void stringAddC(); + void stringAddC(const QChar&); + QString& name(); + void nameClear(); + void nameAddC(); + void nameAddC(const QChar&); + QString& ref(); + void refClear(); + void refAddC(); + void refAddC(const QChar&); + + // used by parseReference() and parsePEReference() + enum EntityRecognitionContext { InContent, InAttributeValue, InEntityValue, InDTD }; + + // private functions + void eat_ws(); + void next_eat_ws(); + + void next(); + bool atEnd(); + + void init( const QXmlInputSource& i ); + + bool entityExist( const QString& ) const; + + bool parseProlog(); + bool parseElement(); + bool parseElementEmptyTag( bool &t, QString &uri, QString &lname ); + bool parseElementETagBegin2( QString &uri, QString &lname ); + bool parseElementAttribute( QString &prefix, QString &uri, QString &lname ); + bool parseMisc(); + bool parseContent(); + + bool parsePI(bool xmldecl=FALSE); + bool parseDoctype(); + bool parseComment(); + + bool parseName( bool useRef=FALSE ); + bool parseNmtoken(); + bool parseAttribute(); + bool parseReference( bool &charDataRead, EntityRecognitionContext context ); + bool processReference( bool &charDataRead, EntityRecognitionContext context ); + + bool parseExternalID( bool allowPublicID = FALSE ); + bool parsePEReference( EntityRecognitionContext context ); + bool parseMarkupdecl(); + bool parseAttlistDecl(); + bool parseAttType(); + bool parseAttValue(); + bool parseElementDecl(); + bool parseNotationDecl(); + bool parseChoiceSeq(); + bool parseEntityDecl(); + bool parseEntityValue(); + + bool parseString( const QString& s ); + + void reportParseError(); + + friend class QXmlSimpleReaderPrivate; + friend class QXmlLocator; +}; + +// +// SAX Locator +// + +class QM_EXPORT QXmlLocator +{ +public: + QXmlLocator( QXmlSimpleReader* parent ) + { reader = parent; } + ~QXmlLocator() + { } + + int columnNumber(); + int lineNumber(); +// QString getPublicId() +// QString getSystemId() + +private: + QXmlSimpleReader* reader; + + QXmlLocatorPrivate *d; +}; + +// +// SAX handler classes +// + +class QM_EXPORT QXmlContentHandler +{ +public: + virtual ~QXmlContentHandler() {} + virtual void setDocumentLocator( QXmlLocator* locator ) = 0; + virtual bool startDocument() = 0; + virtual bool endDocument() = 0; + virtual bool startPrefixMapping( const QString& prefix, const QString& uri ) = 0; + virtual bool endPrefixMapping( const QString& prefix ) = 0; + virtual bool startElement( const QString& namespaceURI, const QString& localName, const QString& qName, const QXmlAttributes& atts ) = 0; + virtual bool endElement( const QString& namespaceURI, const QString& localName, const QString& qName ) = 0; + virtual bool characters( const QString& ch ) = 0; + virtual bool ignorableWhitespace( const QString& ch ) = 0; + virtual bool processingInstruction( const QString& target, const QString& data ) = 0; + virtual bool skippedEntity( const QString& name ) = 0; + virtual QString errorString() = 0; +}; + +class QM_EXPORT QXmlErrorHandler +{ +public: + virtual ~QXmlErrorHandler() {} + virtual bool warning( const QXmlParseException& exception ) = 0; + virtual bool error( const QXmlParseException& exception ) = 0; + virtual bool fatalError( const QXmlParseException& exception ) = 0; + virtual QString errorString() = 0; +}; + +class QM_EXPORT QXmlDTDHandler +{ +public: + virtual ~QXmlDTDHandler() {} + virtual bool notationDecl( const QString& name, const QString& publicId, const QString& systemId ) = 0; + virtual bool unparsedEntityDecl( const QString& name, const QString& publicId, const QString& systemId, const QString& notationName ) = 0; + virtual QString errorString() = 0; +}; + +class QM_EXPORT QXmlEntityResolver +{ +public: + virtual ~QXmlEntityResolver() {} + virtual bool resolveEntity( const QString& publicId, const QString& systemId, QXmlInputSource* &ret ) = 0; + virtual QString errorString() = 0; +}; + +class QM_EXPORT QXmlLexicalHandler +{ +public: + virtual ~QXmlLexicalHandler() {} + virtual bool startDTD( const QString& name, const QString& publicId, const QString& systemId ) = 0; + virtual bool endDTD() = 0; +// virtual bool startEntity( const QString& name ) = 0; +// virtual bool endEntity( const QString& name ) = 0; + virtual bool startCDATA() = 0; + virtual bool endCDATA() = 0; + virtual bool comment( const QString& ch ) = 0; + virtual QString errorString() = 0; +}; + +class QM_EXPORT QXmlDeclHandler +{ +public: + virtual ~QXmlDeclHandler() {} + virtual bool attributeDecl( const QString& eName, const QString& aName, const QString& type, const QString& valueDefault, const QString& value ) = 0; + virtual bool internalEntityDecl( const QString& name, const QString& value ) = 0; + virtual bool externalEntityDecl( const QString& name, const QString& publicId, const QString& systemId ) = 0; + virtual QString errorString() = 0; +}; + + +class QM_EXPORT QXmlDefaultHandler : public QXmlContentHandler, public QXmlErrorHandler, public QXmlDTDHandler, public QXmlEntityResolver, public QXmlLexicalHandler, public QXmlDeclHandler +{ +public: + QXmlDefaultHandler() { } + virtual ~QXmlDefaultHandler() { } + + void setDocumentLocator( QXmlLocator* locator ); + bool startDocument(); + bool endDocument(); + bool startPrefixMapping( const QString& prefix, const QString& uri ); + bool endPrefixMapping( const QString& prefix ); + bool startElement( const QString& namespaceURI, const QString& localName, const QString& qName, const QXmlAttributes& atts ); + bool endElement( const QString& namespaceURI, const QString& localName, const QString& qName ); + bool characters( const QString& ch ); + bool ignorableWhitespace( const QString& ch ); + bool processingInstruction( const QString& target, const QString& data ); + bool skippedEntity( const QString& name ); + + bool warning( const QXmlParseException& exception ); + bool error( const QXmlParseException& exception ); + bool fatalError( const QXmlParseException& exception ); + + bool notationDecl( const QString& name, const QString& publicId, const QString& systemId ); + bool unparsedEntityDecl( const QString& name, const QString& publicId, const QString& systemId, const QString& notationName ); + + bool resolveEntity( const QString& publicId, const QString& systemId, QXmlInputSource* &ret ); + + bool startDTD( const QString& name, const QString& publicId, const QString& systemId ); + bool endDTD(); +// bool startEntity( const QString& name ); +// bool endEntity( const QString& name ); + bool startCDATA(); + bool endCDATA(); + bool comment( const QString& ch ); + + bool attributeDecl( const QString& eName, const QString& aName, const QString& type, const QString& valueDefault, const QString& value ); + bool internalEntityDecl( const QString& name, const QString& value ); + bool externalEntityDecl( const QString& name, const QString& publicId, const QString& systemId ); + + QString errorString(); + +private: + QXmlDefaultHandlerPrivate *d; +}; + +#ifdef _WS_QWS_ +#ifdef QT_XML_CPP +#define inline +#else +#define QT_NO_XML_INLINE +#endif +#endif + +#ifndef QT_NO_XML_INLINE +// +// inlines +// + +inline bool QXmlSimpleReader::is_S(const QChar& ch) +{ return ch==' ' || ch=='\t' || ch=='\n' || ch=='\r'; } + +inline bool QXmlSimpleReader::is_Letter( const QChar& ch ) +{ return ch.isLetter(); } + +inline bool QXmlSimpleReader::is_NameBeginning( const QChar& ch ) +{ return ch=='_' || ch==':' || ch.isLetter(); } + +inline bool QXmlSimpleReader::is_Digit( const QChar& ch ) +{ return ch.isDigit(); } + +inline bool QXmlSimpleReader::is_CombiningChar( const QChar& ) +{ return FALSE; } + +inline bool QXmlSimpleReader::is_Extender( const QChar& ) +{ return FALSE; } + +inline bool QXmlSimpleReader::is_NameChar( const QChar& ch ) +{ + return ch=='.' || ch=='-' || ch=='_' || ch==':' || + is_Letter(ch) || is_Digit(ch) || + is_CombiningChar(ch) || is_Extender(ch); +} + +inline void QXmlSimpleReader::next() +{ + if ( !xmlRef.isEmpty() ) { + c = xmlRef[0]; + xmlRef.remove( 0, 1 ); + } else { + if ( c=='\n' || c=='\r' ) { + lineNr++; + columnNr = -1; + } + if ( pos >= xmlLength ) { + c = QEOF; + } else { + c = xml[pos]; + columnNr++; + pos++; + } + } +} + +inline bool QXmlSimpleReader::atEnd() +{ return c == QEOF; } + +inline void QXmlSimpleReader::eat_ws() +{ while ( !atEnd() && is_S(c) ) next(); } + +inline void QXmlSimpleReader::next_eat_ws() +{ next(); eat_ws(); } + + +// use buffers instead of QString::operator+= when single characters are read +inline QString& QXmlSimpleReader::string() +{ + stringValue += QString( stringArray, stringPos ); + stringPos = 0; + return stringValue; +} +inline QString& QXmlSimpleReader::name() +{ + nameValue += QString( nameArray, namePos ); + namePos = 0; + return nameValue; +} +inline QString& QXmlSimpleReader::ref() +{ + refValue += QString( refArray, refPos ); + refPos = 0; + return refValue; +} + +inline void QXmlSimpleReader::stringClear() +{ stringValue = ""; stringPos = 0; } +inline void QXmlSimpleReader::nameClear() +{ nameValue = ""; namePos = 0; } +inline void QXmlSimpleReader::refClear() +{ refValue = ""; refPos = 0; } + +inline void QXmlSimpleReader::stringAddC() +{ + if ( stringPos >= 256 ) { + stringValue += QString( stringArray, stringPos ); + stringPos = 0; + } + stringArray[stringPos++] = c; +} +inline void QXmlSimpleReader::nameAddC() +{ + if ( namePos >= 256 ) { + nameValue += QString( nameArray, namePos ); + namePos = 0; + } + nameArray[namePos++] = c; +} +inline void QXmlSimpleReader::refAddC() +{ + if ( refPos >= 256 ) { + refValue += QString( refArray, refPos ); + refPos = 0; + } + refArray[refPos++] = c; +} + +inline void QXmlSimpleReader::stringAddC(const QChar& ch) +{ + if ( stringPos >= 256 ) { + stringValue += QString( stringArray, stringPos ); + stringPos = 0; + } + stringArray[stringPos++] = ch; +} +inline void QXmlSimpleReader::nameAddC(const QChar& ch) +{ + if ( namePos >= 256 ) { + nameValue += QString( nameArray, namePos ); + namePos = 0; + } + nameArray[namePos++] = ch; +} +inline void QXmlSimpleReader::refAddC(const QChar& ch) +{ + if ( refPos >= 256 ) { + refValue += QString( refArray, refPos ); + refPos = 0; + } + refArray[refPos++] = ch; +} +#endif + +#ifdef _WS_QWS_ +#ifdef QT_XML_CPP +#undef inline +#endif +#endif + +#endif //QT_NO_XML + +#endif diff --git a/trunk/qtools/scstring.cpp b/trunk/qtools/scstring.cpp new file mode 100644 index 0000000..26d3a52 --- /dev/null +++ b/trunk/qtools/scstring.cpp @@ -0,0 +1,798 @@ +/****************************************************************************** + * + * Copyright (C) 1997-2004 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. + * + */ + +// with this switch you can choose between the original qcstring implementation, +// which implicitly shares data so copying is faster, but requires at least 12 bytes, and +// the new implementation in this file, which has a smaller footprint (only 4 bytes for +// an empty string), but always copies strings. +#define SMALLSTRING + +#include "qcstring.h" +#ifndef SMALLSTRING +#include "qcstring.cpp" +#else +#define SCString QCString + +#include <qstring.h> +#include <stdlib.h> +#include <stdio.h> +#include <stdarg.h> +#include <ctype.h> +#include <qregexp.h> +#include <qdatastream.h> + + +SCString::SCString(int size) +{ + if (size>0) + { + m_data = (char *)malloc(size); + if (m_data) + { + if (size>1) memset(m_data,' ',size-1); + m_data[size-1]='\0'; + } + } + else + { + m_data=0; + } +} + +SCString::SCString( const SCString &s ) +{ + duplicate(s); +} + +SCString::SCString( const char *str ) +{ + duplicate(str); +} + +SCString::SCString( const char *str, uint maxlen ) +{ + uint l; + if (str && ( l = QMIN(qstrlen(str),maxlen) )) + { + m_data=(char *)malloc(l+1); + strncpy(m_data,str,l+1); + m_data[l]='\0'; + } + else + { + m_data=0; + } +} + +SCString::~SCString() +{ + if (m_data) free(m_data); + m_data=0; +} + +SCString &SCString::assign( const char *str ) +{ + if (m_data==str) return *this; + if (m_data) free(m_data); + duplicate(str); + return *this; +} + +bool SCString::resize( uint newlen ) +{ + if (newlen==0) + { + if (m_data) { free(m_data); m_data=0; } + return TRUE; + } + if (m_data==0) // newlen>0 + { + m_data = (char *)malloc(newlen); + } + else + { + m_data = (char *)realloc(m_data,newlen); + } + if (m_data==0) return FALSE; + m_data[newlen-1]='\0'; + return TRUE; +} + +bool SCString::fill( char c, int len ) +{ + uint l=length(); + if (len<0) len=l; + if ((uint)len!=l) + { + if (m_data) free(m_data); + if (len>0) + { + m_data=(char *)malloc(len+1); + if (m_data==0) return FALSE; + m_data[len]='\0'; + } + else + { + m_data=0; + } + } + if (len>0) + { + uint i; + for (i=0;i<(uint)len;i++) m_data[i]=c; + } + return TRUE; +} + +SCString &SCString::sprintf( const char *format, ... ) +{ + va_list ap; + va_start( ap, format ); + uint l = length(); + const uint minlen=4095; + if (l<minlen) + { + if (m_data) + m_data = (char *)realloc(m_data,minlen+1); + else + m_data = (char *)malloc(minlen+1); + m_data[minlen]='\0'; + } + vsnprintf( m_data, minlen, format, ap ); + resize( qstrlen(m_data) + 1 ); // truncate + va_end( ap ); + return *this; +} + + +int SCString::find( char c, int index, bool cs ) const +{ + uint len = length(); + if ( m_data==0 || (uint)index>len ) // index outside string + return -1; + register const char *d; + if ( cs ) // case sensitive + { + d = strchr( m_data+index, c ); + } + else + { + d = m_data+index; + c = tolower( (uchar) c ); + while ( *d && tolower((uchar) *d) != c ) + d++; + if ( !*d && c ) // not found + d = 0; + } + return d ? (int)(d - m_data) : -1; +} + +int SCString::find( const char *str, int index, bool cs ) const +{ + uint l = length(); + if ( m_data==0 || (uint)index > l ) // index outside string + return -1; + if ( !str ) // no search string + return -1; + if ( !*str ) // zero-length search string + return index; + register const char *d; + if ( cs ) // case sensitive + { + d = strstr( m_data+index, str ); + } + else // case insensitive + { + d = m_data+index; + int len = qstrlen( str ); + while ( *d ) + { + if ( qstrnicmp(d, str, len) == 0 ) + break; + d++; + } + if ( !*d ) // not found + d = 0; + } + return d ? (int)(d - m_data) : -1; +} + +int SCString::find( const QCString &str, int index, bool cs ) const +{ + return find(str.data(),index,cs); +} + +int SCString::find( const QRegExp &rx, int index ) const +{ + QString d = QString::fromLatin1( m_data ); + return d.find( rx, index ); +} + +int SCString::findRev( char c, int index, bool cs) const +{ + const char *b = m_data; + const char *d; + uint len = length(); + if ( b == 0 ) return -1; // empty string + if ( index < 0 ) // neg index ==> start from end + { + if ( len == 0 ) return -1; + if ( cs ) + { + d = strrchr( b, c ); + return d ? (int)(d - b) : -1; + } + index = len; + } + else if ( (uint)index > len ) // bad index + { + return -1; + } + d = b+index; + if ( cs ) // case sensitive + { + while ( d >= b && *d != c ) + d--; + } + else // case insensitive + { + c = tolower( (uchar) c ); + while ( d >= b && tolower((uchar) *d) != c ) + d--; + } + return d >= b ? (int)(d - b) : -1; +} + +int SCString::findRev( const char *str, int index, bool cs) const +{ + int slen = qstrlen(str); + uint len = length(); + if ( index < 0 ) // neg index ==> start from end + index = len-slen; + else if ( (uint)index > len ) // bad index + return -1; + else if ( (uint)(index + slen) > len ) // str would be too long + index = len - slen; + if ( index < 0 ) + return -1; + + register char *d = m_data + index; + if ( cs ) // case sensitive + { + for ( int i=index; i>=0; i-- ) + if ( qstrncmp(d--,str,slen)==0 ) + return i; + } + else // case insensitive + { + for ( int i=index; i>=0; i-- ) + if ( qstrnicmp(d--,str,slen)==0 ) + return i; + } + return -1; + +} + +int SCString::findRev( const QRegExp &rx, int index ) const +{ + QString d = QString::fromLatin1( m_data ); + return d.findRev( rx, index ); +} + +int SCString::contains( char c, bool cs ) const +{ + int count = 0; + char *d = m_data; + if ( !d ) + return 0; + if ( cs ) // case sensitive + { + while ( *d ) + if ( *d++ == c ) + count++; + } + else // case insensitive + { + c = tolower( (uchar) c ); + while ( *d ) { + if ( tolower((uchar) *d) == c ) + count++; + d++; + } + } + return count; +} + +int SCString::contains( const char *str, bool cs ) const +{ + int count = 0; + char *d = data(); + if ( !d ) + return 0; + int len = qstrlen( str ); + while ( *d ) // counts overlapping strings + { + if ( cs ) + { + if ( qstrncmp( d, str, len ) == 0 ) + count++; + } + else + { + if ( qstrnicmp(d, str, len) == 0 ) + count++; + } + d++; + } + return count; +} + +int SCString::contains( const QRegExp &rx ) const +{ + QString d = QString::fromLatin1( m_data ); + return d.contains( rx ); +} + +SCString SCString::left( uint len ) const +{ + if ( isEmpty() ) + { + return SCString(); + } + else if ( len >= length() ) + { + return *this; + } + else + { + SCString s( len+1 ); + strncpy( s.data(), m_data, len ); + *(s.data()+len) = '\0'; + return s; + } +} + +SCString SCString::right( uint len ) const +{ + if ( isEmpty() ) + { + return SCString(); + } + else + { + uint l = length(); + if ( len > l ) len = l; + char *p = m_data + (l - len); + return SCString( p ); + } +} + +SCString SCString::mid( uint index, uint len) const +{ + uint slen = length(); + if ( len == 0xffffffff ) len = slen-index; + if ( isEmpty() || index >= slen ) + { + return SCString(); + } + else + { + register char *p = data()+index; + SCString s( len+1 ); + strncpy( s.data(), p, len ); + *(s.data()+len) = '\0'; + return s; + } +} + +SCString SCString::lower() const +{ + SCString s( m_data ); + register char *p = s.data(); + if ( p ) + { + while ( *p ) + { + *p = tolower((uchar) *p); + p++; + } + } + return s; +} + +SCString SCString::upper() const +{ + SCString s( m_data ); + register char *p = s.data(); + if ( p ) { + while ( *p ) { + *p = toupper((uchar)*p); + p++; + } + } + return s; +} + +SCString SCString::stripWhiteSpace() const +{ + if ( isEmpty() ) // nothing to do + return *this; + + register char *s = m_data; + int reslen = length(); + if ( !isspace((uchar) s[0]) && !isspace((uchar) s[reslen-1]) ) + return *this; // returns a copy + + SCString result(s); + s = result.data(); + int start = 0; + int end = reslen - 1; + while ( isspace((uchar) s[start]) ) // skip white space from start + start++; + if ( s[start] == '\0' ) + { // only white space + return SCString(); + } + while ( end && isspace((uchar) s[end]) ) // skip white space from end + end--; + end -= start - 1; + memmove( result.data(), &s[start], end ); + result.resize( end + 1 ); + return result; +} + +SCString SCString::simplifyWhiteSpace() const +{ + if ( isEmpty() ) // nothing to do + return *this; + + SCString result( length()+1 ); + char *from = data(); + char *to = result.data(); + char *first = to; + while ( TRUE ) + { + while ( *from && isspace((uchar) *from) ) + from++; + while ( *from && !isspace((uchar)*from) ) + *to++ = *from++; + if ( *from ) + *to++ = 0x20; // ' ' + else + break; + } + if ( to > first && *(to-1) == 0x20 ) + to--; + *to = '\0'; + result.resize( (int)((long)to - (long)result.data()) + 1 ); + return result; +} + +SCString &SCString::insert( uint index, const char *s ) +{ + int len = qstrlen(s); + if ( len == 0 ) + return *this; + uint olen = length(); + int nlen = olen + len; + if ( index >= olen ) // insert after end of string + { + m_data = (char *)realloc(m_data,nlen+index-olen+1); + if ( m_data ) + { + memset( m_data+olen, ' ', index-olen ); + memcpy( m_data+index, s, len+1 ); + } + } + else if ( (m_data = (char *)realloc(m_data,nlen+1)) ) // normal insert + { + memmove( m_data+index+len, m_data+index, olen-index+1 ); + memcpy( m_data+index, s, len ); + } + return *this; +} + +SCString &SCString::insert( uint index, char c ) // insert char +{ + char buf[2]; + buf[0] = c; + buf[1] = '\0'; + return insert( index, buf ); +} + +SCString& SCString::operator+=( const char *str ) +{ + if ( !str ) return *this; // nothing to append + uint len1 = length(); + uint len2 = qstrlen(str); + char *newData = (char *)realloc( m_data, len1 + len2 + 1 ); + if (newData) + { + m_data = newData; + memcpy( m_data + len1, str, len2 + 1 ); + } + return *this; +} + +SCString &SCString::operator+=( char c ) +{ + uint len = length(); + char *newData = (char *)realloc( m_data, length()+2 ); + if (newData) + { + m_data = newData; + m_data[len] = c; + m_data[len+1] = '\0'; + } + return *this; +} + +SCString &SCString::remove( uint index, uint len ) +{ + uint olen = length(); + if ( index + len >= olen ) // range problems + { + if ( index < olen ) // index ok + { + resize( index+1 ); + } + } + else if ( len != 0 ) + { + memmove( m_data+index, m_data+index+len, olen-index-len+1 ); + resize( olen-len+1 ); + } + return *this; +} + +SCString &SCString::replace( uint index, uint len, const char *s ) +{ + remove( index, len ); + insert( index, s ); + return *this; +} + +SCString &SCString::replace( const QRegExp &rx, const char *str ) +{ + QString d = QString::fromLatin1( m_data ); + QString r = QString::fromLatin1( str ); + d.replace( rx, r ); + return assign(d.ascii()); +} + +long SCString::toLong( bool *ok ) const +{ + QString s(m_data); + return s.toLong(ok); +} + +ulong SCString::toULong( bool *ok ) const +{ + QString s(m_data); + return s.toULong(ok); +} + +short SCString::toShort( bool *ok ) const +{ + QString s(m_data); + return s.toShort(ok); +} + +ushort SCString::toUShort( bool *ok ) const +{ + QString s(m_data); + return s.toUShort(ok); +} + +int SCString::toInt( bool *ok ) const +{ + QString s(m_data); + return s.toInt(ok); +} + +uint SCString::toUInt( bool *ok ) const +{ + QString s(m_data); + return s.toUInt(ok); +} + +SCString &SCString::setNum( long n ) +{ + char buf[20]; + register char *p = &buf[19]; + bool neg; + if ( n < 0 ) + { + neg = TRUE; + n = -n; + } + else + { + neg = FALSE; + } + *p = '\0'; + do + { + *--p = ((int)(n%10)) + '0'; + n /= 10; + } while ( n ); + if ( neg ) *--p = '-'; + operator=( p ); + return *this; +} + +SCString &SCString::setNum( ulong n ) +{ + char buf[20]; + register char *p = &buf[19]; + *p = '\0'; + do + { + *--p = ((int)(n%10)) + '0'; + n /= 10; + } while ( n ); + operator=( p ); + return *this; +} + +void SCString::msg_index( uint index ) +{ +#if defined(CHECK_RANGE) + qWarning( "SCString::at: Absolute index %d out of range", index ); +#else + Q_UNUSED( index ) +#endif +} + +bool SCString::stripPrefix(const char *prefix) +{ + if (prefix==0) return FALSE; + uint plen = qstrlen(prefix); + if (m_data && qstrncmp(prefix,m_data,plen)==0) // prefix matches + { + uint len = qstrlen(m_data); + uint newlen = len-plen+1; + qmemmove(m_data,m_data+plen,newlen); + resize(newlen); + return TRUE; + } + return FALSE; +} + +//--------------------------------------------------------------------------- + +void *qmemmove( void *dst, const void *src, uint len ) +{ + register char *d; + register char *s; + if ( dst > src ) { + d = (char *)dst + len - 1; + s = (char *)src + len - 1; + while ( len-- ) + *d-- = *s--; + } else if ( dst < src ) { + d = (char *)dst; + s = (char *)src; + while ( len-- ) + *d++ = *s++; + } + return dst; +} + +char *qstrdup( const char *str ) +{ + if ( !str ) + return 0; + char *dst = new char[strlen(str)+1]; + CHECK_PTR( dst ); + return strcpy( dst, str ); +} + +char *qstrncpy( char *dst, const char *src, uint len ) +{ + if ( !src ) + return 0; + strncpy( dst, src, len ); + if ( len > 0 ) + dst[len-1] = '\0'; + return dst; +} + +int qstricmp( const char *str1, const char *str2 ) +{ + register const uchar *s1 = (const uchar *)str1; + register const uchar *s2 = (const uchar *)str2; + int res; + uchar c; + if ( !s1 || !s2 ) + return s1 == s2 ? 0 : (int)((long)s2 - (long)s1); + for ( ; !(res = (c=tolower(*s1)) - tolower(*s2)); s1++, s2++ ) + if ( !c ) // strings are equal + break; + return res; +} + +int qstrnicmp( const char *str1, const char *str2, uint len ) +{ + register const uchar *s1 = (const uchar *)str1; + register const uchar *s2 = (const uchar *)str2; + int res; + uchar c; + if ( !s1 || !s2 ) + return (int)((long)s2 - (long)s1); + for ( ; len--; s1++, s2++ ) { + if ( (res = (c=tolower(*s1)) - tolower(*s2)) ) + return res; + if ( !c ) // strings are equal + break; + } + return 0; +} + +#ifndef QT_NO_DATASTREAM + +QDataStream &operator<<( QDataStream &s, const QByteArray &a ) +{ + return s.writeBytes( a.data(), a.size() ); +} + +QDataStream &operator>>( QDataStream &s, QByteArray &a ) +{ + Q_UINT32 len; + s >> len; // read size of array + if ( len == 0 || s.eof() ) { // end of file reached + a.resize( 0 ); + return s; + } + if ( !a.resize( (uint)len ) ) { // resize array +#if defined(CHECK_NULL) + qWarning( "QDataStream: Not enough memory to read QByteArray" ); +#endif + len = 0; + } + if ( len > 0 ) // not null array + s.readRawBytes( a.data(), (uint)len ); + return s; +} + +QDataStream &operator<<( QDataStream &s, const SCString &str ) +{ + return s.writeBytes( str.data(), str.size() ); +} + +QDataStream &operator>>( QDataStream &s, SCString &str ) +{ + Q_UINT32 len; + s >> len; // read size of string + if ( len == 0 || s.eof() ) { // end of file reached + str.resize( 0 ); + return s; + } + if ( !str.resize( (uint)len )) {// resize string +#if defined(CHECK_NULL) + qWarning( "QDataStream: Not enough memory to read QCString" ); +#endif + len = 0; + } + if ( len > 0 ) // not null array + s.readRawBytes( str.data(), (uint)len ); + return s; +} + +#endif //QT_NO_DATASTREAM + + + +#endif diff --git a/trunk/qtools/scstring.h b/trunk/qtools/scstring.h new file mode 100644 index 0000000..a9b462c --- /dev/null +++ b/trunk/qtools/scstring.h @@ -0,0 +1,155 @@ +/****************************************************************************** + * + * Copyright (C) 1997-2004 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. + * + */ + +#ifndef SCSTRING_H +#define SCSTRING_H + +#include <stdlib.h> + +class QRegExp; + +/** This is an alternative implementation of QCString. It provides basically + * the same functions but uses less memory for administration. This class + * is just a wrapper around a plain C string requiring only 4 bytes "overhead". + * QCString features sharing of data and stores the string length, but + * requires 4 + 12 bytes for this (even for the empty string). As doxygen + * uses a LOT of string during a run it saves a lot of memory to use a + * more memory efficient implementation at the cost of relatively low + * runtime overhead. + */ +class SCString +{ +public: + SCString() : m_data(0) {} // make null string + SCString( const SCString &s ); + SCString( int size ); + SCString( const char *str ); + SCString( const char *str, uint maxlen ); + ~SCString(); + + SCString &operator=( const SCString &s );// deep copy + SCString &operator=( const char *str ); // deep copy + + bool isNull() const; + bool isEmpty() const; + uint length() const; + uint size() const { return m_data ? length()+1 : 0; } + char * data() const { return m_data; } + bool resize( uint newlen ); + bool truncate( uint pos ); + bool fill( char c, int len = -1 ); + + SCString copy() const; + + SCString &sprintf( const char *format, ... ); + + int find( char c, int index=0, bool cs=TRUE ) const; + int find( const char *str, int index=0, bool cs=TRUE ) const; + int find( const QRegExp &, int index=0 ) const; + int find( const QCString &str, int index, bool cs ) const; + int findRev( char c, int index=-1, bool cs=TRUE) const; + int findRev( const char *str, int index=-1, bool cs=TRUE) const; + int findRev( const QRegExp &, int index=-1 ) const; + int contains( char c, bool cs=TRUE ) const; + int contains( const char *str, bool cs=TRUE ) const; + int contains( const QRegExp & ) const; + bool stripPrefix(const char *prefix); + + SCString left( uint len ) const; + SCString right( uint len ) const; + SCString mid( uint index, uint len=0xffffffff) const; + + SCString lower() const; + SCString upper() const; + + SCString stripWhiteSpace() const; + SCString simplifyWhiteSpace() const; + + SCString &assign( const char *str ); + SCString &insert( uint index, const char * ); + SCString &insert( uint index, char ); + SCString &append( const char *s ); + SCString &prepend( const char *s ); + SCString &remove( uint index, uint len ); + SCString &replace( uint index, uint len, const char * ); + SCString &replace( const QRegExp &, const char * ); + + short toShort( bool *ok=0 ) const; + ushort toUShort( bool *ok=0 ) const; + int toInt( bool *ok=0 ) const; + uint toUInt( bool *ok=0 ) const; + long toLong( bool *ok=0 ) const; + ulong toULong( bool *ok=0 ) const; + + SCString &setNum( short ); + SCString &setNum( ushort ); + SCString &setNum( int ); + SCString &setNum( uint ); + SCString &setNum( long ); + SCString &setNum( ulong ); + QCString &setNum( float, char f='g', int prec=6 ); + QCString &setNum( double, char f='g', int prec=6 ); + + operator const char *() const; + SCString &operator+=( const char *str ); + SCString &operator+=( char c ); + char &at( uint index ) const; + char &operator[]( int i ) const { return at(i); } + + private: + static void msg_index( uint ); + void duplicate( const SCString &s ); + void duplicate( const char *str); + SCString &duplicate( const char *str, int); + + char * m_data; +}; + +inline char &SCString::at( uint index ) const +{ + return m_data[index]; +} + +inline void SCString::duplicate( const SCString &s ) +{ + if (!s.isEmpty()) + { + uint l = strlen(s.data()); + m_data = (char *)malloc(l+1); + if (m_data) memcpy(m_data,s.data(),l+1); + } + else + m_data=0; +} +inline void SCString::duplicate( const char *str) +{ + if (str && str[0]!='\0') + { + uint l = strlen(str); + m_data = (char *)malloc(l+1); + if (m_data) memcpy(m_data,str,l+1); + } + else + m_data=0; +} +inline SCString &SCString::duplicate( const char *str, int) +{ + if (m_data) free(m_data); + duplicate(str); + return *this; +} + +#endif + diff --git a/trunk/src/Makefile.in b/trunk/src/Makefile.in new file mode 100644 index 0000000..2ecffd2 --- /dev/null +++ b/trunk/src/Makefile.in @@ -0,0 +1,49 @@ + +# +# +# +# Copyright (C) 1997-2012 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. +# + +all: Makefile.libdoxygen Makefile.libdoxycfg Makefile.doxygen Makefile + $(MAKE) -f Makefile.libdoxycfg PERL=$(PERL) $@ + $(MAKE) -f Makefile.libdoxygen PERL=$(PERL) $@ + $(MAKE) -f Makefile.doxygen PERL=$(PERL) $@ + +Makefile.libdoxygen: libdoxygen.pro libdoxygen.t + $(ENV) $(PERL) $(TMAKE) libdoxygen.pro >Makefile.libdoxygen + +Makefile.libdoxycfg: libdoxycfg.pro libdoxycfg.t + $(ENV) $(PERL) $(TMAKE) libdoxycfg.pro >Makefile.libdoxycfg + +Makefile.doxygen: doxygen.pro + $(ENV) $(PERL) $(TMAKE) doxygen.pro >Makefile.doxygen + +tmake: + $(ENV) $(PERL) $(TMAKE) libdoxygen.pro >Makefile.libdoxygen + $(ENV) $(PERL) $(TMAKE) libdoxycfg.pro >Makefile.libdoxycfg + $(ENV) $(PERL) $(TMAKE) doxygen.pro >Makefile.doxygen + +clean: Makefile.libdoxygen Makefile.libdoxycfg Makefile.doxygen + $(MAKE) -f Makefile.libdoxygen clean + $(MAKE) -f Makefile.libdoxycfg clean + $(MAKE) -f Makefile.doxygen clean + +distclean: clean + -$(RM) scanner.cpp code.cpp config.cpp pre.cpp ce_lex.cpp \ + ce_parse.cpp ce_parse.h tag.cpp commentscan.cpp \ + declinfo.cpp defargs.cpp commentcnv.cpp doctokenizer.cpp \ + pycode.cpp pyscanner.cpp fortrancode.cpp fortranscanner.cpp \ + vhdlscanner.cpp vhdlcode.cpp tclscanner.cpp vhdlparser.h \ + vhdlparser.cpp + +FORCE: diff --git a/trunk/src/arguments.cpp b/trunk/src/arguments.cpp new file mode 100644 index 0000000..128223b --- /dev/null +++ b/trunk/src/arguments.cpp @@ -0,0 +1,17 @@ +#include "arguments.h" + +/*! the argument list is documented if one of its + * arguments is documented + */ +bool ArgumentList::hasDocumentation() const +{ + bool hasDocs=FALSE; + ArgumentListIterator ali(*this); + Argument *a; + for (ali.toFirst();!hasDocs && (a=ali.current());++ali) + { + hasDocs = a->hasDocumentation(); + } + return hasDocs; +} + diff --git a/trunk/src/arguments.h b/trunk/src/arguments.h new file mode 100644 index 0000000..c5ca942 --- /dev/null +++ b/trunk/src/arguments.h @@ -0,0 +1,99 @@ +/****************************************************************************** + * + * Copyright (C) 1997-2012 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. + * + */ + +#ifndef ARGUMENTS_H +#define ARGUMENTS_H + +#include "qtbc.h" +#include <qlist.h> + +/*! \brief This class contains the information about the argument of a + * function or template + * + */ +struct Argument +{ + /*! Construct a new argument. */ + Argument() {} + /*! Copy an argument (does a deep copy of all strings). */ + Argument(const Argument &a) + { + attrib=a.attrib.copy(); + type=a.type.copy(); + name=a.name.copy(); + defval=a.defval.copy(); + docs=a.docs.copy(); + array=a.array.copy(); + } + /*! Assignment of an argument (does a deep copy of all strings). */ + Argument &operator=(const Argument &a) + { + if (this!=&a) + { + attrib=a.attrib.copy(); + type=a.type.copy(); + name=a.name.copy(); + defval=a.defval.copy(); + docs=a.docs.copy(); + array=a.array.copy(); + } + return *this; + } + /*! return TRUE if this argument is documentation and the argument has a + * non empty name. + */ + bool hasDocumentation() const + { + return !name.isEmpty() && !docs.isEmpty(); + } + + QCString attrib; /*!< Argument's attribute (IDL only) */ + QCString type; /*!< Argument's type */ + QCString canType; /*!< Cached value of canonical type (after type resolution). Empty initially. */ + QCString name; /*!< Argument's name (may be empty) */ + QCString array; /*!< Argument's array specifier (may be empty) */ + QCString defval; /*!< Argument's default value (may be empty) */ + QCString docs; /*!< Argument's documentation (may be empty) */ +}; + +/*! \brief This class represents an function or template argument list. + * + * This class also stores some information about member that is typically + * put after the argument list, such as wether the member is const, + * volatile or pure virtual. + */ +class ArgumentList : public QList<Argument> +{ + public: + /*! Creates an empty argument list */ + ArgumentList() : QList<Argument>(), + constSpecifier(FALSE), + volatileSpecifier(FALSE), + pureSpecifier(FALSE) + { setAutoDelete(TRUE); } + /*! Destroys the argument list */ + ~ArgumentList() {} + bool hasDocumentation() const; + /*! Does the member modify the state of the class? default: FALSE. */ + bool constSpecifier; + /*! Is the member volatile? default: FALSE. */ + bool volatileSpecifier; + /*! Is this a pure virtual member? default: FALSE */ + bool pureSpecifier; +}; + +typedef QListIterator<Argument> ArgumentListIterator; + +#endif diff --git a/trunk/src/bib2xhtml.h b/trunk/src/bib2xhtml.h new file mode 100644 index 0000000..65e4ed4 --- /dev/null +++ b/trunk/src/bib2xhtml.h @@ -0,0 +1,290 @@ +"#\n" +"# Below is a stripped down version of bib2xhtml used by doxygen.\n" +"# For the full version see http://www.spinellis.gr/sw/textproc/bib2xhtml/\n" +"#\n" +"# Convert from bibtex to XHTML.\n" +"#\n" +"# (C) Copyright 1995, 1996 David Hull.\n" +"# (David Hull / hull@cs.uiuc.edu / http://www.uiuc.edu/ph/www/dlhull)\n" +"#\n" +"# (C) Copyright 2002-2010 Diomidis Spinellis\n" +"# http://www.spinellis.gr\n" +"#\n" +"# This program is free software. You can redistribute it and/or modify\n" +"# it under the terms of the GNU General Public License. See the\n" +"# files README and COPYING for details.\n" +"#\n" +"# This source code contains UTF-8 characters. You might want to use\n" +"# an appropriate editor, if you want to view/modify the LaTeX to Unicode\n" +"# substitution commands.\n" +"#\n" +"\n" +"use Getopt::Std;\n" +"use open IO => ':crlf';\n" +"$label_styles{'numbered'} = $LABEL_NUMBERED = 2;\n" +"$list_start[$LABEL_NUMBERED] = 'dl class=\"citelist\"';\n" +"$list_end[$LABEL_NUMBERED] = \"/dl\";\n" +"@tmpfiles = ();\n" +"sub html_ent {\n" +" s/\\\\i\\b/i/g;\n" +" s/\\\\\\'(\\001\\d+)\\{([AEIOUaeiou])\\1\\}/&$2acute;/gs;\n" +" s/\\\\\\'([AEIOUaeiou])/&$1acute;/g;\n" +" s/\\\\\\`(\\001\\d+)\\{([AEIOUaeiou])\\1\\}/&$2grave;/gs;\n" +" s/\\\\\\`([AEIOUaeiou])/&$1grave;/g;\n" +" s/\\\\\\\"(\\001\\d+)\\{([AEIOUaeiouy])\\1\\}/&$2uml;/gs;\n" +" s/\\\\\\\"([AEIOUaeiouy])/&$1uml;/g;\n" +" s/\\\\\\~(\\001\\d+)\\{([ANOano])\\1\\}/&$2tilde;/gs;\n" +" s/\\\\\\~([ANOano])/&$1tilde;/g;\n" +" s/\\\\\\^(\\001\\d+)\\{([AEIOUaeiou])\\1\\}/&$2circ;/gs;\n" +" s/\\\\\\^([AEIOUaeiou])/&$1circ;/g;\n" +" s/\\\\c(\\001\\d+)\\{([Cc])\\1\\}/&$2cedil;/gs;\n" +" s/\\\\u(\\001\\d+)\\{(.)\\1\\}/$2/gs;\n" +" s/\\\\v(\\001\\d+)\\{(.)\\1\\}/$2/gs;\n" +" s/\\\\([lL])\\b/$1/g;\n" +" s/\\\\\\=(\\001\\d+)\\{(.)\\1\\}/$2/gs;\n" +" s/\\\\\\=(.)/$1/g;\n" +" s/\\\\\\.(\\001\\d+)\\{(.)\\1\\}/$2/gs;\n" +" s/\\\\\\.(.)/$1/g;\n" +" s/\\\\([Oo])\\b\\s*/&$1slash;/g;\n" +" s/\\\\AA\\b\\s*/Å/g;\n" +" s/\\\\aa\\b\\s*/å/g;\n" +" s/\\\\AE\\b\\s*/Æ/g;\n" +" s/\\\\ae\\b\\s*/æ/g;\n" +" s/\\\\ss\\b\\s*/ß/g;\n" +" s/\\\\S\\b\\s*/§/g;\n" +" s/\\\\P\\b\\s*/¶/g;\n" +" s/\\\\pounds\\b\\s*/£/g;\n" +" s/\\?\\`/¿/g;\n" +" s/\\!\\`/¡/g;\n" +" s/\\-\\-\\-/—/g;\n" +" s/([^\\!])\\-\\-([^\\>])/$1–$2/g;\n" +" s/\\\\([aA]lpha)\\b/&$1;/g;\n" +" s/\\\\([bB]eta)\\b/&$1;/g;\n" +" s/\\\\([gG]amma)\\b/&$1;/g;\n" +" s/\\\\([dD]elta)\\b/&$1;/g;\n" +" s/\\\\varepsilon\\b/ε/g;\n" +" s/\\\\([eE]psilon)\\b/&$1;/g;\n" +" s/\\\\([zZ]eta)\\b/&$1;/g;\n" +" s/\\\\([eE]ta)\\b/&$1;/g;\n" +" s/\\\\([tT]heta)\\b/&$1;/g;\n" +" s/\\\\vartheta\\b/θ/g;\n" +" s/\\\\([iI]ota)\\b/&$1;/g;\n" +" s/\\\\([kK]appa)\\b/&$1;/g;\n" +" s/\\\\([lL]ambda)\\b/&$1;/g;\n" +" s/\\\\([mM]u)\\b/&$1;/g;\n" +" s/\\\\([nN]u)\\b/&$1;/g;\n" +" s/\\\\([xX]i)\\b/&$1;/g;\n" +" s/\\\\([oO]micron)\\b/&$1;/g;\n" +" s/\\\\([pP]i)\\b/&$1;/g;\n" +" s/\\\\varpi\\b/π/g;\n" +" s/\\\\([rR]ho)\\b/&$1;/g;\n" +" s/\\\\varrho\\b/ρ/g;\n" +" s/\\\\([sS]igma)\\b/&$1;/g;\n" +" s/\\\\varsigma\\b/ς/g;\n" +" s/\\\\([tT]au)\\b/&$1;/g;\n" +" s/\\\\([uU]psilon)\\b/&$1;/g;\n" +" s/\\\\([pP]hi)\\b/&$1;/g;\n" +" s/\\\\varphi\\b/φ/g;\n" +" s/\\\\([cC]hi)\\b/&$1;/g;\n" +" s/\\\\([pP]si)\\b/&$1;/g;\n" +" s/\\\\([oO]mega)\\b/&$1;/g;\n" +"}\n" +"foreach (@ARGV) {\n" +" if (/\\.bib$/) {\n" +" $bibfile = $_;\n" +" $bibfile =~ s/\\.bib$//;\n" +" push(@bibfiles,$bibfile);\n" +" } else {\n" +" $htmlfile = $_;\n" +" }\n" +"}\n" +"exit(1) unless defined($htmlfile);\n" +"$bibdatacmd=\"\\\\bibdata{\".join(',',@bibfiles).\"}\";\n" +"$label_style = $LABEL_NUMBERED;\n" +"$bstfile = \"doxygen\";\n" +"umask(077);\n" +"open(HTMLFILE,\">$htmlfile$$\");\n" +"if (open(OHTMLFILE, \"$htmlfile\")) {\n" +" $mode = (stat OHTMLFILE)[2] & 0xfff;\n" +"} else {\n" +" print \"Error opening $htmlfile\\n\";\n" +" exit(1);\n" +"}\n" +"$beginstring = \"<!-- BEGIN CITATIONS -->\";\n" +"$endstring = \"<!-- END CITATIONS -->\";\n" +"@citations = ();\n" +"loop:\n" +"while (<OHTMLFILE>) {\n" +" print HTMLFILE;\n" +" last loop if m/^$beginstring$/;\n" +"}\n" +"loop:\n" +"while (<OHTMLFILE>) {\n" +" print HTMLFILE;\n" +" last loop if m/^$endstring$/;\n" +" push(@citations, $2) if m/^([^\\\\]*)?(.+\\})(.*)?$/;\n" +"}\n" +"push(@citations, $bibdatacmd);\n" +"$auxfile = \"bib$$\";\n" +"push(@tmpfiles, \"$auxfile.aux\");\n" +"open(AUXFILE, \">$auxfile\" . \".aux\");\n" +"print AUXFILE \"\\\\relax\\n\\\\bibstyle{$bstfile}\\n\";\n" +"foreach $citation (@citations) {\n" +" print AUXFILE \"$citation\\n\";\n" +"}\n" +"close(AUXFILE);\n" +"push(@tmpfiles, \"$auxfile.blg\");\n" +"push(@tmpfiles, \"$auxfile.bbl\");\n" +"`bibtex $auxfile 2>&1`;\n" +"if ($?==-1)\n" +"{\n" +" print \"bibtex command failed: $!\\n\";\n" +"}\n" +"$beginstring = \"<!-- BEGIN BIBLIOGRAPHY -->\";\n" +"$endstring = \"<!-- END BIBLIOGRAPHY -->\";\n" +"loop:\n" +"while (<OHTMLFILE>) {\n" +" last loop if m/^$beginstring$/;\n" +" print HTMLFILE;\n" +"}\n" +"loop:\n" +"while (<OHTMLFILE>) {\n" +" last loop if m/^$endstring$/;\n" +"}\n" +"print HTMLFILE \"$beginstring\\n\";\n" +"$t = $auxfile . \".bbl\";\n" +"$/ = \"\";\n" +"open(BBLFILE, \"<$t\") || die \"error opening $t: $!\\n\";\n" +"$nentry = 0;\n" +"loop:\n" +"while (<BBLFILE>) {\n" +" if (($nentry == 0) && (m/^#/)) {\n" +" if ((m/#\\s*label-style:\\s*(\\S+)/) && (! defined $label_style)) {\n" +" $label_style = $label_styles{$1};\n" +" if (! defined $label_style) {\n" +" print STDERR \"label style unknown: \\n\";\n" +" next loop;\n" +" }\n" +" }\n" +" next loop;\n" +" }\n" +" $nentry++;\n" +" ($bcite, $blabel) = m+<dt><a name=\\\"([^\\\"]*)\\\">\\[([^\\]]*)\\]</a></dt><dd>+;\n" +" $blabel = \"$nentry\";\n" +" $bibcite{$bcite} = $blabel;\n" +"}\n" +"close(BBLFILE);\n" +"$label_style = $LABEL_DEFAULT if (! defined $label_style);\n" +"$list_start = $list_start[$label_style];\n" +"$list_end = $list_end[$label_style];\n" +"print HTMLFILE \"<$list_start>\\n\\n\";\n" +"open(BBLFILE, \"<$t\") || die \"error opening $t: $!\\n\";\n" +"$nentry = 0;\n" +"loop:\n" +"while (<BBLFILE>) {\n" +" next loop if (($nentry == 0) && (m/^#/));\n" +" $nentry++;\n" +" s/\\\\\\{/\\002/g;\n" +" s/\\\\\\}/\\003/g;\n" +" s/\\\\\\$/\\004/g;\n" +" {\n" +" local ($c, $l, $z) = (0, 0, ());\n" +" s/([\\{\\}])/join(\"\",\"\\001\",($1 eq \"\\{\" ? $z[$l++]=$c++ : $z[--$l]),$1)/ge;\n" +" }\n" +" s/\\%\\n//g;\n" +" s/(\\.(<\\/cite>|<\\/a>|\\')+)\\./$1/g;\n" +" s:(<dt><a name=\\\"[^\\\"]*\\\">\\[)[^\\]]*(\\]</a></dt><dd>):$1$nentry$2:;\n" +" while (m/(\\\\(cite(label)?)(\\001\\d+)\\{([^\\001]+)\\4\\})/) {\n" +" $old = $1;\n" +" $cmd = $2;\n" +" $doxref = defined($3);\n" +" $bcite = $5;\n" +" if (! defined $bibcite{$bcite}) {\n" +" $blabel = \" [\" . $bcite . \"]\";\n" +" } elsif ($doxref) {\n" +" $blabel = \" <a href=\\\"#$bcite\\\">[\" . $bibcite{$bcite} . \"]<\\/a>\";\n" +" } else {\n" +" $blabel = \" [\" . $bibcite{$bcite} . \"]\";\n" +" }\n" +" $old =~ s/(\\W)/\\\\$1/g;\n" +" s/\\s*$old/$blabel/g;\n" +" }\n" +" s/In (<a href=\\\"[^\\\"]*\\\">)([^\\[]+) \\[(\\2)/In $1\\[$2/;\n" +" s/\\\\htmladdnormallink(foot)?(\\001\\d+)\\{([^\\001]+)\\2\\}(\\001\\d+)\\{([^\\001]+)\\4\\}/<a href=\"$5\">$3<\\/a>/gs;\n" +" s/\\&/\\005/g;\n" +" s/\\\\?&/&/g;\n" +" s/\\005/&/g;\n" +" html_ent();\n" +" while (m/\\\\char([\\'\\\"]?[0-9a-fA-F]+)/) {\n" +" $o = $r = $1;\n" +" if ($r =~ s/^\\'//) {\n" +" $r = oct($r);\n" +" } elsif ($r =~ s/^\\\"//) {\n" +" $r = hex($r);\n" +" }\n" +" s/\\\\char$o\\s*/&#$r;/g;\n" +" }\n" +" s/{\\\\etalchar\\001(\\d+)\\{(.)}\\001\\1\\}/$2/g;\n" +" s/\\\\par\\b/<p \\/>/g;\n" +" s/\\\\url(\\001\\d+)\\{(.*)\\1\\}/<a href=\"$2\">$2<\\/a>/gs;\n" +" s/\\\\href(\\001\\d+)\\{(.*)\\1\\}(\\001\\d+)\\{([^\\001]*)\\3\\}/<a href=\"$2\">$4<\\/a>/gs;\n" +" s/\\\\href(\\001\\d+)\\{(.*)\\1\\}/<a href=\"$2\">$2<\\/a>/gs;\n" +" s/(\\001\\d+)\\{\\\\rm\\s+(.*)\\1\\}/$2/gs;\n" +" s/\\\\textrm(\\001\\d+)\\{(.*)\\1\\}/$2/gs;\n" +" s/(\\001\\d+)\\{\\\\em\\s+(.*)\\1\\}/<em>$2<\\/em>/gs;\n" +" s/(\\001\\d+)\\{\\\\it\\s+(.*)\\1\\}/<i>$2<\\/i>/gs;\n" +" s/(\\001\\d+)\\{\\\\bf\\s+(.*)\\1\\}/<b>$2<\\/b>/gs;\n" +" s/(\\001\\d+)\\{\\\\tt\\s+(.*)\\1\\}/<tt>$2<\\/tt>/gs;\n" +" s/\\\\emph(\\001\\d+)\\{(.*)\\1\\}/<em>$2<\\/em>/gs;\n" +" s/\\\\textit(\\001\\d+)\\{(.*)\\1\\}/<i>$2<\\/i>/gs;\n" +" s/\\\\textbf(\\001\\d+)\\{(.*)\\1\\}/<b>$2<\\/b>/gs;\n" +" s/\\\\texttt(\\001\\d+)\\{(.*)\\1\\}/<tt>$2<\\/tt>/gs;\n" +" s/\\\\mathrm(\\001\\d+)\\{(.*)\\1\\}/$2/gs;\n" +" s/\\\\mathnormal(\\001\\d+)\\{(.*)\\1\\}/$2/gs;\n" +" s/\\\\mathsf(\\001\\d+)\\{(.*)\\1\\}/$2/gs;\n" +" s/\\\\mathbf(\\001\\d+)\\{(.*)\\1\\}/<b>$2<\\/b>/gs;\n" +" s/\\\\mathcal(\\001\\d+)\\{(.*)\\1\\}/<i>$2<\\/i>/gs;\n" +" s/\\\\mathit(\\001\\d+)\\{(.*)\\1\\}/<i>$2<\\/i>/gs;\n" +" s/\\\\mathtt(\\001\\d+)\\{(.*)\\1\\}/<tt>$2<\\/tt>/gs;\n" +" s/\\\\bibxhtmlname(\\001\\d+)\\{(.*)\\1\\}/$2/ges;\n" +" sub domath {\n" +" local($t) = @_;\n" +" $t =~ s/\\^(\\001\\d+)\\{\\\\circ\\1\\}/\\&\\#176;/gs;\n" +" $t =~ s/\\^\\\\circ/\\&\\#176;/g;\n" +" $t =~ s/\\^(\\001\\d+)\\{(.*)\\1\\}/<sup>$2<\\/sup>/gs;\n" +" $t =~ s/\\^(\\w)/<sup>$1<\\/sup>/g;\n" +" $t =~ s/\\_(\\001\\d+)\\{(.*)\\1\\}/<sub>$2<\\/sub>/gs;\n" +" $t =~ s/\\_(\\w)/<sub>$1<\\/sub>/g;\n" +" $t;\n" +" }\n" +" s/(\\$([^\\$]+)\\$)/&domath($2)/ge;\n" +" s/(\\\\\\((([^\\\\]|\\\\[^\\(\\)])+)\\\\\\))/&domath($2)/ge;\n" +" s/\\\\mbox(\\001\\d+)\\{(.*)\\1\\}/$2/gs;\n" +" while (s/(\\<a href\\=\\\"[^\"]*?)\\~/$1\\005/g) { ; }\n" +" s/([^\\\\])~/$1 /g;\n" +" s/\\\\\\,/ /g;\n" +" s/\\\\ldots\\b/…/g;\n" +" s/\\\\dots\\b/…/g;\n" +" s/\\005/\\~/g;\n" +" s/\\\\ / /g;\n" +" s/\\\\textasciitilde\\b\\s*/~/g;\n" +" s/\\\\([\\#\\&\\%\\~\\_\\^\\|])/$1/g;\n" +" s/\\\\\\W//g;\n" +" s/\\001(\\d+)\\{\\\\[A-Za-z]+\\001(\\d+)\\{([^\\001]*)\\001\\2\\}\\001\\1\\}/$3/g;\n" +" s/\\\\([A-Za-z]+)/ $1 /g;\n" +" s+In <a href=\\\"[^\\\"]*\\\"></a>++;\n" +" s/\\001\\d+[\\{\\}]//gs;\n" +" tr/\\002\\003\\004/{}$/;\n" +" print HTMLFILE $_;\n" +"}\n" +"close(BBLFILE);\n" +"print HTMLFILE \"<$list_end>\\n\\n$endstring\\n\";\n" +"while (<OHTMLFILE>) {\n" +" print HTMLFILE;\n" +"}\n" +"close (OHTMLFILE);\n" +"close(HTMLFILE);\n" +"chmod($mode, \"$htmlfile$$\");\n" +"rename(\"$htmlfile$$\", $htmlfile);\n" +"unlink(@tmpfiles);\n" +"exit(0);\n" diff --git a/trunk/src/bib2xhtml.pl b/trunk/src/bib2xhtml.pl new file mode 100755 index 0000000..146435f --- /dev/null +++ b/trunk/src/bib2xhtml.pl @@ -0,0 +1,290 @@ +# +# Below is a stripped down version of bib2xhtml used by doxygen. +# For the full version see http://www.spinellis.gr/sw/textproc/bib2xhtml/ +# +# Convert from bibtex to XHTML. +# +# (C) Copyright 1995, 1996 David Hull. +# (David Hull / hull@cs.uiuc.edu / http://www.uiuc.edu/ph/www/dlhull) +# +# (C) Copyright 2002-2010 Diomidis Spinellis +# http://www.spinellis.gr +# +# This program is free software. You can redistribute it and/or modify +# it under the terms of the GNU General Public License. See the +# files README and COPYING for details. +# +# This source code contains UTF-8 characters. You might want to use +# an appropriate editor, if you want to view/modify the LaTeX to Unicode +# substitution commands. +# + +use Getopt::Std; +use open IO => ':crlf'; +$label_styles{'numbered'} = $LABEL_NUMBERED = 2; +$list_start[$LABEL_NUMBERED] = 'dl class="citelist"'; +$list_end[$LABEL_NUMBERED] = "/dl"; +@tmpfiles = (); +sub html_ent { + s/\\i\b/i/g; + s/\\\'(\001\d+)\{([AEIOUaeiou])\1\}/&$2acute;/gs; + s/\\\'([AEIOUaeiou])/&$1acute;/g; + s/\\\`(\001\d+)\{([AEIOUaeiou])\1\}/&$2grave;/gs; + s/\\\`([AEIOUaeiou])/&$1grave;/g; + s/\\\"(\001\d+)\{([AEIOUaeiouy])\1\}/&$2uml;/gs; + s/\\\"([AEIOUaeiouy])/&$1uml;/g; + s/\\\~(\001\d+)\{([ANOano])\1\}/&$2tilde;/gs; + s/\\\~([ANOano])/&$1tilde;/g; + s/\\\^(\001\d+)\{([AEIOUaeiou])\1\}/&$2circ;/gs; + s/\\\^([AEIOUaeiou])/&$1circ;/g; + s/\\c(\001\d+)\{([Cc])\1\}/&$2cedil;/gs; + s/\\u(\001\d+)\{(.)\1\}/$2/gs; + s/\\v(\001\d+)\{(.)\1\}/$2/gs; + s/\\([lL])\b/$1/g; + s/\\\=(\001\d+)\{(.)\1\}/$2/gs; + s/\\\=(.)/$1/g; + s/\\\.(\001\d+)\{(.)\1\}/$2/gs; + s/\\\.(.)/$1/g; + s/\\([Oo])\b\s*/&$1slash;/g; + s/\\AA\b\s*/Å/g; + s/\\aa\b\s*/å/g; + s/\\AE\b\s*/Æ/g; + s/\\ae\b\s*/æ/g; + s/\\ss\b\s*/ß/g; + s/\\S\b\s*/§/g; + s/\\P\b\s*/¶/g; + s/\\pounds\b\s*/£/g; + s/\?\`/¿/g; + s/\!\`/¡/g; + s/\-\-\-/—/g; + s/([^\!])\-\-([^\>])/$1–$2/g; + s/\\([aA]lpha)\b/&$1;/g; + s/\\([bB]eta)\b/&$1;/g; + s/\\([gG]amma)\b/&$1;/g; + s/\\([dD]elta)\b/&$1;/g; + s/\\varepsilon\b/ε/g; + s/\\([eE]psilon)\b/&$1;/g; + s/\\([zZ]eta)\b/&$1;/g; + s/\\([eE]ta)\b/&$1;/g; + s/\\([tT]heta)\b/&$1;/g; + s/\\vartheta\b/θ/g; + s/\\([iI]ota)\b/&$1;/g; + s/\\([kK]appa)\b/&$1;/g; + s/\\([lL]ambda)\b/&$1;/g; + s/\\([mM]u)\b/&$1;/g; + s/\\([nN]u)\b/&$1;/g; + s/\\([xX]i)\b/&$1;/g; + s/\\([oO]micron)\b/&$1;/g; + s/\\([pP]i)\b/&$1;/g; + s/\\varpi\b/π/g; + s/\\([rR]ho)\b/&$1;/g; + s/\\varrho\b/ρ/g; + s/\\([sS]igma)\b/&$1;/g; + s/\\varsigma\b/ς/g; + s/\\([tT]au)\b/&$1;/g; + s/\\([uU]psilon)\b/&$1;/g; + s/\\([pP]hi)\b/&$1;/g; + s/\\varphi\b/φ/g; + s/\\([cC]hi)\b/&$1;/g; + s/\\([pP]si)\b/&$1;/g; + s/\\([oO]mega)\b/&$1;/g; +} +foreach (@ARGV) { + if (/\.bib$/) { + $bibfile = $_; + $bibfile =~ s/\.bib$//; + push(@bibfiles,$bibfile); + } else { + $htmlfile = $_; + } +} +exit(1) unless defined($htmlfile); +$bibdatacmd="\\bibdata{".join(',',@bibfiles)."}"; +$label_style = $LABEL_NUMBERED; +$bstfile = "doxygen"; +umask(077); +open(HTMLFILE,">$htmlfile$$"); +if (open(OHTMLFILE, "$htmlfile")) { + $mode = (stat OHTMLFILE)[2] & 0xfff; +} else { + print "Error opening $htmlfile\n"; + exit(1); +} +$beginstring = "<!-- BEGIN CITATIONS -->"; +$endstring = "<!-- END CITATIONS -->"; +@citations = (); +loop: +while (<OHTMLFILE>) { + print HTMLFILE; + last loop if m/^$beginstring$/; +} +loop: +while (<OHTMLFILE>) { + print HTMLFILE; + last loop if m/^$endstring$/; + push(@citations, $2) if m/^([^\\]*)?(.+\})(.*)?$/; +} +push(@citations, $bibdatacmd); +$auxfile = "bib$$"; +push(@tmpfiles, "$auxfile.aux"); +open(AUXFILE, ">$auxfile" . ".aux"); +print AUXFILE "\\relax\n\\bibstyle{$bstfile}\n"; +foreach $citation (@citations) { + print AUXFILE "$citation\n"; +} +close(AUXFILE); +push(@tmpfiles, "$auxfile.blg"); +push(@tmpfiles, "$auxfile.bbl"); +`bibtex $auxfile 2>&1`; +if ($?==-1) +{ + print "bibtex command failed: $!\n"; +} +$beginstring = "<!-- BEGIN BIBLIOGRAPHY -->"; +$endstring = "<!-- END BIBLIOGRAPHY -->"; +loop: +while (<OHTMLFILE>) { + last loop if m/^$beginstring$/; + print HTMLFILE; +} +loop: +while (<OHTMLFILE>) { + last loop if m/^$endstring$/; +} +print HTMLFILE "$beginstring\n"; +$t = $auxfile . ".bbl"; +$/ = ""; +open(BBLFILE, "<$t") || die "error opening $t: $!\n"; +$nentry = 0; +loop: +while (<BBLFILE>) { + if (($nentry == 0) && (m/^#/)) { + if ((m/#\s*label-style:\s*(\S+)/) && (! defined $label_style)) { + $label_style = $label_styles{$1}; + if (! defined $label_style) { + print STDERR "label style unknown: \n"; + next loop; + } + } + next loop; + } + $nentry++; + ($bcite, $blabel) = m+<dt><a name=\"([^\"]*)\">\[([^\]]*)\]</a></dt><dd>+; + $blabel = "$nentry"; + $bibcite{$bcite} = $blabel; +} +close(BBLFILE); +$label_style = $LABEL_DEFAULT if (! defined $label_style); +$list_start = $list_start[$label_style]; +$list_end = $list_end[$label_style]; +print HTMLFILE "<$list_start>\n\n"; +open(BBLFILE, "<$t") || die "error opening $t: $!\n"; +$nentry = 0; +loop: +while (<BBLFILE>) { + next loop if (($nentry == 0) && (m/^#/)); + $nentry++; + s/\\\{/\002/g; + s/\\\}/\003/g; + s/\\\$/\004/g; + { + local ($c, $l, $z) = (0, 0, ()); + s/([\{\}])/join("","\001",($1 eq "\{" ? $z[$l++]=$c++ : $z[--$l]),$1)/ge; + } + s/\%\n//g; + s/(\.(<\/cite>|<\/a>|\')+)\./$1/g; + s:(<dt><a name=\"[^\"]*\">\[)[^\]]*(\]</a></dt><dd>):$1$nentry$2:; + while (m/(\\(cite(label)?)(\001\d+)\{([^\001]+)\4\})/) { + $old = $1; + $cmd = $2; + $doxref = defined($3); + $bcite = $5; + if (! defined $bibcite{$bcite}) { + $blabel = " [" . $bcite . "]"; + } elsif ($doxref) { + $blabel = " <a href=\"#$bcite\">[" . $bibcite{$bcite} . "]<\/a>"; + } else { + $blabel = " [" . $bibcite{$bcite} . "]"; + } + $old =~ s/(\W)/\\$1/g; + s/\s*$old/$blabel/g; + } + s/In (<a href=\"[^\"]*\">)([^\[]+) \[(\2)/In $1\[$2/; + s/\\htmladdnormallink(foot)?(\001\d+)\{([^\001]+)\2\}(\001\d+)\{([^\001]+)\4\}/<a href="$5">$3<\/a>/gs; + s/\&/\005/g; + s/\\?&/&/g; + s/\005/&/g; + html_ent(); + while (m/\\char([\'\"]?[0-9a-fA-F]+)/) { + $o = $r = $1; + if ($r =~ s/^\'//) { + $r = oct($r); + } elsif ($r =~ s/^\"//) { + $r = hex($r); + } + s/\\char$o\s*/&#$r;/g; + } + s/{\\etalchar\001(\d+)\{(.)}\001\1\}/$2/g; + s/\\par\b/<p \/>/g; + s/\\url(\001\d+)\{(.*)\1\}/<a href="$2">$2<\/a>/gs; + s/\\href(\001\d+)\{(.*)\1\}(\001\d+)\{([^\001]*)\3\}/<a href="$2">$4<\/a>/gs; + s/\\href(\001\d+)\{(.*)\1\}/<a href="$2">$2<\/a>/gs; + s/(\001\d+)\{\\rm\s+(.*)\1\}/$2/gs; + s/\\textrm(\001\d+)\{(.*)\1\}/$2/gs; + s/(\001\d+)\{\\em\s+(.*)\1\}/<em>$2<\/em>/gs; + s/(\001\d+)\{\\it\s+(.*)\1\}/<i>$2<\/i>/gs; + s/(\001\d+)\{\\bf\s+(.*)\1\}/<b>$2<\/b>/gs; + s/(\001\d+)\{\\tt\s+(.*)\1\}/<tt>$2<\/tt>/gs; + s/\\emph(\001\d+)\{(.*)\1\}/<em>$2<\/em>/gs; + s/\\textit(\001\d+)\{(.*)\1\}/<i>$2<\/i>/gs; + s/\\textbf(\001\d+)\{(.*)\1\}/<b>$2<\/b>/gs; + s/\\texttt(\001\d+)\{(.*)\1\}/<tt>$2<\/tt>/gs; + s/\\mathrm(\001\d+)\{(.*)\1\}/$2/gs; + s/\\mathnormal(\001\d+)\{(.*)\1\}/$2/gs; + s/\\mathsf(\001\d+)\{(.*)\1\}/$2/gs; + s/\\mathbf(\001\d+)\{(.*)\1\}/<b>$2<\/b>/gs; + s/\\mathcal(\001\d+)\{(.*)\1\}/<i>$2<\/i>/gs; + s/\\mathit(\001\d+)\{(.*)\1\}/<i>$2<\/i>/gs; + s/\\mathtt(\001\d+)\{(.*)\1\}/<tt>$2<\/tt>/gs; + s/\\bibxhtmlname(\001\d+)\{(.*)\1\}/$2/ges; + sub domath { + local($t) = @_; + $t =~ s/\^(\001\d+)\{\\circ\1\}/\&\#176;/gs; + $t =~ s/\^\\circ/\&\#176;/g; + $t =~ s/\^(\001\d+)\{(.*)\1\}/<sup>$2<\/sup>/gs; + $t =~ s/\^(\w)/<sup>$1<\/sup>/g; + $t =~ s/\_(\001\d+)\{(.*)\1\}/<sub>$2<\/sub>/gs; + $t =~ s/\_(\w)/<sub>$1<\/sub>/g; + $t; + } + s/(\$([^\$]+)\$)/&domath($2)/ge; + s/(\\\((([^\\]|\\[^\(\)])+)\\\))/&domath($2)/ge; + s/\\mbox(\001\d+)\{(.*)\1\}/$2/gs; + while (s/(\<a href\=\"[^"]*?)\~/$1\005/g) { ; } + s/([^\\])~/$1 /g; + s/\\\,/ /g; + s/\\ldots\b/…/g; + s/\\dots\b/…/g; + s/\005/\~/g; + s/\\ / /g; + s/\\textasciitilde\b\s*/~/g; + s/\\([\#\&\%\~\_\^\|])/$1/g; + s/\\\W//g; + s/\001(\d+)\{\\[A-Za-z]+\001(\d+)\{([^\001]*)\001\2\}\001\1\}/$3/g; + s/\\([A-Za-z]+)/ $1 /g; + s+In <a href=\"[^\"]*\"></a>++; + s/\001\d+[\{\}]//gs; + tr/\002\003\004/{}$/; + print HTMLFILE $_; +} +close(BBLFILE); +print HTMLFILE "<$list_end>\n\n$endstring\n"; +while (<OHTMLFILE>) { + print HTMLFILE; +} +close (OHTMLFILE); +close(HTMLFILE); +chmod($mode, "$htmlfile$$"); +rename("$htmlfile$$", $htmlfile); +unlink(@tmpfiles); +exit(0); diff --git a/trunk/src/bufstr.h b/trunk/src/bufstr.h new file mode 100644 index 0000000..2945b5b --- /dev/null +++ b/trunk/src/bufstr.h @@ -0,0 +1,118 @@ +/****************************************************************************** + * + * + * + * + * Copyright (C) 1997-2012 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. + * + */ +#ifndef _BUFSTR_H +#define _BUFSTR_H + +#include "qtbc.h" +#include <stdio.h> +#include <stdlib.h> + +/*! @brief Buffer used to store strings + * + * This buffer is used append characters and strings. It will automatically + * resize itself, yet provide efficient random access to the content. + */ +class BufStr +{ + public: + BufStr(int size) + : m_size(size), m_writeOffset(0), m_spareRoom(10240), m_buf(0) + { + m_buf = (char *)malloc(size); + } + ~BufStr() + { + free(m_buf); + } + void addChar(char c) + { + makeRoomFor(1); + m_buf[m_writeOffset++]=c; + } + void addArray(const char *a,int len) + { + makeRoomFor(len); + memcpy(m_buf+m_writeOffset,a,len); + m_writeOffset+=len; + } + void skip(uint s) + { + makeRoomFor(s); + m_writeOffset+=s; + } + void shrink( uint newlen ) + { + m_writeOffset=newlen; + resize(newlen); + } + void resize( uint newlen ) + { + m_size=newlen; + if (m_writeOffset>=m_size) // offset out of range -> enlarge + { + m_size=m_writeOffset+m_spareRoom; + } + m_buf = (char *)realloc(m_buf,m_size); + } + int size() const + { + return m_size; + } + char *data() const + { + return m_buf; + } + char &at(uint i) const + { + return m_buf[i]; + } + bool isEmpty() const + { + return m_writeOffset==0; + } + operator const char *() const + { + return m_buf; + } + uint curPos() const + { + return m_writeOffset; + } + void dropFromStart(uint bytes) + { + if (bytes>m_size) bytes=m_size; + if (bytes>0) qmemmove(m_buf,m_buf+bytes,m_size-bytes); + m_size-=bytes; + m_writeOffset-=bytes; + } + private: + void makeRoomFor(uint size) + { + if (m_writeOffset+size>=m_size) + { + resize(m_size+size+m_spareRoom); + } + } + uint m_size; + uint m_writeOffset; + const int m_spareRoom; // 10Kb extra room to avoid frequent resizing + char *m_buf; +}; + + +#endif diff --git a/trunk/src/cite.cpp b/trunk/src/cite.cpp new file mode 100644 index 0000000..96e88ae --- /dev/null +++ b/trunk/src/cite.cpp @@ -0,0 +1,254 @@ +/****************************************************************************** + * + * Copyright (C) 2011 by Dimitri van Heesch + * Based on a patch by David Munger + * + * 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. + * + */ + +#include "cite.h" +#include "portable.h" +#include "config.h" +#include "message.h" +#include "util.h" +#include "language.h" +#include "ftextstream.h" +#include <qdir.h> + +//-------------------------------------------------------------------------- + +static const char *doxygen_bst = +#include "doxygen_bst.h" +; + +static const char *bib2xhtml_pl = +#include "bib2xhtml.h" +; + +//-------------------------------------------------------------------------- + +const QCString CiteConsts::fileName("citelist"); +const QCString CiteConsts::anchorPrefix("CITEREF_"); + +//-------------------------------------------------------------------------- + +CiteDict::CiteDict(int size) : m_entries(size, FALSE) +{ + m_entries.setAutoDelete(TRUE); +} + +static QCString getListOfBibFiles(const QCString &sep,bool stripExtension) +{ + QCString result; + QStrList &citeDataList = Config_getList("CITE_BIB_FILES"); + const char *bibdata = citeDataList.first(); + while (bibdata) + { + int i; + QCString bibFile = bibdata; + if (stripExtension && bibFile.right(4)==".bib") + { + bibFile = bibFile.left(bibFile.length()-4); + } + if (stripExtension && (i=bibFile.findRev('/'))!=-1) + { + bibFile = bibFile.mid(i+1); + } + if (!bibFile.isEmpty()) + { + result+=bibFile; + bibdata = citeDataList.next(); + if (bibdata) + { + result+=sep; + } + } + else + { + bibdata = citeDataList.next(); + } + } + return result; +} + +void CiteDict::writeLatexBibliography(FTextStream &t) +{ + if (m_entries.count()==0) return; + QCString style = Config_getString("LATEX_BIB_STYLE"); + if (style.isEmpty()) style="plain"; + t << "\\newpage \\bibliographystyle{" << style << "}" << endl; + t << "\\bibliography{" << getListOfBibFiles(",",TRUE) << "}" << endl; +} + +void CiteDict::insert(const char *label) +{ + m_entries.insert(label,new CiteInfo(label)); +} + +CiteInfo *CiteDict::find(const char *label) const +{ + return label ? m_entries.find(label) : 0; +} + +void CiteDict::clear() +{ + m_entries.clear(); +} + +bool CiteDict::isEmpty() const +{ + QStrList &citeBibFiles = Config_getList("CITE_BIB_FILES"); + return (citeBibFiles.count()==0 || m_entries.isEmpty()); +} + +void CiteDict::generatePage() const +{ + //printf("** CiteDict::generatePage() count=%d\n",m_ordering.count()); + + // do not generate an empty citations page + if (isEmpty()) return; // nothing to cite + + // 1. generate file with markers and citations to OUTPUT_DIRECTORY + QFile f; + QCString outputDir = Config_getString("OUTPUT_DIRECTORY"); + QCString citeListFile = outputDir+"/citelist.doc"; + f.setName(citeListFile); + if (!f.open(IO_WriteOnly)) + { + err("error: could not open file %s for writing\n",citeListFile.data()); + } + FTextStream t(&f); + t << "<!-- BEGIN CITATIONS -->" << endl; + t << "<!--" << endl; + QDictIterator<CiteInfo> it(m_entries); + CiteInfo *ci; + for (it.toFirst();(ci=it.current());++it) + { + t << "\\citation{" << ci->label << "}" << endl; + } + t << "-->" << endl; + t << "<!-- END CITATIONS -->" << endl; + t << "<!-- BEGIN BIBLIOGRAPHY -->" << endl; + t << "<!-- END BIBLIOGRAPHY -->" << endl; + f.close(); + + // 2. generate bib2xhtml + QCString bib2xhtmlFile = outputDir+"/bib2xhtml.pl"; + f.setName(bib2xhtmlFile); + QCString bib2xhtml = bib2xhtml_pl; + if (!f.open(IO_WriteOnly)) + { + err("error: could not open file %s for writing\n",bib2xhtmlFile.data()); + } + f.writeBlock(bib2xhtml, bib2xhtml.length()); + f.close(); + + // 3. generate doxygen.bst + QCString doxygenBstFile = outputDir+"/doxygen.bst"; + QCString bstData = doxygen_bst; + f.setName(doxygenBstFile); + if (!f.open(IO_WriteOnly)) + { + err("error: could not open file %s for writing\n",doxygenBstFile.data()); + } + f.writeBlock(bstData, bstData.length()); + f.close(); + + // 4. run bib2xhtml perl script on the generated file which will insert the + // bibliography in citelist.doc + portable_system("perl",bib2xhtmlFile+" "+getListOfBibFiles(" ",FALSE)+" "+ + citeListFile); + + // 5. read back the file + f.setName(citeListFile); + if (!f.open(IO_ReadOnly)) + { + err("error: could not open file %s/citelist.doc for reading\n",outputDir.data()); + } + bool insideBib=FALSE; + + QCString doc; + QFileInfo fi(citeListFile); + QCString input(fi.size()+1); + f.readBlock(input.data(),fi.size()); + input.at(fi.size())='\0'; + int p=0,s; + //printf("input=[%s]\n",input.data()); + while ((s=input.find('\n',p))!=-1) + { + QCString line = input.mid(p,s-p); + //printf("p=%d s=%d line=[%s]\n",p,s,line.data()); + p=s+1; + + if (line.find("<!-- BEGIN BIBLIOGRAPHY")!=-1) insideBib=TRUE; + else if (line.find("<!-- END BIBLIOGRAPH")!=-1) insideBib=FALSE; + else if (insideBib) doc+=line+"\n"; + int i; + // determine text to use at the location of the @cite command + if (insideBib && (i=line.find("<a name=\"CITEREF_"))!=-1) + { + int j=line.find("\">["); + int k=line.find("]</a>"); + if (j!=-1 && k!=-1) + { + QCString label = line.mid(i+17,j-i-17); + QCString number = line.mid(j+2,k-j-1); + CiteInfo *ci = m_entries.find(label); + //printf("label='%s' number='%s' => %p\n",label.data(),number.data(),ci); + if (ci) + { + ci->text = number; + } + } + } + } + //printf("doc=[%s]\n",doc.data()); + + // 6. add it as a page + addRelatedPage(CiteConsts::fileName, + theTranslator->trCiteReferences(),doc,0,CiteConsts::fileName,1,0,0,0); + + // 7. for latex we just copy the bib files to the output and let + // latex do this work. + if (Config_getBool("GENERATE_LATEX")) + { + // copy bib files to the latex output dir + QStrList &citeDataList = Config_getList("CITE_BIB_FILES"); + QCString latexOutputDir = Config_getString("LATEX_OUTPUT")+"/"; + const char *bibdata = citeDataList.first(); + while (bibdata) + { + QCString bibFile = bibdata; + if (!bibFile.isEmpty() && bibFile.right(4)!=".bib") bibFile+=".bib"; + QFileInfo fi(bibFile); + if (fi.exists()) + { + if (!bibFile.isEmpty()) + { + copyFile(bibFile,latexOutputDir+fi.fileName().data()); + } + } + else + { + err("Error: bib file %s not found!\n",bibFile.data()); + } + bibdata = citeDataList.next(); + } + } + + // 8. Remove temporary files + QDir thisDir; + thisDir.remove(citeListFile); + thisDir.remove(doxygenBstFile); + thisDir.remove(bib2xhtmlFile); + +} + diff --git a/trunk/src/cite.h b/trunk/src/cite.h new file mode 100644 index 0000000..10fc56e --- /dev/null +++ b/trunk/src/cite.h @@ -0,0 +1,100 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 2011 by Dimitri van Heesch + * Based on a patch by David Munger + * + * 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. + * + */ + +#ifndef CITEDB_H +#define CITEDB_H + +#include "qtbc.h" +#include <qdict.h> +#include <qlist.h> + +class FTextStream; + +/// String constants for citations +struct CiteConsts +{ + static const QCString fileName; + static const QCString anchorPrefix; +}; + +/// Citation-related data. +struct CiteInfo +{ + CiteInfo(const char *label_, const char *text_=0, const char *fullText_=0, + const char *ref_=0) : + label(label_), text(text_), fullText(fullText_), ref(ref_) + { } + + CiteInfo(const CiteInfo &o) + { label=o.label.copy(); text=o.text.copy(); fullText=o.fullText.copy(); ref=o.ref.copy(); } + + QCString label; + QCString text; + QCString fullText; + QCString ref; + +}; + +/** + * @brief Cite database access class. + * @details This class provides access do the database of bibliographic + * references through the bibtex backend. + */ +class CiteDict +{ + public: + /** Create the database, with an expected maximum of \a size entries */ + CiteDict(int size); + +// /** Resolve references to citations */ +// void resolve(); + + /** Insert a citation identified by \a label into the database */ + void insert(const char *label); + + /** Return the citation info for a given \a label */ + CiteInfo *find(const char *label) const; + + /** Generate the citations page */ + void generatePage() const; + + /** clears the database */ + void clear(); + + /** return TRUE if there are no citations. + * Only valid after calling resolve() + */ + bool isEmpty() const; + + /** writes the latex code for the standard bibliography + * section to text stream \a t + */ + void writeLatexBibliography(FTextStream &t); + + private: +// bool writeAux(); +// bool writeBst(); +// bool execute(); +// void parse(); +// void clean(); + QDict<CiteInfo> m_entries; +// QList<QCString> m_ordering; + QCString m_baseFileName; +}; + +#endif diff --git a/trunk/src/classdef.cpp b/trunk/src/classdef.cpp new file mode 100644 index 0000000..5e91836 --- /dev/null +++ b/trunk/src/classdef.cpp @@ -0,0 +1,4022 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#include <stdio.h> +#include <qfile.h> +#include <qregexp.h> +#include "classdef.h" +#include "classlist.h" +#include "entry.h" +#include "doxygen.h" +#include "membername.h" +#include "message.h" +#include "config.h" +#include "util.h" +#include "diagram.h" +#include "language.h" +#include "htmlhelp.h" +#include "example.h" +#include "outputlist.h" +#include "dot.h" +#include "defargs.h" +#include "debug.h" +#include "docparser.h" +#include "searchindex.h" +#include "vhdldocgen.h" +#include "layout.h" +#include "arguments.h" + +//----------------------------------------------------------------------------- + +//static inline MemberList *createNewMemberList(MemberList::ListType lt) +//{ +// MemberList *result = new MemberList(lt); +// return result; +//} + +class ClassDefImpl +{ + public: + ClassDefImpl(); + ~ClassDefImpl(); + void init(const char *defFileName, const char *name, + const QCString &ctStr, const char *fName); + + /*! file name that forms the base for the output file containing the + * class documentation. For compatibility with Qt (e.g. links via tag + * files) this name cannot be derived from the class name directly. + */ + QCString fileName; + + /*! Include information about the header file should be included + * in the documentation. 0 by default, set by setIncludeFile(). + */ + IncludeInfo *incInfo; + + /*! List of base class (or super-classes) from which this class derives + * directly. + */ + BaseClassList *inherits; + + /*! List of sub-classes that directly derive from this class + */ + BaseClassList *inheritedBy; + + /*! Namespace this class is part of + * (this is the inner most namespace in case of nested namespaces) + */ + NamespaceDef *nspace; + + /*! File this class is defined in */ + FileDef *fileDef; + + /*! List of all members (including inherited members) */ + MemberNameInfoSDict *allMemberNameInfoSDict; + + /*! Template arguments of this class */ + ArgumentList *tempArgs; + + /*! Type constraints for template parameters */ + ArgumentList *typeConstraints; + + /*! Files that were used for generating the class documentation. */ + QStrList files; + + /*! Examples that use this class */ + ExampleSDict *exampleSDict; + + /*! Holds the kind of "class" this is. */ + ClassDef::CompoundType compType; + + /*! The protection level in which this class was found. + * Typically Public, but for nested classes this can also be Protected + * or Private. + */ + Protection prot; + + /*! The inner classes contained in this class. Will be 0 if there are + * no inner classes. + */ + ClassSDict *innerClasses; + + /* classes for the collaboration diagram */ + UsesClassDict *usesImplClassDict; + UsesClassDict *usedByImplClassDict; + UsesClassDict *usesIntfClassDict; + + /*! Template instances that exists of this class, the key in the + * dictionary is the template argument list. + */ + QDict<ClassDef> *templateInstances; + + /*! Template instances that exists of this class, as defined by variables. + * We do NOT want to document these individually. The key in the + * dictionary is the template argument list. + */ + QDict<ClassDef> *variableInstances; + + QDict<int> *templBaseClassNames; + + /*! The class this class is an instance of. */ + ClassDef *templateMaster; + + /*! local class name which could be a typedef'ed alias name. */ + QCString className; + + /*! If this class is a Objective-C category, then this points to the + * class which is extended. + */ + ClassDef *categoryOf; + + QList<MemberList> memberLists; + + /* user defined member groups */ + MemberGroupSDict *memberGroupSDict; + + /*! Is this an abstact class? */ + bool isAbstract; + + /*! Is the class part of an unnamed namespace? */ + bool isStatic; + + /*! TRUE if classes members are merged with those of the base classes. */ + bool membersMerged; + + /*! TRUE if the class is defined in a source file rather than a header file. */ + bool isLocal; + + bool isTemplArg; + + /*! Does this class group its user-grouped members + * as a sub-section of the normal (public/protected/..) + * groups? + */ + bool subGrouping; + + /** Reason of existance is a "use" relation */ + bool usedOnly; + + /** List of titles to use for the summary */ + SDict<QCString> vhdlSummaryTitles; + + /** Is this a simple (non-nested) C structure? */ + bool isSimple; + + /** Does this class overloaded the -> operator? */ + MemberDef *arrowOperator; + + ClassList *taggedInnerClasses; + ClassDef *tagLessRef; + + /** Does this class represent a Java style enum? */ + bool isJavaEnum; +}; + +void ClassDefImpl::init(const char *defFileName, const char *name, + const QCString &ctStr, const char *fName) +{ + if (fName) + { + fileName=stripExtension(fName); + } + else + { + fileName=ctStr+name; + } + exampleSDict = 0; + inherits = 0; + inheritedBy = 0; + allMemberNameInfoSDict = 0; + incInfo=0; + tempArgs=0; + typeConstraints=0; + prot=Public; + nspace=0; + fileDef=0; + usesImplClassDict=0; + usedByImplClassDict=0; + usesIntfClassDict=0; + memberGroupSDict = 0; + innerClasses = 0; + subGrouping=Config_getBool("SUBGROUPING"); + templateInstances = 0; + variableInstances = 0; + templateMaster =0; + templBaseClassNames = 0; + isAbstract = FALSE; + isStatic = FALSE; + isTemplArg = FALSE; + membersMerged = FALSE; + categoryOf = 0; + usedOnly = FALSE; + isSimple = Config_getBool("INLINE_SIMPLE_STRUCTS"); + arrowOperator = 0; + taggedInnerClasses = 0; + tagLessRef = 0; + //QCString ns; + //extractNamespaceName(name,className,ns); + //printf("m_name=%s m_className=%s ns=%s\n",m_name.data(),m_className.data(),ns.data()); + + // we cannot use getLanguage at this point, as setLanguage has not been called. + SrcLangExt lang = getLanguageFromFileName(defFileName); + if ((lang==SrcLangExt_Cpp || lang==SrcLangExt_ObjC) && + guessSection(defFileName)==Entry::SOURCE_SEC) + { + isLocal=TRUE; + } + else + { + isLocal=FALSE; + } +} + +ClassDefImpl::ClassDefImpl() : vhdlSummaryTitles(17) +{ + vhdlSummaryTitles.setAutoDelete(TRUE); +} + +ClassDefImpl::~ClassDefImpl() +{ + delete inherits; + delete inheritedBy; + delete allMemberNameInfoSDict; + delete exampleSDict; + delete usesImplClassDict; + delete usedByImplClassDict; + delete usesIntfClassDict; + delete incInfo; + delete memberGroupSDict; + delete innerClasses; + delete templateInstances; + delete variableInstances; + delete templBaseClassNames; + delete tempArgs; + delete typeConstraints; + delete taggedInnerClasses; +} + +// constructs a new class definition +ClassDef::ClassDef( + const char *defFileName,int defLine, + const char *nm,CompoundType ct, + const char *lref,const char *fName, + bool isSymbol,bool isJavaEnum) + : Definition(defFileName,defLine,removeRedundantWhiteSpace(nm),0,0,isSymbol) +{ + visited=FALSE; + setReference(lref); + m_impl = new ClassDefImpl; + m_impl->compType = ct; + m_impl->isJavaEnum = isJavaEnum; + m_impl->init(defFileName,name(),compoundTypeString(),fName); +} + +// destroy the class definition +ClassDef::~ClassDef() +{ + delete m_impl; +} + +QCString ClassDef::getMemberListFileName() const +{ + return convertNameToFile(compoundTypeString()+name()+"-members"); +} + +QCString ClassDef::displayName() const +{ + //static bool optimizeOutputForJava = Config_getBool("OPTIMIZE_OUTPUT_JAVA"); + SrcLangExt lang = getLanguage(); + //static bool vhdlOpt = Config_getBool("OPTIMIZE_OUTPUT_VHDL"); + QCString n; + if (lang==SrcLangExt_VHDL) + { + n = VhdlDocGen::getClassName(this); + } + else + { + n=qualifiedNameWithTemplateParameters(); + } + QCString sep=getLanguageSpecificSeparator(lang); + if (sep!="::") + { + n=substitute(n,"::",sep); + } + if (m_impl->compType==ClassDef::Protocol && n.right(2)=="-p") + { + n="<"+n.left(n.length()-2)+">"; + } + else if (n.right(2)=="-g") + { + n = n.left(n.length()-2); + } + //printf("ClassDef::displayName()=%s\n",n.data()); + return n; +} + +// inserts a base class in the inheritance list +void ClassDef::insertBaseClass(ClassDef *cd,const char *n,Protection p, + Specifier s,const char *t) +{ + //printf("*** insert base class %s into %s\n",cd->name().data(),name().data()); + //inherits->inSort(new BaseClassDef(cd,p,s,t)); + if (m_impl->inherits==0) + { + m_impl->inherits = new BaseClassList; + m_impl->inherits->setAutoDelete(TRUE); + } + m_impl->inherits->append(new BaseClassDef(cd,n,p,s,t)); + m_impl->isSimple = FALSE; +} + +// inserts a sub class in the inherited list +void ClassDef::insertSubClass(ClassDef *cd,Protection p, + Specifier s,const char *t) +{ + //printf("*** insert sub class %s into %s\n",cd->name().data(),name().data()); + if (m_impl->inheritedBy==0) + { + m_impl->inheritedBy = new BaseClassList; + m_impl->inheritedBy->setAutoDelete(TRUE); + } + m_impl->inheritedBy->inSort(new BaseClassDef(cd,0,p,s,t)); + m_impl->isSimple = FALSE; +} + +void ClassDef::addMembersToMemberGroup() +{ + QListIterator<MemberList> mli(m_impl->memberLists); + MemberList *ml; + for (mli.toFirst();(ml=mli.current());++mli) + { + if ((ml->listType()&MemberList::detailedLists)==0) + { + ::addMembersToMemberGroup(ml,&m_impl->memberGroupSDict,this); + } + } + + // add members inside sections to their groups + if (m_impl->memberGroupSDict) + { + MemberGroupSDict::Iterator mgli(*m_impl->memberGroupSDict); + MemberGroup *mg; + for (;(mg=mgli.current());++mgli) + { + if (mg->allMembersInSameSection() && m_impl->subGrouping) + { + //printf("addToDeclarationSection(%s)\n",mg->header().data()); + mg->addToDeclarationSection(); + } + } + } +} + +// adds new member definition to the class +void ClassDef::internalInsertMember(MemberDef *md, + Protection prot, + bool addToAllList + ) +{ + //printf("insertInternalMember(%s) isHidden()=%d\n",md->name().data(),md->isHidden()); + if (md->isHidden()) return; + + if (getLanguage()==SrcLangExt_VHDL) + { + QCString title=VhdlDocGen::trVhdlType(md->getMemberSpecifiers(),FALSE); + if (!m_impl->vhdlSummaryTitles.find(title)) + { + m_impl->vhdlSummaryTitles.append(title,new QCString(title)); + } + } + + if (1 /*!isReference()*/) // changed to 1 for showing members of external + // classes when HAVE_DOT and UML_LOOK are enabled. + { + bool isSimple=FALSE; + + /********************************************/ + /* insert member in the declaration section */ + /********************************************/ + if (md->isRelated() && protectionLevelVisible(prot)) + { + addMemberToList(MemberList::related,md,TRUE); + } + else if (md->isFriend()) + { + addMemberToList(MemberList::friends,md,TRUE); + } + else + { + switch (md->memberType()) + { + case MemberDef::Signal: // Qt specific + addMemberToList(MemberList::signals,md,TRUE); + break; + case MemberDef::DCOP: // KDE2 specific + addMemberToList(MemberList::dcopMethods,md,TRUE); + break; + case MemberDef::Property: + addMemberToList(MemberList::properties,md,TRUE); + break; + case MemberDef::Event: + addMemberToList(MemberList::events,md,TRUE); + break; + case MemberDef::Slot: // Qt specific + switch (prot) + { + case Protected: + case Package: // slots in packages are not possible! + addMemberToList(MemberList::proSlots,md,TRUE); + break; + case Public: + addMemberToList(MemberList::pubSlots,md,TRUE); + break; + case Private: + addMemberToList(MemberList::priSlots,md,TRUE); + break; + } + break; + default: // any of the other members + if (md->isStatic()) + { + if (md->isVariable()) + { + switch (prot) + { + case Protected: + addMemberToList(MemberList::proStaticAttribs,md,TRUE); + break; + case Package: + addMemberToList(MemberList::pacStaticAttribs,md,TRUE); + break; + case Public: + addMemberToList(MemberList::pubStaticAttribs,md,TRUE); + break; + case Private: + addMemberToList(MemberList::priStaticAttribs,md,TRUE); + break; + } + } + else // function + { + switch (prot) + { + case Protected: + addMemberToList(MemberList::proStaticMethods,md,TRUE); + break; + case Package: + addMemberToList(MemberList::pacStaticMethods,md,TRUE); + break; + case Public: + addMemberToList(MemberList::pubStaticMethods,md,TRUE); + break; + case Private: + addMemberToList(MemberList::priStaticMethods,md,TRUE); + break; + } + } + } + else // not static + { + if (md->isVariable()) + { + switch (prot) + { + case Protected: + addMemberToList(MemberList::proAttribs,md,TRUE); + break; + case Package: + addMemberToList(MemberList::pacAttribs,md,TRUE); + break; + case Public: + addMemberToList(MemberList::pubAttribs,md,TRUE); + isSimple=!md->isFunctionPtr(); + break; + case Private: + addMemberToList(MemberList::priAttribs,md,TRUE); + break; + } + } + else if (md->isTypedef() || md->isEnumerate() || md->isEnumValue()) + { + switch (prot) + { + case Protected: + addMemberToList(MemberList::proTypes,md,TRUE); + break; + case Package: + addMemberToList(MemberList::pacTypes,md,TRUE); + break; + case Public: + addMemberToList(MemberList::pubTypes,md,TRUE); + break; + case Private: + addMemberToList(MemberList::priTypes,md,TRUE); + break; + } + } + else // member function + { + switch (prot) + { + case Protected: + addMemberToList(MemberList::proMethods,md,TRUE); + break; + case Package: + addMemberToList(MemberList::pacMethods,md,TRUE); + break; + case Public: + addMemberToList(MemberList::pubMethods,md,TRUE); + break; + case Private: + addMemberToList(MemberList::priMethods,md,TRUE); + break; + } + } + } + break; + } + } + if (!isSimple) // not a simple field -> not a simple struct + { + m_impl->isSimple = FALSE; + } + //printf("adding %s simple=%d total_simple=%d\n",name().data(),isSimple,m_impl->isSimple); + + /*******************************************************/ + /* insert member in the detailed documentation section */ + /*******************************************************/ + if ((md->isRelated() && protectionLevelVisible(prot)) || md->isFriend()) + { + addMemberToList(MemberList::relatedMembers,md,FALSE); + } + else + { + switch (md->memberType()) + { + case MemberDef::Property: + addMemberToList(MemberList::propertyMembers,md,FALSE); + break; + case MemberDef::Event: + addMemberToList(MemberList::eventMembers,md,FALSE); + break; + case MemberDef::Signal: // fall through + case MemberDef::DCOP: + addMemberToList(MemberList::functionMembers,md,FALSE); + break; + case MemberDef::Slot: + if (protectionLevelVisible(prot)) + { + addMemberToList(MemberList::functionMembers,md,FALSE); + } + break; + default: // any of the other members + if (protectionLevelVisible(prot)) + { + switch (md->memberType()) + { + case MemberDef::Typedef: + addMemberToList(MemberList::typedefMembers,md,FALSE); + break; + case MemberDef::Enumeration: + addMemberToList(MemberList::enumMembers,md,FALSE); + break; + case MemberDef::EnumValue: + addMemberToList(MemberList::enumValMembers,md,FALSE); + break; + case MemberDef::Function: + if (md->isConstructor() || md->isDestructor()) + { + MemberList *ml = createMemberList(MemberList::constructors); + ml->append(md); + } + else + { + addMemberToList(MemberList::functionMembers,md,FALSE); + } + break; + case MemberDef::Variable: + addMemberToList(MemberList::variableMembers,md,FALSE); + break; + default: + err("Unexpected member type %d found!\n",md->memberType()); + } + } + break; + } + } + + /*************************************************/ + /* insert member in the appropriate member group */ + /*************************************************/ + // Note: this must be done AFTER inserting the member in the + // regular groups + //addMemberToGroup(md,groupId); + + } + + if (md->virtualness()==Pure) + { + m_impl->isAbstract=TRUE; + } + + if (md->name()=="operator->") + { + m_impl->arrowOperator=md; + } + + //::addClassMemberNameToIndex(md); + if (addToAllList && + !(Config_getBool("HIDE_FRIEND_COMPOUNDS") && + md->isFriend() && + (QCString(md->typeString())=="friend class" || + QCString(md->typeString())=="friend struct" || + QCString(md->typeString())=="friend union"))) + { + //printf("=======> adding member %s to class %s\n",md->name().data(),name().data()); + MemberInfo *mi = new MemberInfo((MemberDef *)md, + prot,md->virtualness(),FALSE); + MemberNameInfo *mni=0; + if (m_impl->allMemberNameInfoSDict==0) + { + m_impl->allMemberNameInfoSDict = new MemberNameInfoSDict(17); + m_impl->allMemberNameInfoSDict->setAutoDelete(TRUE); + } + if ((mni=m_impl->allMemberNameInfoSDict->find(md->name()))) + { + mni->append(mi); + } + else + { + mni = new MemberNameInfo(md->name()); + mni->append(mi); + m_impl->allMemberNameInfoSDict->append(mni->memberName(),mni); + } + } +} + +void ClassDef::insertMember(MemberDef *md) +{ + internalInsertMember(md,md->protection(),TRUE); +} + +// compute the anchors for all members +void ClassDef::computeAnchors() +{ + ClassDef *context = Config_getBool("INLINE_INHERITED_MEMB") ? this : 0; + const char *letters = "abcdefghijklmnopqrstuvwxyz0123456789"; + QListIterator<MemberList> mli(m_impl->memberLists); + MemberList *ml; + int index = 0; + for (mli.toFirst();(ml=mli.current());++mli) + { + if ((ml->listType()&MemberList::detailedLists)==0) + { + setAnchors(context,letters[index++],ml); + } + } + + if (m_impl->memberGroupSDict) + { + MemberGroupSDict::Iterator mgli(*m_impl->memberGroupSDict); + MemberGroup *mg; + for (;(mg=mgli.current());++mgli) + { + mg->setAnchors(context); + } + } +} + +void ClassDef::distributeMemberGroupDocumentation() +{ + if (m_impl->memberGroupSDict) + { + MemberGroupSDict::Iterator mgli(*m_impl->memberGroupSDict); + MemberGroup *mg; + for (;(mg=mgli.current());++mgli) + { + mg->distributeMemberGroupDocumentation(); + } + } +} + +void ClassDef::findSectionsInDocumentation() +{ + docFindSections(documentation(),this,0,docFile()); + if (m_impl->memberGroupSDict) + { + MemberGroupSDict::Iterator mgli(*m_impl->memberGroupSDict); + MemberGroup *mg; + for (;(mg=mgli.current());++mgli) + { + mg->findSectionsInDocumentation(); + } + } + QListIterator<MemberList> mli(m_impl->memberLists); + MemberList *ml; + for (mli.toFirst();(ml=mli.current());++mli) + { + if ((ml->listType()&MemberList::detailedLists)==0) + { + ml->findSectionsInDocumentation(); + } + } +} + + +// add a file name to the used files set +void ClassDef::insertUsedFile(const char *f) +{ + if (m_impl->files.find(f)==-1) m_impl->files.append(f); + if (m_impl->templateInstances) + { + QDictIterator<ClassDef> qdi(*m_impl->templateInstances); + ClassDef *cd; + for (qdi.toFirst();(cd=qdi.current());++qdi) + { + cd->insertUsedFile(f); + } + } +} + +static void writeInheritanceSpecifier(OutputList &ol,BaseClassDef *bcd) +{ + if (bcd->prot!=Public || bcd->virt!=Normal) + { + ol.startTypewriter(); + ol.docify(" ["); + QStrList sl; + if (bcd->prot==Protected) sl.append("protected"); + else if (bcd->prot==Private) sl.append("private"); + if (bcd->virt==Virtual) sl.append("virtual"); + const char *s=sl.first(); + while (s) + { + ol.docify(s); + s=sl.next(); + if (s) ol.docify(", "); + } + ol.docify("]"); + ol.endTypewriter(); + } +} + +void ClassDef::setIncludeFile(FileDef *fd, + const char *includeName,bool local, bool force) +{ + //printf("ClassDef::setIncludeFile(%p,%s,%d,%d)\n",fd,includeName,local,force); + if (!m_impl->incInfo) m_impl->incInfo=new IncludeInfo; + if ((includeName && m_impl->incInfo->includeName.isEmpty()) || + (fd!=0 && m_impl->incInfo->fileDef==0) + ) + { + //printf("Setting file info\n"); + m_impl->incInfo->fileDef = fd; + m_impl->incInfo->includeName = includeName; + m_impl->incInfo->local = local; + } + if (force && includeName) m_impl->incInfo->includeName = includeName; +} + +// TODO: fix this: a nested template class can have multiple outer templates +//ArgumentList *ClassDef::outerTemplateArguments() const +//{ +// int ti; +// ClassDef *pcd=0; +// int pi=0; +// if (m_impl->tempArgs) return m_impl->tempArgs; +// // find the outer most class scope +// while ((ti=name().find("::",pi))!=-1 && +// (pcd=getClass(name().left(ti)))==0 +// ) pi=ti+2; +// if (pcd) +// { +// return pcd->templateArguments(); +// } +// return 0; +//} + +static void searchTemplateSpecs(/*in*/ Definition *d, + /*out*/ QList<ArgumentList> &result, + /*out*/ QCString &name) +{ + if (d->definitionType()==Definition::TypeClass) + { + if (d->getOuterScope()) + { + searchTemplateSpecs(d->getOuterScope(),result,name); + } + ClassDef *cd=(ClassDef *)d; + if (!name.isEmpty()) name+="::"; + QCString clName = d->localName(); + if (clName.right(2)=="-g" || clName.right(2)=="-p") + { + clName = clName.left(clName.length()-2); + } + name+=clName; + bool isSpecialization = d->localName().find('<')!=-1; + if (cd->templateArguments()) + { + result.append(cd->templateArguments()); + if (!isSpecialization) + { + name+=tempArgListToString(cd->templateArguments()); + } + } + } + else + { + name+=d->qualifiedName(); + } +} + +static void writeTemplateSpec(OutputList &ol,Definition *d, + const QCString &type) +{ + QList<ArgumentList> specs; + QCString name; + searchTemplateSpecs(d,specs,name); + if (specs.count()>0) // class has template scope specifiers + { + ol.startSubsubsection(); + QListIterator<ArgumentList> spi(specs); + ArgumentList *al; + for (spi.toFirst();(al=spi.current());++spi) + { + ol.docify("template<"); + Argument *a=al->first(); + while (a) + { + ol.docify(a->type); + if (!a->name.isEmpty()) + { + ol.docify(" "); + ol.docify(a->name); + } + if (a->defval.length()!=0) + { + ol.docify(" = "); + ol.docify(a->defval); + } + a=al->next(); + if (a) ol.docify(", "); + } + ol.docify(">"); + ol.pushGeneratorState(); + ol.disableAllBut(OutputGenerator::Html); + ol.lineBreak(); + ol.popGeneratorState(); + } + ol.docify(type.lower()+" "+name); + ol.endSubsubsection(); + ol.writeString("\n"); + } +} + +void ClassDef::writeBriefDescription(OutputList &ol,bool exampleFlag) +{ + if (!briefDescription().isEmpty() && Config_getBool("BRIEF_MEMBER_DESC")) + { + ol.startParagraph(); + ol.parseDoc(briefFile(),briefLine(),this,0, + briefDescription(),TRUE,FALSE,0,TRUE,FALSE); + ol.pushGeneratorState(); + ol.disable(OutputGenerator::RTF); + ol.writeString(" \n"); + ol.enable(OutputGenerator::RTF); + ol.popGeneratorState(); + + if (Config_getBool("REPEAT_BRIEF") || + !documentation().isEmpty() || + exampleFlag + ) + { + writeMoreLink(ol,anchor()); + } + + ol.endParagraph(); + } + ol.writeSynopsis(); +} + +void ClassDef::writeDetailedDocumentationBody(OutputList &ol) +{ + static bool repeatBrief = Config_getBool("REPEAT_BRIEF"); + + ol.startTextBlock(); + + if (getLanguage()==SrcLangExt_Cpp) + { + writeTemplateSpec(ol,this,compoundTypeString()); + } + + // repeat brief description + if (!briefDescription().isEmpty() && repeatBrief) + { + ol.parseDoc(briefFile(),briefLine(),this,0,briefDescription(),FALSE,FALSE); + } + if (!briefDescription().isEmpty() && repeatBrief && + !documentation().isEmpty()) + { + ol.pushGeneratorState(); + ol.disable(OutputGenerator::Html); + ol.writeString("\n\n"); + ol.popGeneratorState(); + } + // write documentation + if (!documentation().isEmpty()) + { + ol.parseDoc(docFile(),docLine(),this,0,documentation(),TRUE,FALSE); + } + // write type constraints + writeTypeConstraints(ol,this,m_impl->typeConstraints); + + // write examples + if (hasExamples() && m_impl->exampleSDict) + { + ol.startSimpleSect(BaseOutputDocInterface::Examples,0,0,theTranslator->trExamples()+": "); + ol.startDescForItem(); + //ol.startParagraph(); + writeExample(ol,m_impl->exampleSDict); + //ol.endParagraph(); + ol.endDescForItem(); + ol.endSimpleSect(); + } + //ol.newParagraph(); + writeSourceDef(ol,name()); + ol.endTextBlock(); +} + +// write the detailed description for this class +void ClassDef::writeDetailedDescription(OutputList &ol, const QCString &pageType, bool exampleFlag, + const QCString &title,const QCString &anchor) +{ + if ((!briefDescription().isEmpty() && Config_getBool("REPEAT_BRIEF")) || + !documentation().isEmpty() || + (Config_getBool("SOURCE_BROWSER") && getStartBodyLine()!=-1 && getBodyDef()) || + exampleFlag) + { + ol.writeRuler(); + + ol.pushGeneratorState(); + ol.disableAllBut(OutputGenerator::Html); + ol.writeAnchor(0,anchor.isEmpty() ? QCString("details") : anchor); + ol.popGeneratorState(); + + if (!anchor.isEmpty()) + { + ol.pushGeneratorState(); + ol.disable(OutputGenerator::Html); + ol.disable(OutputGenerator::Man); + ol.writeAnchor(getOutputFileBase(),anchor); + ol.popGeneratorState(); + } + + ol.startGroupHeader(); + ol.parseText(title); + ol.endGroupHeader(); + + writeDetailedDocumentationBody(ol); + + } + else + { + writeTemplateSpec(ol,this,pageType); + } +} + +void ClassDef::showUsedFiles(OutputList &ol) +{ + ol.pushGeneratorState(); + ol.disable(OutputGenerator::Man); + + SrcLangExt lang = getLanguage(); + ol.writeRuler(); + if (lang==SrcLangExt_Fortran) + { + ol.parseText(theTranslator->trGeneratedFromFilesFortran( + getLanguage()==SrcLangExt_ObjC && m_impl->compType==Interface ? Class : m_impl->compType, + m_impl->files.count()==1)); + } + else if (isJavaEnum()) + { + // TODO: TRANSLATE ME + QCString s; + if (m_impl->files.count()!=1) s="s"; + ol.parseText("The documentation for this enum was generated from the following file"+s+":"); + } + else + { + ol.parseText(theTranslator->trGeneratedFromFiles( + getLanguage()==SrcLangExt_ObjC && m_impl->compType==Interface ? Class : m_impl->compType, + m_impl->files.count()==1)); + } + + + bool first=TRUE; + const char *file = m_impl->files.first(); + while (file) + { + bool ambig; + FileDef *fd=findFileDef(Doxygen::inputNameDict,file,ambig); + if (fd) + { + if (first) + { + first=FALSE; + ol.startItemList(); + } + + ol.startItemListItem(); + QCString path=fd->getPath(); + if (Config_getBool("FULL_PATH_NAMES")) + { + ol.docify(stripFromPath(path)); + } + + QCString fname = fd->name(); + if (!fd->getVersion().isEmpty()) // append version if available + { + fname += " (" + fd->getVersion() + ")"; + } + + // for HTML + ol.pushGeneratorState(); + ol.disableAllBut(OutputGenerator::Html); + if (fd->generateSourceFile()) + { + ol.writeObjectLink(0,fd->getSourceFileBase(),0,fname); + } + else if (fd->isLinkable()) + { + ol.writeObjectLink(fd->getReference(),fd->getOutputFileBase(),0, + fname); + } + else + { + ol.docify(fname); + } + ol.popGeneratorState(); + + // for other output formats + ol.pushGeneratorState(); + ol.disable(OutputGenerator::Html); + if (fd->isLinkable()) + { + ol.writeObjectLink(fd->getReference(),fd->getOutputFileBase(),0, + fname); + } + else + { + ol.docify(fname); + } + ol.popGeneratorState(); + + ol.endItemListItem(); + } + file=m_impl->files.next(); + } + if (!first) ol.endItemList(); + + ol.popGeneratorState(); +} + + +void ClassDef::writeInheritanceGraph(OutputList &ol) +{ + // count direct inheritance relations + int count=0; + BaseClassDef *ibcd; + if (m_impl->inheritedBy) + { + ibcd=m_impl->inheritedBy->first(); + while (ibcd) + { + ClassDef *icd=ibcd->classDef; + if ( icd->isVisibleInHierarchy()) count++; + ibcd=m_impl->inheritedBy->next(); + } + } + if (m_impl->inherits) + { + ibcd=m_impl->inherits->first(); + while (ibcd) + { + ClassDef *icd=ibcd->classDef; + if ( icd->isVisibleInHierarchy()) count++; + ibcd=m_impl->inherits->next(); + } + } + + + bool renderDiagram = FALSE; + if (Config_getBool("HAVE_DOT") && + (Config_getBool("CLASS_DIAGRAMS") || Config_getBool("CLASS_GRAPH"))) + // write class diagram using dot + { + DotClassGraph inheritanceGraph(this,DotNode::Inheritance); + if (!inheritanceGraph.isTrivial() && !inheritanceGraph.isTooBig()) + { + ol.pushGeneratorState(); + ol.disable(OutputGenerator::Man); + ol.startDotGraph(); + ol.parseText(theTranslator->trClassDiagram(displayName())); + ol.endDotGraph(inheritanceGraph); + ol.popGeneratorState(); + renderDiagram = TRUE; + } + } + else if (Config_getBool("CLASS_DIAGRAMS") && count>0) + // write class diagram using build-in generator + { + ClassDiagram diagram(this); // create a diagram of this class. + ol.startClassDiagram(); + ol.disable(OutputGenerator::Man); + ol.parseText(theTranslator->trClassDiagram(displayName())); + ol.enable(OutputGenerator::Man); + ol.endClassDiagram(diagram,getOutputFileBase(),displayName()); + renderDiagram = TRUE; + } + + if (renderDiagram) // if we already show the inheritance relations graphically, + // then hide the text version + { + ol.disableAllBut(OutputGenerator::Man); + } + + if (m_impl->inherits && (count=m_impl->inherits->count())>0) + { + ol.startParagraph(); + //parseText(ol,theTranslator->trInherits()+" "); + + QCString inheritLine = theTranslator->trInheritsList(m_impl->inherits->count()); + QRegExp marker("@[0-9]+"); + int index=0,newIndex,matchLen; + // now replace all markers in inheritLine with links to the classes + while ((newIndex=marker.match(inheritLine,index,&matchLen))!=-1) + { + ol.parseText(inheritLine.mid(index,newIndex-index)); + bool ok; + uint entryIndex = inheritLine.mid(newIndex+1,matchLen-1).toUInt(&ok); + BaseClassDef *bcd=m_impl->inherits->at(entryIndex); + if (ok && bcd) + { + ClassDef *cd=bcd->classDef; + + // use the class name but with the template arguments as given + // in the inheritance relation + QCString displayName = insertTemplateSpecifierInScope( + cd->displayName(),bcd->templSpecifiers); + + if (cd->isLinkable()) + { + if (!Config_getString("GENERATE_TAGFILE").isEmpty()) + { + Doxygen::tagFile << " <base"; + if (bcd->prot==Protected) + { + Doxygen::tagFile << " protection=\"protected\""; + } + else if (bcd->prot==Private) + { + Doxygen::tagFile << " protection=\"private\""; + } + if (bcd->virt==Virtual) + { + Doxygen::tagFile << " virtualness=\"virtual\""; + } + Doxygen::tagFile << ">" << convertToXML(cd->name()) + << "</base>" << endl; + } + ol.writeObjectLink(cd->getReference(), + cd->getOutputFileBase(), + cd->anchor(), + displayName); + } + else + { + ol.docify(displayName); + } + } + else + { + err("error: invalid marker %d in inherits list!\n",entryIndex); + } + index=newIndex+matchLen; + } + ol.parseText(inheritLine.right(inheritLine.length()-index)); + ol.endParagraph(); + } + + // write subclasses + if (m_impl->inheritedBy && (count=m_impl->inheritedBy->count())>0) + { + ol.startParagraph(); + QCString inheritLine = theTranslator->trInheritedByList(m_impl->inheritedBy->count()); + QRegExp marker("@[0-9]+"); + int index=0,newIndex,matchLen; + // now replace all markers in inheritLine with links to the classes + while ((newIndex=marker.match(inheritLine,index,&matchLen))!=-1) + { + ol.parseText(inheritLine.mid(index,newIndex-index)); + bool ok; + uint entryIndex = inheritLine.mid(newIndex+1,matchLen-1).toUInt(&ok); + BaseClassDef *bcd=m_impl->inheritedBy->at(entryIndex); + if (ok && bcd) + { + ClassDef *cd=bcd->classDef; + if (cd->isLinkable()) + { + ol.writeObjectLink(cd->getReference(),cd->getOutputFileBase(),cd->anchor(),cd->displayName()); + } + else + { + ol.docify(cd->displayName()); + } + writeInheritanceSpecifier(ol,bcd); + } + index=newIndex+matchLen; + } + ol.parseText(inheritLine.right(inheritLine.length()-index)); + ol.endParagraph(); + } + + if (renderDiagram) + { + ol.enableAll(); + } +} + +void ClassDef::writeCollaborationGraph(OutputList &ol) +{ + if (Config_getBool("HAVE_DOT") /*&& Config_getBool("COLLABORATION_GRAPH")*/) + { + DotClassGraph usageImplGraph(this,DotNode::Collaboration); + if (!usageImplGraph.isTrivial()) + { + ol.pushGeneratorState(); + ol.disable(OutputGenerator::Man); + ol.startDotGraph(); + ol.parseText(theTranslator->trCollaborationDiagram(displayName())); + ol.endDotGraph(usageImplGraph); + ol.popGeneratorState(); + } + } +} + +void ClassDef::writeIncludeFiles(OutputList &ol) +{ + if (m_impl->incInfo /*&& Config_getBool("SHOW_INCLUDE_FILES")*/) + { + QCString nm=m_impl->incInfo->includeName.isEmpty() ? + (m_impl->incInfo->fileDef ? + m_impl->incInfo->fileDef->docName().data() : "" + ) : + m_impl->incInfo->includeName.data(); + if (!nm.isEmpty()) + { + ol.startParagraph(); + ol.startTypewriter(); + SrcLangExt lang = getLanguage(); + bool isIDLorJava = lang==SrcLangExt_IDL || lang==SrcLangExt_Java; + if (isIDLorJava) + { + ol.docify("import "); + } + else if (isObjectiveC()) + { + ol.docify("#import "); + } + else + { + ol.docify("#include "); + } + if (m_impl->incInfo->local || isIDLorJava) + ol.docify("\""); + else + ol.docify("<"); + ol.pushGeneratorState(); + ol.disable(OutputGenerator::Html); + ol.docify(nm); + ol.disableAllBut(OutputGenerator::Html); + ol.enable(OutputGenerator::Html); + if (m_impl->incInfo->fileDef) + { + ol.writeObjectLink(0,m_impl->incInfo->fileDef->includeName(),0,nm); + } + else + { + ol.docify(nm); + } + ol.popGeneratorState(); + if (m_impl->incInfo->local || isIDLorJava) + ol.docify("\""); + else + ol.docify(">"); + if (isIDLorJava) + ol.docify(";"); + ol.endTypewriter(); + ol.endParagraph(); + } + } +} + +void ClassDef::writeAllMembersLink(OutputList &ol) +{ + // write link to list of all members (HTML only) + if (m_impl->allMemberNameInfoSDict && + !Config_getBool("OPTIMIZE_OUTPUT_FOR_C") + ) + { + ol.pushGeneratorState(); + ol.disableAllBut(OutputGenerator::Html); + ol.startParagraph(); + ol.startTextLink(getMemberListFileName(),0); + ol.parseText(theTranslator->trListOfAllMembers()); + ol.endTextLink(); + ol.endParagraph(); + ol.enableAll(); + ol.popGeneratorState(); + } +} + +void ClassDef::writeMemberGroups(OutputList &ol,bool showInline) +{ + // write user defined member groups + if (m_impl->memberGroupSDict) + { + m_impl->memberGroupSDict->sort(); + MemberGroupSDict::Iterator mgli(*m_impl->memberGroupSDict); + MemberGroup *mg; + for (;(mg=mgli.current());++mgli) + { + if (!mg->allMembersInSameSection() || !m_impl->subGrouping) // group is in its own section + { + mg->writeDeclarations(ol,this,0,0,0,showInline); + } + else // add this group to the corresponding member section + { + //printf("addToDeclarationSection(%s)\n",mg->header().data()); + //mg->addToDeclarationSection(); + } + } + } +} + +void ClassDef::writeNestedClasses(OutputList &ol,const QCString &title) +{ + // nested classes + if (m_impl->innerClasses) + { + m_impl->innerClasses->writeDeclaration(ol,0,title,TRUE); + } +} + +void ClassDef::writeInlineClasses(OutputList &ol) +{ + if (m_impl->innerClasses) + { + m_impl->innerClasses->writeDocumentation(ol,this); + } +} + +void ClassDef::startMemberDocumentation(OutputList &ol) +{ + //printf("%s: ClassDef::startMemberDocumentation()\n",name().data()); + if (Config_getBool("SEPARATE_MEMBER_PAGES")) + { + ol.disable(OutputGenerator::Html); + Doxygen::suppressDocWarnings = TRUE; + } +} + +void ClassDef::endMemberDocumentation(OutputList &ol) +{ + //printf("%s: ClassDef::endMemberDocumentation()\n",name().data()); + if (Config_getBool("SEPARATE_MEMBER_PAGES")) + { + ol.enable(OutputGenerator::Html); + Doxygen::suppressDocWarnings = FALSE; + } +} + +void ClassDef::startMemberDeclarations(OutputList &ol) +{ + //printf("%s: ClassDef::startMemberDeclarations()\n",name().data()); + ol.startMemberSections(); +} + +void ClassDef::endMemberDeclarations(OutputList &ol) +{ + //printf("%s: ClassDef::endMemberDeclarations()\n",name().data()); + ol.endMemberSections(); +} + +void ClassDef::writeAuthorSection(OutputList &ol) +{ + ol.pushGeneratorState(); + ol.disableAllBut(OutputGenerator::Man); + ol.writeString("\n"); + ol.startGroupHeader(); + ol.parseText(theTranslator->trAuthor(TRUE,TRUE)); + ol.endGroupHeader(); + ol.parseText(theTranslator->trGeneratedAutomatically(Config_getString("PROJECT_NAME"))); + ol.popGeneratorState(); +} + + +void ClassDef::writeSummaryLinks(OutputList &ol) +{ + ol.pushGeneratorState(); + ol.disableAllBut(OutputGenerator::Html); + QListIterator<LayoutDocEntry> eli( + LayoutDocManager::instance().docEntries(LayoutDocManager::Class)); + LayoutDocEntry *lde; + bool first=TRUE; + + if (getLanguage()!=SrcLangExt_VHDL) + { + for (eli.toFirst();(lde=eli.current());++eli) + { + if (lde->kind()==LayoutDocEntry::ClassNestedClasses && + m_impl->innerClasses && + m_impl->innerClasses->declVisible() + ) + { + LayoutDocEntrySection *ls = (LayoutDocEntrySection*)lde; + writeSummaryLink(ol,"nested-classes",ls->title,first); + } + else if (lde->kind()== LayoutDocEntry::MemberDecl) + { + LayoutDocEntryMemberDecl *lmd = (LayoutDocEntryMemberDecl*)lde; + MemberList * ml = getMemberList(lmd->type); + if (ml && ml->declVisible()) + { + writeSummaryLink(ol,ml->listTypeAsString(),lmd->title,first); + } + } + } + } + else // VDHL only + { + SDict<QCString>::Iterator li(m_impl->vhdlSummaryTitles); + for (li.toFirst();li.current();++li) + { + writeSummaryLink(ol,li.current()->data(),li.current()->data(),first); + } + } + if (!first) + { + ol.writeString(" </div>\n"); + } + ol.popGeneratorState(); +} + +void ClassDef::writeTagFileMarker() +{ + // write section to the tag file + if (!Config_getString("GENERATE_TAGFILE").isEmpty()) + { + Doxygen::tagFile << " <compound kind=\"" << compoundTypeString(); + Doxygen::tagFile << "\""; + if (isObjectiveC()) { Doxygen::tagFile << " objc=\"yes\""; } + Doxygen::tagFile << ">" << endl; + Doxygen::tagFile << " <name>" << convertToXML(name()) << "</name>" << endl; + Doxygen::tagFile << " <filename>" << convertToXML(getOutputFileBase()) << Doxygen::htmlFileExtension << "</filename>" << endl; + if (!anchor().isEmpty()) + { + Doxygen::tagFile << " <anchor>" << convertToXML(anchor()) << "</anchor>" << endl; + } + if (m_impl->tempArgs) + { + ArgumentListIterator ali(*m_impl->tempArgs); + Argument *a; + for (;(a=ali.current());++ali) + { + Doxygen::tagFile << " <templarg>" << convertToXML(a->name) << "</templarg>" << endl; + } + } + } +} + +/** Write class documentation inside another container (i.e. a group) */ +void ClassDef::writeInlineDocumentation(OutputList &ol) +{ + bool isSimple = m_impl->isSimple; + + ol.addIndexItem(name(),0); + //printf("ClassDef::writeInlineDocumentation(%s)\n",name().data()); + QListIterator<LayoutDocEntry> eli( + LayoutDocManager::instance().docEntries(LayoutDocManager::Class)); + LayoutDocEntry *lde; + + // part 1: anchor and title + QCString s = compoundTypeString()+" "+name(); + + // part 1a + ol.pushGeneratorState(); + ol.disableAllBut(OutputGenerator::Html); + { // only HTML only + ol.writeAnchor(0,anchor()); + ol.startMemberDoc(0,0,0,0,FALSE); + ol.startMemberDocName(FALSE); + ol.parseText(s); + ol.endMemberDocName(); + ol.endMemberDoc(FALSE); + ol.startIndent(); + } + ol.popGeneratorState(); + + // part 1b + ol.pushGeneratorState(); + ol.disable(OutputGenerator::Html); + ol.disable(OutputGenerator::Man); + { // for LaTeX/RTF only + ol.writeAnchor(getOutputFileBase(),anchor()); + } + ol.popGeneratorState(); + + // part 1c + ol.pushGeneratorState(); + ol.disable(OutputGenerator::Html); + { + // for LaTeX/RTF/Man + ol.startGroupHeader(1); + ol.parseText(s); + ol.endGroupHeader(1); + } + ol.popGeneratorState(); + + // part 2: the header and detailed description + for (eli.toFirst();(lde=eli.current());++eli) + { + switch (lde->kind()) + { + case LayoutDocEntry::BriefDesc: + { + // since we already shown the brief description in the + // declaration part of the container, so we use this to + // show the details on top. + writeDetailedDocumentationBody(ol); + } + break; + case LayoutDocEntry::ClassInheritanceGraph: + writeInheritanceGraph(ol); + break; + case LayoutDocEntry::ClassCollaborationGraph: + writeCollaborationGraph(ol); + break; + case LayoutDocEntry::MemberDeclStart: + if (!isSimple) startMemberDeclarations(ol); + break; + case LayoutDocEntry::MemberDecl: + { + LayoutDocEntryMemberDecl *lmd = (LayoutDocEntryMemberDecl*)lde; + if (!isSimple) writeMemberDeclarations(ol,lmd->type,lmd->title,lmd->subscript,TRUE); + } + break; + case LayoutDocEntry::MemberGroups: + if (!isSimple) writeMemberGroups(ol,TRUE); + break; + case LayoutDocEntry::MemberDeclEnd: + if (!isSimple) endMemberDeclarations(ol); + break; + case LayoutDocEntry::MemberDefStart: + if (!isSimple) startMemberDocumentation(ol); + break; + case LayoutDocEntry::MemberDef: + { + LayoutDocEntryMemberDef *lmd = (LayoutDocEntryMemberDef*)lde; + if (isSimple) + { + writeSimpleMemberDocumentation(ol,lmd->type); + } + else + { + writeMemberDocumentation(ol,lmd->type,lmd->title,TRUE); + } + } + break; + case LayoutDocEntry::MemberDefEnd: + if (!isSimple) endMemberDocumentation(ol); + break; + default: + break; + } + } + + // part 3: close the block + ol.pushGeneratorState(); + ol.disableAllBut(OutputGenerator::Html); + { // HTML only + ol.endIndent(); + } + ol.popGeneratorState(); + + // part 4: write tag file information + writeTagFileMarker(); +} + +void ClassDef::writeMoreLink(OutputList &ol,const QCString &anchor) +{ + // TODO: clean up this mess by moving it to + // the output generators... + static bool pdfHyperlinks = Config_getBool("PDF_HYPERLINKS"); + static bool rtfHyperlinks = Config_getBool("RTF_HYPERLINKS"); + static bool usePDFLatex = Config_getBool("USE_PDFLATEX"); + + // HTML only + ol.pushGeneratorState(); + ol.disableAllBut(OutputGenerator::Html); + ol.docify(" "); + ol.startTextLink(getOutputFileBase(), + anchor.isEmpty() ? QCString("details") : anchor); + ol.parseText(theTranslator->trMore()); + ol.endTextLink(); + ol.popGeneratorState(); + + if (!anchor.isEmpty()) + { + ol.pushGeneratorState(); + // LaTeX + RTF + ol.disable(OutputGenerator::Html); + ol.disable(OutputGenerator::Man); + if (!(usePDFLatex && pdfHyperlinks)) + { + ol.disable(OutputGenerator::Latex); + } + if (!rtfHyperlinks) + { + ol.disable(OutputGenerator::RTF); + } + ol.docify(" "); + ol.startTextLink(getOutputFileBase(), anchor); + ol.parseText(theTranslator->trMore()); + ol.endTextLink(); + // RTF only + ol.disable(OutputGenerator::Latex); + ol.writeString("\\par"); + ol.popGeneratorState(); + } +} + + +void ClassDef::writeDeclarationLink(OutputList &ol,bool &found,const char *header,bool localNames) +{ + //static bool fortranOpt = Config_getBool("OPTIMIZE_FOR_FORTRAN"); + //static bool vhdlOpt = Config_getBool("OPTIMIZE_OUTPUT_VHDL"); + static bool hideUndocClasses = Config_getBool("HIDE_UNDOC_CLASSES"); + static bool extractLocalClasses = Config_getBool("EXTRACT_LOCAL_CLASSES"); + bool isLink = isLinkable(); + SrcLangExt lang = getLanguage(); + if (isLink || + (!hideUndocClasses && + (!isLocal() || extractLocalClasses) + ) + ) + { + if (!found) // first class + { + ol.startMemberHeader("nested-classes"); + if (header) + { + ol.parseText(header); + } + else if (lang==SrcLangExt_VHDL) + { + ol.parseText(VhdlDocGen::trVhdlType(VhdlDocGen::ARCHITECTURE,FALSE)); + } + else + { + ol.parseText(lang==SrcLangExt_Fortran ? + theTranslator->trDataTypes() : + theTranslator->trCompounds()); + } + ol.endMemberHeader(); + ol.startMemberList(); + found=TRUE; + } + if (!Config_getString("GENERATE_TAGFILE").isEmpty() && + !isReference()) // skip classes found in tag files + { + Doxygen::tagFile << " <class kind=\"" << compoundTypeString() + << "\">" << convertToXML(name()) << "</class>" << endl; + } + ol.startMemberItem(anchor(),FALSE); + QCString ctype = compoundTypeString(); + QCString cname; + if (localNames) + { + cname = localName(); + if (cname.right(2)=="-p" || cname.right(2)=="-g") + { + cname = cname.left(cname.length()-2); + } + } + else + { + cname = displayName(); + } + + if (lang!=SrcLangExt_VHDL) // for VHDL we swap the name and the type + { + ol.writeString(ctype); + ol.writeString(" "); + ol.insertMemberAlign(); + } + if (isLink) + { + ol.writeObjectLink(getReference(), + getOutputFileBase(), + anchor(), + cname + ); + } + else + { + ol.startBold(); + ol.docify(cname); + ol.endBold(); + } + if (lang==SrcLangExt_VHDL) // now write the type + { + ol.writeString(" "); + ol.insertMemberAlign(); + ol.writeString(VhdlDocGen::getProtectionName((VhdlDocGen::VhdlClasses)protection())); + } + ol.endMemberItem(); + + // add the brief description if available + if (!briefDescription().isEmpty()) + { + ol.startMemberDescription(anchor()); + ol.parseDoc(briefFile(),briefLine(),this,0, + briefDescription(),FALSE,FALSE,0,TRUE,FALSE); + if (isLinkableInProject()) + { + writeMoreLink(ol,anchor()); + } + ol.endMemberDescription(); + } + } +} + +void ClassDef::writeDocumentationContents(OutputList &ol,const QCString &pageTitle) +{ + ol.startContents(); + + QCString pageType = " "; + pageType += compoundTypeString(); + toupper(pageType.at(1)); + + writeTagFileMarker(); + + Doxygen::indexList.addIndexItem(this,0); + + if (Doxygen::searchIndex) + { + Doxygen::searchIndex->setCurrentDoc(pageTitle,getOutputFileBase(),anchor()); + Doxygen::searchIndex->addWord(localName(),TRUE); + } + bool exampleFlag=hasExamples(); + + //---------------------------------------- start flexible part ------------------------------- + + QListIterator<LayoutDocEntry> eli( + LayoutDocManager::instance().docEntries(LayoutDocManager::Class)); + LayoutDocEntry *lde; + for (eli.toFirst();(lde=eli.current());++eli) + { + switch (lde->kind()) + { + case LayoutDocEntry::BriefDesc: + writeBriefDescription(ol,exampleFlag); + break; + case LayoutDocEntry::ClassIncludes: + writeIncludeFiles(ol); + break; + case LayoutDocEntry::ClassInheritanceGraph: + writeInheritanceGraph(ol); + break; + case LayoutDocEntry::ClassCollaborationGraph: + writeCollaborationGraph(ol); + break; + case LayoutDocEntry::ClassAllMembersLink: + writeAllMembersLink(ol); + break; + case LayoutDocEntry::MemberDeclStart: + startMemberDeclarations(ol); + break; + case LayoutDocEntry::MemberGroups: + writeMemberGroups(ol); + break; + case LayoutDocEntry::MemberDecl: + { + LayoutDocEntryMemberDecl *lmd = (LayoutDocEntryMemberDecl*)lde; + writeMemberDeclarations(ol,lmd->type,lmd->title,lmd->subscript); + } + break; + case LayoutDocEntry::ClassNestedClasses: + { + LayoutDocEntrySection *ls = (LayoutDocEntrySection*)lde; + writeNestedClasses(ol,ls->title); + } + break; + case LayoutDocEntry::MemberDeclEnd: + endMemberDeclarations(ol); + break; + case LayoutDocEntry::DetailedDesc: + { + LayoutDocEntrySection *ls = (LayoutDocEntrySection*)lde; + writeDetailedDescription(ol,pageType,exampleFlag,ls->title); + } + break; + case LayoutDocEntry::MemberDefStart: + startMemberDocumentation(ol); + break; + case LayoutDocEntry::ClassInlineClasses: + writeInlineClasses(ol); + break; + case LayoutDocEntry::MemberDef: + { + LayoutDocEntryMemberDef *lmd = (LayoutDocEntryMemberDef*)lde; + writeMemberDocumentation(ol,lmd->type,lmd->title); + } + break; + case LayoutDocEntry::MemberDefEnd: + endMemberDocumentation(ol); + break; + case LayoutDocEntry::ClassUsedFiles: + showUsedFiles(ol); + break; + case LayoutDocEntry::AuthorSection: + writeAuthorSection(ol); + break; + case LayoutDocEntry::NamespaceNestedNamespaces: + case LayoutDocEntry::NamespaceClasses: + case LayoutDocEntry::NamespaceInlineClasses: + case LayoutDocEntry::FileClasses: + case LayoutDocEntry::FileNamespaces: + case LayoutDocEntry::FileIncludes: + case LayoutDocEntry::FileIncludeGraph: + case LayoutDocEntry::FileIncludedByGraph: + case LayoutDocEntry::FileSourceLink: + case LayoutDocEntry::FileInlineClasses: + case LayoutDocEntry::GroupClasses: + case LayoutDocEntry::GroupInlineClasses: + case LayoutDocEntry::GroupNamespaces: + case LayoutDocEntry::GroupDirs: + case LayoutDocEntry::GroupNestedGroups: + case LayoutDocEntry::GroupFiles: + case LayoutDocEntry::GroupGraph: + case LayoutDocEntry::GroupPageDocs: + case LayoutDocEntry::DirSubDirs: + case LayoutDocEntry::DirFiles: + case LayoutDocEntry::DirGraph: + err("Internal inconsistency: member %d should not be part of " + "LayoutDocManager::Class entry list\n",lde->kind()); + break; + } + } + + if (!Config_getString("GENERATE_TAGFILE").isEmpty()) + { + writeDocAnchorsToTagFile(); + Doxygen::tagFile << " </compound>" << endl; + } + ol.endContents(); +} + +// write all documentation for this class +void ClassDef::writeDocumentation(OutputList &ol) +{ + static bool generateTreeView = Config_getBool("GENERATE_TREEVIEW"); + //static bool fortranOpt = Config_getBool("OPTIMIZE_FOR_FORTRAN"); + //static bool vhdlOpt = Config_getBool("OPTIMIZE_OUTPUT_VHDL"); + QCString pageTitle; + SrcLangExt lang = getLanguage(); + + if (lang==SrcLangExt_Fortran) + { + pageTitle = theTranslator->trCompoundReferenceFortran(displayName(), + m_impl->compType, + m_impl->tempArgs != 0); + } + else if (lang==SrcLangExt_VHDL) + { + // TODO: TRANSLATE ME + pageTitle = VhdlDocGen::getClassTitle(this)+" Reference"; + } + else if (isJavaEnum()) + { + // TODO: TRANSLATE ME + pageTitle = displayName()+" Enum Reference"; + } + else + { + pageTitle = theTranslator->trCompoundReference(displayName(), + m_impl->compType == Interface && getLanguage()==SrcLangExt_ObjC ? Class : m_impl->compType, + m_impl->tempArgs != 0); + } + + startFile(ol,getOutputFileBase(),name(),pageTitle,HLI_ClassVisible,!generateTreeView); + if (!generateTreeView) + { + if (getOuterScope()!=Doxygen::globalScope) + { + writeNavigationPath(ol); + } + ol.endQuickIndices(); + } + + startTitle(ol,getOutputFileBase(),this); + ol.parseText(pageTitle); + addGroupListToTitle(ol,this); + endTitle(ol,getOutputFileBase(),displayName()); + writeDocumentationContents(ol,pageTitle); + + endFileWithNavPath(this,ol); + + if (Config_getBool("SEPARATE_MEMBER_PAGES")) + { + writeMemberPages(ol); + } +} + +void ClassDef::writeMemberPages(OutputList &ol) +{ + /////////////////////////////////////////////////////////////////////////// + //// Member definitions on separate pages + /////////////////////////////////////////////////////////////////////////// + + ol.pushGeneratorState(); + ol.disableAllBut(OutputGenerator::Html); + + QListIterator<MemberList> mli(m_impl->memberLists); + MemberList *ml; + for (mli.toFirst();(ml=mli.current());++mli) + { + if (ml->listType()&MemberList::detailedLists) + { + ml->writeDocumentationPage(ol,displayName(),this); + } + } + + ol.popGeneratorState(); +} + +void ClassDef::writeQuickMemberLinks(OutputList &ol,MemberDef *currentMd) const +{ + static bool createSubDirs=Config_getBool("CREATE_SUBDIRS"); + + ol.writeString(" <div class=\"navtab\">\n"); + ol.writeString(" <table>\n"); + + if (m_impl->allMemberNameInfoSDict) + { + MemberNameInfoSDict::Iterator mnili(*m_impl->allMemberNameInfoSDict); + 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->getClassDef()==this && md->isLinkable()) + { + ol.writeString(" <tr><td class=\"navtab\">"); + if (md->isLinkableInProject()) + { + if (md==currentMd) // selected item => highlight + { + ol.writeString("<a class=\"qindexHL\" "); + } + else + { + ol.writeString("<a class=\"qindex\" "); + } + ol.writeString("href=\""); + if (createSubDirs) ol.writeString("../../"); + ol.writeString(md->getOutputFileBase()+Doxygen::htmlFileExtension+"#"+md->anchor()); + ol.writeString("\">"); + ol.writeString(convertToHtml(md->name())); + ol.writeString("</a>"); + } + ol.writeString("</td></tr>\n"); + } + } + } + } + + ol.writeString(" </table>\n"); + ol.writeString(" </div>\n"); +} + + + +void ClassDef::writeDocumentationForInnerClasses(OutputList &ol) +{ + // write inner classes after the parent, so the tag files contain + // the definition in proper order! + if (m_impl->innerClasses) + { + ClassSDict::Iterator cli(*m_impl->innerClasses); + ClassDef *innerCd; + for (cli.toFirst();(innerCd=cli.current());++cli) + { + if (innerCd->isLinkableInProject() && innerCd->templateMaster()==0 && + protectionLevelVisible(innerCd->protection()) && + !innerCd->isEmbeddedInOuterScope() + ) + { + msg("Generating docs for nested compound %s...\n",qPrint(innerCd->name())); + innerCd->writeDocumentation(ol); + innerCd->writeMemberList(ol); + } + innerCd->writeDocumentationForInnerClasses(ol); + } + } +} + +// write the list of all (inherited) members for this class +void ClassDef::writeMemberList(OutputList &ol) +{ + static bool cOpt = Config_getBool("OPTIMIZE_OUTPUT_FOR_C"); + //static bool vhdlOpt = Config_getBool("OPTIMIZE_OUTPUT_VHDL"); + static bool generateTreeView = Config_getBool("GENERATE_TREEVIEW"); + if (m_impl->allMemberNameInfoSDict==0 || cOpt) return; + // only for HTML + ol.pushGeneratorState(); + ol.disableAllBut(OutputGenerator::Html); + + QCString memListFile = getMemberListFileName(); + startFile(ol,memListFile,memListFile,theTranslator->trMemberList(), + HLI_ClassVisible,!generateTreeView,getOutputFileBase()); + if (!generateTreeView) + { + if (getOuterScope()!=Doxygen::globalScope) + { + writeNavigationPath(ol); + } + ol.endQuickIndices(); + } + startTitle(ol,0); + ol.parseText(displayName()+" "+theTranslator->trMemberList()); + endTitle(ol,0,0); + ol.startContents(); + ol.parseText(theTranslator->trThisIsTheListOfAllMembers()); + ol.writeObjectLink(getReference(),getOutputFileBase(),anchor(),displayName()); + ol.parseText(theTranslator->trIncludingInheritedMembers()); + + //ol.startItemList(); + ol.writeString("<table>\n"); + + //MemberNameInfo *mni=m_impl->allMemberNameInfoList->first(); + MemberNameInfoSDict::Iterator mnii(*m_impl->allMemberNameInfoSDict); + MemberNameInfo *mni; + for (mnii.toFirst();(mni=mnii.current());++mnii) + { + MemberInfo *mi=mni->first(); + while (mi) + { + MemberDef *md=mi->memberDef; + ClassDef *cd=md->getClassDef(); + Protection prot = mi->prot; + Specifier virt=md->virtualness(); + + //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); + + + if (cd && !md->name().isEmpty() && md->name()[0]!='@') + { + bool memberWritten=FALSE; + if (cd->isLinkable() && md->isLinkable()) + // create a link to the documentation + { + QCString name=mi->ambiguityResolutionScope+md->name(); + //ol.writeListItem(); + ol.writeString(" <tr class=\"memlist\"><td>"); + if (cd->isObjectiveC()) + { + if (md->isObjCMethod()) + { + if (md->isStatic()) + ol.writeString("+ </td><td>"); + else + ol.writeString("- </td><td>"); + } + else + ol.writeString("</td><td>"); + } + if (md->isObjCMethod()) + { + ol.writeObjectLink(md->getReference(), + md->getOutputFileBase(), + md->anchor(),md->name()); + } + else + { + //Definition *bd = md->getGroupDef(); + //if (bd==0) bd=cd; + ol.writeObjectLink(md->getReference(), + md->getOutputFileBase(), + md->anchor(),name); + + if ( md->isFunction() || md->isSignal() || md->isSlot() || + (md->isFriend() && md->argsString())) + ol.docify(md->argsString()); + else if (md->isEnumerate()) + ol.parseText(" "+theTranslator->trEnumName()); + else if (md->isEnumValue()) + ol.parseText(" "+theTranslator->trEnumValue()); + else if (md->isTypedef()) + ol.docify(" typedef"); + else if (md->isFriend() && !strcmp(md->typeString(),"friend class")) + ol.docify(" class"); + //ol.writeString("\n"); + } + ol.writeString("</td>"); + memberWritten=TRUE; + } + else if (!Config_getBool("HIDE_UNDOC_MEMBERS") && + (protectionLevelVisible(md->protection()) || md->isFriend()) + ) // no documentation, + // generate link to the class instead. + { + //ol.writeListItem(); + ol.writeString(" <tr bgcolor=\"#f0f0f0\"><td>"); + if (cd->isObjectiveC()) + { + if (md->isObjCMethod()) + { + if (md->isStatic()) + ol.writeString("+ </td><td>"); + else + ol.writeString("- </td><td>"); + } + else + ol.writeString("</td><td>"); + } + ol.startBold(); + ol.docify(md->name()); + ol.endBold(); + if (!md->isObjCMethod()) + { + if ( md->isFunction() || md->isSignal() || md->isSlot() ) + ol.docify(md->argsString()); + else if (md->isEnumerate()) + ol.parseText(" "+theTranslator->trEnumName()); + else if (md->isEnumValue()) + ol.parseText(" "+theTranslator->trEnumValue()); + else if (md->isTypedef()) + ol.docify(" typedef"); + } + ol.writeString(" ("); + ol.parseText(theTranslator->trDefinedIn()+" "); + if (cd->isLinkable()) + { + ol.writeObjectLink( + cd->getReference(), + cd->getOutputFileBase(), + cd->anchor(), + cd->displayName()); + } + else + { + ol.startBold(); + ol.docify(cd->displayName()); + ol.endBold(); + } + ol.writeString(")"); + ol.writeString("</td>"); + memberWritten=TRUE; + } + if (memberWritten) + { + ol.writeString("<td>"); + ol.writeObjectLink(cd->getReference(), + cd->getOutputFileBase(), + cd->anchor(), + md->category() ? + md->category()->displayName() : + cd->displayName()); + ol.writeString("</td>"); + ol.writeString("<td>"); + } + SrcLangExt lang = md->getLanguage(); + if ( + (prot!=Public || (virt!=Normal && getLanguage()!=SrcLangExt_ObjC) || + md->isFriend() || md->isRelated() || md->isExplicit() || + md->isMutable() || (md->isInline() && Config_getBool("INLINE_INFO")) || + md->isSignal() || md->isSlot() || + md->isStatic() || lang==SrcLangExt_VHDL + ) + && memberWritten) + { + ol.startTypewriter(); + ol.docify(" ["); + QStrList sl; + if (lang==SrcLangExt_VHDL) + { + sl.append(VhdlDocGen::trVhdlType(md->getMemberSpecifiers())); //append vhdl type + } + else if (md->isFriend()) sl.append("friend"); + else if (md->isRelated()) sl.append("related"); + else + { + if (Config_getBool("INLINE_INFO") && md->isInline()) + sl.append("inline"); + if (md->isExplicit()) sl.append("explicit"); + if (md->isMutable()) sl.append("mutable"); + if (prot==Protected) sl.append("protected"); + else if (prot==Private) sl.append("private"); + else if (prot==Package) sl.append("package"); + if (virt==Virtual && getLanguage()!=SrcLangExt_ObjC) + sl.append("virtual"); + else if (virt==Pure) sl.append("pure virtual"); + if (md->isStatic()) sl.append("static"); + if (md->isSignal()) sl.append("signal"); + if (md->isSlot()) sl.append("slot"); + } + const char *s=sl.first(); + while (s) + { + ol.docify(s); + s=sl.next(); + if (s) ol.docify(", "); + } + ol.docify("]"); + ol.endTypewriter(); + } + if (memberWritten) + { + ol.writeString("</td>"); + ol.writeString("</tr>\n"); + } + } + mi=mni->next(); + } + } + //ol.endItemList(); + + ol.writeString("</table>"); + + endFile(ol); + ol.popGeneratorState(); +} + + +// add a reference to an example +bool ClassDef::addExample(const char *anchor,const char *nameStr, + const char *file) +{ + if (m_impl->exampleSDict==0) + { + m_impl->exampleSDict = new ExampleSDict; + m_impl->exampleSDict->setAutoDelete(TRUE); + } + if (!m_impl->exampleSDict->find(nameStr)) + { + Example *e=new Example; + e->anchor=anchor; + e->name=nameStr; + e->file=file; + m_impl->exampleSDict->inSort(nameStr,e); + return TRUE; + } + return FALSE; +} + +// returns TRUE if this class is used in an example +bool ClassDef::hasExamples() +{ + if (m_impl->exampleSDict==0) + return FALSE; + else + return m_impl->exampleSDict->count()>0; +} + + +void ClassDef::setTemplateArguments(ArgumentList *al) +{ + if (al==0) return; + if (!m_impl->tempArgs) delete m_impl->tempArgs; // delete old list if needed + m_impl->tempArgs=new ArgumentList; + ArgumentListIterator ali(*al); + Argument *a; + for (;(a=ali.current());++ali) + { + m_impl->tempArgs->append(new Argument(*a)); + } +} + +void ClassDef::setTypeConstraints(ArgumentList *al) +{ + if (al==0) return; + if (!m_impl->typeConstraints) delete m_impl->typeConstraints; + m_impl->typeConstraints = new ArgumentList; + ArgumentListIterator ali(*al); + Argument *a; + for (;(a=ali.current());++ali) + { + m_impl->typeConstraints->append(new Argument(*a)); + } +} + +/*! Returns \c TRUE iff this class or a class inheriting from this class + * is \e not defined in an external tag file. + */ +bool ClassDef::hasNonReferenceSuperClass() +{ + bool found=!isReference() && isLinkableInProject() && !isHidden(); + if (found) + { + return TRUE; // we're done if this class is not a reference + } + if (m_impl->inheritedBy) + { + BaseClassListIterator bcli(*m_impl->inheritedBy); + for ( ; bcli.current() && !found ; ++bcli ) // for each super class + { + ClassDef *bcd=bcli.current()->classDef; + // recurse into the super class branch + found = found || bcd->hasNonReferenceSuperClass(); + if (!found) + { + // look for template instances that might have non-reference super classes + QDict<ClassDef> *cil = bcd->getTemplateInstances(); + if (cil) + { + QDictIterator<ClassDef> tidi(*cil); + for ( ; tidi.current() && !found ; ++tidi) // for each template instance + { + // recurse into the template instance branch + found = found || tidi.current()->hasNonReferenceSuperClass(); + } + } + } + } + } + return found; +} + +/*! called from MemberDef::writeDeclaration() to (recusively) write the + * definition of an anonymous struct, union or class. + */ +void ClassDef::writeDeclaration(OutputList &ol,MemberDef *md,bool inGroup) +{ + //ol.insertMemberAlign(); + //printf("ClassName=`%s' inGroup=%d\n",name().data(),inGroup); + + //if (inGroup && md && md->getClassDef()==this) return; + + ol.docify(compoundTypeString()); + int ri=name().findRev("::"); + if (ri==-1) ri=name().length(); + QCString cn=name().right(name().length()-ri-2); + if (!cn.isEmpty() && cn.at(0)!='@' && md) + { + if (cn.right(2)=="-p" || cn.right(2)=="-g") + { + cn = cn.left(cn.length()-2); + } + ol.docify(" "); + if (isLinkable()) + { + ol.writeObjectLink(0,0,md->anchor(),cn); + } + else + { + ol.startBold(); + ol.docify(cn); + ol.endBold(); + } + } + ol.docify(" {"); + ol.endMemberItem(); + + // write user defined member groups + if (m_impl->memberGroupSDict) + { + MemberGroupSDict::Iterator mgli(*m_impl->memberGroupSDict); + MemberGroup *mg; + for (;(mg=mgli.current());++mgli) + { + mg->setInGroup(inGroup); + mg->writePlainDeclarations(ol,this,0,0,0); + } + } + static bool extractPrivate = Config_getBool("EXTRACT_PRIVATE"); + static bool extractPackage = Config_getBool("EXTRACT_PACKAGE"); + + writePlainMemberDeclaration(ol,MemberList::pubTypes,inGroup); + writePlainMemberDeclaration(ol,MemberList::pubMethods,inGroup); + writePlainMemberDeclaration(ol,MemberList::pubAttribs,inGroup); + writePlainMemberDeclaration(ol,MemberList::pubSlots,inGroup); + writePlainMemberDeclaration(ol,MemberList::signals,inGroup); + writePlainMemberDeclaration(ol,MemberList::dcopMethods,inGroup); + writePlainMemberDeclaration(ol,MemberList::properties,inGroup); + writePlainMemberDeclaration(ol,MemberList::events,inGroup); + writePlainMemberDeclaration(ol,MemberList::pubStaticMethods,inGroup); + writePlainMemberDeclaration(ol,MemberList::pubStaticAttribs,inGroup); + writePlainMemberDeclaration(ol,MemberList::proTypes,inGroup); + writePlainMemberDeclaration(ol,MemberList::proMethods,inGroup); + writePlainMemberDeclaration(ol,MemberList::proAttribs,inGroup); + writePlainMemberDeclaration(ol,MemberList::proSlots,inGroup); + writePlainMemberDeclaration(ol,MemberList::proStaticMethods,inGroup); + writePlainMemberDeclaration(ol,MemberList::proStaticAttribs,inGroup); + if (extractPackage) + { + writePlainMemberDeclaration(ol,MemberList::pacTypes,inGroup); + writePlainMemberDeclaration(ol,MemberList::pacMethods,inGroup); + writePlainMemberDeclaration(ol,MemberList::pacAttribs,inGroup); + writePlainMemberDeclaration(ol,MemberList::pacStaticMethods,inGroup); + writePlainMemberDeclaration(ol,MemberList::pacStaticAttribs,inGroup); + } + if (extractPrivate) + { + writePlainMemberDeclaration(ol,MemberList::priTypes,inGroup); + writePlainMemberDeclaration(ol,MemberList::priMethods,inGroup); + writePlainMemberDeclaration(ol,MemberList::priAttribs,inGroup); + writePlainMemberDeclaration(ol,MemberList::priSlots,inGroup); + writePlainMemberDeclaration(ol,MemberList::priStaticMethods,inGroup); + writePlainMemberDeclaration(ol,MemberList::priStaticAttribs,inGroup); + } + writePlainMemberDeclaration(ol,MemberList::friends,inGroup); + writePlainMemberDeclaration(ol,MemberList::related,inGroup); +} + +/*! a link to this class is possible within this project */ +bool ClassDef::isLinkableInProject() const +{ + static bool extractLocal = Config_getBool("EXTRACT_LOCAL_CLASSES"); + static bool extractStatic = Config_getBool("EXTRACT_STATIC"); + static bool hideUndoc = Config_getBool("HIDE_UNDOC_CLASSES"); + if (m_impl->templateMaster) + { + return m_impl->templateMaster->isLinkableInProject(); + } + else + { + return !name().isEmpty() && /* has a name */ + !isArtificial() && !isHidden() && /* not hidden */ + name().find('@')==-1 && /* not anonymous */ + protectionLevelVisible(m_impl->prot) && /* private/internal */ + (!m_impl->isLocal || extractLocal) && /* local */ + (hasDocumentation() || !hideUndoc) && /* documented */ + (!m_impl->isStatic || extractStatic) && /* static */ + !isReference(); /* not an external reference */ + } +} + +bool ClassDef::isLinkable() const +{ + if (m_impl->templateMaster) + { + return m_impl->templateMaster->isLinkable(); + } + else + { + return isLinkableInProject() || isReference(); + } +} + + +/*! the class is visible in a class diagram, or class hierarchy */ +bool ClassDef::isVisibleInHierarchy() +{ + static bool allExternals = Config_getBool("ALLEXTERNALS"); + static bool hideUndocClasses = Config_getBool("HIDE_UNDOC_CLASSES"); + static bool extractStatic = Config_getBool("EXTRACT_STATIC"); + + return // show all classes or a subclass is visible + (allExternals || hasNonReferenceSuperClass()) && + // and not an anonymous compound + name().find('@')==-1 && + // not an artificially introduced class + !isArtificial() && + // and not privately inherited + protectionLevelVisible(m_impl->prot) && + // documented or shown anyway or documentation is external + (hasDocumentation() || + !hideUndocClasses || + (m_impl->templateMaster && m_impl->templateMaster->hasDocumentation()) || + isReference() + ) && + // is not part of an unnamed namespace or shown anyway + (!m_impl->isStatic || extractStatic); +} + +bool ClassDef::hasDocumentation() const +{ + return Definition::hasDocumentation(); +} + +//---------------------------------------------------------------------- +// recursive function: +// returns TRUE iff class definition `bcd' represents an (in)direct base +// class of class definition `cd'. + +bool ClassDef::isBaseClass(ClassDef *bcd, bool followInstances,int level) +{ + bool found=FALSE; + //printf("isBaseClass(cd=%s) looking for %s\n",name().data(),bcd->name().data()); + if (level>256) + { + err("Possible recursive class relation while inside %s and looking for %s\n",qPrint(name()),qPrint(bcd->name())); + abort(); + return FALSE; + } + if (baseClasses()) + { + // Beware: trying to optimise the iterator away using ->first() & ->next() + // causes bug 625531 + BaseClassListIterator bcli(*baseClasses()); + for ( ; bcli.current() && !found ; ++bcli) + { + ClassDef *ccd=bcli.current()->classDef; + if (!followInstances && ccd->templateMaster()) ccd=ccd->templateMaster(); + //printf("isBaseClass() baseclass %s\n",ccd->name().data()); + if (ccd==bcd) + found=TRUE; + else + found=ccd->isBaseClass(bcd,followInstances,level+1); + } + } + return found; +} + +//---------------------------------------------------------------------------- + +static bool isStandardFunc(MemberDef *md) +{ + return md->name()=="operator=" || // assignment operator + md->isConstructor() || // constructor + md->isDestructor(); // destructor +} + +/*! + * recusively merges the `all members' lists of a class base + * with that of this class. Must only be called for classes without + * subclasses! + */ +void ClassDef::mergeMembers() +{ + if (m_impl->membersMerged) return; + + //static bool optimizeOutputForJava = Config_getBool("OPTIMIZE_OUTPUT_JAVA"); + //static bool vhdlOpt = Config_getBool("OPTIMIZE_OUTPUT_VHDL"); + SrcLangExt lang = getLanguage(); + QCString sep=getLanguageSpecificSeparator(lang,TRUE); + int sepLen = sep.length(); + + m_impl->membersMerged=TRUE; + //printf(" mergeMembers for %s\n",name().data()); + bool inlineInheritedMembers = Config_getBool("INLINE_INHERITED_MEMB" ); + if (baseClasses()) + { + //printf(" => has base classes!\n"); + BaseClassListIterator bcli(*baseClasses()); + BaseClassDef *bcd; + for ( ; (bcd=bcli.current()) ; ++bcli ) + { + ClassDef *bClass=bcd->classDef; + + // merge the members in the base class of this inheritance branch first + bClass->mergeMembers(); + + MemberNameInfoSDict *srcMnd = bClass->memberNameInfoSDict(); + MemberNameInfoSDict *dstMnd = m_impl->allMemberNameInfoSDict; + + if (srcMnd) + { + MemberNameInfoSDict::Iterator srcMnili(*srcMnd); + MemberNameInfo *srcMni; + for ( ; (srcMni=srcMnili.current()) ; ++srcMnili) + { + //printf(" Base member name %s\n",srcMni->memberName()); + MemberNameInfo *dstMni; + if (dstMnd!=0 && (dstMni=dstMnd->find(srcMni->memberName()))) + // a member with that name is already in the class. + // the member may hide or reimplement the one in the sub class + // or there may be another path to the base class that is already + // visited via another branch in the class hierarchy. + { + MemberNameInfoIterator srcMnii(*srcMni); + MemberInfo *srcMi; + for ( ; (srcMi=srcMnii.current()) ; ++srcMnii ) + { + MemberDef *srcMd = srcMi->memberDef; + bool found=FALSE; + bool ambigue=FALSE; + bool hidden=FALSE; + MemberNameInfoIterator dstMnii(*dstMni); + MemberInfo *dstMi; + ClassDef *srcCd = srcMd->getClassDef(); + for ( ; (dstMi=dstMnii.current()) && !found; ++dstMnii ) + { + MemberDef *dstMd = dstMi->memberDef; + if (srcMd!=dstMd) // different members + { + ClassDef *dstCd = dstMd->getClassDef(); + //printf(" Is %s a base class of %s?\n",srcCd->name().data(),dstCd->name().data()); + if (srcCd==dstCd || dstCd->isBaseClass(srcCd,TRUE)) + // member is in the same or a base class + { + LockingPtr<ArgumentList> srcAl = srcMd->argumentList(); + LockingPtr<ArgumentList> dstAl = dstMd->argumentList(); + found=matchArguments2( + srcMd->getOuterScope(),srcMd->getFileDef(),srcAl.pointer(), + dstMd->getOuterScope(),dstMd->getFileDef(),dstAl.pointer(), + TRUE + ); + //printf(" Yes, matching (%s<->%s): %d\n", + // argListToString(srcMd->argumentList()).data(), + // argListToString(dstMd->argumentList()).data(), + // found); + hidden = hidden || !found; + } + else // member is in a non base class => multiple inheritance + // using the same base class. + { + //printf("$$ Existing member %s %s add scope %s\n", + // dstMi->ambiguityResolutionScope.data(), + // dstMd->name().data(), + // dstMi->scopePath.left(dstMi->scopePath.find("::")+2).data()); + + QCString scope=dstMi->scopePath.left(dstMi->scopePath.find(sep)+sepLen); + if (scope!=dstMi->ambiguityResolutionScope.left(scope.length())) + dstMi->ambiguityResolutionScope.prepend(scope); + ambigue=TRUE; + } + } + else // same members + { + // do not add if base class is virtual or + // if scope paths are equal or + // if base class is an interface (and thus implicitly virtual). + //printf("same member found srcMi->virt=%d dstMi->virt=%d\n",srcMi->virt,dstMi->virt); + if ((srcMi->virt!=Normal && dstMi->virt!=Normal) || + bClass->name()+sep+srcMi->scopePath == dstMi->scopePath || + dstMd->getClassDef()->compoundType()==Interface + ) + { + found=TRUE; + } + else // member can be reached via multiple paths in the + // inheritance tree + { + //printf("$$ Existing member %s %s add scope %s\n", + // dstMi->ambiguityResolutionScope.data(), + // dstMd->name().data(), + // dstMi->scopePath.left(dstMi->scopePath.find("::")+2).data()); + + QCString scope=dstMi->scopePath.left(dstMi->scopePath.find(sep)+sepLen); + if (scope!=dstMi->ambiguityResolutionScope.left(scope.length())) + { + dstMi->ambiguityResolutionScope.prepend(scope); + } + ambigue=TRUE; + } + } + } + //printf("member %s::%s hidden %d ambigue %d srcMi->ambigClass=%p\n", + // srcCd->name().data(),srcMd->name().data(),hidden,ambigue,srcMi->ambigClass); + + // TODO: fix the case where a member is hidden by inheritance + // of a member with the same name but with another prototype, + // while there is more than one path to the member in the + // base class due to multiple inheritance. In this case + // it seems that the member is not reachable by prefixing a + // scope name either (according to my compiler). Currently, + // this case is shown anyway. + if (!found && srcMd->protection()!=Private) + { + Protection prot=srcMd->protection(); + if (bcd->prot==Protected && prot==Public) prot=bcd->prot; + else if (bcd->prot==Private) prot=bcd->prot; + + if (inlineInheritedMembers) + { + if (!isStandardFunc(srcMd)) + { + //printf(" insertMember `%s'\n",srcMd->name().data()); + internalInsertMember(srcMd,prot,FALSE); + } + } + + Specifier virt=srcMi->virt; + if (srcMi->virt==Normal && bcd->virt!=Normal) virt=bcd->virt; + + MemberInfo *newMi = new MemberInfo(srcMd,prot,virt,TRUE); + newMi->scopePath=bClass->name()+sep+srcMi->scopePath; + if (ambigue) + { + //printf("$$ New member %s %s add scope %s::\n", + // srcMi->ambiguityResolutionScope.data(), + // srcMd->name().data(), + // bClass->name().data()); + + QCString scope=bClass->name()+sep; + if (scope!=srcMi->ambiguityResolutionScope.left(scope.length())) + { + newMi->ambiguityResolutionScope= + scope+srcMi->ambiguityResolutionScope.copy(); + } + } + if (hidden) + { + if (srcMi->ambigClass==0) + { + newMi->ambigClass=bClass; + newMi->ambiguityResolutionScope=bClass->name()+sep; + } + else + { + newMi->ambigClass=srcMi->ambigClass; + newMi->ambiguityResolutionScope=srcMi->ambigClass->name()+sep; + } + } + dstMni->append(newMi); + } + } + } + else // base class has a member that is not in the sub class => copy + { + // create a deep copy of the list (only the MemberInfo's will be + // copied, not the actual MemberDef's) + MemberNameInfo *newMni = 0; + newMni = new MemberNameInfo(srcMni->memberName()); + + // copy the member(s) from the base to the sub class + MemberNameInfoIterator mnii(*srcMni); + MemberInfo *mi; + for (;(mi=mnii.current());++mnii) + { + Protection prot = mi->prot; + if (bcd->prot==Protected) + { + if (prot==Public) prot=Protected; + } + else if (bcd->prot==Private) + { + prot=Private; + } + //printf("%s::%s: prot=%d bcd->prot=%d result=%d\n", + // name().data(),mi->memberDef->name().data(),mi->prot, + // bcd->prot,prot); + + if (mi->prot!=Private) + { + Specifier virt=mi->virt; + if (mi->virt==Normal && bcd->virt!=Normal) virt=bcd->virt; + + if (inlineInheritedMembers) + { + if (!isStandardFunc(mi->memberDef)) + { + //printf(" insertMember `%s'\n",mi->memberDef->name().data()); + internalInsertMember(mi->memberDef,prot,FALSE); + } + } + //printf("Adding!\n"); + MemberInfo *newMi=new MemberInfo(mi->memberDef,prot,virt,TRUE); + newMi->scopePath=bClass->name()+sep+mi->scopePath; + newMi->ambigClass=mi->ambigClass; + newMi->ambiguityResolutionScope=mi->ambiguityResolutionScope.copy(); + newMni->append(newMi); + } + } + + if (dstMnd==0) + { + m_impl->allMemberNameInfoSDict = new MemberNameInfoSDict(17); + m_impl->allMemberNameInfoSDict->setAutoDelete(TRUE); + dstMnd = m_impl->allMemberNameInfoSDict; + } + // add it to the dictionary + dstMnd->append(newMni->memberName(),newMni); + } + } + } + } + } + //printf(" end mergeMembers\n"); +} + +//---------------------------------------------------------------------------- + +/*! Merges the members of a Objective-C category into this class. + */ +void ClassDef::mergeCategory(ClassDef *category) +{ + static bool extractLocalMethods = Config_getBool("EXTRACT_LOCAL_METHODS"); + bool makePrivate = category->isLocal(); + // in case extract local methods is not enabled we don't add the methods + // of the category in case it is defined in the .m file. + if (makePrivate && !extractLocalMethods) return; + + category->setCategoryOf(this); + category->setArtificial(TRUE); + // make methods private for categories defined in the .m file + //printf("%s::mergeCategory makePrivate=%d\n",name().data(),makePrivate); + + MemberNameInfoSDict *srcMnd = category->memberNameInfoSDict(); + MemberNameInfoSDict *dstMnd = m_impl->allMemberNameInfoSDict; + + if (srcMnd && dstMnd) + { + MemberNameInfoSDict::Iterator srcMnili(*srcMnd); + MemberNameInfo *srcMni; + for ( ; (srcMni=srcMnili.current()) ; ++srcMnili) + { + MemberNameInfo *dstMni=dstMnd->find(srcMni->memberName()); + if (dstMni) // method is already defined in the class + { + //printf("Existing member %s\n",srcMni->memberName()); + // TODO: we should remove the other member and insert this one. + MemberInfo *mi = dstMni->getFirst(); + if (mi) + { + Protection prot = mi->prot; + if (makePrivate) prot = Private; + removeMemberFromLists(mi->memberDef); + internalInsertMember(mi->memberDef,prot,FALSE); + } + } + else // new method name + { + //printf("New member %s\n",srcMni->memberName()); + // create a deep copy of the list + MemberNameInfo *newMni = 0; + newMni = new MemberNameInfo(srcMni->memberName()); + + // copy the member(s) from the category to this class + MemberNameInfoIterator mnii(*srcMni); + MemberInfo *mi; + for (;(mi=mnii.current());++mnii) + { + //printf("Adding '%s'\n",mi->memberDef->name().data()); + Protection prot = mi->prot; + if (makePrivate) prot = Private; + MemberInfo *newMi=new MemberInfo(mi->memberDef,prot,mi->virt,mi->inherited); + newMi->scopePath=mi->scopePath; + newMi->ambigClass=mi->ambigClass; + newMi->ambiguityResolutionScope=mi->ambiguityResolutionScope; + newMni->append(newMi); + mi->memberDef->moveTo(this); + mi->memberDef->setCategory(category); + internalInsertMember(mi->memberDef,prot,FALSE); + } + + // add it to the dictionary + dstMnd->append(newMni->memberName(),newMni); + } + } + } +} + +//---------------------------------------------------------------------------- + +void ClassDef::addUsedClass(ClassDef *cd,const char *accessName, + Protection prot) +{ + static bool extractPrivate = Config_getBool("EXTRACT_PRIVATE"); + if (prot==Private && !extractPrivate) return; + //printf("%s::addUsedClass(%s,%s)\n",name().data(),cd->name().data(),accessName); + if (m_impl->usesImplClassDict==0) + { + m_impl->usesImplClassDict = new UsesClassDict(17); + m_impl->usesImplClassDict->setAutoDelete(TRUE); + } + UsesClassDef *ucd=m_impl->usesImplClassDict->find(cd->name()); + if (ucd==0) + { + ucd = new UsesClassDef(cd); + m_impl->usesImplClassDict->insert(cd->name(),ucd); + //printf("Adding used class %s to class %s via accessor %s\n", + // cd->name().data(),name().data(),accessName); + } + ucd->addAccessor(accessName); +} + +void ClassDef::addUsedByClass(ClassDef *cd,const char *accessName, + Protection prot) +{ + static bool extractPrivate = Config_getBool("EXTRACT_PRIVATE"); + if (prot==Private && !extractPrivate) return; + //printf("%s::addUsedByClass(%s,%s)\n",name().data(),cd->name().data(),accessName); + if (m_impl->usedByImplClassDict==0) + { + m_impl->usedByImplClassDict = new UsesClassDict(17); + m_impl->usedByImplClassDict->setAutoDelete(TRUE); + } + UsesClassDef *ucd=m_impl->usedByImplClassDict->find(cd->name()); + if (ucd==0) + { + ucd = new UsesClassDef(cd); + m_impl->usedByImplClassDict->insert(cd->name(),ucd); + //printf("Adding used by 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! + */ + +void ClassDef::determineImplUsageRelation() +{ + MemberNameInfoSDict::Iterator mnili(*m_impl->allMemberNameInfoSDict); + 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()); + //printf("in class %s found var type=`%s' name=`%s'\n", + // name().data(),type.data(),md->name().data()); + int pos=0; + QCString usedClassName; + QCString templSpec; + bool found=FALSE; + while (extractClassNameFromType(type,pos,usedClassName,templSpec)!=-1 && !found) + { + //printf("usedClassName=`%s' templSpec=%s\n",usedClassName.data(),templSpec.data()); + // check if usedClassName is a template argument of its class + ClassDef *cd=md->getClassDef(); + if (cd && cd->templateArguments()) + { + ArgumentListIterator ali(*cd->templateArguments()); + Argument *arg; + int count=0; + for (ali.toFirst();(arg=ali.current());++ali,++count) + { + if (arg->name==usedClassName) // type is a template argument + { + found=TRUE; + if (m_impl->usesImplClassDict==0) m_impl->usesImplClassDict = new UsesClassDict(257); + cd = new ClassDef(cd->getDefFileName(),cd->getDefLine(), + usedClassName,ClassDef::Class); + cd->setIsTemplateBaseClass(count); + UsesClassDef *ucd = new UsesClassDef(cd); + m_impl->usesImplClassDict->insert(cd->name(),ucd); + ucd->templSpecifiers = templSpec; + ucd->addAccessor(md->name()); + Doxygen::hiddenClasses.append(cd); + //printf("Adding used template argument %s to class %s\n", + // cd->name().data(),name().data()); + //printf("Adding accessor %s to class %s\n", + // md->name().data(),ucd->classDef->name().data()); + } + } + } + + if (!found) + { + cd=0; + if (getNamespaceDef()!=0) + { + cd=getResolvedClass(getNamespaceDef()->name()+"::"+usedClassName,0,&templSpec); + } + if (cd==0) cd=getResolvedClass(name()+"::"+usedClassName,0,&templSpec); + if (cd==0) cd=getResolvedClass(usedClassName,0,&templSpec); // TODO: also try inbetween scopes! + //printf("Search for class %s result=%p\n",usedClassName.data(),cd); + if (cd) // class exists + { + found=TRUE; + if (m_impl->usesImplClassDict==0) + { + m_impl->usesImplClassDict = new UsesClassDict(257); + m_impl->usesImplClassDict->setAutoDelete(TRUE); + } + UsesClassDef *ucd=m_impl->usesImplClassDict->find(cd->name()); + if (ucd==0 || ucd->templSpecifiers!=templSpec) + { + ucd = new UsesClassDef(cd); + m_impl->usesImplClassDict->insert(cd->name(),ucd); + ucd->templSpecifiers = templSpec; + //printf("Adding used class %s to class %s\n", + // cd->name().data(),name().data()); + } + ucd->addAccessor(md->name()); + //printf("Adding accessor %s to class %s\n", + // md->name().data(),ucd->classDef->name().data()); + } + } + } + } + } + } +#ifdef DUMP + if (m_impl->usesClassDict) + { + msg("Class %s uses the following classes:\n",name().data()); + UsesClassDictIterator ucdi(*m_impl->usesClassDict); + UsesClassDef *ucd; + for (;(ucd=ucdi.current());++ucdi) + { + msg(" %s via ",ucd->classDef->name().data()); + QDictIterator<void> dvi(*ucd->accessors); + const char *s; + for (;(s=dvi.currentKey());++dvi) + { + msg("%s ",s); + } + msg("\n"); + } + } +#endif +} + +//---------------------------------------------------------------------------- + +// I have disabled this code because the graphs it renders quickly become +// too large to be of practical use. + +void ClassDef::addUsedInterfaceClasses(MemberDef *md,const char *typeStr) +{ + QCString type = typeStr; + static const QRegExp re("[a-z_A-Z][a-z_A-Z0-9:]*"); + int p=0,i,l; + while ((i=re.match(type,p,&l))!=-1) // for each class name in the type + { + ClassDef *cd=getClass(name()+"::"+type.mid(i,l)); + if (cd==0) cd=getClass(type.mid(i,l)); // TODO: also try inbetween scopes! + if (cd && cd!=this && !isBaseClass(cd)) + { + if (m_impl->usesIntfClassDict==0) + { + m_impl->usesIntfClassDict = new UsesClassDict(257); + } + UsesClassDef *ucd=m_impl->usesIntfClassDict->find(cd->name()); + if (ucd==0) + { + ucd = new UsesClassDef(cd); + m_impl->usesIntfClassDict->insert(cd->name(),ucd); + //printf("in class `%s' adding used intf class `%s'\n", + // name().data(),cd->name().data()); + } + ucd->addAccessor(md->name()); + //printf("in class `%s' adding accessor `%s' to class `%s'\n", + // name().data(),md->name().data(),ucd->classDef->name().data()); + } + p=i+l; + } +} + +void ClassDef::determineIntfUsageRelation() +{ + MemberNameInfoSDict::Iterator mnili(*m_impl->allMemberNameInfoList); + MemberNameInfo *mni; + for (;(mni=mnili.current());++mnili) + { + MemberNameInfoIterator mnii(*mni); + MemberInfo *mi; + for (mnii.toFirst();(mi=mnii.current());++mnii) + { + MemberDef *md=mi->memberDef; + + // compute the protection level for this member + Protection protect=md->protection(); + if (mi->prot==Protected) // inherited protection + { + if (protect==Public) protect=Protected; + else if (protect==Protected) protect=Private; + } + + if (!md->name().isEmpty() && md->name()[0]!='@' && + (mi->prot!=Private && protect!=Private) + ) + { + // add classes found in the return type + addUsedInterfaceClasses(md,md->typeString()); + ArgumentList *al = md->argumentList(); + if (al) // member has arguments + { + // add classes found in the types of the argument list + ArgumentListIterator ali(*al); + Argument *a; + for (;(a=ali.current());++ali) + { + if (!a->type.isEmpty() && a->type.at(0)!='@') + { + addUsedInterfaceClasses(md,a->type); + } + } + } + } + } + } +} +#endif + +QCString ClassDef::compoundTypeString() const +{ + if (getLanguage()==SrcLangExt_Fortran) + { + switch (m_impl->compType) + { + case Class: return "module"; + case Struct: return "type"; + case Union: return "union"; + case Interface: return "interface"; + case Protocol: return "protocol"; + case Category: return "category"; + case Exception: return "exception"; + default: return "unknown"; + } + } + else + { + switch (m_impl->compType) + { + case Class: return isJavaEnum() ? "enum" : "class"; + case Struct: return "struct"; + case Union: return "union"; + case Interface: return getLanguage()==SrcLangExt_ObjC ? "class" : "interface"; + case Protocol: return "protocol"; + case Category: return "category"; + case Exception: return "exception"; + default: return "unknown"; + } + } +} + +QCString ClassDef::getOutputFileBase() const +{ + if (!Doxygen::generatingXmlOutput) + { + static bool inlineGroupedClasses = Config_getBool("INLINE_GROUPED_CLASSES"); + static bool inlineSimpleClasses = Config_getBool("INLINE_SIMPLE_STRUCTS"); + Definition *scope=0; + if (inlineGroupedClasses && partOfGroups()!=0) + { + // point to the group that embeds this class + return partOfGroups()->at(0)->getOutputFileBase(); + } + else if (inlineSimpleClasses && m_impl->isSimple && partOfGroups()!=0) + { + // point to simple struct inside a group + return partOfGroups()->at(0)->getOutputFileBase(); + } + else if (inlineSimpleClasses && m_impl->isSimple && (scope=getOuterScope())) + { + if (scope==Doxygen::globalScope && getFileDef() && getFileDef()->isLinkableInProject()) // simple struct embedded in file + { + return getFileDef()->getOutputFileBase(); + } + else if (scope->isLinkableInProject()) // simple struct embedded in other container (namespace/group/class) + { + return getOuterScope()->getOutputFileBase(); + } + } + } + if (m_impl->templateMaster) + { + // point to the template of which this class is an instance + return m_impl->templateMaster->getOutputFileBase(); + } + else if (isReference()) + { + // point to the external location + return m_impl->fileName; + } + else + { + // normal locally defined class + return convertNameToFile(m_impl->fileName); + } +} + +QCString ClassDef::getInstanceOutputFileBase() const +{ + if (isReference()) + { + return m_impl->fileName; + } + else + { + return convertNameToFile(m_impl->fileName); + } +} + +QCString ClassDef::getFileBase() const +{ + if (m_impl->templateMaster) + { + return m_impl->templateMaster->getFileBase(); + } + else + { + return m_impl->fileName; + } +} + +QCString ClassDef::getSourceFileBase() const +{ + if (m_impl->templateMaster) + { + return m_impl->templateMaster->getSourceFileBase(); + } + else + { + return convertNameToFile(m_impl->fileName)+"_source"; + } +} + +void ClassDef::setGroupDefForAllMembers(GroupDef *gd,Grouping::GroupPri_t pri,const QCString &fileName,int startLine,bool hasDocs) +{ + gd->addClass(this); + //printf("ClassDef::setGroupDefForAllMembers(%s)\n",gd->name().data()); + if (m_impl->allMemberNameInfoSDict==0) return; + MemberNameInfoSDict::Iterator mnili(*m_impl->allMemberNameInfoSDict); + MemberNameInfo *mni; + for (;(mni=mnili.current());++mnili) + { + MemberNameInfoIterator mnii(*mni); + MemberInfo *mi; + for (mnii.toFirst();(mi=mnii.current());++mnii) + { + MemberDef *md=mi->memberDef; + md->setGroupDef(gd,pri,fileName,startLine,hasDocs); + gd->insertMember(md,TRUE); + ClassDef *innerClass = md->getClassDefOfAnonymousType(); + if (innerClass) innerClass->setGroupDefForAllMembers(gd,pri,fileName,startLine,hasDocs); + } + } +} + +void ClassDef::addInnerCompound(Definition *d) +{ + //printf("**** %s::addInnerCompound(%s)\n",name().data(),d->name().data()); + if (d->definitionType()==Definition::TypeClass) // only classes can be + // nested in classes. + { + if (m_impl->innerClasses==0) + { + m_impl->innerClasses = new ClassSDict(17); + } + m_impl->innerClasses->inSort(d->localName(),(ClassDef *)d); + } +} + +Definition *ClassDef::findInnerCompound(const char *name) +{ + Definition *result=0; + if (name==0) return 0; + if (m_impl->innerClasses) + { + result = m_impl->innerClasses->find(name); + } + return result; +} + +//void ClassDef::initTemplateMapping() +//{ +// m_impl->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_impl->templateMapping && formal) +// { +// if (m_impl->templateMapping->find(formal)) +// { +// m_impl->templateMapping->remove(formal); +// } +// m_impl->templateMapping->insert(formal,new QCString(actual)); +// } +//} +// +//QCString ClassDef::getTemplateArgumentMapping(const char *formal) const +//{ +// if (m_impl->templateMapping && formal) +// { +// QCString *s = m_impl->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_impl->templateInstances==0) + { + m_impl->templateInstances = new QDict<ClassDef>(17); + } + ClassDef *templateClass=m_impl->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,localName()+templSpec,ClassDef::Class); + templateClass->setTemplateMaster(this); + templateClass->setOuterScope(getOuterScope()); + templateClass->setHidden(isHidden()); + m_impl->templateInstances->insert(templSpec,templateClass); + freshInstance=TRUE; + } + return templateClass; +} + +ClassDef *ClassDef::getVariableInstance(const char *templSpec) +{ + if (m_impl->variableInstances==0) + { + m_impl->variableInstances = new QDict<ClassDef>(17); + m_impl->variableInstances->setAutoDelete(TRUE); + } + ClassDef *templateClass=m_impl->variableInstances->find(templSpec); + if (templateClass==0) + { + Debug::print(Debug::Classes,0," New template variable instance class `%s'`%s'\n",qPrint(name()),qPrint(templSpec)); + templateClass = new ClassDef("<code>",1,name()+templSpec, + ClassDef::Class,0,0,FALSE); + templateClass->addMembersToTemplateInstance( this, templSpec ); + templateClass->setTemplateMaster(this); + m_impl->variableInstances->insert(templSpec,templateClass); + } + return templateClass; +} + +void ClassDef::setTemplateBaseClassNames(QDict<int> *templateNames) +{ + if (templateNames==0) return; + if (m_impl->templBaseClassNames==0) + { + m_impl->templBaseClassNames = new QDict<int>(17); + m_impl->templBaseClassNames->setAutoDelete(TRUE); + } + // make a deep copy of the dictionary. + QDictIterator<int> qdi(*templateNames); + for (;qdi.current();++qdi) + { + if (m_impl->templBaseClassNames->find(qdi.currentKey())==0) + { + m_impl->templBaseClassNames->insert(qdi.currentKey(),new int(*qdi.current())); + } + } +} + +QDict<int> *ClassDef::getTemplateBaseClassNames() const +{ + return m_impl->templBaseClassNames; +} + +void ClassDef::addMembersToTemplateInstance(ClassDef *cd,const char *templSpec) +{ + //printf("%s::addMembersToTemplateInstance(%s,%s)\n",name().data(),cd->name().data(),templSpec); + if (cd->memberNameInfoSDict()==0) return; + MemberNameInfoSDict::Iterator mnili(*cd->memberNameInfoSDict()); + MemberNameInfo *mni; + for (;(mni=mnili.current());++mnili) + { + MemberNameInfoIterator mnii(*mni); + MemberInfo *mi; + for (mnii.toFirst();(mi=mnii.current());++mnii) + { + 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(),md->docFile(),md->docLine()); + imd->setBriefDescription(md->briefDescription(),md->briefFile(),md->briefLine()); + imd->setInbodyDocumentation(md->inbodyDocumentation(),md->inbodyFile(),md->inbodyLine()); + imd->setMemberSpecifiers(md->getMemberSpecifiers()); + imd->setMemberGroupId(md->getMemberGroupId()); + insertMember(imd); + //printf("Adding member=%s %s%s to class %s templSpec %s\n", + // imd->typeString(),imd->name().data(),imd->argsString(), + // imd->getClassDef()->name().data(),templSpec); + // insert imd in the list of all members + //printf("Adding member=%s class=%s\n",imd->name().data(),name().data()); + MemberName *mn = Doxygen::memberNameSDict->find(imd->name()); + if (mn==0) + { + mn = new MemberName(imd->name()); + Doxygen::memberNameSDict->append(imd->name(),mn); + } + mn->append(imd); + } + } +} + +QCString ClassDef::getReference() const +{ + if (m_impl->templateMaster) + { + return m_impl->templateMaster->getReference(); + } + else + { + return Definition::getReference(); + } +} + +bool ClassDef::isReference() const +{ + if (m_impl->templateMaster) + { + return m_impl->templateMaster->isReference(); + } + else + { + return Definition::isReference(); + } +} + +void ClassDef::getTemplateParameterLists(QList<ArgumentList> &lists) const +{ + Definition *d=getOuterScope(); + if (d) + { + if (d->definitionType()==Definition::TypeClass) + { + ClassDef *cd=(ClassDef *)d; + cd->getTemplateParameterLists(lists); + } + } + if (templateArguments()) + { + lists.append(templateArguments()); + } +} + +QCString ClassDef::qualifiedNameWithTemplateParameters( + QList<ArgumentList> *actualParams) const +{ + //static bool optimizeOutputJava = Config_getBool("OPTIMIZE_OUTPUT_JAVA"); + static bool hideScopeNames = Config_getBool("HIDE_SCOPE_NAMES"); + //printf("qualifiedNameWithTemplateParameters() localName=%s\n",localName().data()); + QCString scName; + Definition *d=getOuterScope(); + if (d) + { + if (d->definitionType()==Definition::TypeClass) + { + ClassDef *cd=(ClassDef *)d; + scName = cd->qualifiedNameWithTemplateParameters(actualParams); + } + else if (!hideScopeNames) + { + scName = d->qualifiedName(); + } + } + + SrcLangExt lang = getLanguage(); + QCString scopeSeparator = getLanguageSpecificSeparator(lang); + if (!scName.isEmpty()) scName+=scopeSeparator; + + bool isSpecialization = localName().find('<')!=-1; + bool isGeneric = getLanguage()==SrcLangExt_CSharp; + + QCString clName = className(); + if (isGeneric && clName.right(2)=="-g") + { + clName = clName.left(clName.length()-2); + } + //printf("m_impl->lang=%d clName=%s\n",m_impl->lang,clName.data()); + scName+=clName; + ArgumentList *al=0; + if (templateArguments()) + { + if (actualParams && (al=actualParams->current())) + { + if (!isSpecialization) + { + scName+=tempArgListToString(al); + } + actualParams->next(); + } + else + { + if (!isSpecialization) + { + scName+=tempArgListToString(templateArguments()); + } + } + } + //printf("qualifiedNameWithTemplateParameters: scope=%s qualifiedName=%s\n",name().data(),scName.data()); + return scName; +} + +QCString ClassDef::className() const +{ + if (m_impl->className.isEmpty()) + { + return localName(); + } + else + { + return m_impl->className; + } +}; + +void ClassDef::setClassName(const char *name) +{ + m_impl->className = name; +} + +void ClassDef::addListReferences() +{ + SrcLangExt lang = getLanguage(); + if (!isLinkableInProject()) return; + //printf("ClassDef(%s)::addListReferences()\n",name().data()); + { + LockingPtr< QList<ListItemInfo> > xrefItems = xrefListItems(); + addRefItem(xrefItems.pointer(), + qualifiedName(), + lang==SrcLangExt_Fortran ? theTranslator->trType(TRUE,TRUE) + : theTranslator->trClass(TRUE,TRUE), + getOutputFileBase(), + displayName(), + 0 + ); + } + if (m_impl->memberGroupSDict) + { + MemberGroupSDict::Iterator mgli(*m_impl->memberGroupSDict); + MemberGroup *mg; + for (;(mg=mgli.current());++mgli) + { + mg->addListReferences(this); + } + } + QListIterator<MemberList> mli(m_impl->memberLists); + MemberList *ml; + for (mli.toFirst();(ml=mli.current());++mli) + { + if (ml->listType()&MemberList::detailedLists) + { + ml->addListReferences(this); + } + } +} + +MemberDef *ClassDef::getMemberByName(const QCString &name) const +{ + MemberDef *xmd = 0; + if (m_impl->allMemberNameInfoSDict) + { + MemberNameInfo *mni = m_impl->allMemberNameInfoSDict->find(name); + if (mni) + { + const int maxInheritanceDepth = 100000; + int mdist=maxInheritanceDepth; + MemberNameInfoIterator mnii(*mni); + MemberInfo *mi; + for (mnii.toFirst();(mi=mnii.current());++mnii) + { + ClassDef *mcd=mi->memberDef->getClassDef(); + int m=minClassDistance(this,mcd); + //printf("found member in %s linkable=%d m=%d\n", + // mcd->name().data(),mcd->isLinkable(),m); + if (m<mdist && mcd->isLinkable()) + { + mdist=m; + xmd=mi->memberDef; + } + } + } + } + //printf("getMemberByName(%s)=%p\n",name.data(),xmd); + return xmd; +} + +bool ClassDef::isAccessibleMember(MemberDef *md) +{ + return md->getClassDef() && isBaseClass(md->getClassDef(),TRUE); +} + +MemberList *ClassDef::createMemberList(MemberList::ListType lt) +{ + m_impl->memberLists.setAutoDelete(TRUE); + QListIterator<MemberList> mli(m_impl->memberLists); + MemberList *ml; + for (mli.toFirst();(ml=mli.current());++mli) + { + if (ml->listType()==lt) + { + return ml; + } + } + // not found, create a new member list + ml = new MemberList(lt); + m_impl->memberLists.append(ml); + return ml; +} + +MemberList *ClassDef::getMemberList(MemberList::ListType lt) +{ + MemberList *ml = m_impl->memberLists.first(); + while (ml) + { + if (ml->listType()==lt) + { + return ml; + } + ml = m_impl->memberLists.next(); + } + return 0; +} + +void ClassDef::addMemberToList(MemberList::ListType lt,MemberDef *md,bool isBrief) +{ + static bool sortBriefDocs = Config_getBool("SORT_BRIEF_DOCS"); + static bool sortMemberDocs = Config_getBool("SORT_MEMBER_DOCS"); + MemberList *ml = createMemberList(lt); + ml->setNeedsSorting((isBrief && sortBriefDocs) || (!isBrief && sortMemberDocs)); + ml->append(md); + + // for members in the declaration lists we set the section, needed for member grouping + if ((ml->listType()&MemberList::detailedLists)==0) md->setSectionList(this,ml); +} + +void ClassDef::sortMemberLists() +{ + MemberList *ml = m_impl->memberLists.first(); + while (ml) + { + if (ml->needsSorting()) { ml->sort(); ml->setNeedsSorting(FALSE); } + ml = m_impl->memberLists.next(); + } +} + +void ClassDef::writeMemberDeclarations(OutputList &ol,MemberList::ListType lt,const QCString &title, + const char *subTitle,bool showInline) +{ + //printf("%s: ClassDef::writeMemberDeclarations\n",name().data()); + //static bool optimizeVhdl = Config_getBool("OPTIMIZE_OUTPUT_VHDL"); + MemberList * ml = getMemberList(lt); + if (ml) + { + if (getLanguage()==SrcLangExt_VHDL) // use specific declarations function + { + VhdlDocGen::writeVhdlDeclarations(ml,ol,0,this,0,0); + } + else // use generic declaration function + { + ml->writeDeclarations(ol,this,0,0,0,title,subTitle,FALSE,showInline); + } + } +} + +void ClassDef::writeMemberDocumentation(OutputList &ol,MemberList::ListType lt,const QCString &title,bool showInline) +{ + //printf("%s: ClassDef::writeMemberDocumentation()\n",name().data()); + MemberList * ml = getMemberList(lt); + if (ml) ml->writeDocumentation(ol,displayName(),this,title,FALSE,showInline); +} + +void ClassDef::writeSimpleMemberDocumentation(OutputList &ol,MemberList::ListType lt) +{ + //printf("%s: ClassDef::writeSimpleMemberDocumentation()\n",name().data()); + MemberList * ml = getMemberList(lt); + if (ml) ml->writeSimpleDocumentation(ol,this); +} + +void ClassDef::writePlainMemberDeclaration(OutputList &ol,MemberList::ListType lt,bool inGroup) +{ + //printf("%s: ClassDef::writePlainMemberDeclaration()\n",name().data()); + MemberList * ml = getMemberList(lt); + if (ml) + { + ml->setInGroup(inGroup); + ml->writePlainDeclarations(ol,this,0,0,0); + } +} + +bool ClassDef::isLocal() const +{ + return m_impl->isLocal; +} + +ClassSDict *ClassDef::getClassSDict() +{ + return m_impl->innerClasses; +} + +ClassDef::CompoundType ClassDef::compoundType() const +{ + return m_impl->compType; +} + +BaseClassList *ClassDef::baseClasses() const +{ + return m_impl->inherits; +} + +BaseClassList *ClassDef::subClasses() const +{ + return m_impl->inheritedBy; +} + +MemberNameInfoSDict *ClassDef::memberNameInfoSDict() const +{ + return m_impl->allMemberNameInfoSDict; +} + +Protection ClassDef::protection() const +{ + return m_impl->prot; +} + +ArgumentList *ClassDef::templateArguments() const +{ + return m_impl->tempArgs; +} + +NamespaceDef *ClassDef::getNamespaceDef() const +{ + return m_impl->nspace; +} + +FileDef *ClassDef::getFileDef() const +{ + return m_impl->fileDef; +} + +QDict<ClassDef> *ClassDef::getTemplateInstances() const +{ + return m_impl->templateInstances; +} + +ClassDef *ClassDef::templateMaster() const +{ + return m_impl->templateMaster; +} + +bool ClassDef::isTemplate() const +{ + return m_impl->tempArgs!=0; +} + +IncludeInfo *ClassDef::includeInfo() const +{ + return m_impl->incInfo; +} + +UsesClassDict *ClassDef::usedImplementationClasses() const +{ + return m_impl->usesImplClassDict; +} + +UsesClassDict *ClassDef::usedByImplementationClasses() const +{ + return m_impl->usedByImplClassDict; +} + +UsesClassDict *ClassDef::usedInterfaceClasses() const +{ + return m_impl->usesIntfClassDict; +} + +bool ClassDef::isTemplateArgument() const +{ + return m_impl->isTemplArg; +} + +bool ClassDef::isAbstract() const +{ + return m_impl->isAbstract; +} + +bool ClassDef::isObjectiveC() const +{ + return getLanguage()==SrcLangExt_ObjC; +} + +bool ClassDef::isCSharp() const +{ + return getLanguage()==SrcLangExt_CSharp; +} + +ClassDef *ClassDef::categoryOf() const +{ + return m_impl->categoryOf; +} + +const QList<MemberList> &ClassDef::getMemberLists() const +{ + return m_impl->memberLists; +} + +MemberGroupSDict *ClassDef::getMemberGroupSDict() const +{ + return m_impl->memberGroupSDict; +} + +void ClassDef::setNamespace(NamespaceDef *nd) +{ + m_impl->nspace = nd; +} + +void ClassDef::setFileDef(FileDef *fd) +{ + m_impl->fileDef=fd; +} + +void ClassDef::setSubGrouping(bool enabled) +{ + m_impl->subGrouping = enabled; +} + +void ClassDef::setProtection(Protection p) +{ + m_impl->prot=p; +} + +void ClassDef::setIsStatic(bool b) +{ + m_impl->isStatic=b; +} + +void ClassDef::setCompoundType(CompoundType t) +{ + m_impl->compType = t; +} + +void ClassDef::setTemplateMaster(ClassDef *tm) +{ + m_impl->templateMaster=tm; +} + +void ClassDef::makeTemplateArgument(bool b) +{ + m_impl->isTemplArg = b; +} + +void ClassDef::setCategoryOf(ClassDef *cd) +{ + m_impl->categoryOf = cd; +} + +void ClassDef::setUsedOnly(bool b) +{ + m_impl->usedOnly = b; +} + +bool ClassDef::isUsedOnly() const +{ + return m_impl->usedOnly; +} + +bool ClassDef::isSimple() const +{ + return m_impl->isSimple; +} + +MemberDef *ClassDef::isSmartPointer() const +{ + return m_impl->arrowOperator; +} + +void ClassDef::reclassifyMember(MemberDef *md,MemberDef::MemberType t) +{ + md->setMemberType(t); + MemberList *ml = m_impl->memberLists.first(); + while (ml) + { + ml->remove(md); + ml = m_impl->memberLists.next(); + } + insertMember(md); +} + +QCString ClassDef::anchor() const +{ + QCString anc; + if (isEmbeddedInOuterScope() && !Doxygen::generatingXmlOutput) + { + if (m_impl->templateMaster) + { + // point to the template of which this class is an instance + anc = m_impl->templateMaster->getOutputFileBase(); + } + else if (isReference()) + { + // point to the external location + anc = m_impl->fileName; + } + else + { + // normal locally defined class + anc = convertNameToFile(m_impl->fileName); + } + } + return anc; +} + +bool ClassDef::isEmbeddedInOuterScope() const +{ + static bool inlineGroupedClasses = Config_getBool("INLINE_GROUPED_CLASSES"); + static bool inlineSimpleClasses = Config_getBool("INLINE_SIMPLE_STRUCTS"); + + Definition *container = getOuterScope(); + + bool containerLinkable = + container && + ( + (container==Doxygen::globalScope && getFileDef() && getFileDef()->isLinkableInProject()) || // global class in documented file + container->isLinkableInProject() // class in documented scope + ); + + // inline because of INLINE_GROUPED_CLASSES=YES ? + bool b1 = (inlineGroupedClasses && partOfGroups()!=0); // a grouped class + // inline because of INLINE_SIMPLE_STRUCTS=YES ? + bool b2 = (inlineSimpleClasses && m_impl->isSimple && // a simple class + (containerLinkable || // in a documented container + partOfGroups()!=0 // or part of a group + ) + ); + //printf("%s::isEmbeddedInOuterScope(): inlineGroupedClasses=%d " + // "inlineSimpleClasses=%d partOfGroups()=%p m_impl->isSimple=%d " + // "getOuterScope()=%p b1=%d b2=%d\n", + // name().data(),inlineGroupedClasses,inlineSimpleClasses, + // partOfGroups().pointer(),m_impl->isSimple,getOuterScope(),b1,b2); + return b1 || b2; // either reason will do +} + +const ClassList *ClassDef::taggedInnerClasses() const +{ + return m_impl->taggedInnerClasses; +} + +void ClassDef::addTaggedInnerClass(ClassDef *cd) +{ + if (m_impl->taggedInnerClasses==0) + { + m_impl->taggedInnerClasses = new ClassList; + } + m_impl->taggedInnerClasses->append(cd); +} + +ClassDef *ClassDef::tagLessReference() const +{ + return m_impl->tagLessRef; +} + +void ClassDef::setTagLessReference(ClassDef *cd) +{ + m_impl->tagLessRef = cd; +} + +void ClassDef::removeMemberFromLists(MemberDef *md) +{ + MemberList *ml = m_impl->memberLists.first(); + while (ml) + { + ml->remove(md); + ml = m_impl->memberLists.next(); + } +} + +bool ClassDef::isJavaEnum() const +{ + return m_impl->isJavaEnum; +} diff --git a/trunk/src/classdef.h b/trunk/src/classdef.h new file mode 100644 index 0000000..205b437 --- /dev/null +++ b/trunk/src/classdef.h @@ -0,0 +1,495 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#ifndef CLASSDEF_H +#define CLASSDEF_H + +#include "qtbc.h" +#include <qlist.h> +#include <qdict.h> +#include <qstrlist.h> + +#include "util.h" +#include "memberlist.h" +#include "definition.h" +#include "sortdict.h" + +class MemberDict; +class ClassList; +class ClassSDict; +class OutputList; +class FileDef; +class BaseClassList; +class NamespaceDef; +class MemberDef; +class ExampleSDict; +class MemberNameInfoSDict; +class UsesClassDict; +class MemberGroupSDict; +class QTextStream; +class PackageDef; +class GroupDef; +class StringDict; +struct IncludeInfo; +class ClassDefImpl; + +/*! \brief This class contains all information about a compound. + * + * A compound can be a class, struct, union, interface, or exception. + * \note This class should be renamed to CompoundDef + */ +class ClassDef : public Definition +{ + public: + /*! The various compound types */ + enum CompoundType { Class, //=Entry::CLASS_SEC, + Struct, //=Entry::STRUCT_SEC, + Union, //=Entry::UNION_SEC, + Interface, //=Entry::INTERFACE_SEC, + Protocol, //=Entry::PROTOCOL_SEC, + Category, //=Entry::CATEGORY_SEC, + Exception //=Entry::EXCEPTION_SEC + }; + + /*! Creates a new compound definition. + * \param fileName full path and file name in which this compound was + * found. + * \param startLine line number where the definition of this compound + * starts. + * \param name the name of this compound (including scope) + * \param ct the kind of Compound + * \param ref the tag file from which this compound is extracted + * or 0 if the compound doesn't come from a tag file + * \param fName the file name as found in the tag file. + * This overwrites the file that doxygen normally + * generates based on the compound type & name. + * \param isSymbol If TRUE this class name is added as a publicly + * visible (and referencable) symbol. + * \param isJavaEnum If TRUE this class is actually a Java enum. + * I didn't add this to CompoundType to avoid having + * to adapt all translators. + */ + ClassDef(const char *fileName,int startLine, + const char *name,CompoundType ct, + const char *ref=0,const char *fName=0, + bool isSymbol=TRUE,bool isJavaEnum=FALSE); + /*! Destroys a compound definition. */ + ~ClassDef(); + + //----------------------------------------------------------------------------------- + // --- getters + //----------------------------------------------------------------------------------- + + /*! Used for RTTI, this is a class */ + DefType definitionType() const { return TypeClass; } + + /*! Returns the unique base name (without extension) of the class's file on disk */ + QCString getOutputFileBase() const; + QCString getInstanceOutputFileBase() const; + QCString getFileBase() const; + + /*! Returns the base name for the source code file */ + QCString getSourceFileBase() const; + + /*! If this class originated from a tagfile, this will return the tag file reference */ + QCString getReference() const; + + /*! Returns TRUE if this class is imported via a tag file */ + bool isReference() const; + + /*! Returns TRUE if this is a local class definition, see EXTRACT_LOCAL_CLASSES */ + bool isLocal() const; + + /*! returns the classes nested into this class */ + ClassSDict *getClassSDict(); + + /*! returns TRUE if this class has documentation */ + bool hasDocumentation() const; + + /*! Returns the name as it is appears in the documentation */ + QCString displayName() const; + + /*! Returns the type of compound this is, i.e. class/struct/union/.. */ + CompoundType compoundType() const; + + /*! Returns the type of compound as a string */ + QCString compoundTypeString() const; + + /*! Returns the list of base classes from which this class directly + * inherits. + */ + BaseClassList *baseClasses() const; + + /*! Returns the list of sub classes that directly derive from this class + */ + BaseClassList *subClasses() const; + + /*! Returns a dictionary of all members. This includes any inherited + * members. Members are sorted alphabetically. + */ + MemberNameInfoSDict *memberNameInfoSDict() const; + + /*! Return the protection level (Public,Protected,Private) in which + * this compound was found. + */ + Protection protection() const; + + /*! returns TRUE iff a link is possible to this item within this project. + */ + 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() const; + + /*! the class is visible in a class diagram, or class hierarchy */ + bool isVisibleInHierarchy(); + + /*! Returns the template arguments of this class + * Will return 0 if not applicable. + */ + ArgumentList *templateArguments() const; + + /*! Returns the namespace this compound is in, or 0 if it has a global + * scope. + */ + NamespaceDef *getNamespaceDef() const; + + /*! Returns the file in which this compound's definition can be found. + * Should not return 0 (but it might be a good idea to check anyway). + */ + FileDef *getFileDef() const; + + /*! Returns the Java package this class is in or 0 if not applicable. + */ + + MemberDef *getMemberByName(const QCString &) const; + + /*! Returns TRUE iff \a bcd is a direct or indirect base class of this + * class. This function will recusively traverse all branches of the + * inheritance tree. + */ + bool isBaseClass(ClassDef *bcd,bool followInstances,int level=0); + + /*! returns TRUE iff \a md is a member of this class or of the + * the public/protected members of a base class + */ + bool isAccessibleMember(MemberDef *md); + + /*! 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; + + /*! Returns the template master of which this class is an instance. + * Returns 0 if not applicable. + */ + ClassDef *templateMaster() const; + + /*! Returns TRUE if this class is a template */ + bool isTemplate() const; + + IncludeInfo *includeInfo() const; + + UsesClassDict *usedImplementationClasses() const; + + UsesClassDict *usedByImplementationClasses() const; + + UsesClassDict *usedInterfaceClasses() const; + + bool isTemplateArgument() const; + + /*! 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); + + /*! Returns the template parameter lists that form the template + * declaration of this class. + * + * Example: <code>template<class T> class TC {};</code> + * will return a list with one ArgumentList containing one argument + * with type="class" and name="T". + */ + void getTemplateParameterLists(QList<ArgumentList> &lists) const; + + QCString qualifiedNameWithTemplateParameters( + QList<ArgumentList> *actualParams=0) const; + + /*! Returns TRUE if there is at least one pure virtual member in this + * class. + */ + bool isAbstract() const; + + /*! Returns TRUE if this class is implemented in Objective-C */ + bool isObjectiveC() const; + + /*! Returns TRUE if this class is implemented in C# */ + bool isCSharp() const; + + /*! Returns the class of which this is a category (Objective-C only) */ + ClassDef *categoryOf() const; + + /*! Returns the name of the class including outer classes, but not + * including namespaces. + */ + QCString className() const; + + /*! Returns the members in the list identified by \a lt */ + MemberList *getMemberList(MemberList::ListType lt); + + /*! Returns the list containing the list of members sorted per type */ + const QList<MemberList> &getMemberLists() const; + + /*! Returns the member groups defined for this class */ + MemberGroupSDict *getMemberGroupSDict() const; + + QDict<int> *getTemplateBaseClassNames() const; + + ClassDef *getVariableInstance(const char *templSpec); + + bool isUsedOnly() const; + + QCString anchor() const; + bool isEmbeddedInOuterScope() const; + + bool isSimple() const; + + const ClassList *taggedInnerClasses() const; + ClassDef *tagLessReference() const; + + MemberDef *isSmartPointer() const; + + bool isJavaEnum() const; + + //----------------------------------------------------------------------------------- + // --- setters ---- + //----------------------------------------------------------------------------------- + + void insertBaseClass(ClassDef *,const char *name,Protection p,Specifier s,const char *t=0); + void insertSubClass(ClassDef *,Protection p,Specifier s,const char *t=0); + void setIncludeFile(FileDef *fd,const char *incName,bool local,bool force); + void insertMember(MemberDef *); + void insertUsedFile(const char *); + bool addExample(const char *anchor,const char *name, const char *file); + void mergeCategory(ClassDef *category); + void setNamespace(NamespaceDef *nd); + void setFileDef(FileDef *fd); + void setSubGrouping(bool enabled); + void setProtection(Protection p); + void setGroupDefForAllMembers(GroupDef *g,Grouping::GroupPri_t pri,const QCString &fileName,int startLine,bool hasDocs); + void addInnerCompound(Definition *d); + ClassDef *insertTemplateInstance(const QCString &fileName,int startLine, + const QCString &templSpec,bool &freshInstance); + void addUsedClass(ClassDef *cd,const char *accessName,Protection prot); + void addUsedByClass(ClassDef *cd,const char *accessName,Protection prot); + void setIsStatic(bool b); + void setCompoundType(CompoundType t); + void setClassName(const char *name); + + void setTemplateArguments(ArgumentList *al); + void setTemplateBaseClassNames(QDict<int> *templateNames); + void setTemplateMaster(ClassDef *tm); + void setTypeConstraints(ArgumentList *al); + void addMembersToTemplateInstance(ClassDef *cd,const char *templSpec); + void makeTemplateArgument(bool b=TRUE); + void setCategoryOf(ClassDef *cd); + void setUsedOnly(bool b); + + void addTaggedInnerClass(ClassDef *cd); + void setTagLessReference(ClassDef *cd); + + //----------------------------------------------------------------------------------- + // --- actions ---- + //----------------------------------------------------------------------------------- + + void findSectionsInDocumentation(); + void addMembersToMemberGroup(); + void addListReferences(); + void computeAnchors(); + void mergeMembers(); + void sortMemberLists(); + void distributeMemberGroupDocumentation(); + void writeDocumentation(OutputList &ol); + void writeDocumentationForInnerClasses(OutputList &ol); + void writeMemberPages(OutputList &ol); + void writeMemberList(OutputList &ol); + void writeDeclaration(OutputList &ol,MemberDef *md,bool inGroup); + void writeQuickMemberLinks(OutputList &ol,MemberDef *md) const; + void writeSummaryLinks(OutputList &ol); + void reclassifyMember(MemberDef *md,MemberDef::MemberType t); + void writeInlineDocumentation(OutputList &ol); + void writeDeclarationLink(OutputList &ol,bool &found, + const char *header,bool localNames); + void removeMemberFromLists(MemberDef *md); + + bool visited; + + protected: + void addUsedInterfaceClasses(MemberDef *md,const char *typeStr); + bool hasExamples(); + bool hasNonReferenceSuperClass(); + void showUsedFiles(OutputList &ol); + + private: + void writeTagFileMarker(); + void writeDocumentationContents(OutputList &ol,const QCString &pageTitle); + void internalInsertMember(MemberDef *md,Protection prot,bool addToAllList); + QCString getMemberListFileName() const; + void addMemberToList(MemberList::ListType lt,MemberDef *md,bool isBrief); + MemberList *createMemberList(MemberList::ListType lt); + void writeMemberDeclarations(OutputList &ol,MemberList::ListType lt,const QCString &title, + const char *subTitle=0,bool showInline=FALSE); + void writeMemberDocumentation(OutputList &ol,MemberList::ListType lt,const QCString &title,bool showInline=FALSE); + void writeSimpleMemberDocumentation(OutputList &ol,MemberList::ListType lt); + void writePlainMemberDeclaration(OutputList &ol,MemberList::ListType lt,bool inGroup); + void writeBriefDescription(OutputList &ol,bool exampleFlag); + void writeDetailedDescription(OutputList &ol,const QCString &pageType,bool exampleFlag, + const QCString &title,const QCString &anchor=QCString()); + void writeIncludeFiles(OutputList &ol); + void writeAllMembersLink(OutputList &ol); + void writeInheritanceGraph(OutputList &ol); + void writeCollaborationGraph(OutputList &ol); + void writeMemberGroups(OutputList &ol,bool showInline=FALSE); + void writeNestedClasses(OutputList &ol,const QCString &title); + void writeInlineClasses(OutputList &ol); + void startMemberDeclarations(OutputList &ol); + void endMemberDeclarations(OutputList &ol); + void startMemberDocumentation(OutputList &ol); + void endMemberDocumentation(OutputList &ol); + void writeAuthorSection(OutputList &ol); + void writeMoreLink(OutputList &ol,const QCString &anchor); + void writeDetailedDocumentationBody(OutputList &ol); + + ClassDefImpl *m_impl; + +}; + +/*! \brief Class that contains information about a usage relation. + */ +struct UsesClassDef +{ + UsesClassDef(ClassDef *cd) : classDef(cd) + { + accessors = new QDict<void>(17); + containment = TRUE; + } + ~UsesClassDef() + { + delete accessors; + } + void addAccessor(const char *s) + { + if (accessors->find(s)==0) + { + accessors->insert(s,(void *)666); + } + } + /*! Class definition that this relation uses. */ + ClassDef *classDef; + + /*! Dictionary of member variable names that form the edge labels of the + * usage relation. + */ + QDict<void> *accessors; + + /*! Template arguments used for the base class */ + QCString templSpecifiers; + + bool containment; +}; + +/*! \brief Dictionary of usage relations. + */ +class UsesClassDict : public QDict<UsesClassDef> +{ + public: + UsesClassDict(int size) : QDict<UsesClassDef>(size) {} + ~UsesClassDict() {} +}; + +/*! \brief Iterator class to iterate over a dictionary of usage relations. + */ +class UsesClassDictIterator : public QDictIterator<UsesClassDef> +{ + public: + UsesClassDictIterator(const QDict<UsesClassDef> &d) + : QDictIterator<UsesClassDef>(d) {} + ~UsesClassDictIterator() {} +}; + +/*! \brief Class that contains information about an inheritance relation. + */ +struct BaseClassDef +{ + BaseClassDef(ClassDef *cd,const char *n,Protection p, + Specifier v,const char *t) : + classDef(cd), usedName(n), prot(p), virt(v), templSpecifiers(t) {} + + /*! Class definition that this relation inherits from. */ + ClassDef *classDef; + + /*! name used in the inheritance list + * (may be a typedef name instead of the class name) + */ + QCString usedName; + + /*! Protection level of the inheritance relation: + * Public, Protected, or Private + */ + Protection prot; + + /*! Virtualness of the inheritance relation: + * Normal, or Virtual + */ + Specifier virt; + + /*! Template arguments used for the base class */ + QCString templSpecifiers; +}; + +/*! \brief list of base classes + * + * The classes are alphabetically sorted on name if inSort() is used. + */ +class BaseClassList : public QList<BaseClassDef> +{ + public: + ~BaseClassList() {} + int compareItems(GCI item1,GCI item2) + { + ClassDef *c1=((BaseClassDef *)item1)->classDef; + ClassDef *c2=((BaseClassDef *)item2)->classDef; + if (c1==0 || c2==0) + return FALSE; + else + return stricmp(c1->name(),c2->name()); + } +}; + +/*! \brief Iterator for a list of base classes + */ +class BaseClassListIterator : public QListIterator<BaseClassDef> +{ + public: + BaseClassListIterator(const BaseClassList &bcl) : + QListIterator<BaseClassDef>(bcl) {} +}; + +#endif diff --git a/trunk/src/classlist.cpp b/trunk/src/classlist.cpp new file mode 100644 index 0000000..b85b178 --- /dev/null +++ b/trunk/src/classlist.cpp @@ -0,0 +1,163 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#include "classlist.h" +#include "config.h" +#include "util.h" +#include "outputlist.h" +#include "language.h" +#include "doxygen.h" +#include "vhdldocgen.h" + +ClassList::ClassList() : QList<ClassDef>() +{ +} + +ClassList::~ClassList() +{ +} + +static int compItems(void *item1,void *item2) +{ + ClassDef *c1=(ClassDef *)item1; + ClassDef *c2=(ClassDef *)item2; + static bool b = Config_getBool("SORT_BY_SCOPE_NAME"); + //printf("compItems: %d %s<->%s\n",b,c1->name().data(),c2->name().data()); + if (b) + { + return stricmp(c1->name(), + c2->name()); + } + else + { + return stricmp(c1->className(), + c2->className()); + } +} + +int ClassList::compareItems(GCI item1, GCI item2) +{ + return compItems(item1,item2); +} + +int ClassSDict::compareItems(GCI item1, GCI item2) +{ + return compItems(item1,item2); +} + +ClassListIterator::ClassListIterator(const ClassList &cllist) : + QListIterator<ClassDef>(cllist) +{ +} + +bool ClassSDict::declVisible(const ClassDef::CompoundType *filter) const +{ + static bool hideUndocClasses = Config_getBool("HIDE_UNDOC_CLASSES"); + static bool extractLocalClasses = Config_getBool("EXTRACT_LOCAL_CLASSES"); + if (count()>0) + { + ClassSDict::Iterator sdi(*this); + ClassDef *cd=0; + for (sdi.toFirst();(cd=sdi.current());++sdi) + { + if (cd->name().find('@')==-1 && + (filter==0 || *filter==cd->compoundType()) + ) + { + bool isLink = cd->isLinkable(); + if (isLink || + (!hideUndocClasses && + (!cd->isLocal() || extractLocalClasses) + ) + ) + { + return TRUE; + } + } + } + } + return FALSE; +} + +void ClassSDict::writeDeclaration(OutputList &ol,const ClassDef::CompoundType *filter, + const char *header,bool localNames) +{ + if (count()>0) + { + ClassSDict::Iterator sdi(*this); + ClassDef *cd=0; + bool found=FALSE; + for (sdi.toFirst();(cd=sdi.current());++sdi) + { + //printf(" ClassSDict::writeDeclaration for %s\n",cd->name().data()); + if (cd->name().find('@')==-1 && + (filter==0 || *filter==cd->compoundType()) + ) + { + cd->writeDeclarationLink(ol,found,header,localNames); + } + } + if (found) ol.endMemberList(); + } +} + +void ClassSDict::writeDocumentation(OutputList &ol,Definition * container) +{ + static bool fortranOpt = Config_getBool("OPTIMIZE_FOR_FORTRAN"); + + static bool inlineGroupedClasses = Config_getBool("INLINE_GROUPED_CLASSES"); + static bool inlineSimpleClasses = Config_getBool("INLINE_SIMPLE_STRUCTS"); + if (!inlineGroupedClasses && !inlineSimpleClasses) return; + + if (count()>0) + { + bool found=FALSE; + + ClassSDict::Iterator sdi(*this); + ClassDef *cd=0; + for (sdi.toFirst();(cd=sdi.current());++sdi) + { + //printf("%s:writeDocumentation() %p embedded=%d container=%p\n", + // cd->name().data(),cd->getOuterScope(),cd->isEmbeddedInOuterScope(), + // container); + + if (cd->name().find('@')==-1 && + cd->isLinkableInProject() && + cd->isEmbeddedInOuterScope() && + (container==0 || cd->partOfGroups()==0) // if container==0 -> show as part of the group docs, otherwise only show if not part of a group + //&& + //(container==0 || // no container -> used for groups + // cd->getOuterScope()==container || // correct container -> used for namespaces and classes + // (container->definitionType()==Definition::TypeFile && cd->getOuterScope()==Doxygen::globalScope && cd->partOfGroups()==0) // non grouped class with file scope -> used for files + //) + ) + { + if (!found) + { + ol.writeRuler(); + ol.startGroupHeader(); + ol.parseText(fortranOpt?theTranslator->trTypeDocumentation(): + theTranslator->trClassDocumentation()); + ol.endGroupHeader(); + found=TRUE; + } + cd->writeInlineDocumentation(ol); + } + } + } +} + diff --git a/trunk/src/classlist.h b/trunk/src/classlist.h new file mode 100644 index 0000000..9b76c39 --- /dev/null +++ b/trunk/src/classlist.h @@ -0,0 +1,63 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#ifndef CLASSLIST_H +#define CLASSLIST_H + +#include <qlist.h> +#include <qdict.h> + +#include "classdef.h" +#include "sortdict.h" + +class Definition; + +class ClassList : public QList<ClassDef> +{ + public: + ClassList(); + ~ClassList(); + + int compareItems(GCI item1,GCI item2); +}; + +class ClassListIterator : public QListIterator<ClassDef> +{ + public: + ClassListIterator(const ClassList &list); +}; + +class ClassDict : public QDict<ClassDef> +{ + public: + ClassDict(int size) : QDict<ClassDef>(size) {} + ~ClassDict() {} +}; + +class ClassSDict : public SDict<ClassDef> +{ + public: + ClassSDict(int size=17) : SDict<ClassDef>(size) {} + ~ClassSDict() {} + int compareItems(GCI item1,GCI item2); + void writeDeclaration(OutputList &ol,const ClassDef::CompoundType *filter=0, + const char *header=0,bool localNames=FALSE); + void writeDocumentation(OutputList &ol,Definition *container=0); + bool declVisible(const ClassDef::CompoundType *filter=0) const; +}; + +#endif diff --git a/trunk/src/cmdmapper.cpp b/trunk/src/cmdmapper.cpp new file mode 100644 index 0000000..5d52557 --- /dev/null +++ b/trunk/src/cmdmapper.cpp @@ -0,0 +1,204 @@ +/****************************************************************************** + * + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#include "cmdmapper.h" + +CommandMap cmdMap[] = +{ + { "a", CMD_EMPHASIS }, + { "addindex", CMD_ADDINDEX }, + { "anchor", CMD_ANCHOR }, + { "arg", CMD_LI }, + { "attention", CMD_ATTENTION }, + { "author", CMD_AUTHOR }, + { "authors", CMD_AUTHORS }, + { "b", CMD_BOLD }, + { "c", CMD_CODE }, + { "cite", CMD_CITE }, + { "code", CMD_STARTCODE }, + { "copydoc", CMD_COPYDOC }, + { "copybrief", CMD_COPYBRIEF }, + { "copydetails", CMD_COPYDETAILS }, + { "copyright", CMD_COPYRIGHT }, + { "date", CMD_DATE }, + { "dontinclude", CMD_DONTINCLUDE }, + { "dotfile", CMD_DOTFILE }, + { "e", CMD_EMPHASIS }, + { "em", CMD_EMPHASIS }, + { "endcode", CMD_ENDCODE }, + { "endhtmlonly", CMD_ENDHTMLONLY }, + { "endlatexonly", CMD_ENDLATEXONLY }, + { "endlink", CMD_ENDLINK }, + { "endsecreflist", CMD_ENDSECREFLIST }, + { "endverbatim", CMD_ENDVERBATIM }, + { "endxmlonly", CMD_ENDXMLONLY }, + { "exception", CMD_EXCEPTION }, + { "form", CMD_FORMULA }, + { "htmlinclude", CMD_HTMLINCLUDE }, + { "htmlonly", CMD_HTMLONLY }, + { "image", CMD_IMAGE }, + { "include", CMD_INCLUDE }, + { "internal", CMD_INTERNAL }, + { "invariant", CMD_INVARIANT }, + { "javalink", CMD_JAVALINK }, + { "latexonly", CMD_LATEXONLY }, + { "li", CMD_LI }, + { "line", CMD_LINE }, + { "link", CMD_LINK }, + { "n", CMD_LINEBREAK }, + { "note", CMD_NOTE }, + { "p", CMD_CODE }, + { "par", CMD_PAR }, + { "param", CMD_PARAM }, + { "post", CMD_POST }, + { "pre", CMD_PRE }, + { "ref", CMD_REF }, + { "refitem", CMD_SECREFITEM }, + { "remark", CMD_REMARK }, + { "remarks", CMD_REMARK }, + { "result", CMD_RETURN }, + { "return", CMD_RETURN }, + { "returns", CMD_RETURN }, + { "retval", CMD_RETVAL }, + { "sa", CMD_SA }, + { "secreflist", CMD_SECREFLIST }, + { "section", CMD_SECTION }, + { "snippet", CMD_SNIPPET }, + { "subpage", CMD_SUBPAGE }, + { "subsection", CMD_SUBSECTION }, + { "subsubsection", CMD_SUBSUBSECTION }, + { "paragraph", CMD_PARAGRAPH }, + { "see", CMD_SA }, + { "since", CMD_SINCE }, + { "skip", CMD_SKIP }, + { "skipline", CMD_SKIPLINE }, + { "xmlonly", CMD_XMLONLY }, + { "xrefitem", CMD_XREFITEM }, + { "throw", CMD_EXCEPTION }, + { "until", CMD_UNTIL }, + { "verbatim", CMD_VERBATIM }, + { "verbinclude", CMD_VERBINCLUDE }, + { "version", CMD_VERSION }, + { "warning", CMD_WARNING }, + { "throws", CMD_EXCEPTION }, + { "tparam", CMD_TPARAM }, + { "\\", CMD_BSLASH }, + { "@", CMD_AT }, + { "<", CMD_LESS }, + { ">", CMD_GREATER }, + { "&", CMD_AMP }, + { "$", CMD_DOLLAR }, + { "#", CMD_HASH }, + { "%", CMD_PERCENT }, + { "::", CMD_DCOLON }, + { "\"", CMD_QUOTE }, + { "_internalref", CMD_INTERNALREF }, + { "dot", CMD_DOT }, + { "msc", CMD_MSC }, + { "enddot", CMD_ENDDOT }, + { "endmsc", CMD_ENDMSC }, + { "manonly", CMD_MANONLY }, + { "endmanonly", CMD_ENDMANONLY }, + { "includelineno", CMD_INCWITHLINES }, + { "inheritdoc", CMD_INHERITDOC }, + { "mscfile", CMD_MSCFILE }, + { 0, 0 }, +}; + +//---------------------------------------------------------------------------- + +CommandMap htmlTagMap[] = +{ + { "strong", HTML_BOLD }, + { "center", HTML_CENTER }, + { "table", HTML_TABLE }, + { "caption", HTML_CAPTION }, + { "small", HTML_SMALL }, + { "code", HTML_CODE }, + { "dfn", HTML_CODE }, + { "var", HTML_EMPHASIS }, + { "img", HTML_IMG }, + { "pre", HTML_PRE }, + { "sub", HTML_SUB }, + { "sup", HTML_SUP }, + { "tr", HTML_TR }, + { "td", HTML_TD }, + { "th", HTML_TH }, + { "ol", HTML_OL }, + { "ul", HTML_UL }, + { "li", HTML_LI }, + { "tt", XML_C /*HTML_CODE*/ }, + { "kbd", XML_C /*HTML_CODE*/ }, + { "em", HTML_EMPHASIS }, + { "hr", HTML_HR }, + { "dl", HTML_DL }, + { "dt", HTML_DT }, + { "dd", HTML_DD }, + { "br", HTML_BR }, + { "i", HTML_EMPHASIS }, + { "a", HTML_A }, + { "b", HTML_BOLD }, + { "p", HTML_P }, + { "h1", HTML_H1 }, + { "h2", HTML_H2 }, + { "h3", HTML_H3 }, + { "h4", HTML_H4 }, + { "h5", HTML_H5 }, + { "h6", HTML_H6 }, + { "span", HTML_SPAN }, + { "div", HTML_DIV }, + { "blockquote", HTML_BLOCKQUOTE }, + + { "c", XML_C }, + // { "code", XML_CODE }, <= ambiguous <code> is also a HTML tag + { "description", XML_DESCRIPTION }, + { "example", XML_EXAMPLE }, + { "exception", XML_EXCEPTION }, + { "include", XML_INCLUDE }, + { "item", XML_ITEM }, + { "list", XML_LIST }, // type="table|bullet|number" + { "listheader", XML_LISTHEADER }, + { "para", XML_PARA }, + { "param", XML_PARAM }, + { "paramref", XML_PARAMREF }, + { "typeparam", XML_TYPEPARAM }, + { "typeparamref", XML_TYPEPARAMREF }, + { "permission", XML_PERMISSION }, + { "remarks", XML_REMARKS }, + { "returns", XML_RETURNS }, + { "see", XML_SEE }, + { "seealso", XML_SEEALSO }, + { "summary", XML_SUMMARY }, + { "term", XML_TERM }, + { "value", XML_VALUE }, + { "inheritdoc", XML_INHERITDOC }, + { 0, 0 } +}; + +//---------------------------------------------------------------------------- + +Mapper *Mappers::cmdMapper = new Mapper(cmdMap,TRUE); +Mapper *Mappers::htmlTagMapper = new Mapper(htmlTagMap,FALSE); + +void Mappers::freeMappers() +{ + delete cmdMapper; cmdMapper = 0; + delete htmlTagMapper; htmlTagMapper = 0; +} + + diff --git a/trunk/src/cmdmapper.h b/trunk/src/cmdmapper.h new file mode 100644 index 0000000..04bb3ed --- /dev/null +++ b/trunk/src/cmdmapper.h @@ -0,0 +1,222 @@ +/****************************************************************************** + * + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#ifndef _CMDMAPPER_H +#define _CMDMAPPER_H + +#include <qdict.h> + +struct CommandMap +{ + const char *cmdName; + int cmdId; +}; + +const int SIMPLESECT_BIT = 0x1000; + +enum CommandType +{ + CMD_UNKNOWN = 0, + CMD_ADDINDEX = 1, + CMD_AMP = 2, + CMD_ANCHOR = 3, + CMD_AT = 4, + CMD_ATTENTION = 5 | SIMPLESECT_BIT, + CMD_AUTHOR = 6 | SIMPLESECT_BIT, + CMD_AUTHORS = 7 | SIMPLESECT_BIT, + CMD_BOLD = 8, + CMD_BSLASH = 9, + CMD_CODE = 10, + CMD_COPYDOC = 11, + CMD_DATE = 12 | SIMPLESECT_BIT, + CMD_DOLLAR = 13, + CMD_DONTINCLUDE = 14, + CMD_DOTFILE = 15, + CMD_EMPHASIS = 16, + CMD_ENDCODE = 17, + CMD_ENDHTMLONLY = 18, + CMD_ENDLATEXONLY = 19, + CMD_ENDLINK = 20, + CMD_ENDSECREFLIST= 21, + CMD_ENDVERBATIM = 22, + CMD_ENDXMLONLY = 23, + CMD_EXCEPTION = 24 | SIMPLESECT_BIT, + CMD_FORMULA = 25, + CMD_GREATER = 26, + CMD_HASH = 27, + CMD_HTMLINCLUDE = 28, + CMD_HTMLONLY = 29, + CMD_IMAGE = 30, + CMD_INCLUDE = 31, + CMD_INTERNAL = 32, + CMD_INTERNALREF = 33, + CMD_INVARIANT = 34 | SIMPLESECT_BIT , + CMD_LATEXONLY = 35, + CMD_LESS = 36, + CMD_LI = 37, + CMD_LINE = 38, + CMD_LINEBREAK = 39, + CMD_LINK = 40, + CMD_NOTE = 41 | SIMPLESECT_BIT, + CMD_PAR = 42 | SIMPLESECT_BIT, + CMD_PARAM = 43 | SIMPLESECT_BIT, + CMD_PERCENT = 44, + CMD_POST = 45 | SIMPLESECT_BIT, + CMD_PRE = 46 | SIMPLESECT_BIT, + CMD_REF = 47, + CMD_SECREFITEM = 48, + CMD_REMARK = 49 | SIMPLESECT_BIT , + CMD_RETURN = 50 | SIMPLESECT_BIT , + CMD_RETVAL = 51 | SIMPLESECT_BIT, + CMD_SA = 52 | SIMPLESECT_BIT , + CMD_SECREFLIST = 53, + CMD_SECTION = 54, + CMD_SUBPAGE = 55, + CMD_SUBSECTION = 56, + CMD_SUBSUBSECTION= 57, + CMD_PARAGRAPH = 58, + CMD_SINCE = 59 | SIMPLESECT_BIT, + CMD_SKIP = 60, + CMD_SKIPLINE = 61, + CMD_STARTCODE = 62, + CMD_JAVALINK = 63, + CMD_UNTIL = 64, + CMD_VERBATIM = 65, + CMD_VERBINCLUDE = 66, + CMD_VERSION = 67 | SIMPLESECT_BIT, + CMD_WARNING = 68 | SIMPLESECT_BIT, + CMD_XREFITEM = 69 | SIMPLESECT_BIT, + CMD_XMLONLY = 70, + CMD_DOT = 71, + CMD_ENDDOT = 72, + CMD_MSC = 73, + CMD_ENDMSC = 74, + CMD_MANONLY = 75, + CMD_ENDMANONLY = 76, + CMD_INCWITHLINES = 77, + CMD_INHERITDOC = 78, + CMD_TPARAM = 79 | SIMPLESECT_BIT, + CMD_COPYBRIEF = 80, + CMD_COPYDETAILS = 81, + CMD_QUOTE = 82, + CMD_MSCFILE = 83, + CMD_DCOLON = 84, + CMD_COPYRIGHT = 85 | SIMPLESECT_BIT, + CMD_CITE = 86, + CMD_SNIPPET = 87 +}; + +enum HtmlTagType +{ + HTML_UNKNOWN = 0, + HTML_CENTER = 1, + HTML_TABLE = 2, + HTML_CAPTION = 3, + HTML_SMALL = 4, + HTML_CODE = 5, + HTML_IMG = 6, + HTML_PRE = 7, + HTML_SUB = 8, + HTML_SUP = 9, + HTML_TR = 10, + HTML_TD = 11, + HTML_TH = 12, + HTML_OL = 13, + HTML_UL = 14, + HTML_LI = 15, + HTML_EMPHASIS = 16, + HTML_HR = 17, + HTML_DL = 18, + HTML_DT = 19, + HTML_DD = 20, + HTML_BR = 21, + HTML_A = 22, + HTML_BOLD = 23, + HTML_P = 24, + HTML_H1 = 25, + HTML_H2 = 26, + HTML_H3 = 27, + HTML_H4 = 28, + HTML_H5 = 29, + HTML_H6 = 30, + HTML_SPAN = 31, + HTML_DIV = 32, + HTML_BLOCKQUOTE= 33, + + XML_CmdMask = 0x100, + + XML_C = XML_CmdMask + 0, + XML_CODE = XML_CmdMask + 1, + XML_DESCRIPTION = XML_CmdMask + 2, + XML_EXAMPLE = XML_CmdMask + 3, + XML_EXCEPTION = XML_CmdMask + 4, + XML_INCLUDE = XML_CmdMask + 5, + XML_ITEM = XML_CmdMask + 6, + XML_LIST = XML_CmdMask + 7, + XML_LISTHEADER = XML_CmdMask + 8, + XML_PARA = XML_CmdMask + 9, + XML_PARAM = XML_CmdMask + 10, + XML_PARAMREF = XML_CmdMask + 11, + XML_PERMISSION = XML_CmdMask + 12, + XML_REMARKS = XML_CmdMask + 13, + XML_RETURNS = XML_CmdMask + 14, + XML_SEE = XML_CmdMask + 15, + XML_SEEALSO = XML_CmdMask + 16, + XML_SUMMARY = XML_CmdMask + 17, + XML_TERM = XML_CmdMask + 18, + XML_TYPEPARAM = XML_CmdMask + 19, + XML_TYPEPARAMREF = XML_CmdMask + 20, + XML_VALUE = XML_CmdMask + 21, + XML_INHERITDOC = XML_CmdMask + 22 +}; + +class Mapper +{ + public: + int map(const char *n) + { + QCString name=n; + if (!m_cs) name=name.lower(); + int *result; + return !name.isEmpty() && (result=m_map.find(name)) ? *result: 0; + } + + Mapper(const CommandMap *cm,bool caseSensitive) : m_map(89), m_cs(caseSensitive) + { + m_map.setAutoDelete(TRUE); + const CommandMap *p = cm; + while (p->cmdName) + { + m_map.insert(p->cmdName,new int(p->cmdId)); + p++; + } + } + private: + QDict<int> m_map; + bool m_cs; +}; + +struct Mappers +{ + static void freeMappers(); + static Mapper *cmdMapper; + static Mapper *htmlTagMapper; +}; + + +#endif diff --git a/trunk/src/code.h b/trunk/src/code.h new file mode 100644 index 0000000..f811f55 --- /dev/null +++ b/trunk/src/code.h @@ -0,0 +1,35 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#ifndef CODE_H +#define CODE_H + +#include "qtbc.h" +#include <stdio.h> + +class CodeOutputInterface; +class FileDef; +class MemberDef; + +void parseCCode(CodeOutputInterface &,const char *,const QCString &, + bool ,const char *,FileDef *fd=0, + int startLine=-1,int endLine=-1,bool inlineFragment=FALSE, + MemberDef *memberDef=0,bool showLineNumbers=TRUE); +void resetCCodeParserState(); +void codeFreeScanner(); + +#endif diff --git a/trunk/src/code.l b/trunk/src/code.l new file mode 100644 index 0000000..ae091de --- /dev/null +++ b/trunk/src/code.l @@ -0,0 +1,3567 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +%{ + +/* + * includes + */ +#include <stdio.h> +#include <assert.h> +#include <ctype.h> +#include <qregexp.h> +#include <qdir.h> + +#include "qtbc.h" +#include "entry.h" +#include "doxygen.h" +#include "message.h" +#include "outputlist.h" +#include "util.h" +#include "membername.h" +#include "searchindex.h" +#include "arguments.h" + +#define YY_NEVER_INTERACTIVE 1 + +// Toggle for some debugging info +//#define DBG_CTX(x) fprintf x +#define DBG_CTX(x) do { } while(0) + +#define CLASSBLOCK (int *)4 +#define SCOPEBLOCK (int *)8 +#define INNERBLOCK (int *)12 + +/* ----------------------------------------------------------------- + * statics + */ + +static CodeOutputInterface * g_code; + +static ClassSDict *g_codeClassSDict = 0; +static QCString g_curClassName; +static QStrList g_curClassBases; + +static QCString g_parmType; +static QCString g_parmName; + +static const char * g_inputString; //!< the code fragment as text +static int g_inputPosition; //!< read offset during parsing +static int g_inputLines; //!< number of line in the code fragment +static int g_yyLineNr; //!< current line number +static bool g_needsTermination; + +static bool g_exampleBlock; +static QCString g_exampleName; +static QCString g_exampleFile; + +static bool g_insideTemplate = FALSE; +static QCString g_type; +static QCString g_name; +static QCString g_args; +static QCString g_classScope; +static QCString g_realScope; +static QStack<int> g_scopeStack; //!< 1 if bracket starts a scope, + // 2 for internal blocks +static int g_anchorCount; +static FileDef * g_sourceFileDef; +static bool g_lineNumbers; +static Definition * g_currentDefinition; +static MemberDef * g_currentMemberDef; +static bool g_includeCodeFragment; +static const char * g_currentFontClass; +static bool g_searchingForBody; +static bool g_insideBody; +static int g_bodyCurlyCount; +static QCString g_saveName; +static QCString g_saveType; + +static int g_bracketCount = 0; +static int g_curlyCount = 0; +static int g_sharpCount = 0; +static bool g_inFunctionTryBlock = FALSE; +static bool g_inForEachExpression = FALSE; + +static int g_lastTemplCastContext; +static int g_lastSpecialCContext; +static int g_lastStringContext; +static int g_lastSkipCppContext; +static int g_lastVerbStringContext; +static int g_memCallContext; +static int g_lastCContext; + +static bool g_insideObjC; +static bool g_insideProtocolList; + +static bool g_lexInit = FALSE; + +static QStack<int> g_classScopeLengthStack; + +// context for an Objective-C method call +struct ObjCCallCtx +{ + int id; + QCString methodName; + QCString objectTypeOrName; + ClassDef *objectType; + MemberDef *objectVar; + MemberDef *method; + QCString format; + int lexState; + int braceCount; +}; + +// globals for objective-C method calls +static ObjCCallCtx *g_currentCtx=0; +static int g_currentCtxId=0; +static int g_currentNameId=0; +static int g_currentObjId=0; +static int g_currentWordId=0; +static QStack<ObjCCallCtx> g_contextStack; +static QIntDict<ObjCCallCtx> g_contextDict; +static QIntDict<QCString> g_nameDict; +static QIntDict<QCString> g_objectDict; +static QIntDict<QCString> g_wordDict; +static int g_braceCount=0; + +static void saveObjCContext(); +static void restoreObjCContext(); + +static QCString g_forceTagReference; + + +//------------------------------------------------------------------- + +/*! Represents a stack of variable to class mappings as found in the + * code. Each scope is enclosed in pushScope() and popScope() calls. + * Variables are added by calling addVariables() and one can search + * for variable using findVariable(). + */ +class VariableContext +{ + public: + static const ClassDef *dummyContext; + + class Scope : public SDict<ClassDef> + { + public: + Scope() : SDict<ClassDef>(17) {} + }; + + VariableContext() + { + m_scopes.setAutoDelete(TRUE); + } + virtual ~VariableContext() + { + } + + void pushScope() + { + m_scopes.append(new Scope); + DBG_CTX((stderr,"** Push var context %d\n",m_scopes.count())); + } + + void popScope() + { + if (m_scopes.count()>0) + { + DBG_CTX((stderr,"** Pop var context %d\n",m_scopes.count())); + m_scopes.remove(m_scopes.count()-1); + } + else + { + DBG_CTX((stderr,"** ILLEGAL: Pop var context\n")); + } + } + + void clear() + { + m_scopes.clear(); + m_globalScope.clear(); + } + + void clearExceptGlobal() + { + DBG_CTX((stderr,"** Clear var context\n")); + m_scopes.clear(); + } + + void addVariable(const QCString &type,const QCString &name); + ClassDef *findVariable(const QCString &name); + + int count() const { return m_scopes.count(); } + + private: + Scope m_globalScope; + QList<Scope> m_scopes; +}; + +void VariableContext::addVariable(const QCString &type,const QCString &name) +{ + //printf("VariableContext::addVariable(%s,%s)\n",type.data(),name.data()); + QCString ltype = type.simplifyWhiteSpace(); + QCString lname = name.simplifyWhiteSpace(); + if (ltype.left(7)=="struct ") + { + ltype = ltype.right(ltype.length()-7); + } + else if (ltype.left(6)=="union ") + { + ltype = ltype.right(ltype.length()-6); + } + if (ltype.isEmpty() || lname.isEmpty()) return; + DBG_CTX((stderr,"** addVariable trying: type='%s' name='%s' g_currentDefinition=%s\n", + ltype.data(),lname.data(),g_currentDefinition?g_currentDefinition->name().data():"<none>")); + Scope *scope = m_scopes.count()==0 ? &m_globalScope : m_scopes.getLast(); + ClassDef *varType; + int i=0; + if ( + (varType=g_codeClassSDict->find(ltype)) || // look for class definitions inside the code block + (varType=getResolvedClass(g_currentDefinition,g_sourceFileDef,ltype)) // look for global class definitions + ) + { + DBG_CTX((stderr,"** addVariable type='%s' name='%s'\n",ltype.data(),lname.data())); + scope->append(lname,varType); // add it to a list + } + else if ((i=ltype.find('<'))!=-1) + { + // probably a template class + QCString typeName(ltype.left(i)); + ClassDef* newDef = 0; + QCString templateArgs(ltype.right(ltype.length() - i)); + if ( + ( // look for class definitions inside the code block + (varType=g_codeClassSDict->find(typeName)) || + // otherwise look for global class definitions + (varType=getResolvedClass(g_currentDefinition,g_sourceFileDef,typeName,0,0,TRUE,TRUE)) + ) && // and it must be a template + varType->templateArguments()) + { + newDef = varType->getVariableInstance( templateArgs ); + } + if (newDef) + { + DBG_CTX((stderr,"** addVariable type='%s' templ='%s' name='%s'\n",typeName.data(),templateArgs.data(),lname.data())); + scope->append(lname, newDef); + } + else + { + // Doesn't seem to be a template. Try just the base name. + addVariable(typeName,name); + } + } + else + { + if (m_scopes.count()>0) // for local variables add a dummy entry so the name + // is hidden to avoid false links to global variables with the same name + // TODO: make this work for namespaces as well! + { + DBG_CTX((stderr,"** addVariable: dummy context for '%s'\n",lname.data())); + scope->append(lname,dummyContext); + } + else + { + DBG_CTX((stderr,"** addVariable: not adding variable!\n")); + } + } +} + +ClassDef *VariableContext::findVariable(const QCString &name) +{ + if (name.isEmpty()) return 0; + ClassDef *result = 0; + //QListIterator<Scope> sli(m_scopes); + Scope *scope; + QCString key = name; + // search from inner to outer scope + scope = m_scopes.last(); + //for (sli.toLast();(scope=sli.current());--sli) + while (scope) + { + result = scope->find(key); + if (result) + { + DBG_CTX((stderr,"** findVariable(%s)=%p\n",name.data(),result)); + return result; + } + scope = m_scopes.prev(); + } + // nothing found -> also try the global scope + result=m_globalScope.find(name); + DBG_CTX((stderr,"** findVariable(%s)=%p\n",name.data(),result)); + return result; +} + +static VariableContext g_theVarContext; +const ClassDef *VariableContext::dummyContext = (ClassDef*)0x8; + +//------------------------------------------------------------------- + +class CallContext +{ + public: + struct Ctx + { + Ctx() : name(g_name), type(g_type), cd(0) {} + QCString name; + QCString type; + ClassDef *cd; + }; + + CallContext() + { + m_classList.append(new Ctx); + m_classList.setAutoDelete(TRUE); + } + virtual ~CallContext() {} + void setClass(ClassDef *cd) + { + Ctx *ctx = m_classList.getLast(); + if (ctx) + { + DBG_CTX((stderr,"** Set call context %s (%p)\n",cd==0 ? "<null>" : cd->name().data(),cd)); + ctx->cd=cd; + } + } + void pushScope() + { + m_classList.append(new Ctx); + DBG_CTX((stderr,"** Push call context %d\n",m_classList.count())); + } + void popScope() + { + if (m_classList.count()>1) + { + DBG_CTX((stderr,"** Pop call context %d\n",m_classList.count())); + Ctx *ctx = m_classList.getLast(); + if (ctx) + { + g_name = ctx->name; + g_type = ctx->type; + } + m_classList.removeLast(); + } + else + { + DBG_CTX((stderr,"** ILLEGAL: Pop call context\n")); + } + } + void clear() + { + DBG_CTX((stderr,"** Clear call context\n")); + m_classList.clear(); + m_classList.append(new Ctx); + } + ClassDef *getClass() const + { + Ctx *ctx = m_classList.getLast(); + if (ctx) return ctx->cd; else return 0; + } + + private: + QList<Ctx> m_classList; +}; + +static CallContext g_theCallContext; + +//------------------------------------------------------------------- + +/*! add class/namespace name s to the scope */ +static void pushScope(const char *s) +{ + g_classScopeLengthStack.push(new int(g_classScope.length())); + if (g_classScope.isEmpty()) + { + g_classScope = s; + } + else + { + g_classScope += "::"; + g_classScope += s; + } + //printf("pushScope(%s) result: `%s'\n",s,g_classScope.data()); +} + +/*! remove the top class/namespace name from the scope */ +static void popScope() +{ + if (!g_classScopeLengthStack.isEmpty()) + { + int *pLength = g_classScopeLengthStack.pop(); + g_classScope.truncate(*pLength); + delete pLength; + } + else + { + //err("Error: Too many end of scopes found!\n"); + } + //printf("popScope() result: `%s'\n",g_classScope.data()); +} + +static void setCurrentDoc(const QCString &name,const QCString &base,const QCString &anchor="") +{ + if (Doxygen::searchIndex) + { + Doxygen::searchIndex->setCurrentDoc(name,base,anchor); + } +} + +static void addToSearchIndex(const char *text) +{ + if (Doxygen::searchIndex) + { + Doxygen::searchIndex->addWord(text,FALSE); + } +} + +static void setClassScope(const QCString &name) +{ + //printf("setClassScope(%s)\n",name.data()); + QCString n=name; + n=n.simplifyWhiteSpace(); + int ts=n.find('<'); // start of template + int te=n.findRev('>'); // end of template + //printf("ts=%d te=%d\n",ts,te); + if (ts!=-1 && te!=-1 && te>ts) + { + // remove template from scope + n=n.left(ts)+n.right(n.length()-te-1); + } + while (!g_classScopeLengthStack.isEmpty()) + { + popScope(); + } + g_classScope.resize(0); + int i; + while ((i=n.find("::"))!=-1) + { + pushScope(n.left(i)); + n = n.mid(i+2); + } + pushScope(n); + //printf("--->New class scope `%s'\n",g_classScope.data()); +} + +/*! start a new line of code, inserting a line number if g_sourceFileDef + * is TRUE. If a definition starts at the current line, then the line + * number is linked to the documentation of that definition. + */ +static void startCodeLine() +{ + //if (g_currentFontClass) { g_code->endFontClass(); } + if (g_sourceFileDef && g_lineNumbers) + { + //QCString lineNumber,lineAnchor; + //lineNumber.sprintf("%05d",g_yyLineNr); + //lineAnchor.sprintf("l%05d",g_yyLineNr); + + Definition *d = g_sourceFileDef->getSourceDefinition(g_yyLineNr); + //printf("%s:startCodeLine(%d)=%p\n",g_sourceFileDef->name().data(),g_yyLineNr,d); + if (!g_includeCodeFragment && d) + { + g_currentDefinition = d; + g_currentMemberDef = g_sourceFileDef->getSourceMember(g_yyLineNr); + //printf("->startCodeLine(%s)=%p\n",d->name().data(),g_currentMemberDef); + g_insideBody = FALSE; + g_searchingForBody = TRUE; + g_realScope = d->name(); + //g_classScope = ""; + g_type.resize(0); + g_name.resize(0); + g_args.resize(0); + g_parmType.resize(0); + g_parmName.resize(0); + //printf("Real scope: `%s'\n",g_realScope.data()); + g_bodyCurlyCount = 0; + QCString lineAnchor; + lineAnchor.sprintf("l%05d",g_yyLineNr); + if (g_currentMemberDef) + { + g_code->writeLineNumber(g_currentMemberDef->getReference(), + g_currentMemberDef->getOutputFileBase(), + g_currentMemberDef->anchor(),g_yyLineNr); + setCurrentDoc( + g_currentMemberDef->qualifiedName(), + g_sourceFileDef->getSourceFileBase(), + lineAnchor); + } + else if (d->isLinkableInProject()) + { + g_code->writeLineNumber(d->getReference(), + d->getOutputFileBase(), + 0,g_yyLineNr); + setCurrentDoc( + d->qualifiedName(), + g_sourceFileDef->getSourceFileBase(), + lineAnchor); + } + } + else + { + g_code->writeLineNumber(0,0,0,g_yyLineNr); + } + } + g_code->startCodeLine(); + if (g_currentFontClass) + { + g_code->startFontClass(g_currentFontClass); + } +} + + +static void endFontClass(); +static void startFontClass(const char *s); + +static void endCodeLine() +{ + endFontClass(); + g_code->endCodeLine(); +} + +static void nextCodeLine() +{ + const char * fc = g_currentFontClass; + endCodeLine(); + if (g_yyLineNr<g_inputLines) + { + g_currentFontClass = fc; + startCodeLine(); + } +} + +/*! write a code fragment `text' that may span multiple lines, inserting + * line numbers for each line. + */ +static void codifyLines(const char *text) +{ + //printf("codifyLines(%d,\"%s\")\n",g_yyLineNr,text); + const char *p=text,*sp=p; + char c; + bool done=FALSE; + while (!done) + { + sp=p; + while ((c=*p++) && c!='\n') { } + if (c=='\n') + { + g_yyLineNr++; + //*(p-1)='\0'; + int l = p-sp-1; + char *tmp = (char*)malloc(l+1); + memcpy(tmp,sp,l); + tmp[l]='\0'; + g_code->codify(tmp); + free(tmp); + nextCodeLine(); + } + else + { + g_code->codify(sp); + done=TRUE; + } + } +} + +/*! writes a link to a fragment \a text that may span multiple lines, inserting + * line numbers for each line. If \a text contains newlines, the link will be + * split into multiple links with the same destination, one for each line. + */ +static void writeMultiLineCodeLink(CodeOutputInterface &ol, + const char *ref,const char *file, + const char *anchor,const char *text, + const char *tooltip) +{ + bool done=FALSE; + char *p=(char *)text; + while (!done) + { + char *sp=p; + char c; + while ((c=*p++) && c!='\n') { } + if (c=='\n') + { + g_yyLineNr++; + *(p-1)='\0'; + //printf("writeCodeLink(%s,%s,%s,%s)\n",ref,file,anchor,sp); + ol.writeCodeLink(ref,file,anchor,sp,tooltip); + nextCodeLine(); + } + else + { + //printf("writeCodeLink(%s,%s,%s,%s)\n",ref,file,anchor,sp); + ol.writeCodeLink(ref,file,anchor,sp,tooltip); + done=TRUE; + } + } +} + +static void addType() +{ + if (g_name=="const") { g_name.resize(0); return; } + if (!g_type.isEmpty()) g_type += ' ' ; + g_type += g_name ; + g_name.resize(0) ; + if (!g_type.isEmpty()) g_type += ' ' ; + g_type += g_args ; + g_args.resize(0) ; +} + +static void addParmType() +{ + if (g_parmName=="const") { g_parmName.resize(0); return; } + if (!g_parmType.isEmpty()) g_parmType += ' ' ; + g_parmType += g_parmName ; + g_parmName.resize(0) ; +} + +static void addUsingDirective(const char *name) +{ + if (g_sourceFileDef && name) + { + NamespaceDef *nd = Doxygen::namespaceSDict->find(name); + if (nd) + { + g_sourceFileDef->addUsingDirective(nd); + } + } +} + +static void setParameterList(MemberDef *md) +{ + g_classScope = md->getClassDef() ? md->getClassDef()->name().data() : ""; + LockingPtr<ArgumentList> al = md->argumentList(); + if (al==0) return; + Argument *a = al->first(); + while (a) + { + g_parmName = a->name.copy(); + g_parmType = a->type.copy(); + int i = g_parmType.find('*'); + if (i!=-1) g_parmType = g_parmType.left(i); + i = g_parmType.find('&'); + if (i!=-1) g_parmType = g_parmType.left(i); + g_parmType.stripPrefix("const "); + g_parmType=g_parmType.stripWhiteSpace(); + g_theVarContext.addVariable(g_parmType,g_parmName); + a = al->next(); + } +} + +static ClassDef *stripClassName(const char *s,Definition *d=g_currentDefinition) +{ + int pos=0; + QCString type = s; + QCString className; + QCString templSpec; + while (extractClassNameFromType(type,pos,className,templSpec)!=-1) + { + QCString clName=className+templSpec; + ClassDef *cd=0; + if (!g_classScope.isEmpty()) + { + cd=getResolvedClass(d,g_sourceFileDef,g_classScope+"::"+clName); + } + if (cd==0) + { + cd=getResolvedClass(d,g_sourceFileDef,clName); + } + //printf("stripClass trying `%s' = %p\n",clName.data(),cd); + if (cd) + { + return cd; + } + } + + return 0; +} + +static MemberDef *setCallContextForVar(const QCString &name) +{ + if (name.isEmpty()) return 0; + //fprintf(stderr,"setCallContextForVar(%s) g_classScope=%s\n",name.data(),g_classScope.data()); + + int scopeEnd = name.findRev("::"); + if (scopeEnd!=-1) // name with explicit scope + { + QCString scope = name.left(scopeEnd); + QCString locName = name.right(name.length()-scopeEnd-2); + //printf("explicit scope: name=%s scope=%s\n",locName.data(),scope.data()); + ClassDef *mcd = getClass(scope); + if (mcd && !locName.isEmpty()) + { + MemberDef *md=mcd->getMemberByName(locName); + if (md) + { + //printf("name=%s scope=%s\n",locName.data(),scope.data()); + g_theCallContext.setClass(stripClassName(md->typeString(),md->getOuterScope())); + return md; + } + } + else // check namespace as well + { + NamespaceDef *mnd = getResolvedNamespace(scope); + if (mnd && !locName.isEmpty()) + { + MemberDef *md=mnd->getMemberByName(locName); + if (md) + { + //printf("name=%s scope=%s\n",locName.data(),scope.data()); + g_theCallContext.setClass(stripClassName(md->typeString(),md->getOuterScope())); + return md; + } + } + } + } + + MemberName *mn; + ClassDef *mcd = g_theVarContext.findVariable(name); + if (mcd) // local variable + { + //fprintf(stderr,"local variable?\n"); + if (mcd!=VariableContext::dummyContext) + { + //fprintf(stderr,"local var `%s' mcd=%s\n",name.data(),mcd->name().data()); + g_theCallContext.setClass(mcd); + } + } + else + { + //fprintf(stderr,"class member? scope=%s\n",g_classScope.data()); + // look for a class member + mcd = getClass(g_classScope); + if (mcd) + { + //fprintf(stderr,"Inside class %s\n",mcd->name().data()); + MemberDef *md=mcd->getMemberByName(name); + if (md) + { + //fprintf(stderr,"Found member %s\n",md->name().data()); + if (g_scopeStack.top()!=CLASSBLOCK) + { + //fprintf(stderr,"class member `%s' mcd=%s\n",name.data(),mcd->name().data()); + g_theCallContext.setClass(stripClassName(md->typeString(),md->getOuterScope())); + } + return md; + } + } + } + + // look for a global member + if ((mn=Doxygen::functionNameSDict->find(name))) + { + //printf("global var `%s'\n",name.data()); + if (mn->count()==1) // global defined only once + { + MemberDef *md=mn->getFirst(); + if (!md->isStatic() || md->getBodyDef()==g_sourceFileDef) + { + g_theCallContext.setClass(stripClassName(md->typeString(),md->getOuterScope())); + return md; + } + return 0; + } + else if (mn->count()>1) // global defined more than once + { + MemberDef *md=mn->first(); + while (md) + { + //printf("mn=%p md=%p md->getBodyDef()=%p g_sourceFileDef=%p\n", + // mn,md, + // md->getBodyDef(),g_sourceFileDef); + + // in case there are multiple members we could link to, we + // only link to members if defined in the same file or + // defined as external. + if ((!md->isStatic() || md->getBodyDef()==g_sourceFileDef) && + (g_forceTagReference.isEmpty() || g_forceTagReference==md->getReference()) + ) + { + g_theCallContext.setClass(stripClassName(md->typeString(),md->getOuterScope())); + //printf("returning member %s in source file %s\n",md->name().data(),g_sourceFileDef->name().data()); + return md; + } + md=mn->next(); + } + return 0; + } + } + return 0; +} + +static void updateCallContextForSmartPointer() +{ + ClassDef *cd = g_theCallContext.getClass(); + //printf("updateCallContextForSmartPointer() cd=%s\n",cd ? cd->name().data() : "<none>"); + MemberDef *md; + if (cd && (md=cd->isSmartPointer())) + { + ClassDef *ncd = stripClassName(md->typeString(),md->getOuterScope()); + if (ncd) + { + g_theCallContext.setClass(ncd); + //printf("Found smart pointer call %s->%s!\n",cd->name().data(),ncd->name().data()); + } + } +} + +static void addDocCrossReference(MemberDef *src,MemberDef *dst) +{ + static bool referencedByRelation = Config_getBool("REFERENCED_BY_RELATION"); + static bool referencesRelation = Config_getBool("REFERENCES_RELATION"); + static bool callerGraph = Config_getBool("CALLER_GRAPH"); + static bool callGraph = Config_getBool("CALL_GRAPH"); + + //printf("--> addDocCrossReference src=%s,dst=%s\n",src->name().data(),dst->name().data()); + if (dst->isTypedef() || dst->isEnumerate()) return; // don't add types + if ((referencedByRelation || callerGraph || dst->hasCallerGraph()) && + (src->isFunction() || src->isSlot()) + ) + { + dst->addSourceReferencedBy(src); + MemberDef *mdDef = dst->memberDefinition(); + if (mdDef) + { + mdDef->addSourceReferencedBy(src); + } + MemberDef *mdDecl = dst->memberDeclaration(); + if (mdDecl) + { + mdDecl->addSourceReferencedBy(src); + } + } + if ((referencesRelation || callGraph || src->hasCallGraph()) && + (src->isFunction() || src->isSlot()) + ) + { + src->addSourceReferences(dst); + MemberDef *mdDef = src->memberDefinition(); + if (mdDef) + { + mdDef->addSourceReferences(dst); + } + MemberDef *mdDecl = src->memberDeclaration(); + if (mdDecl) + { + mdDecl->addSourceReferences(dst); + } + } + +} + +static bool getLinkInScope(const QCString &c, // scope + const QCString &m, // member + const char *memberText, // exact text + CodeOutputInterface &ol, + const char *text, + bool varOnly=FALSE + ) +{ + MemberDef *md; + ClassDef *cd; + FileDef *fd; + NamespaceDef *nd; + GroupDef *gd; + //fprintf(stderr,"getLinkInScope: trying `%s'::`%s' varOnly=%d\n",c.data(),m.data(),varOnly); + if (getDefs(c,m,"()",md,cd,fd,nd,gd,FALSE,g_sourceFileDef,FALSE,g_forceTagReference) && + md->isLinkable() && (!varOnly || md->isVariable())) + { + //printf("found it!\n"); + if (g_exampleBlock) + { + QCString anchor; + anchor.sprintf("a%d",g_anchorCount); + //printf("addExampleFile(%s,%s,%s)\n",anchor.data(),g_exampleName.data(), + // g_exampleFile.data()); + if (md->addExample(anchor,g_exampleName,g_exampleFile)) + { + ol.writeCodeAnchor(anchor); + g_anchorCount++; + } + } + + Definition *d = md->getOuterScope()==Doxygen::globalScope ? + md->getBodyDef() : md->getOuterScope(); + if (md->getGroupDef()) d = md->getGroupDef(); + if (d && d->isLinkable()) + { + g_theCallContext.setClass(stripClassName(md->typeString(),md->getOuterScope())); + //printf("g_currentDefinition=%p g_currentMemberDef=%p g_insideBody=%d\n", + // g_currentDefinition,g_currentMemberDef,g_insideBody); + + if (g_currentDefinition && g_currentMemberDef && + md!=g_currentMemberDef && g_insideBody) + { + addDocCrossReference(g_currentMemberDef,md); + } + //printf("d->getReference()=`%s' d->getOutputBase()=`%s' name=`%s' member name=`%s'\n",d->getReference().data(),d->getOutputFileBase().data(),d->name().data(),md->name().data()); + + ol.linkableSymbol(g_yyLineNr,md->name(),md, + g_currentMemberDef ? g_currentMemberDef : g_currentDefinition); + writeMultiLineCodeLink(ol,md->getReference(), + md->getOutputFileBase(), + md->anchor(), + text ? text : memberText, + md->briefDescriptionAsTooltip()); + addToSearchIndex(text ? text : memberText); + return TRUE; + } + } + return FALSE; +} + +static bool getLink(const char *className, + const char *memberName, + CodeOutputInterface &ol, + const char *text=0, + bool varOnly=FALSE) +{ + //printf("getLink(%s,%s) g_curClassName=%s\n",className,memberName,g_curClassName.data()); + QCString m=removeRedundantWhiteSpace(memberName); + QCString c=className; + if (!getLinkInScope(c,m,memberName,ol,text,varOnly)) + { + if (!g_curClassName.isEmpty()) + { + if (!c.isEmpty()) c.prepend("::"); + c.prepend(g_curClassName); + return getLinkInScope(c,m,memberName,ol,text,varOnly); + } + return FALSE; + } + return TRUE; +} + +static void generateClassOrGlobalLink(CodeOutputInterface &ol,const char *clName, + bool typeOnly=FALSE,bool varOnly=FALSE) +{ + int i=0; + if (*clName=='~') // correct for matching negated values i.s.o. destructors. + { + g_code->codify("~"); + clName++; + } + QCString className=clName; + if (className.isEmpty()) return; + if (g_insideProtocolList) // for Obj-C + { + className+="-p"; + } + className = substitute(className,"\\","::"); // for PHP namespaces + ClassDef *cd=0,*lcd=0; + MemberDef *md=0; + bool isLocal=FALSE; + + //printf("generateClassOrGlobalLink(className=%s)\n",className.data()); + if ((lcd=g_theVarContext.findVariable(className))==0) // not a local variable + { + Definition *d = g_currentDefinition; + //printf("d=%s g_sourceFileDef=%s\n",d?d->name().data():"<none>",g_sourceFileDef?g_sourceFileDef->name().data():"<none>"); + cd = getResolvedClass(d,g_sourceFileDef,className,&md); + //fprintf(stderr,"non-local variable name=%s context=%d cd=%s md=%s!\n", + // className.data(),g_theVarContext.count(),cd?cd->name().data():"<none>", + // md?md->name().data():"<none>"); + if (cd==0 && md==0 && (i=className.find('<'))!=-1) + { + QCString bareName = className.left(i); //stripTemplateSpecifiersFromScope(className); + //fprintf(stderr,"bareName=%s\n",bareName.data()); + if (bareName!=className) + { + cd=getResolvedClass(d,g_sourceFileDef,bareName,&md); // try unspecialized version + } + } + //printf("md=%s\n",md?md->name().data():"<none>"); + //fprintf(stderr,"is found as a type %s\n",cd?cd->name().data():"<null>"); + if (cd==0 && md==0) // also see if it is variable or enum or enum value + { + if (getLink(g_classScope,clName,ol,clName,varOnly)) + { + return; + } + } + } + else + { + //printf("local variable!\n"); + if (lcd!=VariableContext::dummyContext) + { + //printf("non-dummy context lcd=%s!\n",lcd->name().data()); + g_theCallContext.setClass(lcd); + + // to following is needed for links to a global variable, but is + // no good for a link to a local variable that is also a global symbol. + + //if (getLink(g_classScope,clName,ol,clName)) + //{ + //return; + //} + } + isLocal=TRUE; + //fprintf(stderr,"is a local variable cd=%p!\n",cd); + } + if (cd && cd->isLinkable()) // is it a linkable class + { + //fprintf(stderr,"is linkable class %s\n",clName); + if (g_exampleBlock) + { + QCString anchor; + anchor.sprintf("_a%d",g_anchorCount); + //printf("addExampleClass(%s,%s,%s)\n",anchor.data(),g_exampleName.data(), + // g_exampleFile.data()); + if (cd->addExample(anchor,g_exampleName,g_exampleFile)) + { + ol.writeCodeAnchor(anchor); + g_anchorCount++; + } + } + ol.linkableSymbol(g_yyLineNr,cd->name(),cd, + g_currentMemberDef ? g_currentMemberDef : g_currentDefinition); + writeMultiLineCodeLink(ol,cd->getReference(),cd->getOutputFileBase(),cd->anchor(),clName,cd->briefDescriptionAsTooltip()); + addToSearchIndex(className); + g_theCallContext.setClass(cd); + if (md) + { + Definition *d = md->getOuterScope()==Doxygen::globalScope ? + md->getBodyDef() : md->getOuterScope(); + if (md->getGroupDef()) d = md->getGroupDef(); + if (d && d->isLinkable() && md->isLinkable() && g_currentMemberDef) + { + addDocCrossReference(g_currentMemberDef,md); + } + } + } + else // not a class, maybe a global member + { + //fprintf(stderr,"class %s not linkable! cd=%p md=%p typeOnly=%d\n",clName,cd,md,typeOnly); + if (!isLocal && (md!=0 || (cd==0 && !typeOnly))) // not a class, see if it is a global enum/variable/typedef. + { + if (md==0) // not found as a typedef + { + md = setCallContextForVar(clName); + //printf("setCallContextForVar(%s) md=%p g_currentDefinition=%p\n",clName,md,g_currentDefinition); + if (md && g_currentDefinition) + { + //fprintf(stderr,"%s accessible from %s? %d md->getOuterScope=%s\n", + // md->name().data(),g_currentDefinition->name().data(), + // isAccessibleFrom(g_currentDefinition,g_sourceFileDef,md), + // md->getOuterScope()->name().data()); + } + + if (md && g_currentDefinition && + isAccessibleFrom(g_currentDefinition,g_sourceFileDef,md)==-1) + { + md=0; // variable not accessible + } + } + if (md && (!varOnly || md->isVariable())) + { + //fprintf(stderr,"is a global md=%p g_currentDefinition=%s linkable=%d\n",md,g_currentDefinition?g_currentDefinition->name().data():"<none>",md->isLinkable()); + if (md->isLinkable()) + { + QCString text; + if (!g_forceTagReference.isEmpty()) // explicit reference to symbol in tag file + { + text=g_forceTagReference; + if (text.right(4)==".tag") // strip .tag if present + { + text=text.left(text.length()-4); + } + text+=getLanguageSpecificSeparator(md->getLanguage()); + text+=clName; + md->setName(text); + md->setLocalName(text); + } + else // normal reference + { + text=clName; + } + ol.linkableSymbol(g_yyLineNr,md->name(),md, + g_currentMemberDef ? g_currentMemberDef : g_currentDefinition); + writeMultiLineCodeLink(ol,md->getReference(),md->getOutputFileBase(),md->anchor(),text,md->briefDescriptionAsTooltip()); + addToSearchIndex(clName); + if (g_currentMemberDef) + { + addDocCrossReference(g_currentMemberDef,md); + } + return; + } + } + } + + // nothing found, just write out the word + //fprintf(stderr,"not found!\n"); + ol.linkableSymbol(g_yyLineNr,clName,0, + g_currentMemberDef?g_currentMemberDef:g_currentDefinition); + codifyLines(clName); + addToSearchIndex(clName); + } +} + +static bool generateClassMemberLink(CodeOutputInterface &ol,MemberDef *xmd,const char *memName) +{ + // extract class definition of the return type in order to resolve + // a->b()->c() like call chains + + //printf("type=`%s' args=`%s' class=%s\n", + // xmd->typeString(),xmd->argsString(), + // xmd->getClassDef()->name().data()); + + if (g_exampleBlock) + { + QCString anchor; + anchor.sprintf("a%d",g_anchorCount); + //printf("addExampleFile(%s,%s,%s)\n",anchor.data(),g_exampleName.data(), + // g_exampleFile.data()); + if (xmd->addExample(anchor,g_exampleName,g_exampleFile)) + { + ol.writeCodeAnchor(anchor); + g_anchorCount++; + } + } + + ClassDef *typeClass = stripClassName(removeAnonymousScopes(xmd->typeString()),xmd->getOuterScope()); + //fprintf(stderr,"%s -> typeName=%p\n",xmd->typeString(),typeClass); + g_theCallContext.setClass(typeClass); + + Definition *xd = xmd->getOuterScope()==Doxygen::globalScope ? + xmd->getBodyDef() : xmd->getOuterScope(); + if (xmd->getGroupDef()) xd = xmd->getGroupDef(); + if (xd && xd->isLinkable()) + { + + //printf("g_currentDefiniton=%p g_currentMemberDef=%p xmd=%p g_insideBody=%d\n",g_currentDefinition,g_currentMemberDef,xmd,g_insideBody); + + if (xmd->templateMaster()) xmd = xmd->templateMaster(); + + if (xmd->isLinkable()) + { + // add usage reference + if (g_currentDefinition && g_currentMemberDef && + /*xmd!=g_currentMemberDef &&*/ g_insideBody) + { + addDocCrossReference(g_currentMemberDef,xmd); + } + + // write the actual link + ol.linkableSymbol(g_yyLineNr,xmd->name(),xmd, + g_currentMemberDef ? g_currentMemberDef : g_currentDefinition); + writeMultiLineCodeLink(ol,xmd->getReference(), + xmd->getOutputFileBase(),xmd->anchor(),memName,xmd->briefDescriptionAsTooltip()); + addToSearchIndex(memName); + return TRUE; + } + } + + return FALSE; +} + +static bool generateClassMemberLink(CodeOutputInterface &ol,ClassDef *mcd,const char *memName) +{ + if (mcd) + { + MemberDef *xmd = mcd->getMemberByName(memName); + //printf("generateClassMemberLink(class=%s,member=%s)=%p\n",mcd->name().data(),memName,xmd); + if (xmd) + { + return generateClassMemberLink(ol,xmd,memName); + } + } + + return FALSE; +} + +static void generateMemberLink(CodeOutputInterface &ol,const QCString &varName, + char *memName) +{ + //printf("generateMemberLink(object=%s,mem=%s) classScope=%s\n", + // varName.data(),memName,g_classScope.data()); + + if (varName.isEmpty()) return; + + // look for the variable in the current context + ClassDef *vcd = g_theVarContext.findVariable(varName); + if (vcd) + { + if (vcd!=VariableContext::dummyContext) + { + //printf("Class found!\n"); + if (getLink(vcd->name(),memName,ol)) + { + //printf("Found result!\n"); + return; + } + if (vcd->baseClasses()) + { + BaseClassListIterator bcli(*vcd->baseClasses()); + for ( ; bcli.current() ; ++bcli) + { + if (getLink(bcli.current()->classDef->name(),memName,ol)) + { + //printf("Found result!\n"); + return; + } + } + } + } + } + else // variable not in current context, maybe it is in a parent context + { + vcd = getResolvedClass(g_currentDefinition,g_sourceFileDef,g_classScope); + if (vcd && vcd->isLinkable()) + { + //printf("Found class %s for variable `%s'\n",g_classScope.data(),varName.data()); + MemberName *vmn=Doxygen::memberNameSDict->find(varName); + if (vmn==0) + { + int vi; + QCString vn=varName; + QCString scope; + if ((vi=vn.findRev("::"))!=-1 || (vi=vn.findRev('.'))!=-1) // explicit scope A::b(), probably static member + { + ClassDef *jcd = getClass(vn.left(vi)); + vn=vn.right(vn.length()-vi-2); + vmn=Doxygen::memberNameSDict->find(vn); + //printf("Trying name `%s' scope=%s\n",vn.data(),scope.data()); + if (vmn) + { + MemberNameIterator vmni(*vmn); + MemberDef *vmd; + for (;(vmd=vmni.current());++vmni) + { + if (/*(vmd->isVariable() || vmd->isFunction()) && */ + vmd->getClassDef()==jcd) + { + //printf("Found variable type=%s\n",vmd->typeString()); + ClassDef *mcd=stripClassName(vmd->typeString(),vmd->getOuterScope()); + if (mcd && mcd->isLinkable()) + { + if (generateClassMemberLink(ol,mcd,memName)) return; + } + } + } + } + } + } + if (vmn) + { + //printf("There is a variable with name `%s'\n",varName); + MemberNameIterator vmni(*vmn); + MemberDef *vmd; + for (;(vmd=vmni.current());++vmni) + { + if (/*(vmd->isVariable() || vmd->isFunction()) && */ + vmd->getClassDef()==vcd) + { + //printf("Found variable type=%s\n",vmd->typeString()); + ClassDef *mcd=stripClassName(vmd->typeString(),vmd->getOuterScope()); + if (mcd && mcd->isLinkable()) + { + if (generateClassMemberLink(ol,mcd,memName)) return; + } + } + } + } + } + } + // nothing found -> write result as is + ol.linkableSymbol(g_yyLineNr,memName,0, + g_currentMemberDef?g_currentMemberDef:g_currentDefinition); + codifyLines(memName); + addToSearchIndex(memName); + return; +} + +static void generatePHPVariableLink(CodeOutputInterface &ol,const char *varName) +{ + QCString name = varName+7; // strip $this-> + name.prepend("$"); + //printf("generatePHPVariableLink(%s) name=%s scope=%s\n",varName,name.data(),g_classScope.data()); + if (!getLink(g_classScope,name,ol,varName)) + { + codifyLines(varName); + } +} + +static void generateFunctionLink(CodeOutputInterface &ol,const char *funcName) +{ + //CodeClassDef *ccd=0; + ClassDef *ccd=0; + QCString locScope=g_classScope; + QCString locFunc=removeRedundantWhiteSpace(funcName); + //fprintf(stdout,"*** locScope=%s locFunc=%s\n",locScope.data(),locFunc.data()); + int len=2; + int i=locFunc.findRev("::"); + if (g_currentMemberDef && g_currentMemberDef->getClassDef() && + funcName==g_currentMemberDef->localName() && + g_currentMemberDef->getDefLine()==g_yyLineNr && + generateClassMemberLink(ol,g_currentMemberDef,funcName) + ) + { + // special case where funcName is the name of a method that is also + // defined on this line. In this case we can directly link to + // g_currentMemberDef, which is not only faster, but + // in case of overloaded methods, this will make sure that we link to + // the correct method, and thereby get the correct reimplemented relations. + // See also bug 549022. + goto exit; + } + if (i==-1) i=locFunc.findRev("."),len=1; + if (i==-1) i=locFunc.findRev("\\"),len=1; // for PHP + if (i>0) + { + if (locScope.isEmpty()) + { + locScope=locFunc.left(i); + } + else + { + locScope+="::"+locFunc.left(i); + } + locFunc=locFunc.right(locFunc.length()-i-len).stripWhiteSpace(); + int ts=locScope.find('<'); // start of template + int te=locScope.findRev('>'); // end of template + //printf("ts=%d te=%d\n",ts,te); + if (ts!=-1 && te!=-1 && te>ts) + { + // remove template from scope + locScope=locScope.left(ts)+locScope.right(locScope.length()-te-1); + } + } + //printf("generateFunctionLink(%s) classScope=`%s'\n",locFunc.data(),locScope.data()); + if (!locScope.isEmpty() && (ccd=g_codeClassSDict->find(locScope))) + { + //printf("using classScope %s\n",g_classScope.data()); + if (ccd->baseClasses()) + { + BaseClassListIterator bcli(*ccd->baseClasses()); + for ( ; bcli.current() ; ++bcli) + { + if (getLink(bcli.current()->classDef->name(),locFunc,ol,funcName)) + { + goto exit; + } + } + } + } + if (!getLink(locScope,locFunc,ol,funcName)) + { + generateClassOrGlobalLink(ol,funcName); + } +exit: + g_forceTagReference.resize(0); + return; +} + +/*! counts the number of lines in the input */ +static int countLines() +{ + const char *p=g_inputString; + char c; + int count=1; + while ((c=*p)) + { + p++ ; + if (c=='\n') count++; + } + if (p>g_inputString && *(p-1)!='\n') + { // last line does not end with a \n, so we add an extra + // line and explicitly terminate the line after parsing. + count++, + g_needsTermination=TRUE; + } + return count; +} + +static void endFontClass() +{ + if (g_currentFontClass) + { + g_code->endFontClass(); + g_currentFontClass=0; + } +} + +static void startFontClass(const char *s) +{ + endFontClass(); + g_code->startFontClass(s); + g_currentFontClass=s; +} + +//---------------------------------------------------------------------------- + +// recursively writes a linkified Objective-C method call +static void writeObjCMethodCall(ObjCCallCtx *ctx) +{ + if (ctx==0) return; + char c; + const char *p = ctx->format.data(); + if (!ctx->methodName.isEmpty()) + { + //printf("writeObjCMethodCall(%s) obj=%s method=%s\n", + // ctx->format.data(),ctx->objectTypeOrName.data(),ctx->methodName.data()); + if (!ctx->objectTypeOrName.isEmpty() && ctx->objectTypeOrName.at(0)!='$') + { + //printf("Looking for object=%s method=%s\n",ctx->objectTypeOrName.data(), + // ctx->methodName.data()); + ClassDef *cd = g_theVarContext.findVariable(ctx->objectTypeOrName); + if (cd==0) // not a local variable + { + if (ctx->objectTypeOrName=="self") + { + if (g_currentDefinition && + g_currentDefinition->definitionType()==Definition::TypeClass) + { + ctx->objectType = (ClassDef *)g_currentDefinition; + } + } + else + { + ctx->objectType = getResolvedClass( + g_currentDefinition, + g_sourceFileDef, + ctx->objectTypeOrName, + &ctx->method); + } + //printf(" object is class? %p\n",ctx->objectType); + if (ctx->objectType) // found class + { + ctx->method = ctx->objectType->getMemberByName(ctx->methodName); + //printf(" yes->method=%s\n",ctx->method?ctx->method->name().data():"<none>"); + } + else if (ctx->method==0) // search for class variable with the same name + { + //printf(" no\n"); + //printf("g_currentDefinition=%p\n",g_currentDefinition); + if (g_currentDefinition && + g_currentDefinition->definitionType()==Definition::TypeClass) + { + ctx->objectVar = ((ClassDef *)g_currentDefinition)->getMemberByName(ctx->objectTypeOrName); + //printf(" ctx->objectVar=%p\n",ctx->objectVar); + if (ctx->objectVar) + { + ctx->objectType = stripClassName(ctx->objectVar->typeString()); + //printf(" ctx->objectType=%p\n",ctx->objectType); + if (ctx->objectType) + { + ctx->method = ctx->objectType->getMemberByName(ctx->methodName); + //printf(" ctx->method=%p\n",ctx->method); + } + } + } + } + } + else // local variable + { + //printf(" object is local variable\n"); + if (cd!=VariableContext::dummyContext) + { + ctx->method = cd->getMemberByName(ctx->methodName); + //printf(" class=%p method=%p\n",cd,ctx->method); + } + } + } + } + + //printf("["); + while ((c=*p++)) // for each character in ctx->format + { + if (c=='$') + { + char nc=*p++; + if (nc=='$') // escaped $ + { + g_code->codify("$"); + } + else // name fragment or reference to a nested call + { + if (nc=='n') // name fragment + { + nc=*p++; + QCString refIdStr; + while (nc!=0 && isdigit(nc)) { refIdStr+=nc; nc=*p++; } + p--; + int refId=refIdStr.toInt(); + QCString *pName = g_nameDict.find(refId); + if (pName) + { + if (ctx->method && ctx->method->isLinkable()) + { + g_code->linkableSymbol(g_yyLineNr,ctx->method->name(),ctx->method, + g_currentMemberDef ? g_currentMemberDef : g_currentDefinition); + writeMultiLineCodeLink(*g_code, + ctx->method->getReference(), + ctx->method->getOutputFileBase(), + ctx->method->anchor(), + pName->data(), + ctx->method->briefDescriptionAsTooltip()); + if (g_currentMemberDef) + { + addDocCrossReference(g_currentMemberDef,ctx->method); + } + } + else + { + g_code->linkableSymbol(g_yyLineNr,pName->data(),0, + g_currentMemberDef ? g_currentMemberDef : g_currentDefinition); + codifyLines(pName->data()); + } + } + else + { + //printf("Invalid name: id=%d\n",refId); + } + } + else if (nc=='o') // reference to potential object name + { + nc=*p++; + QCString refIdStr; + while (nc!=0 && isdigit(nc)) { refIdStr+=nc; nc=*p++; } + p--; + int refId=refIdStr.toInt(); + QCString *pObject = g_objectDict.find(refId); + if (pObject) + { + if (*pObject=="self") + { + if (g_currentDefinition && + g_currentDefinition->definitionType()==Definition::TypeClass) + { + ctx->objectType = (ClassDef *)g_currentDefinition; + if (ctx->objectType->categoryOf()) + { + ctx->objectType = ctx->objectType->categoryOf(); + } + if (ctx->objectType) + { + ctx->method = ctx->objectType->getMemberByName(ctx->methodName); + } + } + startFontClass("keyword"); + codifyLines(pObject->data()); + endFontClass(); + } + else if (*pObject=="super") + { + if (g_currentDefinition && + g_currentDefinition->definitionType()==Definition::TypeClass) + { + ClassDef *cd = (ClassDef *)g_currentDefinition; + if (cd->categoryOf()) + { + cd = cd->categoryOf(); + } + BaseClassList *bcd = cd->baseClasses(); + if (bcd) // get direct base class (there should be only one) + { + BaseClassListIterator bli(*bcd); + BaseClassDef *bclass; + for (bli.toFirst();(bclass=bli.current());++bli) + { + if (bclass->classDef->compoundType()!=ClassDef::Protocol) + { + ctx->objectType = bclass->classDef; + if (ctx->objectType) + { + ctx->method = ctx->objectType->getMemberByName(ctx->methodName); + } + } + } + } + } + startFontClass("keyword"); + codifyLines(pObject->data()); + endFontClass(); + } + else if (ctx->objectVar && ctx->objectVar->isLinkable()) // object is class variable + { + g_code->linkableSymbol(g_yyLineNr,ctx->objectVar->name(),ctx->objectVar, + g_currentMemberDef ? g_currentMemberDef : g_currentDefinition); + writeMultiLineCodeLink(*g_code, + ctx->objectVar->getReference(), + ctx->objectVar->getOutputFileBase(), + ctx->objectVar->anchor(), + pObject->data(), + ctx->objectVar->briefDescriptionAsTooltip()); + if (g_currentMemberDef) + { + addDocCrossReference(g_currentMemberDef,ctx->objectVar); + } + } + else if (ctx->objectType && + ctx->objectType!=VariableContext::dummyContext && + ctx->objectType->isLinkable() + ) // object is class name + { + ClassDef *cd = ctx->objectType; + g_code->linkableSymbol(g_yyLineNr,cd->name(),cd, + g_currentMemberDef ? g_currentMemberDef : g_currentDefinition); + writeMultiLineCodeLink(*g_code, + cd->getReference(), + cd->getOutputFileBase(), + cd->anchor(), + pObject->data(), + cd->briefDescriptionAsTooltip()); + } + else // object still needs to be resolved + { + ClassDef *cd = getResolvedClass(g_currentDefinition, + g_sourceFileDef, *pObject); + if (cd && cd->isLinkable()) + { + if (ctx->objectType==0) ctx->objectType=cd; + g_code->linkableSymbol(g_yyLineNr,cd->name(),cd, + g_currentMemberDef ? g_currentMemberDef : g_currentDefinition); + writeMultiLineCodeLink(*g_code, + cd->getReference(), + cd->getOutputFileBase(), + cd->anchor(), + pObject->data(), + cd->briefDescriptionAsTooltip()); + } + else + { + g_code->linkableSymbol(g_yyLineNr,pObject->data(),0, + g_currentMemberDef ? g_currentMemberDef : g_currentDefinition); + codifyLines(pObject->data()); + } + } + } + else + { + //printf("Invalid object: id=%d\n",refId); + } + } + else if (nc=='c') // reference to nested call + { + nc=*p++; + QCString refIdStr; + while (nc!=0 && isdigit(nc)) { refIdStr+=nc; nc=*p++; } + p--; + int refId=refIdStr.toInt(); + ObjCCallCtx *ictx = g_contextDict.find(refId); + if (ictx) // recurse into nested call + { + writeObjCMethodCall(ictx); + if (ictx->method) // link to nested call successfully + { + // get the ClassDef representing the method's return type + if (QCString(ictx->method->typeString())=="id") + { + // see if the method name is unique, if so we link to it + MemberName *mn=Doxygen::memberNameSDict->find(ctx->methodName); + //printf("mn->count=%d ictx->method=%s ctx->methodName=%s\n", + // mn==0?-1:(int)mn->count(), + // ictx->method->name().data(), + // ctx->methodName.data()); + if (mn && mn->count()==1) // member name unique + { + ctx->method = mn->getFirst(); + } + } + else + { + ctx->objectType = stripClassName(ictx->method->typeString()); + if (ctx->objectType) + { + ctx->method = ctx->objectType->getMemberByName(ctx->methodName); + } + } + //printf(" ***** method=%s -> object=%p\n",ictx->method->name().data(),ctx->objectType); + } + } + else + { + //printf("Invalid context: id=%d\n",refId); + } + } + else if (nc=='w') // some word + { + nc=*p++; + QCString refIdStr; + while (nc!=0 && isdigit(nc)) { refIdStr+=nc; nc=*p++; } + p--; + int refId=refIdStr.toInt(); + QCString *pWord = g_wordDict.find(refId); + if (pWord) + { + g_code->linkableSymbol(g_yyLineNr,pWord->data(),0, + g_currentMemberDef ? g_currentMemberDef : g_currentDefinition); + codifyLines(pWord->data()); + } + } + else // illegal marker + { + ASSERT(!"invalid escape sequence"); + } + } + } + else // normal non-marker character + { + char s[2]; + s[0]=c;s[1]=0; + codifyLines(s); + } + } + //printf("%s %s]\n",ctx->objectTypeOrName.data(),ctx->methodName.data()); + //printf("}=(type='%s',name='%s')", + // ctx->objectTypeOrName.data(), + // ctx->methodName.data()); +} + +// Replaces an Objective-C method name fragment s by a marker of the form +// $n12, the number (12) can later be used as a key for obtaining the name +// fragment, from g_nameDict +static QCString escapeName(const char *s) +{ + QCString result; + result.sprintf("$n%d",g_currentNameId); + g_nameDict.insert(g_currentNameId,new QCString(s)); + g_currentNameId++; + return result; +} + +static QCString escapeObject(const char *s) +{ + QCString result; + result.sprintf("$o%d",g_currentObjId); + g_objectDict.insert(g_currentObjId,new QCString(s)); + g_currentObjId++; + return result; +} + +static QCString escapeWord(const char *s) +{ + QCString result; + result.sprintf("$w%d",g_currentWordId); + g_wordDict.insert(g_currentWordId,new QCString(s)); + g_currentWordId++; + return result; +} + +/* ----------------------------------------------------------------- + */ +#undef YY_INPUT +#define YY_INPUT(buf,result,max_size) result=yyread(buf,max_size); + +static int yyread(char *buf,int max_size) +{ + int c=0; + while( c < max_size && g_inputString[g_inputPosition] ) + { + *buf = g_inputString[g_inputPosition++] ; + c++; buf++; + } + return c; +} + +%} + +B [ \t] +BN [ \t\n\r] +ID "$"?[a-z_A-Z\x80-\xFF][a-z_A-Z0-9\x80-\xFF]* +SEP ("::"|"\\") +SCOPENAME ({SEP}{BN}*)?({ID}{BN}*{SEP}{BN}*)*("~"{BN}*)?{ID} +TEMPLIST "<"[^\"\}\{\(\)\/\n\>]*">" +SCOPETNAME (((({ID}{TEMPLIST}?){BN}*)?{SEP}{BN}*)*)((~{BN}*)?{ID}) +SCOPEPREFIX ({ID}{TEMPLIST}?{BN}*{SEP}{BN}*)+ +KEYWORD_OBJC ("@public"|"@private"|"@protected"|"@class"|"@implementation"|"@interface"|"@end"|"@selector"|"@protocol"|"@optional"|"@required"|"@throw"|"@synthesize"|"@property") +KEYWORD ("asm"|"__assume"|"auto"|"class"|"const"|"delete"|"enum"|"explicit"|"extern"|"false"|"friend"|"gcnew"|"gcroot"|"get"|"inline"|"internal"|"mutable"|"namespace"|"new"|"nullptr"|"override"|"operator"|"pin_ptr"|"private"|"protected"|"public"|"raise"|"register"|"remove"|"self"|"set"|"sizeof"|"static"|"struct"|"__super"|"function"|"template"|"generic"|"this"|"true"|"typedef"|"typeid"|"typename"|"union"|"using"|"virtual"|"volatile"|"abstract"|"final"|"import"|"synchronized"|"transient"|{KEYWORD_OBJC}) +FLOWKW ("break"|"case"|"catch"|"continue"|"default"|"do"|"else"|"finally"|"for"|"foreach"|"for each"|"goto"|"if"|"return"|"switch"|"throw"|"throws"|"try"|"while"|"@try"|"@catch"|"@finally") +TYPEKW ("bool"|"char"|"double"|"float"|"int"|"long"|"object"|"short"|"signed"|"unsigned"|"void"|"wchar_t"|"size_t"|"boolean"|"id"|"SEL"|"string") +CASTKW ("const_cast"|"dynamic_cast"|"reinterpret_cast"|"static_cast") +CHARLIT (("'"\\[0-7]{1,3}"'")|("'"\\."'")|("'"[^' \\\n]{1,4}"'")) +ARITHOP "+"|"-"|"/"|"*"|"%"|"--"|"++" +ASSIGNOP "="|"*="|"/="|"%="|"+="|"-="|"<<="|">>="|"&="|"^="|"|=" +LOGICOP "=="|"!="|">"|"<"|">="|"<="|"&&"|"||"|"!" +BITOP "&"|"|"|"^"|"<<"|">>"|"~" +OPERATOR {ARITHOP}|{ASSIGNOP}|{LOGICOP}|{BITOP} +%option noyywrap + +%x SkipString +%x SkipStringS +%x SkipVerbString +%x SkipCPP +%x SkipComment +%x SkipCxxComment +%x RemoveSpecialCComment +%x StripSpecialCComment +%x Body +%x FuncCall +%x MemberCall +%x MemberCall2 +%x SkipInits +%x ClassName +%x PackageName +%x ClassVar +%x CppCliTypeModifierFollowup +%x Bases +%x SkipSharp +%x ReadInclude +%x TemplDecl +%x TemplCast +%x CallEnd +%x ObjCMethod +%x ObjCParams +%x ObjCParamType +%x ObjCCall +%x ObjCMName +%x ObjCSkipStr +%x OldStyleArgs +%x UsingName + +%% + +<*>\x0d +<Body>^([ \t]*"#"[ \t]*("include"|"import")[ \t]*)("<"|"\"") { + startFontClass("preprocessor"); + g_code->codify(yytext); + BEGIN( ReadInclude ); + } +<Body>("@interface"|"@implementation"|"@protocol")[ \t\n]+ { + g_insideObjC=TRUE; + startFontClass("keyword"); + codifyLines(yytext); + endFontClass(); + if (!g_insideTemplate) + BEGIN( ClassName ); + } +<Body>(("public"|"private"){B}+)?("ref"|"value"|"interface"|"enum"){B}+("class"|"struct") { + if (g_insideTemplate) REJECT; + startFontClass("keyword"); + codifyLines(yytext); + endFontClass(); + BEGIN( ClassName ); + } +<Body>"property"|"event"/{BN}* { + if (g_insideTemplate) REJECT; + startFontClass("keyword"); + codifyLines(yytext); + endFontClass(); + } +<Body>(KEYWORD_CPPCLI_DATATYPE|("partial"{B}+)?"class"|"struct"|"union"|"namespace"|"interface"){B}+ { + startFontClass("keyword"); + codifyLines(yytext); + endFontClass(); + if (!g_insideTemplate) + BEGIN( ClassName ); + } +<Body>("package")[ \t\n]+ { + startFontClass("keyword"); + codifyLines(yytext); + endFontClass(); + BEGIN( PackageName ); + } +<ClassVar>\n { + if (!g_insideObjC) REJECT; + codifyLines(yytext); + BEGIN(Body); + } +<Body,ClassVar,Bases>"-"|"+" { + if (!g_insideObjC || g_insideBody) + { + g_code->codify(yytext); + } + else // Start of Objective-C method + { + //printf("Method!\n"); + g_code->codify(yytext); + BEGIN(ObjCMethod); + } + } +<ObjCMethod>":" { + g_code->codify(yytext); + BEGIN(ObjCParams); + } +<ObjCParams>"(" { + g_code->codify(yytext); + BEGIN(ObjCParamType); + } +<ObjCParams,ObjCMethod>";"|"{" { + g_code->codify(yytext); + if (*yytext=='{') + { + g_curlyCount++; + if (g_searchingForBody) + { + g_searchingForBody=FALSE; + g_insideBody=TRUE; + } + if (g_insideBody) g_bodyCurlyCount++; + if (!g_curClassName.isEmpty()) // valid class name + { + pushScope(g_curClassName); + DBG_CTX((stderr,"** scope stack push SCOPEBLOCK\n")); + g_scopeStack.push(SCOPEBLOCK); + } + } + g_type.resize(0); + g_name.resize(0); + BEGIN(Body); + } +<ObjCParams>{ID}{B}*":" { + g_code->codify(yytext); + } +<ObjCParamType>{TYPEKW} { + startFontClass("keywordtype"); + g_code->codify(yytext); + endFontClass(); + g_parmType=yytext; + } +<ObjCParamType>{ID} { + generateClassOrGlobalLink(*g_code,yytext); + g_parmType=yytext; + } +<ObjCParamType>")" { + g_code->codify(yytext); + BEGIN(ObjCParams); + } +<ObjCParams>{ID} { + g_code->linkableSymbol(g_yyLineNr,yytext,0, + g_currentMemberDef?g_currentMemberDef:g_currentDefinition); + g_code->codify(yytext); + g_parmName=yytext; + g_theVarContext.addVariable(g_parmType,g_parmName); + g_parmType.resize(0);g_parmName.resize(0); + } +<ObjCMethod,ObjCParams,ObjCParamType>{ID} { + generateClassOrGlobalLink(*g_code,yytext); + } +<ObjCMethod,ObjCParams,ObjCParamType>. { + g_code->codify(yytext); + } +<ObjCMethod,ObjCParams,ObjCParamType>\n { + codifyLines(yytext); + } +<ReadInclude>[^\n\"\>]+/(">"|"\"") { + //FileInfo *f; + bool ambig; + bool found=FALSE; + //QCString absPath = yytext; + //if (g_sourceFileDef && QDir::isRelativePath(absPath)) + //{ + // absPath = QDir::cleanDirPath(g_sourceFileDef->getPath()+"/"+absPath); + //} + + FileDef *fd=findFileDef(Doxygen::inputNameDict,yytext,ambig); + //printf("looking for include %s -> %s fd=%p\n",yytext,absPath.data(),fd); + if (fd && fd->isLinkable()) + { + if (ambig) // multiple input files match the name + { + //printf("===== yes %s is ambiguous\n",yytext); + QCString name = convertToQCString(QDir::cleanDirPath(yytext)); + if (!name.isEmpty() && g_sourceFileDef) + { + FileName *fn = Doxygen::inputNameDict->find(name); + if (fn) + { + FileNameIterator fni(*fn); + // for each include name + for (fni.toFirst();!found && (fd=fni.current());++fni) + { + // see if this source file actually includes the file + found = g_sourceFileDef->isIncluded(fd->absFilePath()); + //printf(" include file %s found=%d\n",fd->absFilePath().data(),found); + } + } + } + } + else // not ambiguous + { + found = TRUE; + } + } + //printf(" include file %s found=%d\n",fd ? fd->absFilePath().data() : "<none>",found); + if (found) + { + g_code->writeCodeLink(fd->getReference(),fd->getOutputFileBase(),0,yytext,fd->briefDescriptionAsTooltip()); + } + else + { + g_code->codify(yytext); + } + char c=yyinput(); + QCString text; + text+=c; + g_code->codify(text); + endFontClass(); + BEGIN( Body ); + } +<Body,Bases>^[ \t]*"#" { + startFontClass("preprocessor"); + g_lastSkipCppContext = YY_START; + g_code->codify(yytext); + BEGIN( SkipCPP ) ; + } +<SkipCPP>. { + g_code->codify(yytext); + } +<SkipCPP>[^\n\/\\]+ { + g_code->codify(yytext); + } +<SkipCPP>\\[\r]?\n { + codifyLines(yytext); + } +<SkipCPP>"//" { + g_code->codify(yytext); + } +<Body,FuncCall>"{" { + g_theVarContext.pushScope(); + + DBG_CTX((stderr,"** scope stack push INNERBLOCK\n")); + g_scopeStack.push(INNERBLOCK); + + if (g_searchingForBody) + { + g_searchingForBody=FALSE; + g_insideBody=TRUE; + } + g_code->codify(yytext); + g_curlyCount++; + if (g_insideBody) + { + g_bodyCurlyCount++; + } + g_type.resize(0); + g_name.resize(0); + BEGIN( Body ); + } +<Body,MemberCall,MemberCall2>"}" { + g_theVarContext.popScope(); + g_type.resize(0); + g_name.resize(0); + + int *scope = g_scopeStack.pop(); + DBG_CTX((stderr,"** scope stack pop SCOPEBLOCK=%d\n",scope==SCOPEBLOCK)); + if (scope==SCOPEBLOCK || scope==CLASSBLOCK) + { + popScope(); + } + + g_code->codify(yytext); + + //fprintf(stderr,"g_bodyCurlyCount=%d\n",g_bodyCurlyCount); + if (--g_bodyCurlyCount<=0) + { + g_insideBody=FALSE; + g_currentMemberDef=0; + if (g_currentDefinition) + g_currentDefinition=g_currentDefinition->getOuterScope(); + } + BEGIN(Body); + } +<Body,ClassVar>"@end" { + //printf("End of objc scope fd=%s\n",g_sourceFileDef->name().data()); + if (g_sourceFileDef) + { + FileDef *fd=g_sourceFileDef; + g_insideObjC = fd->name().lower().right(2)==".m" || + fd->name().lower().right(3)==".mm"; + //printf("insideObjC=%d\n",g_insideObjC); + } + else + { + g_insideObjC = FALSE; + } + if (g_insideBody) + { + g_theVarContext.popScope(); + + int *scope = g_scopeStack.pop(); + DBG_CTX((stderr,"** scope stack pop SCOPEBLOCK=%d\n",scope==SCOPEBLOCK)); + if (scope==SCOPEBLOCK || scope==CLASSBLOCK) + { + popScope(); + } + g_insideBody=FALSE; + } + + startFontClass("keyword"); + g_code->codify(yytext); + endFontClass(); + + g_currentMemberDef=0; + if (g_currentDefinition) + g_currentDefinition=g_currentDefinition->getOuterScope(); + BEGIN(Body); + } +<ClassName,ClassVar>";" { + g_code->codify(yytext); + g_searchingForBody=FALSE; + BEGIN( Body ); + } +<ClassName,ClassVar>[*&^%]+ { + g_type=g_curClassName.copy(); + g_name.resize(0); + g_code->codify(yytext); + BEGIN( Body ); // variable of type struct * + } +<ClassName>"__declspec"{B}*"("{B}*{ID}{B}*")" { + startFontClass("keyword"); + g_code->codify(yytext); + endFontClass(); + } +<ClassName>{ID}("::"{ID})* { + g_curClassName=yytext; + addType(); + generateClassOrGlobalLink(*g_code,yytext); + BEGIN( ClassVar ); + } +<ClassName>{ID}("\\"{ID})* { // PHP namespace + g_curClassName=substitute(yytext,"\\","::"); + g_scopeStack.push(CLASSBLOCK); + pushScope(g_curClassName); + addType(); + generateClassOrGlobalLink(*g_code,yytext); + BEGIN( ClassVar ); + } +<PackageName>{ID}("."{ID})* { + g_curClassName=substitute(yytext,".","::"); + //printf("found package: %s\n",g_curClassName.data()); + addType(); + codifyLines(yytext); + } +<ClassVar>"=" { + unput(*yytext); + BEGIN( Body ); + } +<ClassVar>("extends"|"implements") { // Java + startFontClass("keyword"); + codifyLines(yytext); + endFontClass(); + g_curClassBases.clear(); + BEGIN( Bases ); + } +<ClassVar>("sealed"|"abstract")/{BN}*(":"|"{") { + //fprintf(stderr,"***** C++/CLI modifier %s on g_curClassName=%s\n",yytext,g_curClassName.data()); + startFontClass("keyword"); + codifyLines(yytext); + endFontClass(); + BEGIN( CppCliTypeModifierFollowup ); + } +<ClassVar>{ID} { + g_type = g_curClassName.copy(); + g_name = yytext; + if (g_insideBody) + { + g_theVarContext.addVariable(g_type,g_name); + } + generateClassOrGlobalLink(*g_code,yytext); + } +<ClassName,ClassVar,CppCliTypeModifierFollowup>{B}*":"{B}* { + codifyLines(yytext); + g_curClassBases.clear(); + BEGIN( Bases ); + } +<PackageName>[ \t]*";" | +<Bases,ClassName,ClassVar,CppCliTypeModifierFollowup>{B}*"{"{B}* { + g_theVarContext.pushScope(); + g_code->codify(yytext); + g_curlyCount++; + if (YY_START==ClassVar && g_curClassName.isEmpty()) + { + g_curClassName = g_name.copy(); + } + if (g_searchingForBody) + { + g_searchingForBody=FALSE; + g_insideBody=TRUE; + } + if (g_insideBody) g_bodyCurlyCount++; + if (!g_curClassName.isEmpty()) // valid class name + { + DBG_CTX((stderr,"** scope stack push CLASSBLOCK\n")); + g_scopeStack.push(CLASSBLOCK); + pushScope(g_curClassName); + //fprintf(stderr,"***** g_curClassName=%s\n",g_curClassName.data()); + if (getResolvedClass(g_currentDefinition,g_sourceFileDef,g_curClassName)==0) + { + //fprintf(stderr,"Adding new class %s\n",g_curClassName.data()); + ClassDef *ncd=new ClassDef("<code>",1, + g_curClassName,ClassDef::Class,0,0,FALSE); + g_codeClassSDict->append(g_curClassName,ncd); + // insert base classes. + char *s=g_curClassBases.first(); + while (s) + { + ClassDef *bcd; + bcd=g_codeClassSDict->find(s); + if (bcd==0) bcd=getResolvedClass(g_currentDefinition,g_sourceFileDef,s); + if (bcd && bcd!=ncd) + { + ncd->insertBaseClass(bcd,s,Public,Normal); + } + s=g_curClassBases.next(); + } + } + //printf("g_codeClassList.count()=%d\n",g_codeClassList.count()); + } + else // not a class name -> assume inner block + { + DBG_CTX((stderr,"** scope stack push INNERBLOCK\n")); + g_scopeStack.push(INNERBLOCK); + } + g_curClassName.resize(0); + g_curClassBases.clear(); + BEGIN( Body ); + } +<Bases>"virtual"|"public"|"protected"|"private"|"@public"|"@private"|"@protected" { + startFontClass("keyword"); + g_code->codify(yytext); + endFontClass(); + } +<Bases>{SEP}?({ID}{SEP})*{ID} { + //fprintf(stderr,"%s:addBase(%s)\n",g_curClassName.data(),yytext); + g_curClassBases.inSort(yytext); + generateClassOrGlobalLink(*g_code,yytext); + } +<Bases>"<" { + g_code->codify(yytext); + if (!g_insideObjC) + { + g_sharpCount=1; + BEGIN ( SkipSharp ); + } + else + { + g_insideProtocolList=TRUE; + } + } +<Bases>">" { + g_code->codify(yytext); + g_insideProtocolList=FALSE; + } +<SkipSharp>"<" { + g_code->codify(yytext); + ++g_sharpCount; + } +<SkipSharp>">" { + g_code->codify(yytext); + if (--g_sharpCount<=0) + BEGIN ( Bases ); + } +<Bases>"(" { + g_code->codify(yytext); + g_sharpCount=1; + BEGIN ( SkipSharp ); + } +<SkipSharp>"(" { + g_code->codify(yytext); + ++g_sharpCount; + } +<SkipSharp>")" { + g_code->codify(yytext); + if (--g_sharpCount<=0) + BEGIN ( Bases ); + } + + +<Bases>"," { + g_code->codify(yytext); + } + + +<Body>{SCOPEPREFIX}?"operator"{B}*"()"{B}*/"(" { + addType(); + generateFunctionLink(*g_code,yytext); + g_bracketCount=0; + g_args.resize(0); + g_name+=yytext; + BEGIN( FuncCall ); + } +<Body>{SCOPEPREFIX}?"operator"/"(" { + addType(); + generateFunctionLink(*g_code,yytext); + g_bracketCount=0; + g_args.resize(0); + g_name+=yytext; + BEGIN( FuncCall ); + } +<Body>{SCOPEPREFIX}?"operator"[^a-z_A-Z0-9\(\n]+/"(" { + addType(); + generateFunctionLink(*g_code,yytext); + g_bracketCount=0; + g_args.resize(0); + g_name+=yytext; + BEGIN( FuncCall ); + } +<Body,TemplDecl>("template"|"generic")/([^a-zA-Z0-9]) { + startFontClass("keyword"); + codifyLines(yytext); + endFontClass(); + g_insideTemplate=TRUE; + g_sharpCount=0; + } +<Body>"using"{BN}+"namespace"{BN}+ { + startFontClass("keyword"); + codifyLines(yytext); + endFontClass(); + BEGIN(UsingName); + } +<UsingName>{ID}("::"{ID})* { addUsingDirective(yytext); + generateClassOrGlobalLink(*g_code,yytext); + DBG_CTX((stderr,"** scope stack push CLASSBLOCK\n")); + g_scopeStack.push(CLASSBLOCK); + pushScope(yytext); + BEGIN(Body); + } +<UsingName>\n { codifyLines(yytext); BEGIN(Body); } +<UsingName>. { codifyLines(yytext); BEGIN(Body); } +<Body,FuncCall>"$"?"this"("->"|".") { g_code->codify(yytext); // this-> for C++, this. for C# + } +<Body>{KEYWORD}/([^a-z_A-Z0-9]) { + startFontClass("keyword"); + codifyLines(yytext); + if (QCString(yytext)=="typedef") + { + addType(); + g_name+=yytext; + } + endFontClass(); + } +<Body>{KEYWORD}/{B}* { + startFontClass("keyword"); + codifyLines(yytext); + endFontClass(); + } +<Body>{KEYWORD}/{BN}*"(" { + startFontClass("keyword"); + codifyLines(yytext); + endFontClass(); + g_name.resize(0);g_type.resize(0); + } +<FuncCall>"in"/{BN}* { + if (!g_inForEachExpression) REJECT; + startFontClass("keywordflow"); + codifyLines(yytext); + endFontClass(); + // insert the variable in the parent scope, see bug 546158 + g_theVarContext.popScope(); + g_theVarContext.addVariable(g_parmType,g_parmName); + g_theVarContext.pushScope(); + g_name.resize(0);g_type.resize(0); + } +<Body>{FLOWKW}/{BN}*"(" { + startFontClass("keywordflow"); + codifyLines(yytext); + endFontClass(); + g_name.resize(0);g_type.resize(0); + g_inForEachExpression = (strcmp(yytext,"for each")==0 || strcmp(yytext, "foreach")==0); + BEGIN(FuncCall); + } +<Body>{FLOWKW}/([^a-z_A-Z0-9]) { + startFontClass("keywordflow"); + codifyLines(yytext); + endFontClass(); + if (g_inFunctionTryBlock && (strcmp(yytext,"catch")==0 || strcmp(yytext,"finally")==0)) + { + g_inFunctionTryBlock=FALSE; + } + } +<Body>{FLOWKW}/{B}* { + startFontClass("keywordflow"); + codifyLines(yytext); + endFontClass(); + } +<Body>[\\|\)\+\-\/\%\~\!] { + g_code->codify(yytext); + g_name.resize(0);g_type.resize(0); + if (*yytext==')') + { + g_theCallContext.popScope(); + g_bracketCount--; + BEGIN(FuncCall); + } + } +<Body,TemplDecl,ObjCMethod>{TYPEKW}/{B}* { + startFontClass("keywordtype"); + g_code->codify(yytext); + endFontClass(); + addType(); + g_name+=yytext; + } +<Body>"generic"/{B}*"<"[^\n\/\-\.\{\"\>]*">"{B}* { + startFontClass("keyword"); + g_code->codify(yytext); + endFontClass(); + g_sharpCount=0; + BEGIN(TemplDecl); + } +<Body>"template"/{B}*"<"[^\n\/\-\.\{\"\>]*">"{B}* { // template<...> + startFontClass("keyword"); + g_code->codify(yytext); + endFontClass(); + g_sharpCount=0; + BEGIN(TemplDecl); + } +<TemplDecl>"class"|"typename" { + startFontClass("keyword"); + codifyLines(yytext); + endFontClass(); + } +<TemplDecl>"<" { + g_code->codify(yytext); + g_sharpCount++; + } +<TemplDecl>">" { + g_code->codify(yytext); + g_sharpCount--; + if (g_sharpCount<=0) + { + BEGIN(Body); + } + } +<TemplCast>">" { + startFontClass("keyword"); + codifyLines(yytext); + endFontClass(); + BEGIN( g_lastTemplCastContext ); + } +<TemplCast>{ID}("::"{ID})* { + generateClassOrGlobalLink(*g_code,yytext); + } +<TemplCast>("const"|"volatile"){B}* { + startFontClass("keyword"); + codifyLines(yytext); + endFontClass(); + } +<TemplCast>[*^]* { + codifyLines(yytext); + } +<Body,FuncCall>{CASTKW}"<" { // static_cast<T>( + startFontClass("keyword"); + codifyLines(yytext); + endFontClass(); + g_lastTemplCastContext = YY_START; + BEGIN(TemplCast); + } +<Body>"$this->"{SCOPENAME}/{BN}*[;,)\]] { // PHP member variable + addType(); + generatePHPVariableLink(*g_code,yytext); + g_name+=yytext+7; + } +<Body,TemplCast>{SCOPENAME}{B}*"<"[^\n\/\-\.\{\"\>]*">"("::"{ID})*/{B}* { // A<T> *pt; + int i=QCString(yytext).find('<'); + QCString kw = QCString(yytext).left(i).stripWhiteSpace(); + if (kw.right(5)=="_cast" && YY_START==Body) + { + REJECT; + } + addType(); + generateClassOrGlobalLink(*g_code,yytext); + g_name+=yytext; + } +<Body>{SCOPENAME}/{BN}*[;,)\]] { // "int var;" or "var, var2" or "debug(f) macro" + addType(); + // changed this to generateFunctionLink, see bug 624514 + //generateClassOrGlobalLink(*g_code,yytext,FALSE,TRUE); + generateFunctionLink(*g_code,yytext); + g_name+=yytext; + } +<Body>{SCOPENAME}/{B}* { // p->func() + addType(); + generateClassOrGlobalLink(*g_code,yytext); + g_name+=yytext; + } +<Body>"("{B}*("*"{B}*)+{SCOPENAME}*{B}*")"/{B}* { // (*p)->func() but not "if (p) ..." + g_code->codify(yytext); + int s=0;while (s<(int)yyleng && !isId(yytext[s])) s++; + int e=(int)yyleng-1;while (e>=0 && !isId(yytext[e])) e--; + QCString varname = ((QCString)yytext).mid(s,e-s+1); + addType(); + g_name=varname; + } +<Body>{SCOPETNAME}/{BN}*"(" { // a() or c::a() or t<A,B>::a() or A\B\foo() + addType(); + generateFunctionLink(*g_code,yytext); + g_bracketCount=0; + g_args.resize(0); + g_name+=yytext; + BEGIN( FuncCall ); + } +<FuncCall,Body,MemberCall,MemberCall2,SkipInits>\" { + startFontClass("stringliteral"); + g_code->codify(yytext); + g_lastStringContext=YY_START; + g_inForEachExpression = FALSE; + BEGIN( SkipString ); + } +<FuncCall,Body,MemberCall,MemberCall2,SkipInits>\' { + startFontClass("stringliteral"); + g_code->codify(yytext); + g_lastStringContext=YY_START; + g_inForEachExpression = FALSE; + BEGIN( SkipStringS ); + } +<SkipString>[^\"\\\r\n]* { + g_code->codify(yytext); + } +<SkipStringS>[^\'\\\r\n]* { + g_code->codify(yytext); + } +<SkipString,SkipStringS>"//"|"/*" { + g_code->codify(yytext); + } +<SkipString>@?\" { + g_code->codify(yytext); + endFontClass(); + BEGIN( g_lastStringContext ); + } +<SkipStringS>\' { + g_code->codify(yytext); + endFontClass(); + BEGIN( g_lastStringContext ); + } +<SkipString,SkipStringS>\\. { + g_code->codify(yytext); + } +<SkipVerbString>[^"\n]+ { + g_code->codify(yytext); + } +<SkipVerbString>\"\" { // escaped quote + g_code->codify(yytext); + } +<SkipVerbString>\" { // end of string + g_code->codify(yytext); + endFontClass(); + BEGIN( g_lastVerbStringContext ); + } +<SkipVerbString>. { + g_code->codify(yytext); + } +<SkipVerbString>\n { + codifyLines(yytext); + } +<Body>":" { + g_code->codify(yytext); + g_name.resize(0);g_type.resize(0); + } +<Body>"<" { + if (g_insideTemplate) + { + g_sharpCount++; + } + g_code->codify(yytext); + } +<Body>">" { + if (g_insideTemplate) + { + if (--g_sharpCount<=0) + { + g_insideTemplate=FALSE; + } + } + g_code->codify(yytext); + } +<Body,MemberCall,MemberCall2,FuncCall>"'"((\\0[Xx0-9]+)|(\\.)|(.))"'" { + startFontClass("charliteral"); + g_code->codify(yytext); + endFontClass(); + } +<Body>"."|"->" { + if (yytext[0]=='-') // -> could be overloaded + { + updateCallContextForSmartPointer(); + } + g_code->codify(yytext); + g_memCallContext = YY_START; + BEGIN( MemberCall ); + } +<MemberCall>{SCOPETNAME}/{BN}*"(" { + if (g_theCallContext.getClass()) + { + if (!generateClassMemberLink(*g_code,g_theCallContext.getClass(),yytext)) + { + g_code->linkableSymbol(g_yyLineNr,yytext,0, + g_currentMemberDef?g_currentMemberDef:g_currentDefinition); + g_code->codify(yytext); + addToSearchIndex(yytext); + } + g_name.resize(0); + } + else + { + g_code->linkableSymbol(g_yyLineNr,yytext,0, + g_currentMemberDef?g_currentMemberDef:g_currentDefinition); + g_code->codify(yytext); + addToSearchIndex(yytext); + g_name.resize(0); + } + g_type.resize(0); + g_bracketCount=0; + if (g_memCallContext==Body) + { + BEGIN(FuncCall); + } + else + { + BEGIN(g_memCallContext); + } + } +<MemberCall>{SCOPENAME}/{B}* { + if (g_theCallContext.getClass()) + { + //fprintf(stderr,"g_theCallContext.getClass()=%p\n",g_theCallContext.getClass()); + if (!generateClassMemberLink(*g_code,g_theCallContext.getClass(),yytext)) + { + g_code->linkableSymbol(g_yyLineNr,yytext,0, + g_currentMemberDef?g_currentMemberDef:g_currentDefinition); + g_code->codify(yytext); + addToSearchIndex(yytext); + } + g_name.resize(0); + } + else + { + //fprintf(stderr,"no class context!\n"); + g_code->codify(yytext); + addToSearchIndex(yytext); + g_name.resize(0); + } + g_type.resize(0); + BEGIN(g_memCallContext); + } +<Body>[,=;\[] { + if (g_insideObjC && *yytext=='[') + { + //printf("Found start of ObjC call!\n"); + // start of a method call + g_contextDict.setAutoDelete(TRUE); + g_nameDict.setAutoDelete(TRUE); + g_objectDict.setAutoDelete(TRUE); + g_wordDict.setAutoDelete(TRUE); + g_contextDict.clear(); + g_nameDict.clear(); + g_objectDict.clear(); + g_wordDict.clear(); + g_currentCtxId = 0; + g_currentNameId = 0; + g_currentObjId = 0; + g_currentCtx = 0; + g_braceCount = 0; + unput('['); + BEGIN(ObjCCall); + } + else + { + g_code->codify(yytext); + g_saveName = g_name.copy(); + g_saveType = g_type.copy(); + if (*yytext!='[' && !g_type.isEmpty()) + { + //printf("g_scopeStack.bottom()=%p\n",g_scopeStack.bottom()); + if (g_scopeStack.top()!=CLASSBLOCK) + { + //printf("AddVariable: '%s' '%s' context=%d\n", + // g_type.data(),g_name.data(),g_theVarContext.count()); + g_theVarContext.addVariable(g_type,g_name); + } + g_name.resize(0); + } + if (*yytext==';' || *yytext=='=') + { + g_type.resize(0); + g_name.resize(0); + } + else if (*yytext=='[') + { + g_theCallContext.pushScope(); + } + g_args.resize(0); + g_parmType.resize(0); + g_parmName.resize(0); + } + } + /* +<ObjCMemberCall>{ID} { + if (strcmp(yytext,"self")==0 || strcmp(yytext,"super")==0) + { + // TODO: get proper base class for "super" + g_theCallContext.setClass(getClass(g_curClassName)); + startFontClass("keyword"); + g_code->codify(yytext); + endFontClass(); + } + else + { + generateClassOrGlobalLink(*g_code,yytext); + } + g_name.resize(0); + BEGIN(ObjCMemberCall2); + } +<ObjCMemberCall>"[" { + g_code->codify(yytext); + g_theCallContext.pushScope(); + } +<ObjCMemberCall2>{ID}":"? { + g_name+=yytext; + if (g_theCallContext.getClass()) + { + //printf("Calling method %s\n",g_name.data()); + if (!generateClassMemberLink(*g_code,g_theCallContext.getClass(),g_name)) + { + g_code->codify(yytext); + addToSearchIndex(g_name); + } + } + else + { + g_code->codify(yytext); + addToSearchIndex(g_name); + } + g_name.resize(0); + BEGIN(ObjCMemberCall3); + } +<ObjCMemberCall2,ObjCMemberCall3>"]" { + g_theCallContext.popScope(); + g_code->codify(yytext); + BEGIN(Body); + } + */ +<ObjCCall,ObjCMName>"[" { + saveObjCContext(); + g_currentCtx->format+=*yytext; + BEGIN(ObjCCall); + //printf("open\n"); + } +<ObjCCall,ObjCMName>"]" { + g_currentCtx->format+=*yytext; + restoreObjCContext(); + BEGIN(ObjCMName); + if (g_currentCtx==0) + { + // end of call + writeObjCMethodCall(g_contextDict.find(0)); + BEGIN(Body); + } + //printf("close\n"); + } +<ObjCCall>{ID} { + g_currentCtx->format+=escapeObject(yytext); + if (g_braceCount==0) + { + g_currentCtx->objectTypeOrName=yytext; + //printf("new type=%s\n",g_currentCtx->objectTypeOrName.data()); + BEGIN(ObjCMName); + } + } +<ObjCMName>{ID}/{BN}*"]" { + if (g_braceCount==0 && + g_currentCtx->methodName.isEmpty()) + { + g_currentCtx->methodName=yytext; + g_currentCtx->format+=escapeName(yytext); + } + else + { + g_currentCtx->format+=escapeWord(yytext); + } + } +<ObjCMName>{ID}/{BN}*":" { + if (g_braceCount==0) + { + g_currentCtx->methodName+=yytext; + g_currentCtx->methodName+=":"; + } + g_currentCtx->format+=escapeName(yytext); + } +<ObjCSkipStr>[^\n\"$\\]* { g_currentCtx->format+=yytext; } +<ObjCSkipStr>\\. { g_currentCtx->format+=yytext; } +<ObjCSkipStr>"\"" { g_currentCtx->format+=yytext; + BEGIN(g_lastStringContext); + } +<ObjCCall,ObjCMName>{CHARLIT} { g_currentCtx->format+=yytext; } +<ObjCCall,ObjCMName>"@"?"\"" { g_currentCtx->format+=yytext; + g_lastStringContext=YY_START; + BEGIN(ObjCSkipStr); + } +<ObjCCall,ObjCMName,ObjCSkipStr>"$" { g_currentCtx->format+="$$"; } +<ObjCCall,ObjCMName>"(" { g_currentCtx->format+=*yytext; g_braceCount++; } +<ObjCCall,ObjCMName>")" { g_currentCtx->format+=*yytext; g_braceCount--; } +<ObjCSkipStr>"@"/"\"" { // needed to prevent matching the global rule (for C#) + g_currentCtx->format+=yytext; + } +<ObjCCall,ObjCMName,ObjCSkipStr>{ID} { g_currentCtx->format+=escapeWord(yytext); } +<ObjCCall,ObjCMName,ObjCSkipStr>. { g_currentCtx->format+=*yytext; } +<ObjCCall,ObjCMName,ObjCSkipStr>\n { g_currentCtx->format+=*yytext; } + +<Body>"]" { + g_theCallContext.popScope(); + g_code->codify(yytext); + // TODO: nested arrays like: a[b[0]->func()]->func() + g_name = g_saveName.copy(); + g_type = g_saveType.copy(); + } +<Body>[0-9]+ { + g_code->codify(yytext); + } +<Body>[0-9]+[xX][0-9A-Fa-f]+ { + g_code->codify(yytext); + } +<MemberCall2,FuncCall>{KEYWORD}/([^a-z_A-Z0-9]) { + //addParmType(); + //g_parmName=yytext; + startFontClass("keyword"); + g_code->codify(yytext); + endFontClass(); + } +<MemberCall2,FuncCall,OldStyleArgs,TemplCast>{TYPEKW}/([^a-z_A-Z0-9]) { + addParmType(); + g_parmName=yytext; + startFontClass("keywordtype"); + g_code->codify(yytext); + endFontClass(); + } +<MemberCall2,FuncCall>{FLOWKW}/([^a-z_A-Z0-9]) { + addParmType(); + g_parmName=yytext; + startFontClass("keywordflow"); + g_code->codify(yytext); + endFontClass(); + } +<MemberCall2,FuncCall>{ID}(({B}*"<"[^\n\[\](){}<>]*">")?({B}*"::"{B}*{ID})?)* { + addParmType(); + g_parmName=yytext; + generateClassOrGlobalLink(*g_code,yytext,!g_insideBody); + } +<FuncCall>";" { // probably a cast, not a function call + g_code->codify(yytext); + g_inForEachExpression = FALSE; + BEGIN( Body ); + } +<MemberCall2,FuncCall>, { + g_code->codify(yytext); + g_theVarContext.addVariable(g_parmType,g_parmName); + g_parmType.resize(0);g_parmName.resize(0); + } +<MemberCall2,FuncCall>"(" { + g_parmType.resize(0);g_parmName.resize(0); + g_code->codify(yytext); + g_bracketCount++; + g_theCallContext.pushScope(); + if (YY_START==FuncCall && !g_insideBody) + { + g_theVarContext.pushScope(); + } + } +<MemberCall2,FuncCall>{OPERATOR} { // operator + if (strcmp(yytext,"*") && + strcmp(yytext,"&") && + strcmp(yytext,"^") && + strcmp(yytext,"%")) // typically a pointer or reference + { + // not a * or &, or C++/CLI's ^ or % + g_parmType.resize(0);g_parmName.resize(0); + } + g_code->codify(yytext); + } +<MemberCall,MemberCall2,FuncCall>")" { + g_theVarContext.addVariable(g_parmType,g_parmName); + g_theCallContext.popScope(); + g_inForEachExpression = FALSE; + //g_theCallContext.setClass(0); // commented out, otherwise a()->b() does not work for b(). + g_code->codify(yytext); + if (--g_bracketCount<=0) + { + if (g_name.isEmpty()) + { + BEGIN( Body ); + } + else + { + BEGIN( CallEnd ); + } + } + } +<CallEnd>[ \t\n]* { codifyLines(yytext); } + /* +<MemberCall2,FuncCall>")"[ \t\n]*[;:] { + */ +<CallEnd>[;:] { + codifyLines(yytext); + g_bracketCount=0; + if (*yytext==';') g_searchingForBody=FALSE; + if (!g_type.isEmpty()) + { + //fprintf(stderr,"add variable g_type=%s g_name=%s)\n",g_type.data(),g_name.data()); + g_theVarContext.addVariable(g_type,g_name); + } + g_parmType.resize(0);g_parmName.resize(0); + g_theCallContext.setClass(0); + if (*yytext==';' || g_insideBody) + { + if (!g_insideBody) + { + g_theVarContext.popScope(); + } + g_name.resize(0);g_type.resize(0); + BEGIN( Body ); + } + else + { + g_bracketCount=0; + BEGIN( SkipInits ); + } + } +<CallEnd>("const"|"volatile"|"sealed"|"override")({BN}+("const"|"volatile"|"sealed"|"override"))*/{BN}*(";"|"="|"throw"{BN}*"(") { + startFontClass("keyword"); + codifyLines(yytext); + endFontClass(); + } +<CallEnd,OldStyleArgs>("const"|"volatile"|"sealed"|"override")*({BN}+("const"|"volatile"|"sealed"|"override"))*{BN}*"{" { + if (g_insideBody) + { + g_theVarContext.pushScope(); + } + g_theVarContext.addVariable(g_parmType,g_parmName); + //g_theCallContext.popScope(); + g_parmType.resize(0);g_parmName.resize(0); + int index = g_name.findRev("::"); + //fprintf(stderr,"g_name=%s\n",g_name.data()); + if (index!=-1) + { + QCString scope = g_name.left(index); + if (!g_classScope.isEmpty()) scope.prepend(g_classScope+"::"); + ClassDef *cd=getResolvedClass(Doxygen::globalScope,g_sourceFileDef,scope); + if (cd) + { + setClassScope(cd->name()); + g_scopeStack.push(SCOPEBLOCK); + DBG_CTX((stderr,"** scope stack push SCOPEBLOCK\n")); + } + else + { + //setClassScope(g_realScope); + g_scopeStack.push(INNERBLOCK); + DBG_CTX((stderr,"** scope stack push INNERBLOCK\n")); + } + } + else + { + DBG_CTX((stderr,"** scope stack push INNERBLOCK\n")); + g_scopeStack.push(INNERBLOCK); + } + yytext[yyleng-1]='\0'; + QCString cv(yytext); + if (!cv.stripWhiteSpace().isEmpty()) + { + startFontClass("keyword"); + codifyLines(yytext); + endFontClass(); + } + else // just whitespace + { + codifyLines(yytext); + } + g_code->codify("{"); + if (g_searchingForBody) + { + g_searchingForBody=FALSE; + g_insideBody=TRUE; + } + if (g_insideBody) g_bodyCurlyCount++; + g_curlyCount++; + g_type.resize(0); g_name.resize(0); + BEGIN( Body ); + } +<CallEnd>"try" { // function-try-block + startFontClass("keyword"); + g_code->codify(yytext); + endFontClass(); + g_inFunctionTryBlock=TRUE; + } +<CallEnd>{ID} { + if (g_insideBody || !g_parmType.isEmpty()) + { + REJECT; + } + // could be K&R style definition + addParmType(); + g_parmName=yytext; + generateClassOrGlobalLink(*g_code,yytext,!g_insideBody); + BEGIN(OldStyleArgs); + } +<OldStyleArgs>{ID} { + addParmType(); + g_parmName=yytext; + generateClassOrGlobalLink(*g_code,yytext,!g_insideBody); + } +<OldStyleArgs>[,;] { + g_code->codify(yytext); + g_theVarContext.addVariable(g_parmType,g_parmName); + if (*yytext==';') g_parmType.resize(0); + g_parmName.resize(0); + } +<CallEnd,OldStyleArgs>"#" { + startFontClass("preprocessor"); + g_lastSkipCppContext = Body; + g_code->codify(yytext); + BEGIN( SkipCPP ); + } +<CallEnd>. { + unput(*yytext); + if (!g_insideBody) + { + g_theVarContext.popScope(); + } + g_name.resize(0);g_args.resize(0); + g_parmType.resize(0);g_parmName.resize(0); + BEGIN( Body ); + } +<SkipInits>";" { + g_code->codify(yytext); + g_type.resize(0); g_name.resize(0); + BEGIN( Body ); + } +<SkipInits>"{" { + g_code->codify(yytext); + g_curlyCount++; + if (g_searchingForBody) + { + g_searchingForBody=FALSE; + g_insideBody=TRUE; + } + if (g_insideBody) g_bodyCurlyCount++; + if (g_name.find("::")!=-1) + { + DBG_CTX((stderr,"** scope stack push SCOPEBLOCK\n")); + g_scopeStack.push(SCOPEBLOCK); + setClassScope(g_realScope); + } + else + { + DBG_CTX((stderr,"** scope stack push INNERBLOCK\n")); + g_scopeStack.push(INNERBLOCK); + } + g_type.resize(0); g_name.resize(0); + BEGIN( Body ); + } +<SkipInits>{ID} { + generateClassOrGlobalLink(*g_code,yytext); + } +<FuncCall>{ID}/"(" { + generateFunctionLink(*g_code,yytext); + } +<FuncCall>{ID}/("."|"->") { + g_name=yytext; + generateClassOrGlobalLink(*g_code,yytext); + BEGIN( MemberCall2 ); + } +<FuncCall,MemberCall2>("("{B}*("*"{B}*)+{ID}*{B}*")"{B}*)/("."|"->") { + g_code->codify(yytext); + int s=0;while (!isId(yytext[s])) s++; + int e=(int)yyleng-1;while (!isId(yytext[e])) e--; + g_name=((QCString)yytext).mid(s,e-s+1); + BEGIN( MemberCall2 ); + } +<MemberCall2>{ID}/([ \t\n]*"(") { + if (!g_args.isEmpty()) + generateMemberLink(*g_code,g_args,yytext); + else + generateClassOrGlobalLink(*g_code,yytext); + g_args.resize(0); + BEGIN( FuncCall ); + } +<MemberCall2>{ID}/([ \t\n]*("."|"->")) { + //g_code->codify(yytext); + g_name=yytext; + generateClassOrGlobalLink(*g_code,yytext); + BEGIN( MemberCall2 ); + } +<MemberCall2>"->"|"." { + if (yytext[0]=='-') // -> could be overloaded + { + updateCallContextForSmartPointer(); + } + g_code->codify(yytext); + g_memCallContext = YY_START; + BEGIN( MemberCall ); + } +<SkipComment>"/*"("!"?)"*/" { + g_code->codify(yytext); + endFontClass(); + BEGIN( g_lastCContext ) ; + } +<SkipComment>"//"|"/*" { + g_code->codify(yytext); + } +<SkipComment>[^*/\n]+ { + g_code->codify(yytext); + } +<SkipComment>[ \t]*"*/" { + g_code->codify(yytext); + endFontClass(); + BEGIN( g_lastCContext ) ; + } +<SkipCxxComment>[^\r\n]*"\\"[\r]?\n { // line continuation + codifyLines(yytext); + } +<SkipCxxComment>[^\r\n]+ { + g_code->codify(yytext); + } +<SkipCxxComment>\r +<SkipCxxComment>\n { + unput('\n'); + endFontClass(); + BEGIN( g_lastCContext ) ; + } +<SkipCxxComment>. { + g_code->codify(yytext); + } +<RemoveSpecialCComment>"*/"{B}*\n({B}*\n)*({B}*(("//@"[{}])|("/*@"[{}]"*/")){B}*\n)?{B}*"/*"[*!]/[^/*] { + g_yyLineNr+=QCString(yytext).contains('\n'); + } +<RemoveSpecialCComment>"*/"{B}*\n({B}*\n)*({B}*(("//@"[{}])|("/*@"[{}]"*/")){B}*\n)? { + g_yyLineNr+=QCString(yytext).contains('\n'); + nextCodeLine(); + if (g_lastSpecialCContext==SkipCxxComment) + { // force end of C++ comment here + endFontClass(); + BEGIN( g_lastCContext ) ; + } + else + { + BEGIN(g_lastSpecialCContext); + } + } +<RemoveSpecialCComment>"*/" { + BEGIN(g_lastSpecialCContext); + } +<RemoveSpecialCComment>[^*\n]+ +<RemoveSpecialCComment>"//"|"/*" +<RemoveSpecialCComment>\n { g_yyLineNr++; } +<RemoveSpecialCComment>. +<MemberCall>[^a-z_A-Z0-9(\n] { + g_code->codify(yytext); + g_type.resize(0); + g_name.resize(0); + BEGIN(g_memCallContext); + } +<*>\n({B}*"//"[!/][^\n]*\n)+ { // remove special one-line comment + if (YY_START==SkipCPP) REJECT; + if (Config_getBool("STRIP_CODE_COMMENTS")) + { + g_yyLineNr+=((QCString)yytext).contains('\n'); + nextCodeLine(); + } + else + { + startFontClass("comment"); + codifyLines(yytext); + endFontClass(); + } + if (YY_START==SkipCxxComment) + { + endFontClass(); + BEGIN( g_lastCContext ) ; + } + } +<SkipCPP>\n/.*\n { + codifyLines(yytext); + endFontClass(); + BEGIN( g_lastSkipCppContext ) ; + } +<*>\n{B}*"//@"[{}].*\n { // remove one-line group marker + if (Config_getBool("STRIP_CODE_COMMENTS")) + { + g_yyLineNr+=2; + nextCodeLine(); + } + else + { + startFontClass("comment"); + codifyLines(yytext); + endFontClass(); + } + if (YY_START==SkipCxxComment) + { + endFontClass(); + BEGIN( g_lastCContext ) ; + } + } +<*>\n{B}*"/*@"[{}] { // remove one-line group marker + if (Config_getBool("STRIP_CODE_COMMENTS")) + { + g_lastSpecialCContext = YY_START; + g_yyLineNr++; + BEGIN(RemoveSpecialCComment); + } + else + { + // check is to prevent getting stuck in skipping C++ comments + if (YY_START != SkipCxxComment) + { + g_lastCContext = YY_START ; + } + startFontClass("comment"); + codifyLines(yytext); + BEGIN(SkipComment); + } + } +<*>^{B}*"//@"[{}].*\n { // remove one-line group marker + if (Config_getBool("STRIP_CODE_COMMENTS")) + { + g_yyLineNr++; + nextCodeLine(); + } + else + { + startFontClass("comment"); + codifyLines(yytext); + endFontClass(); + } + } +<*>^{B}*"/*@"[{}] { // remove multi-line group marker + if (Config_getBool("STRIP_CODE_COMMENTS")) + { + g_lastSpecialCContext = YY_START; + BEGIN(RemoveSpecialCComment); + } + else + { + // check is to prevent getting stuck in skipping C++ comments + if (YY_START != SkipCxxComment) + { + g_lastCContext = YY_START ; + } + startFontClass("comment"); + g_code->codify(yytext); + BEGIN(SkipComment); + } + } +<*>^{B}*"//"[!/][^\n]*\n { // remove special one-line comment + if (Config_getBool("STRIP_CODE_COMMENTS")) + { + g_yyLineNr++; + nextCodeLine(); + } + else + { + startFontClass("comment"); + codifyLines(yytext); + endFontClass(); + } + } +<*>"//"[!/][^\n]*\n { // strip special one-line comment + if (YY_START==SkipComment || YY_START==SkipString || YY_START==SkipCPP) REJECT; + if (Config_getBool("STRIP_CODE_COMMENTS")) + { + char c[2]; c[0]='\n'; c[1]=0; + codifyLines(c); + } + else + { + startFontClass("comment"); + codifyLines(yytext); + endFontClass(); + } + } +<*>"/*[tag:"[^\]\n]*"]*/"{B}* { // special pattern /*[tag:filename]*/ to force linking to a tag file + g_forceTagReference=yytext; + int s=g_forceTagReference.find(':'); + int e=g_forceTagReference.findRev(']'); + g_forceTagReference = g_forceTagReference.mid(s+1,e-s-1); + } +<*>\n{B}*"/*"[!*]/[^/*] { + if (Config_getBool("STRIP_CODE_COMMENTS")) + { + g_lastSpecialCContext = YY_START; + g_yyLineNr++; + BEGIN(RemoveSpecialCComment); + } + else + { + // check is to prevent getting stuck in skipping C++ comments + if (YY_START != SkipCxxComment) + { + g_lastCContext = YY_START ; + } + startFontClass("comment"); + codifyLines(yytext); + BEGIN(SkipComment); + } + } +<*>^{B}*"/*"[!*]/[^/*] { // special C comment block at a new line + if (Config_getBool("STRIP_CODE_COMMENTS")) + { + g_lastSpecialCContext = YY_START; + BEGIN(RemoveSpecialCComment); + } + else + { + // check is to prevent getting stuck in skipping C++ comments + if (YY_START != SkipCxxComment) + { + g_lastCContext = YY_START ; + } + startFontClass("comment"); + g_code->codify(yytext); + BEGIN(SkipComment); + } + } +<*>"/*"[!*]/[^/*] { // special C comment block half way a line + if (YY_START==SkipString) REJECT; + if (Config_getBool("STRIP_CODE_COMMENTS")) + { + g_lastSpecialCContext = YY_START; + BEGIN(RemoveSpecialCComment); + } + else + { + // check is to prevent getting stuck in skipping C++ comments + if (YY_START != SkipCxxComment) + { + g_lastCContext = YY_START ; + } + startFontClass("comment"); + g_code->codify(yytext); + BEGIN(SkipComment); + } + } +<*>"/*"("!"?)"*/" { + if (YY_START==SkipString) REJECT; + if (!Config_getBool("STRIP_CODE_COMMENTS")) + { + startFontClass("comment"); + g_code->codify(yytext); + endFontClass(); + } + } +<*>"/*" { + startFontClass("comment"); + g_code->codify(yytext); + // check is to prevent getting stuck in skipping C++ comments + if (YY_START != SkipCxxComment) + { + g_lastCContext = YY_START ; + } + BEGIN( SkipComment ) ; + } +<*>@\" { // C# verbatim string + startFontClass("stringliteral"); + g_code->codify(yytext); + g_lastVerbStringContext=YY_START; + BEGIN(SkipVerbString); + } +<*>"//" { + startFontClass("comment"); + g_code->codify(yytext); + g_lastCContext = YY_START ; + BEGIN( SkipCxxComment ) ; + } +<*>"("|"[" { + g_code->codify(yytext); + g_theCallContext.pushScope(); + } +<*>")"|"]" { + g_code->codify(yytext); + g_theCallContext.popScope(); + } +<*>\n { + codifyLines(yytext); + } +<*>. { + g_code->codify(yytext); + } + /* +<*>([ \t\n]*"\n"){2,} { // combine multiple blank lines + //QCString sepLine=yytext; + //g_code->codify("\n\n"); + //g_yyLineNr+=sepLine.contains('\n'); + //char sepLine[3]="\n\n"; + codifyLines(yytext); + } + */ + +%% + +/*@ ---------------------------------------------------------------------------- + */ + +static void saveObjCContext() +{ + if (g_currentCtx) + { + g_currentCtx->format+=QCString().sprintf("$c%d",g_currentCtxId); + if (g_braceCount==0 && YY_START==ObjCCall) + { + g_currentCtx->objectTypeOrName=g_currentCtx->format.mid(1); + //printf("new type=%s\n",g_currentCtx->objectTypeOrName.data()); + } + g_contextStack.push(g_currentCtx); + } + else + { + //printf("Trying to save NULL context!\n"); + } + ObjCCallCtx *newCtx = new ObjCCallCtx; + newCtx->id = g_currentCtxId; + newCtx->lexState = YY_START; + newCtx->braceCount = g_braceCount; + newCtx->objectType = 0; + newCtx->objectVar = 0; + newCtx->method = 0; + //printf("save state=%d\n",YY_START); + g_contextDict.insert(g_currentCtxId,newCtx); + g_currentCtx = newCtx; + g_braceCount = 0; + g_currentCtxId++; +} + +static void restoreObjCContext() +{ + //printf("restore state=%d->%d\n",YY_START,g_currentCtx->lexState); + BEGIN(g_currentCtx->lexState); + g_braceCount = g_currentCtx->braceCount; + if (!g_contextStack.isEmpty()) + { + g_currentCtx = g_contextStack.pop(); + } + else + { + g_currentCtx = 0; + //printf("Trying to pop context while g_contextStack is empty!\n"); + } +} + +void resetCCodeParserState() +{ + //printf("***initParseCodeContext()\n"); + g_forceTagReference.resize(0); + g_theVarContext.clear(); + g_classScopeLengthStack.setAutoDelete(TRUE); + g_classScopeLengthStack.clear(); + delete g_codeClassSDict; + g_codeClassSDict = new ClassSDict(17); + g_codeClassSDict->setAutoDelete(TRUE); + g_codeClassSDict->clear(); + g_curClassBases.clear(); + g_anchorCount = 0; +} + +void parseCCode(CodeOutputInterface &od,const char *className,const QCString &s, + bool exBlock, const char *exName,FileDef *fd, + int startLine,int endLine,bool inlineFragment, + MemberDef *memberDef,bool showLineNumbers) +{ + //printf("***parseCode() exBlock=%d exName=%s fd=%p className=%s\n", + // exBlock,exName,fd,className); + if (s.isEmpty()) return; + if (g_codeClassSDict==0) + { + resetCCodeParserState(); + } + g_code = &od; + g_inputString = s; + g_inputPosition = 0; + g_currentFontClass = 0; + g_needsTermination = FALSE; + g_inFunctionTryBlock = FALSE; + if (endLine!=-1) + g_inputLines = endLine+1; + else + g_inputLines = countLines(); + + if (startLine!=-1) + g_yyLineNr = startLine; + else + g_yyLineNr = 1; + + g_curlyCount = 0; + g_bodyCurlyCount = 0; + g_bracketCount = 0; + g_sharpCount = 0; + g_insideTemplate = FALSE; + g_theCallContext.clear(); + g_scopeStack.clear(); + g_classScope = className; + //printf("parseCCode %s\n",className); + g_exampleBlock = exBlock; + g_exampleName = exName; + g_sourceFileDef = fd; + g_lineNumbers = fd!=0 && showLineNumbers; + bool cleanupSourceDef = FALSE; + if (/* exBlock */ fd==0) + { + // create a dummy filedef for the example + g_sourceFileDef = new FileDef("",(exName?exName:"generated")); + cleanupSourceDef = TRUE; + } + if (g_sourceFileDef) + { + setCurrentDoc(g_sourceFileDef->name(),g_sourceFileDef->getSourceFileBase()); + g_insideObjC = g_sourceFileDef->name().lower().right(2)==".m" || + g_sourceFileDef->name().lower().right(3)==".mm"; + } + g_currentDefinition = 0; + g_currentMemberDef = 0; + g_searchingForBody = exBlock; + g_insideBody = FALSE; + g_bracketCount = 0; + if (!g_exampleName.isEmpty()) + { + g_exampleFile = convertNameToFile(g_exampleName+"-example",FALSE,TRUE); + //printf("g_exampleFile=%s\n",g_exampleFile.data()); + } + g_includeCodeFragment = inlineFragment; + //printf("** exBlock=%d exName=%s include=%d\n",exBlock,exName,inlineFragment); + startCodeLine(); + g_type.resize(0); + g_name.resize(0); + g_args.resize(0); + g_parmName.resize(0); + g_parmType.resize(0); + if (memberDef) setParameterList(memberDef); + codeYYrestart( codeYYin ); + BEGIN( Body ); + codeYYlex(); + g_lexInit=TRUE; + if (g_needsTermination) + { + endFontClass(); + g_code->endCodeLine(); + } + if (cleanupSourceDef) + { + // delete the temporary file definition used for this example + delete g_sourceFileDef; + g_sourceFileDef=0; + } + return; +} + +void codeFreeScanner() +{ +#if defined(YY_FLEX_SUBMINOR_VERSION) + if (g_lexInit) + { + codeYYlex_destroy(); + } +#endif +} + + + +#if !defined(YY_FLEX_SUBMINOR_VERSION) +extern "C" { // some bogus code to keep the compiler happy + void codeYYdummy() { yy_flex_realloc(0,0); } +} +#elif YY_FLEX_SUBMINOR_VERSION<33 +#error "You seem to be using a version of flex newer than 2.5.4 but older than 2.5.33. These versions do NOT work with doxygen! Please use version <=2.5.4 or >=2.5.33 or expect things to be parsed wrongly!" +#endif + diff --git a/trunk/src/commentcnv.h b/trunk/src/commentcnv.h new file mode 100644 index 0000000..5277524 --- /dev/null +++ b/trunk/src/commentcnv.h @@ -0,0 +1,27 @@ +/***************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#ifndef _COMMENTCNV_H +#define _COMMNETCNV_H + +class BufStr; + +extern void convertCppComments(BufStr *inBuf,BufStr *outBuf, + const char *fileName); + +#endif + diff --git a/trunk/src/commentcnv.l b/trunk/src/commentcnv.l new file mode 100644 index 0000000..b031265 --- /dev/null +++ b/trunk/src/commentcnv.l @@ -0,0 +1,881 @@ +/***************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +%{ + +#define YY_NEVER_INTERACTIVE 1 + +#include <stdio.h> +#include <stdlib.h> + +#include <qstack.h> +#include <qregexp.h> +#include <qtextstream.h> +#include <qglobal.h> + +#include "bufstr.h" +#include "debug.h" +#include "message.h" +#include "config.h" +#include "doxygen.h" +#include "util.h" + +#include <assert.h> + +#define ADDCHAR(c) g_outBuf->addChar(c) +#define ADDARRAY(a,s) g_outBuf->addArray(a,s) + +struct CondCtx +{ + CondCtx(int line,QCString id,bool b) + : lineNr(line),sectionId(id), skip(b) {} + int lineNr; + QCString sectionId; + bool skip; +}; + +static BufStr * g_inBuf; +static BufStr * g_outBuf; +static int g_inBufPos; +static int g_col; +static int g_blockHeadCol; +static bool g_mlBrief; +static int g_readLineCtx; +static bool g_skip; +static QCString g_fileName; +static int g_lineNr; +static int g_condCtx; +static QStack<CondCtx> g_condStack; +static QCString g_blockName; +static int g_lastCommentContext; +static bool g_inSpecialComment; +static bool g_inRoseComment; +static int g_stringContext; +static int g_charContext; +static int g_javaBlock; +static bool g_specialComment; + +static QCString g_aliasString; +static int g_blockCount; +static bool g_lastEscaped; +static int g_lastBlockContext; +static bool g_pythonDocString; + + +static SrcLangExt g_lang; + +static void replaceCommentMarker(const char *s,int len) +{ + const char *p=s; + char c; + // copy leading blanks + while ((c=*p) && (c==' ' || c=='\t' || c=='\n')) + { + ADDCHAR(c); + g_lineNr += c=='\n'; + p++; + } + // replace start of comment marker by blanks and the last character by a * + int blanks=0; + while ((c=*p) && (c=='/' || c=='!' || c=='#')) + { + blanks++; + p++; + if (*p=='<') // comment-after-item marker + { + blanks++; + p++; + } + if (c=='!') // end after first ! + { + break; + } + } + if (blanks>0) + { + while (blanks>1) + { + ADDCHAR(' '); + blanks--; + } + ADDCHAR('*'); + } + // copy comment line to output + ADDARRAY(p,len-(p-s)); +} + +static inline int computeIndent(const char *s) +{ + int col=0; + static int tabSize=Config_getInt("TAB_SIZE"); + const char *p=s; + char c; + while ((c=*p++)) + { + if (c==' ') col++; + else if (c=='\t') col+=tabSize-(col%tabSize); + else break; + } + return col; +} + +static inline void copyToOutput(const char *s,int len) +{ + int i; + if (g_skip) // only add newlines. + { + for (i=0;i<len;i++) + { + if (s[i]=='\n') + { + ADDCHAR('\n'); + //fprintf(stderr,"---> skip %d\n",g_lineNr); + g_lineNr++; + } + } + } + else if (len>0) + { + ADDARRAY(s,len); + static int tabSize=Config_getInt("TAB_SIZE"); + for (i=0;i<len;i++) + { + switch (s[i]) + { + case '\n': g_col=0; + //fprintf(stderr,"---> copy %d\n",g_lineNr); + g_lineNr++; break; + case '\t': g_col+=tabSize-(g_col%tabSize); break; + default: g_col++; break; + } + } + } +} + +static void startCondSection(const char *sectId) +{ + g_condStack.push(new CondCtx(g_lineNr,sectId,g_skip)); + if (Config_getList("ENABLED_SECTIONS").find(sectId)!=-1) + { + //printf("*** Section is enabled!\n"); + } + else + { + //printf("*** Section is disabled!\n"); + g_skip=TRUE; + } +} + +static void endCondSection() +{ + if (g_condStack.isEmpty()) + { + warn(g_fileName,g_lineNr,"Found \\endcond command without matching \\cond"); + g_skip=FALSE; + } + else + { + CondCtx *ctx = g_condStack.pop(); + g_skip=ctx->skip; + } +} + +#if 0 +/** remove and executes cond and endcond commands in \a s */ +static QCString handleCondCmdInAliases(const QCString &s) +{ + QCString result; + //printf("handleCondCmdInAliases(%s)\n",s.data()); + static QRegExp cmdPat("[\\\\@][a-z_A-Z][a-z_A-Z0-9]*"); + int p=0,i,l; + while ((i=cmdPat.match(s,p,&l))!=-1) + { + result+=s.mid(p,i-p); + QCString cmd = s.mid(i+1,l-1); + //printf("Found command %s\n",cmd.data()); + if (cmd=="cond") + { + int sp=i+l,ep; + const char *arg=s.data()+sp; + char c; + // skip spaces + while ((c=*arg) && (c==' ' || c=='\t')) arg++,sp++; + // read argument + if (*arg=='\n') // no arg + { + startCondSection(" "); + ep=sp; + } + else // get argument + { + ep=sp; + while ((c=*arg) && isId(c)) arg++,ep++; + if (ep>sp) + { + QCString id = s.mid(sp,ep-sp); + //printf("Found conditional section id %s\n",id.data()); + startCondSection(id); + } + else // invalid identifier + { + } + } + p=ep; + } + else if (cmd=="endcond") + { + endCondSection(); + p=i+l; + } + else + { + result+=s.mid(i,l); + p=i+l; + } + } + result+=s.right(s.length()-p); + return result; +} +#endif + +/** copies string \a s with length \a len to the output, while + * replacing any alias commands found in the string. + */ +static void replaceAliases(const char *s) +{ + QCString result = resolveAliasCmd(s); + //printf("replaceAliases(%s)->'%s'\n",s,result.data()); + copyToOutput(result,result.length()); +} + + +#undef YY_INPUT +#define YY_INPUT(buf,result,max_size) result=yyread(buf,max_size); + +static int yyread(char *buf,int max_size) +{ + int bytesInBuf = g_inBuf->curPos()-g_inBufPos; + int bytesToCopy = QMIN(max_size,bytesInBuf); + memcpy(buf,g_inBuf->data()+g_inBufPos,bytesToCopy); + g_inBufPos+=bytesToCopy; + return bytesToCopy; +} + +void replaceComment(int offset); + +%} + +%option noyywrap + +%x Scan +%x SkipString +%x SkipChar +%x SComment +%x CComment +%x Verbatim +%x VerbatimCode +%x ReadLine +%x CondLine +%x ReadAliasArgs + +%% + +<Scan>[^"'!\/\n\\#\\-]* { /* eat anything that is not " / or \n */ + copyToOutput(yytext,(int)yyleng); + } +<Scan>"\"\"\""! { /* start of python long comment */ + if (g_lang!=SrcLangExt_Python) + { + REJECT; + } + else + { + g_pythonDocString = TRUE; + copyToOutput(yytext,(int)yyleng); + BEGIN(CComment); + } + } +<Scan>"!>" { + if (g_lang!=SrcLangExt_Fortran) + { + REJECT; + } + else + { + copyToOutput(yytext,(int)yyleng); + BEGIN(CComment); + } + } +<Scan>"\"" { /* start of a string */ + copyToOutput(yytext,(int)yyleng); + g_stringContext = YY_START; + BEGIN(SkipString); + } +<Scan>' { + copyToOutput(yytext,(int)yyleng); + g_charContext = YY_START; + BEGIN(SkipChar); + } +<Scan>\n { /* new line */ + copyToOutput(yytext,(int)yyleng); + } +<Scan>("//!"|"///").*/\n[ \t]*"//"[\/!][^\/] { /* start C++ style special comment block */ + if (g_mlBrief) + { + REJECT; // bail out if we do not need to convert + } + else + { + int i=3; + if (yytext[2]=='/') + { + while (i<(int)yyleng && yytext[i]=='/') i++; + } + g_blockHeadCol=g_col; + copyToOutput("/**",3); + replaceAliases(yytext+i); + g_inSpecialComment=TRUE; + BEGIN(SComment); + } + } +<Scan>"//##Documentation".*/\n { /* Start of Rational Rose ANSI C++ comment block */ + if (g_mlBrief) REJECT; + int i=17; //=strlen("//##Documentation"); + g_blockHeadCol=g_col; + copyToOutput("/**",3); + replaceAliases(yytext+i); + g_inRoseComment=TRUE; + BEGIN(SComment); + } +<Scan>"//"/.*\n { /* one line C++ comment */ + copyToOutput(yytext,(int)yyleng); + g_readLineCtx=YY_START; + BEGIN(ReadLine); + } +<Scan>"/*"[*!]? { /* start of a C comment */ + g_specialComment=(int)yyleng==3; + copyToOutput(yytext,(int)yyleng); + BEGIN(CComment); + } +<Scan>"#"("#")? { + if (g_lang!=SrcLangExt_Python) + { + REJECT; + } + else + { + copyToOutput(yytext,(int)yyleng); + BEGIN(CComment); + } + } +<Scan>"--!" { + if (g_lang!=SrcLangExt_VHDL) + { + REJECT; + } + else + { + copyToOutput(yytext,(int)yyleng); + BEGIN(CComment); + } + } +<Scan>"!>" { + if (g_lang!=SrcLangExt_Fortran) + { + REJECT; + } + else + { + copyToOutput(yytext,(int)yyleng); + BEGIN(CComment); + } + } +<CComment>"{@code"/[ \t\n] { + copyToOutput("@code",5); + g_lastCommentContext = YY_START; + g_javaBlock=1; + g_blockName=&yytext[1]; + BEGIN(VerbatimCode); + } +<CComment,ReadLine>[\\@]("dot"|"code"|"msc")/[^a-z_A-Z0-9] { /* start of a verbatim block */ + copyToOutput(yytext,(int)yyleng); + g_lastCommentContext = YY_START; + g_javaBlock=0; + g_blockName=&yytext[1]; + BEGIN(VerbatimCode); + } +<CComment,ReadLine>[\\@]("f$"|"f["|"f{"[a-z]*) { + copyToOutput(yytext,(int)yyleng); + g_blockName=&yytext[1]; + if (g_blockName.at(1)=='[') + { + g_blockName.at(1)=']'; + } + else if (g_blockName.at(1)=='{') + { + g_blockName.at(1)='}'; + } + g_lastCommentContext = YY_START; + BEGIN(Verbatim); + } +<CComment,ReadLine>[\\@]("verbatim"|"latexonly"|"htmlonly"|"xmlonly"|"rtfonly"|"manonly")/[^a-z_A-Z0-9] { /* start of a verbatim block */ + copyToOutput(yytext,(int)yyleng); + g_blockName=&yytext[1]; + g_lastCommentContext = YY_START; + BEGIN(Verbatim); + } +<Scan>. { /* any other character */ + copyToOutput(yytext,(int)yyleng); + } +<Verbatim>[\\@]("endverbatim"|"endlatexonly"|"endhtmlonly"|"endxmlonly"|"endrtfonly"|"endmanonly"|"f$"|"f]"|"f}") { /* end of verbatim block */ + copyToOutput(yytext,(int)yyleng); + if (yytext[1]=='f') // end of formula + { + BEGIN(g_lastCommentContext); + } + else if (&yytext[4]==g_blockName) + { + BEGIN(g_lastCommentContext); + } + } +<VerbatimCode>"{" { + if (g_javaBlock==0) + { + REJECT; + } + else + { + g_javaBlock++; + copyToOutput(yytext,(int)yyleng); + } + } +<VerbatimCode>"}" { + if (g_javaBlock==0) + { + REJECT; + } + else + { + g_javaBlock--; + if (g_javaBlock==0) + { + copyToOutput(" @endcode ",10); + BEGIN(g_lastCommentContext); + } + else + { + copyToOutput(yytext,(int)yyleng); + } + } + } +<VerbatimCode>[\\@]("enddot"|"endcode"|"endmsc") { /* end of verbatim block */ + copyToOutput(yytext,(int)yyleng); + if (&yytext[4]==g_blockName) + { + BEGIN(g_lastCommentContext); + } + } +<VerbatimCode>^[ \t]*"//"[\!\/]? { /* skip leading comments */ + if (!g_inSpecialComment) + { + copyToOutput(yytext,(int)yyleng); + } + } +<Verbatim,VerbatimCode>[^@\/\\\n{}]* { /* any character not a backslash or new line or } */ + copyToOutput(yytext,(int)yyleng); + } +<Verbatim,VerbatimCode>\n { /* new line in verbatim block */ + copyToOutput(yytext,(int)yyleng); + } +<Verbatim,VerbatimCode>^[ \t]*"///" { + if (g_blockName=="dot" || g_blockName=="msc" || g_blockName.at(0)=='f') + { + // see bug 487871, strip /// from dot images and formulas. + copyToOutput(" ",3); + } + else // even slashes are verbatim (e.g. \verbatim, \code) + { + REJECT; + } + } +<Verbatim,VerbatimCode>. { /* any other character */ + copyToOutput(yytext,(int)yyleng); + } +<SkipString>\\. { /* escaped character in string */ + copyToOutput(yytext,(int)yyleng); + } +<SkipString>"\"" { /* end of string */ + copyToOutput(yytext,(int)yyleng); + BEGIN(g_stringContext); + } +<SkipString>. { /* any other string character */ + copyToOutput(yytext,(int)yyleng); + } +<SkipString>\n { /* new line inside string (illegal for some compilers) */ + copyToOutput(yytext,(int)yyleng); + } +<SkipChar>\\. { /* escaped character */ + copyToOutput(yytext,(int)yyleng); + } +<SkipChar>' { /* end of character literal */ + copyToOutput(yytext,(int)yyleng); + BEGIN(g_charContext); + } +<SkipChar>. { /* any other string character */ + copyToOutput(yytext,(int)yyleng); + } +<SkipChar>\n { /* new line character */ + copyToOutput(yytext,(int)yyleng); + } + +<CComment>[^\\!@*\n{\"]* { /* anything that is not a '*' or command */ + copyToOutput(yytext,(int)yyleng); + } +<CComment>"*"+[^*/\\@\n{\"]* { /* stars without slashes */ + copyToOutput(yytext,(int)yyleng); + } +<CComment>"\"\"\"" { /* end of Python docstring */ + if (g_lang!=SrcLangExt_Python) + { + REJECT; + } + else + { + g_pythonDocString = FALSE; + copyToOutput(yytext,(int)yyleng); + BEGIN(Scan); + } + } +<CComment>\n { /* new line in comment */ + copyToOutput(yytext,(int)yyleng); + } +<CComment>"*"+"/" { /* end of C comment */ + if (g_lang==SrcLangExt_Python) + { + REJECT; + } + else + { + copyToOutput(yytext,(int)yyleng); + BEGIN(Scan); + } + } +<CComment>"\n"/[ \t]*[^#] { /* end of Python comment */ + if (g_lang!=SrcLangExt_Python || g_pythonDocString) + { + REJECT; + } + else + { + copyToOutput(yytext,(int)yyleng); + BEGIN(Scan); + } + } +<CComment>"\n"/[ \t]*[^\-] { /* end of VHDL comment */ + if (g_lang!=SrcLangExt_VHDL) + { + REJECT; + } + else + { + copyToOutput(yytext,(int)yyleng); + BEGIN(Scan); + } + } +<CComment>"\n"/[ \t]*[^!] { /* end of Fortran comment */ + if (g_lang!=SrcLangExt_Fortran) + { + REJECT; + } + else + { + copyToOutput(yytext,(int)yyleng); + BEGIN(Scan); + } + } +<CComment>"'" { + g_charContext = YY_START; + copyToOutput(yytext,(int)yyleng); + BEGIN(SkipChar); + } +<CComment>"\"" { + g_stringContext = YY_START; + copyToOutput(yytext,(int)yyleng); + BEGIN(SkipString); + } +<CComment>. { + copyToOutput(yytext,(int)yyleng); + } +<SComment>^[ \t]*"///"[\/]*/\n { + replaceComment(0); + } +<SComment>\n[ \t]*"///"[\/]*/\n { + replaceComment(1); + } +<SComment>^[ \t]*"///"[^\/\n]/.*\n { + replaceComment(0); + g_readLineCtx=YY_START; + BEGIN(ReadLine); + } +<SComment>\n[ \t]*"///"[^\/\n]/.*\n { + replaceComment(1); + g_readLineCtx=YY_START; + BEGIN(ReadLine); + } +<SComment>^[ \t]*"//!" | // just //! +<SComment>^[ \t]*"//!<"/.*\n | // or //!< something +<SComment>^[ \t]*"//!"[^<]/.*\n { // or //!something + replaceComment(0); + g_readLineCtx=YY_START; + BEGIN(ReadLine); + } +<SComment>\n[ \t]*"//!" | +<SComment>\n[ \t]*"//!<"/.*\n | +<SComment>\n[ \t]*"//!"[^<\n]/.*\n { + replaceComment(1); + g_readLineCtx=YY_START; + BEGIN(ReadLine); + } +<SComment>^[ \t]*"//##"/.*\n { + if (!g_inRoseComment) + { + REJECT; + } + else + { + replaceComment(0); + g_readLineCtx=YY_START; + BEGIN(ReadLine); + } + } +<SComment>\n[ \t]*"//##"/.*\n { + if (!g_inRoseComment) + { + REJECT; + } + else + { + replaceComment(1); + g_readLineCtx=YY_START; + BEGIN(ReadLine); + } + } +<SComment>\n { /* end of special comment */ + copyToOutput(" */",3); + copyToOutput(yytext,(int)yyleng); + g_inSpecialComment=FALSE; + g_inRoseComment=FALSE; + BEGIN(Scan); + } +<ReadLine>[^\\@\n]*/\n { + copyToOutput(yytext,(int)yyleng); + BEGIN(g_readLineCtx); + } +<CComment,ReadLine>[\\@][\\@][~a-z_A-Z][a-z_A-Z0-9]*[ \t]* { // escaped command + copyToOutput(yytext,(int)yyleng); + } +<CComment,ReadLine>[\\@]"cond"[ \t]+ { // conditional section + g_condCtx = YY_START; + BEGIN(CondLine); + } +<CComment,ReadLine>[\\@]"endcond"/[^a-z_A-Z0-9] { // end of conditional section + bool oldSkip=g_skip; + endCondSection(); + if (YY_START==CComment && oldSkip && !g_skip) + { + //printf("** Adding start of comment!\n"); + if (g_lang!=SrcLangExt_Python && + g_lang!=SrcLangExt_VHDL && + g_lang!=SrcLangExt_Fortran) + { + ADDCHAR('/'); + ADDCHAR('*'); + if (g_specialComment) + { + ADDCHAR('*'); + } + } + } + } +<CondLine>[a-z_A-Z][a-z_A-Z0-9.\-]* { + bool oldSkip=g_skip; + startCondSection(yytext); + if (g_condCtx==CComment && !oldSkip && g_skip) + { + //printf("** Adding terminator for comment!\n"); + if (g_lang!=SrcLangExt_Python && + g_lang!=SrcLangExt_VHDL && + g_lang!=SrcLangExt_Fortran) + { + ADDCHAR('*'); + ADDCHAR('/'); + } + } + BEGIN(g_condCtx); + } +<CondLine>[ \t]* +<CComment,ReadLine>[\\@]"cond"[ \t\r]*/\n | +<CondLine>. { // forgot section id? + if (YY_START!=CondLine) g_condCtx=YY_START; + bool oldSkip=g_skip; + startCondSection(" "); // fake section id causing the section to be hidden unconditionally + if (g_condCtx==CComment && !oldSkip && g_skip) + { + //printf("** Adding terminator for comment!\n"); + if (g_lang!=SrcLangExt_Python && + g_lang!=SrcLangExt_VHDL) + { + ADDCHAR('*'); + ADDCHAR('/'); + } + } + if (*yytext=='\n') g_lineNr++; + BEGIN(g_condCtx); + } +<CComment,ReadLine>[\\@][a-z_A-Z][a-z_A-Z0-9]* { // expand alias without arguments + replaceAliases(yytext); + } +<CComment,ReadLine>[\\@][a-z_A-Z][a-z_A-Z0-9]*"{" { // expand alias with arguments + g_lastBlockContext=YY_START; + g_blockCount=1; + g_aliasString=yytext; + g_lastEscaped=0; + BEGIN( ReadAliasArgs ); + } +<ReadAliasArgs>^[ \t]*"//"[/!]/[^\n]+ { // skip leading special comments (see bug 618079) + } +<ReadAliasArgs>"*/" { // oops, end of comment in the middle of an alias? + if (g_lang==SrcLangExt_Python) + { + REJECT; + } + else // abort the alias, restart scanning + { + copyToOutput(g_aliasString,g_aliasString.length()); + copyToOutput(yytext,(int)yyleng); + BEGIN(Scan); + } + } +<ReadAliasArgs>[^{}\n\\\*]+ { + g_aliasString+=yytext; + g_lastEscaped=FALSE; + } +<ReadAliasArgs>"\\" { + if (g_lastEscaped) g_lastEscaped=FALSE; + else g_lastEscaped=TRUE; + g_aliasString+=yytext; + } +<ReadAliasArgs>\n { + g_aliasString+=yytext; + g_lineNr++; + g_lastEscaped=FALSE; + } +<ReadAliasArgs>"{" { + g_aliasString+=yytext; + if (!g_lastEscaped) g_blockCount++; + g_lastEscaped=FALSE; + } +<ReadAliasArgs>"}" { + g_aliasString+=yytext; + if (!g_lastEscaped) g_blockCount--; + if (g_blockCount==0) + { + replaceAliases(g_aliasString); + BEGIN( g_lastBlockContext ); + } + g_lastEscaped=FALSE; + } +<ReadAliasArgs>. { + g_aliasString+=yytext; + g_lastEscaped=FALSE; + } +<ReadLine>. { + copyToOutput(yytext,(int)yyleng); + } + +%% + +void replaceComment(int offset) +{ + if (g_mlBrief) + { + copyToOutput(yytext,(int)yyleng); + } + else + { + //printf("replaceComment(%s)\n",yytext); + int i=computeIndent(&yytext[offset]); + if (i==g_blockHeadCol) + { + replaceCommentMarker(yytext,(int)yyleng); + } + else + { + copyToOutput(" */",3); + int i;for (i=(int)yyleng-1;i>=0;i--) unput(yytext[i]); + g_inSpecialComment=FALSE; + BEGIN(Scan); + } + } +} + +/*! This function does three things: + * -# It converts multi-line C++ style comment blocks (that are aligned) + * to C style comment blocks (if MULTILINE_CPP_IS_BRIEF is set to NO). + * -# It replaces aliases with their definition (see ALIASES) + * -# It handles conditional sections (cond...endcond blocks) + */ +void convertCppComments(BufStr *inBuf,BufStr *outBuf,const char *fileName) +{ + //printf("convertCppComments(%s)\n",fileName); + g_inBuf = inBuf; + g_outBuf = outBuf; + g_inBufPos = 0; + g_col = 0; + g_mlBrief = Config_getBool("MULTILINE_CPP_IS_BRIEF"); + g_skip = FALSE; + g_fileName = fileName; + g_lang = getLanguageFromFileName(fileName); + g_pythonDocString = FALSE; + g_lineNr = 1; + g_condStack.clear(); + g_condStack.setAutoDelete(TRUE); + BEGIN(Scan); + yylex(); + while (!g_condStack.isEmpty()) + { + CondCtx *ctx = g_condStack.pop(); + QCString sectionInfo = " "; + if (ctx->sectionId!=" ") sectionInfo.sprintf(" with label %s ",ctx->sectionId.data()); + warn(g_fileName,ctx->lineNr,"Conditional section%sdoes not have " + "a corresponding \\endcond command within this file.",sectionInfo.data()); + } + if (Debug::isFlagSet(Debug::CommentCnv)) + { + g_outBuf->at(g_outBuf->curPos())='\0'; + msg("-------------\n%s\n-------------\n",g_outBuf->data()); + } +} + + +//---------------------------------------------------------------------------- +#if !defined(YY_FLEX_SUBMINOR_VERSION) +extern "C" { // some bogus code to keep the compiler happy + void commentcnvYYdummy() { yy_flex_realloc(0,0); } +} +#endif + diff --git a/trunk/src/commentscan.h b/trunk/src/commentscan.h new file mode 100644 index 0000000..41cf766 --- /dev/null +++ b/trunk/src/commentscan.h @@ -0,0 +1,84 @@ +/****************************************************************************** + * + * Copyright (C) 1997-2012 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. + * + */ + +#ifndef COMMENTSCAN_H +#define COMMENTSCAN_H + +#include "qtbc.h" +#include "entry.h" + +class ParserInterface; + +/** @file + * @brief Interface for the comment block parser */ + +/** Invokes the comment block parser with the request to parse a + * single comment block. + * @param[in] parser The language parse that invoked this function. + * The comment block parse may invoke + * ParserInterface::parsePrototype() in order to parse + * the argument of a @@fn command. + * @param[in] curEntry The Entry to which the comment block belongs. + * Any information (like documentation) that is found in + * the comment block will be stored in this entry. + * @param[in] comment A string representing the actual comment block. + * Note that leading *'s are already stripped from the comment block. + * @param[in] fileName The name of the file in which the comment is found. + * Mainly used for producing warnings. + * @param[in,out] lineNr The line number at which the comment block was found. + * When the function returns it will be set to the last line parsed. + * @param[in] isBrief TRUE iff this comment block represents a brief description. + * @param[in] isJavaDocStyle TRUE iff this comment block is in "JavaDoc" style. + * This means that it starts as a brief description until the end of + * the sentences is found and then proceeds as a detailed description. + * @param[in] isInbody TRUE iff this comment block is located in the body of + * a function. + * @param[in,out] prot The protection level in which this comment block was + * found. Commands in the comment block may override this. + * @param[in,out] position The character position within \a comment where the + * comment block starts. Typically used in case the comment block + * contains multiple structural commands. + * @param[out] newEntryNeeded Boolean that is TRUE if the comment block parser + * finds that a the comment block finishes the entry and a new one + * needs to be started. + * @returns TRUE if the comment requires further processing. The + * parameter \a newEntryNeeded will typically be true in this case and + * \a position will indicate the offset inside the \a comment string + * where to proceed parsing. FALSE indicates no further processing is + * needed. + */ +bool parseCommentBlock(ParserInterface *parser, + Entry *curEntry, + const QCString &comment, + const QCString &fileName, + int &lineNr, + bool isBrief, + bool isJavaDocStyle, + bool isInbody, + Protection &prot, + int &position, + bool &newEntryNeeded + ); + +void groupEnterFile(const char *file,int line); +void groupLeaveFile(const char *file,int line); +void groupLeaveCompound(const char *file,int line,const char *name); +void groupEnterCompound(const char *file,int line,const char *name); +void openGroup(Entry *e,const char *file,int line); +void closeGroup(Entry *,const char *file,int line,bool foundInline=FALSE); +void initGroupInfo(Entry *e); + + +#endif diff --git a/trunk/src/commentscan.l b/trunk/src/commentscan.l new file mode 100644 index 0000000..56c0d08 --- /dev/null +++ b/trunk/src/commentscan.l @@ -0,0 +1,2906 @@ +/***************************************************************************** + * + * Copyright (C) 1997-2012 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. + * + */ + +%{ + +/* + * includes + */ +#include <stdio.h> +#include <stdlib.h> +#include <assert.h> +#include <ctype.h> + +#include "qtbc.h" +#include <qarray.h> +#include <qstack.h> +#include <qregexp.h> +#include <unistd.h> +#include <qfile.h> + +#include "scanner.h" +#include "entry.h" +#include "doxygen.h" +#include "message.h" +#include "config.h" +#include "util.h" +#include "index.h" +#include "defargs.h" +#include "language.h" +#include "outputlist.h" +#include "membergroup.h" +#include "reflist.h" +#include "debug.h" +#include "parserintf.h" +#include "cite.h" +#include "markdown.h" + +// forward declarations +static bool handleBrief(const QCString &); +static bool handleFn(const QCString &); +static bool handleDef(const QCString &); +static bool handleOverload(const QCString &); +static bool handleEnum(const QCString &); +static bool handleDefGroup(const QCString &); +static bool handleAddToGroup(const QCString &); +static bool handleWeakGroup(const QCString &); +static bool handleNamespace(const QCString &); +static bool handlePackage(const QCString &); +static bool handleClass(const QCString &); +static bool handleHeaderFile(const QCString &); +static bool handleProtocol(const QCString &); +static bool handleCategory(const QCString &); +static bool handleUnion(const QCString &); +static bool handleStruct(const QCString &); +static bool handleInterface(const QCString &); +static bool handleIdlException(const QCString &); +static bool handlePage(const QCString &); +static bool handleMainpage(const QCString &); +static bool handleFile(const QCString &); +static bool handleDir(const QCString &); +static bool handleExample(const QCString &); +static bool handleDetails(const QCString &); +static bool handleName(const QCString &); +static bool handleTodo(const QCString &); +static bool handleTest(const QCString &); +static bool handleBug(const QCString &); +static bool handleSubpage(const QCString &s); +static bool handleDeprecated(const QCString &); +static bool handleXRefItem(const QCString &); +static bool handleRelated(const QCString &); +static bool handleRelatedAlso(const QCString &); +static bool handleMemberOf(const QCString &); +static bool handleRefItem(const QCString &); +static bool handleSection(const QCString &); +static bool handleAnchor(const QCString &); +static bool handleCite(const QCString &); +static bool handleFormatBlock(const QCString &); +static bool handleAddIndex(const QCString &); +static bool handleIf(const QCString &); +static bool handleIfNot(const QCString &); +static bool handleElseIf(const QCString &); +static bool handleElse(const QCString &); +static bool handleEndIf(const QCString &); +static bool handleIngroup(const QCString &); +static bool handleNoSubGrouping(const QCString &); +static bool handleShowInitializer(const QCString &); +static bool handleHideInitializer(const QCString &); +static bool handleCallgraph(const QCString &); +static bool handleCallergraph(const QCString &); +static bool handleInternal(const QCString &); +static bool handleLineBr(const QCString &); +static bool handleStatic(const QCString &); +static bool handlePure(const QCString &); +static bool handlePrivate(const QCString &); +static bool handlePrivateSection(const QCString &); +static bool handleProtected(const QCString &); +static bool handleProtectedSection(const QCString &); +static bool handlePublic(const QCString &s); +static bool handlePublicSection(const QCString &s); +static bool handleToc(const QCString &s); +static bool handleInherit(const QCString &); +static bool handleExtends(const QCString &); +static bool handleCopyDoc(const QCString &); + +typedef bool (*DocCmdFunc)(const QCString &name); + +struct DocCmdMap +{ + const char *cmdName; + DocCmdFunc handler; + bool endsBrief; +}; + +// map of command to handler function +static DocCmdMap docCmdMap[] = +{ + // command name handler function ends brief description + { "brief", &handleBrief, FALSE }, + { "short", &handleBrief, FALSE }, + { "fn", &handleFn, FALSE }, + { "var", &handleFn, FALSE }, + { "typedef", &handleFn, FALSE }, + { "property", &handleFn, FALSE }, + { "def", &handleDef, FALSE }, + { "overload", &handleOverload, FALSE }, + { "enum", &handleEnum, FALSE }, + { "defgroup", &handleDefGroup, FALSE }, + { "addtogroup", &handleAddToGroup, FALSE }, + { "weakgroup", &handleWeakGroup, FALSE }, + { "namespace", &handleNamespace, FALSE }, + { "package", &handlePackage, FALSE }, + { "class", &handleClass, FALSE }, + { "headerfile", &handleHeaderFile, FALSE }, + { "protocol", &handleProtocol, FALSE }, + { "category", &handleCategory, FALSE }, + { "union", &handleUnion, FALSE }, + { "struct", &handleStruct, FALSE }, + { "interface", &handleInterface, FALSE }, + { "idlexcept", &handleIdlException, FALSE }, + { "page", &handlePage, FALSE }, + { "mainpage", &handleMainpage, FALSE }, + { "file", &handleFile, FALSE }, + { "dir", &handleDir, FALSE }, + { "example", &handleExample, FALSE }, + { "details", &handleDetails, TRUE }, + { "name", &handleName, FALSE }, + { "todo", &handleTodo, FALSE }, // end brief will be done differently + { "test", &handleTest, FALSE }, // end brief will be done differently + { "bug", &handleBug, FALSE }, // end brief will be done differently + { "deprecated", &handleDeprecated, FALSE }, // end brief will be done differently + { "xrefitem", &handleXRefItem, FALSE }, // end brief will be done differently + { "related", &handleRelated, TRUE }, + { "relates", &handleRelated, TRUE }, + { "relatedalso", &handleRelatedAlso, TRUE }, + { "relatesalso", &handleRelatedAlso, TRUE }, + { "refitem", &handleRefItem, TRUE }, + { "cite", &handleCite, TRUE }, + { "subpage", &handleSubpage, TRUE }, + { "section", &handleSection, TRUE }, + { "subsection", &handleSection, TRUE }, + { "subsubsection", &handleSection, TRUE }, + { "paragraph", &handleSection, TRUE }, + { "anchor", &handleAnchor, TRUE }, + { "verbatim", &handleFormatBlock, TRUE }, + { "latexonly", &handleFormatBlock, FALSE }, + { "htmlonly", &handleFormatBlock, FALSE }, + { "xmlonly", &handleFormatBlock, FALSE }, + { "rtfonly", &handleFormatBlock, FALSE }, + { "manonly", &handleFormatBlock, FALSE }, + { "dot", &handleFormatBlock, TRUE }, + { "msc", &handleFormatBlock, TRUE }, + { "code", &handleFormatBlock, TRUE }, + { "addindex", &handleAddIndex, FALSE }, + { "if", &handleIf, FALSE }, + { "ifnot", &handleIfNot, FALSE }, + { "elseif", &handleElseIf, FALSE }, + { "else", &handleElse, FALSE }, + { "endif", &handleEndIf, FALSE }, + { "ingroup", &handleIngroup, FALSE }, + { "nosubgrouping", &handleNoSubGrouping, FALSE }, + { "showinitializer", &handleShowInitializer, FALSE }, + { "hideinitializer", &handleHideInitializer, FALSE }, + { "callgraph", &handleCallgraph, FALSE }, + { "callergraph", &handleCallergraph, FALSE }, + { "internal", &handleInternal, TRUE }, + { "_linebr", &handleLineBr, FALSE }, + { "static", &handleStatic, FALSE }, + { "pure", &handlePure, FALSE }, + { "private", &handlePrivate, FALSE }, + { "privatesection", &handlePrivateSection, FALSE }, + { "protected", &handleProtected, FALSE }, + { "protectedsection",&handleProtectedSection, FALSE }, + { "public", &handlePublic, FALSE }, + { "publicsection", &handlePublicSection, FALSE }, + { "tableofcontents", &handleToc, FALSE }, + { "inherit", &handleInherit, TRUE }, + { "extends", &handleExtends, TRUE }, + { "implements", &handleExtends, TRUE }, + { "memberof", &handleMemberOf, TRUE }, + { "arg", 0, TRUE }, + { "attention", 0, TRUE }, + { "author", 0, TRUE }, + { "authors", 0, TRUE }, + { "copydoc", &handleCopyDoc, TRUE }, + { "copybrief", 0, FALSE }, + { "copydetails", 0, TRUE }, + { "date", 0, TRUE }, + { "dotfile", 0, TRUE }, + { "htmlinclude", 0, FALSE }, + { "image", 0, TRUE }, + { "include", 0, TRUE }, + { "includelineno", 0, TRUE }, + { "invariant", 0, TRUE }, + { "li", 0, TRUE }, + { "line", 0, TRUE }, + { "note", 0, TRUE }, + { "par", 0, TRUE }, + { "param", 0, TRUE }, + { "tparam", 0, TRUE }, + { "post", 0, TRUE }, + { "pre", 0, TRUE }, + { "remark", 0, TRUE }, + { "remarks", 0, TRUE }, + { "result", 0, TRUE }, + { "return", 0, TRUE }, + { "returns", 0, TRUE }, + { "retval", 0, TRUE }, + { "sa", 0, TRUE }, + { "see", 0, TRUE }, + { "since", 0, TRUE }, + { "throw", 0, TRUE }, + { "throws", 0, TRUE }, + { "until", 0, TRUE }, + { "verbinclude", 0, FALSE }, + { "version", 0, TRUE }, + { "warning", 0, TRUE }, + { 0, 0, FALSE } +}; + +/** @brief Command mapper. + * + * Maps a command name (as found in a comment block) onto a + * specific handler function. + */ +class DocCmdMapper +{ + public: + struct Cmd + { + DocCmdFunc func; + bool endsBrief; + }; + + /** maps a command name to a handler function */ + static Cmd *map(const char *name) + { + return instance()->find(name); + } + + /** release the singleton */ + static void freeInstance() + { + delete s_instance; s_instance=0; + } + + private: + static DocCmdMapper *instance() + { + if (s_instance==0) s_instance = new DocCmdMapper; + return s_instance; + } + + DocCmdMapper() : m_map(113) + { + m_map.setAutoDelete(TRUE); + DocCmdMap *p = docCmdMap; + while (p->cmdName) + { + if (m_map.find(p->cmdName)!=0) + { + printf("Error: DocCmdMapper: command %s already added\n",p->cmdName); + exit(1); + } + Cmd *cmd = new Cmd; + cmd->func = p->handler; + cmd->endsBrief = p->endsBrief; + m_map.insert(p->cmdName,cmd); + p++; + } + } + + Cmd *find(const char *name) + { + return m_map.find(name); + } + QDict<Cmd> m_map; + static DocCmdMapper *s_instance; +}; + +DocCmdMapper *DocCmdMapper::s_instance=0; + + +#define YY_NEVER_INTERACTIVE 1 + +enum XRefKind +{ + XRef_Item, + XRef_Todo, + XRef_Test, + XRef_Bug, + XRef_Deprecated, + XRef_None +}; + +enum OutputContext +{ + OutputDoc, + OutputBrief, + OutputXRef, + OutputInbody +}; + +enum GuardType +{ + Guard_If, + Guard_IfNot, + Guard_Skip +}; + +class GuardedSection +{ + public: + GuardedSection(bool enabled,bool parentVisible) + : m_enabled(enabled),m_parentVisible(parentVisible) {} + bool isEnabled() const { return m_enabled; } + bool parentVisible() const { return m_parentVisible; } + + private: + bool m_enabled; + bool m_parentVisible; +}; + +void openGroup(Entry *e,const char *file,int line); +void closeGroup(Entry *e,const char *file,int line,bool foundInline=FALSE); +void initGroupInfo(Entry *e); +static void groupAddDocs(Entry *e,const char *fileName); + +/* ----------------------------------------------------------------- + * + * statics + */ + +static ParserInterface *langParser; // the language parser that is calling us +static QCString inputString; // input string +static int inputPosition; // read pointer +static QCString yyFileName; // file name that is read from +static int yyLineNr; // line number in the input +static bool inBody; // was the comment found inside the body of a function? +static OutputContext inContext; // are we inside the brief, details or xref part +static bool briefEndsAtDot; // does the brief description stop at a dot? +static QCString formulaText; // Running text of a formula +static QCString formulaEnv; // environment name +static int formulaNewLines; // amount of new lines in the formula +static QCString *pOutputString; // pointer to string to which the output is appended. +static QCString outputXRef; // temp argument of todo/test/../xrefitem commands +static QCString blockName; // preformatted block name (e.g. verbatim, latexonly,...) +static XRefKind xrefKind; // kind of cross-reference command +static XRefKind newXRefKind; // +static GuardType guardType; // kind of guard for conditional section +static bool enabledSectionFound; +static QCString functionProto; // function prototype +static QStack<GuardedSection> guards; // tracks nested conditional sections (if,ifnot,..) +static Entry* current = 0 ; // working entry +//static Entry* current_root = 0 ; // parent of working entry + + +//static Entry* previous = 0 ; // TODO: remove need for this +static bool needNewEntry; + +static QCString g_sectionLabel; +static QCString g_sectionTitle; +static int g_sectionLevel; +static QCString xrefItemKey; +static QCString newXRefItemKey; +static QCString xrefItemTitle; +static QCString xrefListTitle; +static Protection protection; + +static bool xrefAppendFlag; +static bool inGroupParamFound; +static int braceCount; +static bool insidePre; +static bool parseMore; +static int g_condCount; + +static int g_commentCount; +static bool g_spaceBeforeCmd; +static bool g_spaceBeforeIf; +static QCString g_copyDocArg; + +//----------------------------------------------------------------------------- + +static QStack<Grouping> g_autoGroupStack; +static int g_memberGroupId = DOX_NOGROUP; +static QCString g_memberGroupHeader; +static QCString g_memberGroupDocs; +static QCString g_memberGroupRelates; +static QCString g_compoundName; + +//----------------------------------------------------------------------------- + +static void initParser() +{ + g_sectionLabel.resize(0); + g_sectionTitle.resize(0); + g_memberGroupHeader.resize(0); +} + +//----------------------------------------------------------------------------- + +static bool getDocSectionName(int s) +{ + switch(s) + { + case Entry::CLASSDOC_SEC: + case Entry::STRUCTDOC_SEC: + case Entry::UNIONDOC_SEC: + case Entry::EXCEPTIONDOC_SEC: + case Entry::NAMESPACEDOC_SEC: + case Entry::PROTOCOLDOC_SEC: + case Entry::CATEGORYDOC_SEC: + case Entry::ENUMDOC_SEC: + case Entry::PAGEDOC_SEC: + case Entry::VARIABLEDOC_SEC: + case Entry::MEMBERDOC_SEC: + case Entry::OVERLOADDOC_SEC: + case Entry::FILEDOC_SEC: + case Entry::DEFINEDOC_SEC: + case Entry::GROUPDOC_SEC: + case Entry::MAINPAGEDOC_SEC: + case Entry::PACKAGEDOC_SEC: + case Entry::DIRDOC_SEC: + case Entry::EXAMPLE_SEC: + case Entry::MEMBERGRP_SEC: + return TRUE; + default: + return FALSE; + } +} + +//----------------------------------------------------------------------------- + +static bool makeStructuralIndicator(Entry::Sections s) +{ + //printf("current->section=%x\n",current->section); + if (getDocSectionName(current->section)) + { + return TRUE; + } + else + { + needNewEntry = TRUE; + current->section = s; + current->fileName = yyFileName; + current->startLine = yyLineNr; + return FALSE; + } +} + +static void lineCount() +{ + for( const char* c = yytext ; *c ; ++c ) + yyLineNr += (*c == '\n') ; +} + + +static QCString stripQuotes(const char *s) +{ + QCString name; + if (s==0 || *s==0) return name; + name=s; + if (name.at(0)=='"' && name.at(name.length()-1)=='"') + { + name=name.mid(1,name.length()-2); + } + return name; +} + +//----------------------------------------------------------------- + +static void addXRefItem(const char *listName,const char *itemTitle, + const char *listTitle,bool append) +{ + Entry *docEntry = current; // inBody && previous ? previous : current; + if (listName==0) return; + //printf("addXRefItem(%s,%s,%s,%d)\n",listName,itemTitle,listTitle,append); + + ListItemInfo *lii=0; + RefList *refList = Doxygen::xrefLists->find(listName); + if (refList==0) // new list + { + refList = new RefList(listName,listTitle,itemTitle); + Doxygen::xrefLists->insert(listName,refList); + //printf("new list!\n"); + } + if (docEntry->sli) + { + QListIterator<ListItemInfo> slii(*docEntry->sli); + for (slii.toFirst();(lii=slii.current());++slii) + { + if (strcmp(lii->type,listName)==0) + { + //printf("found %s lii->type=%s\n",listName,lii->type); + break; + } + } + } + if (lii && append) // already found item of same type just before this one + { + //printf("listName=%s item id = %d existing\n",listName,lii->itemId); + RefItem *item = refList->getRefItem(lii->itemId); + ASSERT(item!=0); + item->text += " <p>"; + item->text += outputXRef; + //printf("%s: text +=%s\n",listName,item->text.data()); + } + else // new item + { + int itemId = refList->addRefItem(); + //printf("listName=%s item id = %d new current=%p\n",listName,itemId,current); + + // if we have already an item from the same list type (e.g. a second @todo) + // in the same Entry (i.e. lii!=0) then we reuse its link anchor. + char anchorLabel[1024]; + //sprintf(anchorLabel,"_%s%06d",listName,lii ? lii->itemId : itemId); + sprintf(anchorLabel,"_%s%06d",listName,itemId); + RefItem *item = refList->getRefItem(itemId); + ASSERT(item!=0); + item->text = outputXRef; + item->listAnchor = anchorLabel; + docEntry->addSpecialListItem(listName,itemId); + QCString cmdString; + cmdString.sprintf("\\xrefitem %s %d.",listName,itemId); + if (inBody) + { + docEntry->inbodyDocs += cmdString; + } + else + { + docEntry->doc += cmdString; + } + SectionInfo *si=new SectionInfo(listName,anchorLabel, + g_sectionTitle,SectionInfo::Anchor, + g_sectionLevel); + Doxygen::sectionDict.append(anchorLabel,si); + docEntry->anchors->append(si); + } + outputXRef.resize(0); +} + +//----------------------------------------------------------------------------- + +// Adds a formula text to the list/dictionary of formulas if it was +// not already added. Returns the label of the formula. +static QCString addFormula() +{ + QCString formLabel; + QCString fText=formulaText.simplifyWhiteSpace(); + Formula *f=0; + if ((f=Doxygen::formulaDict[fText])==0) + { + f = new Formula(fText); + Doxygen::formulaList.append(f); + Doxygen::formulaDict.insert(fText,f); + formLabel.sprintf("\\form#%d",f->getId()); + Doxygen::formulaNameDict.insert(formLabel,f); + } + else + { + formLabel.sprintf("\\form#%d",f->getId()); + } + int i; + for (i=0;i<formulaNewLines;i++) formLabel+="@_fakenl"; // add fake newlines to + // keep the warnings + // correctly aligned. + return formLabel; +} + +//----------------------------------------------------------------------------- + +static void checkFormula(); +//----------------------------------------------------------------------------- + +static SectionInfo::SectionType sectionLevelToType(int level) +{ + if (level>=0 && level<5) return (SectionInfo::SectionType)level; + return SectionInfo::Anchor; +} + +static void addSection() +{ + // create a new section element + g_sectionTitle+=yytext; + g_sectionTitle=g_sectionTitle.stripWhiteSpace(); + SectionInfo *si = new SectionInfo(yyFileName,g_sectionLabel, + g_sectionTitle,sectionLevelToType(g_sectionLevel),g_sectionLevel); + + // add section to this entry + current->anchors->append(si); + + // add section to the global dictionary + Doxygen::sectionDict.append(g_sectionLabel,si); + +} + +//----------------------------------------------------------------------------- + +static void addCite() +{ + Doxygen::citeDict->insert(yytext); +} + +//----------------------------------------------------------------------------- + +// strip trailing whitespace (excluding newlines) from string s +static void stripTrailingWhiteSpace(QCString &s) +{ + uint len = s.length(); + int i = (int)len-1; + char c; + while (i>=0 && ((c = s.at(i))==' ' || c=='\t' || c=='\r')) i--; + if (i!=(int)len-1) + { + s.resize(i+2); // string upto and including char at pos i and \0 terminator + } +} + +// selects the output to write to +static inline void setOutput(OutputContext ctx) +{ + bool xrefAppendToPrev = xrefAppendFlag; + // determine append flag for the next item (i.e. the end of this item) + xrefAppendFlag = !inBody && + inContext==OutputXRef && ctx==OutputXRef && // two consecutive xref items + newXRefKind==xrefKind && // of the same kind + (xrefKind!=XRef_Item || + newXRefItemKey==xrefItemKey); // with the same key if \xrefitem + //printf("%d && %d && %d && (%d || %d)\n", + // inContext==OutputXRef, + // ctx==OutputXRef, + // newXRefKind==xrefKind, + // xrefKind!=XRef_Item, + // newXRefItemKey==xrefItemKey); + + //printf("refKind=%d newXRefKind=%d xrefAppendToPrev=%d xrefAppendFlag=%d\n", + // xrefKind,newXRefKind,xrefAppendToPrev,xrefAppendFlag); + + //printf("setOutput(inContext=%d ctx=%d)\n",inContext,ctx); + if (inContext==OutputXRef) // end of XRef section => add the item + { + // See if we can append this new xref item to the previous one. + // We know this at the start of the next item of the same + // type and need to remember this until the end of that item. + switch(xrefKind) + { + case XRef_Todo: + addXRefItem("todo", + theTranslator->trTodo(), + theTranslator->trTodoList(), + xrefAppendToPrev + ); + break; + case XRef_Test: + addXRefItem("test", + theTranslator->trTest(), + theTranslator->trTestList(), + xrefAppendToPrev + ); + break; + case XRef_Bug: + addXRefItem("bug", + theTranslator->trBug(), + theTranslator->trBugList(), + xrefAppendToPrev + ); + break; + case XRef_Deprecated: + addXRefItem("deprecated", + theTranslator->trDeprecated(), + theTranslator->trDeprecatedList(), + xrefAppendToPrev + ); + break; + case XRef_Item: // user defined list + addXRefItem(xrefItemKey, + xrefItemTitle, + xrefListTitle, + xrefAppendToPrev + ); + break; + case XRef_None: + ASSERT(0); + break; + } + } + xrefItemKey = newXRefItemKey; + + int oldContext = inContext; + inContext = ctx; + if (inContext!=OutputXRef && inBody) inContext=OutputInbody; + switch(inContext) + { + case OutputDoc: + if (oldContext!=inContext) + { + stripTrailingWhiteSpace(current->doc); + if (current->docFile.isEmpty()) + { + current->docFile = yyFileName; + current->docLine = yyLineNr; + } + } + pOutputString = ¤t->doc; + break; + case OutputBrief: + if (oldContext!=inContext) + { + if (current->briefFile.isEmpty()) + { + current->briefFile = yyFileName; + current->briefLine = yyLineNr; + } + } + if (current->brief.stripWhiteSpace().isEmpty()) // we only want one brief + // description even if multiple + // are given... + { + pOutputString = ¤t->brief; + } + else + { + pOutputString = ¤t->doc; + inContext = OutputDoc; // need to switch to detailed docs, see bug 631380 + } + break; + case OutputXRef: + pOutputString = &outputXRef; + // first item found, so can't append to previous + //xrefAppendFlag = FALSE; + break; + case OutputInbody: + pOutputString = ¤t->inbodyDocs; + break; + } +} + +// add a string to the output +static inline void addOutput(const char *s) +{ + //printf("addOutput(%s)\n",s); + *pOutputString+=s; +} + +// add a character to the output +static inline void addOutput(char c) +{ + *pOutputString+=c; +} + +static void endBrief(bool addToOutput=TRUE) +{ + if (!current->brief.stripWhiteSpace().isEmpty()) + { // only go to the detailed description if we have + // found some brief description and not just whitespace + briefEndsAtDot=FALSE; + setOutput(OutputDoc); + if (addToOutput) addOutput(yytext); + } +} + +/* ----------------------------------------------------------------- */ +#undef YY_INPUT +#define YY_INPUT(buf,result,max_size) result=yyread(buf,max_size); + +static int prevPosition=0; + +static int yyread(char *buf,int max_size) +{ + prevPosition=inputPosition; + int c=0; + while( c < max_size && inputString[inputPosition] ) + { + *buf = inputString[inputPosition++] ; + //printf("%d (%c)\n",*buf,*buf); + c++; buf++; + } + return c; +} + +%} + + /* start command character */ +CMD ("\\"|"@") +DCMD1 ("arg"|"attention"|"author"|"cite"|"code") +DCMD2 ("date"|"dot"|"msc"|"dotfile"|"example") +DCMD3 ("htmlinclude"|"htmlonly"|"image"|"include") +DCMD4 ("includelineno"|"internal"|"invariant") +DCMD5 ("latexonly"|"li"|"line"|"manonly"|"name") +DCMD6 ("note"|"par"|"paragraph"|"param"|"post") +DCMD7 ("pre"|"remarks"|(("relate"[sd])("also")?)) +DCMD8 ("remarks"|("return"[s]?)|"retval"|"sa"|"section") +DCMD9 ("see"|"since"|"subsection"|"subsubsection") +DCMD10 ("throw"|"until"|"verbatim") +DCMD11 ("verbinclude"|"version"|"warning") +DETAILEDCMD {CMD}({DCMD1}|{DCMD2}|{DCMD3}|{DCMD4}|{DCMD5}|{DCMD6}|{DCMD7}|{DCMD8}|{DCMD9}|{DCMD10}|{DCMD11}) +XREFCMD {CMD}("bug"|"deprecated"|"test"|"todo"|"xrefitem") +PRE [pP][rR][eE] +TABLE [tT][aA][bB][lL][eE] +P [pP] +UL [uU][lL] +OL [oO][lL] +DL [dD][lL] +IMG [iI][mM][gG] +HR [hH][rR] +PARA [pP][aA][rR][aA] +DETAILEDHTML {PRE}|{UL}|{TABLE}|{OL}|{DL}|{P}|[Hh][1-6]|{IMG}|{HR}|{PARA} +BN [ \t\n\r] +BL [ \t\r]*"\n" +B [ \t] +BS ^(({B}*"//")?)(({B}*"*"+)?){B}* +ATTR ({B}+[^>\n]*)? +DOCNL "\n"|"\\_linebr" +LC "\\"{B}*"\n" +NW [^a-z_A-Z0-9] +FILESCHAR [a-z_A-Z0-9\x80-\xFF\\:\\\/\-\+] +FILEECHAR [a-z_A-Z0-9\x80-\xFF\-\+] +FILE ({FILESCHAR}*{FILEECHAR}+("."{FILESCHAR}*{FILEECHAR}+)*)|("\""[^\n\"]*"\"") +ID "$"?[a-z_A-Z\x80-\xFF][a-z_A-Z0-9\x80-\xFF]* +LABELID [a-z_A-Z\x80-\xFF][a-z_A-Z0-9\x80-\xFF\-]* +CITEID [a-z_A-Z\x80-\xFF][a-z_A-Z0-9\x80-\xFF\-:/]* +SCOPEID {ID}({ID}*{BN}*"::"{BN}*)*({ID}?) +SCOPENAME "$"?(({ID}?{BN}*("::"|"."){BN}*)*)((~{BN}*)?{ID}) +MAILADR [a-z_A-Z0-9.+\-]+"@"[a-z_A-Z0-9\-]+("."[a-z_A-Z0-9\-]+)+[a-z_A-Z0-9\-]+ +RCSTAG "$"{ID}":"[^\n$]+"$" + +%option noyywrap + + /* comment parsing states. */ +%x Comment +%x PageDocArg1 +%x PageDocArg2 +%x RelatesParam1 +%x ClassDocArg1 +%x ClassDocArg2 +%x ClassDocArg3 +%x CategoryDocArg1 +%x XRefItemParam1 +%x XRefItemParam2 +%x XRefItemParam3 +%x FileDocArg1 +%x EnumDocArg1 +%x NameSpaceDocArg1 +%x PackageDocArg1 +%x GroupDocArg1 +%x GroupDocArg2 +%x SectionLabel +%x SectionTitle +%x SubpageLabel +%x SubpageTitle +%x FormatBlock +%x LineParam +%x GuardParam +%x GuardParamEnd +%x SkipGuardedSection +%x SkipInternal +%x NameParam +%x InGroupParam +%x FnParam +%x OverloadParam +%x InheritParam +%x ExtendsParam +%x ReadFormulaShort +%x ReadFormulaLong +%x AnchorLabel +%x HtmlComment +%x SkipLang +%x CiteLabel +%x CopyDoc + +%% + + /* What can happen in while parsing a comment block: + * commands (e.g. @page, or \page) + * escaped commands (e.g. @@page or \\page). + * formulas (e.g. \f$ \f[ \f{..) + * directories (e.g. \doxygen\src\) + * autolist end. (e.g. a dot on an otherwise empty line) + * newlines. + * end of brief description due to blank line. + * end of brief description due to some command (@command, or <command>). + * words and whitespace and other characters (#,?!, etc). + * grouping commands (e.g. @{ and @}) + * language switch (e.g. \~english or \~). + * mail adress (e.g. dimitri@stack.nl). + * quoted text, such as "foo@bar" + * XML commands, <summary></summary><remarks></remarks> + */ + +<Comment>{CMD}{CMD}[a-z_A-Z]+{B}* { // escaped command + addOutput(yytext); + } +<Comment>{CMD}{CMD}"~"[a-z_A-Z]* { // escaped command + addOutput(yytext); + } +<Comment>{MAILADR} { // mail adress + addOutput(yytext); + } +<Comment>"\""[^"\n]*"\"" { // quoted text + addOutput(yytext); + } +<Comment>("\\"[a-z_A-Z]+)+"\\" { // directory (or chain of commands!) + addOutput(yytext); + } +<Comment>{XREFCMD}/[^a-z_A-Z]* { // xref command + if (inContext!=OutputXRef) + { + briefEndsAtDot=FALSE; + setOutput(OutputDoc); + } + // continue with the same input + REJECT; + } + /* +<Comment>{DETAILEDCMD}/[^a-z_A-Z]* { // command that can end a brief description + briefEndsAtDot=FALSE; + setOutput(OutputDoc); + // continue with the same input + REJECT; + } + */ +<Comment>"<"{DETAILEDHTML}{ATTR}">" { // HTML command that ends a brief description + setOutput(OutputDoc); + // continue with the same input + REJECT; + } +<Comment>"<summary>" { // start of a .NET XML style brief description + setOutput(OutputBrief); + } +<Comment>"<remarks>"|"</summary>" { // start of a .NET XML style detailed description + setOutput(OutputDoc); + } +<Comment>"</remarks>" { // end of a brief or detailed description + } +<Comment>{RCSTAG} { // RCS tag which end a brief description + setOutput(OutputDoc); + REJECT; + } +<Comment>"<!--" { + BEGIN(HtmlComment); + } +<Comment>{B}*{CMD}"endinternal"{B}* { + warn(yyFileName,yyLineNr, + "warning: found \\endinternal without matching \\internal" + ); + } +<Comment>{B}*{CMD}[a-z_A-Z]+{B}* { // potentially interesting command + // the {B}* in the front was added for bug620924 + QCString cmdName = QCString(yytext).stripWhiteSpace().data()+1; + DocCmdMapper::Cmd *cmdPtr = DocCmdMapper::map(cmdName); + g_spaceBeforeCmd = yytext[0]==' ' || yytext[0]=='\t'; + if (cmdPtr) // special action is required + { + if (cmdPtr->endsBrief) + { + briefEndsAtDot=FALSE; + // this command forces the end of brief description + setOutput(OutputDoc); + } + if (cmdPtr->func && cmdPtr->func(cmdName)) + { + // implicit split of the comment block into two + // entries. Restart the next block at the start + // of this command. + parseMore=TRUE; + + // yuk, this is probably not very portable across lex implementations, + // but we need to know the position in the input buffer where this + // rule matched. + // for flex 2.5.33+ we should use YY_CURRENT_BUFFER_LVALUE +#if YY_FLEX_MINOR_VERSION>=5 && YY_FLEX_SUBMINOR_VERSION>=33 + inputPosition=prevPosition + yy_bp - YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; +#else + inputPosition=prevPosition + yy_bp - yy_current_buffer->yy_ch_buf; +#endif + yyterminate(); + } + else if (cmdPtr->func==0) + { + // command without handler, to be processed + // later by parsedoc.cpp + addOutput(yytext); + } + } + else // command not relevant + { + addOutput(yytext); + } + } +<Comment>{B}*("\\\\"|"@@")"f"[$\[{] { // escaped formula command + addOutput(yytext); + } +<Comment>{B}*{CMD}"~"[a-z_A-Z]* { // language switch command + QCString langId = QString(yytext).stripWhiteSpace().data()+2; + if (!langId.isEmpty() && + stricmp(Config_getEnum("OUTPUT_LANGUAGE"),langId)!=0) + { // enable language specific section + BEGIN(SkipLang); + } + } +<Comment>{B}*{CMD}"f{"[^}\n]+"}"("{"?) { // start of a formula with custom environment + formulaText="\\begin"; + formulaEnv=QString(yytext).stripWhiteSpace().data()+2; + if (formulaEnv.at(formulaEnv.length()-1)=='{') + { + // remove trailing open brace + formulaEnv=formulaEnv.left(formulaEnv.length()-1); + } + formulaText+=formulaEnv; + formulaNewLines=0; + BEGIN(ReadFormulaLong); + } +<Comment>{B}*{CMD}"f$" { // start of a inline formula + formulaText="$"; + formulaNewLines=0; + BEGIN(ReadFormulaShort); + } +<Comment>{B}*{CMD}"f[" { // start of a block formula + formulaText="\\["; + formulaNewLines=0; + BEGIN(ReadFormulaLong); + } +<Comment>{B}*{CMD}"{" { // begin of a group + //langParser->handleGroupStartCommand(g_memberGroupHeader); + openGroup(current,yyFileName,yyLineNr); + } +<Comment>{B}*{CMD}"}" { // end of a group + //langParser->handleGroupEndCommand(); + closeGroup(current,yyFileName,yyLineNr,TRUE); + g_memberGroupHeader.resize(0); + parseMore=TRUE; + needNewEntry = TRUE; +#if YY_FLEX_MINOR_VERSION>=5 && YY_FLEX_SUBMINOR_VERSION>=33 + inputPosition=prevPosition + yy_bp - YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + strlen(yytext); +#else + inputPosition=prevPosition + yy_bp - yy_current_buffer->yy_ch_buf + strlen(yytext); +#endif + yyterminate(); + } +<Comment>{B}*{CMD}[$@\\&~<>#%] { // escaped character + addOutput(yytext); + } +<Comment>[a-z_A-Z]+ { // normal word + addOutput(yytext); + } +<Comment>^{B}*"."{B}*/\n { // explicit end autolist: e.g " ." + addOutput(yytext); + } +<Comment>^{B}*[1-9][0-9]*"."{B}+ | +<Comment>^{B}*[*+]{B}+ { // start of autolist + if (!Doxygen::markdownSupport) + { + REJECT; + } + else + { + if (inContext!=OutputXRef) + { + briefEndsAtDot=FALSE; + setOutput(OutputDoc); + } + addOutput(yytext); + } + } +<Comment>^{B}*"-"{B}+ { // start of autolist + if (inContext!=OutputXRef) + { + briefEndsAtDot=FALSE; + setOutput(OutputDoc); + } + addOutput(yytext); + } +<Comment>("."+)[a-z_A-Z0-9\)] { // . at start or in the middle of a word, or ellipsis + addOutput(yytext); + } +<Comment>".\\"[ \t] { // . with escaped space. + addOutput(yytext[0]); + addOutput(yytext[2]); + } +<Comment>".," { // . with comma such as "e.g.," + addOutput(yytext); + } +<Comment>"...\\"[ \t] { // ellipsis with escaped space. + addOutput("... "); + } +<Comment>".."[\.]?/[^ \t\n] { // internal ellipsis + addOutput(yytext); + } +<Comment>(\n|\\_linebr)({B}*(\n|\\_linebr))+ { // at least one blank line (or blank line command) + if (inContext==OutputXRef) + { + // see bug 613024, we need to put the newlines after ending the XRef section. + setOutput(OutputDoc); + addOutput("\n\n"); + } + else if (inContext!=OutputBrief) + { + addOutput("\n\n"); + setOutput(OutputDoc); + } + else // inContext==OutputBrief + { // only go to the detailed description if we have + // found some brief description and not just whitespace + endBrief(FALSE); + } + lineCount(); + } +<Comment>"." { // potential end of a JavaDoc style comment + addOutput(*yytext); + if (briefEndsAtDot) + { + setOutput(OutputDoc); + briefEndsAtDot=FALSE; + } + } +<Comment>\n { // newline + addOutput(*yytext); + yyLineNr++; + } +<Comment>. { // catch-all for anything else + addOutput(*yytext); + } + + + /* -------------- Rules for handling HTML comments ----------- */ + +<HtmlComment>"--"[!]?">"{B}* { BEGIN( Comment ); } +<HtmlComment>{DOCNL} { + if (*yytext=='\n') yyLineNr++; + } +<HtmlComment>[^\\\n\-]+ { // ignore unimportant characters + } +<HtmlComment>. { // ignore every else + } + + /* -------------- Rules for handling formulas ---------------- */ + +<ReadFormulaShort>{CMD}"f$" { // end of inline formula + formulaText+="$"; + addOutput(" "+addFormula()); + BEGIN(Comment); + } +<ReadFormulaLong>{CMD}"f]" { // end of block formula + formulaText+="\\]"; + addOutput(" "+addFormula()); + BEGIN(Comment); + } +<ReadFormulaLong>{CMD}"f}" { // end of custom env formula + formulaText+="\\end"; + formulaText+=formulaEnv; + addOutput(" "+addFormula()); + BEGIN(Comment); + } +<ReadFormulaLong,ReadFormulaShort>[^\\@\n]+ { // any non-special character + formulaText+=yytext; + } +<ReadFormulaLong,ReadFormulaShort>\n { // new line + formulaNewLines++; + formulaText+=*yytext; + yyLineNr++; + } +<ReadFormulaLong,ReadFormulaShort>. { // any othe character + formulaText+=*yytext; + } + + /* ------------ handle argument of enum command --------------- */ + +<EnumDocArg1>{SCOPEID} { // handle argument + current->name = yytext; + BEGIN( Comment ); + } +<EnumDocArg1>{LC} { // line continuation + yyLineNr++; + addOutput('\n'); + } +<EnumDocArg1>{DOCNL} { // missing argument + warn(yyFileName,yyLineNr, + "warning: missing argument after \\enum." + ); + addOutput('\n'); + if (*yytext=='\n') yyLineNr++; + BEGIN( Comment ); + } +<EnumDocArg1>. { // ignore other stuff + } + + /* ------------ handle argument of namespace command --------------- */ + +<NameSpaceDocArg1>{SCOPENAME} { // handle argument + current->name = substitute(yytext,".","::"); + BEGIN( Comment ); + } +<NameSpaceDocArg1>{LC} { // line continuation + yyLineNr++; + addOutput('\n'); + } +<NameSpaceDocArg1>{DOCNL} { // missing argument + warn(yyFileName,yyLineNr, + "warning: missing argument after " + "\\namespace." + ); + addOutput('\n'); + if (*yytext=='\n') yyLineNr++; + BEGIN( Comment ); + } +<NameSpaceDocArg1>. { // ignore other stuff + } + + /* ------------ handle argument of package command --------------- */ + +<PackageDocArg1>{ID}("."{ID})* { // handle argument + current->name = yytext; + BEGIN( Comment ); + } +<PackageDocArg1>{LC} { // line continuation + yyLineNr++; + addOutput('\n'); + } +<PackageDocArg1>{DOCNL} { // missing argument + warn(yyFileName,yyLineNr, + "warning: missing argument after " + "\\package." + ); + addOutput('\n'); + if (*yytext=='\n') yyLineNr++; + BEGIN( Comment ); + } +<PackageDocArg1>. { // ignore other stuff + } + + /* ------ handle argument of class/struct/union command --------------- */ + +<ClassDocArg1>{SCOPENAME} { // first argument + current->name = substitute(yytext,".","::"); + if (current->section==Entry::PROTOCOLDOC_SEC) + { + current->name+="-p"; + } + // prepend outer scope name + BEGIN( ClassDocArg2 ); + } +<CategoryDocArg1>{SCOPENAME}{B}*"("[^\)]+")" { + current->name = substitute(yytext,".","::"); + BEGIN( ClassDocArg2 ); + } +<ClassDocArg1,CategoryDocArg1>{LC} { // line continuation + yyLineNr++; + addOutput('\n'); + } +<ClassDocArg1,CategoryDocArg1>{DOCNL} { + warn(yyFileName,yyLineNr, + "warning: missing argument after " + "\\%s.",YY_START==ClassDocArg1?"class":"category" + ); + addOutput('\n'); + if (*yytext=='\n') yyLineNr++; + BEGIN( Comment ); + } +<ClassDocArg1,CategoryDocArg1>. { // ignore other stuff + } + +<ClassDocArg2>{FILE}|"<>" { // second argument; include file + current->includeFile = yytext; + BEGIN( ClassDocArg3 ); + } +<ClassDocArg2>{LC} { // line continuation + yyLineNr++; + addOutput('\n'); + } +<ClassDocArg2>{DOCNL} { + addOutput('\n'); + if (*yytext=='\n') yyLineNr++; + BEGIN( Comment ); + } +<ClassDocArg2>. { // ignore other stuff + } + +<ClassDocArg3>[<]?{FILE}?[>]? { // third argument; include file name + current->includeName = yytext; + BEGIN( Comment ); + } +<ClassDocArg3>{LC} { // line continuation + yyLineNr++; + addOutput('\n'); + } +<ClassDocArg3>{DOCNL} { + if (*yytext=='\n') yyLineNr++; + BEGIN( Comment ); + } +<ClassDocArg3>. { // ignore other stuff + } + + /* --------- handle arguments of {def,add,weak}group commands --------- */ + +<GroupDocArg1>{LABELID}(".html"?) { // group name + current->name = yytext; + //lastDefGroup.groupname = yytext; + //lastDefGroup.pri = current->groupingPri(); + // the .html stuff is for Qt compatibility + if (current->name.right(5)==".html") + { + current->name=current->name.left(current->name.length()-5); + } + current->type.resize(0); + BEGIN(GroupDocArg2); + } +<GroupDocArg1>"\\"{B}*"\n" { // line continuation + yyLineNr++; + addOutput('\n'); + } +<GroupDocArg1>{DOCNL} { // missing argument! + warn(yyFileName,yyLineNr, + "warning: missing group name after %s", + current->groupDocCmd() + ); + addOutput('\n'); + if (*yytext=='\n') yyLineNr++; + BEGIN( Comment ); + } +<GroupDocArg2>"\\"{B}*"\n" { // line continuation + yyLineNr++; + addOutput('\n'); + } +<GroupDocArg2>[^\n\\\*]+ { // title (stored in type) + current->type += yytext; + current->type = current->type.stripWhiteSpace(); + } +<GroupDocArg2>{DOCNL} { + if ( current->groupDocType==Entry::GROUPDOC_NORMAL && + current->type.isEmpty() + ) // defgroup requires second argument + { + warn(yyFileName,yyLineNr, + "warning: missing title after " + "\\defgroup %s", current->name.data() + ); + } + if (*yytext=='\n') yyLineNr++; + addOutput('\n'); + BEGIN( Comment ); + } + + /* --------- handle arguments of page/mainpage command ------------------- */ + +<PageDocArg1>{FILE} { // first argument; page name + current->name = stripQuotes(yytext); + BEGIN( PageDocArg2 ); + } +<PageDocArg1>{LC} { yyLineNr++; + addOutput('\n'); + } +<PageDocArg1>{DOCNL} { + warn(yyFileName,yyLineNr, + "warning: missing argument after " + "\\page." + ); + if (*yytext=='\n') yyLineNr++; + addOutput('\n'); + BEGIN( Comment ); + } +<PageDocArg1>. { // ignore other stuff + } +<PageDocArg2>.*"\n" { // second argument; page title + yyLineNr++; + current->args = yytext; + addOutput('\n'); + BEGIN( Comment ); + } + + /* --------- handle arguments of the file/dir/example command ------------ */ + +<FileDocArg1>{DOCNL} { // no file name specfied + if (*yytext=='\n') yyLineNr++; + addOutput('\n'); + BEGIN( Comment ); + } +<FileDocArg1>{FILE} { // first argument; name + current->name = stripQuotes(yytext); + BEGIN( Comment ); + } +<FileDocArg1>{LC} { yyLineNr++; + addOutput('\n'); + } +<FileDocArg1>. { // ignore other stuff + } + + /* --------- handle arguments of the xrefitem command ------------ */ + +<XRefItemParam1>{LABELID} { // first argument + newXRefItemKey=yytext; + setOutput(OutputXRef); + BEGIN(XRefItemParam2); + } +<XRefItemParam1>{LC} { // line continuation + yyLineNr++; + addOutput('\n'); + } +<XRefItemParam1>{DOCNL} { // missing arguments + warn(yyFileName,yyLineNr, + "warning: Missing first argument of \\xrefitem" + ); + if (*yytext=='\n') yyLineNr++; + addOutput('\n'); + inContext = OutputDoc; + BEGIN( Comment ); + } +<XRefItemParam1>. { // ignore other stuff + } + +<XRefItemParam2>"\""[^\n\"]*"\"" { // second argument + xrefItemTitle = stripQuotes(yytext); + BEGIN(XRefItemParam3); + } +<XRefItemParam2>{LC} { // line continuation + yyLineNr++; + addOutput('\n'); + } +<XRefItemParam2>{DOCNL} { // missing argument + warn(yyFileName,yyLineNr, + "warning: Missing second argument of \\xrefitem" + ); + if (*yytext=='\n') yyLineNr++; + addOutput('\n'); + inContext = OutputDoc; + BEGIN( Comment ); + } +<XRefItemParam2>. { // ignore other stuff + } + +<XRefItemParam3>"\""[^\n\"]*"\"" { // third argument + xrefListTitle = stripQuotes(yytext); + xrefKind = XRef_Item; + BEGIN( Comment ); + } +<XRefItemParam2,XRefItemParam3>{LC} { // line continuation + yyLineNr++; + addOutput('\n'); + } +<XRefItemParam3>{DOCNL} { // missing argument + warn(yyFileName,yyLineNr, + "warning: Missing third argument of \\xrefitem" + ); + if (*yytext=='\n') yyLineNr++; + addOutput('\n'); + inContext = OutputDoc; + BEGIN( Comment ); + } +<XRefItemParam3>. { // ignore other stuff + } + + + /* ----- handle arguments of the relates(also)/memberof command ------- */ + +<RelatesParam1>({ID}("::"|"."))*{ID} { // argument + current->relates = yytext; + //if (current->mGrpId!=DOX_NOGROUP) + //{ + // memberGroupRelates = yytext; + //} + BEGIN( Comment ); + } +<RelatesParam1>{LC} { // line continuation + yyLineNr++; + addOutput('\n'); + } +<RelatesParam1>{DOCNL} { // missing argument + warn(yyFileName,yyLineNr, + "warning: Missing argument of \\relates or \\memberof command" + ); + if (*yytext=='\n') yyLineNr++; + addOutput('\n'); + BEGIN( Comment ); + } +<RelatesParam1>. { // ignore other stuff + } + + + /* ----- handle arguments of the relates(also)/addindex commands ----- */ + +<LineParam>{DOCNL} { // end of argument + if (*yytext=='\n') yyLineNr++; + addOutput('\n'); + BEGIN( Comment ); + } +<LineParam>{LC} { // line continuation + yyLineNr++; + addOutput('\n'); + } +<LineParam>. { // ignore other stuff + addOutput(*yytext); + } + + /* ----- handle arguments of the section/subsection/.. commands ------- */ + +<SectionLabel>{LABELID} { // first argyment + g_sectionLabel=yytext; + addOutput(yytext); + g_sectionTitle.resize(0); + BEGIN(SectionTitle); + } +<SectionLabel>{DOCNL} { // missing argument + warn(yyFileName,yyLineNr, + "warning: \\section command has no label" + ); + if (*yytext=='\n') yyLineNr++; + addOutput('\n'); + BEGIN( Comment ); + } +<SectionLabel>. { // invalid character for section label + warn(yyFileName,yyLineNr, + "warning: Invalid or missing section label" + ); + BEGIN(Comment); + } +<SectionTitle>[^\n@\\*]*/"\n" { // end of section title + addSection(); + addOutput(yytext); + BEGIN( Comment ); + } +<SectionTitle>[^\n@\\]*/"\\_linebr" { // end of section title + addSection(); + addOutput(yytext); + BEGIN( Comment ); + } +<SectionTitle>{LC} { // line continuation + yyLineNr++; + addOutput('\n'); + } +<SectionTitle>[^\n@\\]* { // any character without special meaning + g_sectionTitle+=yytext; + addOutput(yytext); + } +<SectionTitle>("\\\\"|"@@"){ID} { // unescape escaped command + g_sectionTitle+=&yytext[1]; + addOutput(yytext); + } +<SectionTitle>{CMD}[$@\\&~<>#%] { // unescape escaped character + g_sectionTitle+=yytext[1]; + addOutput(yytext); + } +<SectionTitle>. { // anything else + g_sectionTitle+=yytext; + addOutput(*yytext); + } + + /* ----- handle arguments of the subpage command ------- */ + +<SubpageLabel>{LABELID} { // first argument + addOutput(yytext); + // we add subpage labels as a kind of "inheritance" relation to prevent + // needing to add another list to the Entry class. + current->extends->append(new BaseInfo(yytext,Public,Normal)); + BEGIN(SubpageTitle); + } +<SubpageLabel>{DOCNL} { // missing argument + warn(yyFileName,yyLineNr, + "warning: \\subpage command has no label" + ); + if (*yytext=='\n') yyLineNr++; + addOutput('\n'); + BEGIN( Comment ); + } +<SubpageTitle>{DOCNL} { // no title, end command + addOutput(yytext); + BEGIN( Comment ); + } +<SubpageTitle>[ \t]*"\""[^\"\n]*"\"" { // add title, end of command + addOutput(yytext); + BEGIN( Comment ); + } +<SubpageTitle>. { // no title, end of command + unput(*yytext); + BEGIN( Comment ); + } + + /* ----- handle arguments of the anchor command ------- */ + +<AnchorLabel>{LABELID} { // found argument + SectionInfo *si = new SectionInfo(yyFileName,yytext,0,SectionInfo::Anchor,0); + Doxygen::sectionDict.append(yytext,si); + current->anchors->append(si); + addOutput(yytext); + BEGIN( Comment ); + } +<AnchorLabel>{DOCNL} { // missing argument + warn(yyFileName,yyLineNr, + "warning: \\anchor command has no label" + ); + if (*yytext=='\n') yyLineNr++; + addOutput('\n'); + BEGIN( Comment ); + } +<AnchorLabel>. { // invalid character for anchor label + warn(yyFileName,yyLineNr, + "warning: Invalid or missing anchor label" + ); + BEGIN(Comment); + } + + + /* ----- handle arguments of the preformatted block commands ------- */ + +<FormatBlock>{CMD}("endverbatim"|"endlatexonly"|"endhtmlonly"|"endxmlonly"|"endrtfonly"|"endmanonly"|"enddot"|"endcode"|"endmsc")/{NW} { // possible ends + addOutput(yytext); + if (&yytext[4]==blockName) // found end of the block + { + BEGIN(Comment); + } + } +<FormatBlock>[^ \@\*\/\\\n]* { // some word + addOutput(yytext); + } +<FormatBlock>{DOCNL} { // new line + if (*yytext=='\n') yyLineNr++; + addOutput('\n'); + } +<FormatBlock>"/*" { // start of a C-comment + g_commentCount++; + addOutput(yytext); + } +<FormatBlock>"*/" { // end of a C-comment + addOutput(yytext); + g_commentCount--; + if (g_commentCount<0 && blockName!="verbatim") + { + warn(yyFileName,yyLineNr, + "warning: found */ without matching /* while inside a \\%s block! Perhaps a missing \\end%s?\n",blockName.data(),blockName.data()); + } + } +<FormatBlock>. { + addOutput(*yytext); + } +<FormatBlock><<EOF>> { + warn(yyFileName,yyLineNr, + "warning: reached end of comment while inside a @%s block; check for missing @end%s tag!", + blockName.data(),blockName.data() + ); + yyterminate(); + } + + /* ----- handle arguments of if/ifnot commands ------- */ + +<GuardParam>{LABELID} { // parameter of if/ifnot guard + bool sectionEnabled = Config_getList("ENABLED_SECTIONS").find(yytext)!=-1; + bool parentEnabled = TRUE; + if (!guards.isEmpty()) parentEnabled = guards.top()->isEnabled(); + if (parentEnabled) + { + if ( + (sectionEnabled && guardType==Guard_If) || + (!sectionEnabled && guardType==Guard_IfNot) + ) // section is visible + { + guards.push(new GuardedSection(TRUE,TRUE)); + enabledSectionFound=TRUE; + BEGIN( GuardParamEnd ); + } + else // section is invisible + { + if (guardType!=Guard_Skip) + { + guards.push(new GuardedSection(FALSE,TRUE)); + } + BEGIN( SkipGuardedSection ); + } + } + else // invisible because of parent + { + guards.push(new GuardedSection(FALSE,FALSE)); + BEGIN( SkipGuardedSection ); + } + } +<GuardParam>{DOCNL} { // end of argument + if (*yytext=='\n') yyLineNr++; + //next line is commented out due to bug620924 + //addOutput('\n'); + BEGIN( Comment ); + } +<GuardParam>{LC} { // line continuation + yyLineNr++; + addOutput('\n'); + } +<GuardParam>. { // ignore other stuff + addOutput(*yytext); + } +<GuardParamEnd>{B}*{DOCNL} { + g_spaceBeforeIf=FALSE; + BEGIN(Comment); + } +<GuardParamEnd>{B}* { + if (g_spaceBeforeIf) // needed for 665313 in combation with bug620924 + { + addOutput(" "); + } + g_spaceBeforeIf=FALSE; + BEGIN(Comment); + } +<GuardParamEnd>. { + unput(*yytext); + BEGIN(Comment); + } + + /* ----- handle skipping of conditional sections ------- */ + +<SkipGuardedSection>{CMD}"ifnot"/{NW} { + guardType = Guard_IfNot; + BEGIN( GuardParam ); + } +<SkipGuardedSection>{CMD}"if"/{NW} { + guardType = Guard_If; + BEGIN( GuardParam ); + } +<SkipGuardedSection>{CMD}"endif"/{NW} { + if (guards.isEmpty()) + { + warn(yyFileName,yyLineNr, + "warning: found @endif without matching start command"); + } + else + { + delete guards.pop(); + BEGIN( GuardParamEnd ); + } + } +<SkipGuardedSection>{CMD}"else"/{NW} { + if (guards.isEmpty()) + { + warn(yyFileName,yyLineNr, + "warning: found @else without matching start command"); + } + else + { + if (!enabledSectionFound && guards.top()->parentVisible()) + { + delete guards.pop(); + guards.push(new GuardedSection(TRUE,TRUE)); + enabledSectionFound=TRUE; + BEGIN( GuardParamEnd ); + } + } + } +<SkipGuardedSection>{CMD}"elseif"/{NW} { + if (guards.isEmpty()) + { + warn(yyFileName,yyLineNr, + "warning: found @elseif without matching start command"); + } + else + { + if (!enabledSectionFound && guards.top()->parentVisible()) + { + delete guards.pop(); + BEGIN( GuardParam ); + } + } + } +<SkipGuardedSection>{DOCNL} { // skip line + if (*yytext=='\n') yyLineNr++; + //addOutput('\n'); + } +<SkipGuardedSection>[^ \\@\n]+ { // skip non-special characters + } +<SkipGuardedSection>. { // any other character + } + + + /* ----- handle skipping of internal section ------- */ + +<SkipInternal>{DOCNL} { // skip line + if (*yytext=='\n') yyLineNr++; + addOutput('\n'); + } +<SkipInternal>[@\\]"if"/[ \t] { + g_condCount++; + } +<SkipInternal>[@\\]"ifnot"/[ \t] { + g_condCount++; + } +<SkipInternal>[@\\]/"endif" { + g_condCount--; + if (g_condCount<0) // handle conditional section around of \internal, see bug607743 + { + unput('\\'); + BEGIN(Comment); + } + } +<SkipInternal>[@\\]/"section"[ \t] { + if (g_sectionLevel>0) + { + unput('\\'); + BEGIN(Comment); + } + } +<SkipInternal>[@\\]/"subsection"[ \t] { + if (g_sectionLevel>1) + { + unput('\\'); + BEGIN(Comment); + } + } +<SkipInternal>[@\\]/"subsubsection"[ \t] { + if (g_sectionLevel>2) + { + unput('\\'); + BEGIN(Comment); + } + } +<SkipInternal>[@\\]/"paragraph"[ \t] { + if (g_sectionLevel>3) + { + unput('\\'); + BEGIN(Comment); + } + } +<SkipInternal>[@\\]"endinternal"[ \t]* { + BEGIN(Comment); + } +<SkipInternal>[^ \\@\n]+ { // skip non-special characters + } +<SkipInternal>. { // any other character + } + + + /* ----- handle argument of name command ------- */ + +<NameParam>{DOCNL} { // end of argument + if (*yytext=='\n') yyLineNr++; + addOutput('\n'); + BEGIN( Comment ); + } +<NameParam>{LC} { // line continuation + yyLineNr++; + addOutput('\n'); + g_memberGroupHeader+=' '; + } +<NameParam>. { // ignore other stuff + g_memberGroupHeader+=*yytext; + current->name+=*yytext; + } + + /* ----- handle argument of ingroup command ------- */ + +<InGroupParam>{LABELID} { // group id + current->groups->append( + new Grouping(yytext, Grouping::GROUPING_INGROUP) + ); + inGroupParamFound=TRUE; + } +<InGroupParam>{DOCNL} { // missing argument + if (!inGroupParamFound) + { + warn(yyFileName,yyLineNr, + "warning: Missing group name for \\ingroup command" + ); + } + if (*yytext=='\n') yyLineNr++; + addOutput('\n'); + BEGIN( Comment ); + } +<InGroupParam>{LC} { // line continuation + yyLineNr++; + addOutput('\n'); + } +<InGroupParam>. { // ignore other stuff + addOutput(*yytext); + } + + /* ----- handle argument of fn command ------- */ + +<FnParam>{DOCNL} { // end of argument + if (braceCount==0) + { + if (*yytext=='\n') yyLineNr++; + addOutput('\n'); + langParser->parsePrototype(functionProto); + BEGIN( Comment ); + } + } +<FnParam>{LC} { // line continuation + yyLineNr++; + functionProto+=' '; + } +<FnParam>[^@\\\n()]+ { // non-special characters + functionProto+=yytext; + } +<FnParam>"(" { + functionProto+=yytext; + braceCount++; + } +<FnParam>")" { + functionProto+=yytext; + braceCount--; + } +<FnParam>. { // add other stuff + functionProto+=*yytext; + } + + + /* ----- handle argument of overload command ------- */ + + +<OverloadParam>{DOCNL} { // end of argument + if (*yytext=='\n') yyLineNr++; + addOutput('\n'); + if (functionProto.stripWhiteSpace().isEmpty()) + { // plain overload command + addOutput(getOverloadDocs()); + } + else // overload declaration + { + makeStructuralIndicator(Entry::OVERLOADDOC_SEC); + langParser->parsePrototype(functionProto); + } + BEGIN( Comment ); + } +<OverloadParam>{LC} { // line continuation + yyLineNr++; + functionProto+=' '; + } +<OverloadParam>. { // add other stuff + functionProto+=*yytext; + } + + /* ----- handle argument of inherit command ------- */ + +<InheritParam>({ID}("::"|"."))*{ID} { // found argument + current->extends->append( + new BaseInfo(removeRedundantWhiteSpace(yytext),Public,Normal) + ); + BEGIN( Comment ); + } +<InheritParam>{DOCNL} { // missing argument + warn(yyFileName,yyLineNr, + "warning: \\inherit command has no argument" + ); + if (*yytext=='\n') yyLineNr++; + addOutput('\n'); + BEGIN( Comment ); + } +<InheritParam>. { // invalid character for anchor label + warn(yyFileName,yyLineNr, + "warning: Invalid or missing name for \\inherit command" + ); + BEGIN(Comment); + } + + /* ----- handle argument of extends and implements commands ------- */ + +<ExtendsParam>({ID}("::"|"."))*{ID} { // found argument + current->extends->append( + new BaseInfo(removeRedundantWhiteSpace(yytext),Public,Normal) + ); + BEGIN( Comment ); + } +<ExtendsParam>{DOCNL} { // missing argument + warn(yyFileName,yyLineNr, + "warning: \\extends or \\implements command has no argument" + ); + if (*yytext=='\n') yyLineNr++; + addOutput('\n'); + BEGIN( Comment ); + } +<ExtendsParam>. { // ignore other stuff + } + + /* ----- handle language specific sections ------- */ + +<SkipLang>[\\@]"~"[a-zA-Z]* { /* language switch */ + QCString langId = &yytext[2]; + if (langId.isEmpty() || + stricmp(Config_getEnum("OUTPUT_LANGUAGE"),langId)==0) + { // enable language specific section + BEGIN(Comment); + } + } +<SkipLang>[^*@\\\n]* { /* any character not a *, @, backslash or new line */ + } +<SkipLang>{DOCNL} { /* new line in verbatim block */ + if (*yytext=='\n') yyLineNr++; + } +<SkipLang>. { /* any other character */ + } + + /* ----- handle arguments of the cite command ------- */ + +<CiteLabel>{CITEID} { // found argyment + addCite(); + addOutput(yytext); + BEGIN(Comment); + } +<CiteLabel>{DOCNL} { // missing argument + warn(yyFileName,yyLineNr, + "warning: \\cite command has no label" + ); + if (*yytext=='\n') yyLineNr++; + addOutput('\n'); + BEGIN( Comment ); + } +<CiteLabel>. { // invalid character for cite label + warn(yyFileName,yyLineNr, + "warning: Invalid or missing cite label" + ); + BEGIN(Comment); + } + + /* ----- handle argument of the copydoc command ------- */ + +<CopyDoc><<EOF>> | +<CopyDoc>{DOCNL} { + if (*yytext=='\n') yyLineNr++; + addOutput('\n'); + setOutput(OutputDoc); + addOutput("\\copydetails "); + addOutput(g_copyDocArg); + addOutput("\n"); + BEGIN(Comment); + } +<CopyDoc>[^\n\\]+ { + g_copyDocArg+=yytext; + addOutput(yytext); + } +<CopyDoc>. { + g_copyDocArg+=yytext; + addOutput(yytext); + } + + +%% + +//---------------------------------------------------------------------------- + +static bool handleBrief(const QCString &) +{ + //printf("handleBrief\n"); + setOutput(OutputBrief); + return FALSE; +} + +static bool handleFn(const QCString &) +{ + bool stop=makeStructuralIndicator(Entry::MEMBERDOC_SEC); + functionProto.resize(0); + braceCount=0; + BEGIN(FnParam); + return stop; +} + +static bool handleDef(const QCString &) +{ + bool stop=makeStructuralIndicator(Entry::DEFINEDOC_SEC); + functionProto.resize(0); + BEGIN(FnParam); + return stop; +} + +static bool handleOverload(const QCString &) +{ + functionProto.resize(0); + BEGIN(OverloadParam); + return FALSE; +} + +static bool handleEnum(const QCString &) +{ + bool stop=makeStructuralIndicator(Entry::ENUMDOC_SEC); + BEGIN(EnumDocArg1); + return stop; +} + +static bool handleDefGroup(const QCString &) +{ + bool stop=makeStructuralIndicator(Entry::GROUPDOC_SEC); + current->groupDocType = Entry::GROUPDOC_NORMAL; + BEGIN( GroupDocArg1 ); + return stop; +} + +static bool handleAddToGroup(const QCString &) +{ + bool stop=makeStructuralIndicator(Entry::GROUPDOC_SEC); + current->groupDocType = Entry::GROUPDOC_ADD; + BEGIN( GroupDocArg1 ); + return stop; +} + +static bool handleWeakGroup(const QCString &) +{ + bool stop=makeStructuralIndicator(Entry::GROUPDOC_SEC); + current->groupDocType = Entry::GROUPDOC_WEAK; + BEGIN( GroupDocArg1 ); + return stop; +} + +static bool handleNamespace(const QCString &) +{ + bool stop=makeStructuralIndicator(Entry::NAMESPACEDOC_SEC); + BEGIN( NameSpaceDocArg1 ); + return stop; +} + +static bool handlePackage(const QCString &) +{ + bool stop=makeStructuralIndicator(Entry::PACKAGEDOC_SEC); + BEGIN( PackageDocArg1 ); + return stop; +} + +static bool handleClass(const QCString &) +{ + bool stop=makeStructuralIndicator(Entry::CLASSDOC_SEC); + BEGIN( ClassDocArg1 ); + return stop; +} + +static bool handleHeaderFile(const QCString &) +{ + BEGIN( ClassDocArg2 ); + return FALSE; +} + +static bool handleProtocol(const QCString &) +{ // Obj-C protocol + bool stop=makeStructuralIndicator(Entry::PROTOCOLDOC_SEC); + BEGIN( ClassDocArg1 ); + return stop; +} + +static bool handleCategory(const QCString &) +{ // Obj-C category + bool stop=makeStructuralIndicator(Entry::CATEGORYDOC_SEC); + BEGIN( CategoryDocArg1 ); + return stop; +} + +static bool handleUnion(const QCString &) +{ + bool stop=makeStructuralIndicator(Entry::UNIONDOC_SEC); + BEGIN( ClassDocArg1 ); + return stop; +} + +static bool handleStruct(const QCString &) +{ + bool stop=makeStructuralIndicator(Entry::STRUCTDOC_SEC); + BEGIN( ClassDocArg1 ); + return stop; +} + +static bool handleInterface(const QCString &) +{ + bool stop=makeStructuralIndicator(Entry::INTERFACEDOC_SEC); + BEGIN( ClassDocArg1 ); + return stop; +} + +static bool handleIdlException(const QCString &) +{ + bool stop=makeStructuralIndicator(Entry::EXCEPTIONDOC_SEC); + BEGIN( ClassDocArg1 ); + return stop; +} + +static bool handlePage(const QCString &) +{ + bool stop=makeStructuralIndicator(Entry::PAGEDOC_SEC); + BEGIN( PageDocArg1 ); + return stop; +} + +static bool handleMainpage(const QCString &) +{ + bool stop=makeStructuralIndicator(Entry::MAINPAGEDOC_SEC); + if (!stop) + { + current->name = "mainpage"; + } + BEGIN( PageDocArg2 ); + return stop; +} + +static bool handleFile(const QCString &) +{ + bool stop=makeStructuralIndicator(Entry::FILEDOC_SEC); + if (!stop) + { + current->name = yyFileName; + } + BEGIN( FileDocArg1 ); + return stop; +} + +static bool handleDir(const QCString &) +{ + bool stop=makeStructuralIndicator(Entry::DIRDOC_SEC); + if (!stop) current->name = yyFileName; + BEGIN( FileDocArg1 ); + return stop; +} + +static bool handleExample(const QCString &) +{ + bool stop=makeStructuralIndicator(Entry::EXAMPLE_SEC); + if (!stop) current->name = yyFileName; + BEGIN( FileDocArg1 ); + return stop; +} + +static bool handleDetails(const QCString &) +{ + if (inContext!=OutputBrief) + { + addOutput("\n\n"); // treat @details outside brief description + // as a new paragraph + } + setOutput(OutputDoc); + return FALSE; +} + +static bool handleName(const QCString &) +{ + bool stop=makeStructuralIndicator(Entry::MEMBERGRP_SEC); + if (!stop) + { + g_memberGroupHeader.resize(0); + BEGIN( NameParam ); + if (g_memberGroupId!=DOX_NOGROUP) // end of previous member group + { + closeGroup(current,yyFileName,yyLineNr,TRUE); + } + } + return stop; +} + +static bool handleTodo(const QCString &) +{ + newXRefKind = XRef_Todo; + setOutput(OutputXRef); + xrefKind = XRef_Todo; + return FALSE; +} + +static bool handleTest(const QCString &) +{ + newXRefKind = XRef_Test; + setOutput(OutputXRef); + xrefKind = XRef_Test; + return FALSE; +} + +static bool handleBug(const QCString &) +{ + newXRefKind = XRef_Bug; + setOutput(OutputXRef); + xrefKind = XRef_Bug; + return FALSE; +} + +static bool handleDeprecated(const QCString &) +{ + newXRefKind = XRef_Deprecated; + setOutput(OutputXRef); + xrefKind = XRef_Deprecated; + return FALSE; +} + +static bool handleXRefItem(const QCString &) +{ + BEGIN(XRefItemParam1); + return FALSE; +} + +static bool handleRelated(const QCString &) +{ + BEGIN(RelatesParam1); + return FALSE; +} + +static bool handleRelatedAlso(const QCString &) +{ + current->relatesType = Duplicate; + BEGIN(RelatesParam1); + return FALSE; +} + +static bool handleMemberOf(const QCString &) +{ + current->relatesType = MemberOf; + BEGIN(RelatesParam1); + return FALSE; +} + +static bool handleRefItem(const QCString &) +{ + addOutput(" @refitem "); + BEGIN(LineParam); + return FALSE; +} + +static bool handleSection(const QCString &s) +{ + setOutput(OutputDoc); + addOutput(" @"+s+" "); + BEGIN(SectionLabel); + if (s=="section") g_sectionLevel=1; + else if (s=="subsection") g_sectionLevel=2; + else if (s=="subsubsection") g_sectionLevel=3; + else if (s=="paragraph") g_sectionLevel=4; + return FALSE; +} + +static bool handleSubpage(const QCString &s) +{ + if (current->section!=Entry::EMPTY_SEC && + current->section!=Entry::PAGEDOC_SEC && + current->section!=Entry::MAINPAGEDOC_SEC + ) + { + warn(yyFileName,yyLineNr, + "warning: found \\subpage command in a comment block that is not marked as a page!"); + } + addOutput(" @"+s+" "); + BEGIN(SubpageLabel); + return FALSE; +} + +static bool handleAnchor(const QCString &s) +{ + addOutput(" @"+s+" "); + BEGIN(AnchorLabel); + return FALSE; +} + +static bool handleCite(const QCString &s) +{ + addOutput(" @"+s+" "); + BEGIN(CiteLabel); + return FALSE; +} + +static bool handleFormatBlock(const QCString &s) +{ + addOutput(" @"+s+" "); + //printf("handleFormatBlock(%s)\n",s.data()); + blockName=s; + g_commentCount=0; + BEGIN(FormatBlock); + return FALSE; +} + +static bool handleAddIndex(const QCString &) +{ + addOutput(" @addindex "); + BEGIN(LineParam); + return FALSE; +} + +static bool handleIf(const QCString &) +{ + enabledSectionFound=FALSE; + guardType = Guard_If; + g_spaceBeforeIf = g_spaceBeforeCmd; + BEGIN(GuardParam); + return FALSE; +} + +static bool handleIfNot(const QCString &) +{ + enabledSectionFound=FALSE; + guardType = Guard_IfNot; + g_spaceBeforeIf = g_spaceBeforeCmd; + BEGIN(GuardParam); + return FALSE; +} + +static bool handleElseIf(const QCString &) +{ + if (guards.isEmpty()) + { + warn(yyFileName,yyLineNr, + "warning: found \\else without matching start command"); + } + else + { + guardType = enabledSectionFound ? Guard_Skip : Guard_If; + BEGIN(GuardParam); + } + return FALSE; +} + +static bool handleElse(const QCString &) +{ + if (guards.isEmpty()) + { + warn(yyFileName,yyLineNr, + "warning: found \\else without matching start command"); + } + else + { + BEGIN( SkipGuardedSection ); + } + return FALSE; +} + +static bool handleEndIf(const QCString &) +{ + if (guards.isEmpty()) + { + warn(yyFileName,yyLineNr, + "warning: found \\endif without matching start command"); + } + else + { + delete guards.pop(); + } + enabledSectionFound=FALSE; + BEGIN( GuardParamEnd ); + return FALSE; +} + +static bool handleIngroup(const QCString &) +{ + inGroupParamFound=FALSE; + BEGIN( InGroupParam ); + return FALSE; +} + +static bool handleNoSubGrouping(const QCString &) +{ + current->subGrouping = FALSE; + return FALSE; +} + +static bool handleShowInitializer(const QCString &) +{ + current->initLines = 100000; // ON + return FALSE; +} + +static bool handleHideInitializer(const QCString &) +{ + current->initLines = 0; // OFF + return FALSE; +} + +static bool handleCallgraph(const QCString &) +{ + current->callGraph = TRUE; // ON + return FALSE; +} + +static bool handleCallergraph(const QCString &) +{ + current->callerGraph = TRUE; // ON + return FALSE; +} + +static bool handleInternal(const QCString &) +{ + if (!Config_getBool("INTERNAL_DOCS")) + { + // make sure some whitespace before a \internal command + // is not treated as "documentation" + if (current->doc.stripWhiteSpace().isEmpty()) + { + current->doc.resize(0); + } + g_condCount=0; + BEGIN( SkipInternal ); + } + else + { + // re-enabled for bug640828 + addOutput("\\internal "); + } + return FALSE; +} + +static bool handleLineBr(const QCString &) +{ + addOutput('\n'); + return FALSE; +} + +static bool handleStatic(const QCString &) +{ + endBrief(); + current->stat = TRUE; + return FALSE; +} + +static bool handlePure(const QCString &) +{ + endBrief(); + current->virt = Pure; + return FALSE; +} + +static bool handlePrivate(const QCString &) +{ + current->protection = Private; + return FALSE; +} + +static bool handlePrivateSection(const QCString &) +{ + current->protection = protection = Private; + return FALSE; +} + +static bool handleProtected(const QCString &) +{ + current->protection = Protected; + return FALSE; +} + +static bool handleProtectedSection(const QCString &) +{ + current->protection = protection = Protected ; + return FALSE; +} + +static bool handlePublic(const QCString &) +{ + current->protection = Public; + return FALSE; +} + +static bool handlePublicSection(const QCString &) +{ + current->protection = protection = Public; + return FALSE; +} + +static bool handleToc(const QCString &) +{ + if (current->section==Entry::PAGEDOC_SEC || + current->section==Entry::MAINPAGEDOC_SEC) + { + current->stat=TRUE; // we 'abuse' stat to pass whether or the TOC is enabled + } + return FALSE; +} + +static bool handleInherit(const QCString &) +{ + BEGIN(InheritParam); + return FALSE; +} + +static bool handleExtends(const QCString &) +{ + BEGIN(ExtendsParam); + return FALSE; +} + +static bool handleCopyDoc(const QCString &) +{ + setOutput(OutputBrief); + addOutput("\\copybrief "); + g_copyDocArg.resize(0); + BEGIN(CopyDoc); + return FALSE; +} + +//---------------------------------------------------------------------------- + +static void checkFormula() +{ + if (YY_START==ReadFormulaShort || YY_START==ReadFormulaLong) + { + warn(yyFileName,yyLineNr,"warning: End of comment block while inside formula."); + } +} + +//---------------------------------------------------------------------------- + +bool parseCommentBlock(/* in */ ParserInterface *parser, + /* in */ Entry *curEntry, + /* in */ const QCString &comment, + /* in */ const QCString &fileName, + /* in,out */ int &lineNr, + /* in */ bool isBrief, + /* in */ bool isAutoBriefOn, + /* in */ bool isInbody, + /* in,out */ Protection &prot, + /* in,out */ int &position, + /* out */ bool &newEntryNeeded + ) +{ + //printf("parseCommentBlock() isBrief=%d isAutoBriefOn=%d lineNr=%d\n", + // isBrief,isAutoBriefOn,lineNr); + + initParser(); + guards.setAutoDelete(TRUE); + guards.clear(); + langParser = parser; + current = curEntry; + if (comment.isEmpty()) return FALSE; // avoid empty strings + inputString = comment; + inputString.append(" "); + inputPosition = position; + yyLineNr = lineNr; + yyFileName = fileName; + protection = prot; + needNewEntry = FALSE; + xrefKind = XRef_None; + xrefAppendFlag = FALSE; + insidePre = FALSE; + parseMore = FALSE; + inBody = isInbody; + outputXRef.resize(0); + setOutput( isBrief || isAutoBriefOn ? OutputBrief : OutputDoc ); + briefEndsAtDot = isAutoBriefOn; + g_condCount = 0; + g_sectionLevel = 0; + g_spaceBeforeCmd = FALSE; + g_spaceBeforeIf = FALSE; + + if (!current->inbodyDocs.isEmpty() && isInbody) // separate in body fragments + { + current->inbodyDocs+="\n\n"; + } + + Debug::print(Debug::CommentScan,0,"-----------\nCommentScanner: %s:%d\n" + "input=[%s]\n",fileName.data(),lineNr,comment.data() + ); + + commentScanYYrestart( commentScanYYin ); + BEGIN( Comment ); + commentScanYYlex(); + setOutput( OutputDoc ); + + if (YY_START==OverloadParam) // comment ended with \overload + { + addOutput(getOverloadDocs()); + } + + if (!guards.isEmpty()) + { + warn(yyFileName,yyLineNr,"Documentation block ended in the middle of a conditional section!"); + } + + current->doc=stripLeadingAndTrailingEmptyLines(current->doc,current->docLine); + + if (current->section==Entry::FILEDOC_SEC && current->doc.isEmpty()) + { + // to allow a comment block with just a @file command. + current->doc="\n\n"; + } + + if (current->section==Entry::MEMBERGRP_SEC && + g_memberGroupId==DOX_NOGROUP) // @name section but no group started yet + { + openGroup(current,yyFileName,yyLineNr); + } + + if (Doxygen::markdownSupport) + { + current->brief = processMarkdown(fileName,current,current->brief); + current->doc = processMarkdown(fileName,current,current->doc); + current->inbodyDocs = processMarkdown(fileName,current,current->inbodyDocs); + } + + Debug::print(Debug::CommentScan,0, + "brief=[line=%d\n%s]\ndocs=[line=%d\n%s]\ninbody=[line=%d\n%s]\n===========\n", + current->briefLine,current->brief.data(), + current->docLine,current->doc.data(), + current->inbodyLine,current->inbodyDocs.data() + ); + + checkFormula(); + prot = protection; + + groupAddDocs(curEntry,fileName); + + newEntryNeeded = needNewEntry; + + // if we did not proceed during this call, it does not make + // sense to continue, since we get stuck. See bug 567346 for situations + // were this happens + if (parseMore && position==inputPosition) parseMore=FALSE; + + if (parseMore) position=inputPosition; else position=0; + + lineNr = yyLineNr; + //printf("position=%d parseMore=%d\n",position,parseMore); + + return parseMore; +} + +//--------------------------------------------------------------------------- + +void groupEnterFile(const char *fileName,int) +{ + g_autoGroupStack.setAutoDelete(TRUE); + g_autoGroupStack.clear(); + g_memberGroupId = DOX_NOGROUP; + g_memberGroupDocs.resize(0); + g_memberGroupRelates.resize(0); + g_compoundName=fileName; +} + +void groupLeaveFile(const char *fileName,int line) +{ + //if (g_memberGroupId!=DOX_NOGROUP) + //{ + // warn(fileName,line,"warning: end of file while inside a member group\n"); + //} + g_memberGroupId=DOX_NOGROUP; + g_memberGroupRelates.resize(0); + g_memberGroupDocs.resize(0); + if (!g_autoGroupStack.isEmpty()) + { + warn(fileName,line,"warning: end of file while inside a group\n"); + } +} + +void groupEnterCompound(const char *fileName,int line,const char *name) +{ + if (g_memberGroupId!=DOX_NOGROUP) + { + warn(fileName,line,"warning: try to put compound %s inside a member group\n",name); + } + g_memberGroupId=DOX_NOGROUP; + g_memberGroupRelates.resize(0); + g_memberGroupDocs.resize(0); + g_compoundName = name; + int i = g_compoundName.find('('); + if (i!=-1) + { + g_compoundName=g_compoundName.left(i); // strip category (Obj-C) + } + if (g_compoundName.isEmpty()) + { + g_compoundName=fileName; + } + //printf("groupEnterCompound(%s)\n",name); +} + +void groupLeaveCompound(const char *,int,const char * /*name*/) +{ + //printf("groupLeaveCompound(%s)\n",name); + //if (g_memberGroupId!=DOX_NOGROUP) + //{ + // warn(fileName,line,"warning: end of compound %s while inside a member group\n",name); + //} + g_memberGroupId=DOX_NOGROUP; + g_memberGroupRelates.resize(0); + g_memberGroupDocs.resize(0); + g_compoundName.resize(0); +} + +static int findExistingGroup(int &groupId,const MemberGroupInfo *info) +{ + //printf("findExistingGroup %s:%s\n",info->header.data(),info->compoundName.data()); + QIntDictIterator<MemberGroupInfo> di(Doxygen::memGrpInfoDict); + MemberGroupInfo *mi; + for (di.toFirst();(mi=di.current());++di) + { + if (g_compoundName==mi->compoundName && // same file or scope + !mi->header.isEmpty() && // not a nameless group + stricmp(mi->header,info->header)==0 // same header name + ) + { + //printf("Found it!\n"); + return di.currentKey(); // put the item in this group + } + } + groupId++; // start new group + return groupId; +} + +void openGroup(Entry *e,const char *,int) +{ + //printf("==> openGroup(name=%s,sec=%x) g_autoGroupStack=%d\n", + // e->name.data(),e->section,g_autoGroupStack.count()); + if (e->section==Entry::GROUPDOC_SEC) // auto group + { + g_autoGroupStack.push(new Grouping(e->name,e->groupingPri())); + } + else // start of a member group + { + //printf(" membergroup id=%d %s\n",g_memberGroupId,g_memberGroupHeader.data()); + if (g_memberGroupId==DOX_NOGROUP) // no group started yet + { + static int curGroupId=0; + + MemberGroupInfo *info = new MemberGroupInfo; + info->header = g_memberGroupHeader.stripWhiteSpace(); + info->compoundName = g_compoundName; + g_memberGroupId = findExistingGroup(curGroupId,info); + //printf(" use membergroup %d\n",g_memberGroupId); + Doxygen::memGrpInfoDict.insert(g_memberGroupId,info); + + g_memberGroupRelates = e->relates; + e->mGrpId = g_memberGroupId; + } + } +} + +void closeGroup(Entry *e,const char *fileName,int,bool foundInline) +{ + //printf("==> closeGroup(name=%s,sec=%x) g_autoGroupStack=%d\n", + // e->name.data(),e->section,g_autoGroupStack.count()); + if (g_memberGroupId!=DOX_NOGROUP) // end of member group + { + MemberGroupInfo *info=Doxygen::memGrpInfoDict.find(g_memberGroupId); + if (info) // known group + { + info->doc = g_memberGroupDocs; + info->docFile = fileName; + } + g_memberGroupId=DOX_NOGROUP; + g_memberGroupRelates.resize(0); + g_memberGroupDocs.resize(0); + e->mGrpId=DOX_NOGROUP; + //printf("new group id=%d\n",g_memberGroupId); + } + else if (!g_autoGroupStack.isEmpty()) // end of auto group + { + Grouping *grp = g_autoGroupStack.pop(); + // see bug577005: we should not remove the last group for e + if (!foundInline) e->groups->removeLast(); + //printf("Removing %s e=%p\n",grp->groupname.data(),e); + delete grp; + if (!foundInline) initGroupInfo(e); + } +} + +void initGroupInfo(Entry *e) +{ + //printf("==> initGroup(id=%d,related=%s,e=%p)\n",g_memberGroupId, + // g_memberGroupRelates.data(),e); + e->mGrpId = g_memberGroupId; + e->relates = g_memberGroupRelates; + if (!g_autoGroupStack.isEmpty()) + { + //printf("Appending group %s to %s: count=%d entry=%p\n", + // g_autoGroupStack.top()->groupname.data(), + // e->name.data(),e->groups->count(),e); + e->groups->append(new Grouping(*g_autoGroupStack.top())); + } +} + +static void groupAddDocs(Entry *e,const char *fileName) +{ + if (e->section==Entry::MEMBERGRP_SEC) + { + g_memberGroupDocs=e->brief.stripWhiteSpace(); + e->doc = stripLeadingAndTrailingEmptyLines(e->doc,e->docLine); + if (!g_memberGroupDocs.isEmpty() && !e->doc.isEmpty()) + { + g_memberGroupDocs+="\n\n"; + } + g_memberGroupDocs+=e->doc; + MemberGroupInfo *info=Doxygen::memGrpInfoDict.find(g_memberGroupId); + if (info) + { + info->doc = g_memberGroupDocs; + info->docFile = fileName; + info->setRefItems(e->sli); + } + e->doc.resize(0); + e->brief.resize(0); + } +} + + +#if !defined(YY_FLEX_SUBMINOR_VERSION) +//---------------------------------------------------------------------------- +extern "C" { // some bogus code to keep the compiler happy + void commentScanYYdummy() { yy_flex_realloc(0,0); } +} +#endif + diff --git a/trunk/src/compound.xsd b/trunk/src/compound.xsd new file mode 100644 index 0000000..1149266 --- /dev/null +++ b/trunk/src/compound.xsd @@ -0,0 +1,829 @@ +<?xml version='1.0' encoding='utf-8' ?> +<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> + <xsd:element name="doxygen" type="DoxygenType"/> + + <!-- Complex types --> + + <xsd:complexType name="DoxygenType"> + <xsd:sequence maxOccurs="unbounded"> + <xsd:element name="compounddef" type="compounddefType" minOccurs="0" /> + </xsd:sequence> + <xsd:attribute name="version" type="DoxVersionNumber" use="required" /> + </xsd:complexType> + + <xsd:complexType name="compounddefType"> + <xsd:sequence> + <xsd:element name="compoundname" type="xsd:string"/> + <xsd:element name="title" type="xsd:string" minOccurs="0" /> + <xsd:element name="basecompoundref" type="compoundRefType" minOccurs="0" maxOccurs="unbounded" /> + <xsd:element name="derivedcompoundref" type="compoundRefType" minOccurs="0" maxOccurs="unbounded" /> + <xsd:element name="includes" type="incType" minOccurs="0" maxOccurs="unbounded" /> + <xsd:element name="includedby" type="incType" minOccurs="0" maxOccurs="unbounded" /> + <xsd:element name="incdepgraph" type="graphType" minOccurs="0" /> + <xsd:element name="invincdepgraph" type="graphType" minOccurs="0" /> + <xsd:element name="innerdir" type="refType" minOccurs="0" maxOccurs="unbounded" /> + <xsd:element name="innerfile" type="refType" minOccurs="0" maxOccurs="unbounded" /> + <xsd:element name="innerclass" type="refType" minOccurs="0" maxOccurs="unbounded" /> + <xsd:element name="innernamespace" type="refType" minOccurs="0" maxOccurs="unbounded" /> + <xsd:element name="innerpage" type="refType" minOccurs="0" maxOccurs="unbounded" /> + <xsd:element name="innergroup" type="refType" minOccurs="0" maxOccurs="unbounded" /> + <xsd:element name="templateparamlist" type="templateparamlistType" minOccurs="0" /> + <xsd:element name="sectiondef" type="sectiondefType" minOccurs="0" maxOccurs="unbounded" /> + <xsd:element name="briefdescription" type="descriptionType" minOccurs="0" /> + <xsd:element name="detaileddescription" type="descriptionType" minOccurs="0" /> + <xsd:element name="inheritancegraph" type="graphType" minOccurs="0" /> + <xsd:element name="collaborationgraph" type="graphType" minOccurs="0" /> + <xsd:element name="programlisting" type="listingType" minOccurs="0" /> + <xsd:element name="location" type="locationType" minOccurs="0" /> + <xsd:element name="listofallmembers" type="listofallmembersType" minOccurs="0" /> + </xsd:sequence> + <xsd:attribute name="id" type="xsd:string" /> + <xsd:attribute name="kind" type="DoxCompoundKind" /> + <xsd:attribute name="prot" type="DoxProtectionKind" /> + </xsd:complexType> + + <xsd:complexType name="listofallmembersType"> + <xsd:sequence> + <xsd:element name="member" type="memberRefType" minOccurs="0" maxOccurs="unbounded" /> + </xsd:sequence> + </xsd:complexType> + + <xsd:complexType name="memberRefType"> + <xsd:sequence> + <xsd:element name="scope" /> + <xsd:element name="name" /> + </xsd:sequence> + <xsd:attribute name="refid" type="xsd:string" /> + <xsd:attribute name="prot" type="DoxProtectionKind" /> + <xsd:attribute name="virt" type="DoxVirtualKind" /> + <xsd:attribute name="ambiguityscope" type="xsd:string" /> + </xsd:complexType> + + <xsd:complexType name="compoundRefType"> + <xsd:simpleContent> + <xsd:extension base="xsd:string"> + <xsd:attribute name="refid" type="xsd:string" use="optional" /> + <xsd:attribute name="prot" type="DoxProtectionKind" /> + <xsd:attribute name="virt" type="DoxVirtualKind" /> + </xsd:extension> + </xsd:simpleContent> + </xsd:complexType> + + <xsd:complexType name="reimplementType"> + <xsd:simpleContent> + <xsd:extension base="xsd:string"> + <xsd:attribute name="refid" type="xsd:string" /> + </xsd:extension> + </xsd:simpleContent> + </xsd:complexType> + + <xsd:complexType name="incType"> + <xsd:simpleContent> + <xsd:extension base="xsd:string"> + <xsd:attribute name="refid" type="xsd:string" /> + <xsd:attribute name="local" type="DoxBool" /> + </xsd:extension> + </xsd:simpleContent> + </xsd:complexType> + + <xsd:complexType name="refType"> + <xsd:simpleContent> + <xsd:extension base="xsd:string"> + <xsd:attribute name="refid" type="xsd:string" /> + <xsd:attribute name="prot" type="DoxProtectionKind" use="optional"/> + </xsd:extension> + </xsd:simpleContent> + </xsd:complexType> + + <xsd:complexType name="refTextType"> + <xsd:simpleContent> + <xsd:extension base="xsd:string"> + <xsd:attribute name="refid" type="xsd:string" /> + <xsd:attribute name="kindref" type="DoxRefKind" /> + <xsd:attribute name="external" type="xsd:string" use="optional"/> + <xsd:attribute name="tooltip" type="xsd:string" use="optional"/> + </xsd:extension> + </xsd:simpleContent> + </xsd:complexType> + + <xsd:complexType name="sectiondefType"> + <xsd:sequence> + <xsd:element name="header" type="xsd:string" minOccurs="0" /> + <xsd:element name="description" type="descriptionType" minOccurs="0" /> + <xsd:element name="memberdef" type="memberdefType" maxOccurs="unbounded" /> + </xsd:sequence> + <xsd:attribute name="kind" type="DoxSectionKind" /> + </xsd:complexType> + + <xsd:complexType name="memberdefType"> + <xsd:sequence> + <xsd:element name="templateparamlist" type="templateparamlistType" minOccurs="0" /> + <xsd:element name="type" type="linkedTextType" minOccurs="0" /> + <xsd:element name="definition" minOccurs="0" /> + <xsd:element name="argsstring" minOccurs="0" /> + <xsd:element name="name" /> + <xsd:element name="read" minOccurs="0" /> + <xsd:element name="write" minOccurs="0" /> + <xsd:element name="bitfield" minOccurs="0" /> + <xsd:element name="reimplements" type="reimplementType" minOccurs="0" maxOccurs="unbounded" /> + <xsd:element name="reimplementedby" type="reimplementType" minOccurs="0" maxOccurs="unbounded" /> + <xsd:element name="param" type="paramType" minOccurs="0" maxOccurs="unbounded" /> + <xsd:element name="enumvalue" type="enumvalueType" minOccurs="0" maxOccurs="unbounded" /> + <xsd:element name="initializer" type="linkedTextType" minOccurs="0" /> + <xsd:element name="exceptions" type="linkedTextType" minOccurs="0" /> + <xsd:element name="briefdescription" type="descriptionType" minOccurs="0" /> + <xsd:element name="detaileddescription" type="descriptionType" minOccurs="0" /> + <xsd:element name="inbodydescription" type="descriptionType" minOccurs="0" /> + <xsd:element name="location" type="locationType" /> + <xsd:element name="references" type="referenceType" minOccurs="0" maxOccurs="unbounded" /> + <xsd:element name="referencedby" type="referenceType" minOccurs="0" maxOccurs="unbounded" /> + </xsd:sequence> + <xsd:attribute name="kind" type="DoxMemberKind" /> + <xsd:attribute name="id" type="xsd:string" /> + <xsd:attribute name="prot" type="DoxProtectionKind" /> + <xsd:attribute name="static" type="DoxBool" /> + <xsd:attribute name="const" type="DoxBool" /> + <xsd:attribute name="explicit" type="DoxBool" /> + <xsd:attribute name="inline" type="DoxBool" /> + <xsd:attribute name="virt" type="DoxVirtualKind" /> + <xsd:attribute name="volatile" type="DoxBool" /> + <xsd:attribute name="mutable" type="DoxBool" /> + <!-- Qt property --> + <xsd:attribute name="readable" type="DoxBool" use="optional"/> + <xsd:attribute name="writable" type="DoxBool" use="optional"/> + <!-- C++/CLI variable --> + <xsd:attribute name="initonly" type="DoxBool" use="optional"/> + <!-- C++/CLI and C# property --> + <xsd:attribute name="settable" type="DoxBool" use="optional"/> + <xsd:attribute name="gettable" type="DoxBool" use="optional"/> + <!-- C++/CLI function --> + <xsd:attribute name="final" type="DoxBool" use="optional"/> + <xsd:attribute name="sealed" type="DoxBool" use="optional"/> + <xsd:attribute name="new" type="DoxBool" use="optional"/> + <!-- C++/CLI event --> + <xsd:attribute name="add" type="DoxBool" use="optional"/> + <xsd:attribute name="remove" type="DoxBool" use="optional"/> + <xsd:attribute name="raise" type="DoxBool" use="optional"/> + <!-- Objective-C 2.0 protocol method --> + <xsd:attribute name="optional" type="DoxBool" use="optional"/> + <xsd:attribute name="required" type="DoxBool" use="optional"/> + <!-- Objective-C 2.0 property accessor --> + <xsd:attribute name="accessor" type="DoxAccessor" use="optional"/> + </xsd:complexType> + + <xsd:complexType name="descriptionType" mixed="true"> + <xsd:sequence> + <xsd:element name="title" type="xsd:string" minOccurs="0"/> + <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" /> + <xsd:element name="sect1" type="docSect1Type" minOccurs="0" maxOccurs="unbounded" /> + <xsd:element name="internal" type="docInternalType" minOccurs="0" /> + </xsd:sequence> + </xsd:complexType> + + <xsd:complexType name="enumvalueType" mixed="true"> + <xsd:sequence> + <xsd:element name="name" /> + <xsd:element name="initializer" type="linkedTextType" minOccurs="0" /> + <xsd:element name="briefdescription" type="descriptionType" minOccurs="0" /> + <xsd:element name="detaileddescription" type="descriptionType" minOccurs="0" /> + </xsd:sequence> + <xsd:attribute name="id" type="xsd:string" /> + <xsd:attribute name="prot" type="DoxProtectionKind" /> + </xsd:complexType> + + <xsd:complexType name="templateparamlistType"> + <xsd:sequence> + <xsd:element name="param" type="paramType" minOccurs="0" maxOccurs="unbounded" /> + </xsd:sequence> + </xsd:complexType> + + <xsd:complexType name="paramType"> + <xsd:sequence> + <xsd:element name="type" type="linkedTextType" minOccurs="0" /> + <xsd:element name="declname" minOccurs="0" /> + <xsd:element name="defname" minOccurs="0" /> + <xsd:element name="array" minOccurs="0" /> + <xsd:element name="defval" type="linkedTextType" minOccurs="0" /> + <xsd:element name="briefdescription" type="descriptionType" minOccurs="0" /> + </xsd:sequence> + </xsd:complexType> + + <xsd:complexType name="linkedTextType" mixed="true"> + <xsd:sequence> + <xsd:element name="ref" type="refTextType" minOccurs="0" maxOccurs="unbounded" /> + </xsd:sequence> + </xsd:complexType> + + <xsd:complexType name="graphType"> + <xsd:sequence> + <xsd:element name="node" type="nodeType" maxOccurs="unbounded" /> + </xsd:sequence> + </xsd:complexType> + + <xsd:complexType name="nodeType"> + <xsd:sequence> + <xsd:element name="label" /> + <xsd:element name="link" type="linkType" minOccurs="0" /> + <xsd:element name="childnode" type="childnodeType" minOccurs="0" maxOccurs="unbounded" /> + </xsd:sequence> + <xsd:attribute name="id" type="xsd:string" /> + </xsd:complexType> + + <xsd:complexType name="childnodeType"> + <xsd:sequence> + <xsd:element name="edgelabel" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attribute name="refid" type="xsd:string" /> + <xsd:attribute name="relation" type="DoxGraphRelation" /> + </xsd:complexType> + + <xsd:complexType name="linkType"> + <xsd:attribute name="refid" type="xsd:string" /> + <xsd:attribute name="external" type="xsd:string" use="optional"/> + </xsd:complexType> + + <xsd:complexType name="listingType"> + <xsd:sequence> + <xsd:element name="codeline" type="codelineType" minOccurs="0" maxOccurs="unbounded" /> + </xsd:sequence> + </xsd:complexType> + + <xsd:complexType name="codelineType"> + <xsd:sequence> + <xsd:element name="highlight" type="highlightType" minOccurs="0" maxOccurs="unbounded" /> + </xsd:sequence> + <xsd:attribute name="lineno" type="xsd:integer" /> + <xsd:attribute name="refid" type="xsd:string" /> + <xsd:attribute name="refkind" type="DoxRefKind" /> + <xsd:attribute name="external" type="DoxBool" /> + </xsd:complexType> + + <xsd:complexType name="highlightType" mixed="true"> + <xsd:choice minOccurs="0" maxOccurs="unbounded"> + <xsd:element name="sp" /> + <xsd:element name="ref" type="refTextType" /> + </xsd:choice> + <xsd:attribute name="class" type="DoxHighlightClass" /> + </xsd:complexType> + + <xsd:complexType name="referenceType" mixed="true"> + <xsd:attribute name="refid" type="xsd:string" /> + <xsd:attribute name="compoundref" type="xsd:string" use="optional" /> + <xsd:attribute name="startline" type="xsd:integer" /> + <xsd:attribute name="endline" type="xsd:integer" /> + </xsd:complexType> + + <xsd:complexType name="locationType"> + <xsd:attribute name="file" type="xsd:string" /> + <xsd:attribute name="line" type="xsd:integer" /> + <xsd:attribute name="bodyfile" type="xsd:string" /> + <xsd:attribute name="bodystart" type="xsd:integer" /> + <xsd:attribute name="bodyend" type="xsd:integer" /> + </xsd:complexType> + + <xsd:complexType name="docSect1Type" mixed="true"> + <xsd:sequence> + <xsd:element name="title" type="xsd:string" /> + <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" /> + <xsd:element name="sect2" type="docSect2Type" minOccurs="0" maxOccurs="unbounded" /> + <xsd:element name="internal" type="docInternalS1Type" minOccurs="0" /> + </xsd:sequence> + <xsd:attribute name="id" type="xsd:string" /> + </xsd:complexType> + + <xsd:complexType name="docSect2Type" mixed="true"> + <xsd:sequence> + <xsd:element name="title" type="xsd:string" /> + <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" /> + <xsd:element name="sect3" type="docSect3Type" minOccurs="0" maxOccurs="unbounded" /> + <xsd:element name="internal" type="docInternalS2Type" minOccurs="0" /> + </xsd:sequence> + <xsd:attribute name="id" type="xsd:string" /> + </xsd:complexType> + + <xsd:complexType name="docSect3Type" mixed="true"> + <xsd:sequence> + <xsd:element name="title" type="xsd:string" /> + <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" /> + <xsd:element name="sect4" type="docSect4Type" minOccurs="0" maxOccurs="unbounded" /> + <xsd:element name="internal" type="docInternalS3Type" minOccurs="0" /> + </xsd:sequence> + <xsd:attribute name="id" type="xsd:string" /> + </xsd:complexType> + + <xsd:complexType name="docSect4Type" mixed="true"> + <xsd:sequence> + <xsd:element name="title" type="xsd:string" /> + <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" /> + <xsd:element name="internal" type="docInternalS4Type" minOccurs="0" /> + </xsd:sequence> + <xsd:attribute name="id" type="xsd:string" /> + </xsd:complexType> + + <xsd:complexType name="docInternalType" mixed="true"> + <xsd:sequence> + <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" /> + <xsd:element name="sect1" type="docSect1Type" minOccurs="0" maxOccurs="unbounded" /> + </xsd:sequence> + </xsd:complexType> + + <xsd:complexType name="docInternalS1Type" mixed="true"> + <xsd:sequence> + <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" /> + <xsd:element name="sect2" type="docSect2Type" minOccurs="0" maxOccurs="unbounded" /> + </xsd:sequence> + </xsd:complexType> + + <xsd:complexType name="docInternalS2Type" mixed="true"> + <xsd:sequence> + <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" /> + <xsd:element name="sect3" type="docSect3Type" minOccurs="0" maxOccurs="unbounded" /> + </xsd:sequence> + </xsd:complexType> + + <xsd:complexType name="docInternalS3Type" mixed="true"> + <xsd:sequence> + <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" /> + <xsd:element name="sect3" type="docSect4Type" minOccurs="0" maxOccurs="unbounded" /> + </xsd:sequence> + </xsd:complexType> + + <xsd:complexType name="docInternalS4Type" mixed="true"> + <xsd:sequence> + <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" /> + </xsd:sequence> + </xsd:complexType> + + <xsd:group name="docTitleCmdGroup"> + <xsd:choice> + <xsd:element name="ulink" type="docURLLink" /> + <xsd:element name="bold" type="docMarkupType" /> + <xsd:element name="emphasis" type="docMarkupType" /> + <xsd:element name="computeroutput" type="docMarkupType" /> + <xsd:element name="subscript" type="docMarkupType" /> + <xsd:element name="superscript" type="docMarkupType" /> + <xsd:element name="center" type="docMarkupType" /> + <xsd:element name="small" type="docMarkupType" /> + <xsd:element name="htmlonly" type="xsd:string" /> + <xsd:element name="latexonly" type="xsd:string" /> + <xsd:element name="dot" type="xsd:string" /> + <xsd:element name="anchor" type="docAnchorType" /> + <xsd:element name="formula" type="docFormulaType" /> + <xsd:element name="ref" type="docRefTextType" /> + <xsd:element name="copy" type="docEmptyType" /> + <xsd:element name="trademark" type="docEmptyType" /> + <xsd:element name="registered" type="docEmptyType" /> + <xsd:element name="lsquo" type="docEmptyType" /> + <xsd:element name="rsquo" type="docEmptyType" /> + <xsd:element name="ldquo" type="docEmptyType" /> + <xsd:element name="rdquo" type="docEmptyType" /> + <xsd:element name="ndash" type="docEmptyType" /> + <xsd:element name="mdash" type="docEmptyType" /> + <xsd:element name="umlaut" type="docCharType" /> + <xsd:element name="acute" type="docCharType" /> + <xsd:element name="grave" type="docCharType" /> + <xsd:element name="circ" type="docCharType" /> + <xsd:element name="slash" type="docCharType" /> + <xsd:element name="tilde" type="docCharType" /> + <xsd:element name="cedil" type="docCharType" /> + <xsd:element name="ring" type="docCharType" /> + <xsd:element name="szlig" type="docEmptyType" /> + <xsd:element name="nonbreakablespace" type="docEmptyType" /> + </xsd:choice> + </xsd:group> + + <xsd:complexType name="docTitleType" mixed="true"> + <xsd:group ref="docTitleCmdGroup" minOccurs="0" maxOccurs="unbounded" /> + </xsd:complexType> + + <xsd:group name="docCmdGroup"> + <xsd:choice> + <xsd:group ref="docTitleCmdGroup"/> + <xsd:element name="linebreak" type="docEmptyType" /> + <xsd:element name="hruler" type="docEmptyType" /> + <xsd:element name="preformatted" type="docMarkupType" /> + <xsd:element name="programlisting" type="listingType" /> + <xsd:element name="verbatim" type="xsd:string" /> + <xsd:element name="indexentry" type="docIndexEntryType" /> + <xsd:element name="orderedlist" type="docListType" /> + <xsd:element name="itemizedlist" type="docListType" /> + <xsd:element name="simplesect" type="docSimpleSectType" /> + <xsd:element name="title" type="docTitleType" /> + <xsd:element name="variablelist" type="docVariableListType" /> + <xsd:element name="table" type="docTableType" /> + <xsd:element name="heading" type="docHeadingType" /> + <xsd:element name="image" type="docImageType" /> + <xsd:element name="dotfile" type="docDotFileType" /> + <xsd:element name="toclist" type="docTocListType" /> + <xsd:element name="language" type="docLanguageType" /> + <xsd:element name="parameterlist" type="docParamListType" /> + <xsd:element name="xrefsect" type="docXRefSectType" /> + <xsd:element name="copydoc" type="docCopyType" /> + <xsd:element name="blockquote" type="docBlockQuoteType" /> + </xsd:choice> + </xsd:group> + + <xsd:complexType name="docParaType" mixed="true"> + <xsd:group ref="docCmdGroup" minOccurs="0" maxOccurs="unbounded" /> + </xsd:complexType> + + <xsd:complexType name="docMarkupType" mixed="true"> + <xsd:group ref="docCmdGroup" minOccurs="0" maxOccurs="unbounded" /> + </xsd:complexType> + + <xsd:complexType name="docURLLink" mixed="true"> + <xsd:group ref="docTitleCmdGroup" minOccurs="0" maxOccurs="unbounded" /> + <xsd:attribute name="url" type="xsd:string" /> + </xsd:complexType> + + <xsd:complexType name="docAnchorType" mixed="true"> + <xsd:attribute name="id" type="xsd:string" /> + </xsd:complexType> + + <xsd:complexType name="docFormulaType" mixed="true"> + <xsd:attribute name="id" type="xsd:string" /> + </xsd:complexType> + + <xsd:complexType name="docIndexEntryType"> + <xsd:sequence> + <xsd:element name="primaryie" type="xsd:string" /> + <xsd:element name="secondaryie" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + + <xsd:complexType name="docListType"> + <xsd:sequence> + <xsd:element name="listitem" type="docListItemType" maxOccurs="unbounded" /> + </xsd:sequence> + </xsd:complexType> + + <xsd:complexType name="docListItemType"> + <xsd:sequence> + <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" /> + </xsd:sequence> + </xsd:complexType> + + <xsd:complexType name="docSimpleSectType"> + <xsd:sequence> + <xsd:element name="title" type="docTitleType" minOccurs="0" /> + <xsd:sequence minOccurs="0" maxOccurs="unbounded"> + <xsd:element name="para" type="docParaType" minOccurs="1" maxOccurs="unbounded" /> + <xsd:element name="simplesectsep" type="docEmptyType" minOccurs="0"/> + </xsd:sequence> + </xsd:sequence> + <xsd:attribute name="kind" type="DoxSimpleSectKind" /> + </xsd:complexType> + + <xsd:complexType name="docVarListEntryType"> + <xsd:sequence> + <xsd:element name="term" type="docTitleType" /> + </xsd:sequence> + </xsd:complexType> + + <xsd:group name="docVariableListGroup"> + <xsd:sequence> + <xsd:element name="varlistentry" type="docVarListEntryType" /> + <xsd:element name="listitem" type="docListItemType" /> + </xsd:sequence> + </xsd:group> + + <xsd:complexType name="docVariableListType"> + <xsd:sequence> + <xsd:group ref="docVariableListGroup" maxOccurs="unbounded" /> + </xsd:sequence> + </xsd:complexType> + + <xsd:complexType name="docRefTextType" mixed="true"> + <xsd:group ref="docTitleCmdGroup" minOccurs="0" maxOccurs="unbounded" /> + <xsd:attribute name="refid" type="xsd:string" /> + <xsd:attribute name="kindref" type="DoxRefKind" /> + <xsd:attribute name="external" type="xsd:string" /> + </xsd:complexType> + + <xsd:complexType name="docTableType"> + <xsd:sequence> + <xsd:element name="row" type="docRowType" minOccurs="0" maxOccurs="unbounded" /> + <xsd:element name="caption" type="docCaptionType" minOccurs="0" /> + </xsd:sequence> + <xsd:attribute name="rows" type="xsd:integer" /> + <xsd:attribute name="cols" type="xsd:integer" /> + </xsd:complexType> + + <xsd:complexType name="docRowType"> + <xsd:sequence> + <xsd:element name="entry" type="docEntryType" minOccurs="0" maxOccurs="unbounded" /> + </xsd:sequence> + </xsd:complexType> + + <xsd:complexType name="docEntryType"> + <xsd:sequence> + <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" /> + </xsd:sequence> + <xsd:attribute name="thead" type="DoxBool" /> + </xsd:complexType> + + <xsd:complexType name="docCaptionType" mixed="true"> + <xsd:group ref="docTitleCmdGroup" minOccurs="0" maxOccurs="unbounded" /> + </xsd:complexType> + + <xsd:complexType name="docHeadingType" mixed="true"> + <xsd:group ref="docTitleCmdGroup" minOccurs="0" maxOccurs="unbounded" /> + <xsd:attribute name="level" type="xsd:integer" /> <!-- todo: range 1-6 --> + </xsd:complexType> + + <xsd:complexType name="docImageType" mixed="true"> + <xsd:group ref="docTitleCmdGroup" minOccurs="0" maxOccurs="unbounded" /> + <xsd:attribute name="type" type="DoxImageKind" /> + <xsd:attribute name="name" type="xsd:string" /> + <xsd:attribute name="width" type="xsd:string" /> + <xsd:attribute name="height" type="xsd:string" /> + </xsd:complexType> + + <xsd:complexType name="docDotFileType" mixed="true"> + <xsd:group ref="docTitleCmdGroup" minOccurs="0" maxOccurs="unbounded" /> + <xsd:attribute name="name" type="xsd:string" /> + </xsd:complexType> + + <xsd:complexType name="docTocItemType" mixed="true"> + <xsd:group ref="docTitleCmdGroup" minOccurs="0" maxOccurs="unbounded" /> + <xsd:attribute name="id" type="xsd:string" /> + </xsd:complexType> + + <xsd:complexType name="docTocListType"> + <xsd:sequence> + <xsd:element name="tocitem" type="docTocItemType" minOccurs="0" maxOccurs="unbounded" /> + </xsd:sequence> + </xsd:complexType> + + <xsd:complexType name="docLanguageType"> + <xsd:sequence> + <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" /> + </xsd:sequence> + <xsd:attribute name="langid" type="xsd:string" /> + </xsd:complexType> + + <xsd:complexType name="docParamListType"> + <xsd:sequence> + <xsd:element name="parameteritem" type="docParamListItem" minOccurs="0" maxOccurs="unbounded" /> + </xsd:sequence> + <xsd:attribute name="kind" type="DoxParamListKind" /> + </xsd:complexType> + + <xsd:complexType name="docParamListItem"> + <xsd:sequence> + <xsd:element name="parameternamelist" type="docParamNameList" minOccurs="0" maxOccurs="unbounded" /> + <xsd:element name="parameterdescription" type="descriptionType" /> + </xsd:sequence> + </xsd:complexType> + + <xsd:complexType name="docParamNameList"> + <xsd:sequence> + <xsd:element name="parametertype" type="docParamType" minOccurs="0" maxOccurs="unbounded" /> + <xsd:element name="parametername" type="docParamName" minOccurs="0" maxOccurs="unbounded" /> + </xsd:sequence> + </xsd:complexType> + + <xsd:complexType name="docParamType" mixed="true"> + <xsd:sequence> + <xsd:element name="ref" type="refTextType" minOccurs="0" maxOccurs="1" /> + </xsd:sequence> + </xsd:complexType> + + <xsd:complexType name="docParamName" mixed="true"> + <xsd:sequence> + <xsd:element name="ref" type="refTextType" minOccurs="0" maxOccurs="1" /> + </xsd:sequence> + <xsd:attribute name="direction" type="DoxParamDir" use="optional" /> + </xsd:complexType> + + <xsd:complexType name="docXRefSectType"> + <xsd:sequence> + <xsd:element name="xreftitle" type="xsd:string" minOccurs="0" maxOccurs="unbounded" /> + <xsd:element name="xrefdescription" type="descriptionType" /> + </xsd:sequence> + <xsd:attribute name="id" type="xsd:string" /> + </xsd:complexType> + + <xsd:complexType name="docCopyType"> + <xsd:sequence> + <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" /> + <xsd:element name="sect1" type="docSect1Type" minOccurs="0" maxOccurs="unbounded" /> + <xsd:element name="internal" type="docInternalType" minOccurs="0" /> + </xsd:sequence> + <xsd:attribute name="link" type="xsd:string" /> + </xsd:complexType> + + <xsd:complexType name="docBlockQuoteType"> + <xsd:sequence> + <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" /> + </xsd:sequence> + </xsd:complexType> + + <xsd:complexType name="docCharType"> + <xsd:attribute name="char" type="DoxCharRange"/> + </xsd:complexType> + + <xsd:complexType name="docEmptyType"/> + + <!-- Simple types --> + + <xsd:simpleType name="DoxBool"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="yes" /> + <xsd:enumeration value="no" /> + </xsd:restriction> + </xsd:simpleType> + + <xsd:simpleType name="DoxGraphRelation"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="include" /> + <xsd:enumeration value="usage" /> + <xsd:enumeration value="template-instance" /> + <xsd:enumeration value="public-inheritance" /> + <xsd:enumeration value="protected-inheritance" /> + <xsd:enumeration value="private-inheritance" /> + </xsd:restriction> + </xsd:simpleType> + + <xsd:simpleType name="DoxRefKind"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="compound" /> + <xsd:enumeration value="member" /> + </xsd:restriction> + </xsd:simpleType> + + <xsd:simpleType name="DoxMemberKind"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="define" /> + <xsd:enumeration value="property" /> + <xsd:enumeration value="event" /> + <xsd:enumeration value="variable" /> + <xsd:enumeration value="typedef" /> + <xsd:enumeration value="enum" /> + <xsd:enumeration value="function" /> + <xsd:enumeration value="signal" /> + <xsd:enumeration value="prototype" /> + <xsd:enumeration value="friend" /> + <xsd:enumeration value="dcop" /> + <xsd:enumeration value="slot" /> + </xsd:restriction> + </xsd:simpleType> + + <xsd:simpleType name="DoxProtectionKind"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="public" /> + <xsd:enumeration value="protected" /> + <xsd:enumeration value="private" /> + <xsd:enumeration value="package" /> + </xsd:restriction> + </xsd:simpleType> + + <xsd:simpleType name="DoxVirtualKind"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="non-virtual" /> + <xsd:enumeration value="virtual" /> + <xsd:enumeration value="pure-virtual" /> + </xsd:restriction> + </xsd:simpleType> + + <xsd:simpleType name="DoxCompoundKind"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="class" /> + <xsd:enumeration value="struct" /> + <xsd:enumeration value="union" /> + <xsd:enumeration value="interface" /> + <xsd:enumeration value="protocol" /> + <xsd:enumeration value="category" /> + <xsd:enumeration value="exception" /> + <xsd:enumeration value="file" /> + <xsd:enumeration value="namespace" /> + <xsd:enumeration value="group" /> + <xsd:enumeration value="page" /> + <xsd:enumeration value="example" /> + <xsd:enumeration value="dir" /> + </xsd:restriction> + </xsd:simpleType> + + <xsd:simpleType name="DoxSectionKind"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="user-defined" /> + <xsd:enumeration value="public-type" /> + <xsd:enumeration value="public-func" /> + <xsd:enumeration value="public-attrib" /> + <xsd:enumeration value="public-slot" /> + <xsd:enumeration value="signal" /> + <xsd:enumeration value="dcop-func" /> + <xsd:enumeration value="property" /> + <xsd:enumeration value="event" /> + <xsd:enumeration value="public-static-func" /> + <xsd:enumeration value="public-static-attrib" /> + <xsd:enumeration value="protected-type" /> + <xsd:enumeration value="protected-func" /> + <xsd:enumeration value="protected-attrib" /> + <xsd:enumeration value="protected-slot" /> + <xsd:enumeration value="protected-static-func" /> + <xsd:enumeration value="protected-static-attrib" /> + <xsd:enumeration value="package-type" /> + <xsd:enumeration value="package-func" /> + <xsd:enumeration value="package-attrib" /> + <xsd:enumeration value="package-static-func" /> + <xsd:enumeration value="package-static-attrib" /> + <xsd:enumeration value="private-type" /> + <xsd:enumeration value="private-func" /> + <xsd:enumeration value="private-attrib" /> + <xsd:enumeration value="private-slot" /> + <xsd:enumeration value="private-static-func" /> + <xsd:enumeration value="private-static-attrib" /> + <xsd:enumeration value="friend" /> + <xsd:enumeration value="related" /> + <xsd:enumeration value="define" /> + <xsd:enumeration value="prototype" /> + <xsd:enumeration value="typedef" /> + <xsd:enumeration value="enum" /> + <xsd:enumeration value="func" /> + <xsd:enumeration value="var" /> + </xsd:restriction> + </xsd:simpleType> + + <xsd:simpleType name="DoxHighlightClass"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="comment" /> + <xsd:enumeration value="normal" /> + <xsd:enumeration value="preprocessor" /> + <xsd:enumeration value="keyword" /> + <xsd:enumeration value="keywordtype" /> + <xsd:enumeration value="keywordflow" /> + <xsd:enumeration value="stringliteral" /> + <xsd:enumeration value="charliteral" /> + </xsd:restriction> + </xsd:simpleType> + + <xsd:simpleType name="DoxSimpleSectKind"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="see" /> + <xsd:enumeration value="return" /> + <xsd:enumeration value="author" /> + <xsd:enumeration value="authors" /> + <xsd:enumeration value="version" /> + <xsd:enumeration value="since" /> + <xsd:enumeration value="date" /> + <xsd:enumeration value="note" /> + <xsd:enumeration value="warning" /> + <xsd:enumeration value="pre" /> + <xsd:enumeration value="post" /> + <xsd:enumeration value="copyright" /> + <xsd:enumeration value="invariant" /> + <xsd:enumeration value="remark" /> + <xsd:enumeration value="attention" /> + <xsd:enumeration value="par" /> + <xsd:enumeration value="rcs" /> + </xsd:restriction> + </xsd:simpleType> + + <xsd:simpleType name="DoxVersionNumber"> + <xsd:restriction base="xsd:string"> + <xsd:pattern value="\d+\.\d+.*" /> + </xsd:restriction> + </xsd:simpleType> + + <xsd:simpleType name="DoxImageKind"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="html" /> + <xsd:enumeration value="latex" /> + <xsd:enumeration value="rtf" /> + </xsd:restriction> + </xsd:simpleType> + + <xsd:simpleType name="DoxParamListKind"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="param" /> + <xsd:enumeration value="retval" /> + <xsd:enumeration value="exception" /> + <xsd:enumeration value="templateparam" /> + </xsd:restriction> + </xsd:simpleType> + + <xsd:simpleType name="DoxCharRange"> + <xsd:restriction base="xsd:string"> + <xsd:pattern value="[aeiouncAEIOUNC]" /> + </xsd:restriction> + </xsd:simpleType> + + <xsd:simpleType name="DoxParamDir"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="in"/> + <xsd:enumeration value="out"/> + <xsd:enumeration value="inout"/> + </xsd:restriction> + </xsd:simpleType> + + <xsd:simpleType name="DoxAccessor"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="retain"/> + <xsd:enumeration value="copy"/> + <xsd:enumeration value="assign"/> + </xsd:restriction> + </xsd:simpleType> + +</xsd:schema> + diff --git a/trunk/src/compound_xsd.h b/trunk/src/compound_xsd.h new file mode 100644 index 0000000..6531857 --- /dev/null +++ b/trunk/src/compound_xsd.h @@ -0,0 +1,829 @@ +"<?xml version='1.0' encoding='utf-8' ?>\n" +"<xsd:schema xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">\n" +" <xsd:element name=\"doxygen\" type=\"DoxygenType\"/>\n" +"\n" +" <!-- Complex types -->\n" +"\n" +" <xsd:complexType name=\"DoxygenType\">\n" +" <xsd:sequence maxOccurs=\"unbounded\">\n" +" <xsd:element name=\"compounddef\" type=\"compounddefType\" minOccurs=\"0\" />\n" +" </xsd:sequence>\n" +" <xsd:attribute name=\"version\" type=\"DoxVersionNumber\" use=\"required\" />\n" +" </xsd:complexType>\n" +"\n" +" <xsd:complexType name=\"compounddefType\">\n" +" <xsd:sequence>\n" +" <xsd:element name=\"compoundname\" type=\"xsd:string\"/>\n" +" <xsd:element name=\"title\" type=\"xsd:string\" minOccurs=\"0\" />\n" +" <xsd:element name=\"basecompoundref\" type=\"compoundRefType\" minOccurs=\"0\" maxOccurs=\"unbounded\" />\n" +" <xsd:element name=\"derivedcompoundref\" type=\"compoundRefType\" minOccurs=\"0\" maxOccurs=\"unbounded\" />\n" +" <xsd:element name=\"includes\" type=\"incType\" minOccurs=\"0\" maxOccurs=\"unbounded\" />\n" +" <xsd:element name=\"includedby\" type=\"incType\" minOccurs=\"0\" maxOccurs=\"unbounded\" />\n" +" <xsd:element name=\"incdepgraph\" type=\"graphType\" minOccurs=\"0\" />\n" +" <xsd:element name=\"invincdepgraph\" type=\"graphType\" minOccurs=\"0\" />\n" +" <xsd:element name=\"innerdir\" type=\"refType\" minOccurs=\"0\" maxOccurs=\"unbounded\" />\n" +" <xsd:element name=\"innerfile\" type=\"refType\" minOccurs=\"0\" maxOccurs=\"unbounded\" />\n" +" <xsd:element name=\"innerclass\" type=\"refType\" minOccurs=\"0\" maxOccurs=\"unbounded\" />\n" +" <xsd:element name=\"innernamespace\" type=\"refType\" minOccurs=\"0\" maxOccurs=\"unbounded\" />\n" +" <xsd:element name=\"innerpage\" type=\"refType\" minOccurs=\"0\" maxOccurs=\"unbounded\" />\n" +" <xsd:element name=\"innergroup\" type=\"refType\" minOccurs=\"0\" maxOccurs=\"unbounded\" />\n" +" <xsd:element name=\"templateparamlist\" type=\"templateparamlistType\" minOccurs=\"0\" />\n" +" <xsd:element name=\"sectiondef\" type=\"sectiondefType\" minOccurs=\"0\" maxOccurs=\"unbounded\" />\n" +" <xsd:element name=\"briefdescription\" type=\"descriptionType\" minOccurs=\"0\" />\n" +" <xsd:element name=\"detaileddescription\" type=\"descriptionType\" minOccurs=\"0\" />\n" +" <xsd:element name=\"inheritancegraph\" type=\"graphType\" minOccurs=\"0\" />\n" +" <xsd:element name=\"collaborationgraph\" type=\"graphType\" minOccurs=\"0\" />\n" +" <xsd:element name=\"programlisting\" type=\"listingType\" minOccurs=\"0\" />\n" +" <xsd:element name=\"location\" type=\"locationType\" minOccurs=\"0\" />\n" +" <xsd:element name=\"listofallmembers\" type=\"listofallmembersType\" minOccurs=\"0\" />\n" +" </xsd:sequence>\n" +" <xsd:attribute name=\"id\" type=\"xsd:string\" />\n" +" <xsd:attribute name=\"kind\" type=\"DoxCompoundKind\" />\n" +" <xsd:attribute name=\"prot\" type=\"DoxProtectionKind\" />\n" +" </xsd:complexType>\n" +"\n" +" <xsd:complexType name=\"listofallmembersType\">\n" +" <xsd:sequence>\n" +" <xsd:element name=\"member\" type=\"memberRefType\" minOccurs=\"0\" maxOccurs=\"unbounded\" />\n" +" </xsd:sequence>\n" +" </xsd:complexType>\n" +"\n" +" <xsd:complexType name=\"memberRefType\">\n" +" <xsd:sequence>\n" +" <xsd:element name=\"scope\" />\n" +" <xsd:element name=\"name\" />\n" +" </xsd:sequence>\n" +" <xsd:attribute name=\"refid\" type=\"xsd:string\" />\n" +" <xsd:attribute name=\"prot\" type=\"DoxProtectionKind\" />\n" +" <xsd:attribute name=\"virt\" type=\"DoxVirtualKind\" />\n" +" <xsd:attribute name=\"ambiguityscope\" type=\"xsd:string\" />\n" +" </xsd:complexType>\n" +"\n" +" <xsd:complexType name=\"compoundRefType\">\n" +" <xsd:simpleContent>\n" +" <xsd:extension base=\"xsd:string\">\n" +" <xsd:attribute name=\"refid\" type=\"xsd:string\" use=\"optional\" />\n" +" <xsd:attribute name=\"prot\" type=\"DoxProtectionKind\" />\n" +" <xsd:attribute name=\"virt\" type=\"DoxVirtualKind\" />\n" +" </xsd:extension>\n" +" </xsd:simpleContent>\n" +" </xsd:complexType>\n" +"\n" +" <xsd:complexType name=\"reimplementType\">\n" +" <xsd:simpleContent>\n" +" <xsd:extension base=\"xsd:string\">\n" +" <xsd:attribute name=\"refid\" type=\"xsd:string\" />\n" +" </xsd:extension>\n" +" </xsd:simpleContent>\n" +" </xsd:complexType>\n" +"\n" +" <xsd:complexType name=\"incType\">\n" +" <xsd:simpleContent>\n" +" <xsd:extension base=\"xsd:string\">\n" +" <xsd:attribute name=\"refid\" type=\"xsd:string\" />\n" +" <xsd:attribute name=\"local\" type=\"DoxBool\" />\n" +" </xsd:extension>\n" +" </xsd:simpleContent>\n" +" </xsd:complexType>\n" +"\n" +" <xsd:complexType name=\"refType\">\n" +" <xsd:simpleContent>\n" +" <xsd:extension base=\"xsd:string\">\n" +" <xsd:attribute name=\"refid\" type=\"xsd:string\" />\n" +" <xsd:attribute name=\"prot\" type=\"DoxProtectionKind\" use=\"optional\"/>\n" +" </xsd:extension>\n" +" </xsd:simpleContent>\n" +" </xsd:complexType>\n" +"\n" +" <xsd:complexType name=\"refTextType\">\n" +" <xsd:simpleContent>\n" +" <xsd:extension base=\"xsd:string\">\n" +" <xsd:attribute name=\"refid\" type=\"xsd:string\" />\n" +" <xsd:attribute name=\"kindref\" type=\"DoxRefKind\" />\n" +" <xsd:attribute name=\"external\" type=\"xsd:string\" use=\"optional\"/>\n" +" <xsd:attribute name=\"tooltip\" type=\"xsd:string\" use=\"optional\"/>\n" +" </xsd:extension>\n" +" </xsd:simpleContent>\n" +" </xsd:complexType>\n" +"\n" +" <xsd:complexType name=\"sectiondefType\">\n" +" <xsd:sequence>\n" +" <xsd:element name=\"header\" type=\"xsd:string\" minOccurs=\"0\" />\n" +" <xsd:element name=\"description\" type=\"descriptionType\" minOccurs=\"0\" />\n" +" <xsd:element name=\"memberdef\" type=\"memberdefType\" maxOccurs=\"unbounded\" />\n" +" </xsd:sequence>\n" +" <xsd:attribute name=\"kind\" type=\"DoxSectionKind\" />\n" +" </xsd:complexType>\n" +"\n" +" <xsd:complexType name=\"memberdefType\">\n" +" <xsd:sequence>\n" +" <xsd:element name=\"templateparamlist\" type=\"templateparamlistType\" minOccurs=\"0\" />\n" +" <xsd:element name=\"type\" type=\"linkedTextType\" minOccurs=\"0\" />\n" +" <xsd:element name=\"definition\" minOccurs=\"0\" />\n" +" <xsd:element name=\"argsstring\" minOccurs=\"0\" />\n" +" <xsd:element name=\"name\" />\n" +" <xsd:element name=\"read\" minOccurs=\"0\" />\n" +" <xsd:element name=\"write\" minOccurs=\"0\" />\n" +" <xsd:element name=\"bitfield\" minOccurs=\"0\" />\n" +" <xsd:element name=\"reimplements\" type=\"reimplementType\" minOccurs=\"0\" maxOccurs=\"unbounded\" />\n" +" <xsd:element name=\"reimplementedby\" type=\"reimplementType\" minOccurs=\"0\" maxOccurs=\"unbounded\" />\n" +" <xsd:element name=\"param\" type=\"paramType\" minOccurs=\"0\" maxOccurs=\"unbounded\" />\n" +" <xsd:element name=\"enumvalue\" type=\"enumvalueType\" minOccurs=\"0\" maxOccurs=\"unbounded\" />\n" +" <xsd:element name=\"initializer\" type=\"linkedTextType\" minOccurs=\"0\" />\n" +" <xsd:element name=\"exceptions\" type=\"linkedTextType\" minOccurs=\"0\" />\n" +" <xsd:element name=\"briefdescription\" type=\"descriptionType\" minOccurs=\"0\" />\n" +" <xsd:element name=\"detaileddescription\" type=\"descriptionType\" minOccurs=\"0\" />\n" +" <xsd:element name=\"inbodydescription\" type=\"descriptionType\" minOccurs=\"0\" />\n" +" <xsd:element name=\"location\" type=\"locationType\" />\n" +" <xsd:element name=\"references\" type=\"referenceType\" minOccurs=\"0\" maxOccurs=\"unbounded\" />\n" +" <xsd:element name=\"referencedby\" type=\"referenceType\" minOccurs=\"0\" maxOccurs=\"unbounded\" />\n" +" </xsd:sequence>\n" +" <xsd:attribute name=\"kind\" type=\"DoxMemberKind\" />\n" +" <xsd:attribute name=\"id\" type=\"xsd:string\" />\n" +" <xsd:attribute name=\"prot\" type=\"DoxProtectionKind\" />\n" +" <xsd:attribute name=\"static\" type=\"DoxBool\" />\n" +" <xsd:attribute name=\"const\" type=\"DoxBool\" />\n" +" <xsd:attribute name=\"explicit\" type=\"DoxBool\" />\n" +" <xsd:attribute name=\"inline\" type=\"DoxBool\" />\n" +" <xsd:attribute name=\"virt\" type=\"DoxVirtualKind\" />\n" +" <xsd:attribute name=\"volatile\" type=\"DoxBool\" />\n" +" <xsd:attribute name=\"mutable\" type=\"DoxBool\" />\n" +" <!-- Qt property -->\n" +" <xsd:attribute name=\"readable\" type=\"DoxBool\" use=\"optional\"/>\n" +" <xsd:attribute name=\"writable\" type=\"DoxBool\" use=\"optional\"/>\n" +" <!-- C++/CLI variable -->\n" +" <xsd:attribute name=\"initonly\" type=\"DoxBool\" use=\"optional\"/>\n" +" <!-- C++/CLI and C# property -->\n" +" <xsd:attribute name=\"settable\" type=\"DoxBool\" use=\"optional\"/>\n" +" <xsd:attribute name=\"gettable\" type=\"DoxBool\" use=\"optional\"/>\n" +" <!-- C++/CLI function -->\n" +" <xsd:attribute name=\"final\" type=\"DoxBool\" use=\"optional\"/>\n" +" <xsd:attribute name=\"sealed\" type=\"DoxBool\" use=\"optional\"/>\n" +" <xsd:attribute name=\"new\" type=\"DoxBool\" use=\"optional\"/>\n" +" <!-- C++/CLI event -->\n" +" <xsd:attribute name=\"add\" type=\"DoxBool\" use=\"optional\"/>\n" +" <xsd:attribute name=\"remove\" type=\"DoxBool\" use=\"optional\"/>\n" +" <xsd:attribute name=\"raise\" type=\"DoxBool\" use=\"optional\"/>\n" +" <!-- Objective-C 2.0 protocol method -->\n" +" <xsd:attribute name=\"optional\" type=\"DoxBool\" use=\"optional\"/>\n" +" <xsd:attribute name=\"required\" type=\"DoxBool\" use=\"optional\"/>\n" +" <!-- Objective-C 2.0 property accessor -->\n" +" <xsd:attribute name=\"accessor\" type=\"DoxAccessor\" use=\"optional\"/>\n" +" </xsd:complexType>\n" +"\n" +" <xsd:complexType name=\"descriptionType\" mixed=\"true\">\n" +" <xsd:sequence>\n" +" <xsd:element name=\"title\" type=\"xsd:string\" minOccurs=\"0\"/> \n" +" <xsd:element name=\"para\" type=\"docParaType\" minOccurs=\"0\" maxOccurs=\"unbounded\" />\n" +" <xsd:element name=\"sect1\" type=\"docSect1Type\" minOccurs=\"0\" maxOccurs=\"unbounded\" />\n" +" <xsd:element name=\"internal\" type=\"docInternalType\" minOccurs=\"0\" />\n" +" </xsd:sequence>\n" +" </xsd:complexType>\n" +"\n" +" <xsd:complexType name=\"enumvalueType\" mixed=\"true\">\n" +" <xsd:sequence>\n" +" <xsd:element name=\"name\" />\n" +" <xsd:element name=\"initializer\" type=\"linkedTextType\" minOccurs=\"0\" />\n" +" <xsd:element name=\"briefdescription\" type=\"descriptionType\" minOccurs=\"0\" />\n" +" <xsd:element name=\"detaileddescription\" type=\"descriptionType\" minOccurs=\"0\" />\n" +" </xsd:sequence>\n" +" <xsd:attribute name=\"id\" type=\"xsd:string\" />\n" +" <xsd:attribute name=\"prot\" type=\"DoxProtectionKind\" />\n" +" </xsd:complexType>\n" +"\n" +" <xsd:complexType name=\"templateparamlistType\">\n" +" <xsd:sequence>\n" +" <xsd:element name=\"param\" type=\"paramType\" minOccurs=\"0\" maxOccurs=\"unbounded\" />\n" +" </xsd:sequence>\n" +" </xsd:complexType>\n" +"\n" +" <xsd:complexType name=\"paramType\">\n" +" <xsd:sequence>\n" +" <xsd:element name=\"type\" type=\"linkedTextType\" minOccurs=\"0\" />\n" +" <xsd:element name=\"declname\" minOccurs=\"0\" />\n" +" <xsd:element name=\"defname\" minOccurs=\"0\" />\n" +" <xsd:element name=\"array\" minOccurs=\"0\" />\n" +" <xsd:element name=\"defval\" type=\"linkedTextType\" minOccurs=\"0\" />\n" +" <xsd:element name=\"briefdescription\" type=\"descriptionType\" minOccurs=\"0\" />\n" +" </xsd:sequence>\n" +" </xsd:complexType>\n" +"\n" +" <xsd:complexType name=\"linkedTextType\" mixed=\"true\">\n" +" <xsd:sequence>\n" +" <xsd:element name=\"ref\" type=\"refTextType\" minOccurs=\"0\" maxOccurs=\"unbounded\" />\n" +" </xsd:sequence>\n" +" </xsd:complexType>\n" +"\n" +" <xsd:complexType name=\"graphType\">\n" +" <xsd:sequence>\n" +" <xsd:element name=\"node\" type=\"nodeType\" maxOccurs=\"unbounded\" />\n" +" </xsd:sequence>\n" +" </xsd:complexType>\n" +"\n" +" <xsd:complexType name=\"nodeType\">\n" +" <xsd:sequence>\n" +" <xsd:element name=\"label\" />\n" +" <xsd:element name=\"link\" type=\"linkType\" minOccurs=\"0\" />\n" +" <xsd:element name=\"childnode\" type=\"childnodeType\" minOccurs=\"0\" maxOccurs=\"unbounded\" />\n" +" </xsd:sequence>\n" +" <xsd:attribute name=\"id\" type=\"xsd:string\" />\n" +" </xsd:complexType>\n" +"\n" +" <xsd:complexType name=\"childnodeType\">\n" +" <xsd:sequence>\n" +" <xsd:element name=\"edgelabel\" minOccurs=\"0\" maxOccurs=\"unbounded\"/>\n" +" </xsd:sequence>\n" +" <xsd:attribute name=\"refid\" type=\"xsd:string\" />\n" +" <xsd:attribute name=\"relation\" type=\"DoxGraphRelation\" />\n" +" </xsd:complexType>\n" +"\n" +" <xsd:complexType name=\"linkType\">\n" +" <xsd:attribute name=\"refid\" type=\"xsd:string\" />\n" +" <xsd:attribute name=\"external\" type=\"xsd:string\" use=\"optional\"/>\n" +" </xsd:complexType>\n" +"\n" +" <xsd:complexType name=\"listingType\">\n" +" <xsd:sequence>\n" +" <xsd:element name=\"codeline\" type=\"codelineType\" minOccurs=\"0\" maxOccurs=\"unbounded\" />\n" +" </xsd:sequence>\n" +" </xsd:complexType>\n" +"\n" +" <xsd:complexType name=\"codelineType\">\n" +" <xsd:sequence>\n" +" <xsd:element name=\"highlight\" type=\"highlightType\" minOccurs=\"0\" maxOccurs=\"unbounded\" />\n" +" </xsd:sequence>\n" +" <xsd:attribute name=\"lineno\" type=\"xsd:integer\" />\n" +" <xsd:attribute name=\"refid\" type=\"xsd:string\" />\n" +" <xsd:attribute name=\"refkind\" type=\"DoxRefKind\" />\n" +" <xsd:attribute name=\"external\" type=\"DoxBool\" />\n" +" </xsd:complexType>\n" +"\n" +" <xsd:complexType name=\"highlightType\" mixed=\"true\">\n" +" <xsd:choice minOccurs=\"0\" maxOccurs=\"unbounded\">\n" +" <xsd:element name=\"sp\" />\n" +" <xsd:element name=\"ref\" type=\"refTextType\" />\n" +" </xsd:choice>\n" +" <xsd:attribute name=\"class\" type=\"DoxHighlightClass\" />\n" +" </xsd:complexType>\n" +"\n" +" <xsd:complexType name=\"referenceType\" mixed=\"true\">\n" +" <xsd:attribute name=\"refid\" type=\"xsd:string\" />\n" +" <xsd:attribute name=\"compoundref\" type=\"xsd:string\" use=\"optional\" />\n" +" <xsd:attribute name=\"startline\" type=\"xsd:integer\" />\n" +" <xsd:attribute name=\"endline\" type=\"xsd:integer\" />\n" +" </xsd:complexType>\n" +"\n" +" <xsd:complexType name=\"locationType\">\n" +" <xsd:attribute name=\"file\" type=\"xsd:string\" />\n" +" <xsd:attribute name=\"line\" type=\"xsd:integer\" />\n" +" <xsd:attribute name=\"bodyfile\" type=\"xsd:string\" />\n" +" <xsd:attribute name=\"bodystart\" type=\"xsd:integer\" />\n" +" <xsd:attribute name=\"bodyend\" type=\"xsd:integer\" />\n" +" </xsd:complexType>\n" +"\n" +" <xsd:complexType name=\"docSect1Type\" mixed=\"true\">\n" +" <xsd:sequence>\n" +" <xsd:element name=\"title\" type=\"xsd:string\" /> \n" +" <xsd:element name=\"para\" type=\"docParaType\" minOccurs=\"0\" maxOccurs=\"unbounded\" />\n" +" <xsd:element name=\"sect2\" type=\"docSect2Type\" minOccurs=\"0\" maxOccurs=\"unbounded\" />\n" +" <xsd:element name=\"internal\" type=\"docInternalS1Type\" minOccurs=\"0\" />\n" +" </xsd:sequence>\n" +" <xsd:attribute name=\"id\" type=\"xsd:string\" />\n" +" </xsd:complexType>\n" +"\n" +" <xsd:complexType name=\"docSect2Type\" mixed=\"true\">\n" +" <xsd:sequence>\n" +" <xsd:element name=\"title\" type=\"xsd:string\" /> \n" +" <xsd:element name=\"para\" type=\"docParaType\" minOccurs=\"0\" maxOccurs=\"unbounded\" />\n" +" <xsd:element name=\"sect3\" type=\"docSect3Type\" minOccurs=\"0\" maxOccurs=\"unbounded\" />\n" +" <xsd:element name=\"internal\" type=\"docInternalS2Type\" minOccurs=\"0\" />\n" +" </xsd:sequence>\n" +" <xsd:attribute name=\"id\" type=\"xsd:string\" />\n" +" </xsd:complexType>\n" +"\n" +" <xsd:complexType name=\"docSect3Type\" mixed=\"true\">\n" +" <xsd:sequence>\n" +" <xsd:element name=\"title\" type=\"xsd:string\" /> \n" +" <xsd:element name=\"para\" type=\"docParaType\" minOccurs=\"0\" maxOccurs=\"unbounded\" />\n" +" <xsd:element name=\"sect4\" type=\"docSect4Type\" minOccurs=\"0\" maxOccurs=\"unbounded\" />\n" +" <xsd:element name=\"internal\" type=\"docInternalS3Type\" minOccurs=\"0\" />\n" +" </xsd:sequence>\n" +" <xsd:attribute name=\"id\" type=\"xsd:string\" />\n" +" </xsd:complexType>\n" +"\n" +" <xsd:complexType name=\"docSect4Type\" mixed=\"true\">\n" +" <xsd:sequence>\n" +" <xsd:element name=\"title\" type=\"xsd:string\" /> \n" +" <xsd:element name=\"para\" type=\"docParaType\" minOccurs=\"0\" maxOccurs=\"unbounded\" />\n" +" <xsd:element name=\"internal\" type=\"docInternalS4Type\" minOccurs=\"0\" />\n" +" </xsd:sequence>\n" +" <xsd:attribute name=\"id\" type=\"xsd:string\" />\n" +" </xsd:complexType>\n" +"\n" +" <xsd:complexType name=\"docInternalType\" mixed=\"true\">\n" +" <xsd:sequence>\n" +" <xsd:element name=\"para\" type=\"docParaType\" minOccurs=\"0\" maxOccurs=\"unbounded\" />\n" +" <xsd:element name=\"sect1\" type=\"docSect1Type\" minOccurs=\"0\" maxOccurs=\"unbounded\" />\n" +" </xsd:sequence>\n" +" </xsd:complexType>\n" +"\n" +" <xsd:complexType name=\"docInternalS1Type\" mixed=\"true\">\n" +" <xsd:sequence>\n" +" <xsd:element name=\"para\" type=\"docParaType\" minOccurs=\"0\" maxOccurs=\"unbounded\" />\n" +" <xsd:element name=\"sect2\" type=\"docSect2Type\" minOccurs=\"0\" maxOccurs=\"unbounded\" />\n" +" </xsd:sequence>\n" +" </xsd:complexType>\n" +"\n" +" <xsd:complexType name=\"docInternalS2Type\" mixed=\"true\">\n" +" <xsd:sequence>\n" +" <xsd:element name=\"para\" type=\"docParaType\" minOccurs=\"0\" maxOccurs=\"unbounded\" />\n" +" <xsd:element name=\"sect3\" type=\"docSect3Type\" minOccurs=\"0\" maxOccurs=\"unbounded\" />\n" +" </xsd:sequence>\n" +" </xsd:complexType>\n" +"\n" +" <xsd:complexType name=\"docInternalS3Type\" mixed=\"true\">\n" +" <xsd:sequence>\n" +" <xsd:element name=\"para\" type=\"docParaType\" minOccurs=\"0\" maxOccurs=\"unbounded\" />\n" +" <xsd:element name=\"sect3\" type=\"docSect4Type\" minOccurs=\"0\" maxOccurs=\"unbounded\" />\n" +" </xsd:sequence>\n" +" </xsd:complexType>\n" +"\n" +" <xsd:complexType name=\"docInternalS4Type\" mixed=\"true\">\n" +" <xsd:sequence>\n" +" <xsd:element name=\"para\" type=\"docParaType\" minOccurs=\"0\" maxOccurs=\"unbounded\" />\n" +" </xsd:sequence>\n" +" </xsd:complexType>\n" +" \n" +" <xsd:group name=\"docTitleCmdGroup\">\n" +" <xsd:choice>\n" +" <xsd:element name=\"ulink\" type=\"docURLLink\" />\n" +" <xsd:element name=\"bold\" type=\"docMarkupType\" />\n" +" <xsd:element name=\"emphasis\" type=\"docMarkupType\" />\n" +" <xsd:element name=\"computeroutput\" type=\"docMarkupType\" />\n" +" <xsd:element name=\"subscript\" type=\"docMarkupType\" />\n" +" <xsd:element name=\"superscript\" type=\"docMarkupType\" />\n" +" <xsd:element name=\"center\" type=\"docMarkupType\" />\n" +" <xsd:element name=\"small\" type=\"docMarkupType\" />\n" +" <xsd:element name=\"htmlonly\" type=\"xsd:string\" />\n" +" <xsd:element name=\"latexonly\" type=\"xsd:string\" />\n" +" <xsd:element name=\"dot\" type=\"xsd:string\" />\n" +" <xsd:element name=\"anchor\" type=\"docAnchorType\" />\n" +" <xsd:element name=\"formula\" type=\"docFormulaType\" />\n" +" <xsd:element name=\"ref\" type=\"docRefTextType\" />\n" +" <xsd:element name=\"copy\" type=\"docEmptyType\" />\n" +" <xsd:element name=\"trademark\" type=\"docEmptyType\" />\n" +" <xsd:element name=\"registered\" type=\"docEmptyType\" />\n" +" <xsd:element name=\"lsquo\" type=\"docEmptyType\" />\n" +" <xsd:element name=\"rsquo\" type=\"docEmptyType\" />\n" +" <xsd:element name=\"ldquo\" type=\"docEmptyType\" />\n" +" <xsd:element name=\"rdquo\" type=\"docEmptyType\" />\n" +" <xsd:element name=\"ndash\" type=\"docEmptyType\" />\n" +" <xsd:element name=\"mdash\" type=\"docEmptyType\" />\n" +" <xsd:element name=\"umlaut\" type=\"docCharType\" />\n" +" <xsd:element name=\"acute\" type=\"docCharType\" />\n" +" <xsd:element name=\"grave\" type=\"docCharType\" />\n" +" <xsd:element name=\"circ\" type=\"docCharType\" />\n" +" <xsd:element name=\"slash\" type=\"docCharType\" />\n" +" <xsd:element name=\"tilde\" type=\"docCharType\" />\n" +" <xsd:element name=\"cedil\" type=\"docCharType\" />\n" +" <xsd:element name=\"ring\" type=\"docCharType\" />\n" +" <xsd:element name=\"szlig\" type=\"docEmptyType\" />\n" +" <xsd:element name=\"nonbreakablespace\" type=\"docEmptyType\" />\n" +" </xsd:choice>\n" +" </xsd:group>\n" +"\n" +" <xsd:complexType name=\"docTitleType\" mixed=\"true\">\n" +" <xsd:group ref=\"docTitleCmdGroup\" minOccurs=\"0\" maxOccurs=\"unbounded\" />\n" +" </xsd:complexType>\n" +"\n" +" <xsd:group name=\"docCmdGroup\">\n" +" <xsd:choice>\n" +" <xsd:group ref=\"docTitleCmdGroup\"/>\n" +" <xsd:element name=\"linebreak\" type=\"docEmptyType\" />\n" +" <xsd:element name=\"hruler\" type=\"docEmptyType\" />\n" +" <xsd:element name=\"preformatted\" type=\"docMarkupType\" />\n" +" <xsd:element name=\"programlisting\" type=\"listingType\" />\n" +" <xsd:element name=\"verbatim\" type=\"xsd:string\" />\n" +" <xsd:element name=\"indexentry\" type=\"docIndexEntryType\" />\n" +" <xsd:element name=\"orderedlist\" type=\"docListType\" />\n" +" <xsd:element name=\"itemizedlist\" type=\"docListType\" />\n" +" <xsd:element name=\"simplesect\" type=\"docSimpleSectType\" />\n" +" <xsd:element name=\"title\" type=\"docTitleType\" />\n" +" <xsd:element name=\"variablelist\" type=\"docVariableListType\" />\n" +" <xsd:element name=\"table\" type=\"docTableType\" />\n" +" <xsd:element name=\"heading\" type=\"docHeadingType\" />\n" +" <xsd:element name=\"image\" type=\"docImageType\" />\n" +" <xsd:element name=\"dotfile\" type=\"docDotFileType\" />\n" +" <xsd:element name=\"toclist\" type=\"docTocListType\" />\n" +" <xsd:element name=\"language\" type=\"docLanguageType\" />\n" +" <xsd:element name=\"parameterlist\" type=\"docParamListType\" />\n" +" <xsd:element name=\"xrefsect\" type=\"docXRefSectType\" />\n" +" <xsd:element name=\"copydoc\" type=\"docCopyType\" />\n" +" <xsd:element name=\"blockquote\" type=\"docBlockQuoteType\" />\n" +" </xsd:choice>\n" +" </xsd:group>\n" +"\n" +" <xsd:complexType name=\"docParaType\" mixed=\"true\">\n" +" <xsd:group ref=\"docCmdGroup\" minOccurs=\"0\" maxOccurs=\"unbounded\" />\n" +" </xsd:complexType>\n" +"\n" +" <xsd:complexType name=\"docMarkupType\" mixed=\"true\">\n" +" <xsd:group ref=\"docCmdGroup\" minOccurs=\"0\" maxOccurs=\"unbounded\" />\n" +" </xsd:complexType>\n" +"\n" +" <xsd:complexType name=\"docURLLink\" mixed=\"true\">\n" +" <xsd:group ref=\"docTitleCmdGroup\" minOccurs=\"0\" maxOccurs=\"unbounded\" />\n" +" <xsd:attribute name=\"url\" type=\"xsd:string\" />\n" +" </xsd:complexType>\n" +"\n" +" <xsd:complexType name=\"docAnchorType\" mixed=\"true\">\n" +" <xsd:attribute name=\"id\" type=\"xsd:string\" />\n" +" </xsd:complexType>\n" +"\n" +" <xsd:complexType name=\"docFormulaType\" mixed=\"true\">\n" +" <xsd:attribute name=\"id\" type=\"xsd:string\" />\n" +" </xsd:complexType>\n" +"\n" +" <xsd:complexType name=\"docIndexEntryType\">\n" +" <xsd:sequence>\n" +" <xsd:element name=\"primaryie\" type=\"xsd:string\" />\n" +" <xsd:element name=\"secondaryie\" type=\"xsd:string\" />\n" +" </xsd:sequence>\n" +" </xsd:complexType>\n" +"\n" +" <xsd:complexType name=\"docListType\">\n" +" <xsd:sequence>\n" +" <xsd:element name=\"listitem\" type=\"docListItemType\" maxOccurs=\"unbounded\" />\n" +" </xsd:sequence>\n" +" </xsd:complexType>\n" +"\n" +" <xsd:complexType name=\"docListItemType\">\n" +" <xsd:sequence>\n" +" <xsd:element name=\"para\" type=\"docParaType\" minOccurs=\"0\" maxOccurs=\"unbounded\" />\n" +" </xsd:sequence>\n" +" </xsd:complexType>\n" +"\n" +" <xsd:complexType name=\"docSimpleSectType\">\n" +" <xsd:sequence>\n" +" <xsd:element name=\"title\" type=\"docTitleType\" minOccurs=\"0\" />\n" +" <xsd:sequence minOccurs=\"0\" maxOccurs=\"unbounded\">\n" +" <xsd:element name=\"para\" type=\"docParaType\" minOccurs=\"1\" maxOccurs=\"unbounded\" />\n" +" <xsd:element name=\"simplesectsep\" type=\"docEmptyType\" minOccurs=\"0\"/>\n" +" </xsd:sequence>\n" +" </xsd:sequence>\n" +" <xsd:attribute name=\"kind\" type=\"DoxSimpleSectKind\" />\n" +" </xsd:complexType>\n" +"\n" +" <xsd:complexType name=\"docVarListEntryType\">\n" +" <xsd:sequence>\n" +" <xsd:element name=\"term\" type=\"docTitleType\" />\n" +" </xsd:sequence>\n" +" </xsd:complexType>\n" +"\n" +" <xsd:group name=\"docVariableListGroup\">\n" +" <xsd:sequence>\n" +" <xsd:element name=\"varlistentry\" type=\"docVarListEntryType\" />\n" +" <xsd:element name=\"listitem\" type=\"docListItemType\" />\n" +" </xsd:sequence>\n" +" </xsd:group>\n" +"\n" +" <xsd:complexType name=\"docVariableListType\">\n" +" <xsd:sequence>\n" +" <xsd:group ref=\"docVariableListGroup\" maxOccurs=\"unbounded\" />\n" +" </xsd:sequence>\n" +" </xsd:complexType>\n" +"\n" +" <xsd:complexType name=\"docRefTextType\" mixed=\"true\">\n" +" <xsd:group ref=\"docTitleCmdGroup\" minOccurs=\"0\" maxOccurs=\"unbounded\" />\n" +" <xsd:attribute name=\"refid\" type=\"xsd:string\" />\n" +" <xsd:attribute name=\"kindref\" type=\"DoxRefKind\" />\n" +" <xsd:attribute name=\"external\" type=\"xsd:string\" />\n" +" </xsd:complexType>\n" +"\n" +" <xsd:complexType name=\"docTableType\">\n" +" <xsd:sequence>\n" +" <xsd:element name=\"row\" type=\"docRowType\" minOccurs=\"0\" maxOccurs=\"unbounded\" />\n" +" <xsd:element name=\"caption\" type=\"docCaptionType\" minOccurs=\"0\" />\n" +" </xsd:sequence>\n" +" <xsd:attribute name=\"rows\" type=\"xsd:integer\" />\n" +" <xsd:attribute name=\"cols\" type=\"xsd:integer\" />\n" +" </xsd:complexType>\n" +"\n" +" <xsd:complexType name=\"docRowType\">\n" +" <xsd:sequence>\n" +" <xsd:element name=\"entry\" type=\"docEntryType\" minOccurs=\"0\" maxOccurs=\"unbounded\" />\n" +" </xsd:sequence>\n" +" </xsd:complexType>\n" +"\n" +" <xsd:complexType name=\"docEntryType\">\n" +" <xsd:sequence>\n" +" <xsd:element name=\"para\" type=\"docParaType\" minOccurs=\"0\" maxOccurs=\"unbounded\" />\n" +" </xsd:sequence>\n" +" <xsd:attribute name=\"thead\" type=\"DoxBool\" />\n" +" </xsd:complexType>\n" +"\n" +" <xsd:complexType name=\"docCaptionType\" mixed=\"true\">\n" +" <xsd:group ref=\"docTitleCmdGroup\" minOccurs=\"0\" maxOccurs=\"unbounded\" />\n" +" </xsd:complexType>\n" +"\n" +" <xsd:complexType name=\"docHeadingType\" mixed=\"true\">\n" +" <xsd:group ref=\"docTitleCmdGroup\" minOccurs=\"0\" maxOccurs=\"unbounded\" />\n" +" <xsd:attribute name=\"level\" type=\"xsd:integer\" /> <!-- todo: range 1-6 -->\n" +" </xsd:complexType>\n" +"\n" +" <xsd:complexType name=\"docImageType\" mixed=\"true\">\n" +" <xsd:group ref=\"docTitleCmdGroup\" minOccurs=\"0\" maxOccurs=\"unbounded\" />\n" +" <xsd:attribute name=\"type\" type=\"DoxImageKind\" /> \n" +" <xsd:attribute name=\"name\" type=\"xsd:string\" /> \n" +" <xsd:attribute name=\"width\" type=\"xsd:string\" /> \n" +" <xsd:attribute name=\"height\" type=\"xsd:string\" /> \n" +" </xsd:complexType>\n" +"\n" +" <xsd:complexType name=\"docDotFileType\" mixed=\"true\">\n" +" <xsd:group ref=\"docTitleCmdGroup\" minOccurs=\"0\" maxOccurs=\"unbounded\" />\n" +" <xsd:attribute name=\"name\" type=\"xsd:string\" /> \n" +" </xsd:complexType>\n" +"\n" +" <xsd:complexType name=\"docTocItemType\" mixed=\"true\">\n" +" <xsd:group ref=\"docTitleCmdGroup\" minOccurs=\"0\" maxOccurs=\"unbounded\" />\n" +" <xsd:attribute name=\"id\" type=\"xsd:string\" /> \n" +" </xsd:complexType>\n" +"\n" +" <xsd:complexType name=\"docTocListType\">\n" +" <xsd:sequence>\n" +" <xsd:element name=\"tocitem\" type=\"docTocItemType\" minOccurs=\"0\" maxOccurs=\"unbounded\" />\n" +" </xsd:sequence>\n" +" </xsd:complexType>\n" +"\n" +" <xsd:complexType name=\"docLanguageType\">\n" +" <xsd:sequence>\n" +" <xsd:element name=\"para\" type=\"docParaType\" minOccurs=\"0\" maxOccurs=\"unbounded\" />\n" +" </xsd:sequence>\n" +" <xsd:attribute name=\"langid\" type=\"xsd:string\" /> \n" +" </xsd:complexType>\n" +"\n" +" <xsd:complexType name=\"docParamListType\">\n" +" <xsd:sequence>\n" +" <xsd:element name=\"parameteritem\" type=\"docParamListItem\" minOccurs=\"0\" maxOccurs=\"unbounded\" />\n" +" </xsd:sequence>\n" +" <xsd:attribute name=\"kind\" type=\"DoxParamListKind\" /> \n" +" </xsd:complexType>\n" +"\n" +" <xsd:complexType name=\"docParamListItem\">\n" +" <xsd:sequence>\n" +" <xsd:element name=\"parameternamelist\" type=\"docParamNameList\" minOccurs=\"0\" maxOccurs=\"unbounded\" />\n" +" <xsd:element name=\"parameterdescription\" type=\"descriptionType\" />\n" +" </xsd:sequence>\n" +" </xsd:complexType>\n" +"\n" +" <xsd:complexType name=\"docParamNameList\">\n" +" <xsd:sequence>\n" +" <xsd:element name=\"parametertype\" type=\"docParamType\" minOccurs=\"0\" maxOccurs=\"unbounded\" />\n" +" <xsd:element name=\"parametername\" type=\"docParamName\" minOccurs=\"0\" maxOccurs=\"unbounded\" />\n" +" </xsd:sequence>\n" +" </xsd:complexType>\n" +"\n" +" <xsd:complexType name=\"docParamType\" mixed=\"true\">\n" +" <xsd:sequence>\n" +" <xsd:element name=\"ref\" type=\"refTextType\" minOccurs=\"0\" maxOccurs=\"1\" />\n" +" </xsd:sequence>\n" +" </xsd:complexType>\n" +"\n" +" <xsd:complexType name=\"docParamName\" mixed=\"true\">\n" +" <xsd:sequence>\n" +" <xsd:element name=\"ref\" type=\"refTextType\" minOccurs=\"0\" maxOccurs=\"1\" />\n" +" </xsd:sequence>\n" +" <xsd:attribute name=\"direction\" type=\"DoxParamDir\" use=\"optional\" />\n" +" </xsd:complexType>\n" +"\n" +" <xsd:complexType name=\"docXRefSectType\">\n" +" <xsd:sequence>\n" +" <xsd:element name=\"xreftitle\" type=\"xsd:string\" minOccurs=\"0\" maxOccurs=\"unbounded\" />\n" +" <xsd:element name=\"xrefdescription\" type=\"descriptionType\" />\n" +" </xsd:sequence>\n" +" <xsd:attribute name=\"id\" type=\"xsd:string\" /> \n" +" </xsd:complexType>\n" +"\n" +" <xsd:complexType name=\"docCopyType\">\n" +" <xsd:sequence>\n" +" <xsd:element name=\"para\" type=\"docParaType\" minOccurs=\"0\" maxOccurs=\"unbounded\" />\n" +" <xsd:element name=\"sect1\" type=\"docSect1Type\" minOccurs=\"0\" maxOccurs=\"unbounded\" />\n" +" <xsd:element name=\"internal\" type=\"docInternalType\" minOccurs=\"0\" />\n" +" </xsd:sequence>\n" +" <xsd:attribute name=\"link\" type=\"xsd:string\" /> \n" +" </xsd:complexType>\n" +"\n" +" <xsd:complexType name=\"docBlockQuoteType\">\n" +" <xsd:sequence>\n" +" <xsd:element name=\"para\" type=\"docParaType\" minOccurs=\"0\" maxOccurs=\"unbounded\" />\n" +" </xsd:sequence>\n" +" </xsd:complexType>\n" +"\n" +" <xsd:complexType name=\"docCharType\">\n" +" <xsd:attribute name=\"char\" type=\"DoxCharRange\"/> \n" +" </xsd:complexType>\n" +"\n" +" <xsd:complexType name=\"docEmptyType\"/>\n" +"\n" +" <!-- Simple types -->\n" +"\n" +" <xsd:simpleType name=\"DoxBool\">\n" +" <xsd:restriction base=\"xsd:string\">\n" +" <xsd:enumeration value=\"yes\" />\n" +" <xsd:enumeration value=\"no\" />\n" +" </xsd:restriction>\n" +" </xsd:simpleType>\n" +"\n" +" <xsd:simpleType name=\"DoxGraphRelation\">\n" +" <xsd:restriction base=\"xsd:string\">\n" +" <xsd:enumeration value=\"include\" />\n" +" <xsd:enumeration value=\"usage\" />\n" +" <xsd:enumeration value=\"template-instance\" />\n" +" <xsd:enumeration value=\"public-inheritance\" />\n" +" <xsd:enumeration value=\"protected-inheritance\" />\n" +" <xsd:enumeration value=\"private-inheritance\" />\n" +" </xsd:restriction>\n" +" </xsd:simpleType>\n" +"\n" +" <xsd:simpleType name=\"DoxRefKind\">\n" +" <xsd:restriction base=\"xsd:string\">\n" +" <xsd:enumeration value=\"compound\" />\n" +" <xsd:enumeration value=\"member\" />\n" +" </xsd:restriction>\n" +" </xsd:simpleType>\n" +"\n" +" <xsd:simpleType name=\"DoxMemberKind\">\n" +" <xsd:restriction base=\"xsd:string\">\n" +" <xsd:enumeration value=\"define\" />\n" +" <xsd:enumeration value=\"property\" />\n" +" <xsd:enumeration value=\"event\" />\n" +" <xsd:enumeration value=\"variable\" />\n" +" <xsd:enumeration value=\"typedef\" />\n" +" <xsd:enumeration value=\"enum\" />\n" +" <xsd:enumeration value=\"function\" />\n" +" <xsd:enumeration value=\"signal\" />\n" +" <xsd:enumeration value=\"prototype\" />\n" +" <xsd:enumeration value=\"friend\" />\n" +" <xsd:enumeration value=\"dcop\" />\n" +" <xsd:enumeration value=\"slot\" />\n" +" </xsd:restriction>\n" +" </xsd:simpleType>\n" +"\n" +" <xsd:simpleType name=\"DoxProtectionKind\">\n" +" <xsd:restriction base=\"xsd:string\">\n" +" <xsd:enumeration value=\"public\" />\n" +" <xsd:enumeration value=\"protected\" />\n" +" <xsd:enumeration value=\"private\" />\n" +" <xsd:enumeration value=\"package\" />\n" +" </xsd:restriction>\n" +" </xsd:simpleType>\n" +"\n" +" <xsd:simpleType name=\"DoxVirtualKind\">\n" +" <xsd:restriction base=\"xsd:string\">\n" +" <xsd:enumeration value=\"non-virtual\" />\n" +" <xsd:enumeration value=\"virtual\" />\n" +" <xsd:enumeration value=\"pure-virtual\" />\n" +" </xsd:restriction>\n" +" </xsd:simpleType>\n" +"\n" +" <xsd:simpleType name=\"DoxCompoundKind\">\n" +" <xsd:restriction base=\"xsd:string\">\n" +" <xsd:enumeration value=\"class\" />\n" +" <xsd:enumeration value=\"struct\" />\n" +" <xsd:enumeration value=\"union\" />\n" +" <xsd:enumeration value=\"interface\" />\n" +" <xsd:enumeration value=\"protocol\" />\n" +" <xsd:enumeration value=\"category\" />\n" +" <xsd:enumeration value=\"exception\" />\n" +" <xsd:enumeration value=\"file\" />\n" +" <xsd:enumeration value=\"namespace\" />\n" +" <xsd:enumeration value=\"group\" />\n" +" <xsd:enumeration value=\"page\" />\n" +" <xsd:enumeration value=\"example\" />\n" +" <xsd:enumeration value=\"dir\" />\n" +" </xsd:restriction>\n" +" </xsd:simpleType>\n" +"\n" +" <xsd:simpleType name=\"DoxSectionKind\">\n" +" <xsd:restriction base=\"xsd:string\">\n" +" <xsd:enumeration value=\"user-defined\" />\n" +" <xsd:enumeration value=\"public-type\" />\n" +" <xsd:enumeration value=\"public-func\" />\n" +" <xsd:enumeration value=\"public-attrib\" />\n" +" <xsd:enumeration value=\"public-slot\" />\n" +" <xsd:enumeration value=\"signal\" />\n" +" <xsd:enumeration value=\"dcop-func\" />\n" +" <xsd:enumeration value=\"property\" />\n" +" <xsd:enumeration value=\"event\" />\n" +" <xsd:enumeration value=\"public-static-func\" />\n" +" <xsd:enumeration value=\"public-static-attrib\" />\n" +" <xsd:enumeration value=\"protected-type\" />\n" +" <xsd:enumeration value=\"protected-func\" />\n" +" <xsd:enumeration value=\"protected-attrib\" />\n" +" <xsd:enumeration value=\"protected-slot\" />\n" +" <xsd:enumeration value=\"protected-static-func\" />\n" +" <xsd:enumeration value=\"protected-static-attrib\" />\n" +" <xsd:enumeration value=\"package-type\" />\n" +" <xsd:enumeration value=\"package-func\" />\n" +" <xsd:enumeration value=\"package-attrib\" />\n" +" <xsd:enumeration value=\"package-static-func\" />\n" +" <xsd:enumeration value=\"package-static-attrib\" />\n" +" <xsd:enumeration value=\"private-type\" />\n" +" <xsd:enumeration value=\"private-func\" />\n" +" <xsd:enumeration value=\"private-attrib\" />\n" +" <xsd:enumeration value=\"private-slot\" />\n" +" <xsd:enumeration value=\"private-static-func\" />\n" +" <xsd:enumeration value=\"private-static-attrib\" />\n" +" <xsd:enumeration value=\"friend\" />\n" +" <xsd:enumeration value=\"related\" />\n" +" <xsd:enumeration value=\"define\" />\n" +" <xsd:enumeration value=\"prototype\" />\n" +" <xsd:enumeration value=\"typedef\" />\n" +" <xsd:enumeration value=\"enum\" />\n" +" <xsd:enumeration value=\"func\" />\n" +" <xsd:enumeration value=\"var\" />\n" +" </xsd:restriction>\n" +" </xsd:simpleType>\n" +"\n" +" <xsd:simpleType name=\"DoxHighlightClass\">\n" +" <xsd:restriction base=\"xsd:string\">\n" +" <xsd:enumeration value=\"comment\" />\n" +" <xsd:enumeration value=\"normal\" />\n" +" <xsd:enumeration value=\"preprocessor\" />\n" +" <xsd:enumeration value=\"keyword\" />\n" +" <xsd:enumeration value=\"keywordtype\" />\n" +" <xsd:enumeration value=\"keywordflow\" />\n" +" <xsd:enumeration value=\"stringliteral\" />\n" +" <xsd:enumeration value=\"charliteral\" />\n" +" </xsd:restriction>\n" +" </xsd:simpleType>\n" +"\n" +" <xsd:simpleType name=\"DoxSimpleSectKind\">\n" +" <xsd:restriction base=\"xsd:string\">\n" +" <xsd:enumeration value=\"see\" />\n" +" <xsd:enumeration value=\"return\" />\n" +" <xsd:enumeration value=\"author\" />\n" +" <xsd:enumeration value=\"authors\" />\n" +" <xsd:enumeration value=\"version\" />\n" +" <xsd:enumeration value=\"since\" />\n" +" <xsd:enumeration value=\"date\" />\n" +" <xsd:enumeration value=\"note\" />\n" +" <xsd:enumeration value=\"warning\" />\n" +" <xsd:enumeration value=\"pre\" />\n" +" <xsd:enumeration value=\"post\" />\n" +" <xsd:enumeration value=\"copyright\" />\n" +" <xsd:enumeration value=\"invariant\" />\n" +" <xsd:enumeration value=\"remark\" />\n" +" <xsd:enumeration value=\"attention\" />\n" +" <xsd:enumeration value=\"par\" />\n" +" <xsd:enumeration value=\"rcs\" />\n" +" </xsd:restriction>\n" +" </xsd:simpleType>\n" +"\n" +" <xsd:simpleType name=\"DoxVersionNumber\">\n" +" <xsd:restriction base=\"xsd:string\">\n" +" <xsd:pattern value=\"\\d+\\.\\d+.*\" />\n" +" </xsd:restriction>\n" +" </xsd:simpleType>\n" +"\n" +" <xsd:simpleType name=\"DoxImageKind\">\n" +" <xsd:restriction base=\"xsd:string\">\n" +" <xsd:enumeration value=\"html\" />\n" +" <xsd:enumeration value=\"latex\" />\n" +" <xsd:enumeration value=\"rtf\" />\n" +" </xsd:restriction>\n" +" </xsd:simpleType>\n" +"\n" +" <xsd:simpleType name=\"DoxParamListKind\">\n" +" <xsd:restriction base=\"xsd:string\">\n" +" <xsd:enumeration value=\"param\" />\n" +" <xsd:enumeration value=\"retval\" />\n" +" <xsd:enumeration value=\"exception\" />\n" +" <xsd:enumeration value=\"templateparam\" />\n" +" </xsd:restriction>\n" +" </xsd:simpleType>\n" +"\n" +" <xsd:simpleType name=\"DoxCharRange\">\n" +" <xsd:restriction base=\"xsd:string\">\n" +" <xsd:pattern value=\"[aeiouncAEIOUNC]\" />\n" +" </xsd:restriction>\n" +" </xsd:simpleType>\n" +"\n" +" <xsd:simpleType name=\"DoxParamDir\">\n" +" <xsd:restriction base=\"xsd:string\">\n" +" <xsd:enumeration value=\"in\"/>\n" +" <xsd:enumeration value=\"out\"/>\n" +" <xsd:enumeration value=\"inout\"/>\n" +" </xsd:restriction>\n" +" </xsd:simpleType>\n" +"\n" +" <xsd:simpleType name=\"DoxAccessor\">\n" +" <xsd:restriction base=\"xsd:string\">\n" +" <xsd:enumeration value=\"retain\"/>\n" +" <xsd:enumeration value=\"copy\"/>\n" +" <xsd:enumeration value=\"assign\"/>\n" +" </xsd:restriction>\n" +" </xsd:simpleType>\n" +"\n" +"</xsd:schema>\n" +"\n" diff --git a/trunk/src/config.h b/trunk/src/config.h new file mode 100644 index 0000000..ccbf713 --- /dev/null +++ b/trunk/src/config.h @@ -0,0 +1,610 @@ +/****************************************************************************** + * + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#ifndef CONFIG_H +#define CONFIG_H + +#include "qtbc.h" +#include <qstrlist.h> +#include <qfile.h> +#include <qdict.h> +#include <qlist.h> +#include "ftextstream.h" + + +/*! \brief Abstract base class for any configuration option. + * + */ +class ConfigOption +{ + friend class Config; + + public: + + /*! The type of option */ + enum OptionType + { + O_Info, //<! A section header + O_List, //<! A list of items + O_Enum, //<! A fixed set of items + O_String, //<! A single item + O_Int, //<! An integer value + O_Bool, //<! A boolean value + O_Obsolete //<! An obsolete option + }; + enum + { + /*! Maximum length of an option in the config file. Used for + * alignment purposes. + */ + MAX_OPTION_LENGTH = 23 + }; + ConfigOption(OptionType t) : m_kind(t) + { + m_spaces.fill(' ',40); + } + virtual ~ConfigOption() + { + } + + /*! returns the kind of option this is. */ + OptionType kind() const { return m_kind; } + QCString name() const { return m_name; } + QCString docs() const { return m_doc; } + + QCString dependsOn() const { return m_dependency; } + void addDependency(const char *dep) { m_dependency = dep; } + void setEncoding(const QCString &e) { m_encoding = e; } + + protected: + virtual void writeTemplate(FTextStream &t,bool sl,bool upd) = 0; + virtual void convertStrToVal() {} + virtual void substEnvVars() = 0; + virtual void writeXML(FTextStream&) {} + virtual void init() {} + + QCString convertToComment(const QCString &s); + void writeBoolValue(FTextStream &t,bool v); + void writeIntValue(FTextStream &t,int i); + void writeStringValue(FTextStream &t,QCString &s); + void writeStringList(FTextStream &t,QStrList &l); + + QCString m_spaces; + QCString m_name; + QCString m_doc; + QCString m_dependency; + QCString m_encoding; + OptionType m_kind; +}; + +/*! \brief Section marker for grouping the configuration options + * + */ +class ConfigInfo : public ConfigOption +{ + public: + ConfigInfo(const char *name,const char *doc) + : ConfigOption(O_Info) + { + m_name = name; + m_doc = doc; + } + void writeTemplate(FTextStream &t, bool sl,bool) + { + if (!sl) + { + t << "\n"; + } + t << "#---------------------------------------------------------------------------\n"; + t << "# " << m_doc << endl; + t << "#---------------------------------------------------------------------------\n"; + } + void substEnvVars() {} +}; + +/*! \brief Option of the list type. + * + */ +class ConfigList : public ConfigOption +{ + public: + enum WidgetType { String, File, Dir, FileAndDir }; + ConfigList(const char *name,const char *doc) + : ConfigOption(O_List) + { + m_name = name; + m_doc = doc; + m_widgetType = String; + } + void addValue(const char *v) { m_value.append(v); } + void setWidgetType(WidgetType w) { m_widgetType = w; } + WidgetType widgetType() const { return m_widgetType; } + QStrList *valueRef() { return &m_value; } + void writeTemplate(FTextStream &t,bool sl,bool) + { + if (!sl) + { + t << endl; + t << convertToComment(m_doc); + t << endl; + } + t << m_name << m_spaces.left(MAX_OPTION_LENGTH-m_name.length()) << "="; + writeStringList(t,m_value); + t << "\n"; + } + void substEnvVars(); + void writeXML(FTextStream&); + void init() { m_value.clear(); } + private: + QStrList m_value; + WidgetType m_widgetType; +}; + +/*! \brief Option of the enum type. + * + */ +class ConfigEnum : public ConfigOption +{ + public: + ConfigEnum(const char *name,const char *doc,const char *defVal) + : ConfigOption(O_Enum) + { + m_name = name; + m_doc = doc; + m_value = defVal; + m_defValue = defVal; + } + void addValue(const char *v) { m_valueRange.append(v); } + QStrListIterator iterator() + { + return QStrListIterator(m_valueRange); + } + QCString *valueRef() { return &m_value; } + void substEnvVars(); + void writeTemplate(FTextStream &t,bool sl,bool) + { + if (!sl) + { + t << endl; + t << convertToComment(m_doc); + t << endl; + } + t << m_name << m_spaces.left(MAX_OPTION_LENGTH-m_name.length()) << "="; + writeStringValue(t,m_value); + t << "\n"; + } + void writeXML(FTextStream&); + void init() { m_value = m_defValue.copy(); } + + private: + QStrList m_valueRange; + QCString m_value; + QCString m_defValue; +}; + +/*! \brief Option of the string type. + * + */ +class ConfigString : public ConfigOption +{ + public: + enum WidgetType { String, File, Dir }; + ConfigString(const char *name,const char *doc) + : ConfigOption(O_String) + { + m_name = name; + m_doc = doc; + m_widgetType = String; + } + ~ConfigString() + { + } + void setWidgetType(WidgetType w) { m_widgetType = w; } + WidgetType widgetType() const { return m_widgetType; } + void setDefaultValue(const char *v) { m_defValue = v; } + QCString *valueRef() { return &m_value; } + void writeTemplate(FTextStream &t,bool sl,bool) + { + if (!sl) + { + t << endl; + t << convertToComment(m_doc); + t << endl; + } + t << m_name << m_spaces.left(MAX_OPTION_LENGTH-m_name.length()) << "="; + writeStringValue(t,m_value); + t << "\n"; + } + void substEnvVars(); + void writeXML(FTextStream&); + void init() { m_value = m_defValue.copy(); } + + private: + QCString m_value; + QCString m_defValue; + WidgetType m_widgetType; +}; + +/*! \brief Option of the integer type. + * + */ +class ConfigInt : public ConfigOption +{ + public: + ConfigInt(const char *name,const char *doc,int minVal,int maxVal,int defVal) + : ConfigOption(O_Int) + { + m_name = name; + m_doc = doc; + m_value = defVal; + m_defValue = defVal; + m_minVal = minVal; + m_maxVal = maxVal; + } + QCString *valueStringRef() { return &m_valueString; } + int *valueRef() { return &m_value; } + int minVal() const { return m_minVal; } + int maxVal() const { return m_maxVal; } + void convertStrToVal(); + void substEnvVars(); + void writeTemplate(FTextStream &t,bool sl,bool upd) + { + if (!sl) + { + t << endl; + t << convertToComment(m_doc); + t << endl; + } + t << m_name << m_spaces.left(MAX_OPTION_LENGTH-m_name.length()) << "="; + if (upd && !m_valueString.isEmpty()) + { + writeStringValue(t,m_valueString); + } + else + { + writeIntValue(t,m_value); + } + t << "\n"; + } + void writeXML(FTextStream&); + void init() { m_value = m_defValue; } + private: + int m_value; + int m_defValue; + int m_minVal; + int m_maxVal; + QCString m_valueString; +}; + +/*! \brief Option of the boolean type. + * + */ +class ConfigBool : public ConfigOption +{ + public: + ConfigBool(const char *name,const char *doc,bool defVal) + : ConfigOption(O_Bool) + { + m_name = name; + m_doc = doc; + m_value = defVal; + m_defValue = defVal; + } + QCString *valueStringRef() { return &m_valueString; } + bool *valueRef() { return &m_value; } + void convertStrToVal(); + void substEnvVars(); + void setValueString(const QCString &v) { m_valueString = v; } + void writeTemplate(FTextStream &t,bool sl,bool upd) + { + if (!sl) + { + t << endl; + t << convertToComment(m_doc); + t << endl; + } + t << m_name << m_spaces.left(MAX_OPTION_LENGTH-m_name.length()) << "="; + if (upd && !m_valueString.isEmpty()) + { + writeStringValue(t,m_valueString); + } + else + { + writeBoolValue(t,m_value); + } + t << "\n"; + } + void writeXML(FTextStream&); + void init() { m_value = m_defValue; } + private: + bool m_value; + bool m_defValue; + QCString m_valueString; +}; + +/*! \brief Section marker for obsolete options + * + */ +class ConfigObsolete : public ConfigOption +{ + public: + ConfigObsolete(const char *name,OptionType t) : ConfigOption(t) + { m_name = name; } + void writeTemplate(FTextStream &,bool,bool) {} + void substEnvVars() {} + void writeXML(FTextStream&); +}; + + +// some convenience macros +#define Config_getString(val) Config::instance()->getString(__FILE__,__LINE__,val) +#define Config_getInt(val) Config::instance()->getInt(__FILE__,__LINE__,val) +#define Config_getList(val) Config::instance()->getList(__FILE__,__LINE__,val) +#define Config_getEnum(val) Config::instance()->getEnum(__FILE__,__LINE__,val) +#define Config_getBool(val) Config::instance()->getBool(__FILE__,__LINE__,val) + +/*! \brief Singleton for configuration variables. + * + * This object holds the global static variables + * read from a user-supplied configuration file. + * The static member instance() can be used to get + * a pointer to the one and only instance. + * + * Set all variables to their default values by + * calling Config::instance()->init() + * + */ +class Config +{ + public: + ///////////////////////////// + // public API + ///////////////////////////// + + /*! Returns the one and only instance of this class */ + static Config *instance() + { + if (m_instance==0) m_instance = new Config; + return m_instance; + } + /*! Delete the instance */ + static void deleteInstance() + { + delete m_instance; + m_instance=0; + } + + /*! Returns an iterator that can by used to iterate over the + * configuration options. + */ + QListIterator<ConfigOption> iterator() + { + return QListIterator<ConfigOption>(*m_options); + } + + /*! + * @name Getting configuration values. + * @{ + */ + + /*! Returns the value of the string option with name \a fileName. + * The arguments \a num and \a name are for debugging purposes only. + * There is a convenience function Config_getString() for this. + */ + QCString &getString(const char *fileName,int num,const char *name) const; + + /*! Returns the value of the list option with name \a fileName. + * The arguments \a num and \a name are for debugging purposes only. + * There is a convenience function Config_getList() for this. + */ + QStrList &getList(const char *fileName,int num,const char *name) const; + + /*! Returns the value of the enum option with name \a fileName. + * The arguments \a num and \a name are for debugging purposes only. + * There is a convenience function Config_getEnum() for this. + */ + QCString &getEnum(const char *fileName,int num,const char *name) const; + + /*! Returns the value of the integer option with name \a fileName. + * The arguments \a num and \a name are for debugging purposes only. + * There is a convenience function Config_getInt() for this. + */ + int &getInt(const char *fileName,int num,const char *name) const; + + /*! Returns the value of the boolean option with name \a fileName. + * The arguments \a num and \a name are for debugging purposes only. + * There is a convenience function Config_getBool() for this. + */ + bool &getBool(const char *fileName,int num,const char *name) const; + + /*! Returns the ConfigOption corresponding with \a name or 0 if + * the option is not supported. + */ + ConfigOption *get(const char *name) const + { + return m_dict->find(name); + } + /* @} */ + + /*! + * @name Adding configuration options. + * @{ + */ + + /*! Starts a new configuration section with \a name and description \a doc. + * \returns An object representing the option. + */ + ConfigInfo *addInfo(const char *name,const char *doc) + { + ConfigInfo *result = new ConfigInfo(name,doc); + m_options->append(result); + return result; + } + + /*! Adds a new string option with \a name and documentation \a doc. + * \returns An object representing the option. + */ + ConfigString *addString(const char *name, + const char *doc) + { + ConfigString *result = new ConfigString(name,doc); + m_options->append(result); + m_dict->insert(name,result); + return result; + } + + /*! Adds a new enumeration option with \a name and documentation \a doc + * and initial value \a defVal. + * \returns An object representing the option. + */ + ConfigEnum *addEnum(const char *name, + const char *doc, + const char *defVal) + { + ConfigEnum *result = new ConfigEnum(name,doc,defVal); + m_options->append(result); + m_dict->insert(name,result); + return result; + } + + /*! Adds a new string option with \a name and documentation \a doc. + * \returns An object representing the option. + */ + ConfigList *addList(const char *name, + const char *doc) + { + ConfigList *result = new ConfigList(name,doc); + m_options->append(result); + m_dict->insert(name,result); + return result; + } + + /*! Adds a new integer option with \a name and documentation \a doc. + * The integer has a range between \a minVal and \a maxVal and a + * default value of \a defVal. + * \returns An object representing the option. + */ + ConfigInt *addInt(const char *name, + const char *doc, + int minVal,int maxVal,int defVal) + { + ConfigInt *result = new ConfigInt(name,doc,minVal,maxVal,defVal); + m_options->append(result); + m_dict->insert(name,result); + return result; + } + + /*! Adds a new boolean option with \a name and documentation \a doc. + * The boolean has a default value of \a defVal. + * \returns An object representing the option. + */ + ConfigBool *addBool(const char *name, + const char *doc, + bool defVal) + { + ConfigBool *result = new ConfigBool(name,doc,defVal); + m_options->append(result); + m_dict->insert(name,result); + return result; + } + /*! Adds an option that has become obsolete. */ + ConfigOption *addObsolete(const char *name) + { + ConfigObsolete *option = new ConfigObsolete(name,ConfigOption::O_Obsolete); + m_dict->insert(name,option); + m_obsolete->append(option); + return option; + } + /*! @} */ + + /*! Writes a template configuration to stream \a t. If \a shortIndex + * is \c TRUE the description of each configuration option will + * be omitted. + */ + void writeTemplate(FTextStream &t,bool shortIndex,bool updateOnly); + + /** Write XML representation of the config file */ + void writeXML(FTextStream &t); + + ///////////////////////////// + // internal API + ///////////////////////////// + + /*! Converts the string values read from the configuration file + * to real values for non-string type options (like int, and bools) + */ + void convertStrToVal(); + + /*! Replaces references to environment variable by the actual value + * of the environment variable. + */ + void substituteEnvironmentVars(); + + /*! Checks if the values of the variable are correct, adjusts them + * if needed, and report any errors. + */ + void check(); + + /*! Initialize config variables to their default value */ + void init(); + + /*! Parse a configuration data in string \a str. + * \returns TRUE if successful, or FALSE if the string could not be + * parsed. + */ + bool parseString(const char *fn,const char *str); + + /*! Parse a configuration file with name \a fn. + * \returns TRUE if successful, FALSE if the file could not be + * opened or read. + */ + bool parse(const char *fn); + + /*! Called from the constructor, will add doxygen's default options + * to the configuration object + */ + void create(); + + protected: + + Config() + { + m_options = new QList<ConfigOption>; + m_obsolete = new QList<ConfigOption>; + m_dict = new QDict<ConfigOption>(257); + m_options->setAutoDelete(TRUE); + m_obsolete->setAutoDelete(TRUE); + m_initialized = FALSE; + create(); + } + ~Config() + { + delete m_options; + delete m_obsolete; + delete m_dict; + } + + private: + QList<ConfigOption> *m_options; + QList<ConfigOption> *m_obsolete; + QDict<ConfigOption> *m_dict; + static Config *m_instance; + bool m_initialized; +}; + +#endif diff --git a/trunk/src/config.l b/trunk/src/config.l new file mode 100644 index 0000000..5dfbae3 --- /dev/null +++ b/trunk/src/config.l @@ -0,0 +1,1609 @@ +/****************************************************************************** + * + * Copyright (C) 1997-2012 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. + * + */ + +%{ + +/* + * includes + */ +#include <stdio.h> +#include <stdlib.h> +#include <assert.h> +#include <ctype.h> +#include <stdarg.h> +#include <errno.h> + +#include <qfileinfo.h> +#include <qdir.h> +#include <qtextstream.h> +#include <qregexp.h> +#include <qstack.h> +#include <qglobal.h> + +#include "config.h" +#include "version.h" +#include "portable.h" +#include "util.h" + +#include "lang_cfg.h" +#include "configoptions.h" + +#undef Config_getString +#undef Config_getInt +#undef Config_getList +#undef Config_getEnum +#undef Config_getBool + +// use in-class definitions +#define Config_getString(val) getString(__FILE__,__LINE__,val) +#define Config_getInt(val) getInt(__FILE__,__LINE__,val) +#define Config_getList(val) getList(__FILE__,__LINE__,val) +#define Config_getEnum(val) getEnum(__FILE__,__LINE__,val) +#define Config_getBool(val) getBool(__FILE__,__LINE__,val) + +void config_err(const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + vfprintf(stderr, fmt, args); + va_end(args); +} +void config_warn(const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + vfprintf(stderr, fmt, args); + va_end(args); +} + +static QCString configStringRecode( + const QCString &str, + const char *fromEncoding, + const char *toEncoding); + +#define MAX_INCLUDE_DEPTH 10 +#define YY_NEVER_INTERACTIVE 1 + +/* ----------------------------------------------------------------- + */ +QCString ConfigOption::convertToComment(const QCString &s) +{ + QCString result; + if (s.isEmpty()) return result; + else + { + QCString tmp=s.stripWhiteSpace(); + char *p=tmp.data(); + char c; + result+="#"; + if (*p && *p!='\n') + result+=" "; + while ((c=*p++)) + { + if (c=='\n') + { + result+="\n#"; + if (*p && *p!='\n') + result+=" "; + } + else result+=c; + } + result+='\n'; + } + return result; +} + +void ConfigOption::writeBoolValue(FTextStream &t,bool v) +{ + t << " "; + if (v) t << "YES"; else t << "NO"; +} + +void ConfigOption::writeIntValue(FTextStream &t,int i) +{ + t << " " << i; +} + +void ConfigOption::writeStringValue(FTextStream &t,QCString &s) +{ + char c; + bool needsEscaping=FALSE; + // convert the string back to it original encoding + QCString se = configStringRecode(s,"UTF-8",m_encoding); + const char *p=se.data(); + if (p) + { + t << " "; + while ((c=*p++)!=0 && !needsEscaping) + needsEscaping = (c==' ' || c=='\n' || c=='\t' || c=='"' || c=='#'); + if (needsEscaping) + { + t << "\""; + p=se.data(); + while (*p) + { + if (*p==' ' && *(p+1)=='\0') break; // skip inserted space at the end + if (*p=='"') t << "\\"; // escape quotes + t << *p++; + } + t << "\""; + } + else + { + t << se; + } + } +} + +void ConfigOption::writeStringList(FTextStream &t,QStrList &l) +{ + const char *p = l.first(); + bool first=TRUE; + while (p) + { + QCString s=p; + if (!first) + t << " "; + first=FALSE; + writeStringValue(t,s); + p = l.next(); + if (p) t << " \\" << endl; + } +} + +/* ----------------------------------------------------------------- + */ + +Config *Config::m_instance = 0; + +void ConfigInt::convertStrToVal() +{ + if (!m_valueString.isEmpty()) + { + bool ok; + int val = m_valueString.toInt(&ok); + if (!ok || val<m_minVal || val>m_maxVal) + { + config_warn("warning: argument `%s' for option %s is not a valid number in the range [%d..%d]!\n" + "Using the default: %d!\n",m_valueString.data(),m_name.data(),m_minVal,m_maxVal,m_value); + } + m_value=val; + } +} + +void ConfigBool::convertStrToVal() +{ + QCString val = m_valueString.stripWhiteSpace().lower(); + if (!val.isEmpty()) + { + if (val=="yes" || val=="true" || val=="1" || val=="all") + { + m_value=TRUE; + } + else if (val=="no" || val=="false" || val=="0" || val=="none") + { + m_value=FALSE; + } + else + { + config_warn("warning: argument `%s' for option %s is not a valid boolean value\n" + "Using the default: %s!\n",m_valueString.data(),m_name.data(),m_value?"YES":"NO"); + } + } +} + +QCString &Config::getString(const char *fileName,int num,const char *name) const +{ + ConfigOption *opt = m_dict->find(name); + if (opt==0) + { + config_err("%s<%d>: Internal error: Requested unknown option %s!\n",fileName,num,name); + exit(1); + } + else if (opt->kind()!=ConfigOption::O_String) + { + config_err("%s<%d>: Internal error: Requested option %s not of string type!\n",fileName,num,name); + exit(1); + } + return *((ConfigString *)opt)->valueRef(); +} + +QStrList &Config::getList(const char *fileName,int num,const char *name) const +{ + ConfigOption *opt = m_dict->find(name); + if (opt==0) + { + config_err("%s<%d>: Internal error: Requested unknown option %s!\n",fileName,num,name); + exit(1); + } + else if (opt->kind()!=ConfigOption::O_List) + { + config_err("%d<%d>: Internal error: Requested option %s not of list type!\n",fileName,num,name); + exit(1); + } + return *((ConfigList *)opt)->valueRef(); +} + +QCString &Config::getEnum(const char *fileName,int num,const char *name) const +{ + ConfigOption *opt = m_dict->find(name); + if (opt==0) + { + config_err("%s<%d>: Internal error: Requested unknown option %s!\n",fileName,num,name); + exit(1); + } + else if (opt->kind()!=ConfigOption::O_Enum) + { + config_err("%s<%d>: Internal error: Requested option %s not of enum type!\n",fileName,num,name); + exit(1); + } + return *((ConfigEnum *)opt)->valueRef(); +} + +int &Config::getInt(const char *fileName,int num,const char *name) const +{ + ConfigOption *opt = m_dict->find(name); + if (opt==0) + { + config_err("%s<%d>: Internal error: Requested unknown option %s!\n",fileName,num,name); + exit(1); + } + else if (opt->kind()!=ConfigOption::O_Int) + { + config_err("%s<%d>: Internal error: Requested option %s not of integer type!\n",fileName,num,name); + exit(1); + } + return *((ConfigInt *)opt)->valueRef(); +} + +bool &Config::getBool(const char *fileName,int num,const char *name) const +{ + ConfigOption *opt = m_dict->find(name); + if (opt==0) + { + config_err("%s<%d>: Internal error: Requested unknown option %s!\n",fileName,num,name); + exit(1); + } + else if (opt->kind()!=ConfigOption::O_Bool) + { + config_err("%s<%d>: Internal error: Requested option %s not of integer type!\n",fileName,num,name); + exit(1); + } + return *((ConfigBool *)opt)->valueRef(); +} + +/* ----------------------------------------------------------------- + */ + +void ConfigInt::writeXML(FTextStream& t) +{ + t << " <option type='int' " + "id='" << convertToXML(name()) << "' " + "docs='\n" << convertToXML(docs()) << "' " + "minval='" << m_minVal << "' " + "maxval='" << m_maxVal << "' " + "defval='" << m_defValue << "'"; + if (!m_dependency.isEmpty()) t << " depends='" << m_dependency << "'"; + t << "/>" << endl; +} + +void ConfigBool::writeXML(FTextStream& t) +{ + t << " <option type='bool' " + "id='" << convertToXML(name()) << "' " + "docs='\n" << convertToXML(docs()) << "' " + "defval='" << m_defValue << "'"; + if (!m_dependency.isEmpty()) t << " depends='" << m_dependency << "'"; + t << "/>" << endl; +} + +void ConfigString::writeXML(FTextStream& t) +{ + QString format; + switch (m_widgetType) + { + case String: format="string"; break; + case File: format="file"; break; + case Dir: format="dir"; break; + } + t << " <option type='string' " + "id='" << convertToXML(name()) << "' " + "format='" << format << "' " + "docs='\n" << convertToXML(docs()) << "' " + "defval='" << convertToXML(m_defValue) << "'"; + if (!m_dependency.isEmpty()) t << " depends='" << m_dependency << "'"; + t << "/>" << endl; +} + +void ConfigEnum::writeXML(FTextStream &t) +{ + t << " <option type='enum' " + "id='" << convertToXML(name()) << "' " + "defval='" << convertToXML(m_defValue) << "' " + "docs='\n" << convertToXML(docs()) << "'"; + if (!m_dependency.isEmpty()) t << " depends='" << m_dependency << "'"; + t << ">" << endl; + + char *enumVal = m_valueRange.first(); + while (enumVal) + { + t << " <value name='" << convertToXML(enumVal) << "'/>" << endl; + enumVal = m_valueRange.next(); + } + + t << " </option>" << endl; +} + +void ConfigList::writeXML(FTextStream &t) +{ + QString format; + switch (m_widgetType) + { + case String: format="string"; break; + case File: format="file"; break; + case Dir: format="dir"; break; + case FileAndDir: format="filedir"; break; + } + t << " <option type='list' " + "id='" << convertToXML(name()) << "' " + "format='" << format << "' " + "docs='\n" << convertToXML(docs()) << "'"; + if (!m_dependency.isEmpty()) t << " depends='" << m_dependency << "'"; + t << ">" << endl; + char *enumVal = m_value.first(); + while (enumVal) + { + t << " <value name='" << convertToXML(enumVal) << "'/>" << endl; + enumVal = m_value.next(); + } + + t << " </option>" << endl; +} + +void ConfigObsolete::writeXML(FTextStream &t) +{ + t << " <option type='obsolete' " + "id='" << convertToXML(name()) << "'/>" << endl; +} + + +/* ----------------------------------------------------------------- + * + * static variables + */ + +struct ConfigFileState +{ + int lineNr; + FILE *filePtr; + YY_BUFFER_STATE oldState; + YY_BUFFER_STATE newState; + QCString fileName; +}; + +static const char *inputString; +static int inputPosition; +static int yyLineNr; +static QCString yyFileName; +static QCString tmpString; +static QCString *s=0; +static bool *b=0; +static QStrList *l=0; +static int lastState; +static QCString elemStr; +static QCString includeName; +static QStrList includePathList; +static QStack<ConfigFileState> includeStack; +static int includeDepth; + +static QCString tabSizeString; +static QCString maxInitLinesString; +static QCString colsInAlphaIndexString; +static QCString enumValuesPerLineString; +static QCString treeViewWidthString; +static QCString maxDotGraphWidthString; +static QCString maxDotGraphHeightString; +static QCString encoding; + +static Config *config; + +/* ----------------------------------------------------------------- + */ +#undef YY_INPUT +#define YY_INPUT(buf,result,max_size) result=yyread(buf,max_size); + +static int yyread(char *buf,int max_size) +{ + // no file included + if (includeStack.isEmpty()) + { + int c=0; + if (inputString==0) return c; + while( c < max_size && inputString[inputPosition] ) + { + *buf = inputString[inputPosition++] ; + c++; buf++; + } + return c; + } + else + { + //assert(includeStack.current()->newState==YY_CURRENT_BUFFER); + return (int)fread(buf,1,max_size,includeStack.current()->filePtr); + } +} + + +static QCString configStringRecode( + const QCString &str, + const char *fromEncoding, + const char *toEncoding) +{ + QCString inputEncoding = fromEncoding; + QCString outputEncoding = toEncoding; + if (inputEncoding.isEmpty() || outputEncoding.isEmpty() || inputEncoding==outputEncoding) return str; + int inputSize=str.length(); + int outputSize=inputSize*4+1; + QCString output(outputSize); + void *cd = portable_iconv_open(outputEncoding,inputEncoding); + if (cd==(void *)(-1)) + { + fprintf(stderr,"error: unsupported character conversion: '%s'->'%s'\n", + inputEncoding.data(),outputEncoding.data()); + exit(1); + } + size_t iLeft=(size_t)inputSize; + size_t oLeft=(size_t)outputSize; + const char *inputPtr = str.data(); + char *outputPtr = output.data(); + if (!portable_iconv(cd, &inputPtr, &iLeft, &outputPtr, &oLeft)) + { + outputSize-=(int)oLeft; + output.resize(outputSize+1); + output.at(outputSize)='\0'; + //printf("iconv: input size=%d output size=%d\n[%s]\n",size,newSize,srcBuf.data()); + } + else + { + fprintf(stderr,"error: failed to translate characters from %s to %s: %s\n", + inputEncoding.data(),outputEncoding.data(),strerror(errno)); + exit(1); + } + portable_iconv_close(cd); + return output; +} + +static void checkEncoding() +{ + ConfigString *option = (ConfigString*)config->get("DOXYFILE_ENCODING"); + encoding = *option->valueRef(); +} + +static FILE *tryPath(const char *path,const char *fileName) +{ + QCString absName=(path ? (QCString)path+"/"+fileName : (QCString)fileName); + QFileInfo fi(absName); + if (fi.exists() && fi.isFile()) + { + FILE *f=portable_fopen(absName,"r"); + if (!f) config_err("error: could not open file %s for reading\n",absName.data()); + return f; + } + return 0; +} + +static void substEnvVarsInStrList(QStrList &sl); +static void substEnvVarsInString(QCString &s); + +static bool isAbsolute(const char * fileName) +{ +# ifdef _WIN32 + if (isalpha (fileName [0]) && fileName[1] == ':') + fileName += 2; +# endif + char const fst = fileName [0]; + if (fst == '/') { + return true; + } +# ifdef _WIN32 + if (fst == '\\') + return true; +# endif + return false; +} + +static FILE *findFile(const char *fileName) +{ + if(isAbsolute(fileName)) + return tryPath(NULL, fileName); + substEnvVarsInStrList(includePathList); + char *s=includePathList.first(); + while (s) // try each of the include paths + { + FILE *f = tryPath(s,fileName); + if (f) return f; + s=includePathList.next(); + } + // try cwd if includePathList fails + return tryPath(".",fileName); +} + +static void readIncludeFile(const char *incName) +{ + if (includeDepth==MAX_INCLUDE_DEPTH) { + config_err("error: maximum include depth (%d) reached, %s is not included. Aborting...\n", + MAX_INCLUDE_DEPTH,incName); + exit(1); + } + + QCString inc = incName; + substEnvVarsInString(inc); + inc = inc.stripWhiteSpace(); + uint incLen = inc.length(); + if (inc.at(0)=='"' && inc.at(incLen-1)=='"') // strip quotes + { + inc=inc.mid(1,incLen-2); + } + + FILE *f; + + if ((f=findFile(inc))) // see if the include file can be found + { + // For debugging +#if SHOW_INCLUDES + for (i=0;i<includeStack.count();i++) msg(" "); + msg("@INCLUDE = %s: parsing...\n",inc.data()); +#endif + + // store the state of the old file + ConfigFileState *fs=new ConfigFileState; + fs->oldState=YY_CURRENT_BUFFER; + fs->lineNr=yyLineNr; + fs->fileName=yyFileName; + fs->filePtr=f; + // push the state on the stack + includeStack.push(fs); + // set the scanner to the include file + yy_switch_to_buffer(yy_create_buffer(f, YY_BUF_SIZE)); + fs->newState=YY_CURRENT_BUFFER; + yyFileName=inc; + includeDepth++; + } + else + { + config_err("error: @INCLUDE = %s: not found!\n",inc.data()); + exit(1); + } +} + + +%} + +%option nounput +%option noyywrap + +%x Start +%x SkipComment +%x SkipInvalid +%x GetString +%x GetBool +%x GetStrList +%x GetQuotedString +%x GetEnvVar +%x Include + +%% + +<*>\0x0d +<Start,GetString,GetStrList,GetBool,SkipInvalid>"#" { BEGIN(SkipComment); } +<Start>[a-z_A-Z][a-z_A-Z0-9]*[ \t]*"=" { QCString cmd=yytext; + cmd=cmd.left(cmd.length()-1).stripWhiteSpace(); + ConfigOption *option = config->get(cmd); + if (option==0) // oops not known + { + config_err("warning: ignoring unsupported tag `%s' at line %d, file %s\n", + yytext,yyLineNr,yyFileName.data()); + BEGIN(SkipInvalid); + } + else // known tag + { + option->setEncoding(encoding); + switch(option->kind()) + { + case ConfigOption::O_Info: + // shouldn't get here! + BEGIN(SkipInvalid); + break; + case ConfigOption::O_List: + l = ((ConfigList *)option)->valueRef(); + l->clear(); + elemStr=""; + BEGIN(GetStrList); + break; + case ConfigOption::O_Enum: + s = ((ConfigEnum *)option)->valueRef(); + s->resize(0); + BEGIN(GetString); + break; + case ConfigOption::O_String: + s = ((ConfigString *)option)->valueRef(); + s->resize(0); + BEGIN(GetString); + break; + case ConfigOption::O_Int: + s = ((ConfigInt *)option)->valueStringRef(); + s->resize(0); + BEGIN(GetString); + break; + case ConfigOption::O_Bool: + s = ((ConfigBool *)option)->valueStringRef(); + s->resize(0); + BEGIN(GetString); + break; + case ConfigOption::O_Obsolete: + config_err("warning: Tag `%s' at line %d of file %s has become obsolete.\n" + "To avoid this warning please update your configuration " + "file using \"doxygen -u\"\n", cmd.data(),yyLineNr,yyFileName.data()); + BEGIN(SkipInvalid); + break; + } + } + } +<Start>[a-z_A-Z][a-z_A-Z0-9]*[ \t]*"+=" { QCString cmd=yytext; + cmd=cmd.left(cmd.length()-2).stripWhiteSpace(); + ConfigOption *option = config->get(cmd); + if (option==0) // oops not known + { + config_err("warning: ignoring unsupported tag `%s' at line %d, file %s\n", + yytext,yyLineNr,yyFileName.data()); + BEGIN(SkipInvalid); + } + else // known tag + { + switch(option->kind()) + { + case ConfigOption::O_Info: + // shouldn't get here! + BEGIN(SkipInvalid); + break; + case ConfigOption::O_List: + l = ((ConfigList *)option)->valueRef(); + elemStr=""; + BEGIN(GetStrList); + break; + case ConfigOption::O_Enum: + case ConfigOption::O_String: + case ConfigOption::O_Int: + case ConfigOption::O_Bool: + config_err("warning: operator += not supported for `%s'. Ignoring line at line %d, file %s\n", + yytext,yyLineNr,yyFileName.data()); + BEGIN(SkipInvalid); + break; + case ConfigOption::O_Obsolete: + config_err("warning: Tag `%s' at line %d of file %s has become obsolete.\n" + "To avoid this warning please update your configuration " + "file using \"doxygen -u\"\n", cmd.data(),yyLineNr,yyFileName.data()); + BEGIN(SkipInvalid); + break; + } + } + } +<Start>"@INCLUDE_PATH"[ \t]*"=" { BEGIN(GetStrList); l=&includePathList; l->clear(); elemStr=""; } + /* include a config file */ +<Start>"@INCLUDE"[ \t]*"=" { BEGIN(Include);} +<Include>([^ \"\t\r\n]+)|("\""[^\n\"]+"\"") { + readIncludeFile(configStringRecode(yytext,encoding,"UTF-8")); + BEGIN(Start); + } +<<EOF>> { + //printf("End of include file\n"); + //printf("Include stack depth=%d\n",g_includeStack.count()); + if (includeStack.isEmpty()) + { + //printf("Terminating scanner!\n"); + yyterminate(); + } + else + { + ConfigFileState *fs=includeStack.pop(); + fclose(fs->filePtr); + YY_BUFFER_STATE oldBuf = YY_CURRENT_BUFFER; + yy_switch_to_buffer( fs->oldState ); + yy_delete_buffer( oldBuf ); + yyLineNr=fs->lineNr; + yyFileName=fs->fileName; + delete fs; fs=0; + includeDepth--; + } + } + +<Start>[a-z_A-Z0-9]+ { config_err("warning: ignoring unknown tag `%s' at line %d, file %s\n",yytext,yyLineNr,yyFileName.data()); } +<GetString,GetBool,SkipInvalid>\n { yyLineNr++; BEGIN(Start); } +<GetStrList>\n { + yyLineNr++; + if (!elemStr.isEmpty()) + { + //printf("elemStr1=`%s'\n",elemStr.data()); + l->append(elemStr); + } + BEGIN(Start); + } +<GetStrList>[ \t]+ { + if (!elemStr.isEmpty()) + { + //printf("elemStr2=`%s'\n",elemStr.data()); + l->append(elemStr); + } + elemStr.resize(0); + } +<GetString>[^ \"\t\r\n]+ { (*s)+=configStringRecode(yytext,encoding,"UTF-8"); + checkEncoding(); + } +<GetString,GetStrList,SkipInvalid>"\"" { lastState=YY_START; + BEGIN(GetQuotedString); + tmpString.resize(0); + } +<GetQuotedString>"\""|"\n" { + // we add a bogus space to signal that the string was quoted. This space will be stripped later on. + tmpString+=" "; + //printf("Quoted String = `%s'\n",tmpString.data()); + if (lastState==GetString) + { + (*s)+=configStringRecode(tmpString,encoding,"UTF-8"); + checkEncoding(); + } + else + { + elemStr+=configStringRecode(tmpString,encoding,"UTF-8"); + } + if (*yytext=='\n') + { + config_err("warning: Missing end quote (\") on line %d, file %s\n",yyLineNr,yyFileName.data()); + yyLineNr++; + } + BEGIN(lastState); + } +<GetQuotedString>"\\\"" { + tmpString+='"'; + } +<GetQuotedString>. { tmpString+=*yytext; } +<GetBool>[a-zA-Z]+ { + QCString bs=yytext; + bs=bs.upper(); + if (bs=="YES" || bs=="1") + *b=TRUE; + else if (bs=="NO" || bs=="0") + *b=FALSE; + else + { + *b=FALSE; + config_warn("warning: Invalid value `%s' for " + "boolean tag in line %d, file %s; use YES or NO\n", + bs.data(),yyLineNr,yyFileName.data()); + } + } +<GetStrList>[^ \#\"\t\r\n]+ { + elemStr+=configStringRecode(yytext,encoding,"UTF-8"); + } +<SkipComment>\n { yyLineNr++; BEGIN(Start); } +<SkipComment>\\[ \r\t]*\n { yyLineNr++; BEGIN(Start); } +<*>\\[ \r\t]*\n { yyLineNr++; } +<*>. +<*>\n { yyLineNr++ ; } + +%% + +/*@ ---------------------------------------------------------------------------- + */ + +void Config::writeTemplate(FTextStream &t,bool sl,bool upd) +{ + t << "# Doxyfile " << versionString << endl << endl; + if (!sl) + { + t << "# This file describes the settings to be used by the documentation system\n"; + t << "# doxygen (www.doxygen.org) for a project.\n"; + t << "#\n"; + t << "# All text after a hash (#) is considered a comment and will be ignored.\n"; + t << "# The format is:\n"; + t << "# TAG = value [value, ...]\n"; + t << "# For lists items can also be appended using:\n"; + t << "# TAG += value [value, ...]\n"; + t << "# Values that contain spaces should be placed between quotes (\" \").\n"; + } + ConfigOption *option = m_options->first(); + while (option) + { + option->writeTemplate(t,sl,upd); + option = m_options->next(); + } +} + +void Config::writeXML(FTextStream &t) +{ + t << "<doxygenconfig>" << endl; + bool first=TRUE; + ConfigOption *option = m_options->first(); + while (option) + { + if (option->kind()==ConfigOption::O_Info) + { + if (!first) t << " </group>" << endl; + t << " <group name='" << option->name() << "' " + "docs='" << option->docs() << "'>" << endl; + first=FALSE; + } + else + { + option->writeXML(t); + } + option = m_options->next(); + } + option = m_obsolete->first(); + while (option) + { + option->writeXML(t); + option = m_obsolete->next(); + } + if (!first) t << " </group>" << endl; + t << "</doxygenconfig>" << endl; +} + +void Config::convertStrToVal() +{ + ConfigOption *option = m_options->first(); + while (option) + { + option->convertStrToVal(); + option = m_options->next(); + } +} + +static void substEnvVarsInString(QCString &s) +{ + static QRegExp re("\\$\\([a-z_A-Z0-9.-]+\\)"); + static QRegExp re2("\\$\\([a-z_A-Z0-9.-]+\\([a-z_A-Z0-9.-]+\\)\\)"); // For e.g. PROGRAMFILES(X86) + if (s.isEmpty()) return; + int p=0; + int i,l; + //printf("substEnvVarInString(%s) start\n",s.data()); + while ((i=re.match(s,p,&l))!=-1 || (i=re2.match(s,p,&l))!=-1) + { + //printf("Found environment var s.mid(%d,%d)=`%s'\n",i+2,l-3,s.mid(i+2,l-3).data()); + QCString env=portable_getenv(s.mid(i+2,l-3)); + substEnvVarsInString(env); // recursively expand variables if needed. + s = s.left(i)+env+s.right(s.length()-i-l); + p=i+env.length(); // next time start at the end of the expanded string + } + s=s.stripWhiteSpace(); // to strip the bogus space that was added when an argument + // has quotes + //printf("substEnvVarInString(%s) end\n",s.data()); +} + +static void substEnvVarsInStrList(QStrList &sl) +{ + char *s = sl.first(); + while (s) + { + QCString result(s); + // an argument with quotes will have an extra space at the end, so wasQuoted will be TRUE. + bool wasQuoted = (result.find(' ')!=-1) || (result.find('\t')!=-1); + // here we strip the quote again + substEnvVarsInString(result); + + //printf("Result %s was quoted=%d\n",result.data(),wasQuoted); + + if (!wasQuoted) /* as a result of the expansion, a single string + may have expanded into a list, which we'll + add to sl. If the orginal string already + contained multiple elements no further + splitting is done to allow quoted items with spaces! */ + { + int l=result.length(); + int i,p=0; + // skip spaces + // search for a "word" + for (i=0;i<l;i++) + { + char c=0; + // skip until start of new word + while (i<l && ((c=result.at(i))==' ' || c=='\t')) i++; + p=i; // p marks the start index of the word + // skip until end of a word + while (i<l && ((c=result.at(i))!=' ' && c!='\t' && c!='"')) i++; + if (i<l) // not at the end of the string + { + if (c=='"') // word within quotes + { + p=i+1; + for (i++;i<l;i++) + { + c=result.at(i); + if (c=='"') // end quote + { + // replace the string in the list and go to the next item. + sl.insert(sl.at(),result.mid(p,i-p)); // insert new item before current item. + sl.next(); // current item is now the old item + p=i+1; + break; + } + else if (c=='\\') // skip escaped stuff + { + i++; + } + } + } + else if (c==' ' || c=='\t') // separator + { + // replace the string in the list and go to the next item. + sl.insert(sl.at(),result.mid(p,i-p)); // insert new item before current item. + sl.next(); // current item is now the old item + p=i+1; + } + } + } + if (p!=l) // add the leftover as a string + { + // replace the string in the list and go to the next item. + sl.insert(sl.at(),result.right(l-p)); // insert new item before current item. + sl.next(); // current item is now the old item + } + } + else // just goto the next element in the list + { + sl.insert(sl.at(),result); + sl.next(); + } + // remove the old unexpanded string from the list + int i=sl.at(); + sl.remove(); // current item index changes if the last element is removed. + if (sl.at()==i) // not last item + s = sl.current(); + else // just removed last item + s = 0; + } +} + +void ConfigString::substEnvVars() +{ + substEnvVarsInString(m_value); +} + +void ConfigList::substEnvVars() +{ + substEnvVarsInStrList(m_value); +} + +void ConfigBool::substEnvVars() +{ + substEnvVarsInString(m_valueString); +} + +void ConfigInt::substEnvVars() +{ + substEnvVarsInString(m_valueString); +} + +void ConfigEnum::substEnvVars() +{ + substEnvVarsInString(m_value); +} + +void Config::substituteEnvironmentVars() +{ + ConfigOption *option = m_options->first(); + while (option) + { + option->substEnvVars(); + option = m_options->next(); + } +} + +static void cleanUpPaths(QStrList &str) +{ + char *sfp = str.first(); + while (sfp) + { + register char *p = sfp; + if (p) + { + char c; + while ((c=*p)) + { + if (c=='\\') *p='/'; + p++; + } + } + QCString path = sfp; + if ((path.at(0)!='/' && (path.length()<=2 || path.at(1)!=':')) || + path.at(path.length()-1)!='/' + ) + { + QFileInfo fi(path); + if (fi.exists() && fi.isDir()) + { + int i = str.at(); + str.remove(); + if (str.at()==i) // did not remove last item + str.insert(i,fi.absFilePath()+"/"); + else + str.append(fi.absFilePath()+"/"); + } + } + sfp = str.next(); + } +} + +void Config::check() +{ + //if (!projectName.isEmpty()) + //{ + // projectName[0]=toupper(projectName[0]); + //} + + QCString &warnFormat = Config_getString("WARN_FORMAT"); + if (warnFormat.stripWhiteSpace().isEmpty()) + { + warnFormat="$file:$line $text"; + } + else + { + if (warnFormat.find("$file")==-1) + { + config_err("warning: warning format does not contain a $file tag!\n"); + } + if (warnFormat.find("$line")==-1) + { + config_err("warning: warning format does not contain a $line tag!\n"); + } + if (warnFormat.find("$text")==-1) + { + config_err("warning: warning format foes not contain a $text tag!\n"); + } + } + + QCString &manExtension = Config_getString("MAN_EXTENSION"); + + // set default man page extension if non is given by the user + if (manExtension.isEmpty()) + { + manExtension=".3"; + } + + QCString &paperType = Config_getEnum("PAPER_TYPE"); + paperType=paperType.lower().stripWhiteSpace(); + if (paperType.isEmpty()) + { + paperType = "a4"; + } + if (paperType!="a4" && paperType!="a4wide" && paperType!="letter" && + paperType!="legal" && paperType!="executive") + { + config_err("error: Unknown page type specified"); + } + + QCString &outputLanguage=Config_getEnum("OUTPUT_LANGUAGE"); + outputLanguage=outputLanguage.stripWhiteSpace(); + if (outputLanguage.isEmpty()) + { + outputLanguage = "English"; + } + + QCString &htmlFileExtension=Config_getString("HTML_FILE_EXTENSION"); + htmlFileExtension=htmlFileExtension.stripWhiteSpace(); + if (htmlFileExtension.isEmpty()) + { + htmlFileExtension = ".html"; + } + + // expand the relative stripFromPath values + QStrList &stripFromPath = Config_getList("STRIP_FROM_PATH"); + char *sfp = stripFromPath.first(); + if (sfp==0) // by default use the current path + { + stripFromPath.append(QDir::currentDirPath()+"/"); + } + else + { + cleanUpPaths(stripFromPath); + } + + // expand the relative stripFromPath values + QStrList &stripFromIncPath = Config_getList("STRIP_FROM_INC_PATH"); + cleanUpPaths(stripFromIncPath); + + // Test to see if HTML header is valid + QCString &headerFile = Config_getString("HTML_HEADER"); + if (!headerFile.isEmpty()) + { + QFileInfo fi(headerFile); + if (!fi.exists()) + { + config_err("error: tag HTML_HEADER: header file `%s' " + "does not exist\n",headerFile.data()); + exit(1); + } + } + // Test to see if HTML footer is valid + QCString &footerFile = Config_getString("HTML_FOOTER"); + if (!footerFile.isEmpty()) + { + QFileInfo fi(footerFile); + if (!fi.exists()) + { + config_err("error: tag HTML_FOOTER: footer file `%s' " + "does not exist\n",footerFile.data()); + exit(1); + } + } + // Test to see if LaTeX header is valid + QCString &latexHeaderFile = Config_getString("LATEX_HEADER"); + if (!latexHeaderFile.isEmpty()) + { + QFileInfo fi(latexHeaderFile); + if (!fi.exists()) + { + config_err("error: tag LATEX_HEADER: header file `%s' " + "does not exist\n",latexHeaderFile.data()); + exit(1); + } + } + // check include path + QStrList &includePath = Config_getList("INCLUDE_PATH"); + char *s=includePath.first(); + while (s) + { + QFileInfo fi(s); + if (!fi.exists()) config_err("warning: tag INCLUDE_PATH: include path `%s' " + "does not exist\n",s); + s=includePath.next(); + } + + // check aliases + QStrList &aliasList = Config_getList("ALIASES"); + s=aliasList.first(); + while (s) + { + QRegExp re1("[a-z_A-Z][a-z_A-Z0-9]*[ \t]*="); // alias without argument + QRegExp re2("[a-z_A-Z][a-z_A-Z0-9]*{[0-9]*}[ \t]*="); // alias with argument + QCString alias=s; + alias=alias.stripWhiteSpace(); + if (alias.find(re1)!=0 && alias.find(re2)!=0) + { + config_err("Illegal alias format `%s'. Use \"name=value\" or \"name(n)=value\", where n is the number of arguments\n", + alias.data()); + } + s=aliasList.next(); + } + + // check if GENERATE_TREEVIEW and GENERATE_HTMLHELP are both enabled + if (Config_getBool("GENERATE_TREEVIEW") && Config_getBool("GENERATE_HTMLHELP")) + { + config_err("When enabling GENERATE_HTMLHELP the tree view (GENERATE_TREEVIEW) should be disabled. I'll do it for you.\n"); + Config_getBool("GENERATE_TREEVIEW")=FALSE; + } + if (Config_getBool("SEARCHENGINE") && Config_getBool("GENERATE_HTMLHELP")) + { + config_err("When enabling GENERATE_HTMLHELP the search engine (SEARCHENGINE) should be disabled. I'll do it for you.\n"); + Config_getBool("SEARCHENGINE")=FALSE; + } + + // check if SEPARATE_MEMBER_PAGES and INLINE_GROUPED_CLASSES are both enabled + if (Config_getBool("SEPARATE_MEMBER_PAGES") && Config_getBool("INLINE_GROUPED_CLASSES")) + { + config_err("When enabling INLINE_GROUPED_CLASSES the SEPARATE_MEMBER_PAGES option should be disabled. I'll do it for you.\n"); + Config_getBool("SEPARATE_MEMBER_PAGES")=FALSE; + } + + // check dot image format + QCString &dotImageFormat=Config_getEnum("DOT_IMAGE_FORMAT"); + dotImageFormat=dotImageFormat.stripWhiteSpace(); + if (dotImageFormat.isEmpty()) + { + dotImageFormat = "png"; + } + //else if (dotImageFormat!="gif" && dotImageFormat!="png" && dotImageFormat!="jpg") + //{ + // config_err("Invalid value for DOT_IMAGE_FORMAT: `%s'. Using the default.\n",dotImageFormat.data()); + // dotImageFormat = "png"; + //} + + + // check dot path + QCString &dotPath = Config_getString("DOT_PATH"); + if (!dotPath.isEmpty()) + { + QFileInfo fi(dotPath); + if (fi.exists() && fi.isFile()) // user specified path + exec + { + dotPath=fi.dirPath(TRUE); + } + else + { + QFileInfo dp(dotPath+"/dot"+portable_commandExtension()); + if (!dp.exists() || !dp.isFile()) + { + config_err("warning: the dot tool could not be found at %s\n",dotPath.data()); + dotPath=""; + } + else + { + dotPath=dp.dirPath(TRUE)+"/"; + } + } +#if defined(_WIN32) // convert slashes + uint i=0,l=dotPath.length(); + for (i=0;i<l;i++) if (dotPath.at(i)=='/') dotPath.at(i)='\\'; +#endif + } + else // make sure the string is empty but not null! + { + dotPath=""; + } + + // check mscgen path + QCString &mscgenPath = Config_getString("MSCGEN_PATH"); + if (!mscgenPath.isEmpty()) + { + QFileInfo dp(mscgenPath+"/mscgen"+portable_commandExtension()); + if (!dp.exists() || !dp.isFile()) + { + config_err("warning: the mscgen tool could not be found at %s\n",mscgenPath.data()); + mscgenPath=""; + } + else + { + mscgenPath=dp.dirPath(TRUE)+"/"; +#if defined(_WIN32) // convert slashes + uint i=0,l=mscgenPath.length(); + for (i=0;i<l;i++) if (mscgenPath.at(i)=='/') mscgenPath.at(i)='\\'; +#endif + } + } + else // make sure the string is empty but not null! + { + mscgenPath=""; + } + + + // check input + QStrList &inputSources=Config_getList("INPUT"); + if (inputSources.count()==0) + { + // use current dir as the default + inputSources.append(QDir::currentDirPath()); + } + else + { + s=inputSources.first(); + while (s) + { + QFileInfo fi(s); + if (!fi.exists()) + { + config_err("warning: tag INPUT: input source `%s' does not exist\n",s); + } + s=inputSources.next(); + } + } + + // add default pattern if needed + QStrList &filePatternList = Config_getList("FILE_PATTERNS"); + if (filePatternList.isEmpty()) + { + filePatternList.append("*.c"); + filePatternList.append("*.cc"); + filePatternList.append("*.cxx"); + filePatternList.append("*.cpp"); + filePatternList.append("*.c++"); + filePatternList.append("*.d"); + filePatternList.append("*.java"); + filePatternList.append("*.ii"); + filePatternList.append("*.ixx"); + filePatternList.append("*.ipp"); + filePatternList.append("*.i++"); + filePatternList.append("*.inl"); + filePatternList.append("*.h"); + filePatternList.append("*.hh"); + filePatternList.append("*.hxx"); + filePatternList.append("*.hpp"); + filePatternList.append("*.h++"); + filePatternList.append("*.idl"); + filePatternList.append("*.odl"); + filePatternList.append("*.cs"); + filePatternList.append("*.php"); + filePatternList.append("*.php3"); + filePatternList.append("*.inc"); + filePatternList.append("*.m"); + filePatternList.append("*.mm"); + filePatternList.append("*.dox"); + filePatternList.append("*.py"); + filePatternList.append("*.f90"); + filePatternList.append("*.f"); + filePatternList.append("*.for"); + filePatternList.append("*.vhd"); + filePatternList.append("*.vhdl"); + filePatternList.append("*.tcl"); + filePatternList.append("*.md"); + filePatternList.append("*.markdown"); + if (portable_fileSystemIsCaseSensitive()) + { + // unix => case sensitive match => also include useful uppercase versions + filePatternList.append("*.C"); + filePatternList.append("*.CC"); + filePatternList.append("*.C++"); + filePatternList.append("*.II"); + filePatternList.append("*.I++"); + filePatternList.append("*.H"); + filePatternList.append("*.HH"); + filePatternList.append("*.H++"); + filePatternList.append("*.CS"); + filePatternList.append("*.PHP"); + filePatternList.append("*.PHP3"); + filePatternList.append("*.M"); + filePatternList.append("*.MM"); + filePatternList.append("*.PY"); + filePatternList.append("*.F90"); + filePatternList.append("*.F"); + filePatternList.append("*.VHD"); + filePatternList.append("*.VHDL"); + filePatternList.append("*.TCL"); + filePatternList.append("*.MD"); + filePatternList.append("*.MARKDOWN"); + } + } + + // add default pattern if needed + QStrList &examplePatternList = Config_getList("EXAMPLE_PATTERNS"); + if (examplePatternList.isEmpty()) + { + examplePatternList.append("*"); + } + + // if no output format is enabled, warn the user + if (!Config_getBool("GENERATE_HTML") && + !Config_getBool("GENERATE_LATEX") && + !Config_getBool("GENERATE_MAN") && + !Config_getBool("GENERATE_RTF") && + !Config_getBool("GENERATE_XML") && + !Config_getBool("GENERATE_PERLMOD") && + !Config_getBool("GENERATE_RTF") && + !Config_getBool("GENERATE_AUTOGEN_DEF") && + Config_getString("GENERATE_TAGFILE").isEmpty() + ) + { + config_err("warning: No output formats selected! Set at least one of the main GENERATE_* options to YES.\n"); + } + + // check HTMLHELP creation requirements + if (!Config_getBool("GENERATE_HTML") && + Config_getBool("GENERATE_HTMLHELP")) + { + config_err("warning: GENERATE_HTMLHELP=YES requires GENERATE_HTML=YES.\n"); + } + + // check QHP creation requirements + if (Config_getBool("GENERATE_QHP")) + { + if (Config_getString("QHP_NAMESPACE").isEmpty()) + { + config_err("error: GENERATE_QHP=YES requires QHP_NAMESPACE to be set. Using 'org.doxygen.doc' as default!.\n"); + Config_getString("QHP_NAMESPACE")="org.doxygen.doc"; + } + + if (Config_getString("QHP_VIRTUAL_FOLDER").isEmpty()) + { + config_err("error: GENERATE_QHP=YES requires QHP_VIRTUAL_FOLDER to be set. Using 'doc' as default!\n"); + Config_getString("QHP_VIRTUAL_FOLDER")="doc"; + } + } + + if (Config_getBool("OPTIMIZE_OUTPUT_JAVA") && Config_getBool("INLINE_INFO")) + { + // don't show inline info for Java output, since Java has no inline + // concept. + Config_getBool("INLINE_INFO")=FALSE; + } + + int &depth = Config_getInt("MAX_DOT_GRAPH_DEPTH"); + if (depth==0) + { + depth=1000; + } + + int &hue = Config_getInt("HTML_COLORSTYLE_HUE"); + if (hue<0) + { + hue=0; + } + else if (hue>=360) + { + hue=hue%360; + } + + int &sat = Config_getInt("HTML_COLORSTYLE_SAT"); + if (sat<0) + { + sat=0; + } + else if (sat>255) + { + sat=255; + } + int &gamma = Config_getInt("HTML_COLORSTYLE_GAMMA"); + if (gamma<40) + { + gamma=40; + } + else if (gamma>240) + { + gamma=240; + } + + + // add default words if needed + QStrList &annotationFromBrief = Config_getList("ABBREVIATE_BRIEF"); + if (annotationFromBrief.isEmpty()) + { + annotationFromBrief.append("The $name class"); + annotationFromBrief.append("The $name widget"); + annotationFromBrief.append("The $name file"); + annotationFromBrief.append("is"); + annotationFromBrief.append("provides"); + annotationFromBrief.append("specifies"); + annotationFromBrief.append("contains"); + annotationFromBrief.append("represents"); + annotationFromBrief.append("a"); + annotationFromBrief.append("an"); + annotationFromBrief.append("the"); + } + + // some default settings for vhdl + if (Config_getBool("OPTIMIZE_OUTPUT_VHDL") && + (Config_getBool("INLINE_INHERITED_MEMB") || + Config_getBool("INHERIT_DOCS") || + !Config_getBool("HIDE_SCOPE_NAMES") || + !Config_getBool("EXTRACT_PRIVATE") || + !Config_getBool("EXTRACT_PACKAGE") + ) + ) + { + bool b1 = Config_getBool("INLINE_INHERITED_MEMB"); + bool b2 = Config_getBool("INHERIT_DOCS"); + bool b3 = Config_getBool("HIDE_SCOPE_NAMES"); + bool b4 = Config_getBool("EXTRACT_PRIVATE"); + bool b5 = Config_getBool("SKIP_FUNCTION_MACROS"); + bool b6 = Config_getBool("EXTRACT_PACKAGE"); + const char *s1,*s2,*s3,*s4,*s5,*s6; + if (b1) s1=" INLINDE_INHERITED_MEMB = NO (was YES)\n"; else s1=""; + if (b2) s2=" INHERIT_DOCS = NO (was YES)\n"; else s2=""; + if (!b3) s3=" HIDE_SCOPE_NAMES = YES (was NO)\n"; else s3=""; + if (!b4) s4=" EXTRACT_PRIVATE = YES (was NO)\n"; else s4=""; + if (b5) s5=" ENABLE_PREPROCESSING = NO (was YES)\n"; else s5=""; + if (!b6) s6=" EXTRACT_PACKAGE = YES (was NO)\n"; else s6=""; + + + config_err("warning: enabling OPTIMIZE_OUTPUT_VHDL assumes the following settings:\n" + "%s%s%s%s%s%s",s1,s2,s3,s4,s5,s6 + ); + + Config_getBool("INLINE_INHERITED_MEMB") = FALSE; + Config_getBool("INHERIT_DOCS") = FALSE; + Config_getBool("HIDE_SCOPE_NAMES") = TRUE; + Config_getBool("EXTRACT_PRIVATE") = TRUE; + Config_getBool("ENABLE_PREPROCESSING") = FALSE; + Config_getBool("EXTRACT_PACKAGE") = TRUE; + } + +} + +void Config::init() +{ + ConfigOption *option = m_options->first(); + while (option) + { + option->init(); + option = m_options->next(); + } +} + +void Config::create() +{ + if (m_initialized) return; + m_initialized = TRUE; + addConfigOptions(this); +} + +static QCString configFileToString(const char *name) +{ + if (name==0 || name[0]==0) return 0; + QFile f; + + bool fileOpened=FALSE; + if (name[0]=='-' && name[1]==0) // read from stdin + { + fileOpened=f.open(IO_ReadOnly,stdin); + if (fileOpened) + { + const int bSize=4096; + QCString contents(bSize); + int totalSize=0; + int size; + while ((size=f.readBlock(contents.data()+totalSize,bSize))==bSize) + { + totalSize+=bSize; + contents.resize(totalSize+bSize); + } + totalSize+=size+2; + contents.resize(totalSize); + contents.at(totalSize-2)='\n'; // to help the scanner + contents.at(totalSize-1)='\0'; + return contents; + } + } + else // read from file + { + QFileInfo fi(name); + if (!fi.exists() || !fi.isFile()) + { + config_err("error: file `%s' not found\n",name); + return ""; + } + f.setName(name); + fileOpened=f.open(IO_ReadOnly); + if (fileOpened) + { + int fsize=f.size(); + QCString contents(fsize+2); + f.readBlock(contents.data(),fsize); + f.close(); + if (fsize==0 || contents[fsize-1]=='\n') + contents[fsize]='\0'; + else + contents[fsize]='\n'; // to help the scanner + contents[fsize+1]='\0'; + return contents; + } + } + if (!fileOpened) + { + config_err("error: cannot open file `%s' for reading\n",name); + } + return ""; +} + +bool Config::parseString(const char *fn,const char *str) +{ + config = Config::instance(); + inputString = str; + inputPosition = 0; + yyFileName = fn; + yyLineNr = 1; + includeStack.setAutoDelete(TRUE); + includeStack.clear(); + includeDepth = 0; + configYYrestart( configYYin ); + BEGIN( Start ); + configYYlex(); + inputString = 0; + return TRUE; +} + +bool Config::parse(const char *fn) +{ + encoding = "UTF-8"; + return parseString(fn,configFileToString(fn)); +} + +extern "C" { // some bogus code to keep the compiler happy + //int configYYwrap() { return 1 ; } +} diff --git a/trunk/src/config.xml b/trunk/src/config.xml new file mode 100644 index 0000000..8e12fe0 --- /dev/null +++ b/trunk/src/config.xml @@ -0,0 +1,1641 @@ +<doxygenconfig> + <group name='Project' docs='Project related configuration options'> + <option type='string' id='DOXYFILE_ENCODING' format='string' docs=' +This tag specifies the encoding used for all characters in the config file +that follow. The default is UTF-8 which is also the encoding used for all +text before the first occurrence of this tag. Doxygen uses libiconv (or the +iconv built into libc) for the transcoding. See +http://www.gnu.org/software/libiconv for the list of possible encodings. +' defval='UTF-8'/> + <option type='string' id='PROJECT_NAME' format='string' docs=' +The PROJECT_NAME tag is a single word (or sequence of words) that should +identify the project. Note that if you do not use Doxywizard you need +to put quotes around the project name if it contains spaces.' defval='My Project'/> + <option type='string' id='PROJECT_NUMBER' format='string' docs=' +The PROJECT_NUMBER tag can be used to enter a project or revision number. +This could be handy for archiving the generated documentation or +if some version control system is used. +' defval=''/> + <option type='string' id='PROJECT_BRIEF' format='string' docs=' +Using the PROJECT_BRIEF tag one can provide an optional one line description +for a project that appears at the top of each page and should give viewer +a quick idea about the purpose of the project. Keep the description short. +' defval=''/> + <option type='string' id='PROJECT_LOGO' format='file' docs=' +With the PROJECT_LOGO tag one can specify an logo or icon that is +included in the documentation. The maximum height of the logo should not +exceed 55 pixels and the maximum width should not exceed 200 pixels. +Doxygen will copy the logo to the output directory. +' defval=''/> + <option type='string' id='OUTPUT_DIRECTORY' format='dir' docs=' +The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +base path where the generated documentation will be put. +If a relative path is entered, it will be relative to the location +where doxygen was started. If left blank the current directory will be used. +' defval=''/> + <option type='bool' id='CREATE_SUBDIRS' docs=' +If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +4096 sub-directories (in 2 levels) under the output directory of each output +format and will distribute the generated files over these directories. +Enabling this option can be useful when feeding doxygen a huge amount of +source files, where putting all generated files in the same directory would +otherwise cause performance problems for the file system. +' defval='0'/> + <option type='enum' id='OUTPUT_LANGUAGE' defval='English' docs=' +The OUTPUT_LANGUAGE tag is used to specify the language in which all +documentation generated by doxygen is written. Doxygen will use this +information to generate all constant output in the proper language. +The default language is English, other supported languages are: +Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, +Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English +messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, +Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, +Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. +'> + <value name='Afrikaans'/> + <value name='Arabic'/> + <value name='Brazilian'/> + <value name='Catalan'/> + <value name='Chinese'/> + <value name='Chinese-Traditional'/> + <value name='Croatian'/> + <value name='Czech'/> + <value name='Danish'/> + <value name='Dutch'/> + <value name='English'/> + <value name='Esperanto'/> + <value name='Farsi'/> + <value name='Finnish'/> + <value name='French'/> + <value name='German'/> + <value name='Greek'/> + <value name='Hungarian'/> + <value name='Italian'/> + <value name='Japanese'/> + <value name='Japanese-en'/> + <value name='Korean'/> + <value name='Korean-en'/> + <value name='Norwegian'/> + <value name='Macedonian'/> + <value name='Persian'/> + <value name='Polish'/> + <value name='Portuguese'/> + <value name='Romanian'/> + <value name='Russian'/> + <value name='Serbian'/> + <value name='Slovak'/> + <value name='Slovene'/> + <value name='Spanish'/> + <value name='Swedish'/> + <value name='Turkish'/> + <value name='Ukrainian'/> + <value name='Vietnamese'/> + </option> + <option type='bool' id='BRIEF_MEMBER_DESC' docs=' +If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +include brief member descriptions after the members that are listed in +the file and class documentation (similar to JavaDoc). +Set to NO to disable this. +' defval='1'/> + <option type='bool' id='REPEAT_BRIEF' docs=' +If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +the brief description of a member or function before the detailed description. +Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +brief descriptions will be completely suppressed. +' defval='1'/> + <option type='list' id='ABBREVIATE_BRIEF' format='string' docs=' +This tag implements a quasi-intelligent brief description abbreviator +that is used to form the text in various listings. Each string +in this list, if found as the leading text of the brief description, will be +stripped from the text and the result after processing the whole list, is +used as the annotated text. Otherwise, the brief description is used as-is. +If left blank, the following values are used ("$name" is automatically +replaced with the name of the entity): "The $name class" "The $name widget" +"The $name file" "is" "provides" "specifies" "contains" +"represents" "a" "an" "the" +'> + <value name='The $name class'/> + <value name='The $name widget'/> + <value name='The $name file'/> + <value name='is'/> + <value name='provides'/> + <value name='specifies'/> + <value name='contains'/> + <value name='represents'/> + <value name='a'/> + <value name='an'/> + <value name='the'/> + </option> + <option type='bool' id='ALWAYS_DETAILED_SEC' docs=' +If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +Doxygen will generate a detailed section even if there is only a brief +description. +' defval='0'/> + <option type='bool' id='INLINE_INHERITED_MEMB' docs=' +If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +inherited members of a class in the documentation of that class as if those +members were ordinary class members. Constructors, destructors and assignment +operators of the base classes will not be shown. +' defval='0'/> + <option type='bool' id='FULL_PATH_NAMES' docs=' +If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +path before files name in the file list and in the header files. If set +to NO the shortest path that makes the file name unique will be used. +' defval='1'/> + <option type='list' id='STRIP_FROM_PATH' format='string' docs=' +If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +can be used to strip a user-defined part of the path. Stripping is +only done if one of the specified strings matches the left-hand part of +the path. The tag can be used to show relative paths in the file list. +If left blank the directory from which doxygen is run is used as the +path to strip. +' depends='FULL_PATH_NAMES'> + <value name=''/> + </option> + <option type='list' id='STRIP_FROM_INC_PATH' format='string' docs=' +The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +the path mentioned in the documentation of a class, which tells +the reader which header file to include in order to use a class. +If left blank only the name of the header file containing the class +definition is used. Otherwise one should specify the include paths that +are normally passed to the compiler using the -I flag. +'> + </option> + <option type='bool' id='SHORT_NAMES' docs=' +If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +(but less readable) file names. This can be useful if your file system +doesn't support long names like on DOS, Mac, or CD-ROM. +' defval='0'/> + <option type='bool' id='JAVADOC_AUTOBRIEF' docs=' +If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +will interpret the first line (until the first dot) of a JavaDoc-style +comment as the brief description. If set to NO, the JavaDoc +comments will behave just like regular Qt-style comments +(thus requiring an explicit @brief command for a brief description.) +' defval='0'/> + <option type='bool' id='QT_AUTOBRIEF' docs=' +If the QT_AUTOBRIEF tag is set to YES then Doxygen will +interpret the first line (until the first dot) of a Qt-style +comment as the brief description. If set to NO, the comments +will behave just like regular Qt-style comments (thus requiring +an explicit \brief command for a brief description.) +' defval='0'/> + <option type='bool' id='MULTILINE_CPP_IS_BRIEF' docs=' +The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +treat a multi-line C++ special comment block (i.e. a block of //! or /// +comments) as a brief description. This used to be the default behaviour. +The new default is to treat a multi-line C++ comment block as a detailed +description. Set this tag to YES if you prefer the old behaviour instead. +' defval='0'/> + <option type='bool' id='INHERIT_DOCS' docs=' +If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +member inherits the documentation from any documented member that it +re-implements. +' defval='1'/> + <option type='bool' id='SEPARATE_MEMBER_PAGES' docs=' +If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +a new page for each member. If set to NO, the documentation of a member will +be part of the file/class/namespace that contains it. +' defval='0'/> + <option type='int' id='TAB_SIZE' docs=' +The TAB_SIZE tag can be used to set the number of spaces in a tab. +Doxygen uses this value to replace tabs by spaces in code fragments. +' minval='1' maxval='16' defval='8'/> + <option type='list' id='ALIASES' format='string' docs=' +This tag can be used to specify a number of aliases that acts +as commands in the documentation. An alias has the form "name=value". +For example adding "sideeffect=\par Side Effects:\n" will allow you to +put the command \sideeffect (or @sideeffect) in the documentation, which +will result in a user-defined paragraph with heading "Side Effects:". +You can put \n's in the value part of an alias to insert newlines. +'/> + <option type='list' id='TCL_SUBST' format='string' docs=' +This tag can be used to specify a number of word-keyword mappings (TCL only). +A mapping has the form "name=value". For example adding +"class=itcl::class" will allow you to use the command class in the +itcl::class meaning. +'/> + <option type='bool' id='OPTIMIZE_OUTPUT_FOR_C' docs=' +Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +sources only. Doxygen will then generate output that is more tailored for C. +For instance, some of the names that are used will be different. The list +of all members will be omitted, etc. +' defval='0'/> + <option type='bool' id='OPTIMIZE_OUTPUT_JAVA' docs=' +Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +sources only. Doxygen will then generate output that is more tailored for +Java. For instance, namespaces will be presented as packages, qualified +scopes will look different, etc. +' defval='0'/> + <option type='bool' id='OPTIMIZE_FOR_FORTRAN' docs=' +Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +sources only. Doxygen will then generate output that is more tailored for +Fortran. +' defval='0'/> + <option type='bool' id='OPTIMIZE_OUTPUT_VHDL' docs=' +Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +sources. Doxygen will then generate output that is tailored for +VHDL. +' defval='0'/> + <option type='list' id='EXTENSION_MAPPING' format='string' docs=' +Doxygen selects the parser to use depending on the extension of the files it +parses. With this tag you can assign which parser to use for a given extension. +Doxygen has a built-in mapping, but you can override or extend it using this +tag. The format is ext=language, where ext is a file extension, and language +is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C, +C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make +doxygen treat .inc files as Fortran files (default is PHP), and .f files as C +(default is Fortran), use: inc=Fortran f=C. Note that for custom extensions +you also need to set FILE_PATTERNS otherwise the files are not read by doxygen. +'> + </option> + <option type='bool' id='MARKDOWN_SUPPORT' docs=' +If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all +comments according to the Markdown format, which allows for more readable +documentation. See http://daringfireball.net/projects/markdown/ for details. +The output of markdown processing is further processed by doxygen, so you +can mix doxygen, HTML, and XML commands with Markdown formatting. +Disable only in case of backward compatibilities issues. +' defval='1'/> + <option type='bool' id='BUILTIN_STL_SUPPORT' docs=' +If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +to include (a tag file for) the STL sources as input, then you should +set this tag to YES in order to let doxygen match functions declarations and +definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +func(std::string) {}). This also makes the inheritance and collaboration +diagrams that involve STL classes more complete and accurate. +' defval='0'/> + <option type='bool' id='CPP_CLI_SUPPORT' docs=' +If you use Microsoft's C++/CLI language, you should set this option to YES to +enable parsing support. +' defval='0'/> + <option type='bool' id='SIP_SUPPORT' docs=' +Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. +Doxygen will parse them like normal C++ but will assume all classes use public +instead of private inheritance when no explicit protection keyword is present. +' defval='0'/> + <option type='bool' id='IDL_PROPERTY_SUPPORT' docs=' +For Microsoft's IDL there are propget and propput attributes to indicate getter +and setter methods for a property. Setting this option to YES (the default) +will make doxygen replace the get and set methods by a property in the +documentation. This will only work if the methods are indeed getting or +setting a simple type. If this is not the case, or you want to show the +methods anyway, you should set this option to NO. +' defval='1'/> + <option type='bool' id='DISTRIBUTE_GROUP_DOC' docs=' +If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +tag is set to YES, then doxygen will reuse the documentation of the first +member in the group (if any) for the other members of the group. By default +all members of a group must be documented explicitly. +' defval='0'/> + <option type='bool' id='SUBGROUPING' docs=' +Set the SUBGROUPING tag to YES (the default) to allow class member groups of +the same type (for instance a group of public functions) to be put as a +subgroup of that type (e.g. under the Public Functions section). Set it to +NO to prevent subgrouping. Alternatively, this can be done per class using +the \nosubgrouping command. +' defval='1'/> + <option type='bool' id='INLINE_GROUPED_CLASSES' docs=' +When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and +unions are shown inside the group in which they are included (e.g. using +@ingroup) instead of on a separate page (for HTML and Man pages) or +section (for LaTeX and RTF). +' defval='0'/> + <option type='bool' id='INLINE_SIMPLE_STRUCTS' docs=' +When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and +unions with only public data fields will be shown inline in the documentation +of the scope in which they are defined (i.e. file, namespace, or group +documentation), provided this scope is documented. If set to NO (the default), +structs, classes, and unions are shown on a separate page (for HTML and Man +pages) or section (for LaTeX and RTF).' defval='0'/> + <option type='bool' id='TYPEDEF_HIDES_STRUCT' docs=' +When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum +is documented as struct, union, or enum with the name of the typedef. So +typedef struct TypeS {} TypeT, will appear in the documentation as a struct +with name TypeT. When disabled the typedef will appear as a member of a file, +namespace, or class. And the struct will be named TypeS. This can typically +be useful for C code in case the coding convention dictates that all compound +types are typedef'ed and only the typedef is referenced, never the tag name. +' defval='0'/> + <option type='int' id='SYMBOL_CACHE_SIZE' docs=' +The SYMBOL_CACHE_SIZE determines the size of the internal cache use to +determine which symbols to keep in memory and which to flush to disk. +When the cache is full, less often used symbols will be written to disk. +For small to medium size projects (<1000 input files) the default value is +probably good enough. For larger projects a too small cache size can cause +doxygen to be busy swapping symbols to and from disk most of the time +causing a significant performance penalty. +If the system has enough physical memory increasing the cache will improve the +performance by keeping more symbols in memory. Note that the value works on +a logarithmic scale so increasing the size by one will roughly double the +memory usage. The cache size is given by this formula: +2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, +corresponding to a cache size of 2^16 = 65536 symbols. +' minval='0' maxval='9' defval='0'/> + <option type='int' id='LOOKUP_CACHE_SIZE' docs=' +Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be +set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given +their name and scope. Since this can be an expensive process and often the +same symbol appear multiple times in the code, doxygen keeps a cache of +pre-resolved symbols. If the cache is too small doxygen will become slower. +If the cache is too large, memory is wasted. The cache size is given by this +formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range is 0..9, the default is 0, +corresponding to a cache size of 2^16 = 65536 symbols. +' minval='0' maxval='9' defval='0'/> + </group> + <group name='Build' docs='Build related configuration options'> + <option type='bool' id='EXTRACT_ALL' docs=' +If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +documentation are documented, even if no documentation was available. +Private class members and static file members will be hidden unless +the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES +' defval='0'/> + <option type='bool' id='EXTRACT_PRIVATE' docs=' +If the EXTRACT_PRIVATE tag is set to YES all private members of a class +will be included in the documentation. +' defval='0'/> + <option type='bool' id='EXTRACT_PACKAGE' docs=' +If the EXTRACT_PACKAGE tag is set to YES all members with package or internal +scope will be included in the documentation. +' defval='0'/> + <option type='bool' id='EXTRACT_STATIC' docs=' +If the EXTRACT_STATIC tag is set to YES all static members of a file +will be included in the documentation. +' defval='0'/> + <option type='bool' id='EXTRACT_LOCAL_CLASSES' docs=' +If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +defined locally in source files will be included in the documentation. +If set to NO only classes defined in header files are included. +' defval='1'/> + <option type='bool' id='EXTRACT_LOCAL_METHODS' docs=' +This flag is only useful for Objective-C code. When set to YES local +methods, which are defined in the implementation section but not in +the interface are included in the documentation. +If set to NO (the default) only methods in the interface are included. +' defval='0'/> + <option type='bool' id='EXTRACT_ANON_NSPACES' docs=' +If this flag is set to YES, the members of anonymous namespaces will be +extracted and appear in the documentation as a namespace called +'anonymous_namespace{file}', where file will be replaced with the base +name of the file that contains the anonymous namespace. By default +anonymous namespaces are hidden. +' defval='0'/> + <option type='bool' id='HIDE_UNDOC_MEMBERS' docs=' +If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +undocumented members of documented classes, files or namespaces. +If set to NO (the default) these members will be included in the +various overviews, but no documentation section is generated. +This option has no effect if EXTRACT_ALL is enabled. +' defval='0'/> + <option type='bool' id='HIDE_UNDOC_CLASSES' docs=' +If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +undocumented classes that are normally visible in the class hierarchy. +If set to NO (the default) these classes will be included in the various +overviews. This option has no effect if EXTRACT_ALL is enabled. +' defval='0'/> + <option type='bool' id='HIDE_FRIEND_COMPOUNDS' docs=' +If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +friend (class|struct|union) declarations. +If set to NO (the default) these declarations will be included in the +documentation. +' defval='0'/> + <option type='bool' id='HIDE_IN_BODY_DOCS' docs=' +If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +documentation blocks found inside the body of a function. +If set to NO (the default) these blocks will be appended to the +function's detailed documentation block. +' defval='0'/> + <option type='bool' id='INTERNAL_DOCS' docs=' +The INTERNAL_DOCS tag determines if documentation +that is typed after a \internal command is included. If the tag is set +to NO (the default) then the documentation will be excluded. +Set it to YES to include the internal documentation. +' defval='0'/> + <option type='bool' id='CASE_SENSE_NAMES' docs=' +If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +file names in lower-case letters. If set to YES upper-case letters are also +allowed. This is useful if you have classes or files whose names only differ +in case and if your file system supports case sensitive file names. Windows +and Mac users are advised to set this option to NO. +' defval='0' altdefval='portable_fileSystemIsCaseSensitive()'/> + <option type='bool' id='HIDE_SCOPE_NAMES' docs=' +If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +will show members with their full class and namespace scopes in the +documentation. If set to YES the scope will be hidden. +' defval='0'/> + <option type='bool' id='SHOW_INCLUDE_FILES' docs=' +If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +will put a list of the files that are included by a file in the documentation +of that file. +' defval='1'/> + <option type='bool' id='FORCE_LOCAL_INCLUDES' docs=' +If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen +will list include files with double quotes in the documentation +rather than with sharp brackets. +' defval='0'/> + <option type='bool' id='INLINE_INFO' docs=' +If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +is inserted in the documentation for inline members. +' defval='1'/> + <option type='bool' id='SORT_MEMBER_DOCS' docs=' +If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +will sort the (detailed) documentation of file and class members +alphabetically by member name. If set to NO the members will appear in +declaration order. +' defval='1'/> + <option type='bool' id='SORT_BRIEF_DOCS' docs=' +If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +brief documentation of file, namespace and class members alphabetically +by member name. If set to NO (the default) the members will appear in +declaration order. +' defval='0'/> + <option type='bool' id='SORT_MEMBERS_CTORS_1ST' docs=' +If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen +will sort the (brief and detailed) documentation of class members so that +constructors and destructors are listed first. If set to NO (the default) +the constructors will appear in the respective orders defined by +SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. +This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO +and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO.' defval='0'/> + <option type='bool' id='SORT_GROUP_NAMES' docs=' +If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the +hierarchy of group names into alphabetical order. If set to NO (the default) +the group names will appear in their defined order. +' defval='0'/> + <option type='bool' id='SORT_BY_SCOPE_NAME' docs=' +If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +sorted by fully-qualified names, including namespaces. If set to +NO (the default), the class list will be sorted only by class name, +not including the namespace part. +Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +Note: This option applies only to the class list, not to the +alphabetical list. +' defval='0'/> + <option type='bool' id='STRICT_PROTO_MATCHING' docs=' +If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to +do proper type resolution of all parameters of a function it will reject a +match between the prototype and the implementation of a member function even +if there is only one candidate or it is obvious which candidate to choose +by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen +will still accept a match between prototype and implementation in such cases. +' defval='0'/> + <option type='bool' id='GENERATE_TODOLIST' docs=' +The GENERATE_TODOLIST tag can be used to enable (YES) or +disable (NO) the todo list. This list is created by putting \todo +commands in the documentation. +' defval='1'/> + <option type='bool' id='GENERATE_TESTLIST' docs=' +The GENERATE_TESTLIST tag can be used to enable (YES) or +disable (NO) the test list. This list is created by putting \test +commands in the documentation. +' defval='1'/> + <option type='bool' id='GENERATE_BUGLIST' docs=' +The GENERATE_BUGLIST tag can be used to enable (YES) or +disable (NO) the bug list. This list is created by putting \bug +commands in the documentation. +' defval='1'/> + <option type='bool' id='GENERATE_DEPRECATEDLIST' docs=' +The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +disable (NO) the deprecated list. This list is created by putting +\deprecated commands in the documentation. +' defval='1'/> + <option type='list' id='ENABLED_SECTIONS' format='string' docs=' +The ENABLED_SECTIONS tag can be used to enable conditional +documentation sections, marked by \if sectionname ... \endif. +'> + </option> + <option type='int' id='MAX_INITIALIZER_LINES' docs=' +The MAX_INITIALIZER_LINES tag determines the maximum number of lines +the initial value of a variable or macro consists of for it to appear in +the documentation. If the initializer consists of more lines than specified +here it will be hidden. Use a value of 0 to hide initializers completely. +The appearance of the initializer of individual variables and macros in the +documentation can be controlled using \showinitializer or \hideinitializer +command in the documentation regardless of this setting. +' minval='0' maxval='10000' defval='30'/> + <option type='bool' id='SHOW_USED_FILES' docs=' +Set the SHOW_USED_FILES tag to NO to disable the list of files generated +at the bottom of the documentation of classes and structs. If set to YES the +list will mention the files that were used to generate the documentation. +' defval='1'/> + <option type='bool' id='SHOW_DIRECTORIES' docs=' +If the sources in your project are distributed over multiple directories +then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy +in the documentation. The default is NO. +' defval='0'/> + <option type='bool' id='SHOW_FILES' docs=' +Set the SHOW_FILES tag to NO to disable the generation of the Files page. +This will remove the Files entry from the Quick Index and from the +Folder Tree View (if specified). The default is YES. +' defval='1'/> + <option type='bool' id='SHOW_NAMESPACES' docs=' +Set the SHOW_NAMESPACES tag to NO to disable the generation of the +Namespaces page. This will remove the Namespaces entry from the Quick Index +and from the Folder Tree View (if specified). The default is YES. +' defval='1'/> + <option type='string' id='FILE_VERSION_FILTER' format='file' docs=' +The FILE_VERSION_FILTER tag can be used to specify a program or script that +doxygen should invoke to get the current version for each file (typically from +the version control system). Doxygen will invoke the program by executing (via +popen()) the command <command> <input-file>, where <command> is the value of +the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file +provided by doxygen. Whatever the program writes to standard output +is used as the file version. See the manual for examples. +' defval=''/> + <option type='string' id='LAYOUT_FILE' format='file' docs=' +The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +by doxygen. The layout file controls the global structure of the generated +output files in an output format independent way. The create the layout file +that represents doxygen's defaults, run doxygen with the -l option. +You can optionally specify a file name after the option, if omitted +DoxygenLayout.xml will be used as the name of the layout file. +' defval=''/> + <option type='list' id='CITE_BIB_FILES' format='file' docs=' +The CITE_BIB_FILES tag can be used to specify one or more bib files +containing the references data. This must be a list of .bib files. The +.bib extension is automatically appended if omitted. Using this command +requires the bibtex tool to be installed. See also +http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style +of the bibliography can be controlled using LATEX_BIB_STYLE. To use this +feature you need bibtex and perl available in the search path. +' defval=''/> + </group> + <group name='Messages' docs='configuration options related to warning and progress messages'> + <option type='bool' id='QUIET' docs=' +The QUIET tag can be used to turn on/off the messages that are generated +by doxygen. Possible values are YES and NO. If left blank NO is used. +' defval='0'/> + <option type='bool' id='WARNINGS' docs=' +The WARNINGS tag can be used to turn on/off the warning messages that are +generated by doxygen. Possible values are YES and NO. If left blank +NO is used. +' defval='1'/> + <option type='bool' id='WARN_IF_UNDOCUMENTED' docs=' +If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +for undocumented members. If EXTRACT_ALL is set to YES then this flag will +automatically be disabled. +' defval='1'/> + <option type='bool' id='WARN_IF_DOC_ERROR' docs=' +If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +potential errors in the documentation, such as not documenting some +parameters in a documented function, or documenting parameters that +don't exist or using markup commands wrongly. +' defval='1'/> + <option type='bool' id='WARN_NO_PARAMDOC' docs=' +The WARN_NO_PARAMDOC option can be enabled to get warnings for +functions that are documented, but have no documentation for their parameters +or return value. If set to NO (the default) doxygen will only warn about +wrong or incomplete parameter documentation, but not about the absence of +documentation. +' defval='0'/> + <option type='string' id='WARN_FORMAT' format='string' docs=' +The WARN_FORMAT tag determines the format of the warning messages that +doxygen can produce. The string should contain the $file, $line, and $text +tags, which will be replaced by the file and line number from which the +warning originated and the warning text. Optionally the format may contain +$version, which will be replaced by the version of the file (if it could +be obtained via FILE_VERSION_FILTER) +' defval='$file:$line: $text'/> + <option type='string' id='WARN_LOGFILE' format='file' docs=' +The WARN_LOGFILE tag can be used to specify a file to which warning +and error messages should be written. If left blank the output is written +to stderr. +' defval=''/> + </group> + <group name='Input' docs='configuration options related to the input files'> + <option type='list' id='INPUT' format='filedir' docs=' +The INPUT tag can be used to specify the files and/or directories that contain +documented source files. You may enter file names like "myfile.cpp" or +directories like "/usr/src/myproject". Separate the files or directories +with spaces. +'> + <value name=''/> + </option> + <option type='string' id='INPUT_ENCODING' format='string' docs=' +This tag can be used to specify the character encoding of the source files +that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is +also the default input encoding. Doxygen uses libiconv (or the iconv built +into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +the list of possible encodings. +' defval='UTF-8'/> + <option type='list' id='FILE_PATTERNS' format='string' docs=' +If the value of the INPUT tag contains directories, you can use the +FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +and *.h) to filter out the source-files in the directories. If left +blank the following patterns are tested: +*.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh +*.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py +*.f90 *.f *.for *.vhd *.vhdl +'> + <value name='*.c'/> + <value name='*.cc'/> + <value name='*.cxx'/> + <value name='*.cpp'/> + <value name='*.c++'/> + <value name='*.d'/> + <value name='*.java'/> + <value name='*.ii'/> + <value name='*.ixx'/> + <value name='*.ipp'/> + <value name='*.i++'/> + <value name='*.inl'/> + <value name='*.h'/> + <value name='*.hh'/> + <value name='*.hxx'/> + <value name='*.hpp'/> + <value name='*.h++'/> + <value name='*.idl'/> + <value name='*.odl'/> + <value name='*.cs'/> + <value name='*.php'/> + <value name='*.php3'/> + <value name='*.inc'/> + <value name='*.m'/> + <value name='*.markdown'/> + <value name='*.md'/> + <value name='*.mm'/> + <value name='*.dox'/> + <value name='*.py'/> + <value name='*.f90'/> + <value name='*.f'/> + <value name='*.for'/> + <value name='*.vhd'/> + <value name='*.vhdl'/> + </option> + <option type='bool' id='RECURSIVE' docs=' +The RECURSIVE tag can be used to turn specify whether or not subdirectories +should be searched for input files as well. Possible values are YES and NO. +If left blank NO is used. +' defval='0'/> + <option type='list' id='EXCLUDE' format='filedir' docs=' +The EXCLUDE tag can be used to specify files and/or directories that should be +excluded from the INPUT source files. This way you can easily exclude a +subdirectory from a directory tree whose root is specified with the INPUT tag. +Note that relative paths are relative to the directory from which doxygen is +run. +'> + </option> + <option type='bool' id='EXCLUDE_SYMLINKS' docs=' +The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +directories that are symbolic links (a Unix file system feature) are excluded +from the input. +' defval='0'/> + <option type='list' id='EXCLUDE_PATTERNS' format='string' docs=' +If the value of the INPUT tag contains directories, you can use the +EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +certain files from those directories. Note that the wildcards are matched +against the file with absolute path, so to exclude all test directories +for example use the pattern */test/* +'> + </option> + <option type='list' id='EXCLUDE_SYMBOLS' format='string' docs=' +The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +(namespaces, classes, functions, etc.) that should be excluded from the +output. The symbol name can be a fully qualified name, a word, or if the +wildcard * is used, a substring. Examples: ANamespace, AClass, +AClass::ANamespace, ANamespace::*Test +'> + </option> + <option type='list' id='EXAMPLE_PATH' format='dir' docs=' +The EXAMPLE_PATH tag can be used to specify one or more files or +directories that contain example code fragments that are included (see +the \include command). +'> + </option> + <option type='list' id='EXAMPLE_PATTERNS' format='string' docs=' +If the value of the EXAMPLE_PATH tag contains directories, you can use the +EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +and *.h) to filter out the source-files in the directories. If left +blank all files are included. +'> + <value name='*'/> + </option> + <option type='bool' id='EXAMPLE_RECURSIVE' docs=' +If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +searched for input files to be used with the \include or \dontinclude +commands irrespective of the value of the RECURSIVE tag. +Possible values are YES and NO. If left blank NO is used. +' defval='0'/> + <option type='list' id='IMAGE_PATH' format='dir' docs=' +The IMAGE_PATH tag can be used to specify one or more files or +directories that contain image that are included in the documentation (see +the \image command). +'> + </option> + <option type='string' id='INPUT_FILTER' format='file' docs=' +The INPUT_FILTER tag can be used to specify a program that doxygen should +invoke to filter for each input file. Doxygen will invoke the filter program +by executing (via popen()) the command <filter> <input-file>, where <filter> +is the value of the INPUT_FILTER tag, and <input-file> is the name of an +input file. Doxygen will then use the output that the filter program writes +to standard output. If FILTER_PATTERNS is specified, this tag will be +ignored. +' defval=''/> + <option type='list' id='FILTER_PATTERNS' format='string' docs=' +The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +basis. Doxygen will compare the file name with each pattern and apply the +filter if there is a match. The filters are a list of the form: +pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +info on how filters are used. If FILTER_PATTERNS is empty or if +non of the patterns match the file name, INPUT_FILTER is applied. +'> + </option> + <option type='bool' id='FILTER_SOURCE_FILES' docs=' +If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +INPUT_FILTER) will be used to filter the input files when producing source +files to browse (i.e. when SOURCE_BROWSER is set to YES). +' defval='0'/> + <option type='list' id='FILTER_SOURCE_PATTERNS' format='string' docs=' +The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +pattern. A pattern will override the setting for FILTER_PATTERN (if any) +and it is also possible to disable source filtering for a specific pattern +using *.ext= (so without naming a filter). This option only has effect when +FILTER_SOURCE_FILES is enabled. +' depends='FILTER_SOURCE_FILES'/> + </group> + <group name='Source Browser' docs='configuration options related to source browsing'> + <option type='bool' id='SOURCE_BROWSER' docs=' +If the SOURCE_BROWSER tag is set to YES then a list of source files will +be generated. Documented entities will be cross-referenced with these sources. +Note: To get rid of all source code in the generated output, make sure also +VERBATIM_HEADERS is set to NO. +' defval='0'/> + <option type='bool' id='INLINE_SOURCES' docs=' +Setting the INLINE_SOURCES tag to YES will include the body +of functions and classes directly in the documentation. +' defval='0'/> + <option type='bool' id='STRIP_CODE_COMMENTS' docs=' +Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +doxygen to hide any special comment blocks from generated source code +fragments. Normal C and C++ comments will always remain visible. +' defval='1'/> + <option type='bool' id='REFERENCED_BY_RELATION' docs=' +If the REFERENCED_BY_RELATION tag is set to YES +then for each documented function all documented +functions referencing it will be listed. +' defval='0'/> + <option type='bool' id='REFERENCES_RELATION' docs=' +If the REFERENCES_RELATION tag is set to YES +then for each documented function all documented entities +called/used by that function will be listed. +' defval='0'/> + <option type='bool' id='REFERENCES_LINK_SOURCE' docs=' +If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +link to the source code. Otherwise they will link to the documentation. +' defval='1'/> + <option type='bool' id='USE_HTAGS' docs=' +If the USE_HTAGS tag is set to YES then the references to source code +will point to the HTML generated by the htags(1) tool instead of doxygen +built-in source browser. The htags tool is part of GNU's global source +tagging system (see http://www.gnu.org/software/global/global.html). You +will need version 4.8.6 or higher. +' defval='0' depends='SOURCE_BROWSER'/> + <option type='bool' id='VERBATIM_HEADERS' docs=' +If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +will generate a verbatim copy of the header file for each class for +which an include is specified. Set to NO to disable this. +' defval='1'/> + </group> + <group name='Index' docs='configuration options related to the alphabetical class index'> + <option type='bool' id='ALPHABETICAL_INDEX' docs=' +If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +of all compounds will be generated. Enable this if the project +contains a lot of classes, structs, unions or interfaces. +' defval='1'/> + <option type='int' id='COLS_IN_ALPHA_INDEX' docs=' +If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +in which this list will be split (can be a number in the range [1..20]) +' minval='1' maxval='20' defval='5'/> + <option type='list' id='IGNORE_PREFIX' format='string' docs=' +In case all classes in a project start with a common prefix, all +classes will be put under the same header in the alphabetical index. +The IGNORE_PREFIX tag can be used to specify one or more prefixes that +should be ignored while generating the index headers. +'> + </option> + </group> + <group name='HTML' docs='configuration options related to the HTML output'> + <option type='bool' id='GENERATE_HTML' docs=' +If the GENERATE_HTML tag is set to YES (the default) Doxygen will +generate HTML output. +' defval='1'/> + <option type='string' id='HTML_OUTPUT' format='dir' docs=' +The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +If a relative path is entered the value of OUTPUT_DIRECTORY will be +put in front of it. If left blank `html' will be used as the default path. +' defval='html' depends='GENERATE_HTML'/> + <option type='string' id='HTML_FILE_EXTENSION' format='string' docs=' +The HTML_FILE_EXTENSION tag can be used to specify the file extension for +each generated HTML page (for example: .htm,.php,.asp). If it is left blank +doxygen will generate files with .html extension. +' defval='.html' depends='GENERATE_HTML'/> + <option type='string' id='HTML_HEADER' format='file' docs=' +The HTML_HEADER tag can be used to specify a personal HTML header for +each generated HTML page. If it is left blank doxygen will generate a +standard header. Note that when using a custom header you are responsible +for the proper inclusion of any scripts and style sheets that doxygen +needs, which is dependent on the configuration options used. +It is advised to generate a default header using "doxygen -w html +header.html footer.html stylesheet.css YourConfigFile" and then modify +that header. Note that the header is subject to change so you typically +have to redo this when upgrading to a newer version of doxygen or when +changing the value of configuration settings such as GENERATE_TREEVIEW! +' defval='' depends='GENERATE_HTML'/> + <option type='string' id='HTML_FOOTER' format='file' docs=' +The HTML_FOOTER tag can be used to specify a personal HTML footer for +each generated HTML page. If it is left blank doxygen will generate a +standard footer. +' defval='' depends='GENERATE_HTML'/> + <option type='string' id='HTML_STYLESHEET' format='file' docs=' +The HTML_STYLESHEET tag can be used to specify a user-defined cascading +style sheet that is used by each HTML page. It can be used to +fine-tune the look of the HTML output. If the tag is left blank doxygen +will generate a default style sheet. Note that doxygen will try to copy +the style sheet file to the HTML output directory, so don't put your own +style sheet in the HTML output directory as well, or it will be erased! +' defval='' depends='GENERATE_HTML'/> + <option type='list' id='HTML_EXTRA_FILES' format='file' docs=' +The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +other source files which should be copied to the HTML output directory. Note +that these files will be copied to the base HTML output directory. Use the +$relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +files. In the HTML_STYLESHEET file, use the file name only. Also note that +the files will be copied as-is; there are no commands or markers available. +' depends='GENERATE_HTML'/> + <option type='int' id='HTML_COLORSTYLE_HUE' docs=' +The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. +Doxygen will adjust the colors in the style sheet and background images +according to this color. Hue is specified as an angle on a colorwheel, +see http://en.wikipedia.org/wiki/Hue for more information. +For instance the value 0 represents red, 60 is yellow, 120 is green, +180 is cyan, 240 is blue, 300 purple, and 360 is red again. +The allowed range is 0 to 359. +' minval='0' maxval='359' defval='220' depends='GENERATE_HTML'/> + <option type='int' id='HTML_COLORSTYLE_SAT' docs=' +The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of +the colors in the HTML output. For a value of 0 the output will use +grayscales only. A value of 255 will produce the most vivid colors. +' minval='0' maxval='255' defval='100' depends='GENERATE_HTML'/> + <option type='int' id='HTML_COLORSTYLE_GAMMA' docs=' +The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to +the luminance component of the colors in the HTML output. Values below +100 gradually make the output lighter, whereas values above 100 make +the output darker. The value divided by 100 is the actual gamma applied, +so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, +and 100 does not change the gamma. +' minval='40' maxval='240' defval='80'/> + <option type='bool' id='HTML_TIMESTAMP' docs=' +If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +page will contain the date and time when the page was generated. Setting +this to NO can help when comparing the output of multiple runs. +' defval='1' depends='GENERATE_HTML'/> + <option type='bool' id='HTML_ALIGN_MEMBERS' docs=' +If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +files or namespaces will be aligned in HTML using tables. If set to +NO a bullet list will be used. +' defval='1' depends='GENERATE_HTML'/> + <option type='bool' id='HTML_DYNAMIC_SECTIONS' docs=' +If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +documentation will contain sections that can be hidden and shown after the +page has loaded. For this to work a browser that supports +JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox +Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). +' defval='0' depends='GENERATE_HTML'/> + <option type='bool' id='GENERATE_DOCSET' docs=' +If the GENERATE_DOCSET tag is set to YES, additional index files +will be generated that can be used as input for Apple's Xcode 3 +integrated development environment, introduced with OSX 10.5 (Leopard). +To create a documentation set, doxygen will generate a Makefile in the +HTML output directory. Running make will produce the docset in that +directory and running "make install" will install the docset in +~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find +it at startup. +See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +for more information. +' defval='0' depends='GENERATE_HTML'/> + <option type='string' id='DOCSET_FEEDNAME' format='string' docs=' +When GENERATE_DOCSET tag is set to YES, this tag determines the name of the +feed. A documentation feed provides an umbrella under which multiple +documentation sets from a single provider (such as a company or product suite) +can be grouped. +' defval='Doxygen generated docs' depends='GENERATE_DOCSET'/> + <option type='string' id='DOCSET_BUNDLE_ID' format='string' docs=' +When GENERATE_DOCSET tag is set to YES, this tag specifies a string that +should uniquely identify the documentation set bundle. This should be a +reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen +will append .docset to the name. +' defval='org.doxygen.Project' depends='GENERATE_DOCSET'/> + <option type='string' id='DOCSET_PUBLISHER_ID' format='string' docs=' +When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify +the documentation publisher. This should be a reverse domain-name style +string, e.g. com.mycompany.MyDocSet.documentation. +' defval='org.doxygen.Publisher' depends='GENERATE_DOCSET'/> + <option type='string' id='DOCSET_PUBLISHER_NAME' format='string' docs=' +The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. +' defval='Publisher' depends='GENERATE_DOCSET'/> + <option type='bool' id='GENERATE_HTMLHELP' docs=' +If the GENERATE_HTMLHELP tag is set to YES, additional index files +will be generated that can be used as input for tools like the +Microsoft HTML help workshop to generate a compiled HTML help file (.chm) +of the generated HTML documentation. +' defval='0' depends='GENERATE_HTML'/> + <option type='string' id='CHM_FILE' format='file' docs=' +If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +be used to specify the file name of the resulting .chm file. You +can add a path in front of the file if the result should not be +written to the html output directory. +' defval='' depends='GENERATE_HTMLHELP'/> + <option type='string' id='HHC_LOCATION' format='file' docs=' +If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +be used to specify the location (absolute path including file name) of +the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +the HTML help compiler on the generated index.hhp. +' defval='' depends='GENERATE_HTMLHELP' abspath='1'/> + <option type='bool' id='GENERATE_CHI' docs=' +If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +controls if a separate .chi index file is generated (YES) or that +it should be included in the master .chm file (NO). +' defval='0' depends='GENERATE_HTMLHELP'/> + <option type='string' id='CHM_INDEX_ENCODING' format='string' docs=' +If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING +is used to encode HtmlHelp index (hhk), content (hhc) and project file +content. +' defval='' depends='GENERATE_HTMLHELP'/> + <option type='bool' id='BINARY_TOC' docs=' +If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +controls whether a binary table of contents is generated (YES) or a +normal table of contents (NO) in the .chm file. +' defval='0' depends='GENERATE_HTMLHELP'/> + <option type='bool' id='TOC_EXPAND' docs=' +The TOC_EXPAND flag can be set to YES to add extra items for group members +to the contents of the HTML help documentation and to the tree view. +' defval='0' depends='GENERATE_HTMLHELP'/> + <option type='bool' id='GENERATE_QHP' docs=' +If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +QHP_VIRTUAL_FOLDER are set, an additional index file will be generated +that can be used as input for Qt's qhelpgenerator to generate a +Qt Compressed Help (.qch) of the generated HTML documentation. +' defval='0' depends='GENERATE_HTML'/> + <option type='string' id='QCH_FILE' format='file' docs=' +If the QHG_LOCATION tag is specified, the QCH_FILE tag can +be used to specify the file name of the resulting .qch file. +The path specified is relative to the HTML output folder. +' defval='' depends='GENERATE_QHP'/> + <option type='string' id='QHP_NAMESPACE' format='string' docs=' +The QHP_NAMESPACE tag specifies the namespace to use when generating +Qt Help Project output. For more information please see +http://doc.trolltech.com/qthelpproject.html#namespace +' defval='org.doxygen.Project' depends='GENERATE_QHP'/> + <option type='string' id='QHP_VIRTUAL_FOLDER' format='string' docs=' +The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating +Qt Help Project output. For more information please see +http://doc.trolltech.com/qthelpproject.html#virtual-folders +' defval='doc' depends='GENERATE_QHP'/> + <option type='string' id='QHP_CUST_FILTER_NAME' format='string' docs=' +If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to +add. For more information please see +http://doc.trolltech.com/qthelpproject.html#custom-filters +' defval='' depends='GENERATE_QHP'/> + <option type='string' id='QHP_CUST_FILTER_ATTRS' format='string' docs=' +The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the +custom filter to add. For more information please see +<a href="http://doc.trolltech.com/qthelpproject.html#custom-filters"> +Qt Help Project / Custom Filters</a>. +' defval='' depends='GENERATE_QHP'/> + <option type='string' id='QHP_SECT_FILTER_ATTRS' format='string' docs=' +The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +project's +filter section matches. +<a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes"> +Qt Help Project / Filter Attributes</a>. +' defval='' depends='GENERATE_QHP'/> + <option type='string' id='QHG_LOCATION' format='file' docs=' +If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can +be used to specify the location of Qt's qhelpgenerator. +If non-empty doxygen will try to run qhelpgenerator on the generated +.qhp file. +' defval='' depends='GENERATE_QHP'/> + <option type='bool' id='GENERATE_ECLIPSEHELP' docs=' +If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files +will be generated, which together with the HTML files, form an Eclipse help +plugin. To install this plugin and make it available under the help contents +menu in Eclipse, the contents of the directory containing the HTML and XML +files needs to be copied into the plugins directory of eclipse. The name of +the directory within the plugins directory should be the same as +the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before +the help appears. +' defval='0' depends='GENERATE_HTML'/> + <option type='string' id='ECLIPSE_DOC_ID' docs=' +A unique identifier for the eclipse help plugin. When installing the plugin +the directory name containing the HTML and XML files should also have +this name. +' defval='org.doxygen.Project' depends='GENERATE_ECLIPSEHELP'/> + <option type='bool' id='DISABLE_INDEX' docs=' +The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) +at top of each HTML page. The value NO (the default) enables the index and +the value YES disables it. Since the tabs have the same information as the +navigation tree you can set this option to NO if you already set +GENERATE_TREEVIEW to YES. +' defval='0' depends='GENERATE_HTML'/> + <option type='bool' id='GENERATE_TREEVIEW' defval='0' docs=' +The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +structure should be generated to display hierarchical information. +If the tag value is set to YES, a side panel will be generated +containing a tree-like index structure (just like the one that +is generated for HTML Help). For this to work a browser that supports +JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). +Windows users are probably better off using the HTML help feature. +Since the tree basically has the same information as the tab index you +could consider to set DISABLE_INDEX to NO when enabling this option. +' depends='GENERATE_HTML'/> + <option type='int' id='ENUM_VALUES_PER_LINE' docs=' +The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values +(range [0,1..20]) that doxygen will group on one line in the generated HTML +documentation. Note that a value of 0 will completely suppress the enum +values from appearing in the overview section. +' minval='0' maxval='20' defval='4' depends='GENERATE_HTML'/> + <option type='bool' id='USE_INLINE_TREES' defval='0' docs=' +By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories, +and Class Hierarchy pages using a tree view instead of an ordered list. +' depends='GENERATE_HTML'/> + <option type='int' id='TREEVIEW_WIDTH' docs=' +If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +used to set the initial width (in pixels) of the frame in which the tree +is shown. +' minval='0' maxval='1500' defval='250' depends='GENERATE_HTML'/> + <option type='bool' id='EXT_LINKS_IN_WINDOW' defval='0' docs=' +When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open +links to external symbols imported via tag files in a separate window. +' depends='GENERATE_HTML'/> + <option type='int' id='FORMULA_FONTSIZE' docs=' +Use this tag to change the font size of Latex formulas included +as images in the HTML documentation. The default is 10. Note that +when you change the font size after a successful doxygen run you need +to manually remove any form_*.png images from the HTML output directory +to force them to be regenerated. +' minval='8' maxval='50' defval='10' depends='GENERATE_HTML'/> + <option type='bool' id='FORMULA_TRANSPARENT' docs=' +Use the FORMULA_TRANPARENT tag to determine whether or not the images +generated for formulas are transparent PNGs. Transparent PNGs are +not supported properly for IE 6.0, but are supported on all modern browsers. +Note that when changing this option you need to delete any form_*.png files +in the HTML output before the changes have effect. +' defval='1' depends='GENERATE_HTML'/> + <option type='bool' id='USE_MATHJAX' docs=' +Enable the USE_MATHJAX option to render LaTeX formulas using MathJax +(see http://www.mathjax.org) which uses client side Javascript for the +rendering instead of using prerendered bitmaps. Use this if you do not +have LaTeX installed or if you want to formulas look prettier in the HTML +output. When enabled you may also need to install MathJax separately and +configure the path to it using the MATHJAX_RELPATH option. +' defval='0'/> + <option type='string' id='MATHJAX_RELPATH' docs=' +When MathJax is enabled you need to specify the location relative to the +HTML output directory using the MATHJAX_RELPATH option. The destination +directory should contain the MathJax.js script. For instance, if the mathjax +directory is located at the same level as the HTML output directory, then +MATHJAX_RELPATH should be ../mathjax. The default value points to +the MathJax Content Delivery Network so you can quickly see the result without +installing MathJax. However, it is strongly recommended to install a local +copy of MathJax from http://www.mathjax.org before deployment. +' defval='http://cdn.mathjax.org/mathjax/latest'/> + <option type='list' id='MATHJAX_EXTENSIONS' format='string' docs=' +The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension +names that should be enabled during MathJax rendering. +' depends='USE_MATHJAX'> + </option> + <option type='bool' id='SEARCHENGINE' docs=' +When the SEARCHENGINE tag is enabled doxygen will generate a search box +for the HTML output. The underlying search engine uses javascript +and DHTML and should work on any modern browser. Note that when using +HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets +(GENERATE_DOCSET) there is already a search function so this one should +typically be disabled. For large projects the javascript based search engine +can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. +' defval='1' depends='GENERATE_HTML'/> + <option type='bool' id='SERVER_BASED_SEARCH' docs=' +When the SERVER_BASED_SEARCH tag is enabled the search engine will be +implemented using a PHP enabled web server instead of at the web client +using Javascript. Doxygen will generate the search PHP script and index +file to put on the web server. The advantage of the server +based approach is that it scales better to large projects and allows +full text search. The disadvantages are that it is more difficult to setup +and does not have live searching capabilities. +' defval='0' depends='SEARCHENGINE'/> + </group> + <group name='LaTeX' docs='configuration options related to the LaTeX output'> + <option type='bool' id='GENERATE_LATEX' docs=' +If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +generate Latex output. +' defval='1'/> + <option type='string' id='LATEX_OUTPUT' format='dir' docs=' +The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +If a relative path is entered the value of OUTPUT_DIRECTORY will be +put in front of it. If left blank `latex' will be used as the default path. +' defval='latex' depends='GENERATE_LATEX'/> + <option type='string' id='LATEX_CMD_NAME' format='file' docs=' +The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +invoked. If left blank `latex' will be used as the default command name. +Note that when enabling USE_PDFLATEX this option is only used for +generating bitmaps for formulas in the HTML output, but not in the +Makefile that is written to the output directory. +' defval='latex' depends='GENERATE_LATEX'/> + <option type='string' id='MAKEINDEX_CMD_NAME' format='file' docs=' +The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +generate index for LaTeX. If left blank `makeindex' will be used as the +default command name. +' defval='makeindex' depends='GENERATE_LATEX'/> + <option type='bool' id='COMPACT_LATEX' docs=' +If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +LaTeX documents. This may be useful for small projects and may help to +save some trees in general. +' defval='0' depends='GENERATE_LATEX'/> + <option type='enum' id='PAPER_TYPE' defval='a4' docs=' +The PAPER_TYPE tag can be used to set the paper type that is used +by the printer. Possible values are: a4, letter, legal and +executive. If left blank a4wide will be used. +' depends='GENERATE_LATEX'> + <value name='a4'/> + <value name='a4wide'/> + <value name='letter'/> + <value name='legal'/> + <value name='executive'/> + </option> + <option type='list' id='EXTRA_PACKAGES' format='string' docs=' +The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +packages that should be included in the LaTeX output. +' depends='GENERATE_LATEX'> + </option> + <option type='string' id='LATEX_HEADER' format='file' docs=' +The LATEX_HEADER tag can be used to specify a personal LaTeX header for +the generated latex document. The header should contain everything until +the first chapter. If it is left blank doxygen will generate a +standard header. Notice: only use this tag if you know what you are doing! +' defval='' depends='GENERATE_LATEX'/> + <option type='string' id='LATEX_FOOTER' format='file' docs=' +The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for +the generated latex document. The footer should contain everything after +the last chapter. If it is left blank doxygen will generate a +standard footer. Notice: only use this tag if you know what you are doing! +' defval='' depends='GENERATE_LATEX'/> + <option type='bool' id='PDF_HYPERLINKS' docs=' +If the PDF_HYPERLINKS tag is set to YES, the LaTeX 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 +This makes the output suitable for online browsing using a pdf viewer. +' defval='1' depends='GENERATE_LATEX'/> + <option type='bool' id='USE_PDFLATEX' docs=' +If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +plain latex in the generated Makefile. Set this option to YES to get a +higher quality PDF documentation. +' defval='1' depends='GENERATE_LATEX'/> + <option type='bool' id='LATEX_BATCHMODE' docs=' +If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +command to the generated LaTeX files. This will instruct LaTeX to keep +running if errors occur, instead of asking the user for help. +This option is also used when generating formulas in HTML. +' defval='0' depends='GENERATE_LATEX'/> + <option type='bool' id='LATEX_HIDE_INDICES' docs=' +If LATEX_HIDE_INDICES is set to YES then doxygen will not +include the index chapters (such as File Index, Compound Index, etc.) +in the output. +' defval='0' depends='GENERATE_LATEX'/> + <option type='bool' id='LATEX_SOURCE_CODE' docs=' +If LATEX_SOURCE_CODE is set to YES then doxygen will include +source code with syntax highlighting in the LaTeX output. +Note that which sources are shown also depends on other settings +such as SOURCE_BROWSER. +' defval='0' depends='GENERATE_LATEX'/> + <option type='string' id='LATEX_BIB_STYLE' format='string' docs=' +The LATEX_BIB_STYLE tag can be used to specify the style to use for the +bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See +http://en.wikipedia.org/wiki/BibTeX for more info. +' defval='plain'/> + </group> + <group name='RTF' docs='configuration options related to the RTF output'> + <option type='bool' id='GENERATE_RTF' docs=' +If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +The RTF output is optimized for Word 97 and may not look very pretty with +other RTF readers or editors. +' defval='0'/> + <option type='string' id='RTF_OUTPUT' format='dir' docs=' +The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +If a relative path is entered the value of OUTPUT_DIRECTORY will be +put in front of it. If left blank `rtf' will be used as the default path. +' defval='rtf' depends='GENERATE_RTF'/> + <option type='bool' id='COMPACT_RTF' docs=' +If the COMPACT_RTF tag is set to YES Doxygen generates more compact +RTF documents. This may be useful for small projects and may help to +save some trees in general. +' defval='0' depends='GENERATE_RTF'/> + <option type='bool' id='RTF_HYPERLINKS' docs=' +If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +will contain hyperlink fields. The RTF file will +contain links (just like the HTML output) instead of page references. +This makes the output suitable for online browsing using WORD or other +programs which support those fields. +Note: wordpad (write) and others do not support links. +' defval='0' depends='GENERATE_RTF'/> + <option type='string' id='RTF_STYLESHEET_FILE' format='file' docs=' +Load style sheet definitions from file. Syntax is similar to doxygen's +config file, i.e. a series of assignments. You only have to provide +replacements, missing definitions are set to their default value. +' defval='' depends='GENERATE_RTF'/> + <option type='string' id='RTF_EXTENSIONS_FILE' format='file' docs=' +Set optional variables used in the generation of an rtf document. +Syntax is similar to doxygen's config file. +' defval='' depends='GENERATE_RTF'/> + </group> + <group name='Man' docs='configuration options related to the man page output'> + <option type='bool' id='GENERATE_MAN' docs=' +If the GENERATE_MAN tag is set to YES (the default) Doxygen will +generate man pages +' defval='0'/> + <option type='string' id='MAN_OUTPUT' format='dir' docs=' +The MAN_OUTPUT tag is used to specify where the man pages will be put. +If a relative path is entered the value of OUTPUT_DIRECTORY will be +put in front of it. If left blank `man' will be used as the default path. +' defval='man' depends='GENERATE_MAN'/> + <option type='string' id='MAN_EXTENSION' format='string' docs=' +The MAN_EXTENSION tag determines the extension that is added to +the generated man pages (default is the subroutine's section .3) +' defval='.3' depends='GENERATE_MAN'/> + <option type='bool' id='MAN_LINKS' docs=' +If the MAN_LINKS tag is set to 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, but without them the man command +would be unable to find the correct page. The default is NO. +' defval='0' depends='GENERATE_MAN'/> + </group> + <group name='XML' docs='configuration options related to the XML output'> + <option type='bool' id='GENERATE_XML' docs=' +If the GENERATE_XML tag is set to YES Doxygen will +generate an XML file that captures the structure of +the code including all documentation. +' defval='0'/> + <option type='string' id='XML_OUTPUT' format='dir' docs=' +The XML_OUTPUT tag is used to specify where the XML pages will be put. +If a relative path is entered the value of OUTPUT_DIRECTORY will be +put in front of it. If left blank `xml' will be used as the default path. +' defval='xml' depends='GENERATE_XML'/> + <option type='string' id='XML_SCHEMA' format='string' docs=' +The XML_SCHEMA tag can be used to specify an XML schema, +which can be used by a validating XML parser to check the +syntax of the XML files. +' defval='' depends='GENERATE_XML'/> + <option type='string' id='XML_DTD' format='string' docs=' +The XML_DTD tag can be used to specify an XML DTD, +which can be used by a validating XML parser to check the +syntax of the XML files. +' defval='' depends='GENERATE_XML'/> + <option type='bool' id='XML_PROGRAMLISTING' docs=' +If the XML_PROGRAMLISTING tag is set to YES Doxygen will +dump the program listings (including syntax highlighting +and cross-referencing information) to the XML output. Note that +enabling this will significantly increase the size of the XML output. +' defval='1' depends='GENERATE_XML'/> + </group> + <group name='DEF' docs='configuration options for the AutoGen Definitions output'> + <option type='bool' id='GENERATE_AUTOGEN_DEF' docs=' +If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +generate an AutoGen Definitions (see autogen.sf.net) file +that captures the structure of the code including all +documentation. Note that this feature is still experimental +and incomplete at the moment. +' defval='0'/> + </group> + <group name='PerlMod' docs='configuration options related to the Perl module output'> + <option type='bool' id='GENERATE_PERLMOD' docs=' +If the GENERATE_PERLMOD tag is set to YES Doxygen will +generate a Perl module file that captures the structure of +the code including all documentation. Note that this +feature is still experimental and incomplete at the +moment. +' defval='0'/> + <option type='bool' id='PERLMOD_LATEX' docs=' +If the PERLMOD_LATEX tag is set to YES Doxygen will generate +the necessary Makefile rules, Perl scripts and LaTeX code to be able +to generate PDF and DVI output from the Perl module output. +' defval='0' depends='GENERATE_PERLMOD'/> + <option type='bool' id='PERLMOD_PRETTY' docs=' +If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +nicely formatted so it can be parsed by a human reader. This is useful +if you want to understand what is going on. On the other hand, if this +tag is set to NO the size of the Perl module output will be much smaller +and Perl will parse it just the same. +' defval='1' depends='GENERATE_PERLMOD'/> + <option type='string' id='PERLMOD_MAKEVAR_PREFIX' format='string' docs=' +The names of the make variables in the generated doxyrules.make file +are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +This is useful so different doxyrules.make files included by the same +Makefile don't overwrite each other's variables.' defval='' depends='GENERATE_PERLMOD'/> + </group> + <group name='Preprocessor' docs='Configuration options related to the preprocessor'> + <option type='bool' id='ENABLE_PREPROCESSING' docs=' +If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +evaluate all C-preprocessor directives found in the sources and include +files. +' defval='1'/> + <option type='bool' id='MACRO_EXPANSION' docs=' +If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +names in the source code. If set to NO (the default) only conditional +compilation will be performed. Macro expansion can be done in a controlled +way by setting EXPAND_ONLY_PREDEF to YES. +' defval='0' depends='ENABLE_PREPROCESSING'/> + <option type='bool' id='EXPAND_ONLY_PREDEF' docs=' +If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +then the macro expansion is limited to the macros specified with the +PREDEFINED and EXPAND_AS_DEFINED tags. +' defval='0' depends='ENABLE_PREPROCESSING'/> + <option type='bool' id='SEARCH_INCLUDES' docs=' +If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +pointed to by INCLUDE_PATH will be searched when a #include is found. +' defval='1' depends='ENABLE_PREPROCESSING'/> + <option type='list' id='INCLUDE_PATH' format='dir' docs=' +The INCLUDE_PATH tag can be used to specify one or more directories that +contain include files that are not input files but should be processed by +the preprocessor. +' depends='ENABLE_PREPROCESSING'> + </option> + <option type='list' id='INCLUDE_FILE_PATTERNS' format='string' docs=' +You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +patterns (like *.h and *.hpp) to filter out the header-files in the +directories. If left blank, the patterns specified with FILE_PATTERNS will +be used. +' depends='ENABLE_PREPROCESSING'> + </option> + <option type='list' id='PREDEFINED' format='string' docs=' +The PREDEFINED tag can be used to specify one or more macro names that +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: name +or name=definition (no spaces). If the definition and the = are +omitted =1 is assumed. To prevent a macro definition from being +undefined via #undef or recursively expanded use the := operator +instead of the = operator. +' depends='ENABLE_PREPROCESSING'> + </option> + <option type='list' id='EXPAND_AS_DEFINED' format='string' docs=' +If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +this tag can be used to specify a list of macro names that should be expanded. +The macro definition that is found in the sources will be used. +Use the PREDEFINED tag if you want to use a different macro definition that +overrules the definition found in the source code. +' depends='ENABLE_PREPROCESSING'> + </option> + <option type='bool' id='SKIP_FUNCTION_MACROS' docs=' +If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +doxygen's preprocessor will remove all references to function-like macros +that are alone on a line, have an all uppercase name, and do not end with a +semicolon, because these will confuse the parser if not removed. +' defval='1' depends='ENABLE_PREPROCESSING'/> + </group> + <group name='External' docs='Configuration::additions related to external references'> + <option type='list' id='TAGFILES' format='file' docs=' +The TAGFILES option can be used to specify one or more tagfiles. For each +tag file the location of the external documentation should be added. The +format of a tag file without this location is as follows: + TAGFILES = file1 file2 ... +Adding location for the tag files is done as follows: + TAGFILES = file1=loc1 "file2 = loc2" ... +where "loc1" and "loc2" can be relative or absolute paths +or URLs. Note that each tag file must have a unique name (where the name does +NOT include the path). If a tag file is not located in the directory in which +doxygen is run, you must also specify the path to the tagfile here. +'> + </option> + <option type='string' id='GENERATE_TAGFILE' format='file' docs=' +When a file name is specified after GENERATE_TAGFILE, doxygen will create +a tag file that is based on the input files it reads. +' defval=''/> + <option type='bool' id='ALLEXTERNALS' docs=' +If the ALLEXTERNALS tag is set to YES all external classes will be listed +in the class index. If set to NO only the inherited external classes +will be listed. +' defval='0'/> + <option type='bool' id='EXTERNAL_GROUPS' docs=' +If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +in the modules index. If set to NO, only the current project's groups will +be listed. +' defval='1'/> + <option type='string' id='PERL_PATH' format='dir' docs=' +The PERL_PATH should be the absolute path and name of the perl script +interpreter (i.e. the result of `which perl'). +' defval='/usr/bin/perl'/> + </group> + <group name='Dot' docs='Configuration options related to the dot tool'> + <option type='bool' id='CLASS_DIAGRAMS' docs=' +If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +or super classes. Setting the tag to NO turns the diagrams off. Note that +this option also works with HAVE_DOT disabled, but it is recommended to +install and use dot, since it yields more powerful graphs. +' defval='1'/> + <option type='string' id='MSCGEN_PATH' format='string' docs=' +You can define message sequence charts within doxygen comments using the \msc +command. Doxygen will then run the mscgen tool (see +http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the +documentation. The MSCGEN_PATH tag allows you to specify the directory where +the mscgen tool resides. If left empty the tool is assumed to be found in the +default search path. +' defval=''/> + <option type='bool' id='HIDE_UNDOC_RELATIONS' docs=' +If set to YES, the inheritance and collaboration graphs will hide +inheritance and usage relations if the target is undocumented +or is not a class. +' defval='1'/> + <option type='bool' id='HAVE_DOT' docs=' +If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +available from the path. This tool is part of Graphviz, 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 NO (the default) +' defval='0'/> + <option type='int' id='DOT_NUM_THREADS' docs=' +The DOT_NUM_THREADS specifies the number of dot invocations doxygen is +allowed to run in parallel. When set to 0 (the default) doxygen will +base this on the number of processors available in the system. You can set it +explicitly to a value larger than 0 to get control over the balance +between CPU load and processing speed. +' defval='0' minval='0' maxval='32'/> + <option type='string' id='DOT_FONTNAME' format='string' docs=' +By default doxygen will use the Helvetica font for all dot files that +doxygen generates. When you want a differently looking font you can specify +the font name using DOT_FONTNAME. You need to make sure dot is able to find +the font, which can be done by putting it in a standard location or by setting +the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the +directory containing the font. +' defval='Helvetica' depends='HAVE_DOT'/> + <option type='int' id='DOT_FONTSIZE' docs=' +The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. +The default size is 10pt. +' minval='4' maxval='24' defval='10' depends='HAVE_DOT'/> + <option type='string' id='DOT_FONTPATH' format='string' docs=' +By default doxygen will tell dot to use the Helvetica font. +If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to +set the path where dot can find it. +' defval='' depends='HAVE_DOT'/> + <option type='bool' id='CLASS_GRAPH' docs=' +If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +will generate a graph for each documented class showing the direct and +indirect inheritance relations. Setting this tag to YES will force the +CLASS_DIAGRAMS tag to NO. +' defval='1' depends='HAVE_DOT'/> + <option type='bool' id='COLLABORATION_GRAPH' docs=' +If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +will generate a graph for each documented class showing the direct and +indirect implementation dependencies (inheritance, containment, and +class references variables) of the class with other documented classes. +' defval='1' depends='HAVE_DOT'/> + <option type='bool' id='GROUP_GRAPHS' docs=' +If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +will generate a graph for groups, showing the direct groups dependencies +' defval='1' depends='HAVE_DOT'/> + <option type='bool' id='UML_LOOK' docs=' +If the UML_LOOK tag is set to YES doxygen will generate inheritance and +collaboration diagrams in a style similar to the OMG's Unified Modeling +Language. +' defval='0' depends='HAVE_DOT'/> + <option type='int' id='UML_LIMIT_NUM_FIELDS' docs=' +If the UML_LOOK tag is enabled, the fields and methods are shown inside +the class node. If there are many fields or methods and many nodes the +graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS +threshold limits the number of items for each type to make the size more +managable. Set this to 0 for no limit. Note that the threshold may be +exceeded by 50% before the limit is enforced. +' defval='10' minval='0' maxval='100' depends='HAVE_DOT'/> + <option type='bool' id='TEMPLATE_RELATIONS' docs=' +If set to YES, the inheritance and collaboration graphs will show the +relations between templates and their instances. +' defval='0' depends='HAVE_DOT'/> + <option type='bool' id='INCLUDE_GRAPH' docs=' +If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +tags are set to YES then doxygen will generate a graph for each documented +file showing the direct and indirect include dependencies of the file with +other documented files. +' defval='1' depends='HAVE_DOT'/> + <option type='bool' id='INCLUDED_BY_GRAPH' docs=' +If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +HAVE_DOT tags are set to YES then doxygen will generate a graph for each +documented header file showing the documented files that directly or +indirectly include this file. +' defval='1' depends='HAVE_DOT'/> + <option type='bool' id='CALL_GRAPH' docs=' +If the CALL_GRAPH and HAVE_DOT options are set to YES then +doxygen will generate a call dependency graph for every global function +or class method. Note that enabling this option will significantly increase +the time of a run. So in most cases it will be better to enable call graphs +for selected functions only using the \callgraph command. +' defval='0' depends='HAVE_DOT'/> + <option type='bool' id='CALLER_GRAPH' docs=' +If the CALLER_GRAPH and HAVE_DOT tags are set to YES then +doxygen will generate a caller dependency graph for every global function +or class method. Note that enabling this option will significantly increase +the time of a run. So in most cases it will be better to enable caller +graphs for selected functions only using the \callergraph command. +' defval='0' depends='HAVE_DOT'/> + <option type='bool' id='GRAPHICAL_HIERARCHY' docs=' +If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +will generate a graphical hierarchy of all classes instead of a textual one. +' defval='1' depends='HAVE_DOT'/> + <option type='bool' id='DIRECTORY_GRAPH' docs=' +If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES +then doxygen will show the dependencies a directory has on other directories +in a graphical way. The dependency relations are determined by the #include +relations between the files in the directories. +' defval='1' depends='HAVE_DOT'/> + <option type='enum' id='DOT_IMAGE_FORMAT' defval='png' docs=' +The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +generated by dot. Possible values are svg, png, jpg, or gif. +If left blank png will be used. If you choose svg you need to set +HTML_FILE_EXTENSION to xhtml in order to make the SVG files +visible in IE 9+ (other browsers do not have this requirement). +' depends='HAVE_DOT'> + <value name='png'/> + <value name='jpg'/> + <value name='gif'/> + <value name='svg'/> + </option> + <option type='bool' id='INTERACTIVE_SVG' docs=' +If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to +enable generation of interactive SVG images that allow zooming and panning. +Note that this requires a modern browser other than Internet Explorer. +Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you +need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files +visible. Older versions of IE do not have SVG support. +' defval='0' depends='HAVE_DOT'/> + <option type='string' id='DOT_PATH' format='dir' docs=' +The tag DOT_PATH can be used to specify the path where the dot tool can be +found. If left blank, it is assumed the dot tool can be found in the path. +' defval='' depends='HAVE_DOT'/> + <option type='list' id='DOTFILE_DIRS' format='dir' docs=' +The DOTFILE_DIRS tag can be used to specify one or more directories that +contain dot files that are included in the documentation (see the +\dotfile command). +' depends='HAVE_DOT'> + </option> + <option type='list' id='MSCFILE_DIRS' format='dir' docs=' +The MSCFILE_DIRS tag can be used to specify one or more directories that +contain msc files that are included in the documentation (see the +\mscfile command). +' > + </option> + <option type='int' id='DOT_GRAPH_MAX_NODES' docs=' +The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +nodes that will be shown in the graph. If the number of nodes in a graph +becomes larger than this value, doxygen will truncate the graph, which is +visualized by representing a node as a red box. Note that doxygen if the +number of direct children of the root node in a graph is already larger than +DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note +that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. +' minval='0' maxval='10000' defval='50' depends='HAVE_DOT'/> + <option type='int' id='MAX_DOT_GRAPH_DEPTH' docs=' +The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +graphs generated by dot. A depth value of 3 means that only nodes reachable +from the root by following a path via at most 3 edges will be shown. Nodes +that lay further from the root node will be omitted. Note that setting this +option to 1 or 2 may greatly reduce the computation time needed for large +code bases. Also note that the size of a graph can be further restricted by +DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. +' minval='0' maxval='1000' defval='0' depends='HAVE_DOT'/> + <option type='bool' id='DOT_TRANSPARENT' docs=' +Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +background. This is disabled by default, because dot on Windows does not +seem to support this out of the box. Warning: Depending on the platform used, +enabling this option may lead to badly anti-aliased labels on the edges of +a graph (i.e. they become hard to read). +' defval='0' depends='HAVE_DOT'/> + <option type='bool' id='DOT_MULTI_TARGETS' docs=' +Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +files in one run (i.e. multiple -o and -T options on the command line). This +makes dot run faster, but since only newer versions of dot (>1.8.10) +support this, this feature is disabled by default. +' defval='0' depends='HAVE_DOT'/> + <option type='bool' id='GENERATE_LEGEND' docs=' +If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +generate a legend page explaining the meaning of the various boxes and +arrows in the dot generated graphs. +' defval='1' depends='HAVE_DOT'/> + <option type='bool' id='DOT_CLEANUP' docs=' +If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +remove the intermediate dot files that are used to generate +the various graphs. +' defval='1' depends='HAVE_DOT'/> + <option type='obsolete' id='USE_WINDOWS_ENCODING'/> + <option type='obsolete' id='DETAILS_AT_TOP'/> + <option type='obsolete' id='QTHELP_FILE'/> + <option type='obsolete' id='QTHELP_CONFIG'/> + <option type='obsolete' id='DOXYGEN2QTHELP_LOC'/> + <option type='obsolete' id='MAX_DOT_GRAPH_WIDTH'/> + <option type='obsolete' id='MAX_DOT_GRAPH_HEIGHT'/> + <option type='obsolete' id='CGI_NAME'/> + <option type='obsolete' id='CGI_URL'/> + <option type='obsolete' id='DOC_URL'/> + <option type='obsolete' id='DOC_ABSPATH'/> + <option type='obsolete' id='BIN_ABSPATH'/> + <option type='obsolete' id='EXT_DOC_PATHS'/> + </group> +</doxygenconfig> diff --git a/trunk/src/configgen.py b/trunk/src/configgen.py new file mode 100755 index 0000000..2b06d9e --- /dev/null +++ b/trunk/src/configgen.py @@ -0,0 +1,137 @@ +# python script to generate configoptions.cpp from config.xml +# +# Copyright (C) 1997-2012 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. +# +import xml.dom.minidom +from xml.dom import minidom, Node + +def addValues(var,node): + for n in node.childNodes: + if n.nodeType == Node.ELEMENT_NODE: + name = n.getAttribute('name'); + print " %s->addValue(\"%s\");" % (var,name) + +def parseOption(node): + name = node.getAttribute('id') + type = node.getAttribute('type') + format = node.getAttribute('format') + doc = node.getAttribute('docs') + defval = node.getAttribute('defval') + adefval = node.getAttribute('altdefval') + depends = node.getAttribute('depends') + # replace \ by \\, replace " by \", and ' ' by a newline with end string and start string at next line + docC = doc.strip().replace('\\','\\\\').replace('"','\\"').replace(' ','\\n"\n "') + print " //----" + if type=='bool': + if len(adefval)>0: + enabled = adefval + else: + enabled = "TRUE" if defval=='1' else "FALSE" + print " cb = cfg->addBool(" + print " \"%s\"," % (name) + print " \"%s\"," % (docC) + print " %s" % (enabled) + print " );" + if depends!='': + print " cb->addDependency(\"%s\");" % (depends) + elif type=='string': + print " cs = cfg->addString(" + print " \"%s\"," % (name) + print " \"%s\"" % (docC) + print " );" + if defval!='': + print " cs->setDefaultValue(\"%s\");" % (defval) + if format=='file': + print " cs->setWidgetType(ConfigString::File);" + elif format=='dir': + print " cs->setWidgetType(ConfigString::Dir);" + if depends!='': + print " cs->addDependency(\"%s\");" % (depends) + elif type=='enum': + print " ce = cfg->addEnum(" + print " \"%s\"," % (name) + print " \"%s\"," % (docC) + print " \"%s\"" % (defval) + print " );" + addValues("ce",node) + if depends!='': + print " ce->addDependency(\"%s\");" % (depends) + elif type=='int': + minval = node.getAttribute('minval') + maxval = node.getAttribute('maxval') + print " ci = cfg->addInt(" + print " \"%s\"," % (name) + print " \"%s\"," % (docC) + print " %s,%s,%s" % (minval,maxval,defval) + print " );" + if depends!='': + print " ci->addDependency(\"%s\");" % (depends) + elif type=='list': + print " cl = cfg->addList(" + print " \"%s\"," % (name) + print " \"%s\"" % (docC) + print " );" + addValues("cl",node) + if depends!='': + print " cl->addDependency(\"%s\");" % (depends) + if format=='file': + print " cl->setWidgetType(ConfigList::File);" + elif format=='dir': + print " cl->setWidgetType(ConfigList::Dir);" + elif format=='filedir': + print " cl->setWidgetType(ConfigList::FileAndDir);" + elif type=='obsolete': + print " cfg->addObsolete(\"%s\");" % (name) + + + + +def parseGroups(node): + name = node.getAttribute('name') + doc = node.getAttribute('docs') + print " //---------------------------------------------------------------------------"; + print " cfg->addInfo(\"%s\",\"%s\");" % (name,doc) + print " //---------------------------------------------------------------------------"; + print + for n in node.childNodes: + if n.nodeType == Node.ELEMENT_NODE: + parseOption(n) + + +def main(): + doc = xml.dom.minidom.parse("config.xml") + elem = doc.documentElement + print "/* WARNING: This file is generated!" + print " * Do not edit this file, but edit config.xml instead and run" + print " * python configgen.py to regenerate this file!" + print " */" + print "" + print "#include \"configoptions.h\"" + print "#include \"config.h\"" + print "#include \"portable.h\"" + print "" + print "void addConfigOptions(Config *cfg)" + print "{" + print " ConfigString *cs;" + print " ConfigEnum *ce;" + print " ConfigList *cl;" + print " ConfigInt *ci;" + print " ConfigBool *cb;" + print "" + for n in elem.childNodes: + if n.nodeType == Node.ELEMENT_NODE: + parseGroups(n) + print "}" + +if __name__ == '__main__': + main() + diff --git a/trunk/src/configoptions.cpp b/trunk/src/configoptions.cpp new file mode 100644 index 0000000..3573248 --- /dev/null +++ b/trunk/src/configoptions.cpp @@ -0,0 +1,2494 @@ +/* WARNING: This file is generated! + * Do not edit this file, but edit config.xml instead and run + * python configgen.py to regenerate this file! + */ + +#include "configoptions.h" +#include "config.h" +#include "portable.h" + +void addConfigOptions(Config *cfg) +{ + ConfigString *cs; + ConfigEnum *ce; + ConfigList *cl; + ConfigInt *ci; + ConfigBool *cb; + + //--------------------------------------------------------------------------- + cfg->addInfo("Project","Project related configuration options"); + //--------------------------------------------------------------------------- + + //---- + cs = cfg->addString( + "DOXYFILE_ENCODING", + "This tag specifies the encoding used for all characters in the config file\n" + "that follow. The default is UTF-8 which is also the encoding used for all\n" + "text before the first occurrence of this tag. Doxygen uses libiconv (or the\n" + "iconv built into libc) for the transcoding. See\n" + "http://www.gnu.org/software/libiconv for the list of possible encodings." + ); + cs->setDefaultValue("UTF-8"); + //---- + cs = cfg->addString( + "PROJECT_NAME", + "The PROJECT_NAME tag is a single word (or sequence of words) that should\n" + "identify the project. Note that if you do not use Doxywizard you need\n" + "to put quotes around the project name if it contains spaces." + ); + cs->setDefaultValue("My Project"); + //---- + cs = cfg->addString( + "PROJECT_NUMBER", + "The PROJECT_NUMBER tag can be used to enter a project or revision number.\n" + "This could be handy for archiving the generated documentation or\n" + "if some version control system is used." + ); + //---- + cs = cfg->addString( + "PROJECT_BRIEF", + "Using the PROJECT_BRIEF tag one can provide an optional one line description\n" + "for a project that appears at the top of each page and should give viewer\n" + "a quick idea about the purpose of the project. Keep the description short." + ); + //---- + cs = cfg->addString( + "PROJECT_LOGO", + "With the PROJECT_LOGO tag one can specify an logo or icon that is\n" + "included in the documentation. The maximum height of the logo should not\n" + "exceed 55 pixels and the maximum width should not exceed 200 pixels.\n" + "Doxygen will copy the logo to the output directory." + ); + cs->setWidgetType(ConfigString::File); + //---- + cs = cfg->addString( + "OUTPUT_DIRECTORY", + "The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)\n" + "base path where the generated documentation will be put.\n" + "If a relative path is entered, it will be relative to the location\n" + "where doxygen was started. If left blank the current directory will be used." + ); + cs->setWidgetType(ConfigString::Dir); + //---- + cb = cfg->addBool( + "CREATE_SUBDIRS", + "If the CREATE_SUBDIRS tag is set to YES, then doxygen will create\n" + "4096 sub-directories (in 2 levels) under the output directory of each output\n" + "format and will distribute the generated files over these directories.\n" + "Enabling this option can be useful when feeding doxygen a huge amount of\n" + "source files, where putting all generated files in the same directory would\n" + "otherwise cause performance problems for the file system.", + FALSE + ); + //---- + ce = cfg->addEnum( + "OUTPUT_LANGUAGE", + "The OUTPUT_LANGUAGE tag is used to specify the language in which all\n" + "documentation generated by doxygen is written. Doxygen will use this\n" + "information to generate all constant output in the proper language.\n" + "The default language is English, other supported languages are:\n" + "Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,\n" + "Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,\n" + "Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English\n" + "messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian,\n" + "Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak,\n" + "Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.", + "English" + ); + ce->addValue("Afrikaans"); + ce->addValue("Arabic"); + ce->addValue("Brazilian"); + ce->addValue("Catalan"); + ce->addValue("Chinese"); + ce->addValue("Chinese-Traditional"); + ce->addValue("Croatian"); + ce->addValue("Czech"); + ce->addValue("Danish"); + ce->addValue("Dutch"); + ce->addValue("English"); + ce->addValue("Esperanto"); + ce->addValue("Farsi"); + ce->addValue("Finnish"); + ce->addValue("French"); + ce->addValue("German"); + ce->addValue("Greek"); + ce->addValue("Hungarian"); + ce->addValue("Italian"); + ce->addValue("Japanese"); + ce->addValue("Japanese-en"); + ce->addValue("Korean"); + ce->addValue("Korean-en"); + ce->addValue("Norwegian"); + ce->addValue("Macedonian"); + ce->addValue("Persian"); + ce->addValue("Polish"); + ce->addValue("Portuguese"); + ce->addValue("Romanian"); + ce->addValue("Russian"); + ce->addValue("Serbian"); + ce->addValue("Slovak"); + ce->addValue("Slovene"); + ce->addValue("Spanish"); + ce->addValue("Swedish"); + ce->addValue("Turkish"); + ce->addValue("Ukrainian"); + ce->addValue("Vietnamese"); + //---- + cb = cfg->addBool( + "BRIEF_MEMBER_DESC", + "If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will\n" + "include brief member descriptions after the members that are listed in\n" + "the file and class documentation (similar to JavaDoc).\n" + "Set to NO to disable this.", + TRUE + ); + //---- + cb = cfg->addBool( + "REPEAT_BRIEF", + "If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend\n" + "the brief description of a member or function before the detailed description.\n" + "Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the\n" + "brief descriptions will be completely suppressed.", + TRUE + ); + //---- + cl = cfg->addList( + "ABBREVIATE_BRIEF", + "This tag implements a quasi-intelligent brief description abbreviator\n" + "that is used to form the text in various listings. Each string\n" + "in this list, if found as the leading text of the brief description, will be\n" + "stripped from the text and the result after processing the whole list, is\n" + "used as the annotated text. Otherwise, the brief description is used as-is.\n" + "If left blank, the following values are used (\"$name\" is automatically\n" + "replaced with the name of the entity): \"The $name class\" \"The $name widget\"\n" + "\"The $name file\" \"is\" \"provides\" \"specifies\" \"contains\"\n" + "\"represents\" \"a\" \"an\" \"the\"" + ); + cl->addValue("The $name class"); + cl->addValue("The $name widget"); + cl->addValue("The $name file"); + cl->addValue("is"); + cl->addValue("provides"); + cl->addValue("specifies"); + cl->addValue("contains"); + cl->addValue("represents"); + cl->addValue("a"); + cl->addValue("an"); + cl->addValue("the"); + //---- + cb = cfg->addBool( + "ALWAYS_DETAILED_SEC", + "If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then\n" + "Doxygen will generate a detailed section even if there is only a brief\n" + "description.", + FALSE + ); + //---- + cb = cfg->addBool( + "INLINE_INHERITED_MEMB", + "If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all\n" + "inherited members of a class in the documentation of that class as if those\n" + "members were ordinary class members. Constructors, destructors and assignment\n" + "operators of the base classes will not be shown.", + FALSE + ); + //---- + cb = cfg->addBool( + "FULL_PATH_NAMES", + "If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full\n" + "path before files name in the file list and in the header files. If set\n" + "to NO the shortest path that makes the file name unique will be used.", + TRUE + ); + //---- + cl = cfg->addList( + "STRIP_FROM_PATH", + "If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag\n" + "can be used to strip a user-defined part of the path. Stripping is\n" + "only done if one of the specified strings matches the left-hand part of\n" + "the path. The tag can be used to show relative paths in the file list.\n" + "If left blank the directory from which doxygen is run is used as the\n" + "path to strip." + ); + cl->addValue(""); + cl->addDependency("FULL_PATH_NAMES"); + //---- + cl = cfg->addList( + "STRIP_FROM_INC_PATH", + "The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of\n" + "the path mentioned in the documentation of a class, which tells\n" + "the reader which header file to include in order to use a class.\n" + "If left blank only the name of the header file containing the class\n" + "definition is used. Otherwise one should specify the include paths that\n" + "are normally passed to the compiler using the -I flag." + ); + //---- + cb = cfg->addBool( + "SHORT_NAMES", + "If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter\n" + "(but less readable) file names. This can be useful if your file system\n" + "doesn't support long names like on DOS, Mac, or CD-ROM.", + FALSE + ); + //---- + cb = cfg->addBool( + "JAVADOC_AUTOBRIEF", + "If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen\n" + "will interpret the first line (until the first dot) of a JavaDoc-style\n" + "comment as the brief description. If set to NO, the JavaDoc\n" + "comments will behave just like regular Qt-style comments\n" + "(thus requiring an explicit @brief command for a brief description.)", + FALSE + ); + //---- + cb = cfg->addBool( + "QT_AUTOBRIEF", + "If the QT_AUTOBRIEF tag is set to YES then Doxygen will\n" + "interpret the first line (until the first dot) of a Qt-style\n" + "comment as the brief description. If set to NO, the comments\n" + "will behave just like regular Qt-style comments (thus requiring\n" + "an explicit \\brief command for a brief description.)", + FALSE + ); + //---- + cb = cfg->addBool( + "MULTILINE_CPP_IS_BRIEF", + "The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen\n" + "treat a multi-line C++ special comment block (i.e. a block of //! or ///\n" + "comments) as a brief description. This used to be the default behaviour.\n" + "The new default is to treat a multi-line C++ comment block as a detailed\n" + "description. Set this tag to YES if you prefer the old behaviour instead.", + FALSE + ); + //---- + cb = cfg->addBool( + "INHERIT_DOCS", + "If the INHERIT_DOCS tag is set to YES (the default) then an undocumented\n" + "member inherits the documentation from any documented member that it\n" + "re-implements.", + TRUE + ); + //---- + cb = cfg->addBool( + "SEPARATE_MEMBER_PAGES", + "If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce\n" + "a new page for each member. If set to NO, the documentation of a member will\n" + "be part of the file/class/namespace that contains it.", + FALSE + ); + //---- + ci = cfg->addInt( + "TAB_SIZE", + "The TAB_SIZE tag can be used to set the number of spaces in a tab.\n" + "Doxygen uses this value to replace tabs by spaces in code fragments.", + 1,16,8 + ); + //---- + cl = cfg->addList( + "ALIASES", + "This tag can be used to specify a number of aliases that acts\n" + "as commands in the documentation. An alias has the form \"name=value\".\n" + "For example adding \"sideeffect=\\par Side Effects:\\n\" will allow you to\n" + "put the command \\sideeffect (or @sideeffect) in the documentation, which\n" + "will result in a user-defined paragraph with heading \"Side Effects:\".\n" + "You can put \\n's in the value part of an alias to insert newlines." + ); + //---- + cl = cfg->addList( + "TCL_SUBST", + "This tag can be used to specify a number of word-keyword mappings (TCL only).\n" + "A mapping has the form \"name=value\". For example adding\n" + "\"class=itcl::class\" will allow you to use the command class in the\n" + "itcl::class meaning." + ); + //---- + cb = cfg->addBool( + "OPTIMIZE_OUTPUT_FOR_C", + "Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C\n" + "sources only. Doxygen will then generate output that is more tailored for C.\n" + "For instance, some of the names that are used will be different. The list\n" + "of all members will be omitted, etc.", + FALSE + ); + //---- + cb = cfg->addBool( + "OPTIMIZE_OUTPUT_JAVA", + "Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java\n" + "sources only. Doxygen will then generate output that is more tailored for\n" + "Java. For instance, namespaces will be presented as packages, qualified\n" + "scopes will look different, etc.", + FALSE + ); + //---- + cb = cfg->addBool( + "OPTIMIZE_FOR_FORTRAN", + "Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran\n" + "sources only. Doxygen will then generate output that is more tailored for\n" + "Fortran.", + FALSE + ); + //---- + cb = cfg->addBool( + "OPTIMIZE_OUTPUT_VHDL", + "Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL\n" + "sources. Doxygen will then generate output that is tailored for\n" + "VHDL.", + FALSE + ); + //---- + cl = cfg->addList( + "EXTENSION_MAPPING", + "Doxygen selects the parser to use depending on the extension of the files it\n" + "parses. With this tag you can assign which parser to use for a given extension.\n" + "Doxygen has a built-in mapping, but you can override or extend it using this\n" + "tag. The format is ext=language, where ext is a file extension, and language\n" + "is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C,\n" + "C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make\n" + "doxygen treat .inc files as Fortran files (default is PHP), and .f files as C\n" + "(default is Fortran), use: inc=Fortran f=C. Note that for custom extensions\n" + "you also need to set FILE_PATTERNS otherwise the files are not read by doxygen." + ); + //---- + cb = cfg->addBool( + "MARKDOWN_SUPPORT", + "If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all\n" + "comments according to the Markdown format, which allows for more readable\n" + "documentation. See http://daringfireball.net/projects/markdown/ for details.\n" + "The output of markdown processing is further processed by doxygen, so you\n" + "can mix doxygen, HTML, and XML commands with Markdown formatting.\n" + "Disable only in case of backward compatibilities issues.", + TRUE + ); + //---- + cb = cfg->addBool( + "BUILTIN_STL_SUPPORT", + "If you use STL classes (i.e. std::string, std::vector, etc.) but do not want\n" + "to include (a tag file for) the STL sources as input, then you should\n" + "set this tag to YES in order to let doxygen match functions declarations and\n" + "definitions whose arguments contain STL classes (e.g. func(std::string); v.s.\n" + "func(std::string) {}). This also makes the inheritance and collaboration\n" + "diagrams that involve STL classes more complete and accurate.", + FALSE + ); + //---- + cb = cfg->addBool( + "CPP_CLI_SUPPORT", + "If you use Microsoft's C++/CLI language, you should set this option to YES to\n" + "enable parsing support.", + FALSE + ); + //---- + cb = cfg->addBool( + "SIP_SUPPORT", + "Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.\n" + "Doxygen will parse them like normal C++ but will assume all classes use public\n" + "instead of private inheritance when no explicit protection keyword is present.", + FALSE + ); + //---- + cb = cfg->addBool( + "IDL_PROPERTY_SUPPORT", + "For Microsoft's IDL there are propget and propput attributes to indicate getter\n" + "and setter methods for a property. Setting this option to YES (the default)\n" + "will make doxygen replace the get and set methods by a property in the\n" + "documentation. This will only work if the methods are indeed getting or\n" + "setting a simple type. If this is not the case, or you want to show the\n" + "methods anyway, you should set this option to NO.", + TRUE + ); + //---- + cb = cfg->addBool( + "DISTRIBUTE_GROUP_DOC", + "If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC\n" + "tag is set to YES, then doxygen will reuse the documentation of the first\n" + "member in the group (if any) for the other members of the group. By default\n" + "all members of a group must be documented explicitly.", + FALSE + ); + //---- + cb = cfg->addBool( + "SUBGROUPING", + "Set the SUBGROUPING tag to YES (the default) to allow class member groups of\n" + "the same type (for instance a group of public functions) to be put as a\n" + "subgroup of that type (e.g. under the Public Functions section). Set it to\n" + "NO to prevent subgrouping. Alternatively, this can be done per class using\n" + "the \\nosubgrouping command.", + TRUE + ); + //---- + cb = cfg->addBool( + "INLINE_GROUPED_CLASSES", + "When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and\n" + "unions are shown inside the group in which they are included (e.g. using\n" + "@ingroup) instead of on a separate page (for HTML and Man pages) or\n" + "section (for LaTeX and RTF).", + FALSE + ); + //---- + cb = cfg->addBool( + "INLINE_SIMPLE_STRUCTS", + "When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and\n" + "unions with only public data fields will be shown inline in the documentation\n" + "of the scope in which they are defined (i.e. file, namespace, or group\n" + "documentation), provided this scope is documented. If set to NO (the default),\n" + "structs, classes, and unions are shown on a separate page (for HTML and Man\n" + "pages) or section (for LaTeX and RTF).", + FALSE + ); + //---- + cb = cfg->addBool( + "TYPEDEF_HIDES_STRUCT", + "When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum\n" + "is documented as struct, union, or enum with the name of the typedef. So\n" + "typedef struct TypeS {} TypeT, will appear in the documentation as a struct\n" + "with name TypeT. When disabled the typedef will appear as a member of a file,\n" + "namespace, or class. And the struct will be named TypeS. This can typically\n" + "be useful for C code in case the coding convention dictates that all compound\n" + "types are typedef'ed and only the typedef is referenced, never the tag name.", + FALSE + ); + //---- + ci = cfg->addInt( + "SYMBOL_CACHE_SIZE", + "The SYMBOL_CACHE_SIZE determines the size of the internal cache use to\n" + "determine which symbols to keep in memory and which to flush to disk.\n" + "When the cache is full, less often used symbols will be written to disk.\n" + "For small to medium size projects (<1000 input files) the default value is\n" + "probably good enough. For larger projects a too small cache size can cause\n" + "doxygen to be busy swapping symbols to and from disk most of the time\n" + "causing a significant performance penalty.\n" + "If the system has enough physical memory increasing the cache will improve the\n" + "performance by keeping more symbols in memory. Note that the value works on\n" + "a logarithmic scale so increasing the size by one will roughly double the\n" + "memory usage. The cache size is given by this formula:\n" + "2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,\n" + "corresponding to a cache size of 2^16 = 65536 symbols.", + 0,9,0 + ); + //---- + ci = cfg->addInt( + "LOOKUP_CACHE_SIZE", + "Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be\n" + "set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given\n" + "their name and scope. Since this can be an expensive process and often the\n" + "same symbol appear multiple times in the code, doxygen keeps a cache of\n" + "pre-resolved symbols. If the cache is too small doxygen will become slower.\n" + "If the cache is too large, memory is wasted. The cache size is given by this\n" + "formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range is 0..9, the default is 0,\n" + "corresponding to a cache size of 2^16 = 65536 symbols.", + 0,9,0 + ); + //--------------------------------------------------------------------------- + cfg->addInfo("Build","Build related configuration options"); + //--------------------------------------------------------------------------- + + //---- + cb = cfg->addBool( + "EXTRACT_ALL", + "If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in\n" + "documentation are documented, even if no documentation was available.\n" + "Private class members and static file members will be hidden unless\n" + "the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES", + FALSE + ); + //---- + cb = cfg->addBool( + "EXTRACT_PRIVATE", + "If the EXTRACT_PRIVATE tag is set to YES all private members of a class\n" + "will be included in the documentation.", + FALSE + ); + //---- + cb = cfg->addBool( + "EXTRACT_PACKAGE", + "If the EXTRACT_PACKAGE tag is set to YES all members with package or internal scope will be included in the documentation.", + FALSE + ); + //---- + cb = cfg->addBool( + "EXTRACT_STATIC", + "If the EXTRACT_STATIC tag is set to YES all static members of a file\n" + "will be included in the documentation.", + FALSE + ); + //---- + cb = cfg->addBool( + "EXTRACT_LOCAL_CLASSES", + "If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)\n" + "defined locally in source files will be included in the documentation.\n" + "If set to NO only classes defined in header files are included.", + TRUE + ); + //---- + cb = cfg->addBool( + "EXTRACT_LOCAL_METHODS", + "This flag is only useful for Objective-C code. When set to YES local\n" + "methods, which are defined in the implementation section but not in\n" + "the interface are included in the documentation.\n" + "If set to NO (the default) only methods in the interface are included.", + FALSE + ); + //---- + cb = cfg->addBool( + "EXTRACT_ANON_NSPACES", + "If this flag is set to YES, the members of anonymous namespaces will be\n" + "extracted and appear in the documentation as a namespace called\n" + "'anonymous_namespace{file}', where file will be replaced with the base\n" + "name of the file that contains the anonymous namespace. By default\n" + "anonymous namespaces are hidden.", + FALSE + ); + //---- + cb = cfg->addBool( + "HIDE_UNDOC_MEMBERS", + "If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all\n" + "undocumented members of documented classes, files or namespaces.\n" + "If set to NO (the default) these members will be included in the\n" + "various overviews, but no documentation section is generated.\n" + "This option has no effect if EXTRACT_ALL is enabled.", + FALSE + ); + //---- + cb = cfg->addBool( + "HIDE_UNDOC_CLASSES", + "If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all\n" + "undocumented classes that are normally visible in the class hierarchy.\n" + "If set to NO (the default) these classes will be included in the various\n" + "overviews. This option has no effect if EXTRACT_ALL is enabled.", + FALSE + ); + //---- + cb = cfg->addBool( + "HIDE_FRIEND_COMPOUNDS", + "If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all\n" + "friend (class|struct|union) declarations.\n" + "If set to NO (the default) these declarations will be included in the\n" + "documentation.", + FALSE + ); + //---- + cb = cfg->addBool( + "HIDE_IN_BODY_DOCS", + "If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any\n" + "documentation blocks found inside the body of a function.\n" + "If set to NO (the default) these blocks will be appended to the\n" + "function's detailed documentation block.", + FALSE + ); + //---- + cb = cfg->addBool( + "INTERNAL_DOCS", + "The INTERNAL_DOCS tag determines if documentation\n" + "that is typed after a \\internal command is included. If the tag is set\n" + "to NO (the default) then the documentation will be excluded.\n" + "Set it to YES to include the internal documentation.", + FALSE + ); + //---- + cb = cfg->addBool( + "CASE_SENSE_NAMES", + "If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate\n" + "file names in lower-case letters. If set to YES upper-case letters are also\n" + "allowed. This is useful if you have classes or files whose names only differ\n" + "in case and if your file system supports case sensitive file names. Windows\n" + "and Mac users are advised to set this option to NO.", + portable_fileSystemIsCaseSensitive() + ); + //---- + cb = cfg->addBool( + "HIDE_SCOPE_NAMES", + "If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen\n" + "will show members with their full class and namespace scopes in the\n" + "documentation. If set to YES the scope will be hidden.", + FALSE + ); + //---- + cb = cfg->addBool( + "SHOW_INCLUDE_FILES", + "If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen\n" + "will put a list of the files that are included by a file in the documentation\n" + "of that file.", + TRUE + ); + //---- + cb = cfg->addBool( + "FORCE_LOCAL_INCLUDES", + "If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen\n" + "will list include files with double quotes in the documentation\n" + "rather than with sharp brackets.", + FALSE + ); + //---- + cb = cfg->addBool( + "INLINE_INFO", + "If the INLINE_INFO tag is set to YES (the default) then a tag [inline]\n" + "is inserted in the documentation for inline members.", + TRUE + ); + //---- + cb = cfg->addBool( + "SORT_MEMBER_DOCS", + "If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen\n" + "will sort the (detailed) documentation of file and class members\n" + "alphabetically by member name. If set to NO the members will appear in\n" + "declaration order.", + TRUE + ); + //---- + cb = cfg->addBool( + "SORT_BRIEF_DOCS", + "If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the\n" + "brief documentation of file, namespace and class members alphabetically\n" + "by member name. If set to NO (the default) the members will appear in\n" + "declaration order.", + FALSE + ); + //---- + cb = cfg->addBool( + "SORT_MEMBERS_CTORS_1ST", + "If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen\n" + "will sort the (brief and detailed) documentation of class members so that\n" + "constructors and destructors are listed first. If set to NO (the default)\n" + "the constructors will appear in the respective orders defined by\n" + "SORT_MEMBER_DOCS and SORT_BRIEF_DOCS.\n" + "This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO\n" + "and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO.", + FALSE + ); + //---- + cb = cfg->addBool( + "SORT_GROUP_NAMES", + "If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the\n" + "hierarchy of group names into alphabetical order. If set to NO (the default)\n" + "the group names will appear in their defined order.", + FALSE + ); + //---- + cb = cfg->addBool( + "SORT_BY_SCOPE_NAME", + "If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be\n" + "sorted by fully-qualified names, including namespaces. If set to\n" + "NO (the default), the class list will be sorted only by class name,\n" + "not including the namespace part.\n" + "Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.\n" + "Note: This option applies only to the class list, not to the\n" + "alphabetical list.", + FALSE + ); + //---- + cb = cfg->addBool( + "STRICT_PROTO_MATCHING", + "If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to\n" + "do proper type resolution of all parameters of a function it will reject a\n" + "match between the prototype and the implementation of a member function even\n" + "if there is only one candidate or it is obvious which candidate to choose\n" + "by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen\n" + "will still accept a match between prototype and implementation in such cases.", + FALSE + ); + //---- + cb = cfg->addBool( + "GENERATE_TODOLIST", + "The GENERATE_TODOLIST tag can be used to enable (YES) or\n" + "disable (NO) the todo list. This list is created by putting \\todo\n" + "commands in the documentation.", + TRUE + ); + //---- + cb = cfg->addBool( + "GENERATE_TESTLIST", + "The GENERATE_TESTLIST tag can be used to enable (YES) or\n" + "disable (NO) the test list. This list is created by putting \\test\n" + "commands in the documentation.", + TRUE + ); + //---- + cb = cfg->addBool( + "GENERATE_BUGLIST", + "The GENERATE_BUGLIST tag can be used to enable (YES) or\n" + "disable (NO) the bug list. This list is created by putting \\bug\n" + "commands in the documentation.", + TRUE + ); + //---- + cb = cfg->addBool( + "GENERATE_DEPRECATEDLIST", + "The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or\n" + "disable (NO) the deprecated list. This list is created by putting\n" + "\\deprecated commands in the documentation.", + TRUE + ); + //---- + cl = cfg->addList( + "ENABLED_SECTIONS", + "The ENABLED_SECTIONS tag can be used to enable conditional\n" + "documentation sections, marked by \\if sectionname ... \\endif." + ); + //---- + ci = cfg->addInt( + "MAX_INITIALIZER_LINES", + "The MAX_INITIALIZER_LINES tag determines the maximum number of lines\n" + "the initial value of a variable or macro consists of for it to appear in\n" + "the documentation. If the initializer consists of more lines than specified\n" + "here it will be hidden. Use a value of 0 to hide initializers completely.\n" + "The appearance of the initializer of individual variables and macros in the\n" + "documentation can be controlled using \\showinitializer or \\hideinitializer\n" + "command in the documentation regardless of this setting.", + 0,10000,30 + ); + //---- + cb = cfg->addBool( + "SHOW_USED_FILES", + "Set the SHOW_USED_FILES tag to NO to disable the list of files generated\n" + "at the bottom of the documentation of classes and structs. If set to YES the\n" + "list will mention the files that were used to generate the documentation.", + TRUE + ); + //---- + cb = cfg->addBool( + "SHOW_DIRECTORIES", + "If the sources in your project are distributed over multiple directories\n" + "then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy\n" + "in the documentation. The default is NO.", + FALSE + ); + //---- + cb = cfg->addBool( + "SHOW_FILES", + "Set the SHOW_FILES tag to NO to disable the generation of the Files page.\n" + "This will remove the Files entry from the Quick Index and from the\n" + "Folder Tree View (if specified). The default is YES.", + TRUE + ); + //---- + cb = cfg->addBool( + "SHOW_NAMESPACES", + "Set the SHOW_NAMESPACES tag to NO to disable the generation of the\n" + "Namespaces page.\n" + "This will remove the Namespaces entry from the Quick Index\n" + "and from the Folder Tree View (if specified). The default is YES.", + TRUE + ); + //---- + cs = cfg->addString( + "FILE_VERSION_FILTER", + "The FILE_VERSION_FILTER tag can be used to specify a program or script that\n" + "doxygen should invoke to get the current version for each file (typically from\n" + "the version control system). Doxygen will invoke the program by executing (via\n" + "popen()) the command <command> <input-file>, where <command> is the value of\n" + "the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file\n" + "provided by doxygen. Whatever the program writes to standard output\n" + "is used as the file version. See the manual for examples." + ); + cs->setWidgetType(ConfigString::File); + //---- + cs = cfg->addString( + "LAYOUT_FILE", + "The LAYOUT_FILE tag can be used to specify a layout file which will be parsed\n" + "by doxygen. The layout file controls the global structure of the generated\n" + "output files in an output format independent way. The create the layout file\n" + "that represents doxygen's defaults, run doxygen with the -l option.\n" + "You can optionally specify a file name after the option, if omitted\n" + "DoxygenLayout.xml will be used as the name of the layout file." + ); + cs->setWidgetType(ConfigString::File); + //---- + cl = cfg->addList( + "CITE_BIB_FILES", + "The CITE_BIB_FILES tag can be used to specify one or more bib files\n" + "containing the references data. This must be a list of .bib files. The\n" + ".bib extension is automatically appended if omitted. Using this command\n" + "requires the bibtex tool to be installed. See also\n" + "http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style\n" + "of the bibliography can be controlled using LATEX_BIB_STYLE. To use this\n" + "feature you need bibtex and perl available in the search path." + ); + cl->setWidgetType(ConfigList::File); + //--------------------------------------------------------------------------- + cfg->addInfo("Messages","configuration options related to warning and progress messages"); + //--------------------------------------------------------------------------- + + //---- + cb = cfg->addBool( + "QUIET", + "The QUIET tag can be used to turn on/off the messages that are generated\n" + "by doxygen. Possible values are YES and NO. If left blank NO is used.", + FALSE + ); + //---- + cb = cfg->addBool( + "WARNINGS", + "The WARNINGS tag can be used to turn on/off the warning messages that are\n" + "generated by doxygen. Possible values are YES and NO. If left blank\n" + "NO is used.", + TRUE + ); + //---- + cb = cfg->addBool( + "WARN_IF_UNDOCUMENTED", + "If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings\n" + "for undocumented members. If EXTRACT_ALL is set to YES then this flag will\n" + "automatically be disabled.", + TRUE + ); + //---- + cb = cfg->addBool( + "WARN_IF_DOC_ERROR", + "If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for\n" + "potential errors in the documentation, such as not documenting some\n" + "parameters in a documented function, or documenting parameters that\n" + "don't exist or using markup commands wrongly.", + TRUE + ); + //---- + cb = cfg->addBool( + "WARN_NO_PARAMDOC", + "The WARN_NO_PARAMDOC option can be enabled to get warnings for\n" + "functions that are documented, but have no documentation for their parameters\n" + "or return value. If set to NO (the default) doxygen will only warn about\n" + "wrong or incomplete parameter documentation, but not about the absence of\n" + "documentation.", + FALSE + ); + //---- + cs = cfg->addString( + "WARN_FORMAT", + "The WARN_FORMAT tag determines the format of the warning messages that\n" + "doxygen can produce. The string should contain the $file, $line, and $text\n" + "tags, which will be replaced by the file and line number from which the\n" + "warning originated and the warning text. Optionally the format may contain\n" + "$version, which will be replaced by the version of the file (if it could\n" + "be obtained via FILE_VERSION_FILTER)" + ); + cs->setDefaultValue("$file:$line: $text"); + //---- + cs = cfg->addString( + "WARN_LOGFILE", + "The WARN_LOGFILE tag can be used to specify a file to which warning\n" + "and error messages should be written. If left blank the output is written\n" + "to stderr." + ); + cs->setWidgetType(ConfigString::File); + //--------------------------------------------------------------------------- + cfg->addInfo("Input","configuration options related to the input files"); + //--------------------------------------------------------------------------- + + //---- + cl = cfg->addList( + "INPUT", + "The INPUT tag can be used to specify the files and/or directories that contain\n" + "documented source files. You may enter file names like \"myfile.cpp\" or\n" + "directories like \"/usr/src/myproject\". Separate the files or directories\n" + "with spaces." + ); + cl->addValue(""); + cl->setWidgetType(ConfigList::FileAndDir); + //---- + cs = cfg->addString( + "INPUT_ENCODING", + "This tag can be used to specify the character encoding of the source files\n" + "that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is\n" + "also the default input encoding. Doxygen uses libiconv (or the iconv built\n" + "into libc) for the transcoding. See http://www.gnu.org/software/libiconv for\n" + "the list of possible encodings." + ); + cs->setDefaultValue("UTF-8"); + //---- + cl = cfg->addList( + "FILE_PATTERNS", + "If the value of the INPUT tag contains directories, you can use the\n" + "FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp\n" + "and *.h) to filter out the source-files in the directories. If left\n" + "blank the following patterns are tested:\n" + "*.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh\n" + "*.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py\n" + "*.f90 *.f *.for *.vhd *.vhdl" + ); + cl->addValue("*.c"); + cl->addValue("*.cc"); + cl->addValue("*.cxx"); + cl->addValue("*.cpp"); + cl->addValue("*.c++"); + cl->addValue("*.d"); + cl->addValue("*.java"); + cl->addValue("*.ii"); + cl->addValue("*.ixx"); + cl->addValue("*.ipp"); + cl->addValue("*.i++"); + cl->addValue("*.inl"); + cl->addValue("*.h"); + cl->addValue("*.hh"); + cl->addValue("*.hxx"); + cl->addValue("*.hpp"); + cl->addValue("*.h++"); + cl->addValue("*.idl"); + cl->addValue("*.odl"); + cl->addValue("*.cs"); + cl->addValue("*.php"); + cl->addValue("*.php3"); + cl->addValue("*.inc"); + cl->addValue("*.m"); + cl->addValue("*.markdown"); + cl->addValue("*.md"); + cl->addValue("*.mm"); + cl->addValue("*.dox"); + cl->addValue("*.py"); + cl->addValue("*.f90"); + cl->addValue("*.f"); + cl->addValue("*.for"); + cl->addValue("*.vhd"); + cl->addValue("*.vhdl"); + //---- + cb = cfg->addBool( + "RECURSIVE", + "The RECURSIVE tag can be used to turn specify whether or not subdirectories\n" + "should be searched for input files as well. Possible values are YES and NO.\n" + "If left blank NO is used.", + FALSE + ); + //---- + cl = cfg->addList( + "EXCLUDE", + "The EXCLUDE tag can be used to specify files and/or directories that should be\n" + "excluded from the INPUT source files. This way you can easily exclude a\n" + "subdirectory from a directory tree whose root is specified with the INPUT tag.\n" + "Note that relative paths are relative to the directory from which doxygen is\n" + "run." + ); + cl->setWidgetType(ConfigList::FileAndDir); + //---- + cb = cfg->addBool( + "EXCLUDE_SYMLINKS", + "The EXCLUDE_SYMLINKS tag can be used to select whether or not files or\n" + "directories that are symbolic links (a Unix file system feature) are excluded\n" + "from the input.", + FALSE + ); + //---- + cl = cfg->addList( + "EXCLUDE_PATTERNS", + "If the value of the INPUT tag contains directories, you can use the\n" + "EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude\n" + "certain files from those directories. Note that the wildcards are matched\n" + "against the file with absolute path, so to exclude all test directories\n" + "for example use the pattern */test/*" + ); + //---- + cl = cfg->addList( + "EXCLUDE_SYMBOLS", + "The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names\n" + "(namespaces, classes, functions, etc.) that should be excluded from the\n" + "output. The symbol name can be a fully qualified name, a word, or if the\n" + "wildcard * is used, a substring. Examples: ANamespace, AClass,\n" + "AClass::ANamespace, ANamespace::*Test" + ); + //---- + cl = cfg->addList( + "EXAMPLE_PATH", + "The EXAMPLE_PATH tag can be used to specify one or more files or\n" + "directories that contain example code fragments that are included (see\n" + "the \\include command)." + ); + cl->setWidgetType(ConfigList::Dir); + //---- + cl = cfg->addList( + "EXAMPLE_PATTERNS", + "If the value of the EXAMPLE_PATH tag contains directories, you can use the\n" + "EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp\n" + "and *.h) to filter out the source-files in the directories. If left\n" + "blank all files are included." + ); + cl->addValue("*"); + //---- + cb = cfg->addBool( + "EXAMPLE_RECURSIVE", + "If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be\n" + "searched for input files to be used with the \\include or \\dontinclude\n" + "commands irrespective of the value of the RECURSIVE tag.\n" + "Possible values are YES and NO. If left blank NO is used.", + FALSE + ); + //---- + cl = cfg->addList( + "IMAGE_PATH", + "The IMAGE_PATH tag can be used to specify one or more files or\n" + "directories that contain image that are included in the documentation (see\n" + "the \\image command)." + ); + cl->setWidgetType(ConfigList::Dir); + //---- + cs = cfg->addString( + "INPUT_FILTER", + "The INPUT_FILTER tag can be used to specify a program that doxygen should\n" + "invoke to filter for each input file. Doxygen will invoke the filter program\n" + "by executing (via popen()) the command <filter> <input-file>, where <filter>\n" + "is the value of the INPUT_FILTER tag, and <input-file> is the name of an\n" + "input file. Doxygen will then use the output that the filter program writes\n" + "to standard output.\n" + "If FILTER_PATTERNS is specified, this tag will be\n" + "ignored." + ); + cs->setWidgetType(ConfigString::File); + //---- + cl = cfg->addList( + "FILTER_PATTERNS", + "The FILTER_PATTERNS tag can be used to specify filters on a per file pattern\n" + "basis.\n" + "Doxygen will compare the file name with each pattern and apply the\n" + "filter if there is a match.\n" + "The filters are a list of the form:\n" + "pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further\n" + "info on how filters are used. If FILTER_PATTERNS is empty or if\n" + "non of the patterns match the file name, INPUT_FILTER is applied." + ); + //---- + cb = cfg->addBool( + "FILTER_SOURCE_FILES", + "If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using\n" + "INPUT_FILTER) will be used to filter the input files when producing source\n" + "files to browse (i.e. when SOURCE_BROWSER is set to YES).", + FALSE + ); + //---- + cl = cfg->addList( + "FILTER_SOURCE_PATTERNS", + "The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file\n" + "pattern. A pattern will override the setting for FILTER_PATTERN (if any)\n" + "and it is also possible to disable source filtering for a specific pattern\n" + "using *.ext= (so without naming a filter). This option only has effect when\n" + "FILTER_SOURCE_FILES is enabled." + ); + cl->addDependency("FILTER_SOURCE_FILES"); + //--------------------------------------------------------------------------- + cfg->addInfo("Source Browser","configuration options related to source browsing"); + //--------------------------------------------------------------------------- + + //---- + cb = cfg->addBool( + "SOURCE_BROWSER", + "If the SOURCE_BROWSER tag is set to YES then a list of source files will\n" + "be generated. Documented entities will be cross-referenced with these sources.\n" + "Note: To get rid of all source code in the generated output, make sure also\n" + "VERBATIM_HEADERS is set to NO.", + FALSE + ); + //---- + cb = cfg->addBool( + "INLINE_SOURCES", + "Setting the INLINE_SOURCES tag to YES will include the body\n" + "of functions and classes directly in the documentation.", + FALSE + ); + //---- + cb = cfg->addBool( + "STRIP_CODE_COMMENTS", + "Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct\n" + "doxygen to hide any special comment blocks from generated source code\n" + "fragments. Normal C and C++ comments will always remain visible.", + TRUE + ); + //---- + cb = cfg->addBool( + "REFERENCED_BY_RELATION", + "If the REFERENCED_BY_RELATION tag is set to YES\n" + "then for each documented function all documented\n" + "functions referencing it will be listed.", + FALSE + ); + //---- + cb = cfg->addBool( + "REFERENCES_RELATION", + "If the REFERENCES_RELATION tag is set to YES\n" + "then for each documented function all documented entities\n" + "called/used by that function will be listed.", + FALSE + ); + //---- + cb = cfg->addBool( + "REFERENCES_LINK_SOURCE", + "If the REFERENCES_LINK_SOURCE tag is set to YES (the default)\n" + "and SOURCE_BROWSER tag is set to YES, then the hyperlinks from\n" + "functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will\n" + "link to the source code.\n" + "Otherwise they will link to the documentation.", + TRUE + ); + //---- + cb = cfg->addBool( + "USE_HTAGS", + "If the USE_HTAGS tag is set to YES then the references to source code\n" + "will point to the HTML generated by the htags(1) tool instead of doxygen\n" + "built-in source browser. The htags tool is part of GNU's global source\n" + "tagging system (see http://www.gnu.org/software/global/global.html). You\n" + "will need version 4.8.6 or higher.", + FALSE + ); + cb->addDependency("SOURCE_BROWSER"); + //---- + cb = cfg->addBool( + "VERBATIM_HEADERS", + "If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen\n" + "will generate a verbatim copy of the header file for each class for\n" + "which an include is specified. Set to NO to disable this.", + TRUE + ); + //--------------------------------------------------------------------------- + cfg->addInfo("Index","configuration options related to the alphabetical class index"); + //--------------------------------------------------------------------------- + + //---- + cb = cfg->addBool( + "ALPHABETICAL_INDEX", + "If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index\n" + "of all compounds will be generated. Enable this if the project\n" + "contains a lot of classes, structs, unions or interfaces.", + TRUE + ); + //---- + ci = cfg->addInt( + "COLS_IN_ALPHA_INDEX", + "If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then\n" + "the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns\n" + "in which this list will be split (can be a number in the range [1..20])", + 1,20,5 + ); + //---- + cl = cfg->addList( + "IGNORE_PREFIX", + "In case all classes in a project start with a common prefix, all\n" + "classes will be put under the same header in the alphabetical index.\n" + "The IGNORE_PREFIX tag can be used to specify one or more prefixes that\n" + "should be ignored while generating the index headers." + ); + //--------------------------------------------------------------------------- + cfg->addInfo("HTML","configuration options related to the HTML output"); + //--------------------------------------------------------------------------- + + //---- + cb = cfg->addBool( + "GENERATE_HTML", + "If the GENERATE_HTML tag is set to YES (the default) Doxygen will\n" + "generate HTML output.", + TRUE + ); + //---- + cs = cfg->addString( + "HTML_OUTPUT", + "The HTML_OUTPUT tag is used to specify where the HTML docs will be put.\n" + "If a relative path is entered the value of OUTPUT_DIRECTORY will be\n" + "put in front of it. If left blank `html' will be used as the default path." + ); + cs->setDefaultValue("html"); + cs->setWidgetType(ConfigString::Dir); + cs->addDependency("GENERATE_HTML"); + //---- + cs = cfg->addString( + "HTML_FILE_EXTENSION", + "The HTML_FILE_EXTENSION tag can be used to specify the file extension for\n" + "each generated HTML page (for example: .htm,.php,.asp). If it is left blank\n" + "doxygen will generate files with .html extension." + ); + cs->setDefaultValue(".html"); + cs->addDependency("GENERATE_HTML"); + //---- + cs = cfg->addString( + "HTML_HEADER", + "The HTML_HEADER tag can be used to specify a personal HTML header for\n" + "each generated HTML page. If it is left blank doxygen will generate a\n" + "standard header. Note that when using a custom header you are responsible\n" + " for the proper inclusion of any scripts and style sheets that doxygen\n" + "needs, which is dependent on the configuration options used.\n" + "It is advised to generate a default header using \"doxygen -w html\n" + "header.html footer.html stylesheet.css YourConfigFile\" and then modify\n" + "that header. Note that the header is subject to change so you typically\n" + "have to redo this when upgrading to a newer version of doxygen or when\n" + "changing the value of configuration settings such as GENERATE_TREEVIEW!" + ); + cs->setWidgetType(ConfigString::File); + cs->addDependency("GENERATE_HTML"); + //---- + cs = cfg->addString( + "HTML_FOOTER", + "The HTML_FOOTER tag can be used to specify a personal HTML footer for\n" + "each generated HTML page. If it is left blank doxygen will generate a\n" + "standard footer." + ); + cs->setWidgetType(ConfigString::File); + cs->addDependency("GENERATE_HTML"); + //---- + cs = cfg->addString( + "HTML_STYLESHEET", + "The HTML_STYLESHEET tag can be used to specify a user-defined cascading\n" + "style sheet that is used by each HTML page. It can be used to\n" + "fine-tune the look of the HTML output. If the tag is left blank doxygen\n" + "will generate a default style sheet. Note that doxygen will try to copy\n" + "the style sheet file to the HTML output directory, so don't put your own\n" + "style sheet in the HTML output directory as well, or it will be erased!" + ); + cs->setWidgetType(ConfigString::File); + cs->addDependency("GENERATE_HTML"); + //---- + cl = cfg->addList( + "HTML_EXTRA_FILES", + "The HTML_EXTRA_FILES tag can be used to specify one or more extra images or\n" + "other source files which should be copied to the HTML output directory. Note\n" + "that these files will be copied to the base HTML output directory. Use the\n" + "$relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these\n" + "files. In the HTML_STYLESHEET file, use the file name only. Also note that\n" + "the files will be copied as-is; there are no commands or markers available." + ); + cl->addDependency("GENERATE_HTML"); + cl->setWidgetType(ConfigList::File); + //---- + ci = cfg->addInt( + "HTML_COLORSTYLE_HUE", + "The HTML_COLORSTYLE_HUE tag controls the color of the HTML output.\n" + "Doxygen will adjust the colors in the style sheet and background images\n" + "according to this color. Hue is specified as an angle on a colorwheel,\n" + "see http://en.wikipedia.org/wiki/Hue for more information.\n" + "For instance the value 0 represents red, 60 is yellow, 120 is green,\n" + "180 is cyan, 240 is blue, 300 purple, and 360 is red again.\n" + "The allowed range is 0 to 359.", + 0,359,220 + ); + ci->addDependency("GENERATE_HTML"); + //---- + ci = cfg->addInt( + "HTML_COLORSTYLE_SAT", + "The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of\n" + "the colors in the HTML output. For a value of 0 the output will use\n" + "grayscales only. A value of 255 will produce the most vivid colors.", + 0,255,100 + ); + ci->addDependency("GENERATE_HTML"); + //---- + ci = cfg->addInt( + "HTML_COLORSTYLE_GAMMA", + "The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to\n" + "the luminance component of the colors in the HTML output. Values below\n" + "100 gradually make the output lighter, whereas values above 100 make\n" + "the output darker. The value divided by 100 is the actual gamma applied,\n" + "so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2,\n" + "and 100 does not change the gamma.", + 40,240,80 + ); + //---- + cb = cfg->addBool( + "HTML_TIMESTAMP", + "If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML\n" + "page will contain the date and time when the page was generated. Setting\n" + "this to NO can help when comparing the output of multiple runs.", + TRUE + ); + cb->addDependency("GENERATE_HTML"); + //---- + cb = cfg->addBool( + "HTML_ALIGN_MEMBERS", + "If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,\n" + "files or namespaces will be aligned in HTML using tables. If set to\n" + "NO a bullet list will be used.", + TRUE + ); + cb->addDependency("GENERATE_HTML"); + //---- + cb = cfg->addBool( + "HTML_DYNAMIC_SECTIONS", + "If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML\n" + "documentation will contain sections that can be hidden and shown after the\n" + "page has loaded. For this to work a browser that supports\n" + "JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox\n" + "Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).", + FALSE + ); + cb->addDependency("GENERATE_HTML"); + //---- + cb = cfg->addBool( + "GENERATE_DOCSET", + "If the GENERATE_DOCSET tag is set to YES, additional index files\n" + "will be generated that can be used as input for Apple's Xcode 3\n" + "integrated development environment, introduced with OSX 10.5 (Leopard).\n" + "To create a documentation set, doxygen will generate a Makefile in the\n" + "HTML output directory. Running make will produce the docset in that\n" + "directory and running \"make install\" will install the docset in\n" + "~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find\n" + "it at startup.\n" + "See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html\n" + "for more information.", + FALSE + ); + cb->addDependency("GENERATE_HTML"); + //---- + cs = cfg->addString( + "DOCSET_FEEDNAME", + "When GENERATE_DOCSET tag is set to YES, this tag determines the name of the\n" + "feed. A documentation feed provides an umbrella under which multiple\n" + "documentation sets from a single provider (such as a company or product suite)\n" + "can be grouped." + ); + cs->setDefaultValue("Doxygen generated docs"); + cs->addDependency("GENERATE_DOCSET"); + //---- + cs = cfg->addString( + "DOCSET_BUNDLE_ID", + "When GENERATE_DOCSET tag is set to YES, this tag specifies a string that\n" + "should uniquely identify the documentation set bundle. This should be a\n" + "reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen\n" + "will append .docset to the name." + ); + cs->setDefaultValue("org.doxygen.Project"); + cs->addDependency("GENERATE_DOCSET"); + //---- + cs = cfg->addString( + "DOCSET_PUBLISHER_ID", + "When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify\n" + "the documentation publisher. This should be a reverse domain-name style\n" + "string, e.g. com.mycompany.MyDocSet.documentation." + ); + cs->setDefaultValue("org.doxygen.Publisher"); + cs->addDependency("GENERATE_DOCSET"); + //---- + cs = cfg->addString( + "DOCSET_PUBLISHER_NAME", + "The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher." + ); + cs->setDefaultValue("Publisher"); + cs->addDependency("GENERATE_DOCSET"); + //---- + cb = cfg->addBool( + "GENERATE_HTMLHELP", + "If the GENERATE_HTMLHELP tag is set to YES, additional index files\n" + "will be generated that can be used as input for tools like the\n" + "Microsoft HTML help workshop to generate a compiled HTML help file (.chm)\n" + "of the generated HTML documentation.", + FALSE + ); + cb->addDependency("GENERATE_HTML"); + //---- + cs = cfg->addString( + "CHM_FILE", + "If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can\n" + "be used to specify the file name of the resulting .chm file. You\n" + "can add a path in front of the file if the result should not be\n" + "written to the html output directory." + ); + cs->setWidgetType(ConfigString::File); + cs->addDependency("GENERATE_HTMLHELP"); + //---- + cs = cfg->addString( + "HHC_LOCATION", + "If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can\n" + "be used to specify the location (absolute path including file name) of\n" + "the HTML help compiler (hhc.exe). If non-empty doxygen will try to run\n" + "the HTML help compiler on the generated index.hhp." + ); + cs->setWidgetType(ConfigString::File); + cs->addDependency("GENERATE_HTMLHELP"); + //---- + cb = cfg->addBool( + "GENERATE_CHI", + "If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag\n" + "controls if a separate .chi index file is generated (YES) or that\n" + "it should be included in the master .chm file (NO).", + FALSE + ); + cb->addDependency("GENERATE_HTMLHELP"); + //---- + cs = cfg->addString( + "CHM_INDEX_ENCODING", + "If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING\n" + "is used to encode HtmlHelp index (hhk), content (hhc) and project file\n" + "content." + ); + cs->addDependency("GENERATE_HTMLHELP"); + //---- + cb = cfg->addBool( + "BINARY_TOC", + "If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag\n" + "controls whether a binary table of contents is generated (YES) or a\n" + "normal table of contents (NO) in the .chm file.", + FALSE + ); + cb->addDependency("GENERATE_HTMLHELP"); + //---- + cb = cfg->addBool( + "TOC_EXPAND", + "The TOC_EXPAND flag can be set to YES to add extra items for group members\n" + "to the contents of the HTML help documentation and to the tree view.", + FALSE + ); + cb->addDependency("GENERATE_HTMLHELP"); + //---- + cb = cfg->addBool( + "GENERATE_QHP", + "If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and\n" + "QHP_VIRTUAL_FOLDER are set, an additional index file will be generated\n" + "that can be used as input for Qt's qhelpgenerator to generate a\n" + "Qt Compressed Help (.qch) of the generated HTML documentation.", + FALSE + ); + cb->addDependency("GENERATE_HTML"); + //---- + cs = cfg->addString( + "QCH_FILE", + "If the QHG_LOCATION tag is specified, the QCH_FILE tag can\n" + "be used to specify the file name of the resulting .qch file.\n" + "The path specified is relative to the HTML output folder." + ); + cs->setWidgetType(ConfigString::File); + cs->addDependency("GENERATE_QHP"); + //---- + cs = cfg->addString( + "QHP_NAMESPACE", + "The QHP_NAMESPACE tag specifies the namespace to use when generating\n" + "Qt Help Project output. For more information please see\n" + "http://doc.trolltech.com/qthelpproject.html#namespace" + ); + cs->setDefaultValue("org.doxygen.Project"); + cs->addDependency("GENERATE_QHP"); + //---- + cs = cfg->addString( + "QHP_VIRTUAL_FOLDER", + "The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating\n" + "Qt Help Project output. For more information please see\n" + "http://doc.trolltech.com/qthelpproject.html#virtual-folders" + ); + cs->setDefaultValue("doc"); + cs->addDependency("GENERATE_QHP"); + //---- + cs = cfg->addString( + "QHP_CUST_FILTER_NAME", + "If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to\n" + "add. For more information please see\n" + "http://doc.trolltech.com/qthelpproject.html#custom-filters" + ); + cs->addDependency("GENERATE_QHP"); + //---- + cs = cfg->addString( + "QHP_CUST_FILTER_ATTRS", + "The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the\n" + "custom filter to add. For more information please see\n" + "<a href=\"http://doc.trolltech.com/qthelpproject.html#custom-filters\">\n" + "Qt Help Project / Custom Filters</a>." + ); + cs->addDependency("GENERATE_QHP"); + //---- + cs = cfg->addString( + "QHP_SECT_FILTER_ATTRS", + "The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this\n" + "project's\n" + "filter section matches.\n" + "<a href=\"http://doc.trolltech.com/qthelpproject.html#filter-attributes\">\n" + "Qt Help Project / Filter Attributes</a>." + ); + cs->addDependency("GENERATE_QHP"); + //---- + cs = cfg->addString( + "QHG_LOCATION", + "If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can\n" + "be used to specify the location of Qt's qhelpgenerator.\n" + "If non-empty doxygen will try to run qhelpgenerator on the generated\n" + ".qhp file." + ); + cs->setWidgetType(ConfigString::File); + cs->addDependency("GENERATE_QHP"); + //---- + cb = cfg->addBool( + "GENERATE_ECLIPSEHELP", + "If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files\n" + " will be generated, which together with the HTML files, form an Eclipse help\n" + "plugin. To install this plugin and make it available under the help contents\n" + "menu in Eclipse, the contents of the directory containing the HTML and XML\n" + "files needs to be copied into the plugins directory of eclipse. The name of\n" + "the directory within the plugins directory should be the same as\n" + "the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before\n" + "the help appears.", + FALSE + ); + cb->addDependency("GENERATE_HTML"); + //---- + cs = cfg->addString( + "ECLIPSE_DOC_ID", + "A unique identifier for the eclipse help plugin. When installing the plugin\n" + "the directory name containing the HTML and XML files should also have\n" + "this name." + ); + cs->setDefaultValue("org.doxygen.Project"); + cs->addDependency("GENERATE_ECLIPSEHELP"); + //---- + cb = cfg->addBool( + "DISABLE_INDEX", + "The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs)\n" + "at top of each HTML page. The value NO (the default) enables the index and\n" + "the value YES disables it. Since the tabs have the same information as the\n" + "navigation tree you can set this option to NO if you already set\n" + "GENERATE_TREEVIEW to YES.", + FALSE + ); + cb->addDependency("GENERATE_HTML"); + //---- + cb = cfg->addBool( + "GENERATE_TREEVIEW", + "The GENERATE_TREEVIEW tag is used to specify whether a tree-like index\n" + "structure should be generated to display hierarchical information.\n" + "If the tag value is set to YES, a side panel will be generated\n" + "containing a tree-like index structure (just like the one that\n" + "is generated for HTML Help). For this to work a browser that supports\n" + "JavaScript, DHTML, CSS and frames is required (i.e. any modern browser).\n" + "Windows users are probably better off using the HTML help feature.\n" + "Since the tree basically has the same information as the tab index you\n" + "could consider to set DISABLE_INDEX to NO when enabling this option.", + FALSE + ); + cb->addDependency("GENERATE_HTML"); + //---- + ci = cfg->addInt( + "ENUM_VALUES_PER_LINE", + "The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values\n" + "(range [0,1..20]) that doxygen will group on one line in the generated HTML\n" + "documentation. Note that a value of 0 will completely suppress the enum\n" + "values from appearing in the overview section.", + 0,20,4 + ); + ci->addDependency("GENERATE_HTML"); + //---- + cb = cfg->addBool( + "USE_INLINE_TREES", + "By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories,\n" + "and Class Hierarchy pages using a tree view instead of an ordered list.", + FALSE + ); + cb->addDependency("GENERATE_HTML"); + //---- + ci = cfg->addInt( + "TREEVIEW_WIDTH", + "If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be\n" + "used to set the initial width (in pixels) of the frame in which the tree\n" + "is shown.", + 0,1500,250 + ); + ci->addDependency("GENERATE_HTML"); + //---- + cb = cfg->addBool( + "EXT_LINKS_IN_WINDOW", + "When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open\n" + "links to external symbols imported via tag files in a separate window.", + FALSE + ); + cb->addDependency("GENERATE_HTML"); + //---- + ci = cfg->addInt( + "FORMULA_FONTSIZE", + "Use this tag to change the font size of Latex formulas included\n" + "as images in the HTML documentation. The default is 10. Note that\n" + "when you change the font size after a successful doxygen run you need\n" + "to manually remove any form_*.png images from the HTML output directory\n" + "to force them to be regenerated.", + 8,50,10 + ); + ci->addDependency("GENERATE_HTML"); + //---- + cb = cfg->addBool( + "FORMULA_TRANSPARENT", + "Use the FORMULA_TRANPARENT tag to determine whether or not the images\n" + "generated for formulas are transparent PNGs. Transparent PNGs are\n" + "not supported properly for IE 6.0, but are supported on all modern browsers.\n" + "Note that when changing this option you need to delete any form_*.png files\n" + "in the HTML output before the changes have effect.", + TRUE + ); + cb->addDependency("GENERATE_HTML"); + //---- + cb = cfg->addBool( + "USE_MATHJAX", + "Enable the USE_MATHJAX option to render LaTeX formulas using MathJax\n" + "(see http://www.mathjax.org) which uses client side Javascript for the\n" + "rendering instead of using prerendered bitmaps. Use this if you do not\n" + "have LaTeX installed or if you want to formulas look prettier in the HTML\n" + "output. When enabled you may also need to install MathJax separately and\n" + "configure the path to it using the MATHJAX_RELPATH option.", + FALSE + ); + //---- + cs = cfg->addString( + "MATHJAX_RELPATH", + "When MathJax is enabled you need to specify the location relative to the\n" + "HTML output directory using the MATHJAX_RELPATH option. The destination\n" + "directory should contain the MathJax.js script. For instance, if the mathjax\n" + "directory is located at the same level as the HTML output directory, then\n" + "MATHJAX_RELPATH should be ../mathjax. The default value points to\n" + "the MathJax Content Delivery Network so you can quickly see the result without\n" + "installing MathJax.\n" + "However, it is strongly recommended to install a local\n" + "copy of MathJax from http://www.mathjax.org before deployment." + ); + cs->setDefaultValue("http://cdn.mathjax.org/mathjax/latest"); + //---- + cl = cfg->addList( + "MATHJAX_EXTENSIONS", + "The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension\n" + "names that should be enabled during MathJax rendering." + ); + cl->addDependency("USE_MATHJAX"); + //---- + cb = cfg->addBool( + "SEARCHENGINE", + "When the SEARCHENGINE tag is enabled doxygen will generate a search box\n" + "for the HTML output. The underlying search engine uses javascript\n" + "and DHTML and should work on any modern browser. Note that when using\n" + "HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets\n" + "(GENERATE_DOCSET) there is already a search function so this one should\n" + "typically be disabled. For large projects the javascript based search engine\n" + "can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution.", + TRUE + ); + cb->addDependency("GENERATE_HTML"); + //---- + cb = cfg->addBool( + "SERVER_BASED_SEARCH", + "When the SERVER_BASED_SEARCH tag is enabled the search engine will be\n" + "implemented using a PHP enabled web server instead of at the web client\n" + "using Javascript. Doxygen will generate the search PHP script and index\n" + "file to put on the web server. The advantage of the server\n" + "based approach is that it scales better to large projects and allows\n" + "full text search. The disadvantages are that it is more difficult to setup\n" + "and does not have live searching capabilities.", + FALSE + ); + cb->addDependency("SEARCHENGINE"); + //--------------------------------------------------------------------------- + cfg->addInfo("LaTeX","configuration options related to the LaTeX output"); + //--------------------------------------------------------------------------- + + //---- + cb = cfg->addBool( + "GENERATE_LATEX", + "If the GENERATE_LATEX tag is set to YES (the default) Doxygen will\n" + "generate Latex output.", + TRUE + ); + //---- + cs = cfg->addString( + "LATEX_OUTPUT", + "The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.\n" + "If a relative path is entered the value of OUTPUT_DIRECTORY will be\n" + "put in front of it. If left blank `latex' will be used as the default path." + ); + cs->setDefaultValue("latex"); + cs->setWidgetType(ConfigString::Dir); + cs->addDependency("GENERATE_LATEX"); + //---- + cs = cfg->addString( + "LATEX_CMD_NAME", + "The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be\n" + "invoked. If left blank `latex' will be used as the default command name.\n" + "Note that when enabling USE_PDFLATEX this option is only used for\n" + "generating bitmaps for formulas in the HTML output, but not in the\n" + "Makefile that is written to the output directory." + ); + cs->setDefaultValue("latex"); + cs->setWidgetType(ConfigString::File); + cs->addDependency("GENERATE_LATEX"); + //---- + cs = cfg->addString( + "MAKEINDEX_CMD_NAME", + "The MAKEINDEX_CMD_NAME tag can be used to specify the command name to\n" + "generate index for LaTeX. If left blank `makeindex' will be used as the\n" + "default command name." + ); + cs->setDefaultValue("makeindex"); + cs->setWidgetType(ConfigString::File); + cs->addDependency("GENERATE_LATEX"); + //---- + cb = cfg->addBool( + "COMPACT_LATEX", + "If the COMPACT_LATEX tag is set to YES Doxygen generates more compact\n" + "LaTeX documents. This may be useful for small projects and may help to\n" + "save some trees in general.", + FALSE + ); + cb->addDependency("GENERATE_LATEX"); + //---- + ce = cfg->addEnum( + "PAPER_TYPE", + "The PAPER_TYPE tag can be used to set the paper type that is used\n" + "by the printer. Possible values are: a4, letter, legal and\n" + "executive. If left blank a4wide will be used.", + "a4" + ); + ce->addValue("a4"); + ce->addValue("a4wide"); + ce->addValue("letter"); + ce->addValue("legal"); + ce->addValue("executive"); + ce->addDependency("GENERATE_LATEX"); + //---- + cl = cfg->addList( + "EXTRA_PACKAGES", + "The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX\n" + "packages that should be included in the LaTeX output." + ); + cl->addDependency("GENERATE_LATEX"); + //---- + cs = cfg->addString( + "LATEX_HEADER", + "The LATEX_HEADER tag can be used to specify a personal LaTeX header for\n" + "the generated latex document. The header should contain everything until\n" + "the first chapter. If it is left blank doxygen will generate a\n" + "standard header. Notice: only use this tag if you know what you are doing!" + ); + cs->setWidgetType(ConfigString::File); + cs->addDependency("GENERATE_LATEX"); + //---- + cs = cfg->addString( + "LATEX_FOOTER", + "The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for\n" + "the generated latex document. The footer should contain everything after\n" + "the last chapter. If it is left blank doxygen will generate a\n" + "standard footer. Notice: only use this tag if you know what you are doing!" + ); + cs->setWidgetType(ConfigString::File); + cs->addDependency("GENERATE_LATEX"); + //---- + cb = cfg->addBool( + "PDF_HYPERLINKS", + "If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated\n" + "is prepared for conversion to pdf (using ps2pdf). The pdf file will\n" + "contain links (just like the HTML output) instead of page references\n" + "This makes the output suitable for online browsing using a pdf viewer.", + TRUE + ); + cb->addDependency("GENERATE_LATEX"); + //---- + cb = cfg->addBool( + "USE_PDFLATEX", + "If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of\n" + "plain latex in the generated Makefile. Set this option to YES to get a\n" + "higher quality PDF documentation.", + TRUE + ); + cb->addDependency("GENERATE_LATEX"); + //---- + cb = cfg->addBool( + "LATEX_BATCHMODE", + "If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\\\batchmode.\n" + "command to the generated LaTeX files. This will instruct LaTeX to keep\n" + "running if errors occur, instead of asking the user for help.\n" + "This option is also used when generating formulas in HTML.", + FALSE + ); + cb->addDependency("GENERATE_LATEX"); + //---- + cb = cfg->addBool( + "LATEX_HIDE_INDICES", + "If LATEX_HIDE_INDICES is set to YES then doxygen will not\n" + "include the index chapters (such as File Index, Compound Index, etc.)\n" + "in the output.", + FALSE + ); + cb->addDependency("GENERATE_LATEX"); + //---- + cb = cfg->addBool( + "LATEX_SOURCE_CODE", + "If LATEX_SOURCE_CODE is set to YES then doxygen will include\n" + "source code with syntax highlighting in the LaTeX output.\n" + "Note that which sources are shown also depends on other settings\n" + "such as SOURCE_BROWSER.", + FALSE + ); + cb->addDependency("GENERATE_LATEX"); + //---- + cs = cfg->addString( + "LATEX_BIB_STYLE", + "The LATEX_BIB_STYLE tag can be used to specify the style to use for the\n" + "bibliography, e.g. plainnat, or ieeetr. The default style is \"plain\". See\n" + "http://en.wikipedia.org/wiki/BibTeX for more info." + ); + cs->setDefaultValue("plain"); + //--------------------------------------------------------------------------- + cfg->addInfo("RTF","configuration options related to the RTF output"); + //--------------------------------------------------------------------------- + + //---- + cb = cfg->addBool( + "GENERATE_RTF", + "If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output\n" + "The RTF output is optimized for Word 97 and may not look very pretty with\n" + "other RTF readers or editors.", + FALSE + ); + //---- + cs = cfg->addString( + "RTF_OUTPUT", + "The RTF_OUTPUT tag is used to specify where the RTF docs will be put.\n" + "If a relative path is entered the value of OUTPUT_DIRECTORY will be\n" + "put in front of it. If left blank `rtf' will be used as the default path." + ); + cs->setDefaultValue("rtf"); + cs->setWidgetType(ConfigString::Dir); + cs->addDependency("GENERATE_RTF"); + //---- + cb = cfg->addBool( + "COMPACT_RTF", + "If the COMPACT_RTF tag is set to YES Doxygen generates more compact\n" + "RTF documents. This may be useful for small projects and may help to\n" + "save some trees in general.", + FALSE + ); + cb->addDependency("GENERATE_RTF"); + //---- + cb = cfg->addBool( + "RTF_HYPERLINKS", + "If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated\n" + "will contain hyperlink fields. The RTF file will\n" + "contain links (just like the HTML output) instead of page references.\n" + "This makes the output suitable for online browsing using WORD or other\n" + "programs which support those fields.\n" + "Note: wordpad (write) and others do not support links.", + FALSE + ); + cb->addDependency("GENERATE_RTF"); + //---- + cs = cfg->addString( + "RTF_STYLESHEET_FILE", + "Load style sheet definitions from file. Syntax is similar to doxygen's\n" + "config file, i.e. a series of assignments. You only have to provide\n" + "replacements, missing definitions are set to their default value." + ); + cs->setWidgetType(ConfigString::File); + cs->addDependency("GENERATE_RTF"); + //---- + cs = cfg->addString( + "RTF_EXTENSIONS_FILE", + "Set optional variables used in the generation of an rtf document.\n" + "Syntax is similar to doxygen's config file." + ); + cs->setWidgetType(ConfigString::File); + cs->addDependency("GENERATE_RTF"); + //--------------------------------------------------------------------------- + cfg->addInfo("Man","configuration options related to the man page output"); + //--------------------------------------------------------------------------- + + //---- + cb = cfg->addBool( + "GENERATE_MAN", + "If the GENERATE_MAN tag is set to YES (the default) Doxygen will\n" + "generate man pages", + FALSE + ); + //---- + cs = cfg->addString( + "MAN_OUTPUT", + "The MAN_OUTPUT tag is used to specify where the man pages will be put.\n" + "If a relative path is entered the value of OUTPUT_DIRECTORY will be\n" + "put in front of it. If left blank `man' will be used as the default path." + ); + cs->setDefaultValue("man"); + cs->setWidgetType(ConfigString::Dir); + cs->addDependency("GENERATE_MAN"); + //---- + cs = cfg->addString( + "MAN_EXTENSION", + "The MAN_EXTENSION tag determines the extension that is added to\n" + "the generated man pages (default is the subroutine's section .3)" + ); + cs->setDefaultValue(".3"); + cs->addDependency("GENERATE_MAN"); + //---- + cb = cfg->addBool( + "MAN_LINKS", + "If the MAN_LINKS tag is set to YES and Doxygen generates man output,\n" + "then it will generate one additional man file for each entity\n" + "documented in the real man page(s). These additional files\n" + "only source the real man page, but without them the man command\n" + "would be unable to find the correct page. The default is NO.", + FALSE + ); + cb->addDependency("GENERATE_MAN"); + //--------------------------------------------------------------------------- + cfg->addInfo("XML","configuration options related to the XML output"); + //--------------------------------------------------------------------------- + + //---- + cb = cfg->addBool( + "GENERATE_XML", + "If the GENERATE_XML tag is set to YES Doxygen will\n" + "generate an XML file that captures the structure of\n" + "the code including all documentation.", + FALSE + ); + //---- + cs = cfg->addString( + "XML_OUTPUT", + "The XML_OUTPUT tag is used to specify where the XML pages will be put.\n" + "If a relative path is entered the value of OUTPUT_DIRECTORY will be\n" + "put in front of it. If left blank `xml' will be used as the default path." + ); + cs->setDefaultValue("xml"); + cs->setWidgetType(ConfigString::Dir); + cs->addDependency("GENERATE_XML"); + //---- + cs = cfg->addString( + "XML_SCHEMA", + "The XML_SCHEMA tag can be used to specify an XML schema,\n" + "which can be used by a validating XML parser to check the\n" + "syntax of the XML files." + ); + cs->addDependency("GENERATE_XML"); + //---- + cs = cfg->addString( + "XML_DTD", + "The XML_DTD tag can be used to specify an XML DTD,\n" + "which can be used by a validating XML parser to check the\n" + "syntax of the XML files." + ); + cs->addDependency("GENERATE_XML"); + //---- + cb = cfg->addBool( + "XML_PROGRAMLISTING", + "If the XML_PROGRAMLISTING tag is set to YES Doxygen will\n" + "dump the program listings (including syntax highlighting\n" + "and cross-referencing information) to the XML output. Note that\n" + "enabling this will significantly increase the size of the XML output.", + TRUE + ); + cb->addDependency("GENERATE_XML"); + //--------------------------------------------------------------------------- + cfg->addInfo("DEF","configuration options for the AutoGen Definitions output"); + //--------------------------------------------------------------------------- + + //---- + cb = cfg->addBool( + "GENERATE_AUTOGEN_DEF", + "If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will\n" + "generate an AutoGen Definitions (see autogen.sf.net) file\n" + "that captures the structure of the code including all\n" + "documentation. Note that this feature is still experimental\n" + "and incomplete at the moment.", + FALSE + ); + //--------------------------------------------------------------------------- + cfg->addInfo("PerlMod","configuration options related to the Perl module output"); + //--------------------------------------------------------------------------- + + //---- + cb = cfg->addBool( + "GENERATE_PERLMOD", + "If the GENERATE_PERLMOD tag is set to YES Doxygen will\n" + "generate a Perl module file that captures the structure of\n" + "the code including all documentation. Note that this\n" + "feature is still experimental and incomplete at the\n" + "moment.", + FALSE + ); + //---- + cb = cfg->addBool( + "PERLMOD_LATEX", + "If the PERLMOD_LATEX tag is set to YES Doxygen will generate\n" + "the necessary Makefile rules, Perl scripts and LaTeX code to be able\n" + "to generate PDF and DVI output from the Perl module output.", + FALSE + ); + cb->addDependency("GENERATE_PERLMOD"); + //---- + cb = cfg->addBool( + "PERLMOD_PRETTY", + "If the PERLMOD_PRETTY tag is set to YES the Perl module output will be\n" + "nicely formatted so it can be parsed by a human reader.\n" + "This is useful\n" + "if you want to understand what is going on.\n" + "On the other hand, if this\n" + "tag is set to NO the size of the Perl module output will be much smaller\n" + "and Perl will parse it just the same.", + TRUE + ); + cb->addDependency("GENERATE_PERLMOD"); + //---- + cs = cfg->addString( + "PERLMOD_MAKEVAR_PREFIX", + "The names of the make variables in the generated doxyrules.make file\n" + "are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.\n" + "This is useful so different doxyrules.make files included by the same\n" + "Makefile don't overwrite each other's variables." + ); + cs->addDependency("GENERATE_PERLMOD"); + //--------------------------------------------------------------------------- + cfg->addInfo("Preprocessor","Configuration options related to the preprocessor"); + //--------------------------------------------------------------------------- + + //---- + cb = cfg->addBool( + "ENABLE_PREPROCESSING", + "If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will\n" + "evaluate all C-preprocessor directives found in the sources and include\n" + "files.", + TRUE + ); + //---- + cb = cfg->addBool( + "MACRO_EXPANSION", + "If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro\n" + "names in the source code. If set to NO (the default) only conditional\n" + "compilation will be performed. Macro expansion can be done in a controlled\n" + "way by setting EXPAND_ONLY_PREDEF to YES.", + FALSE + ); + cb->addDependency("ENABLE_PREPROCESSING"); + //---- + cb = cfg->addBool( + "EXPAND_ONLY_PREDEF", + "If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES\n" + "then the macro expansion is limited to the macros specified with the\n" + "PREDEFINED and EXPAND_AS_DEFINED tags.", + FALSE + ); + cb->addDependency("ENABLE_PREPROCESSING"); + //---- + cb = cfg->addBool( + "SEARCH_INCLUDES", + "If the SEARCH_INCLUDES tag is set to YES (the default) the includes files\n" + "pointed to by INCLUDE_PATH will be searched when a #include is found.", + TRUE + ); + cb->addDependency("ENABLE_PREPROCESSING"); + //---- + cl = cfg->addList( + "INCLUDE_PATH", + "The INCLUDE_PATH tag can be used to specify one or more directories that\n" + "contain include files that are not input files but should be processed by\n" + "the preprocessor." + ); + cl->addDependency("ENABLE_PREPROCESSING"); + cl->setWidgetType(ConfigList::Dir); + //---- + cl = cfg->addList( + "INCLUDE_FILE_PATTERNS", + "You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard\n" + "patterns (like *.h and *.hpp) to filter out the header-files in the\n" + "directories. If left blank, the patterns specified with FILE_PATTERNS will\n" + "be used." + ); + cl->addDependency("ENABLE_PREPROCESSING"); + //---- + cl = cfg->addList( + "PREDEFINED", + "The PREDEFINED tag can be used to specify one or more macro names that\n" + "are defined before the preprocessor is started (similar to the -D option of\n" + "gcc). The argument of the tag is a list of macros of the form: name\n" + "or name=definition (no spaces). If the definition and the = are\n" + "omitted =1 is assumed. To prevent a macro definition from being\n" + "undefined via #undef or recursively expanded use the := operator\n" + "instead of the = operator." + ); + cl->addDependency("ENABLE_PREPROCESSING"); + //---- + cl = cfg->addList( + "EXPAND_AS_DEFINED", + "If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then\n" + "this tag can be used to specify a list of macro names that should be expanded.\n" + "The macro definition that is found in the sources will be used.\n" + "Use the PREDEFINED tag if you want to use a different macro definition that\n" + "overrules the definition found in the source code." + ); + cl->addDependency("ENABLE_PREPROCESSING"); + //---- + cb = cfg->addBool( + "SKIP_FUNCTION_MACROS", + "If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then\n" + "doxygen's preprocessor will remove all references to function-like macros\n" + "that are alone on a line, have an all uppercase name, and do not end with a\n" + "semicolon, because these will confuse the parser if not removed.", + TRUE + ); + cb->addDependency("ENABLE_PREPROCESSING"); + //--------------------------------------------------------------------------- + cfg->addInfo("External","Configuration::additions related to external references"); + //--------------------------------------------------------------------------- + + //---- + cl = cfg->addList( + "TAGFILES", + "The TAGFILES option can be used to specify one or more tagfiles. For each\n" + "tag file the location of the external documentation should be added. The\n" + "format of a tag file without this location is as follows:\n" + "\n" + "TAGFILES = file1 file2 ...\n" + "Adding location for the tag files is done as follows:\n" + "\n" + "TAGFILES = file1=loc1 \"file2 = loc2\" ...\n" + "where \"loc1\" and \"loc2\" can be relative or absolute paths\n" + "or URLs. Note that each tag file must have a unique name (where the name does\n" + "NOT include the path). If a tag file is not located in the directory in which\n" + "doxygen is run, you must also specify the path to the tagfile here." + ); + cl->setWidgetType(ConfigList::File); + //---- + cs = cfg->addString( + "GENERATE_TAGFILE", + "When a file name is specified after GENERATE_TAGFILE, doxygen will create\n" + "a tag file that is based on the input files it reads." + ); + cs->setWidgetType(ConfigString::File); + //---- + cb = cfg->addBool( + "ALLEXTERNALS", + "If the ALLEXTERNALS tag is set to YES all external classes will be listed\n" + "in the class index. If set to NO only the inherited external classes\n" + "will be listed.", + FALSE + ); + //---- + cb = cfg->addBool( + "EXTERNAL_GROUPS", + "If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed\n" + "in the modules index. If set to NO, only the current project's groups will\n" + "be listed.", + TRUE + ); + //---- + cs = cfg->addString( + "PERL_PATH", + "The PERL_PATH should be the absolute path and name of the perl script\n" + "interpreter (i.e. the result of `which perl')." + ); + cs->setDefaultValue("/usr/bin/perl"); + cs->setWidgetType(ConfigString::Dir); + //--------------------------------------------------------------------------- + cfg->addInfo("Dot","Configuration options related to the dot tool"); + //--------------------------------------------------------------------------- + + //---- + cb = cfg->addBool( + "CLASS_DIAGRAMS", + "If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will\n" + "generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base\n" + "or super classes. Setting the tag to NO turns the diagrams off. Note that\n" + "this option also works with HAVE_DOT disabled, but it is recommended to\n" + "install and use dot, since it yields more powerful graphs.", + TRUE + ); + //---- + cs = cfg->addString( + "MSCGEN_PATH", + "You can define message sequence charts within doxygen comments using the \\msc\n" + "command. Doxygen will then run the mscgen tool (see\n" + "http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the\n" + "documentation. The MSCGEN_PATH tag allows you to specify the directory where\n" + "the mscgen tool resides. If left empty the tool is assumed to be found in the\n" + "default search path." + ); + //---- + cb = cfg->addBool( + "HIDE_UNDOC_RELATIONS", + "If set to YES, the inheritance and collaboration graphs will hide\n" + "inheritance and usage relations if the target is undocumented\n" + "or is not a class.", + TRUE + ); + //---- + cb = cfg->addBool( + "HAVE_DOT", + "If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is\n" + "available from the path. This tool is part of Graphviz, a graph visualization\n" + "toolkit from AT&T and Lucent Bell Labs. The other options in this section\n" + "have no effect if this option is set to NO (the default)", + FALSE + ); + //---- + ci = cfg->addInt( + "DOT_NUM_THREADS", + "The DOT_NUM_THREADS specifies the number of dot invocations doxygen is\n" + "allowed to run in parallel. When set to 0 (the default) doxygen will\n" + "base this on the number of processors available in the system. You can set it\n" + "explicitly to a value larger than 0 to get control over the balance\n" + "between CPU load and processing speed.", + 0,32,0 + ); + //---- + cs = cfg->addString( + "DOT_FONTNAME", + "By default doxygen will use the Helvetica font for all dot files that\n" + "doxygen generates. When you want a differently looking font you can specify\n" + "the font name using DOT_FONTNAME. You need to make sure dot is able to find\n" + "the font, which can be done by putting it in a standard location or by setting\n" + "the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the\n" + "directory containing the font." + ); + cs->setDefaultValue("Helvetica"); + cs->addDependency("HAVE_DOT"); + //---- + ci = cfg->addInt( + "DOT_FONTSIZE", + "The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.\n" + "The default size is 10pt.", + 4,24,10 + ); + ci->addDependency("HAVE_DOT"); + //---- + cs = cfg->addString( + "DOT_FONTPATH", + "By default doxygen will tell dot to use the Helvetica font.\n" + "If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to\n" + "set the path where dot can find it." + ); + cs->addDependency("HAVE_DOT"); + //---- + cb = cfg->addBool( + "CLASS_GRAPH", + "If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen\n" + "will generate a graph for each documented class showing the direct and\n" + "indirect inheritance relations. Setting this tag to YES will force the\n" + "CLASS_DIAGRAMS tag to NO.", + TRUE + ); + cb->addDependency("HAVE_DOT"); + //---- + cb = cfg->addBool( + "COLLABORATION_GRAPH", + "If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen\n" + "will generate a graph for each documented class showing the direct and\n" + "indirect implementation dependencies (inheritance, containment, and\n" + "class references variables) of the class with other documented classes.", + TRUE + ); + cb->addDependency("HAVE_DOT"); + //---- + cb = cfg->addBool( + "GROUP_GRAPHS", + "If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen\n" + "will generate a graph for groups, showing the direct groups dependencies", + TRUE + ); + cb->addDependency("HAVE_DOT"); + //---- + cb = cfg->addBool( + "UML_LOOK", + "If the UML_LOOK tag is set to YES doxygen will generate inheritance and\n" + "collaboration diagrams in a style similar to the OMG's Unified Modeling\n" + "Language.", + FALSE + ); + cb->addDependency("HAVE_DOT"); + //---- + ci = cfg->addInt( + "UML_LIMIT_NUM_FIELDS", + "If the UML_LOOK tag is enabled, the fields and methods are shown inside\n" + "the class node. If there are many fields or methods and many nodes the\n" + "graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS\n" + "threshold limits the number of items for each type to make the size more\n" + "managable. Set this to 0 for no limit. Note that the threshold may be\n" + "exceeded by 50% before the limit is enforced.", + 0,100,10 + ); + ci->addDependency("HAVE_DOT"); + //---- + cb = cfg->addBool( + "TEMPLATE_RELATIONS", + "If set to YES, the inheritance and collaboration graphs will show the\n" + "relations between templates and their instances.", + FALSE + ); + cb->addDependency("HAVE_DOT"); + //---- + cb = cfg->addBool( + "INCLUDE_GRAPH", + "If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT\n" + "tags are set to YES then doxygen will generate a graph for each documented\n" + "file showing the direct and indirect include dependencies of the file with\n" + "other documented files.", + TRUE + ); + cb->addDependency("HAVE_DOT"); + //---- + cb = cfg->addBool( + "INCLUDED_BY_GRAPH", + "If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and\n" + "HAVE_DOT tags are set to YES then doxygen will generate a graph for each\n" + "documented header file showing the documented files that directly or\n" + "indirectly include this file.", + TRUE + ); + cb->addDependency("HAVE_DOT"); + //---- + cb = cfg->addBool( + "CALL_GRAPH", + "If the CALL_GRAPH and HAVE_DOT options are set to YES then\n" + "doxygen will generate a call dependency graph for every global function\n" + "or class method. Note that enabling this option will significantly increase\n" + "the time of a run. So in most cases it will be better to enable call graphs\n" + "for selected functions only using the \\callgraph command.", + FALSE + ); + cb->addDependency("HAVE_DOT"); + //---- + cb = cfg->addBool( + "CALLER_GRAPH", + "If the CALLER_GRAPH and HAVE_DOT tags are set to YES then\n" + "doxygen will generate a caller dependency graph for every global function\n" + "or class method. Note that enabling this option will significantly increase\n" + "the time of a run. So in most cases it will be better to enable caller\n" + "graphs for selected functions only using the \\callergraph command.", + FALSE + ); + cb->addDependency("HAVE_DOT"); + //---- + cb = cfg->addBool( + "GRAPHICAL_HIERARCHY", + "If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen\n" + "will generate a graphical hierarchy of all classes instead of a textual one.", + TRUE + ); + cb->addDependency("HAVE_DOT"); + //---- + cb = cfg->addBool( + "DIRECTORY_GRAPH", + "If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES\n" + "then doxygen will show the dependencies a directory has on other directories\n" + "in a graphical way. The dependency relations are determined by the #include\n" + "relations between the files in the directories.", + TRUE + ); + cb->addDependency("HAVE_DOT"); + //---- + ce = cfg->addEnum( + "DOT_IMAGE_FORMAT", + "The DOT_IMAGE_FORMAT tag can be used to set the image format of the images\n" + "generated by dot. Possible values are svg, png, jpg, or gif.\n" + "If left blank png will be used. If you choose svg you need to set\n" + "HTML_FILE_EXTENSION to xhtml in order to make the SVG files\n" + "visible in IE 9+ (other browsers do not have this requirement).", + "png" + ); + ce->addValue("png"); + ce->addValue("jpg"); + ce->addValue("gif"); + ce->addValue("svg"); + ce->addDependency("HAVE_DOT"); + //---- + cb = cfg->addBool( + "INTERACTIVE_SVG", + "If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to\n" + "enable generation of interactive SVG images that allow zooming and panning.\n" + "Note that this requires a modern browser other than Internet Explorer.\n" + "Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you\n" + "need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files\n" + "visible. Older versions of IE do not have SVG support.", + FALSE + ); + cb->addDependency("HAVE_DOT"); + //---- + cs = cfg->addString( + "DOT_PATH", + "The tag DOT_PATH can be used to specify the path where the dot tool can be\n" + "found. If left blank, it is assumed the dot tool can be found in the path." + ); + cs->setWidgetType(ConfigString::Dir); + cs->addDependency("HAVE_DOT"); + //---- + cl = cfg->addList( + "DOTFILE_DIRS", + "The DOTFILE_DIRS tag can be used to specify one or more directories that\n" + "contain dot files that are included in the documentation (see the\n" + "\\dotfile command)." + ); + cl->addDependency("HAVE_DOT"); + cl->setWidgetType(ConfigList::Dir); + //---- + cl = cfg->addList( + "MSCFILE_DIRS", + "The MSCFILE_DIRS tag can be used to specify one or more directories that\n" + "contain msc files that are included in the documentation (see the\n" + "\\mscfile command)." + ); + cl->setWidgetType(ConfigList::Dir); + //---- + ci = cfg->addInt( + "DOT_GRAPH_MAX_NODES", + "The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of\n" + "nodes that will be shown in the graph. If the number of nodes in a graph\n" + "becomes larger than this value, doxygen will truncate the graph, which is\n" + "visualized by representing a node as a red box. Note that doxygen if the\n" + "number of direct children of the root node in a graph is already larger than\n" + "DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note\n" + "that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.", + 0,10000,50 + ); + ci->addDependency("HAVE_DOT"); + //---- + ci = cfg->addInt( + "MAX_DOT_GRAPH_DEPTH", + "The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the\n" + "graphs generated by dot. A depth value of 3 means that only nodes reachable\n" + "from the root by following a path via at most 3 edges will be shown. Nodes\n" + "that lay further from the root node will be omitted. Note that setting this\n" + "option to 1 or 2 may greatly reduce the computation time needed for large\n" + "code bases. Also note that the size of a graph can be further restricted by\n" + "DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.", + 0,1000,0 + ); + ci->addDependency("HAVE_DOT"); + //---- + cb = cfg->addBool( + "DOT_TRANSPARENT", + "Set the DOT_TRANSPARENT tag to YES to generate images with a transparent\n" + "background. This is disabled by default, because dot on Windows does not\n" + "seem to support this out of the box. Warning: Depending on the platform used,\n" + "enabling this option may lead to badly anti-aliased labels on the edges of\n" + "a graph (i.e. they become hard to read).", + FALSE + ); + cb->addDependency("HAVE_DOT"); + //---- + cb = cfg->addBool( + "DOT_MULTI_TARGETS", + "Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output\n" + "files in one run (i.e. multiple -o and -T options on the command line). This\n" + "makes dot run faster, but since only newer versions of dot (>1.8.10)\n" + "support this, this feature is disabled by default.", + FALSE + ); + cb->addDependency("HAVE_DOT"); + //---- + cb = cfg->addBool( + "GENERATE_LEGEND", + "If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will\n" + "generate a legend page explaining the meaning of the various boxes and\n" + "arrows in the dot generated graphs.", + TRUE + ); + cb->addDependency("HAVE_DOT"); + //---- + cb = cfg->addBool( + "DOT_CLEANUP", + "If the DOT_CLEANUP tag is set to YES (the default) Doxygen will\n" + "remove the intermediate dot files that are used to generate\n" + "the various graphs.", + TRUE + ); + cb->addDependency("HAVE_DOT"); + //---- + cfg->addObsolete("USE_WINDOWS_ENCODING"); + //---- + cfg->addObsolete("DETAILS_AT_TOP"); + //---- + cfg->addObsolete("QTHELP_FILE"); + //---- + cfg->addObsolete("QTHELP_CONFIG"); + //---- + cfg->addObsolete("DOXYGEN2QTHELP_LOC"); + //---- + cfg->addObsolete("MAX_DOT_GRAPH_WIDTH"); + //---- + cfg->addObsolete("MAX_DOT_GRAPH_HEIGHT"); + //---- + cfg->addObsolete("CGI_NAME"); + //---- + cfg->addObsolete("CGI_URL"); + //---- + cfg->addObsolete("DOC_URL"); + //---- + cfg->addObsolete("DOC_ABSPATH"); + //---- + cfg->addObsolete("BIN_ABSPATH"); + //---- + cfg->addObsolete("EXT_DOC_PATHS"); +} diff --git a/trunk/src/configoptions.h b/trunk/src/configoptions.h new file mode 100644 index 0000000..8bf94d5 --- /dev/null +++ b/trunk/src/configoptions.h @@ -0,0 +1,26 @@ +/****************************************************************************** + * + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#ifndef CONFIGOPTIONS +#define CONFIGOPTIONS + +class Config; + +void addConfigOptions(Config *cfg); + +#endif diff --git a/trunk/src/constexp.h b/trunk/src/constexp.h new file mode 100644 index 0000000..8fedc34 --- /dev/null +++ b/trunk/src/constexp.h @@ -0,0 +1,33 @@ +/****************************************************************************** + * + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#ifndef _CONSTEXP_H +#define _CONSTEXP_H + +#include "qtbc.h" +#include "cppvalue.h" + +extern bool parseCppExpression(const char *fileName,int line,const QCString &s); +extern int cppExpYYparse(); +extern int cppExpYYdebug; +extern QCString g_strToken; +extern CPPValue g_resultValue; +extern QCString g_constExpFileName; +extern int g_constExpLineNr; + +#endif diff --git a/trunk/src/constexp.l b/trunk/src/constexp.l new file mode 100644 index 0000000..fae99cf --- /dev/null +++ b/trunk/src/constexp.l @@ -0,0 +1,120 @@ +/****************************************************************************** + * + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +%{ + +#include "constexp.h" +#include "cppvalue.h" +#include "ce_parse.h" // generated header file + +#define YY_NEVER_INTERACTIVE 1 + +QCString g_strToken; +CPPValue g_resultValue; +int g_constExpLineNr; +QCString g_constExpFileName; + +static const char *g_inputString; +static int g_inputPosition; + +#undef YY_INPUT +#define YY_INPUT(buf,result,max_size) result=yyread(buf,max_size); + +static int yyread(char *buf,int max_size) +{ + int c=0; + while( c < max_size && g_inputString[g_inputPosition] ) + { + *buf = g_inputString[g_inputPosition++] ; + c++; buf++; + } + return c; +} + +%} + +CONSTSUFFIX ([uU][lL]?[lL]?)|([lL][lL]?[uU]?) + +%option nounput + +%% + +"?" { return TOK_QUESTIONMARK; } +":" { return TOK_COLON; } +"||" { return TOK_OR; } +"&&" { return TOK_AND; } +"|" { return TOK_BITWISEOR; } +"^" { return TOK_BITWISEXOR; } +"&" { return TOK_AMPERSAND; } +"!=" { return TOK_NOTEQUAL; } +"==" { return TOK_EQUAL; } +"<" { return TOK_LESSTHAN; } +">" { return TOK_GREATERTHAN; } +"<=" { return TOK_LESSTHANOREQUALTO; } +">=" { return TOK_GREATERTHANOREQUALTO; } +"<<" { return TOK_SHIFTLEFT; } +">>" { return TOK_SHIFTRIGHT; } +"+" { return TOK_PLUS; } +"-" { return TOK_MINUS; } +"*" { return TOK_STAR; } +"/" { return TOK_DIVIDE; } +"%" { return TOK_MOD; } +"~" { return TOK_TILDE; } +"!" { return TOK_NOT; } +"(" { return TOK_LPAREN; } +")" { return TOK_RPAREN; } +"'"(([^\'\n\r\\]+)|(\\(([ntvbrfa\\?'\"])|([0-9]+)|([xX][0-9a-fA-F]+))))"'" { + g_strToken=yytext; + return TOK_CHARACTER; + } +0[0-7]*{CONSTSUFFIX}? { g_strToken=yytext; + return TOK_OCTALINT; + } +[1-9][0-9]*{CONSTSUFFIX}? { g_strToken=yytext; + return TOK_DECIMALINT; + } +(0x|0X)[0-9a-fA-F]+{CONSTSUFFIX}? { g_strToken=yytext+2; + return TOK_HEXADECIMALINT; + } +(([0-9]+\.[0-9]*)|([0-9]*\.[0-9]+))([eE]([\-\+])?[0-9]+)?([fFlL])? { + g_strToken=yytext; return TOK_FLOAT; + } +([0-9]+[eE])([\-\+])?[0-9]+([fFlL])? { + g_strToken=yytext; return TOK_FLOAT; + } +. +\n + +%% + +bool parseCppExpression(const char *fileName,int lineNr,const QCString &s) +{ + //printf("Expression: `%s'\n",s.data()); + g_constExpFileName = fileName; + g_constExpLineNr = lineNr; + g_inputString = s; + g_inputPosition = 0; + cppExpYYrestart( cppExpYYin ); + cppExpYYparse(); + //printf("Result: %ld\n",(long)g_resultValue); + return (long)g_resultValue!=0; +} + +extern "C" { + int cppExpYYwrap() { return 1; } +} diff --git a/trunk/src/constexp.y b/trunk/src/constexp.y new file mode 100644 index 0000000..c8b35e5 --- /dev/null +++ b/trunk/src/constexp.y @@ -0,0 +1,278 @@ +/****************************************************************************** + * + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +%{ + +#include "cppvalue.h" +#include "constexp.h" +#include "message.h" + +#if defined(_MSC_VER) +#define MSDOS +#endif + +#define YYSTYPE CPPValue + +#include <stdio.h> +#include <stdlib.h> + +int cppExpYYerror(const char *s) +{ + warn(g_constExpFileName,g_constExpLineNr, + "warning: preprocessing issue while doing constant expression evaluation: %s",s); + return 0; +} + +int cppExpYYlex(); + +%} + +%token TOK_QUESTIONMARK +%token TOK_COLON +%token TOK_OR +%token TOK_AND +%token TOK_BITWISEOR +%token TOK_BITWISEXOR +%token TOK_AMPERSAND +%token TOK_NOTEQUAL +%token TOK_EQUAL +%token TOK_LESSTHAN +%token TOK_GREATERTHAN +%token TOK_LESSTHANOREQUALTO +%token TOK_GREATERTHANOREQUALTO +%token TOK_SHIFTLEFT +%token TOK_SHIFTRIGHT +%token TOK_PLUS +%token TOK_MINUS +%token TOK_STAR +%token TOK_DIVIDE +%token TOK_MOD +%token TOK_TILDE +%token TOK_NOT +%token TOK_LPAREN +%token TOK_RPAREN +%token TOK_OCTALINT +%token TOK_DECIMALINT +%token TOK_HEXADECIMALINT +%token TOK_CHARACTER +%token TOK_FLOAT + +%% + +start: constant_expression + { g_resultValue = $1; return 0; } +; + +constant_expression: logical_or_expression + { $$ = $1; } + | logical_or_expression + TOK_QUESTIONMARK logical_or_expression + TOK_COLON logical_or_expression + { + bool c = ($1.isInt() ? ((long)$1 != 0) : ((double)$1 != 0.0)); + $$ = c ? $3 : $5; + } +; + +logical_or_expression: logical_and_expression + { $$ = $1; } + | logical_or_expression TOK_OR logical_and_expression + { + $$ = CPPValue( (long)((long)$1 || (long)$3) ); + } +; + +logical_and_expression: inclusive_or_expression + { $$ = $1; } + | logical_and_expression TOK_AND inclusive_or_expression + { + $$ = CPPValue( (long)((long)$1 && (long)$3) ); + } +; + +inclusive_or_expression: exclusive_or_expression + { $$ = $1; } + | inclusive_or_expression TOK_BITWISEOR + exclusive_or_expression + { + $$ = CPPValue( (long)$1 | (long)$3 ); + } +; + +exclusive_or_expression: and_expression + { $$ = $1; } + | exclusive_or_expression TOK_BITWISEXOR and_expression + { + $$ = CPPValue( (long)$1 ^ (long)$3 ); + } +; + +and_expression: equality_expression + { $$ = $1; } + | and_expression TOK_AMPERSAND equality_expression + { + $$ = CPPValue( (long)$1 & (long)$3 ); + } +; + +equality_expression: relational_expression + { $$ = $1; } + | equality_expression TOK_EQUAL relational_expression + { + $$ = CPPValue( (long)((double)$1 == (double)$3) ); + } + | equality_expression TOK_NOTEQUAL relational_expression + { + $$ = CPPValue( (long)((double)$1 != (double)$3) ); + } +; + +relational_expression: shift_expression + { $$ = $1; } + | relational_expression TOK_LESSTHAN shift_expression + { + $$ = CPPValue( (long)((double)$1 < (double)$3) ); + } + | relational_expression TOK_GREATERTHAN shift_expression + { + $$ = CPPValue( (long)((double)$1 > (double)$3) ); + } + | relational_expression TOK_LESSTHANOREQUALTO + shift_expression + { + $$ = CPPValue( (long)((double)$1 <= (double)$3) ); + } + | relational_expression TOK_GREATERTHANOREQUALTO + shift_expression + { + $$ = CPPValue( (long)((double)$1 >= (double)$3) ); + } +; + +shift_expression: additive_expression + { $$ = $1; } + | shift_expression TOK_SHIFTLEFT additive_expression + { + $$ = CPPValue( (long)$1 << (long)$3 ); + } + | shift_expression TOK_SHIFTRIGHT additive_expression + { + $$ = CPPValue( (long)$1 >> (long)$3 ); + } +; + +additive_expression: multiplicative_expression + { $$ = $1; } + | additive_expression TOK_PLUS multiplicative_expression + { + if (!$1.isInt() || !$3.isInt()) + { + $$ = CPPValue( (double)$1 + (double)$3 ); + } + else + { + $$ = CPPValue( (long)$1 + (long)$3 ); + } + } + | additive_expression TOK_MINUS multiplicative_expression + { + if (!$1.isInt() || !$3.isInt()) + { + $$ = CPPValue( (double)$1 - (double)$3 ); + } + else + { + $$ = CPPValue( (long)$1 - (long)$3 ); + } + } +; + +multiplicative_expression: unary_expression + { $$ = $1; } + | multiplicative_expression TOK_STAR unary_expression + { + if (!$1.isInt() || !$3.isInt()) + { + $$ = CPPValue( (double)$1 * (double)$3 ); + } + else + { + $$ = CPPValue( (long)$1 * (long)$3 ); + } + } + | multiplicative_expression TOK_DIVIDE unary_expression + { + if (!$1.isInt() || !$3.isInt()) + { + $$ = CPPValue( (double)$1 / (double)$3 ); + } + else + { + long value = $3; + if (value==0) value=1; + $$ = CPPValue( (long)$1 / value ); + } + } + | multiplicative_expression TOK_MOD unary_expression + { + long value = $3; + if (value==0) value=1; + $$ = CPPValue( (long)$1 % value ); + } +; + +unary_expression: primary_expression + { $$ = $1; } + | TOK_PLUS unary_expression + { $$ = $1; } + | TOK_MINUS unary_expression + { + if ($2.isInt()) + $$ = CPPValue(-(long)$2); + else + $$ = CPPValue(-(double)$2); + } + | TOK_TILDE unary_expression + { + $$ = CPPValue(~(long)$2); + } + | TOK_NOT unary_expression + { + $$ = CPPValue((long)!(long)$2); + } +; + +primary_expression: constant + { $$ = $1; } + | TOK_LPAREN constant_expression TOK_RPAREN + { $$ = $2; } +; + +constant: TOK_OCTALINT + { $$ = parseOctal(); } + | TOK_DECIMALINT + { $$ = parseDecimal(); } + | TOK_HEXADECIMALINT + { $$ = parseHexadecimal(); } + | TOK_CHARACTER + { $$ = parseCharacter(); } + | TOK_FLOAT + { $$ = parseFloat(); } +; + +%% diff --git a/trunk/src/cppvalue.cpp b/trunk/src/cppvalue.cpp new file mode 100644 index 0000000..69b8be4 --- /dev/null +++ b/trunk/src/cppvalue.cpp @@ -0,0 +1,95 @@ +/****************************************************************************** + * + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#include <stdlib.h> + +#include "cppvalue.h" +#include "constexp.h" + +CPPValue parseOctal() +{ + long val = 0; + for (const char *p = g_strToken.data(); *p != 0; p++) + { + if (*p >= '0' && *p <= '7') val = val * 8 + *p - '0'; + } + return CPPValue(val); +} + +CPPValue parseDecimal() +{ + long val = 0; + for (const char *p = g_strToken.data(); *p != 0; p++) + { + if (*p >= '0' && *p <= '9') val = val * 10 + *p - '0'; + } + return CPPValue(val); +} + +CPPValue parseHexadecimal() +{ + long val = 0; + 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; + else if (*p >= 'A' && *p <= 'F') val = val * 16 + *p - 'A' + 10; + } + //printf("parseHexadecimal %s->%x\n",g_strToken.data(),val); + return CPPValue(val); +} + +CPPValue parseCharacter() // does not work for '\n' and the alike +{ + if (g_strToken[1]=='\\') + { + switch(g_strToken[2]) + { + case 'n': return CPPValue((long)'\n'); + case 't': return CPPValue((long)'\t'); + case 'v': return CPPValue((long)'\v'); + case 'b': return CPPValue((long)'\b'); + case 'r': return CPPValue((long)'\r'); + case 'f': return CPPValue((long)'\f'); + case 'a': return CPPValue((long)'\a'); + case '\\': return CPPValue((long)'\\'); + case '?': return CPPValue((long)'\?'); + case '\'': return CPPValue((long)'\''); + case '"': return CPPValue((long)'"'); + case '0': // fall through + case '1': // fall through + case '2': // fall through + case '3': // fall through + case '4': // fall through + case '5': // fall through + case '6': // fall through + case '7': // fall through + return parseOctal(); + case 'x': + case 'X': return parseHexadecimal(); + default: printf("Invalid escape sequence %s found!\n",g_strToken.data()); + return CPPValue(0L); + } + } + return CPPValue((long)g_strToken[1]); +} + +CPPValue parseFloat() +{ + return CPPValue(atof(g_strToken)); +} diff --git a/trunk/src/cppvalue.h b/trunk/src/cppvalue.h new file mode 100644 index 0000000..d3e2a1d --- /dev/null +++ b/trunk/src/cppvalue.h @@ -0,0 +1,62 @@ +/****************************************************************************** + * + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#ifndef _CPPVALUE_H +#define _CPPVALUE_H + +#include <stdio.h> +#include <qglobal.h> + +class CPPValue +{ + public: + + + enum Type { Int, Float }; + + CPPValue(long val=0) : type(Int) { v.l = val; } + CPPValue(double val) : type(Float) { v.d = val; } + + operator double () const { return type==Int ? (double)v.l : v.d; } + operator long () const { return type==Int ? v.l : (long)v.d; } + + bool isInt() const { return type == Int; } + + void print() const + { + if (type==Int) + printf("(%ld)\n",v.l); + else + printf("(%f)\n",v.d); + } + + private: + Type type; + union { + double d; + long l; + } v; +}; + +extern CPPValue parseOctal(); +extern CPPValue parseDecimal(); +extern CPPValue parseHexadecimal(); +extern CPPValue parseCharacter(); +extern CPPValue parseFloat(); + +#endif diff --git a/trunk/src/dbusxmlscanner.cpp b/trunk/src/dbusxmlscanner.cpp new file mode 100644 index 0000000..51b0a59 --- /dev/null +++ b/trunk/src/dbusxmlscanner.cpp @@ -0,0 +1,875 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 2009 by Tobias Hunger <tobias@aquazul.com> + * + * 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. + * + */ + +#include "dbusxmlscanner.h" + +#include "commentscan.h" +#include "entry.h" + +#include <qfile.h> +#include <qxml.h> +#include <qstring.h> + +#include "message.h" +#include "util.h" +#include "arguments.h" + +// ----------------------------------------------------------------------- +// Convenience defines: +// ----------------------------------------------------------------------- + +#define CONDITION(cond, msg) \ + do {\ + if (cond)\ + {\ + if (m_errorString.isEmpty()) { m_errorString = msg; }\ + return false;\ + }\ + }\ + while (0) + +#define DOC_ERROR(msg) \ + warn_doc_error(m_fileName.utf8().data(), lineNumber(), msg.utf8().data()) + +#define COND_DOC_ERROR(cond, msg) \ + do {\ + if (cond)\ + {\ + DOC_ERROR(msg);\ + return true;\ + }\ + }\ + while (0) + +#define DBUS(name) isDBusElement(namespaceURI, localName, qName, name) +#define EXTENSION(name) isExtensionElement(namespaceURI, localName, qName, name) + +// ----------------------------------------------------------------------- +// DBusXMLHandler class +// ----------------------------------------------------------------------- + +const QString EXTENSION_URI("http://psiamp.org/dtd/doxygen_dbusxml.dtd"); + +class DBusXMLHandler : public QXmlDefaultHandler +{ +public: + DBusXMLHandler(ParserInterface * parser, + QXmlSimpleReader * reader, + const char * file_name, + Entry * root) : + m_parser(parser), + m_locator(reader), + m_currentEntry(0), + m_currentInterface(0), + m_currentMethod(0), + m_currentArgument(0), + m_currentProperty(0), + m_currentEnum(0), + m_fileName(file_name), + m_currentComment(0) + { + setDocumentLocator(&m_locator); + + m_scopeCount = 0; + + // Set up stack cleanup: + m_structStack.setAutoDelete(TRUE); + m_elementStack.setAutoDelete(TRUE); + m_scopeStack.setAutoDelete(TRUE); + + openScopes(root); + } + + ~DBusXMLHandler() + { closeScopes(); } + + QString errorString() + { return m_errorString; } + + bool startElement(const QString &namespaceURI, + const QString &localName, + const QString &qName, + const QXmlAttributes &attributes) + { + // add to elements stack: + m_elementStack.append(new ElementData(qName)); + + // First we need a node. + if (DBUS("node")) + { + CONDITION(!m_currentNode.isEmpty(), "Node inside a node."); + + const int idx(indexOf(attributes, "name")); + COND_DOC_ERROR(idx < 0, QString("Anonymous node found.")); + + m_currentNode = attributes.value(idx); + // A node is actually of little interest, so do nothing here. + return true; + } + + // Then we need an interface. + if (DBUS("interface")) + { + // We need a nodeName for interfaces: + CONDITION(m_currentNode.isEmpty(), "Interface without a node."); + CONDITION(m_currentInterface, "Interface within another interface."); + + const int idx(indexOf(attributes, "name")); + COND_DOC_ERROR(idx < 0, QString("Interface without a name found.")); + + // A interface is roughly equivalent to a class: + m_currentInterface = createEntry(); + + m_currentInterface->section = Entry::CLASS_SEC; + m_currentInterface->spec |= Entry::Interface; + m_currentInterface->type = "Interface"; + m_currentInterface->name = substitute(attributes.value(idx), ".", "::"); + + openScopes(m_currentInterface); + + return true; + } + + if (DBUS("method") || DBUS("signal")) + { + // We need a interfaceName for methods and signals: + CONDITION(!m_currentInterface, "Method or signal found outside a interface."); + CONDITION(m_currentMethod, "Method or signal found inside another method or signal."); + CONDITION(m_currentProperty, "Methor or signal found inside a property."); + CONDITION(!m_structStack.isEmpty(), "Method or signal found inside a struct."); + CONDITION(m_currentEnum, "Methor or signal found inside a enum."); + + const int idx(indexOf(attributes, "name")); + COND_DOC_ERROR(idx < 0, QString("Method or signal without a name found.")); + + m_currentMethod = createEntry(); + + m_currentMethod->section = Entry::FUNCTION_SEC; + m_currentMethod->name = attributes.value(idx); + m_currentMethod->mtype = Method; + m_currentMethod->type = "void"; + + if (DBUS("signal")) + { m_currentMethod->mtype = Signal; } + } + + if (DBUS("arg")) + { + // We need a method for arguments: + CONDITION(!m_currentMethod, "Argument found outside a method or signal."); + CONDITION(m_currentArgument, "Argument found inside another argument."); + + const int name_idx(indexOf(attributes, "name")); + COND_DOC_ERROR(name_idx < 0, QString("Argument without a name found.")); + COND_DOC_ERROR(!hasType(attributes), QString("Argument without a type found.")); + + const int direction_idx(indexOf(attributes, "direction")); + + if ((m_currentMethod->mtype == Signal && + direction_idx >= 0 && + attributes.value(direction_idx) != "in") || + (m_currentMethod->mtype == Method && + direction_idx >= 0 && + attributes.value(direction_idx) != "in" && + attributes.value(direction_idx) != "out")) + { + m_errorString = "Invalid direction found."; + return false; + } + + m_currentArgument = new Argument; + m_currentArgument->type = getType(attributes); + m_currentArgument->name = attributes.value(name_idx); + if (direction_idx >= 0) + { m_currentArgument->attrib = attributes.value(direction_idx); } + else + { + if (m_currentMethod->mtype == Signal) + { m_currentArgument->attrib = "in"; } + else + { m_currentArgument->attrib = "out"; } + } + } + + if (DBUS("property")) + { + CONDITION(m_currentMethod, "Property found inside a method or signal."); + CONDITION(!m_currentInterface, "Property found outside an interface."); + CONDITION(m_currentProperty, "Property found inside another property."); + CONDITION(!m_structStack.isEmpty(), "Property found inside a struct."); + CONDITION(m_currentEnum, "Property found inside a enum."); + + const int name_idx(indexOf(attributes, "name")); + COND_DOC_ERROR(name_idx < 0, QString("Anonymous property found.")); + COND_DOC_ERROR(!hasType(attributes), QString("Property without a type found.")); + + const int access_idx(indexOf(attributes, "access")); + COND_DOC_ERROR(access_idx < 0, QString("Property without a access attribute found.")); + COND_DOC_ERROR(attributes.value(access_idx) != "read" && + attributes.value(access_idx) != "write" && + attributes.value(access_idx) != "readwrite", + QString("Property with invalid access attribute \"%1\" found."). + arg(attributes.value(access_idx))); + + m_currentProperty = createEntry(); + + m_currentProperty->section = Entry::FUNCTION_SEC; + + if (attributes.value(access_idx) == "read" || + attributes.value(access_idx) == "readwrite") + { m_currentProperty->spec |= Entry::Readable; } + + if (attributes.value(access_idx) == "write" || + attributes.value(access_idx) == "readwrite") + { m_currentProperty->spec |= Entry::Writable; } + + m_currentProperty->name = attributes.value(name_idx); + m_currentProperty->mtype = Property; + m_currentProperty->type = getType(attributes); + } + + if (EXTENSION("namespace")) + { + CONDITION(m_currentNode.isEmpty(), "Namespace found outside a node."); + CONDITION(m_currentInterface, "Namespace found inside an interface."); + + const int idx(indexOf(attributes, "name")); + COND_DOC_ERROR(idx < 0, QString("Anonymous namespace found.")); + + m_namespaceStack.append(openNamespace(attributes.value(idx))); + openScopes(m_namespaceStack.last()); + } + + if (EXTENSION("struct")) + { + CONDITION(m_currentMethod, "Struct found inside a method or signal."); + CONDITION(m_currentProperty, "Struct found inside a property."); + CONDITION(m_currentEnum, "Struct found inside an enum."); + + const int idx(indexOf(attributes, "name")); + COND_DOC_ERROR(idx < 0, QString("Anonymous struct found.")); + + Entry * current_struct = createEntry(); + current_struct->section = Entry::CLASS_SEC; + current_struct->spec = Entry::Struct; + current_struct->name = attributes.value(idx); + + openScopes(current_struct); + + current_struct->type = current_struct->name + " struct"; + + m_structStack.append(new StructData(current_struct)); + } + + if (EXTENSION("member")) + { + CONDITION(m_structStack.isEmpty(), "Member found outside of struct."); + + const int name_idx(indexOf(attributes, "name")); + COND_DOC_ERROR(name_idx < 0, QString("Anonymous member found.")); + COND_DOC_ERROR(!hasType(attributes), QString("Member without a type found.")); + + createEntry(); + + m_currentEntry->section = Entry::VARIABLE_SEC; + m_currentEntry->name = attributes.value(name_idx); + m_currentEntry->type = getType(attributes); + + QString type(getDBusType(m_currentEntry->type)); + m_structStack.last()->type.append(type); + } + + if (EXTENSION("enum") || EXTENSION("flagset")) + { + CONDITION(m_currentMethod, "Enum found inside a method or signal."); + CONDITION(m_currentProperty, "Enum found inside a property."); + + const int name_idx(indexOf(attributes, "name")); + COND_DOC_ERROR(name_idx < 0, QString("Anonymous enum found.")); + + const int type_idx(indexOf(attributes, "type")); + QString type = "u"; + if (type_idx >= 0) + { type = attributes.value(type_idx); } + if (type != "y" && type != "q" && type != "u" && type != "t") + { DOC_ERROR(QString("Invalid enum type \"%1\" found.").arg(type)); } + + m_currentEnum = createEntry(); + m_currentEnum->section = Entry::ENUM_SEC; + m_currentEnum->name = attributes.value(name_idx); + + openScopes(m_currentEnum); + + m_currentEnum->type = m_currentEntry->name + " enum"; + + addNamedType(type); + } + + if (EXTENSION("value")) + { + CONDITION(!m_currentEnum, "Value found outside an enum."); + + const int name_idx(indexOf(attributes, "name")); + COND_DOC_ERROR(name_idx < 0, QString("Anonymous value found.")); + + const int value_idx(indexOf(attributes, "value")); + + createEntry(); + + m_currentEntry->section = Entry::VARIABLE_SEC; + m_currentEntry->name = attributes.value(name_idx); + m_currentEntry->type = m_currentEnum->name; // "@"; // enum marker! + if (value_idx >= 0) + { m_currentEntry->initializer = attributes.value(value_idx); } + } + + return true; + } + + bool endElement(const QString &namespaceURI, + const QString &localName, + const QString &qName) + { + // Clean up elements stack: + // Since we made sure to get the elements in the proper order when + // adding we do not need to do so again here. + COND_DOC_ERROR(m_elementStack.last()->element != qName, + QString("Malformed XML: Unexpected closing element found."). + arg(m_elementStack.last()->element)); + m_elementStack.removeLast(); + + // Interface: + if (DBUS("interface")) + { + CONDITION(!m_currentInterface, "end of interface found without start."); + m_currentInterface->endBodyLine = lineNumber(); + closeScopes(); + m_currentInterface = 0; + } + + if (DBUS("method") || DBUS("signal")) + { + CONDITION(!m_currentMethod, "end of method found without start."); + CONDITION(!m_currentInterface, "end of method found outside interface."); + m_currentMethod->endBodyLine = lineNumber(); + m_currentInterface->addSubEntry(m_currentMethod); + m_currentMethod = 0; + } + + if (DBUS("property")) + { + CONDITION(!m_currentProperty, "end of property found without start."); + CONDITION(!m_currentInterface, "end of property found outside interface."); + m_currentProperty->endBodyLine = lineNumber(); + m_currentInterface->addSubEntry(m_currentProperty); + m_currentProperty = 0; + } + + if (DBUS("arg")) + { + CONDITION(!m_currentMethod, "end of arg found outside method."); + m_currentMethod->argList->append(m_currentArgument); + m_currentArgument = 0; + } + + if (EXTENSION("namespace")) + { + Entry * current = m_namespaceStack.last(); + CONDITION(!current, "end of namespace without start."); + m_namespaceStack.removeLast(); + + current->endBodyLine = lineNumber(); + closeScopes(); + } + + if (EXTENSION("struct")) + { + StructData * data = m_structStack.last(); + CONDITION(!data, "end of struct without start."); + + data->entry->endBodyLine = lineNumber(); + + QString current_type; + current_type.append(QString("(")); + current_type.append(data->type); + current_type.append(QString(")")); + + addNamedType(current_type); + + closeScopes(); + + m_structStack.removeLast(); + } + + if (EXTENSION("member")) + { + StructData * data = m_structStack.last(); + CONDITION(!data, "end of member outside struct."); + data->entry->addSubEntry(m_currentEntry); + } + + if (EXTENSION("enum") || EXTENSION("flagset")) + { + CONDITION(!m_currentEnum, "end of enum without start."); + m_currentEnum->endBodyLine = lineNumber(); + closeScopes(); + + m_currentEnum = 0; + } + + if (EXTENSION("value")) + { + CONDITION(!m_currentEntry, "end of value without start"); + m_currentEntry->endBodyLine = lineNumber(); + + m_currentEnum->addSubEntry(m_currentEntry); + } + + return true; + } + + bool characters(const QString & /*chars*/) + { return true; } + + bool comment(const QString & comment_) + { + if (m_currentComment) + { handleComment(); } + + m_currentComment = new CommentData(m_fileName, lineNumber(), comment_); + + if (m_currentComment->shouldIgnore) + { + delete m_currentComment; + m_currentComment = 0; + return true; + } + + if (m_currentComment->associateWithPrevious) + { handleComment(); } + + return true; + } + + void handleComment() + { + if (m_currentComment == 0 || m_currentEntry == 0) + { return; } + + QCString text(m_currentComment->text); + + m_currentEntry->docFile = m_currentComment->fileName; + m_currentEntry->docLine = m_currentComment->line; + + int position(0); + bool needs_entry(false); + bool brief(false); + Protection prot(Public); + int lineNr = lineNumber(); + + while (parseCommentBlock(m_parser, + m_currentEntry, + text, m_fileName.utf8().data(), + lineNr, + brief, m_currentComment->isJavaStyle, + false, + prot, + position, + needs_entry)) + { + if (needs_entry) { createEntry(); } + } + if (needs_entry) { createEntry(); } + + delete m_currentComment; + m_currentComment = 0; + } + + QXmlLocator * locator() + { return &m_locator; } + + int lineNumber() + { return m_locator.lineNumber(); } + + void setSection() + { + Entry * current = createEntry(); + current->reset(); + + current->name = m_fileName.utf8(); + current->section = Entry::SOURCE_SEC; + + // Open/Close the scope to do the bookkeeping: + openScopes(current); + closeScopes(); + } + +private: + bool isDBusElement(const QString & namespaceURI, + const QString & localName, + const QString & qName, + const QString & element) + { + return (namespaceURI.isEmpty() && localName == element && qName == element) || + (namespaceURI.isEmpty() && localName.isEmpty() && qName == element); + } + + bool isExtensionElement(const QString & namespaceURI, + const QString & localName, + const QString & qName, + const QString & element) + { + (void)qName; + + return namespaceURI == EXTENSION_URI && localName == element; + } + + bool hasType(const QXmlAttributes & attributes) + { + const int type_idx(indexOf(attributes, "type")); + const int named_type_idx(indexOf(attributes, "named-type")); + + return named_type_idx >= 0 || type_idx >= 0; + } + + QString getType(const QXmlAttributes & attributes) + { + const int type_idx(indexOf(attributes, "type")); + const int named_type_idx(indexOf(attributes, "named-type")); + + QString type; + + if (named_type_idx >= 0) + { + type = attributes.value(named_type_idx); + if (!type.startsWith("::")) + { type = getCurrentScope(attributes.value(named_type_idx)); } + else + { type = type.mid(2); } + if (m_namedTypeMap.contains(type)) + { + if (type_idx >= 0) + { + const QString dbus_type(attributes.value(type_idx)); + if (dbus_type != m_namedTypeMap[type]) + { + DOC_ERROR(QString("Type \"%1\" does not match up with " + "previous definition of named type \"%2\" (which was \"%3\"."). + arg(dbus_type). + arg(type). + arg(m_namedTypeMap[type])); + } + } + return type; + } + + DOC_ERROR(QString("Undefined named type \"%1\" used.").arg(type)); + } + + if (type_idx >= 0) + { + type = attributes.value(type_idx); + + QRegExp reg_exp(QCString("(a?[ybnqiuxdtsogv]|a[{]sv[}])")); + if (reg_exp.match(type.data())) + { return type; } + + DOC_ERROR(QString("Unnamed complex D-Bus type \"%1\" found.").arg(type)); + } + + return QString(); + } + + QString getDBusType(const QString & type) + { + QString scoped_type = type; + if (!scoped_type.contains("::")) + { scoped_type = getCurrentScope(type); } + + if (m_namedTypeMap.contains(scoped_type)) + { return m_namedTypeMap[scoped_type]; } + else + { return type; } + } + + void addNamedType(const QString type) + { + QString scoped_name(getCurrentScope()); + + if (m_namedTypeMap.contains(scoped_name)) + { + DOC_ERROR(QString("Named type \"%1\" is already defined.").arg(scoped_name)); + return; + } + + m_namedTypeMap.insert(scoped_name, type); + } + + QString getCurrentScope(const QString & type = QString()) + { + QString scoped_name; + if (!m_scopeStack.isEmpty()) + { + scoped_name = m_scopeStack.last()->scope->name; + scoped_name.append("::"); + } + if (!type.isEmpty()) + { scoped_name.append(type); } + else + { scoped_name = scoped_name.left(scoped_name.length() - 2); } + + return scoped_name; + } + + int indexOf(const QXmlAttributes & attributes, const QString & name, + const QString & type = "CDATA", const bool mandatory = true) + { + const int idx(attributes.index(name)); + if (idx < 0 || idx > attributes.length()) { return -1; } + if (attributes.type(idx) != type) { return -1; } + if (mandatory && attributes.value(idx).isEmpty()) { return -1; } + + return idx; + } + + Entry * createEntry() + { + Entry * entry = new Entry(); + + entry->protection = Public ; + entry->virt = Normal; + entry->stat = false; + entry->lang = SrcLangExt_XML; + entry->spec = 0; + + entry->fileName = m_fileName; + entry->startLine = lineNumber(); + entry->bodyLine = lineNumber(); + + entry->callGraph = false; + entry->callerGraph = false; + + initGroupInfo(entry); + + m_currentEntry = entry; + + handleComment(); + + return entry; + } + + void openScopes(Entry * object) + { + int cur_scope_separator_pos = 0; + int last_scope_separator_pos = 0; + while (0 <= (cur_scope_separator_pos = object->name.find("::", last_scope_separator_pos))) + { + QString scope = object->name.mid(last_scope_separator_pos, + cur_scope_separator_pos - last_scope_separator_pos); + last_scope_separator_pos = cur_scope_separator_pos + 2; + + Entry * current_namespace = openNamespace(scope); + + if (!m_scopeStack.isEmpty()) + { m_scopeStack.last()->scope->addSubEntry(current_namespace); } + + m_scopeStack.append(new ScopeData(current_namespace, m_scopeCount)); + } + + QString scoped_name(getCurrentScope()); + if (!scoped_name.isEmpty()) + { scoped_name.append("::"); } + scoped_name.append(object->name.mid(last_scope_separator_pos)); + + object->name = scoped_name; + + if (!m_scopeStack.isEmpty()) + { m_scopeStack.last()->scope->addSubEntry(object); } + m_scopeStack.append(new ScopeData(object, m_scopeCount)); + + ++m_scopeCount; + } + + Entry * openNamespace(const QString & name) + { + Entry * current_namespace = createEntry(); + QString scoped_name(getCurrentScope()); + if (!scoped_name.isEmpty()) + { scoped_name.append("::"); } + scoped_name.append(name); + current_namespace->name = scoped_name; + current_namespace->section = Entry::NAMESPACE_SEC; + current_namespace->type = "namespace" ; + + return current_namespace; + } + + void closeScopes() + { + const int current_scope_count(m_scopeStack.last()->count); + + // Do not close the root scope. + if (current_scope_count == 0) + { return; } + + while (current_scope_count == m_scopeStack.last()->count) + { m_scopeStack.removeLast(); } + } + + ParserInterface * m_parser; + + QXmlLocator m_locator; + QString m_currentNode; // Nodes can not be nested, no entry necessary. + + struct ElementData + { + ElementData(const QString & e) : + element(e) + { } + ~ElementData() { } + + QString element; //*< The element name + QString text; //*< The actual xml code. + }; + QList<ElementData> m_elementStack; + + Entry * m_currentEntry; // The currently open entry. + + Entry * m_currentInterface; // Interfaces can not be nested. + Entry * m_currentMethod; // Methods can not be nested. + Argument * m_currentArgument; // Arguments can not be nested. + Entry * m_currentProperty; // Properties can not be nested. + Entry * m_currentEnum; // Enums can not be nested. + QList<Entry> m_namespaceStack; + + struct StructData + { + StructData(Entry * e) : entry(e) { } + ~StructData() { } + + QString type; + Entry * entry; + }; + QList<StructData> m_structStack; // Structs can be nested. + + struct ScopeData + { + ScopeData(Entry * s, int c) : + scope(s), + count(c) + { } + ~ScopeData() { } + + Entry * scope; + int count; + }; + QList<ScopeData> m_scopeStack; // Scopes are nested. + + QString m_fileName; + + struct CommentData + { + CommentData(const QString & f, const int l, const QString & t) : + isJavaStyle(false), + isQtStyle(false), + line(l), + fileName(f) + { + isJavaStyle = t.startsWith(QChar('*')); + isQtStyle = t.startsWith(QChar('!')); + shouldIgnore = (!isJavaStyle && !isQtStyle); + associateWithPrevious = (t.at(1) == QChar('<')); + if (associateWithPrevious) + { text = t.mid(2); } + else + { text = t.mid(1); } + } + ~CommentData() { } + + QString text; + bool isJavaStyle; + bool isQtStyle; + bool shouldIgnore; + bool associateWithPrevious; + int line; + QString fileName; + }; + CommentData * m_currentComment; + + int m_scopeCount; //*< unique scope id. + + QString m_errorString; + + QMap<QString, QString> m_namedTypeMap; +}; + +// ----------------------------------------------------------------------- +// DBusXMLScanner +// ----------------------------------------------------------------------- + +DBusXMLScanner::DBusXMLScanner() +{ } + +DBusXMLScanner::~DBusXMLScanner() +{ } + +void DBusXMLScanner::parseInput(const char * fileName, + const char * /* fileBuf */, + Entry * root) +{ + QFile inputFile(fileName); + + QXmlInputSource inputSource(inputFile); + QXmlSimpleReader reader; + + DBusXMLHandler handler(this, &reader, fileName, root); + reader.setContentHandler(&handler); + reader.setErrorHandler(&handler); + reader.setLexicalHandler(&handler); + + groupEnterFile(fileName, 1); + handler.setSection(); + reader.parse(inputSource); + + if (!handler.errorString().isEmpty()) + { err("DBus XML Parser: Error at line %d: %s\n", + handler.locator()->lineNumber(),handler.errorString().utf8().data()); } + + groupLeaveFile(fileName, 1); +} + +bool DBusXMLScanner::needsPreprocessing(const QCString & /* extension */) +{ return (false); } + +void DBusXMLScanner::parseCode(CodeOutputInterface & /* codeOutIntf */, + const char * /* scopeName */, + const QCString & /* input */, + bool /* isExampleBlock */, + const char * /* exampleName */, + FileDef * /* fileDef */, + int /* startLine */, + int /* endLine */, + bool /* inlineFragment */, + MemberDef * /* memberDef */, + bool /*showLineNumbers*/) +{ } + +void DBusXMLScanner::resetCodeParserState() +{ } + +void DBusXMLScanner::parsePrototype(const char * /* text */) +{ } diff --git a/trunk/src/dbusxmlscanner.h b/trunk/src/dbusxmlscanner.h new file mode 100644 index 0000000..fd48cbc --- /dev/null +++ b/trunk/src/dbusxmlscanner.h @@ -0,0 +1,58 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 2009 by Tobias Hunger <tobias@aquazul.com> + * + * 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. + * + */ + +#ifndef SCANNER_DBUSXML_H +#define SCANNER_DBUSXML_H + +#include "parserintf.h" + +/** \brief D-Bus XML parser. + * + * This is the D-Bus XML parser for doxygen. + */ +class DBusXMLScanner : public ParserInterface +{ +public: + DBusXMLScanner(); + virtual ~DBusXMLScanner(); + void parseInput(const char *fileName, + const char *fileBuf, + Entry *root); + + bool needsPreprocessing(const QCString &extension); + + void parseCode(CodeOutputInterface &codeOutIntf, + const char *scopeName, + const QCString &input, + bool isExampleBlock, + const char *exampleName=0, + FileDef *fileDef=0, + int startLine=-1, + int endLine=-1, + bool inlineFragment=FALSE, + MemberDef *memberDef=0, + bool showLineNumbers=TRUE + ); + + void resetCodeParserState(); + + void parsePrototype(const char *text); + +private: +}; + +#endif diff --git a/trunk/src/debug.cpp b/trunk/src/debug.cpp new file mode 100644 index 0000000..1c3c1c1 --- /dev/null +++ b/trunk/src/debug.cpp @@ -0,0 +1,118 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#include <stdarg.h> +#include <stdio.h> + +#include <qdict.h> + +#include "qtbc.h" +#include "debug.h" + +//------------------------------------------------------------------------ + +struct LabelMap +{ + const char *name; + Debug::DebugMask event; +}; + +static LabelMap s_labels[] = +{ + { "findmembers", Debug::FindMembers }, + { "functions", Debug::Functions }, + { "variables", Debug::Variables }, + { "preprocessor", Debug::Preprocessor }, + { "classes", Debug::Classes }, + { "commentcnv", Debug::CommentCnv }, + { "commentscan", Debug::CommentScan }, + { "validate", Debug::Validate }, + { "printtree", Debug::PrintTree }, + { "time", Debug::Time }, + { "extcmd", Debug::ExtCmd }, + { "markdown", Debug::Markdown }, + { "filteroutput", Debug::FilterOutput }, + { 0, (Debug::DebugMask)0 } +}; + +class LabelMapper +{ + public: + LabelMapper() : m_map(17) + { + m_map.setAutoDelete(TRUE); + LabelMap *p = s_labels; + while (p->name) + { + m_map.insert(p->name,new Debug::DebugMask(p->event)); + p++; + } + } + Debug::DebugMask *find(const char *s) const + { + if (s==0) return 0; + return m_map.find(s); + } + private: + QDict<Debug::DebugMask> m_map; +}; + +static LabelMapper g_labelMapper; + +//------------------------------------------------------------------------ + +Debug::DebugMask Debug::curMask = Debug::Quiet; +int Debug::curPrio = 0; + +void Debug::print(DebugMask mask,int prio,const char *fmt,...) +{ + if ((curMask&mask) && prio<=curPrio) + { + va_list args; + va_start(args,fmt); + vfprintf(stdout, fmt, args); + va_end(args); + } +} + +static int labelToEnumValue(const char *l) +{ + QCString label=l; + Debug::DebugMask *event = g_labelMapper.find(label.lower()); + if (event) return *event; else return 0; +} + +void Debug::setFlag(const char *lab) +{ + curMask = (DebugMask)(curMask | labelToEnumValue(lab)); +} + +void Debug::clearFlag(const char *lab) +{ + curMask = (DebugMask)(curMask & ~labelToEnumValue(lab)); +} + +void Debug::setPriority(int p) +{ + curPrio = p; +} + +bool Debug::isFlagSet(DebugMask mask) +{ + return (curMask & mask)!=0; +} + diff --git a/trunk/src/debug.h b/trunk/src/debug.h new file mode 100644 index 0000000..f624628 --- /dev/null +++ b/trunk/src/debug.h @@ -0,0 +1,51 @@ +/****************************************************************************** + * + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#ifndef _DEBUG_H +#define _DEBUG_H + +class Debug +{ + public: + enum DebugMask { Quiet = 0x00000000, + FindMembers = 0x00000001, + Functions = 0x00000002, + Variables = 0x00000004, + Preprocessor = 0x00000008, + Classes = 0x00000010, + CommentCnv = 0x00000020, + CommentScan = 0x00000040, + Validate = 0x00000080, + PrintTree = 0x00000100, + Time = 0x00000200, + ExtCmd = 0x00000400, + Markdown = 0x00000800, + FilterOutput = 0x00001000 + }; + static void print(DebugMask mask,int prio,const char *fmt,...); + static void setFlag(const char *label); + static void clearFlag(const char *label); + static bool isFlagSet(DebugMask mask); + static void setPriority(int p); + + private: + static DebugMask curMask; + static int curPrio; +}; + +#endif diff --git a/trunk/src/declinfo.h b/trunk/src/declinfo.h new file mode 100644 index 0000000..a91f5bb --- /dev/null +++ b/trunk/src/declinfo.h @@ -0,0 +1,33 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#ifndef DECLINFO_H +#define DECLINFO_H + +#include "qtbc.h" +#include <stdio.h> + +extern void parseFuncDecl(const QCString &decl, + bool objC, + QCString &clName, + QCString &type, + QCString &name, + QCString &args, + QCString &funcTempList, + QCString &exceptions + ); +#endif diff --git a/trunk/src/declinfo.l b/trunk/src/declinfo.l new file mode 100644 index 0000000..746aaae --- /dev/null +++ b/trunk/src/declinfo.l @@ -0,0 +1,357 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +%{ + +/* + * includes + */ +#include <stdio.h> +//#include <iostream.h> +#include <assert.h> +#include <ctype.h> + +#include "declinfo.h" +#include "util.h" +#include "message.h" + +/* ----------------------------------------------------------------- + * + * statics + */ + +static const char * inputString; +static int inputPosition; +static QCString scope; +static QCString className; +static QCString classTempList; +static QCString funcTempList; +static QCString type; +static QCString name; +static QCString args; +static QCString tmpType; +static int sharpCount; +static bool classTempListFound; +static bool funcTempListFound; +static QCString exceptionString; +static bool insideObjC; + +static void addType() +{ + //printf("addType() type=`%s' scope=`%s' name=`%s'\n", + // type.data(),scope.data(),name.data()); + if (name.isEmpty() && scope.isEmpty()) return; + if (!type.isEmpty()) type+=" "; + if (!scope.isEmpty()) type+=scope+"::"; + type+=name; + scope.resize(0); + name.resize(0); +} + +static void addTypeName() +{ + //printf("addTypeName() type=`%s' scope=`%s' name=`%s'\n", + // type.data(),scope.data(),name.data()); + if (name.isEmpty() || + name.at(name.length()-1)==':') // end of Objective-C keyword => append to name not type + { + return; + } + if (!type.isEmpty()) type+=' '; + type+=name; + name.resize(0); +} + +#define YY_NEVER_INTERACTIVE 1 + +/* ----------------------------------------------------------------- + */ +#undef YY_INPUT +#define YY_INPUT(buf,result,max_size) result=yyread(buf,max_size); + +static int yyread(char *buf,int max_size) +{ + int c=0; + while( c < max_size && inputString[inputPosition] ) + { + *buf = inputString[inputPosition++] ; + c++; buf++; + } + return c; +} + +%} + +B [ \t] +ID "$"?([a-z_A-Z\x80-\xFF][a-z_A-Z0-9\x80-\xFF]*)|(@[0-9]+) + +%option nounput +%option noyywrap + +%x Start +%x Template +%x ReadArgs +%x Operator +%x FuncPtr +%x EndTemplate +%x StripTempArgs +%x SkipSharp +%x ReadExceptions + +%% + +<Start>"operator"/({B}*"["{B}*"]")* { // operator rule must be before {ID} rule + name += yytext; + BEGIN(Operator); + } +<Start>{ID}{B}*"("{B}*{ID}{B}*")" { // Objective-C class categories + if (!insideObjC) + { + REJECT; + } + else + { + name += yytext; + } + } +<Start>([~!]{B}*)?{ID}/({B}*"["{B}*"]")* { // the []'s are for Java, + // the / was add to deal with multi- + // dimensional C++ arrays like A[][15] + // the leading ~ is for a destructor + // the leading ! is for a C++/CLI finalizer (see bug 456475 and 635198) + addTypeName(); + name += yytext; + } +<Start>{B}*"::"{B}* { // found a scope specifier + if (!scope.isEmpty()) + { + scope+="::"+name; // add name to scope + } + else + { + scope = name.copy(); // scope becomes name + } + name.resize(0); + } +<Start>{B}*":" { // Objective-C argument separator + name+=yytext; + } +<Start>[*&]+ { + addType(); + type+=yytext; + } +<Start>{B}+ { + addType(); + } +<Start>{B}*"("({ID}"::")*{B}*[&*]({B}*("const"|"volatile"){B}+)? { + addType(); + QCString text=yytext; + type+=text.stripWhiteSpace(); + } +<Start>{B}*")" { + type+=")"; + } +<Start>{B}*"(" { // TODO: function pointers + args+="("; + BEGIN(ReadArgs); + } +<Start>{B}*"[" { + args+="["; + BEGIN(ReadArgs); + } +<Start>{B}*"<" { + name+="<"; + sharpCount=0; + BEGIN(Template); + } +<Template>"<<" { name+="<<"; } +<Template>">>" { name+=">>"; } +<Template>"<" { + name+="<"; + sharpCount++; + } +<Template>">" { + name+=">"; + if (sharpCount) + --sharpCount; + else + { + BEGIN(Start); + } + } +<Template>. { + name+=*yytext; + } +<Operator>{B}*"("{B}*")"{B}*"<>"{B}*/"(" { + name+="() <>"; + BEGIN(ReadArgs); + } +<Operator>{B}*"("{B}*")"{B}*/"(" { + name+="()"; + BEGIN(ReadArgs); + } +<Operator>[^(]*{B}*("<>"{B}*)?/"(" { + name+=yytext; + BEGIN(ReadArgs); + } +<ReadArgs>"throw"{B}*"(" { + exceptionString="throw("; + BEGIN(ReadExceptions); + } +<ReadArgs>. { + args+=*yytext; + } +<ReadExceptions>. { + exceptionString+=*yytext; + } +<*>. +<*>\n + +%% + +/*@ ---------------------------------------------------------------------------- + */ + +void parseFuncDecl(const QCString &decl,bool objC,QCString &cl,QCString &t, + QCString &n,QCString &a,QCString &ftl,QCString &exc) +{ + inputString = decl; + //printf("Input=`%s'\n",inputString); + if (inputString==0) return; + inputPosition = 0; + classTempListFound = FALSE; + funcTempListFound = FALSE; + insideObjC = objC; + scope.resize(0); + className.resize(0); + classTempList.resize(0); + funcTempList.resize(0); + name.resize(0); + type.resize(0); + args.resize(0); + exceptionString.resize(0); + // first we try to find the type, scope, name and arguments + declinfoYYrestart( declinfoYYin ); + BEGIN( Start ); + declinfoYYlex(); + + //printf("type=`%s' class=`%s' name=`%s' args=`%s'\n", + // type.data(),scope.data(),name.data(),args.data()); + + int nb = name.findRev('['); + if (nb!=-1 && args.isEmpty()) // correct for [] in name ambigity (due to Java return type allowing []) + { + args.prepend(name.right(name.length()-nb)); + name=name.left(nb); + } + +#if 0 + { + int l=scope.length(); + int i=0; + int skipCount=0; + cl.resize(0); + ctl.resize(0); + for (i=0;i<l;i++) + { + char c=scope.at(i); + if (c=='<') + skipCount++; + else if (c=='>') + skipCount--; + else if (skipCount==0) + cl+=c; + } + } + cl=stripTemplateSpecifiersFromScope(removeRedundantWhiteSpace(scope),FALSE); + ctl.resize(0); +#endif + + cl=scope; + n=removeRedundantWhiteSpace(name); + int il,ir; + if ((il=n.find('<'))!=-1 && (ir=n.findRev('>'))!=-1) + // TODO: handle cases like where n="operator<< <T>" + { + ftl=removeRedundantWhiteSpace(n.right(n.length()-il)); + n=n.left(il); + } + + //ctl=classTempList.copy(); + //ftl=funcTempList.copy(); + t=removeRedundantWhiteSpace(type); + a=removeRedundantWhiteSpace(args); + exc=removeRedundantWhiteSpace(exceptionString); + + if (!t.isEmpty() && t.at(t.length()-1)==')') // for function pointers + { + a.prepend(")"); + t=t.left(t.length()-1); + } + //printf("type=`%s' class=`%s' name=`%s' args=`%s'\n", + // t.data(),cl.data(),n.data(),a.data()); + + return; + + +} + +//extern "C" { // some bogus code to keep the compiler happy +// int declinfoYYwrap() { return 1 ; } +// void declinfoYYdummy() { yy_flex_realloc(0,0); } +//} + +#if 0 +void dumpDecl(const char *s) +{ + QCString className; + QCString classTNames; + QCString type; + QCString name; + QCString args; + QCString funcTNames; + msg("-----------------------------------------\n"); + parseFuncDecl(s,className,classTNames,type,name,args,funcTNames); + msg("type=`%s' class=`%s' classTempl=`%s' name=`%s' " + "funcTemplateNames=`%s' args=`%s'\n", + type.data(),className.data(),classTNames.data(), + name.data(),funcTNames.data(),args.data() + ); +} + +// some test code +int main() +{ + dumpDecl("A < T > :: Value * A < T > :: getValue < S > ( const A < T > & a )"); + dumpDecl("const A<T>::Value* A<T>::getValue<S>(const A<T>&a)"); + dumpDecl("func()"); + dumpDecl("friend void bla<>()"); + dumpDecl("name< T > :: operator () (int bla)"); + dumpDecl("name< T > :: operator << (int bla)"); + dumpDecl("name< T > :: operator << <> (int bla)"); + dumpDecl("className::func()"); + dumpDecl("void ( * Name < T > :: bla ) ( int, char * )"); +} +#endif + +#if !defined(YY_FLEX_SUBMINOR_VERSION) +//---------------------------------------------------------------------------- +extern "C" { // some bogus code to keep the compiler happy + void declinfoYYdummy() { yy_flex_realloc(0,0); } +} +#endif + diff --git a/trunk/src/defargs.h b/trunk/src/defargs.h new file mode 100644 index 0000000..b2bc198 --- /dev/null +++ b/trunk/src/defargs.h @@ -0,0 +1,29 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#ifndef DEFARGS_H +#define DEFARGS_H + +#include "qtbc.h" +#include <stdio.h> + +class ArgumentList; + +extern void stringToArgumentList(const char *argsString,ArgumentList* argList, + QCString *extraTypeChars=0); + +#endif diff --git a/trunk/src/defargs.l b/trunk/src/defargs.l new file mode 100644 index 0000000..acada87 --- /dev/null +++ b/trunk/src/defargs.l @@ -0,0 +1,482 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +/*! \file + * This scanner is used to convert a string into a list of function or + * template arguments. Each parsed argument results in a Argument struct, + * that is put into an ArgumentList in declaration order. + * Comment blocks for arguments can also be included in the string. + * The argument string does not contain new-lines (except inside any + * comment blocks). + * An Argument consists of the string fields: + * type,name,default value, and documentation + * The Argument list as a whole can be pure, constant or volatile. + * + * Examples of input strings are: + * \code + * "(int a,int b) const" + * "(const char *s="hello world",int=5) = 0" + * "<class T,class N>" + * "(char c,const char)" + * \endcode + * + * Note: It is not always possible to distinguish between the name and + * type of an argument. In case of doubt the name is added to the + * type, and the matchArgumentList in util.cpp is be used to + * further determine the correct separation. + */ + +%{ + +/* + * includes + */ +#include "qtbc.h" +#include <stdio.h> +//#include <iostream.h> +#include <assert.h> +#include <ctype.h> +#include <qregexp.h> + +#include "defargs.h" +#include "entry.h" +#include "util.h" +#include "arguments.h" + +#define YY_NEVER_INTERACTIVE 1 + +/* ----------------------------------------------------------------- + * state variables + */ +static const char *g_inputString; +static int g_inputPosition; +static ArgumentList *g_argList; +static QCString *g_copyArgValue; +static QCString g_curArgTypeName; +static QCString g_curArgDefValue; +static QCString g_curArgName; +static QCString g_curArgDocs; +static QCString g_curArgAttrib; +static QCString g_curArgArray; +static QCString g_extraTypeChars; +static int g_argRoundCount; +static int g_argSharpCount; +static int g_argCurlyCount; +static int g_readArgContext; +static int g_lastDocContext; +static int g_lastDocChar; + +/* ----------------------------------------------------------------- + */ +#undef YY_INPUT +#define YY_INPUT(buf,result,max_size) result=yyread(buf,max_size); + +static int yyread(char *buf,int max_size) +{ + int c=0; + while( c < max_size && g_inputString[g_inputPosition] ) + { + *buf = g_inputString[g_inputPosition++] ; + c++; buf++; + } + return c; +} + +%} + +B [ \t] +ID [a-z_A-Z\x80-\xFF][a-z_A-Z0-9\x80-\xFF]* + +%option noyywrap + +%x Start +%x CopyArgString +%x CopyArgRound +%x CopyArgRound2 +%x CopyArgSharp +%x CopyArgCurly +%x ReadFuncArgType +%x ReadFuncArgDef +%x ReadFuncArgPtr +%x FuncQual +%x ReadDocBlock +%x ReadDocLine + + +%% + +<Start>[<(] { BEGIN(ReadFuncArgType); } + +<ReadFuncArgType>{B}* { + g_curArgTypeName+=" "; + } +<ReadFuncArgType>"["[^\]]*"]" { + if (g_curArgTypeName.stripWhiteSpace().isEmpty()) + { + g_curArgAttrib=yytext; // for M$-IDL + } + else // array type + { + g_curArgArray+=yytext; + } + } +<ReadFuncArgDef>"'"\\[0-7]{1,3}"'" { g_curArgDefValue+=yytext; } +<ReadFuncArgDef>"'"\\."'" { g_curArgDefValue+=yytext; } +<ReadFuncArgDef>"'"."'" { g_curArgDefValue+=yytext; } +<ReadFuncArgDef>\" { + g_curArgDefValue+=*yytext; + BEGIN( CopyArgString ); + } +<ReadFuncArgType>"("([^:)]+{B}*"::")*{B}*[&*\^]+{B}*/{ID} { + // function pointer as argument + g_curArgTypeName+=yytext; + //g_curArgTypeName=g_curArgTypeName.simplifyWhiteSpace(); + BEGIN( ReadFuncArgPtr ); + } +<ReadFuncArgPtr>{ID} { + g_curArgName=yytext; + } +<ReadFuncArgPtr>")"{B}*"(" { // function pointer + g_curArgTypeName+=yytext; + //g_curArgTypeName=g_curArgTypeName.simplifyWhiteSpace(); + g_readArgContext = ReadFuncArgType; + g_copyArgValue=&g_curArgTypeName; + g_argRoundCount=0; + BEGIN( CopyArgRound2 ); + } +<ReadFuncArgPtr>")"/{B}*"[" { // pointer to fixed size array + g_curArgTypeName+=yytext; + g_curArgTypeName+=g_curArgName; + //g_curArgTypeName=g_curArgTypeName.simplifyWhiteSpace(); + BEGIN( ReadFuncArgType ); + } +<ReadFuncArgPtr>")" { // redundant braces detected / remove them + int i=g_curArgTypeName.findRev('('),l=g_curArgTypeName.length(); + if (i!=-1) + g_curArgTypeName=g_curArgTypeName.left(i)+ + g_curArgTypeName.right(l-i-1); + g_curArgTypeName+=g_curArgName; + BEGIN( ReadFuncArgType ); + } +<ReadFuncArgType>"<="|">="|"->"|">>"|"<<" { // handle operators in defargs + g_curArgTypeName+=yytext; + } +<ReadFuncArgType,ReadFuncArgDef>[({<] { + if (YY_START==ReadFuncArgType) + { + g_curArgTypeName+=*yytext; + g_copyArgValue=&g_curArgTypeName; + } + else // YY_START==ReadFuncArgDef + { + g_curArgDefValue+=*yytext; + g_copyArgValue=&g_curArgDefValue; + } + g_readArgContext = YY_START; + if (*yytext=='(') + { + g_argRoundCount=0; + BEGIN( CopyArgRound ); + } + else if (*yytext=='{') + { + g_argCurlyCount=0; + BEGIN( CopyArgCurly ); + } + else // yytext=='<' + { + g_argSharpCount=0; + BEGIN( CopyArgSharp ); + } + } +<CopyArgRound,CopyArgRound2>"(" { + g_argRoundCount++; + *g_copyArgValue += *yytext; + } +<CopyArgRound,CopyArgRound2>")"({B}*{ID})* { + *g_copyArgValue += yytext; + if (g_argRoundCount>0) + { + g_argRoundCount--; + } + else + { + if (YY_START==CopyArgRound2) + { + *g_copyArgValue+=" "+g_curArgName; + } + BEGIN( g_readArgContext ); + } + } +<CopyArgSharp>"<" { + g_argSharpCount++; + *g_copyArgValue += *yytext; + } +<CopyArgSharp>">" { + *g_copyArgValue += *yytext; + if (g_argSharpCount>0) g_argSharpCount--; + else BEGIN( g_readArgContext ); + } +<CopyArgCurly>"{" { + g_argCurlyCount++; + *g_copyArgValue += *yytext; + } +<CopyArgSharp>"}" { + *g_copyArgValue += *yytext; + if (g_argCurlyCount>0) g_argCurlyCount--; + else BEGIN( g_readArgContext ); + } +<CopyArgString>\\. { + g_curArgDefValue+=yytext; + } +<CopyArgString>\" { + g_curArgDefValue+=*yytext; + BEGIN( ReadFuncArgDef ); + } +<ReadFuncArgType>"=" { + BEGIN( ReadFuncArgDef ); + } +<ReadFuncArgType,ReadFuncArgDef>[,)>]{B}*("/*"[*!]|"//"[/!])"<" { + g_lastDocContext=YY_START; + g_lastDocChar=*yytext; + QCString text=yytext; + if (text.find("//")!=-1) + BEGIN( ReadDocLine ); + else + BEGIN( ReadDocBlock ); + } +<ReadFuncArgType,ReadFuncArgDef>[,)>] { + if (*yytext==')' && g_curArgTypeName.stripWhiteSpace().isEmpty()) + { + g_curArgTypeName+=*yytext; + BEGIN(FuncQual); + } + else + { + g_curArgTypeName=removeRedundantWhiteSpace(g_curArgTypeName); + g_curArgDefValue=g_curArgDefValue.stripWhiteSpace(); + //printf("curArgType=`%s' curArgDefVal=`%s'\n",g_curArgTypeName.data(),g_curArgDefValue.data()); + int l=g_curArgTypeName.length(); + if (l>0) + { + int i=l-1; + while (i>=0 && (isspace((uchar)g_curArgTypeName.at(i)) || g_curArgTypeName.at(i)=='.')) i--; + while (i>=0 && isId(g_curArgTypeName.at(i))) i--; + Argument *a = new Argument; + a->attrib = g_curArgAttrib.copy(); + //printf("a->type=%s a->name=%s i=%d l=%d\n", + // a->type.data(),a->name.data(),i,l); + a->array.resize(0); + if (i==l-1 && g_curArgTypeName.at(i)==')') // function argument + { + int bi=g_curArgTypeName.find('('); + int fi=bi-1; + //printf("func arg fi=%d\n",fi); + while (fi>=0 && isId(g_curArgTypeName.at(fi))) fi--; + if (fi>=0) + { + a->type = g_curArgTypeName.left(fi+1); + a->name = g_curArgTypeName.mid(fi+1,bi-fi-1).stripWhiteSpace(); + a->array = g_curArgTypeName.right(l-bi); + } + else + { + a->type = g_curArgTypeName; + } + } + else if (i>=0 && g_curArgTypeName.at(i)!=':') + { // type contains a name + a->type = removeRedundantWhiteSpace(g_curArgTypeName.left(i+1)).stripWhiteSpace(); + a->name = g_curArgTypeName.right(l-i-1).stripWhiteSpace(); + + // if the type becomes a type specifier only then we make a mistake + // and need to correct it to avoid seeing a nameless parameter + // "struct A" as a parameter with type "struct" and name "A". + int sv=0; + if (a->type.left(6)=="const ") sv=6; + else if (a->type.left(9)=="volatile ") sv=9; + + if (a->type.mid(sv)=="struct" || + a->type.mid(sv)=="union" || + a->type.mid(sv)=="class" || + a->type.mid(sv)=="typename" || + a->type=="const" || + a->type=="volatile" + ) + { + a->type = a->type + " " + a->name; + a->name.resize(0); + } + //printf(" --> a->type='%s'\n",a->type.data()); + } + else // assume only the type was specified, try to determine name later + { + a->type = removeRedundantWhiteSpace(g_curArgTypeName); + } + a->array += removeRedundantWhiteSpace(g_curArgArray); + //printf("array=%s\n",a->array.data()); + int alen = a->array.length(); + if (alen>2 && a->array.at(0)=='(' && + a->array.at(alen-1)==')') // fix-up for int *(a[10]) + { + int i=a->array.find('[')-1; + a->array = a->array.mid(1,alen-2); + if (i>0 && a->name.isEmpty()) + { + a->name = a->array.left(i).stripWhiteSpace(); + a->array = a->array.mid(i); + } + } + a->defval = g_curArgDefValue.copy(); + //printf("a->type=%s a->name=%s a->defval=\"%s\"\n",a->type.data(),a->name.data(),a->defval.data()); + a->docs = g_curArgDocs.stripWhiteSpace(); + //printf("Argument `%s' `%s' adding docs=`%s'\n",a->type.data(),a->name.data(),a->docs.data()); + g_argList->append(a); + } + g_curArgAttrib.resize(0); + g_curArgTypeName.resize(0); + g_curArgDefValue.resize(0); + g_curArgArray.resize(0); + g_curArgDocs.resize(0); + if (*yytext==')') + { + BEGIN(FuncQual); + //printf(">>> end of argument list\n"); + } + else + { + BEGIN( ReadFuncArgType ); + } + } + } +<ReadFuncArgType,ReadFuncArgPtr>{ID} { + QCString name=yytext; //resolveDefines(yytext); + if (YY_START==ReadFuncArgType && g_curArgArray=="[]") // Java style array + { + g_curArgTypeName+=" []"; + g_curArgArray.resize(0); + } + //printf("resolveName `%s'->`%s'\n",yytext,name.data()); + g_curArgTypeName+=name; + } +<ReadFuncArgType,ReadFuncArgPtr>. { + g_curArgTypeName+=*yytext; + } + +<ReadFuncArgDef,CopyArgString>"->"|">="|">>" { + g_curArgDefValue+=yytext; + } +<ReadFuncArgDef,CopyArgString>. { + g_curArgDefValue+=*yytext; + } +<CopyArgRound,CopyArgRound2,CopyArgSharp,CopyArgCurly>{ID} { + QCString name=yytext; //resolveDefines(yytext); + *g_copyArgValue+=name; + } +<CopyArgRound,CopyArgRound2,CopyArgSharp,CopyArgCurly>. { + *g_copyArgValue += *yytext; + } +<FuncQual>"const" { + g_argList->constSpecifier=TRUE; + } +<FuncQual>"volatile" { + g_argList->volatileSpecifier=TRUE; + } +<FuncQual>"="{B}*"0" { + g_argList->pureSpecifier=TRUE; + } +<FuncQual>")"{B}*"["[^]]*"]" { // for functions returning a pointer to an array, + // i.e. ")[]" in "int (*f(int))[4]" with argsString="(int))[4]" + g_extraTypeChars=yytext; + } +<ReadDocBlock>[^\*\n]+ { + g_curArgDocs+=yytext; + } +<ReadDocLine>[^\n]+ { + g_curArgDocs+=yytext; + } +<ReadDocBlock>"*/" { + if (g_lastDocChar!=0) + unput(g_lastDocChar); + BEGIN(g_lastDocContext); + } +<ReadDocLine>\n { + if (g_lastDocChar!=0) + unput(g_lastDocChar); + BEGIN(g_lastDocContext); + } +<ReadDocBlock>\n { + g_curArgDocs+=*yytext; + } +<ReadDocBlock>. { + g_curArgDocs+=*yytext; + } +<*>("/*"[*!]|"//"[/!])("<"?) { + g_lastDocContext=YY_START; + g_lastDocChar=0; + if (yytext[1]=='/') + BEGIN( ReadDocLine ); + else + BEGIN( ReadDocBlock ); + } +<*>\n +<*>. + +%% + +/* ---------------------------------------------------------------------------- + */ + +/*! Converts an argument string into an ArgumentList. + * \param argsString the list of Arguments. + * \param al a reference to resulting argument list pointer. + */ + +void stringToArgumentList(const char *argsString,ArgumentList* al,QCString *extraTypeChars) +{ + if (al==0) return; + if (argsString==0) return; + + g_copyArgValue=0; + g_curArgDocs.resize(0); + g_curArgAttrib.resize(0); + g_curArgArray.resize(0); + g_extraTypeChars.resize(0); + g_argRoundCount = 0; + g_argSharpCount = 0; + g_argCurlyCount = 0; + g_lastDocChar = 0; + + g_inputString = argsString; + g_inputPosition = 0; + g_curArgTypeName.resize(0); + g_curArgDefValue.resize(0); + g_curArgName.resize(0); + g_argList = al; + defargsYYrestart( defargsYYin ); + BEGIN( Start ); + defargsYYlex(); + if (extraTypeChars) *extraTypeChars=g_extraTypeChars; + //printf("stringToArgumentList(%s) result=%s\n",argsString,argListToString(al).data()); +} + +#if !defined(YY_FLEX_SUBMINOR_VERSION) +extern "C" { // some bogus code to keep the compiler happy + void defargsYYdummy() { yy_flex_realloc(0,0); } +} +#endif + diff --git a/trunk/src/defgen.cpp b/trunk/src/defgen.cpp new file mode 100644 index 0000000..c3b17ba --- /dev/null +++ b/trunk/src/defgen.cpp @@ -0,0 +1,631 @@ +/****************************************************************************** + * + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#include <stdlib.h> + +#include "qtbc.h" +#include "defgen.h" +#include "doxygen.h" +#include "message.h" +#include "config.h" +#include "classlist.h" +#include "util.h" +#include "defargs.h" +#include "outputgen.h" +#include "dot.h" +#include "arguments.h" + +#include <qdir.h> +#include <qfile.h> +#include <qtextstream.h> + +#define DEF_DB(x) + +inline void writeDEFString(FTextStream &t,const char *s) +{ + const char* p=s; + char c; + + t << '\''; + while ((c = *(p++))) + { + if (c == '\'') + t << '\\'; + t << c; + } + t << '\''; +} + +void generateDEFForMember(MemberDef *md, + FTextStream &t, + Definition *def, + const char* Prefix) +{ + QCString memPrefix; + + // + declaration + // - reimplements + // - reimplementedBy + // - exceptions + // - const/volatile specifiers + // - examples + // + source definition + // - source references + // - source referenced by + // - include code + + if (md->memberType()==MemberDef::EnumValue) return; + + QCString scopeName; + if (md->getClassDef()) + scopeName=md->getClassDef()->name(); + else if (md->getNamespaceDef()) + scopeName=md->getNamespaceDef()->name(); + + t << " " << Prefix << "-member = {" << endl; + memPrefix = " "; + memPrefix.append( Prefix ); + memPrefix.append( "-mem-" ); + + QCString memType; + bool isFunc=FALSE; + switch (md->memberType()) + { + case MemberDef::Define: memType="define"; break; + case MemberDef::EnumValue: ASSERT(0); break; + case MemberDef::Property: memType="property"; break; + case MemberDef::Event: memType="event"; break; + case MemberDef::Variable: memType="variable"; break; + case MemberDef::Typedef: memType="typedef"; break; + case MemberDef::Enumeration: memType="enum"; break; + case MemberDef::Function: memType="function"; isFunc=TRUE; break; + case MemberDef::Signal: memType="signal"; isFunc=TRUE; break; + case MemberDef::Friend: memType="friend"; isFunc=TRUE; break; + case MemberDef::DCOP: memType="dcop"; isFunc=TRUE; break; + case MemberDef::Slot: memType="slot"; isFunc=TRUE; break; + } + + t << memPrefix << "kind = '" << memType << "';" << endl; + t << memPrefix << "id = '" + << md->getOutputFileBase() << "_1" << md->anchor() + << "';" << endl; + + t << memPrefix << "virt = "; + switch (md->virtualness()) + { + case Normal: t << "normal;" << endl; break; + case Virtual: t << "virtual;" << endl; break; + case Pure: t << "pure-virtual;" << endl; break; + default: ASSERT(0); + } + + t << memPrefix << "prot = "; + switch(md->protection()) + { + case Public: t << "public;" << endl; break; + case Protected: t << "protected;" << endl; break; + case Private: t << "private;" << endl; break; + case Package: t << "package;" << endl; break; + } + + if (md->memberType()!=MemberDef::Define && + md->memberType()!=MemberDef::Enumeration + ) + { + QCString typeStr = replaceAnonymousScopes(md->typeString()); + t << memPrefix << "type = <<_EnD_oF_dEf_TeXt_" << endl << typeStr << endl + << "_EnD_oF_dEf_TeXt_;" << endl; + } + + t << memPrefix << "name = '" << md->name() << "';" << endl; + + if (isFunc) //function + { + ArgumentList *declAl = new ArgumentList; + LockingPtr<ArgumentList> defAl = md->argumentList(); + stringToArgumentList(md->argsString(),declAl); + QCString fcnPrefix = " " + memPrefix + "param-"; + + if (declAl->count()>0) + { + ArgumentListIterator declAli(*declAl); + ArgumentListIterator defAli(*defAl); + Argument *a; + for (declAli.toFirst();(a=declAli.current());++declAli) + { + Argument *defArg = defAli.current(); + t << memPrefix << "param = {" << endl; + if (!a->attrib.isEmpty()) + { + t << fcnPrefix << "attributes = "; + writeDEFString(t,a->attrib); + t << ';' << endl; + } + if (!a->type.isEmpty()) + { + t << fcnPrefix << "type = <<_EnD_oF_dEf_TeXt_" << endl + << a->type << endl << "_EnD_oF_dEf_TeXt_;" << endl; + } + if (!a->name.isEmpty()) + { + t << fcnPrefix << "declname = "; + writeDEFString(t,a->name); + t << ';' << endl; + } + if (defArg && !defArg->name.isEmpty() && defArg->name!=a->name) + { + t << fcnPrefix << "defname = "; + writeDEFString(t,defArg->name); + t << ';' << endl; + } + if (!a->array.isEmpty()) + { + t << fcnPrefix << "array = "; + writeDEFString(t,a->array); + t << ';' << endl; + } + if (!a->defval.isEmpty()) + { + t << fcnPrefix << "defval = <<_EnD_oF_dEf_TeXt_" << endl + << a->defval << endl << "_EnD_oF_dEf_TeXt_;" << endl; + } + if (defArg) ++defAli; + t << " }; /*" << fcnPrefix << "-param */" << endl; + } + } + delete declAl; + } + else if ( md->memberType()==MemberDef::Define + && md->argsString()!=0) + { + ArgumentListIterator ali(*md->argumentList()); + Argument *a; + QCString defPrefix = " " + memPrefix + "def-"; + + for (ali.toFirst();(a=ali.current());++ali) + { + t << memPrefix << "param = {" << endl; + t << defPrefix << "name = '" << a->type << "';" << endl; + t << " }; /*" << defPrefix << "-param */" << endl; + } + } + + if (!md->initializer().isEmpty()) + { + t << memPrefix << "initializer = <<_EnD_oF_dEf_TeXt_" << endl + << md->initializer() << endl << "_EnD_oF_dEf_TeXt_;" << endl; + } + // TODO: exceptions, const volatile + if (md->memberType()==MemberDef::Enumeration) // enum + { + LockingPtr<MemberList> enumList = md->enumFieldList(); + if (enumList!=0) + { + MemberListIterator emli(*enumList); + MemberDef *emd; + for (emli.toFirst();(emd=emli.current());++emli) + { + t << memPrefix << "enum = { enum-name = " << emd->name() << ';'; + if (!emd->initializer().isEmpty()) + { + t << " enum-value = "; + writeDEFString(t,emd->initializer()); + t << ';'; + } + t << " };" << endl; + } + } + } + + t << memPrefix << "desc-file = '" << md->getDefFileName() << "';" << endl; + t << memPrefix << "desc-line = '" << md->getDefLine() << "';" << endl; + t << memPrefix << "briefdesc = <<_EnD_oF_dEf_TeXt_" << endl + << md->briefDescription() << endl << "_EnD_oF_dEf_TeXt_;" << endl; + t << memPrefix << "documentation = <<_EnD_oF_dEf_TeXt_" << endl + << md->documentation() << endl << "_EnD_oF_dEf_TeXt_;" << endl; + + //printf("md->getReferencesMembers()=%p\n",md->getReferencesMembers()); + + LockingPtr<MemberSDict> mdict = md->getReferencesMembers(); + if (!mdict.isNull()) + { + MemberSDict::Iterator mdi(*mdict); + MemberDef *rmd; + QCString refPrefix = " " + memPrefix + "ref-"; + + for (mdi.toFirst();(rmd=mdi.current());++mdi) + { + if (rmd->getStartBodyLine()!=-1 && rmd->getBodyDef()) + { + t << memPrefix << "referenceto = {" << endl; + t << refPrefix << "id = '" + << rmd->getBodyDef()->getOutputFileBase() + << "_1" // encoded `:' character (see util.cpp:convertNameToFile) + << rmd->anchor() << "';" << endl; + + t << refPrefix << "line = '" + << rmd->getStartBodyLine() << "';" << endl; + + QCString scope = rmd->getScopeString(); + QCString name = rmd->name(); + if (!scope.isEmpty() && scope!=def->name()) + { + name.prepend(scope+"::"); + } + + t << refPrefix << "name = "; + writeDEFString(t,name); + t << ';' << endl << " };" << endl; + } + } /* for (mdi.toFirst...) */ + } + mdict = md->getReferencedByMembers(); + if (!mdict.isNull()) + { + MemberSDict::Iterator mdi(*mdict); + MemberDef *rmd; + QCString refPrefix = " " + memPrefix + "ref-"; + + for (mdi.toFirst();(rmd=mdi.current());++mdi) + { + if (rmd->getStartBodyLine()!=-1 && rmd->getBodyDef()) + { + t << memPrefix << "referenceby = {" << endl; + t << refPrefix << "id = '" + << rmd->getBodyDef()->getOutputFileBase() + << "_1" // encoded `:' character (see util.cpp:convertNameToFile) + << rmd->anchor() << "';" << endl; + + t << refPrefix << "line = '" + << rmd->getStartBodyLine() << "';" << endl; + + QCString scope = rmd->getScopeString(); + QCString name = rmd->name(); + if (!scope.isEmpty() && scope!=def->name()) + { + name.prepend(scope+"::"); + } + + t << refPrefix << "name = "; + writeDEFString(t,name); + t << ';' << endl << " };" << endl; + } + } /* for (mdi.toFirst...) */ + } + + t << " }; /* " << Prefix << "-member */" << endl; +} + + +void generateDEFClassSection(ClassDef *cd, + FTextStream &t, + MemberList *ml, + const char *kind) +{ + if (cd && ml && ml->count()>0) + { + t << " cp-section = {" << endl; + t << " sec-kind = '" << kind << "';" << endl; + + MemberListIterator mli(*ml); + MemberDef *md; + for (mli.toFirst();(md=mli.current());++mli) + { + generateDEFForMember(md,t,cd,"sec"); + } + t << " }; /* cp-section */" << endl; + } +} + +void generateDEFForClass(ClassDef *cd,FTextStream &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 member documentation + // - examples + + if (cd->isReference()) return; // skip external references. + if (cd->name().find('@')!=-1) return; // skip anonymous compounds. + if (cd->templateMaster()!=0) return; // skip generated template instances. + + t << cd->compoundTypeString() << " = {" << endl; + t << " cp-id = '" << cd->getOutputFileBase() << "';" << endl; + t << " cp-name = '" << cd->name() << "';" << endl; + + if (cd->baseClasses()) + { + BaseClassListIterator bcli(*cd->baseClasses()); + BaseClassDef *bcd; + for (bcli.toFirst();(bcd=bcli.current());++bcli) + { + t << " cp-ref = {" << endl << " ref-type = base;" << endl; + t << " ref-id = '" + << bcd->classDef->getOutputFileBase() << "';" << endl; + t << " ref-prot = "; + switch (bcd->prot) + { + case Public: t << "public;" << endl; break; + case Package: // package scope is not possible + case Protected: t << "protected;" << endl; break; + case Private: t << "private;" << endl; break; + } + t << " ref-virt = "; + switch(bcd->virt) + { + case Normal: t << "non-virtual;"; break; + case Virtual: t << "virtual;"; break; + case Pure: t << "pure-virtual;"; break; + } + t << endl << " };" << endl; + } + } + + if (cd->subClasses()) + { + BaseClassListIterator bcli(*cd->subClasses()); + BaseClassDef *bcd; + for (bcli.toFirst();(bcd=bcli.current());++bcli) + { + t << " cp-ref = {" << endl << " ref-type = derived;" << endl; + t << " ref-id = '" + << bcd->classDef->getOutputFileBase() << "';" << endl; + t << " ref-prot = "; + switch (bcd->prot) + { + case Public: t << "public;" << endl; break; + case Package: // packet scope is not possible! + case Protected: t << "protected;" << endl; break; + case Private: t << "private;" << endl; break; + } + t << " ref-virt = "; + switch(bcd->virt) + { + case Normal: t << "non-virtual;"; break; + case Virtual: t << "virtual;"; break; + case Pure: t << "pure-virtual;"; break; + } + t << endl << " };" << endl; + } + } + + int numMembers = 0; + QListIterator<MemberList> mli(cd->getMemberLists()); + MemberList *ml; + for (mli.toFirst();(ml=mli.current());++mli) + { + if ((ml->listType()&MemberList::detailedLists)==0) + { + numMembers+=ml->count(); + } + } + if (numMembers>0) + { + generateDEFClassSection(cd,t,cd->getMemberList(MemberList::pubTypes),"public-type"); + generateDEFClassSection(cd,t,cd->getMemberList(MemberList::pubMethods),"public-func"); + generateDEFClassSection(cd,t,cd->getMemberList(MemberList::pubAttribs),"public-attrib"); + generateDEFClassSection(cd,t,cd->getMemberList(MemberList::pubSlots),"public-slot"); + generateDEFClassSection(cd,t,cd->getMemberList(MemberList::signals),"signal"); + generateDEFClassSection(cd,t,cd->getMemberList(MemberList::dcopMethods),"dcop-func"); + generateDEFClassSection(cd,t,cd->getMemberList(MemberList::properties),"property"); + generateDEFClassSection(cd,t,cd->getMemberList(MemberList::pubStaticMethods),"public-static-func"); + generateDEFClassSection(cd,t,cd->getMemberList(MemberList::pubStaticAttribs),"public-static-attrib"); + generateDEFClassSection(cd,t,cd->getMemberList(MemberList::proTypes),"protected-type"); + generateDEFClassSection(cd,t,cd->getMemberList(MemberList::proMethods),"protected-func"); + generateDEFClassSection(cd,t,cd->getMemberList(MemberList::proAttribs),"protected-attrib"); + generateDEFClassSection(cd,t,cd->getMemberList(MemberList::proSlots),"protected-slot"); + generateDEFClassSection(cd,t,cd->getMemberList(MemberList::proStaticMethods),"protected-static-func"); + generateDEFClassSection(cd,t,cd->getMemberList(MemberList::proStaticAttribs),"protected-static-attrib"); + generateDEFClassSection(cd,t,cd->getMemberList(MemberList::priTypes),"private-type"); + generateDEFClassSection(cd,t,cd->getMemberList(MemberList::priMethods),"private-func"); + generateDEFClassSection(cd,t,cd->getMemberList(MemberList::priAttribs),"private-attrib"); + generateDEFClassSection(cd,t,cd->getMemberList(MemberList::priSlots),"private-slot"); + generateDEFClassSection(cd,t,cd->getMemberList(MemberList::priStaticMethods),"private-static-func"); + generateDEFClassSection(cd,t,cd->getMemberList(MemberList::priStaticAttribs),"private-static-attrib"); + generateDEFClassSection(cd,t,cd->getMemberList(MemberList::friends),"signal"); + generateDEFClassSection(cd,t,cd->getMemberList(MemberList::related),"related"); + } + + t << " cp-filename = '" << cd->getDefFileName() << "';" << endl; + t << " cp-fileline = '" << cd->getDefLine() << "';" << endl; + t << " cp-briefdesc = <<_EnD_oF_dEf_TeXt_" << endl + << cd->briefDescription() << endl << "_EnD_oF_dEf_TeXt_;" << endl; + + t << " cp-documentation = <<_EnD_oF_dEf_TeXt_" << endl + << cd->documentation() << endl << "_EnD_oF_dEf_TeXt_;" << endl; + + DotClassGraph inheritanceGraph(cd,DotNode::Inheritance); + if (!inheritanceGraph.isTrivial()) + { + t << " cp-inheritancegraph = <<_EnD_oF_dEf_TeXt_" << endl; + inheritanceGraph.writeDEF(t); + t << endl << "_EnD_oF_dEf_TeXt_;" << endl; + } + DotClassGraph collaborationGraph(cd,DotNode::Collaboration); + if (!collaborationGraph.isTrivial()) + { + t << " cp-collaborationgraph = <<_EnD_oF_dEf_TeXt_" << endl; + collaborationGraph.writeDEF(t); + t << endl << "_EnD_oF_dEf_TeXt_;" << endl; + } + t << "}; /* " << cd->compoundTypeString() << " */" << endl; +} + +void generateDEFSection(Definition *d, + FTextStream &t, + MemberList *ml, + const char *kind) +{ + if (ml && ml->count()>0) + { + t << " " << kind << " = {" << endl; + MemberListIterator mli(*ml); + MemberDef *md; + for (mli.toFirst();(md=mli.current());++mli) + { + generateDEFForMember(md,t,d,kind); + } + t << " };" << endl; + } +} + +void generateDEFForNamespace(NamespaceDef *nd,FTextStream &t) +{ + if (nd->isReference()) return; // skip external references + t << " namespace = {" << endl; + t << " ns-id = '" << nd->getOutputFileBase() << "';" << endl; + t << " ns-name = "; + writeDEFString(t,nd->name()); + t << ';' << endl; + + generateDEFSection(nd,t,nd->getMemberList(MemberList::decDefineMembers),"define"); + generateDEFSection(nd,t,nd->getMemberList(MemberList::decProtoMembers),"prototype"); + generateDEFSection(nd,t,nd->getMemberList(MemberList::decTypedefMembers),"typedef"); + generateDEFSection(nd,t,nd->getMemberList(MemberList::decEnumMembers),"enum"); + generateDEFSection(nd,t,nd->getMemberList(MemberList::decFuncMembers),"func"); + generateDEFSection(nd,t,nd->getMemberList(MemberList::decVarMembers),"var"); + + t << " ns-filename = '" << nd->getDefFileName() << "';" << endl; + t << " ns-fileline = '" << nd->getDefLine() << "';" << endl; + t << " ns-briefdesc = <<_EnD_oF_dEf_TeXt_" << endl + << nd->briefDescription() << endl << "_EnD_oF_dEf_TeXt_;" << endl; + + t << " ns-documentation = <<_EnD_oF_dEf_TeXt_" << endl + << nd->documentation() << endl << "_EnD_oF_dEf_TeXt_;" << endl; + t << " };" << endl; +} + +void generateDEFForFile(FileDef *fd,FTextStream &t) +{ + if (fd->isReference()) return; // skip external references + + t << "file = {" << endl; + t << " file-id = '" << fd->getOutputFileBase() << "';" << endl; + t << " file-name = "; + writeDEFString(t,fd->name()); + t << ';' << endl; + + generateDEFSection(fd,t,fd->getMemberList(MemberList::decDefineMembers),"define"); + generateDEFSection(fd,t,fd->getMemberList(MemberList::decProtoMembers),"prototype"); + generateDEFSection(fd,t,fd->getMemberList(MemberList::decTypedefMembers),"typedef"); + generateDEFSection(fd,t,fd->getMemberList(MemberList::decEnumMembers),"enum"); + generateDEFSection(fd,t,fd->getMemberList(MemberList::decFuncMembers),"func"); + generateDEFSection(fd,t,fd->getMemberList(MemberList::decVarMembers),"var"); + + t << " file-full-name = '" << fd->getDefFileName() << "';" << endl; + t << " file-first-line = '" << fd->getDefLine() << "';" << endl; + + t << " file-briefdesc = <<_EnD_oF_dEf_TeXt_" << endl + << fd->briefDescription() << endl << "_EnD_oF_dEf_TeXt_;" << endl; + + t << " file-documentation = <<_EnD_oF_dEf_TeXt_" << endl + << fd->documentation() << endl << "_EnD_oF_dEf_TeXt_;" << endl; + + t << "}; /* file */" << endl; +} + + +void generateDEF() +{ + QCString outputDirectory = Config_getString("OUTPUT_DIRECTORY"); + if (outputDirectory.isEmpty()) + { + outputDirectory=QDir::currentDirPath(); + } + else + { + QDir dir(outputDirectory); + if (!dir.exists()) + { + dir.setPath(QDir::currentDirPath()); + if (!dir.mkdir(outputDirectory)) + { + err("error: tag OUTPUT_DIRECTORY: Output directory `%s' does not " + "exist and cannot be created\n",outputDirectory.data()); + exit(1); + } + else if (!Config_getBool("QUIET")) + { + err("notice: Output directory `%s' does not exist. " + "I have created it for you.\n", outputDirectory.data()); + } + dir.cd(outputDirectory); + } + outputDirectory=dir.absPath(); + } + + QDir dir(outputDirectory); + if (!dir.exists()) + { + dir.setPath(QDir::currentDirPath()); + if (!dir.mkdir(outputDirectory)) + { + err("Cannot create directory %s\n",outputDirectory.data()); + return; + } + } + QDir defDir(outputDirectory+"/def"); + if (!defDir.exists() && !defDir.mkdir(outputDirectory+"/def")) + { + err("Could not create def directory in %s\n",outputDirectory.data()); + return; + } + + QCString fileName=outputDirectory+"/def/doxygen.def"; + QFile f(fileName); + if (!f.open(IO_WriteOnly)) + { + err("Cannot open file %s for writing!\n",fileName.data()); + return; + } + FTextStream t(&f); + t << "AutoGen Definitions dummy;" << endl; + + if (Doxygen::classSDict->count()+Doxygen::inputNameList->count()>0) + { + ClassSDict::Iterator cli(*Doxygen::classSDict); + ClassDef *cd; + for (cli.toFirst();(cd=cli.current());++cli) + { + generateDEFForClass(cd,t); + } + FileNameListIterator fnli(*Doxygen::inputNameList); + FileName *fn; + for (;(fn=fnli.current());++fnli) + { + FileNameIterator fni(*fn); + FileDef *fd; + for (;(fd=fni.current());++fni) + { + generateDEFForFile(fd,t); + } + } + } + else + { + t << "dummy_value = true;" << endl; + } +} diff --git a/trunk/src/defgen.h b/trunk/src/defgen.h new file mode 100644 index 0000000..5b26cd0 --- /dev/null +++ b/trunk/src/defgen.h @@ -0,0 +1,20 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#ifndef DEFGEN_H +#define DEFGEN_H + +void generateDEF(); + +#endif diff --git a/trunk/src/define.cpp b/trunk/src/define.cpp new file mode 100644 index 0000000..e5dd154 --- /dev/null +++ b/trunk/src/define.cpp @@ -0,0 +1,52 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#include "define.h" +#include "config.h" + +Define::Define() +{ + fileDef=0; + lineNr=1; + nargs=-1; + undef=FALSE; + varArgs=FALSE; + isPredefined=FALSE; + nonRecursive=FALSE; +} + +Define::Define(const Define &d) + : name(d.name),definition(d.definition),fileName(d.fileName) +{ + //name=d.name; definition=d.definition; fileName=d.fileName; + lineNr=d.lineNr; + nargs=d.nargs; + undef=d.undef; + varArgs=d.varArgs; + isPredefined=d.isPredefined; + nonRecursive=d.nonRecursive; + fileDef=0; +} + +Define::~Define() +{ +} + +bool Define::hasDocumentation() +{ + return definition && (doc || Config_getBool("EXTRACT_ALL")); +} diff --git a/trunk/src/define.h b/trunk/src/define.h new file mode 100644 index 0000000..b5e4f6e --- /dev/null +++ b/trunk/src/define.h @@ -0,0 +1,91 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#ifndef DEFINE_H +#define DEFINE_H + +#include "qtbc.h" +#include <qdict.h> +#include <qlist.h> + +class FileDef; + +class Define +{ + public: + Define(); + Define(const Define &d); + ~Define(); + bool hasDocumentation(); + QCString name; + QCString definition; + QCString fileName; + QCString doc; + QCString brief; + QCString args; + QCString anchor; + FileDef *fileDef; + int lineNr; + int nargs; + bool undef; + bool varArgs; + bool isPredefined; + bool nonRecursive; +}; + +class DefineList : public QList<Define> +{ + public: + DefineList() : QList<Define>() {} + ~DefineList() {} + int compareItems(GCI i1,GCI i2) + { + return stricmp(((Define *)i1)->name,((Define *)i2)->name); + } +}; + +class DefineName : public QList<Define> +{ + public: + DefineName(const char *n) : QList<Define>() { name=n; } + ~DefineName() {} + const char *nameString() const { return name; } + int compareItems(GCI i1,GCI i2) + { + return stricmp(((Define *)i1)->name,((Define *)i2)->name); + } + + private: + QCString name; +}; + +class DefineNameList : public QList<DefineName> +{ + public: + DefineNameList() : QList<DefineName>() {} + ~DefineNameList() {} + int compareItems(GCI i1,GCI i2) + { + return stricmp(((DefineName *)i1)->nameString(), + ((DefineName *)i2)->nameString()); + } +}; + +typedef QDict<Define> DefineDict; +typedef QDict<DefineName> DefineNameDict; + +#endif diff --git a/trunk/src/definition.cpp b/trunk/src/definition.cpp new file mode 100644 index 0000000..18e6253 --- /dev/null +++ b/trunk/src/definition.cpp @@ -0,0 +1,1791 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#include "qtbc.h" +#include <ctype.h> +#include <qregexp.h> +#include "md5.h" +#include <stdio.h> +#include <stdlib.h> +#include <assert.h> +#include "config.h" +#include "definition.h" +#include "doxygen.h" +#include "language.h" +#include "message.h" +#include "outputlist.h" +#include "code.h" +#include "util.h" +#include "groupdef.h" +#include "pagedef.h" +#include "section.h" +#include "htags.h" +#include "parserintf.h" +#include "marshal.h" +#include "debug.h" +#include "vhdldocgen.h" + +#define START_MARKER 0x4445465B // DEF[ +#define END_MARKER 0x4445465D // DEF] + +//----------------------------------------------------------------------------------------- + +class DefinitionImpl +{ + public: + DefinitionImpl(); + ~DefinitionImpl(); + void init(const char *df, const char *n); + + SectionDict *sectionDict; // dictionary of all sections, not accessible + + MemberSDict *sourceRefByDict; + MemberSDict *sourceRefsDict; + QList<ListItemInfo> *xrefListItems; + GroupList *partOfGroups; + + DocInfo *details; // not exported + DocInfo *inbodyDocs; // not exported + BriefInfo *brief; // not exported + BodyInfo *body; // not exported + QCString docSignatures; + + QCString localName; // local (unqualified) name of the definition + // in the future m_name should become m_localName + QCString qualifiedName; + QCString ref; // reference to external documentation + + bool hidden; + bool isArtificial; + + Definition *outerScope; // not owner + + // where the item was found + QCString defFileName; + QCString defFileExt; + + SrcLangExt lang; +}; + +DefinitionImpl::DefinitionImpl() + : sectionDict(0), sourceRefByDict(0), sourceRefsDict(0), + xrefListItems(0), partOfGroups(0), + details(0), inbodyDocs(0), brief(0), body(0), + outerScope(0) +{ +} + +DefinitionImpl::~DefinitionImpl() +{ + delete sectionDict; + delete sourceRefByDict; + delete sourceRefsDict; + delete partOfGroups; + delete xrefListItems; + delete brief; + delete details; + delete body; + delete inbodyDocs; +} + +void DefinitionImpl::init(const char *df, const char *n) +{ + defFileName = df; + int lastDot = defFileName.findRev('.'); + if (lastDot!=-1) + { + defFileExt = defFileName.mid(lastDot); + } + QCString name = n; + if (name!="<globalScope>") + { + //extractNamespaceName(m_name,m_localName,ns); + localName=stripScope(n); + } + else + { + localName=n; + } + //printf("m_localName=%s\n",m_localName.data()); + + brief = 0; + details = 0; + body = 0; + inbodyDocs = 0; + sourceRefByDict = 0; + sourceRefsDict = 0; + sectionDict = 0, + outerScope = Doxygen::globalScope; + partOfGroups = 0; + xrefListItems = 0; + hidden = FALSE; + isArtificial = FALSE; + lang = SrcLangExt_Unknown; +} + +//----------------------------------------------------------------------------------------- + +static bool matchExcludedSymbols(const char *name) +{ + static QStrList &exclSyms = Config_getList("EXCLUDE_SYMBOLS"); + if (exclSyms.count()==0) return FALSE; // nothing specified + const char *pat = exclSyms.first(); + QCString symName = name; + while (pat) + { + QCString pattern = pat; + bool forceStart=FALSE; + bool forceEnd=FALSE; + if (pattern.at(0)=='^') + pattern=pattern.mid(1),forceStart=TRUE; + if (pattern.at(pattern.length()-1)=='$') + pattern=pattern.left(pattern.length()-1),forceEnd=TRUE; + if (pattern.find('*')!=-1) // wildcard mode + { + QRegExp re(substitute(pattern,"*",".*"),TRUE); + int i,pl; + i = re.match(symName,0,&pl); + //printf(" %d = re.match(%s) pattern=%s\n",i,symName.data(),pattern.data()); + if (i!=-1) // wildcard match + { + int sl=symName.length(); + // check if it is a whole word match + if ((i==0 || pattern.at(0)=='*' || (!isId(symName.at(i-1)) && !forceStart)) && + (i+pl==sl || pattern.at(i+pl)=='*' || (!isId(symName.at(i+pl)) && !forceEnd)) + ) + { + //printf("--> name=%s pattern=%s match at %d\n",symName.data(),pattern.data(),i); + return TRUE; + } + } + } + else if (!pattern.isEmpty()) // match words + { + int i = symName.find(pattern); + if (i!=-1) // we have a match! + { + int pl=pattern.length(); + int sl=symName.length(); + // check if it is a whole word match + if ((i==0 || (!isId(symName.at(i-1)) && !forceStart)) && + (i+pl==sl || (!isId(symName.at(i+pl)) && !forceEnd)) + ) + { + //printf("--> name=%s pattern=%s match at %d\n",symName.data(),pattern.data(),i); + return TRUE; + } + } + } + pat = exclSyms.next(); + } + //printf("--> name=%s: no match\n",name); + return FALSE; +} + +void Definition::addToMap(const char *name,Definition *d) +{ + bool vhdlOpt = Config_getBool("OPTIMIZE_OUTPUT_VHDL"); + QCString symbolName = name; + int index=computeQualifiedIndex(symbolName); + if (!vhdlOpt && index!=-1) symbolName=symbolName.mid(index+2); + if (!symbolName.isEmpty()) + { + //printf("******* adding symbol `%s' (%p)\n",symbolName.data(),d); + DefinitionIntf *di=Doxygen::symbolMap->find(symbolName); + //printf(" addToMap(%p): looking for symbol %s: %p\n",d,symbolName.data(),di); + if (di==0) // new Symbol + { + //printf(" new symbol!\n"); + Doxygen::symbolMap->insert(symbolName,d); + } + else // existing symbol + { + //printf(" existing symbol: "); + if (di->definitionType()==DefinitionIntf::TypeSymbolList) // already multiple symbols + { + //printf("adding to exiting list\n"); + DefinitionList *dl = (DefinitionList*)di; + dl->append(d); + } + else // going from one to two symbols + { + Doxygen::symbolMap->take(symbolName); + DefinitionList *dl = new DefinitionList; + //printf("replacing symbol by list %p with elements %p and %p\n",dl,di,d); + dl->append((Definition*)di); + dl->append(d); + Doxygen::symbolMap->insert(symbolName,dl); + } + } + + // auto resize if needed + static int sizeIndex=9; + if (Doxygen::symbolMap->size()>SDict_primes[sizeIndex]) + { + Doxygen::symbolMap->resize(SDict_primes[++sizeIndex]); + } + + d->_setSymbolName(symbolName); + } +} + +void Definition::removeFromMap(Definition *d) +{ + QString symbolName = d->m_symbolName; + if (!symbolName.isEmpty()) + { + //printf("******* removing symbol `%s' (%p)\n",symbolName.data(),d); + DefinitionIntf *di=Doxygen::symbolMap->find(symbolName); + if (di) + { + if (di!=d) // symbolName not unique + { + //printf(" removing from list: %p!\n",di); + DefinitionList *dl = (DefinitionList*)di; + bool b = dl->removeRef(d); + ASSERT(b==TRUE); + if (dl->isEmpty()) + { + Doxygen::symbolMap->take(symbolName); + } + } + else // symbolName unique + { + //printf(" removing symbol %p\n",di); + Doxygen::symbolMap->take(symbolName); + } + } + } +} + +Definition::Definition(const char *df,int dl, + const char *name,const char *b, + const char *d,bool isSymbol) +{ + m_name = name; + m_defLine = dl; + m_impl = new DefinitionImpl; + m_impl->init(df,name); + m_isSymbol = isSymbol; + if (isSymbol) addToMap(name,this); + _setBriefDescription(b,df,dl); + _setDocumentation(d,df,dl,TRUE,FALSE); + if (matchExcludedSymbols(name)) + { + m_impl->hidden = TRUE; + } +} + +Definition::~Definition() +{ + if (m_isSymbol) + { + removeFromMap(this); + } + if (m_impl) + { + delete m_impl; + m_impl=0; + } +} + +void Definition::setName(const char *name) +{ + if (name==0) return; + m_name = name; +} + +void Definition::addSectionsToDefinition(QList<SectionInfo> *anchorList) +{ + if (!anchorList) return; + makeResident(); + //printf("%s: addSectionsToDefinition(%d)\n",name().data(),anchorList->count()); + SectionInfo *si=anchorList->first(); + while (si) + { + //printf("Add section `%s' to definition `%s'\n", + // si->label.data(),name().data()); + SectionInfo *gsi=Doxygen::sectionDict.find(si->label); + //printf("===== label=%s gsi=%p\n",si->label.data(),gsi); + if (gsi==0) + { + gsi = new SectionInfo(*si); + Doxygen::sectionDict.append(si->label,gsi); + } + if (m_impl->sectionDict==0) + { + m_impl->sectionDict = new SectionDict(17); + } + if (m_impl->sectionDict->find(gsi->label)==0) + { + m_impl->sectionDict->append(gsi->label,gsi); + gsi->definition = this; + } + si=anchorList->next(); + } +} + +bool Definition::hasSections() const +{ + makeResident(); + //printf("Definition::hasSections(%s) #sections=%d\n",name().data(), + // m_impl->sectionDict ? m_impl->sectionDict->count() : 0); + if (m_impl->sectionDict==0) return FALSE; + SDict<SectionInfo>::Iterator li(*m_impl->sectionDict); + SectionInfo *si; + for (li.toFirst();(si=li.current());++li) + { + if (si->type==SectionInfo::Section || + si->type==SectionInfo::Subsection || + si->type==SectionInfo::Subsubsection || + si->type==SectionInfo::Paragraph) + { + return TRUE; + } + } + return FALSE; +} + +void Definition::addSectionsToIndex() +{ + makeResident(); + if (m_impl->sectionDict==0) return; + //printf("Definition::addSectionsToIndex()\n"); + SDict<SectionInfo>::Iterator li(*m_impl->sectionDict); + SectionInfo *si; + int level=1; + for (li.toFirst();(si=li.current());++li) + { + if (si->type==SectionInfo::Section || + si->type==SectionInfo::Subsection || + si->type==SectionInfo::Subsubsection || + si->type==SectionInfo::Paragraph) + { + //printf(" level=%d title=%s\n",level,si->title.data()); + int nextLevel = (int)si->type; + int i; + if (nextLevel>level) + { + for (i=level;i<nextLevel;i++) + { + Doxygen::indexList.incContentsDepth(); + } + } + else if (nextLevel<level) + { + for (i=nextLevel;i<level;i++) + { + Doxygen::indexList.decContentsDepth(); + } + } + Doxygen::indexList.addContentsItem(TRUE,si->title, + getReference(), + getOutputFileBase(), + si->label, + FALSE, + TRUE); + level = nextLevel; + } + } + while (level>1) + { + Doxygen::indexList.decContentsDepth(); + level--; + } +} + +void Definition::writeToc(OutputList &ol) +{ + makeResident(); + if (m_impl->sectionDict==0) return; + ol.pushGeneratorState(); + ol.disableAllBut(OutputGenerator::Html); + ol.writeString("<div class=\"toc\">"); + ol.writeString("<h3>"); + ol.writeString(theTranslator->trRTFTableOfContents()); + ol.writeString("</h3>\n"); + ol.writeString("<ul>"); + SDict<SectionInfo>::Iterator li(*m_impl->sectionDict); + SectionInfo *si; + int level=1; + char cs[2]; + cs[1]='\0'; + bool inLi[5]={ FALSE, FALSE, FALSE, FALSE }; + for (li.toFirst();(si=li.current());++li) + { + if (si->type==SectionInfo::Section || + si->type==SectionInfo::Subsection || + si->type==SectionInfo::Subsubsection || + si->type==SectionInfo::Paragraph) + { + //printf(" level=%d title=%s\n",level,si->title.data()); + int nextLevel = (int)si->type; + if (nextLevel>level) + { + ol.writeString("<ul>"); + } + else if (nextLevel<level) + { + if (inLi[level]) ol.writeString("</li>\n"); + inLi[level]=FALSE; + ol.writeString("</ul>\n"); + } + cs[0]='0'+nextLevel; + if (inLi[nextLevel]) ol.writeString("</li>\n"); + ol.writeString("<li class=\"level"+QCString(cs)+"\"><a href=\"#"+si->label+"\">"+si->title+"</a>"); + inLi[nextLevel]=TRUE; + level = nextLevel; + } + } + while (level>1) + { + if (inLi[level]) ol.writeString("</li>\n"); + inLi[level]=FALSE; + ol.writeString("</ul>\n"); + level--; + } + if (inLi[level]) ol.writeString("</li>\n"); + inLi[level]=FALSE; + ol.writeString("</ul>\n"); + ol.writeString("</div>\n"); + ol.popGeneratorState(); +} + +void Definition::writeDocAnchorsToTagFile() +{ + makeResident(); + if (!Config_getString("GENERATE_TAGFILE").isEmpty() && m_impl->sectionDict) + { + //printf("%s: writeDocAnchorsToTagFile(%d)\n",name().data(),m_sectionDict->count()); + SDict<SectionInfo>::Iterator sdi(*m_impl->sectionDict); + SectionInfo *si; + for (;(si=sdi.current());++sdi) + { + if (!si->generated) + { + //printf("write an entry!\n"); + if (definitionType()==TypeMember) Doxygen::tagFile << " "; + Doxygen::tagFile << " <docanchor file=\"" + << si->fileName << "\">" << si->label + << "</docanchor>" << endl; + } + } + } +} + +bool Definition::_docsAlreadyAdded(const QCString &doc) +{ + uchar md5_sig[16]; + QCString sigStr(33); + // to avoid mismatches due to differences in indenting, we first remove + // double whitespaces... + QCString docStr = doc.simplifyWhiteSpace(); + MD5Buffer((const unsigned char *)docStr.data(),docStr.length(),md5_sig); + MD5SigToString(md5_sig,sigStr.data(),33); + if (m_impl->docSignatures.find(sigStr)==-1) // new docs, add signature to prevent re-adding it + { + m_impl->docSignatures+=":"+sigStr; + return FALSE; + } + else + { + return TRUE; + } +} + +void Definition::_setDocumentation(const char *d,const char *docFile,int docLine, + bool stripWhiteSpace,bool atTop) +{ + if (d==0) return; + //printf("Definition::setDocumentation(%s,%s,%d,%d)\n",d,docFile,docLine,stripWhiteSpace); + QCString doc = d; + if (stripWhiteSpace) + { + doc = stripLeadingAndTrailingEmptyLines(doc,docLine); + } + else // don't strip whitespace + { + doc=d; + } + if (!_docsAlreadyAdded(doc)) + { + //printf("setting docs for %s: `%s'\n",name().data(),m_doc.data()); + if (m_impl->details==0) + { + m_impl->details = new DocInfo; + } + if (m_impl->details->doc.isEmpty()) // fresh detailed description + { + m_impl->details->doc = doc; + } + else if (atTop) // another detailed description, append it to the start + { + m_impl->details->doc = doc+"\n\n"+m_impl->details->doc; + } + else // another detailed description, append it to the end + { + m_impl->details->doc += "\n\n"+doc; + } + if (docLine!=-1) // store location if valid + { + m_impl->details->file = docFile; + m_impl->details->line = docLine; + } + else + { + m_impl->details->file = docFile; + m_impl->details->line = 1; + } + } +} + +void Definition::setDocumentation(const char *d,const char *docFile,int docLine,bool stripWhiteSpace) +{ + if (d==0) return; + makeResident(); + _setDocumentation(d,docFile,docLine,stripWhiteSpace,FALSE); +} + +#define uni_isupper(c) (QChar(c).category()==QChar::Letter_Uppercase) + +// do a UTF-8 aware search for the last real character and return TRUE +// if that is a multibyte one. +static bool lastCharIsMultibyte(const QCString &s) +{ + int l = s.length(); + int p = 0; + int pp = -1; + while ((p=nextUtf8CharPosition(s,l,p))<l) pp=p; + if (pp==-1 || ((uchar)s[pp])<0x80) return FALSE; + return TRUE; +} + +void Definition::_setBriefDescription(const char *b,const char *briefFile,int briefLine) +{ + static QCString outputLanguage = Config_getEnum("OUTPUT_LANGUAGE"); + static bool needsDot = outputLanguage!="Japanese" && + outputLanguage!="Chinese" && + outputLanguage!="Korean"; + QCString brief = b; + brief = brief.stripWhiteSpace(); + if (brief.isEmpty()) return; + int bl = brief.length(); + if (bl>0 && needsDot) // add punctuation if needed + { + int c = brief.at(bl-1); + switch(c) + { + case '.': case '!': case '?': case '>': case ':': case ')': break; + default: + if (uni_isupper(brief.at(0)) && !lastCharIsMultibyte(brief)) brief+='.'; + break; + } + } + + if (m_impl->brief && !m_impl->brief->doc.isEmpty()) + { + //printf("adding to details\n"); + _setDocumentation(brief,briefFile,briefLine,FALSE,TRUE); + } + else if (!_docsAlreadyAdded(brief)) + { + //fprintf(stderr,"Definition::setBriefDescription(%s,%s,%d)\n",b,briefFile,briefLine); + if (m_impl->brief==0) + { + m_impl->brief = new BriefInfo; + } + m_impl->brief->doc=brief; + if (briefLine!=-1) + { + m_impl->brief->file = briefFile; + m_impl->brief->line = briefLine; + } + else + { + m_impl->brief->file = briefFile; + m_impl->brief->line = 1; + } + } +} + +void Definition::setBriefDescription(const char *b,const char *briefFile,int briefLine) +{ + if (b==0) return; + makeResident(); + _setBriefDescription(b,briefFile,briefLine); +} + +void Definition::_setInbodyDocumentation(const char *doc,const char *inbodyFile,int inbodyLine) +{ + if (m_impl->inbodyDocs==0) + { + m_impl->inbodyDocs = new DocInfo; + } + if (m_impl->inbodyDocs->doc.isEmpty()) // fresh inbody docs + { + m_impl->inbodyDocs->doc = doc; + m_impl->inbodyDocs->file = inbodyFile; + m_impl->inbodyDocs->line = inbodyLine; + } + else // another inbody documentation fragment, append this to the end + { + m_impl->inbodyDocs->doc += QCString("\n\n")+doc; + } +} + +void Definition::setInbodyDocumentation(const char *d,const char *inbodyFile,int inbodyLine) +{ + if (d==0) return; + makeResident(); + _setInbodyDocumentation(d,inbodyFile,inbodyLine); +} + +/*! Reads a fragment of code from file \a fileName starting at + * line \a startLine and ending at line \a endLine (inclusive). The fragment is + * stored in \a result. If FALSE is returned the code fragment could not be + * found. + * + * The file is scanned for a opening bracket ('{') from \a startLine onward + * The line actually containing the bracket is returned via startLine. + * The file is scanned for a closing bracket ('}') from \a endLine backward. + * The line actually containing the bracket is returned via endLine. + * Note that for VHDL code the bracket search is not done. + */ +static bool readCodeFragment(const char *fileName, + int &startLine,int &endLine,QCString &result) +{ + static bool filterSourceFiles = Config_getBool("FILTER_SOURCE_FILES"); + //printf("readCodeFragment(%s,%d,%d)\n",fileName,startLine,endLine); + if (fileName==0 || fileName[0]==0) return FALSE; // not a valid file name + QCString filter = getFileFilter(fileName,TRUE); + FILE *f=0; + bool usePipe = !filter.isEmpty() && filterSourceFiles; + SrcLangExt lang = getLanguageFromFileName(fileName); + if (!usePipe) // no filter given or wanted + { + f = portable_fopen(fileName,"r"); + } + else // use filter + { + QCString cmd=filter+" \""+fileName+"\""; + Debug::print(Debug::ExtCmd,0,"Executing popen(`%s`)\n",cmd.data()); + f = portable_popen(cmd,"r"); + } + bool found = lang==SrcLangExt_VHDL || + lang==SrcLangExt_Tcl || + lang==SrcLangExt_Python || + lang==SrcLangExt_Fortran; + // for VHDL, TCL, Python, and Fortran no bracket search is possible + if (f) + { + int c=0; + int col=0; + int lineNr=1; + // skip until the startLine has reached + while (lineNr<startLine && !feof(f)) + { + while ((c=fgetc(f))!='\n' && c!=EOF) /* skip */; + lineNr++; + } + if (!feof(f)) + { + // skip until the opening bracket or lonely : is found + char cn=0; + while (lineNr<=endLine && !feof(f) && !found) + { + int pc=0; + while ((c=fgetc(f))!='{' && c!=':' && c!=EOF) + { + //printf("parsing char `%c'\n",c); + if (c=='\n') + { + lineNr++,col=0; + } + else if (c=='\t') + { + col+=Config_getInt("TAB_SIZE") - (col%Config_getInt("TAB_SIZE")); + } + else if (pc=='/' && c=='/') // skip single line comment + { + while ((c=fgetc(f))!='\n' && c!=EOF) pc=c; + if (c=='\n') lineNr++,col=0; + } + else if (pc=='/' && c=='*') // skip C style comment + { + while (((c=fgetc(f))!='/' || pc!='*') && c!=EOF) + { + if (c=='\n') lineNr++,col=0; + pc=c; + } + } + else + { + col++; + } + pc = c; + } + if (c==':') + { + cn=fgetc(f); + if (cn!=':') found=TRUE; + } + else if (c=='{') // } so vi matching brackets has no problem + { + found=TRUE; + } + } + //printf(" -> readCodeFragment(%s,%d,%d) lineNr=%d\n",fileName,startLine,endLine,lineNr); + if (found) + { + // For code with more than one line, + // fill the line with spaces until we are at the right column + // so that the opening brace lines up with the closing brace + if (endLine!=startLine) + { + QCString spaces; + spaces.fill(' ',col); + result+=spaces; + } + // copy until end of line + result+=c; + if (c==':') + { + result+=cn; + if (cn=='\n') lineNr++; + } + startLine=lineNr; + const int maxLineLength=4096; + char lineStr[maxLineLength]; + do + { + //printf("reading line %d in range %d-%d\n",lineNr,startLine,endLine); + int size_read; + do + { + // read up to maxLineLength-1 bytes, the last byte being zero + char *p = fgets(lineStr, maxLineLength,f); + //printf(" read %s",p); + if (p) + { + size_read=qstrlen(p); + } + else // nothing read + { + size_read=-1; + lineStr[0]='\0'; + } + result+=lineStr; + } while (size_read == (maxLineLength-1)); + + lineNr++; + } while (lineNr<=endLine && !feof(f)); + + // strip stuff after closing bracket + int newLineIndex = result.findRev('\n'); + int braceIndex = result.findRev('}'); + if (braceIndex > newLineIndex) + { + result.truncate(braceIndex+1); + } + endLine=lineNr-1; + } + } + if (usePipe) + { + portable_pclose(f); + Debug::print(Debug::FilterOutput, 0, "Filter output\n"); + Debug::print(Debug::FilterOutput,0,"-------------\n%s\n-------------\n",result.data()); + } + else + { + fclose(f); + } + } + result = transcodeCharacterStringToUTF8(result); + return found; +} + +/*! Write a reference to the source code defining this definition */ +void Definition::writeSourceDef(OutputList &ol,const char *) +{ + static bool sourceBrowser = Config_getBool("SOURCE_BROWSER"); + static bool latexSourceCode = Config_getBool("LATEX_SOURCE_CODE"); + makeResident(); + ol.pushGeneratorState(); + //printf("Definition::writeSourceRef %d %p\n",bodyLine,bodyDef); + if (sourceBrowser && + m_impl->body && m_impl->body->startLine!=-1 && m_impl->body->fileDef) + { + QCString refText = theTranslator->trDefinedAtLineInSourceFile(); + int lineMarkerPos = refText.find("@0"); + int fileMarkerPos = refText.find("@1"); + if (lineMarkerPos!=-1 && fileMarkerPos!=-1) // should always pass this. + { + QCString lineStr,anchorStr; + lineStr.sprintf("%d",m_impl->body->startLine); + anchorStr.sprintf(Htags::useHtags ? "L%d" : "l%05d",m_impl->body->startLine); + ol.startParagraph(); + if (lineMarkerPos<fileMarkerPos) // line marker before file marker + { + // write text left from linePos marker + ol.parseText(refText.left(lineMarkerPos)); + ol.pushGeneratorState(); + ol.disable(OutputGenerator::RTF); + ol.disable(OutputGenerator::Man); + if (!latexSourceCode) + { + ol.disable(OutputGenerator::Latex); + } + // write line link (HTML, LaTeX optionally) + ol.writeObjectLink(0,m_impl->body->fileDef->getSourceFileBase(), + anchorStr,lineStr); + ol.enableAll(); + ol.disable(OutputGenerator::Html); + if (latexSourceCode) + { + ol.disable(OutputGenerator::Latex); + } + // write normal text (Man/RTF, Latex optionally) + ol.docify(lineStr); + ol.popGeneratorState(); + + // write text between markers + ol.parseText(refText.mid(lineMarkerPos+2, + fileMarkerPos-lineMarkerPos-2)); + + ol.pushGeneratorState(); + ol.disable(OutputGenerator::RTF); + ol.disable(OutputGenerator::Man); + if (!latexSourceCode) + { + ol.disable(OutputGenerator::Latex); + } + // write line link (HTML, LaTeX optionally) + ol.writeObjectLink(0,m_impl->body->fileDef->getSourceFileBase(), + 0,m_impl->body->fileDef->name()); + ol.enableAll(); + ol.disable(OutputGenerator::Html); + if (latexSourceCode) + { + ol.disable(OutputGenerator::Latex); + } + // write normal text (Man/RTF, Latex optionally) + ol.docify(m_impl->body->fileDef->name()); + ol.popGeneratorState(); + + // write text right from file marker + ol.parseText(refText.right( + refText.length()-fileMarkerPos-2)); + } + else // file marker before line marker + { + // write text left from file marker + ol.parseText(refText.left(fileMarkerPos)); + ol.pushGeneratorState(); + ol.disable(OutputGenerator::RTF); + ol.disable(OutputGenerator::Man); + if (!latexSourceCode) + { + ol.disable(OutputGenerator::Latex); + } + // write file link (HTML only) + ol.writeObjectLink(0,m_impl->body->fileDef->getSourceFileBase(), + 0,m_impl->body->fileDef->name()); + ol.enableAll(); + ol.disable(OutputGenerator::Html); + if (latexSourceCode) + { + ol.disable(OutputGenerator::Latex); + } + // write normal text (Latex/Man only) + ol.docify(m_impl->body->fileDef->name()); + ol.popGeneratorState(); + + // write text between markers + ol.parseText(refText.mid(fileMarkerPos+2, + lineMarkerPos-fileMarkerPos-2)); + + ol.pushGeneratorState(); + ol.disable(OutputGenerator::RTF); + ol.disable(OutputGenerator::Man); + if (!latexSourceCode) + { + ol.disable(OutputGenerator::Latex); + } + ol.disableAllBut(OutputGenerator::Html); + // write line link (HTML only) + ol.writeObjectLink(0,m_impl->body->fileDef->getSourceFileBase(), + anchorStr,lineStr); + ol.enableAll(); + ol.disable(OutputGenerator::Html); + if (latexSourceCode) + { + ol.disable(OutputGenerator::Latex); + } + // write normal text (Latex/Man only) + ol.docify(lineStr); + ol.popGeneratorState(); + + // write text right from linePos marker + ol.parseText(refText.right( + refText.length()-lineMarkerPos-2)); + } + ol.endParagraph(); + } + else + { + err("error: translation error: invalid markers in trDefinedInSourceFile()\n"); + } + } + ol.popGeneratorState(); +} + +void Definition::setBodySegment(int bls,int ble) +{ + //printf("setBodySegment(%d,%d) for %s\n",bls,ble,name().data()); + makeResident(); + if (m_impl->body==0) m_impl->body = new BodyInfo; + m_impl->body->startLine=bls; + m_impl->body->endLine=ble; +} + +void Definition::setBodyDef(FileDef *fd) +{ + makeResident(); + if (m_impl->body==0) m_impl->body = new BodyInfo; + m_impl->body->fileDef=fd; +} + +/*! Write code of this definition into the documentation */ +void Definition::writeInlineCode(OutputList &ol,const char *scopeName) +{ + makeResident(); + ol.pushGeneratorState(); + //printf("Source Fragment %s: %d-%d bodyDef=%p\n",name().data(), + // m_startBodyLine,m_endBodyLine,m_bodyDef); + if (Config_getBool("INLINE_SOURCES") && + m_impl->body && m_impl->body->startLine!=-1 && + m_impl->body->endLine>=m_impl->body->startLine && m_impl->body->fileDef) + { + QCString codeFragment; + int actualStart=m_impl->body->startLine,actualEnd=m_impl->body->endLine; + if (readCodeFragment(m_impl->body->fileDef->absFilePath(), + actualStart,actualEnd,codeFragment) + ) + { + //printf("Adding code fragement '%s' ext='%s'\n", + // codeFragment.data(),m_impl->defFileExt.data()); + ParserInterface *pIntf = Doxygen::parserManager->getParser(m_impl->defFileExt); + pIntf->resetCodeParserState(); + //printf("Read:\n`%s'\n\n",codeFragment.data()); + MemberDef *thisMd = 0; + if (definitionType()==TypeMember) thisMd = (MemberDef *)this; + + // vhdl parser can' t start at an arbitrary point in the source code + if(this->getLanguage()==SrcLangExt_VHDL) + { + if (thisMd) VhdlDocGen::writeCodeFragment(ol,actualStart,codeFragment,thisMd); + return; + } + + ol.startCodeFragment(); + pIntf->parseCode(ol, // codeOutIntf + scopeName, // scope + codeFragment, // input + FALSE, // isExample + 0, // exampleName + m_impl->body->fileDef, // fileDef + actualStart, // startLine + actualEnd, // endLine + TRUE, // inlineFragment + thisMd, // memberDef + FALSE // show line numbers + ); + ol.endCodeFragment(); + } + } + ol.popGeneratorState(); +} + +/*! Write a reference to the source code fragments in which this + * definition is used. + */ +void Definition::_writeSourceRefList(OutputList &ol,const char *scopeName, + const QCString &text,MemberSDict *members,bool /*funcOnly*/) +{ + LockingPtr<Definition> lock(this,this); // since this can be a memberDef + // accessing other memberDefs prevent + // it from being flushed to disk + static bool latexSourceCode = Config_getBool("LATEX_SOURCE_CODE"); + static bool sourceBrowser = Config_getBool("SOURCE_BROWSER"); + static bool refLinkSource = Config_getBool("REFERENCES_LINK_SOURCE"); + ol.pushGeneratorState(); + if (members) + { + members->sort(); + + ol.startParagraph(); + ol.parseText(text); + ol.docify(" "); + + QCString ldefLine=theTranslator->trWriteList(members->count()); + + QRegExp marker("@[0-9]+"); + int index=0,newIndex,matchLen; + // now replace all markers in inheritLine with links to the classes + while ((newIndex=marker.match(ldefLine,index,&matchLen))!=-1) + { + bool ok; + ol.parseText(ldefLine.mid(index,newIndex-index)); + uint entryIndex = ldefLine.mid(newIndex+1,matchLen-1).toUInt(&ok); + MemberDef *md=members->at(entryIndex); + if (ok && md) + { + QCString scope=md->getScopeString(); + QCString name=md->name(); + //printf("class=%p scope=%s scopeName=%s\n",md->getClassDef(),scope.data(),scopeName); + if (!scope.isEmpty() && scope!=scopeName) + { + name.prepend(scope+getLanguageSpecificSeparator(m_impl->lang)); + } + if (!md->isObjCMethod() && + (md->isFunction() || md->isSlot() || + md->isPrototype() || md->isSignal() + ) + ) + { + name+="()"; + } + //Definition *d = md->getOutputFileBase(); + //if (d==Doxygen::globalScope) d=md->getBodyDef(); + if (sourceBrowser && + !(md->isLinkable() && !refLinkSource) && + md->getStartBodyLine()!=-1 && + md->getBodyDef() + ) + { + //printf("md->getBodyDef()=%p global=%p\n",md->getBodyDef(),Doxygen::globalScope); + // for HTML write a real link + ol.pushGeneratorState(); + //ol.disableAllBut(OutputGenerator::Html); + + ol.disable(OutputGenerator::RTF); + ol.disable(OutputGenerator::Man); + if (!latexSourceCode) + { + ol.disable(OutputGenerator::Latex); + } + QCString lineStr,anchorStr; + anchorStr.sprintf("l%05d",md->getStartBodyLine()); + //printf("Write object link to %s\n",md->getBodyDef()->getSourceFileBase().data()); + ol.writeObjectLink(0,md->getBodyDef()->getSourceFileBase(),anchorStr,name); + ol.popGeneratorState(); + + // for the other output formats just mention the name + ol.pushGeneratorState(); + ol.disable(OutputGenerator::Html); + if (latexSourceCode) + { + ol.disable(OutputGenerator::Latex); + } + ol.docify(name); + ol.popGeneratorState(); + } + else if (md->isLinkable() /*&& d && d->isLinkable()*/) + { + // for HTML write a real link + ol.pushGeneratorState(); + //ol.disableAllBut(OutputGenerator::Html); + ol.disable(OutputGenerator::RTF); + ol.disable(OutputGenerator::Man); + if (!latexSourceCode) + { + ol.disable(OutputGenerator::Latex); + } + + ol.writeObjectLink(md->getReference(), + md->getOutputFileBase(), + md->anchor(),name); + ol.popGeneratorState(); + + // for the other output formats just mention the name + ol.pushGeneratorState(); + ol.disable(OutputGenerator::Html); + if (latexSourceCode) + { + ol.disable(OutputGenerator::Latex); + } + ol.docify(name); + ol.popGeneratorState(); + } + else + { + ol.docify(name); + } + } + index=newIndex+matchLen; + } + ol.parseText(ldefLine.right(ldefLine.length()-index)); + ol.writeString("."); + ol.endParagraph(); + } + ol.popGeneratorState(); +} + +void Definition::writeSourceReffedBy(OutputList &ol,const char *scopeName) +{ + makeResident(); + if (Config_getBool("REFERENCED_BY_RELATION")) + { + _writeSourceRefList(ol,scopeName,theTranslator->trReferencedBy(),m_impl->sourceRefByDict,FALSE); + } +} + +void Definition::writeSourceRefs(OutputList &ol,const char *scopeName) +{ + makeResident(); + if (Config_getBool("REFERENCES_RELATION")) + { + _writeSourceRefList(ol,scopeName,theTranslator->trReferences(),m_impl->sourceRefsDict,TRUE); + } +} + +bool Definition::hasDocumentation() const +{ + static bool extractAll = Config_getBool("EXTRACT_ALL"); + //static bool sourceBrowser = Config_getBool("SOURCE_BROWSER"); + makeResident(); + bool hasDocs = + (m_impl->details && !m_impl->details->doc.isEmpty()) || // has detailed docs + (m_impl->brief && !m_impl->brief->doc.isEmpty()) || // has brief description + (m_impl->inbodyDocs && !m_impl->inbodyDocs->doc.isEmpty()) || // has inbody docs + extractAll //|| // extract everything + // (sourceBrowser && m_impl->body && + // m_impl->body->startLine!=-1 && m_impl->body->fileDef) + ; // link to definition + return hasDocs; +} + +bool Definition::hasUserDocumentation() const +{ + makeResident(); + bool hasDocs = + (m_impl->details && !m_impl->details->doc.isEmpty()) || + (m_impl->brief && !m_impl->brief->doc.isEmpty()) || + (m_impl->inbodyDocs && !m_impl->inbodyDocs->doc.isEmpty()); + return hasDocs; +} + +void Definition::addSourceReferencedBy(MemberDef *md) +{ + if (md) + { + makeResident(); + QCString name = md->name(); + QCString scope = md->getScopeString(); + + if (!scope.isEmpty()) + { + name.prepend(scope+"::"); + } + + if (m_impl->sourceRefByDict==0) + { + m_impl->sourceRefByDict = new MemberSDict; + } + if (m_impl->sourceRefByDict->find(name)==0) + { + m_impl->sourceRefByDict->append(name,md); + } + } +} + +void Definition::addSourceReferences(MemberDef *md) +{ + if (md) + { + QCString name = md->name(); + QCString scope = md->getScopeString(); + makeResident(); + + if (!scope.isEmpty()) + { + name.prepend(scope+"::"); + } + + if (m_impl->sourceRefsDict==0) + { + m_impl->sourceRefsDict = new MemberSDict; + } + if (m_impl->sourceRefsDict->find(name)==0) + { + m_impl->sourceRefsDict->append(name,md); + } + } +} + +Definition *Definition::findInnerCompound(const char *) +{ + return 0; +} + +void Definition::addInnerCompound(Definition *) +{ + err("error: Definition::addInnerCompound() called\n"); +} + +QCString Definition::qualifiedName() const +{ + //static int count=0; + //count++; + makeResident(); + if (!m_impl->qualifiedName.isEmpty()) + { + //count--; + return m_impl->qualifiedName; + } + + //printf("start %s::qualifiedName() localName=%s\n",name().data(),m_impl->localName.data()); + if (m_impl->outerScope==0) + { + if (m_impl->localName=="<globalScope>") + { + //count--; + return ""; + } + else + { + //count--; + return m_impl->localName; + } + } + + if (m_impl->outerScope->name()=="<globalScope>") + { + m_impl->qualifiedName = m_impl->localName; + } + else + { + m_impl->qualifiedName = m_impl->outerScope->qualifiedName()+ + getLanguageSpecificSeparator(getLanguage())+ + m_impl->localName; + } + //printf("end %s::qualifiedName()=%s\n",name().data(),m_impl->qualifiedName.data()); + //count--; + return m_impl->qualifiedName; +}; + +void Definition::setOuterScope(Definition *d) +{ + makeResident(); + if (m_impl->outerScope!=d) + { + m_impl->qualifiedName.resize(0); // flush cached scope name + m_impl->outerScope = d; + } + m_impl->hidden = m_impl->hidden || d->isHidden(); +} + +QCString Definition::localName() const +{ + makeResident(); + return m_impl->localName; +} + +void Definition::makePartOfGroup(GroupDef *gd) +{ + makeResident(); + if (m_impl->partOfGroups==0) m_impl->partOfGroups = new GroupList; + m_impl->partOfGroups->append(gd); +} + +void Definition::setRefItems(const QList<ListItemInfo> *sli) +{ + //printf("%s::setRefItems()\n",name().data()); + if (sli) + { + makeResident(); + // deep copy the list + if (m_impl->xrefListItems==0) + { + m_impl->xrefListItems=new QList<ListItemInfo>; + m_impl->xrefListItems->setAutoDelete(TRUE); + } + QListIterator<ListItemInfo> slii(*sli); + ListItemInfo *lii; + for (slii.toFirst();(lii=slii.current());++slii) + { + m_impl->xrefListItems->append(new ListItemInfo(*lii)); + } + } +} + +void Definition::mergeRefItems(Definition *d) +{ + //printf("%s::mergeRefItems()\n",name().data()); + LockingPtr< QList<ListItemInfo> > xrefList = d->xrefListItems(); + if (xrefList!=0) + { + makeResident(); + // deep copy the list + if (m_impl->xrefListItems==0) + { + m_impl->xrefListItems=new QList<ListItemInfo>; + m_impl->xrefListItems->setAutoDelete(TRUE); + } + QListIterator<ListItemInfo> slii(*xrefList); + ListItemInfo *lii; + for (slii.toFirst();(lii=slii.current());++slii) + { + if (_getXRefListId(lii->type)==-1) + { + m_impl->xrefListItems->append(new ListItemInfo(*lii)); + } + } + } +} + +int Definition::_getXRefListId(const char *listName) const +{ + makeResident(); + if (m_impl->xrefListItems) + { + QListIterator<ListItemInfo> slii(*m_impl->xrefListItems); + ListItemInfo *lii; + for (slii.toFirst();(lii=slii.current());++slii) + { + if (strcmp(lii->type,listName)==0) + { + return lii->itemId; + } + } + } + return -1; +} + +LockingPtr< QList<ListItemInfo> > Definition::xrefListItems() const +{ + makeResident(); + return LockingPtr< QList<ListItemInfo> >(this,m_impl->xrefListItems); +} + + +QCString Definition::convertNameToFile(const char *name,bool allowDots) const +{ + makeResident(); + if (!m_impl->ref.isEmpty()) + { + return name; + } + else + { + return ::convertNameToFile(name,allowDots); + } +} + +QCString Definition::pathFragment() const +{ + makeResident(); + QCString result; + if (m_impl->outerScope && m_impl->outerScope!=Doxygen::globalScope) + { + result = m_impl->outerScope->pathFragment(); + } + if (isLinkable()) + { + if (!result.isEmpty()) result+="/"; + if (definitionType()==Definition::TypeGroup && ((const GroupDef*)this)->groupTitle()) + { + result+=((const GroupDef*)this)->groupTitle(); + } + else if (definitionType()==Definition::TypePage && !((const PageDef*)this)->title().isEmpty()) + { + result+=((const PageDef*)this)->title(); + } + else + { + result+=m_impl->localName; + } + } + else + { + result+=m_impl->localName; + } + return result; +} + +void Definition::writePathFragment(OutputList &ol) const +{ + makeResident(); + if (m_impl->outerScope && m_impl->outerScope!=Doxygen::globalScope) + { + m_impl->outerScope->writePathFragment(ol); + } + ol.writeString(" <li class=\"navelem\">"); + if (isLinkable()) + { + if (definitionType()==Definition::TypeGroup && ((const GroupDef*)this)->groupTitle()) + { + ol.writeObjectLink(getReference(),getOutputFileBase(),0,((const GroupDef*)this)->groupTitle()); + } + else if (definitionType()==Definition::TypePage && !((const PageDef*)this)->title().isEmpty()) + { + ol.writeObjectLink(getReference(),getOutputFileBase(),0,((const PageDef*)this)->title()); + } + else if (definitionType()==Definition::TypeClass) + { + QCString name = m_impl->localName; + if (name.right(2)=="-p" || name.right(2)=="-g") + { + name = name.left(name.length()-2); + } + ol.writeObjectLink(getReference(),getOutputFileBase(),0,name); + } + else + { + ol.writeObjectLink(getReference(),getOutputFileBase(),0,m_impl->localName); + } + } + else + { + ol.startBold(); + ol.docify(m_impl->localName); + ol.endBold(); + } + ol.writeString(" </li>\n"); +} + +void Definition::writeNavigationPath(OutputList &ol) const +{ + static bool generateTreeView = Config_getBool("GENERATE_TREEVIEW"); + + ol.pushGeneratorState(); + ol.disableAllBut(OutputGenerator::Html); + + if (generateTreeView) + { + ol.writeString("</div>\n"); + } + //if (showSearchInfo) + //{ + // ol.writeSearchInfo(); + //} + + ol.writeString(" <div id=\"nav-path\" class=\"navpath\">\n"); + ol.writeString(" <ul>\n"); + writePathFragment(ol); + if (!generateTreeView) + { + ol.writeString(" </ul>\n"); + ol.writeString(" </div>\n"); + } + + ol.popGeneratorState(); +} + +QCString Definition::symbolName() const +{ + return m_symbolName; +} + +//---------------------- + +QCString Definition::documentation() const +{ + makeResident(); + return m_impl->details ? m_impl->details->doc : QCString(""); +} + +int Definition::docLine() const +{ + makeResident(); + return m_impl->details ? m_impl->details->line : 1; +} + +QCString Definition::docFile() const +{ + makeResident(); + return m_impl->details ? m_impl->details->file : QCString("<"+m_name+">"); +} + +//---------------------- + +QCString Definition::briefDescription() const +{ + makeResident(); + return m_impl->brief ? m_impl->brief->doc : QCString(""); +} + +QCString Definition::briefDescriptionAsTooltip() const +{ + makeResident(); + LockingPtr<Definition> lock(this,this); // since this can be a memberDef + // accessing other memberDefs prevent + // it from being flushed to disk + if (m_impl->brief) + { + if (m_impl->brief->tooltip.isEmpty() && !m_impl->brief->doc.isEmpty()) + { + static bool reentering=FALSE; + if (!reentering) + { + MemberDef *md = definitionType()==TypeMember ? (MemberDef*)this : 0; + const Definition *scope = definitionType()==TypeMember ? getOuterScope() : this; + reentering=TRUE; // prevent requests for tooltips while parsing a tooltip + m_impl->brief->tooltip = parseCommentAsText( + scope,md, + m_impl->brief->doc, + m_impl->brief->file, + m_impl->brief->line); + reentering=FALSE; + } + } + return m_impl->brief->tooltip; + } + return QCString(""); +} + +int Definition::briefLine() const +{ + makeResident(); + return m_impl->brief ? m_impl->brief->line : 1; +} + +QCString Definition::briefFile() const +{ + makeResident(); + return m_impl->brief ? m_impl->brief->file : QCString("<"+m_name+">"); +} + +//---------------------- + +QCString Definition::inbodyDocumentation() const +{ + makeResident(); + return m_impl->inbodyDocs ? m_impl->inbodyDocs->doc : QCString(""); +} + +int Definition::inbodyLine() const +{ + makeResident(); + return m_impl->inbodyDocs ? m_impl->inbodyDocs->line : 1; +} + +QCString Definition::inbodyFile() const +{ + makeResident(); + return m_impl->inbodyDocs ? m_impl->inbodyDocs->file : QCString("<"+m_name+">"); +} + + +//---------------------- + +QCString Definition::getDefFileName() const +{ + makeResident(); + return m_impl->defFileName; +} + +QCString Definition::getDefFileExtension() const +{ + makeResident(); + return m_impl->defFileExt; +} + +bool Definition::isHidden() const +{ + makeResident(); + return m_impl->hidden; +} + +bool Definition::isVisibleInProject() const +{ + return isLinkableInProject() && !m_impl->hidden; +} + +bool Definition::isVisible() const +{ + return isLinkable() && !m_impl->hidden; +} + +bool Definition::isArtificial() const +{ + return m_impl->isArtificial; +} + +QCString Definition::getReference() const +{ + makeResident(); + return m_impl->ref; +} + +bool Definition::isReference() const +{ + makeResident(); + return !m_impl->ref.isEmpty(); +} + +int Definition::getStartBodyLine() const +{ + makeResident(); + return m_impl->body ? m_impl->body->startLine : -1; +} + +int Definition::getEndBodyLine() const +{ + makeResident(); + return m_impl->body ? m_impl->body->endLine : -1; +} + +FileDef *Definition::getBodyDef() +{ + makeResident(); + return m_impl->body ? m_impl->body->fileDef : 0; +} + +LockingPtr<GroupList> Definition::partOfGroups() const +{ + makeResident(); + return LockingPtr<GroupList>(this,m_impl->partOfGroups); +} + +Definition *Definition::getOuterScope() const +{ + makeResident(); + return m_impl->outerScope; +} + +LockingPtr<MemberSDict> Definition::getReferencesMembers() const +{ + makeResident(); + return LockingPtr<MemberSDict>(this,m_impl->sourceRefsDict); +} + +LockingPtr<MemberSDict> Definition::getReferencedByMembers() const +{ + makeResident(); + return LockingPtr<MemberSDict>(this,m_impl->sourceRefByDict); +} + +void Definition::setReference(const char *r) +{ + makeResident(); + m_impl->ref=r; +} + +SrcLangExt Definition::getLanguage() const +{ + makeResident(); + return m_impl->lang; +} + +void Definition::setHidden(bool b) +{ + makeResident(); + m_impl->hidden = m_impl->hidden || b; +} + +void Definition::setArtificial(bool b) +{ + makeResident(); + m_impl->isArtificial = b; +} + +void Definition::setLocalName(const QCString name) +{ + makeResident(); + m_impl->localName=name; +} + +void Definition::setLanguage(SrcLangExt lang) +{ + makeResident(); + m_impl->lang=lang; +} + +void Definition::makeResident() const +{ +} + +//--------------- + +void Definition::_setSymbolName(const QCString &name) +{ + m_symbolName=name; +} + +void Definition::flushToDisk() const +{ + //printf("%p: Definition::flushToDisk()\n",this); + Definition *that = (Definition *)this; + //printf("Definition::flushToDisk(): pos=%d\n",(int)m_storagePos); + marshalUInt(Doxygen::symbolStorage,START_MARKER); + marshalSectionDict (Doxygen::symbolStorage,m_impl->sectionDict); + marshalMemberSDict (Doxygen::symbolStorage,m_impl->sourceRefByDict); + marshalMemberSDict (Doxygen::symbolStorage,m_impl->sourceRefsDict); + marshalItemInfoList (Doxygen::symbolStorage,m_impl->xrefListItems); + marshalGroupList (Doxygen::symbolStorage,m_impl->partOfGroups); + marshalDocInfo (Doxygen::symbolStorage,m_impl->details); + marshalDocInfo (Doxygen::symbolStorage,m_impl->inbodyDocs); + marshalBriefInfo (Doxygen::symbolStorage,m_impl->brief); + marshalBodyInfo (Doxygen::symbolStorage,m_impl->body); + marshalQCString (Doxygen::symbolStorage,m_impl->docSignatures); + marshalQCString (Doxygen::symbolStorage,m_impl->localName); + marshalQCString (Doxygen::symbolStorage,m_impl->qualifiedName); + marshalQCString (Doxygen::symbolStorage,m_impl->ref); + marshalBool (Doxygen::symbolStorage,m_impl->hidden); + marshalBool (Doxygen::symbolStorage,m_impl->isArtificial); + marshalObjPointer (Doxygen::symbolStorage,m_impl->outerScope); + marshalQCString (Doxygen::symbolStorage,m_impl->defFileName); + marshalQCString (Doxygen::symbolStorage,m_impl->defFileExt); + marshalInt (Doxygen::symbolStorage,(int)m_impl->lang); + marshalUInt(Doxygen::symbolStorage,END_MARKER); + delete that->m_impl; + that->m_impl = 0; +} + +void Definition::loadFromDisk() const +{ + //printf("%p: Definition::loadFromDisk()\n",this); + Definition *that = (Definition *)this; + assert(m_impl==0); + that->m_impl = new DefinitionImpl; + uint marker = unmarshalUInt(Doxygen::symbolStorage); + assert(marker==START_MARKER); + m_impl->sectionDict = unmarshalSectionDict (Doxygen::symbolStorage); + m_impl->sourceRefByDict = unmarshalMemberSDict (Doxygen::symbolStorage); + m_impl->sourceRefsDict = unmarshalMemberSDict (Doxygen::symbolStorage); + m_impl->xrefListItems = unmarshalItemInfoList (Doxygen::symbolStorage); + m_impl->partOfGroups = unmarshalGroupList (Doxygen::symbolStorage); + m_impl->details = unmarshalDocInfo (Doxygen::symbolStorage); + m_impl->inbodyDocs = unmarshalDocInfo (Doxygen::symbolStorage); + m_impl->brief = unmarshalBriefInfo (Doxygen::symbolStorage); + m_impl->body = unmarshalBodyInfo (Doxygen::symbolStorage); + m_impl->docSignatures = unmarshalQCString (Doxygen::symbolStorage); + m_impl->localName = unmarshalQCString (Doxygen::symbolStorage); + m_impl->qualifiedName = unmarshalQCString (Doxygen::symbolStorage); + m_impl->ref = unmarshalQCString (Doxygen::symbolStorage); + m_impl->hidden = unmarshalBool (Doxygen::symbolStorage); + m_impl->isArtificial = unmarshalBool (Doxygen::symbolStorage); + m_impl->outerScope = (Definition *)unmarshalObjPointer (Doxygen::symbolStorage); + m_impl->defFileName = unmarshalQCString (Doxygen::symbolStorage); + m_impl->defFileExt = unmarshalQCString (Doxygen::symbolStorage); + m_impl->lang = (SrcLangExt)unmarshalInt(Doxygen::symbolStorage); + marker = unmarshalUInt(Doxygen::symbolStorage); + assert(marker==END_MARKER); +} + diff --git a/trunk/src/definition.h b/trunk/src/definition.h new file mode 100644 index 0000000..e09a478 --- /dev/null +++ b/trunk/src/definition.h @@ -0,0 +1,386 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#ifndef DEFINITION_H +#define DEFINITION_H + +#include "qtbc.h" +#include <qlist.h> +#include <qdict.h> +#include <sys/types.h> + +#include "lockingptr.h" +#include "util.h" + +class FileDef; +class OutputList; +class SectionDict; +class MemberSDict; +class MemberDef; +class GroupDef; +class GroupList; +struct ListItemInfo; +struct SectionInfo; +class Definition; +class DefinitionImpl; + +#if 0 +struct ReachableDefinition +{ + ReachableDefinition(Definition *d,int dist) : def(d), distance(dist) {} + Definition *def; + int distance; +}; +#endif + +struct DocInfo +{ + QCString doc; + int line; + QCString file; +}; + +struct BriefInfo +{ + QCString doc; + QCString tooltip; + int line; + QCString file; +}; + +struct BodyInfo +{ + int startLine; // line number of the start of the definition + int endLine; // line number of the end of the definition + FileDef *fileDef; // file definition containing the function body +}; + +/*! Abstract interface for a Definition or DefinitionList */ +class DefinitionIntf +{ + public: + DefinitionIntf() {} + virtual ~DefinitionIntf() {} + /*! Types of derived classes */ + enum DefType + { + TypeClass = 0, + TypeFile = 1, + TypeNamespace = 2, + TypeMember = 3, + TypeGroup = 4, + TypePackage = 5, + TypePage = 6, + TypeDir = 7, + TypeSymbolList = 8 + }; + /*! Use this for dynamic inspection of the type of the derived class */ + virtual DefType definitionType() const = 0; +}; + +/*! The common base class of all entity definitions found in the sources. + * This can be a class or a member function, or a file, or a namespace, etc. + * Use definitionType() to find which type of definition this is. + */ +class Definition : public DefinitionIntf, public LockableObj +{ + public: + + /*! Create a new definition */ + Definition( + const char *defFileName,int defLine, + const char *name,const char *b=0,const char *d=0, + bool isSymbol=TRUE); + + /*! Destroys the definition */ + virtual ~Definition(); + + //----------------------------------------------------------------------------------- + // ---- getters ----- + //----------------------------------------------------------------------------------- + + /*! Returns the name of the definition */ + const QCString& name() const { return m_name; } + + /*! Returns the name of the definition as it appears in the output */ + virtual QCString displayName() const = 0; + + /*! Returns the local name without any scope qualifiers. */ + QCString localName() const; + + /*! Returns the fully qualified name of this definition + */ + virtual QCString qualifiedName() const; + + /*! Returns the name of this definition as it appears in the symbol map. + */ + QCString symbolName() const; + + /*! Returns the base file name (without extension) of this definition. + * as it is referenced to/written to disk. + */ + virtual QCString getOutputFileBase() const = 0; + + /*! Returns the anchor within a page where this item can be found */ + virtual QCString anchor() const = 0; + + /*! Returns the name of the source listing of this file. */ + virtual QCString getSourceFileBase() const { ASSERT(0); return "NULL"; } + + /*! Returns the detailed description of this definition */ + QCString documentation() const; + + /*! Returns the line number at which the detailed documentation was found. */ + int docLine() const; + + /*! Returns the file in which the detailed documentation block was found. + * This can differ from getDefFileName(). + */ + QCString docFile() const; + + /*! Returns the brief description of this definition. This can include commands. */ + QCString briefDescription() const; + + /*! Returns a plain text version of the brief description suitable for use + * as a tool tip. + */ + QCString briefDescriptionAsTooltip() const; + + /*! Returns the line number at which the brief description was found. */ + int briefLine() const; + + /*! Returns the documentation found inside the body of a member */ + QCString inbodyDocumentation() const; + + /*! Returns the file in which the in body documentation was found */ + QCString inbodyFile() const; + + /*! Returns the line at which the first in body documentation + part was found */ + int inbodyLine() const; + + /*! Returns the file in which the brief description was found. + * This can differ from getDefFileName(). + */ + QCString briefFile() const; + + /*! returns the file in which this definition was found */ + QCString getDefFileName() const; + + /*! returns the extension of the file in which this definition was found */ + QCString getDefFileExtension() const; + + /*! returns the line number at which the definition was found */ + int getDefLine() const { return m_defLine; } + + /*! Returns TRUE iff the definition is documented + * (which could be generated documentation) + * @see hasUserDocumentation() + */ + virtual bool hasDocumentation() const; + + /*! Returns TRUE iff the definition is documented by the user. */ + virtual bool hasUserDocumentation() const; + + /*! Returns TRUE iff it is possible to link to this item within this + * project. + */ + virtual bool isLinkableInProject() const = 0; + + /*! Returns TRUE iff it is possible to link to this item. This can + * be a link to another project imported via a tag file. + */ + virtual bool isLinkable() const = 0; + + /*! Returns TRUE iff the name is part of this project and + * may appear in the output + */ + virtual bool isVisibleInProject() const; + + /*! Returns TRUE iff the name may appear in the output */ + virtual bool isVisible() const; + + /*! Returns TRUE iff this item is supposed to be hidden from the output. */ + bool isHidden() const; + + /*! returns TRUE if this entity was artificially introduced, for + * instance because it is used to show a template instantiation relation. + */ + bool isArtificial() const; + + /*! If this definition was imported via a tag file, this function + * returns the tagfile for the external project. This can be + * translated into an external link target via + * Doxygen::tagDestinationDict + */ + virtual QCString getReference() const; + + /*! Returns TRUE if this definition is imported via a tag file. */ + virtual bool isReference() const; + + /*! Returns the first line of the body of this item (applicable to classes and + * functions). + */ + int getStartBodyLine() const; + + /*! Returns the last line of the body of this item (applicable to classes and + * functions). + */ + int getEndBodyLine() const; + + /*! Returns the file in which the body of this item is located or 0 if no + * body is available. + */ + FileDef *getBodyDef(); + + /** Returns the programming language this definition was written in. */ + SrcLangExt getLanguage() const; + + LockingPtr<GroupList> partOfGroups() const; + + LockingPtr< QList<ListItemInfo> > xrefListItems() const; + + virtual Definition *findInnerCompound(const char *name); + virtual Definition *getOuterScope() const; + + LockingPtr<MemberSDict> getReferencesMembers() const; + LockingPtr<MemberSDict> getReferencedByMembers() const; + + bool hasSections() const; + + //----------------------------------------------------------------------------------- + // ---- setters ----- + //----------------------------------------------------------------------------------- + + /*! Sets a new \a name for the definition */ + void setName(const char *name); + + /*! Sets the documentation of this definition to \a d. */ + virtual void setDocumentation(const char *d,const char *docFile,int docLine,bool stripWhiteSpace=TRUE); + + /*! Sets the brief description of this definition to \a b. + * A dot is added to the sentence if not available. + */ + virtual void setBriefDescription(const char *b,const char *briefFile,int briefLine); + + /*! Set the documentation that was found inside the body of an item. + * If there was already some documentation set, the new documentation + * will be appended. + */ + virtual void setInbodyDocumentation(const char *d,const char *docFile,int docLine); + + /*! Sets the tag file id via which this definition was imported. */ + void setReference(const char *r); + + /*! Add the list of anchors that mark the sections that are found in the + * documentation. + */ + void addSectionsToDefinition(QList<SectionInfo> *anchorList); + + // source references + void setBodySegment(int bls,int ble); + void setBodyDef(FileDef *fd); + void addSourceReferencedBy(MemberDef *d); + void addSourceReferences(MemberDef *d); + + void setRefItems(const QList<ListItemInfo> *sli); + void mergeRefItems(Definition *d); + virtual void addInnerCompound(Definition *d); + virtual void setOuterScope(Definition *d); + + virtual void setHidden(bool b); + + void setArtificial(bool b); + void setLanguage(SrcLangExt lang); + + //----------------------------------------------------------------------------------- + // --- actions ---- + //----------------------------------------------------------------------------------- + + QCString convertNameToFile(const char *name,bool allowDots=FALSE) const; + void writeSourceDef(OutputList &ol,const char *scopeName); + void writeInlineCode(OutputList &ol,const char *scopeName); + void writeSourceRefs(OutputList &ol,const char *scopeName); + void writeSourceReffedBy(OutputList &ol,const char *scopeName); + void makePartOfGroup(GroupDef *gd); + void writePathFragment(OutputList &ol) const; + void writeNavigationPath(OutputList &ol) const; + virtual void writeQuickMemberLinks(OutputList &,MemberDef *) const {} + virtual void writeSummaryLinks(OutputList &) {} + QCString pathFragment() const; + + /*! Writes the documentation anchors of the definition to + * the Doxygen::tagFile stream. + */ + void writeDocAnchorsToTagFile(); + void setLocalName(const QCString name); + + void addSectionsToIndex(); + void writeToc(OutputList &ol); + + protected: + + virtual void flushToDisk() const; + virtual void loadFromDisk() const; + virtual void makeResident() const; + void lock() const {} + void unlock() const {} + + private: + + static void addToMap(const char *name,Definition *d); + static void removeFromMap(Definition *d); + + void _setSymbolName(const QCString &name); + + int _getXRefListId(const char *listName) const; + void _writeSourceRefList(OutputList &ol,const char *scopeName, + const QCString &text,MemberSDict *members,bool); + void _setBriefDescription(const char *b,const char *briefFile,int briefLine); + void _setDocumentation(const char *d,const char *docFile,int docLine,bool stripWhiteSpace,bool atTop); + void _setInbodyDocumentation(const char *d,const char *docFile,int docLine); + bool _docsAlreadyAdded(const QCString &doc); + DefinitionImpl *m_impl; // internal structure holding all private data + QCString m_name; + bool m_isSymbol; + QCString m_symbolName; + int m_defLine; +}; + +class DefinitionList : public QList<Definition>, public DefinitionIntf +{ + public: + ~DefinitionList() {} + DefType definitionType() const { return TypeSymbolList; } + int compareItems(GCI item1,GCI item2) + { + return stricmp(((Definition *)item1)->name(), + ((Definition *)item2)->name() + ); + } + +}; + +class DefinitionListIterator : public QListIterator<Definition> +{ + public: + DefinitionListIterator(const DefinitionList &l) : + QListIterator<Definition>(l) {} + ~DefinitionListIterator() {} +}; + +#endif diff --git a/trunk/src/diagram.cpp b/trunk/src/diagram.cpp new file mode 100644 index 0000000..07fb4aa --- /dev/null +++ b/trunk/src/diagram.cpp @@ -0,0 +1,1306 @@ +/****************************************************************************** + * + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#include "qtbc.h" +#include <stdio.h> +#include <stdlib.h> +#include <qlist.h> +#include <qarray.h> +#include "ftextstream.h" +#include <qfile.h> + +#include "diagram.h" +#include "image.h" +#include "classdef.h" +#include "config.h" +#include "message.h" +#include "util.h" +#include "doxygen.h" +#include "portable.h" +#include "index.h" + +//----------------------------------------------------------------------------- + +const uint maxTreeWidth = 8; +const int gridWidth = 100; +const int gridHeight = 100; + +const uint labelHorSpacing = 10; // horizontal distance between labels +const uint labelVertSpacing = 32; // vertical distance between labels +const uint labelHorMargin = 6; // horiz. spacing between label and box +const uint fontHeight = 12; // height of a character + +//static QCString escapeLatex(const char *s) +//{ +// QCString result; +// char c; +// while ((c=*s++)) +// { +// if (c=='_') result+="\\_"; +// else result+=c; +// } +// return result; +//} + +static uint protToMask(Protection p) +{ + switch(p) + { + case Public: return 0xffffffff; + case Package: // package is not possible! + case Protected: return 0xcccccccc; + case Private: return 0xaaaaaaaa; + } + return 0; +} + +static uint protToColor(Protection p) +{ + switch(p) + { + case Public: return 6; + case Package: // package is not possible! + case Protected: return 5; + case Private: return 4; + } + return 0; +} + +static QCString protToString(Protection p) +{ + switch(p) + { + case Public: return "solid"; + case Package: // package is not possible! + case Protected: return "dashed"; + case Private: return "dotted"; + } + return 0; +} + +static uint virtToMask(Specifier p) +{ + switch(p) + { + case Normal: return 0xffffffff; + case Virtual: return 0xf0f0f0f0; + default: return 0; + } + return 0; +} + +// pre: dil is not empty +static Protection getMinProtectionLevel(DiagramItemList *dil) +{ + DiagramItem *di=dil->first(); + Protection result=di->protection(); + di=dil->next(); + while (di) + { + Protection p=di->protection(); + if (p!=result) + { + if (result==Protected && p==Public) result=p; + else if (result==Private) result=p; + } + di=dil->next(); + } + return result; +} + +static void writeBitmapBox(DiagramItem *di,Image *image, + int x,int y,int w,int h,bool firstRow, + bool hasDocs,bool children=FALSE) +{ + int colFill = hasDocs ? (firstRow ? 0 : 2) : 7; + int colBorder = (firstRow || !hasDocs) ? 1 : 3; + int l = Image::stringLength(di->label()); + uint mask=virtToMask(di->virtualness()); + image->fillRect(x+1,y+1,w-2,h-2,colFill,mask); + image->drawRect(x,y,w,h,colBorder,mask); + image->writeString(x+(w-l)/2, y+(h-fontHeight)/2, di->label(),1); + if (children) + { + int i; + for (i=0;i<5;i++) + image->drawHorzLine(y+h+i-6,x+w-2-i,x+w-2,firstRow?1:3,0xffffffff); + } +} + +static void writeVectorBox(FTextStream &t,DiagramItem *di, + float x,float y,bool children=FALSE) +{ + if (di->virtualness()==Virtual) t << "dashed\n"; + t << " (" << di->label() << ") " << x << " " << y << " box\n"; + if (children) t << x << " " << y << " mark\n"; + if (di->virtualness()==Virtual) t << "solid\n"; +} + +static void writeMapArea(FTextStream &t,ClassDef *cd,QCString relPath, + int x,int y,int w,int h) +{ + if (cd->isLinkable()) + { + QCString ref=cd->getReference(); + t << "<area "; + if (!ref.isEmpty()) + { + t << externalLinkTarget() << externalRef(relPath,ref,FALSE); + } + t << "href=\""; + t << externalRef(relPath,ref,TRUE); + t << cd->getOutputFileBase() << Doxygen::htmlFileExtension; + if (!cd->anchor().isEmpty()) + { + t << "#" << cd->anchor(); + } + t << "\" "; + QCString tooltip = cd->briefDescriptionAsTooltip(); + if (!tooltip.isEmpty()) + { + t << "title=\"" << tooltip << "\" "; + } + t << "alt=\"" << convertToXML(cd->displayName()); + t << "\" shape=\"rect\" coords=\"" << x << "," << y << ","; + t << (x+w) << "," << (y+h) << "\"/>" << endl; + } +} +//----------------------------------------------------------------------------- + +DiagramItem::DiagramItem(DiagramItem *p,int number,ClassDef *cd, + Protection pr,Specifier vi,const char *ts) +{ + parent=p; + x=y=0; + //name=n; + num=number; + children = new DiagramItemList; + prot=pr; + virt=vi; + inList=FALSE; + classDef=cd; + templSpec=ts; +} + +DiagramItem::~DiagramItem() +{ + delete children; +} + +QCString DiagramItem::label() const +{ + QCString result; + if (!templSpec.isEmpty()) + { + // we use classDef->name() here and not diplayName() in order + // to get the name used in the inheritance relation. + QCString n = classDef->name(); + if (n.right(2)=="-g" || n.right(2)=="-p") + { + n = n.left(n.length()-2); + } + result=insertTemplateSpecifierInScope(n,templSpec); + } + else + { + result=classDef->displayName(); + } + if (Config_getBool("HIDE_SCOPE_NAMES")) result=stripScope(result); + return result; +} + +QCString DiagramItem::fileName() const +{ + return classDef->getOutputFileBase(); +} + +int DiagramItem::avgChildPos() const +{ + DiagramItem *di; + int c=children->count(); + if (c==0) // no children -> don't move + return xPos(); + if ((di=children->getFirst())->isInList()) // children should be in a list + return di->xPos(); + if (c&1) // odd number of children -> get pos of middle child + return children->at(c/2)->xPos(); + else // even number of children -> get middle of most middle children + return (children->at(c/2-1)->xPos()+children->at(c/2)->xPos())/2; +} + +int DiagramItem::numChildren() const +{ + return children->count(); +} + +void DiagramItem::addChild(DiagramItem *di) +{ + children->append(di); +} + +void DiagramRow::insertClass(DiagramItem *parent,ClassDef *cd,bool doBases, + Protection prot,Specifier virt,const char *ts) +{ + //if (cd->visited) return; // the visit check does not work in case of + // multiple inheritance of the same class! + DiagramItem *di=new DiagramItem(parent, diagram->at(level)->count(), + cd,prot,virt,ts); + //cd->visited=TRUE; + if (parent) parent->addChild(di); + di->move(count()*gridWidth,level*gridHeight); + append(di); + BaseClassList *bcl=doBases ? cd->baseClasses() : cd->subClasses(); + int count=0; + if (bcl) + { + /* there are base/sub classes */ + BaseClassDef *bcd=bcl->first(); + while (bcd) + { + ClassDef *ccd=bcd->classDef; + if (ccd && ccd->isVisibleInHierarchy() /*&& !ccd->visited*/) count++; + bcd=bcl->next(); + } + } + if (count>0 && (prot!=Private || !doBases)) + { + DiagramRow *row=0; + if (diagram->count()<=level+1) /* add new row */ + { + row = new DiagramRow(diagram,level+1); + diagram->append(row); + } + else /* get next row */ + { + row=diagram->at(level+1); + } + /* insert base classes in the next row */ + BaseClassDef *bcd=bcl->first(); + while (bcd) + { + ClassDef *ccd=bcd->classDef; + if (ccd && ccd->isVisibleInHierarchy() /*&& !ccd->visited*/) + { + row->insertClass(di,ccd,doBases,bcd->prot, + doBases?bcd->virt:Normal, + doBases?bcd->templSpecifiers.data():""); + } + bcd=bcl->next(); + } + } +} + +TreeDiagram::TreeDiagram(ClassDef *root,bool doBases) +{ + setAutoDelete(TRUE); + DiagramRow *row=new DiagramRow(this,0); + append(row); + row->insertClass(0,root,doBases,Public,Normal,0); +} + +TreeDiagram::~TreeDiagram() +{ +} + + +void TreeDiagram::moveChildren(DiagramItem *root,int dx) +{ + DiagramItemList *dil=root->getChildren(); + DiagramItem *di=dil->first(); + while (di) + { + di->move(dx,0); + moveChildren(di,dx); + di=dil->next(); + } +} + +bool TreeDiagram::layoutTree(DiagramItem *root,int r) +{ + bool moved=FALSE; + //printf("layoutTree(%s,%d)\n",root->label().data(),r); + + DiagramItemList *dil=root->getChildren(); + if (dil->count()>0) + { + uint k; + int pPos=root->xPos(); + int cPos=root->avgChildPos(); + if (pPos>cPos) // move children + { + DiagramRow *row=at(r+1); + //printf("Moving children %d-%d in row %d\n", + // dil->getFirst()->number(),row->count()-1,r+1); + for (k=dil->getFirst()->number();k<row->count();k++) + row->at(k)->move(pPos-cPos,0); + moved=TRUE; + } + else if (pPos<cPos) // move parent + { + DiagramRow *row=at(r); + //printf("Moving parents %d-%d in row %d\n", + // root->number(),row->count()-1,r); + for (k=root->number();k<row->count();k++) + row->at(k)->move(cPos-pPos,0); + moved=TRUE; + } + + // recurse to children + DiagramItem *di=dil->first(); + while (di && !moved && !di->isInList()) + { + moved = layoutTree(di,r+1); + di=dil->next(); + } + } + return moved; +} + +void TreeDiagram::computeLayout() +{ + DiagramRow *row=first(); + while (row && row->count()<maxTreeWidth) row=next(); + if (row) + { + //printf("computeLayout() list row at %d\n",row->number()); + DiagramItem *di=row->first(); + DiagramItem *opi=0; + int delta=0; + bool first=TRUE; + while (di) + { + DiagramItem *pi=di->parentItem(); + if (pi==opi && !first) { delta-=gridWidth; } + first = pi!=opi; + opi=pi; + di->move(delta,0); // collapse all items in the same + // list (except the first) + di->putInList(); + di=row->next(); + } + } + + // re-organize the diagram items + DiagramItem *root=getFirst()->getFirst(); + while (layoutTree(root,0)) { } + + // move first items of the lists + if (row) + { + DiagramItem *di=row->first(); + while (di) + { + DiagramItem *pi=di->parentItem(); + if (pi->getChildren()->count()>1) + { + di->move(gridWidth,0); + while (di && di->parentItem()==pi) di=row->next(); + } + else + { + di=row->next(); + } + } + } +} + +uint TreeDiagram::computeRows() +{ + //printf("TreeDiagram::computeRows()=%d\n",count()); + int count=0; + DiagramRow *row=first(); + while (row && !row->getFirst()->isInList()) + { + count++; + row=next(); + } + //printf("count=%d row=%p\n",count,row); + if (row) + { + int maxListLen=0; + int curListLen=0; + DiagramItem *di=row->first(),*opi=0; + while (di) + { + if (di->parentItem()!=opi) curListLen=1; else curListLen++; + if (curListLen>maxListLen) maxListLen=curListLen; + opi=di->parentItem(); + di=row->next(); + } + //printf("maxListLen=%d\n",maxListLen); + count+=maxListLen; + } + return count; +} + +#if 0 +uint TreeDiagram::computeCols() +{ + uint count=0; + DiagramRow *row=first(); + while (row && !row->getFirst()->isInList()) + { + if (row->count()>count) count=row->count(); + row=next(); + } + if (row) + { + row=prev(); + uint cols=row->count(); + if (row->getLast()->getChildren()->count()>1) cols++; + if (cols>count) count=cols; + } + return count; +}; +#endif + +void TreeDiagram::computeExtremes(uint *maxLabelLen,uint *maxXPos) +{ + uint ml=0,mx=0; + DiagramRow *dr=first(); + bool done=FALSE; + while (dr && !done) + { + DiagramItem *di=dr->first(); + while (di) + { + if (di->isInList()) done=TRUE; + if (maxXPos) mx=QMAX(mx,(uint)di->xPos()); + if (maxLabelLen) ml=QMAX(ml,Image::stringLength(di->label())); + di=dr->next(); + } + dr=next(); + } + if (maxLabelLen) *maxLabelLen=ml; + if (maxXPos) *maxXPos=mx; +} + +void TreeDiagram::drawBoxes(FTextStream &t,Image *image, + bool doBase,bool bitmap, + uint baseRows,uint superRows, + uint cellWidth,uint cellHeight, + QCString relPath, + bool generateMap) +{ + DiagramRow *dr=first(); + if (!doBase) dr=next(); + bool done=FALSE; + bool firstRow = doBase; + while (dr && !done) + { + int x=0,y=0; + float xf=0.0,yf=0.0; + DiagramItem *di=dr->first(); + if (di->isInList()) // put boxes in a list + { + DiagramItem *opi=0; + if (doBase) di=dr->last(); + while (di) + { + if (di->parentItem()==opi) + { + if (bitmap) + { + if (doBase) y -= cellHeight+labelVertSpacing; + else y += cellHeight+labelVertSpacing; + } + else + { + if (doBase) yf += 1.0; + else yf -= 1.0; + } + } + else + { + if (bitmap) + { + x = di->xPos()*(cellWidth+labelHorSpacing)/gridWidth; + if (doBase) + { + y = image->getHeight()- + superRows*cellHeight- + (superRows-1)*labelVertSpacing- + di->yPos()*(cellHeight+labelVertSpacing)/gridHeight; + } + else + { + y = (baseRows-1)*(cellHeight+labelVertSpacing)+ + di->yPos()*(cellHeight+labelVertSpacing)/gridHeight; + } + } + else + { + xf = di->xPos()/(float)gridWidth; + if (doBase) + { + yf = di->yPos()/(float)gridHeight+superRows-1; + } + else + { + yf = superRows-1-di->yPos()/(float)gridHeight; + } + } + } + opi=di->parentItem(); + + if (bitmap) + { + bool hasDocs=di->getClassDef()->isLinkable(); + writeBitmapBox(di,image,x,y,cellWidth,cellHeight,firstRow, + hasDocs,di->getChildren()->count()>0); + if (!firstRow && generateMap) + writeMapArea(t,di->getClassDef(),relPath,x,y,cellWidth,cellHeight); + } + else + { + writeVectorBox(t,di,xf,yf,di->getChildren()->count()>0); + } + + if (doBase) di=dr->prev(); else di=dr->next(); + } + done=TRUE; + } + else // draw a tree of boxes + { + while (di) + { + if (bitmap) + { + x = di->xPos()*(cellWidth+labelHorSpacing)/gridWidth; + if (doBase) + { + y = image->getHeight()- + superRows*cellHeight- + (superRows-1)*labelVertSpacing- + di->yPos()*(cellHeight+labelVertSpacing)/gridHeight; + } + else + { + y = (baseRows-1)*(cellHeight+labelVertSpacing)+ + di->yPos()*(cellHeight+labelVertSpacing)/gridHeight; + } + bool hasDocs=di->getClassDef()->isLinkable(); + writeBitmapBox(di,image,x,y,cellWidth,cellHeight,firstRow,hasDocs); + if (!firstRow && generateMap) + writeMapArea(t,di->getClassDef(),relPath,x,y,cellWidth,cellHeight); + } + else + { + xf=di->xPos()/(float)gridWidth; + if (doBase) + { + yf = di->yPos()/(float)gridHeight+superRows-1; + } + else + { + yf = superRows-1-di->yPos()/(float)gridHeight; + } + writeVectorBox(t,di,xf,yf); + } + + di=dr->next(); + } + } + dr=next(); + firstRow=FALSE; + } +} + +void TreeDiagram::drawConnectors(FTextStream &t,Image *image, + bool doBase,bool bitmap, + uint baseRows,uint superRows, + uint cellWidth,uint cellHeight) +{ + DiagramRow *dr=first(); + bool done=FALSE; + while (dr && !done) // for each row + { + DiagramItem *di=dr->first(); + if (di->isInList()) // row consists of list connectors + { + int x=0,y=0,ys=0; + float xf=0.0,yf=0.0,ysf=0.0; + while (di) + { + DiagramItem *pi=di->parentItem(); + DiagramItemList *dil=pi->getChildren(); + DiagramItem *last=dil->getLast(); + if (di==last) // single child + { + if (bitmap) // draw pixels + { + x = di->xPos()*(cellWidth+labelHorSpacing)/gridWidth + cellWidth/2; + if (doBase) // base classes + { + y = image->getHeight()- + (superRows-1)*(cellHeight+labelVertSpacing)- + di->yPos()*(cellHeight+labelVertSpacing)/gridHeight; + image->drawVertArrow(x,y,y+labelVertSpacing/2, + protToColor(di->protection()), + protToMask(di->protection())); + } + else // super classes + { + y = (baseRows-1)*(cellHeight+labelVertSpacing)- + labelVertSpacing/2+ + di->yPos()*(cellHeight+labelVertSpacing)/gridHeight; + image->drawVertLine(x,y,y+labelVertSpacing/2, + protToColor(di->protection()), + protToMask(di->protection())); + } + } + else // draw vectors + { + t << protToString(di->protection()) << endl; + if (doBase) + { + t << "1 " << (di->xPos()/(float)gridWidth) << " " + << (di->yPos()/(float)gridHeight+superRows-1) << " in\n"; + } + else + { + t << "0 " << (di->xPos()/(float)gridWidth) << " " + << ((float)superRows-0.25-di->yPos()/(float)gridHeight) + << " in\n"; + } + } + } + else // multiple children, put them in a vertical list + { + if (bitmap) + { + x = di->parentItem()->xPos()* + (cellWidth+labelHorSpacing)/gridWidth+cellWidth/2; + if (doBase) // base classes + { + ys = image->getHeight()- + (superRows-1)*(cellHeight+labelVertSpacing)- + di->yPos()*(cellHeight+labelVertSpacing)/gridHeight; + y = ys - cellHeight/2; + } + else // super classes + { + ys = (baseRows-1)*(cellHeight+labelVertSpacing)+ + di->yPos()*(cellHeight+labelVertSpacing)/gridHeight; + y = ys + cellHeight/2; + } + } + else + { + xf = di->parentItem()->xPos()/(float)gridWidth; + if (doBase) + { + ysf = di->yPos()/(float)gridHeight+superRows-1; + yf = ysf + 0.5; + } + else + { + ysf = (float)superRows-0.25-di->yPos()/(float)gridHeight; + yf = ysf - 0.25; + } + } + while (di!=last) // more children to add + { + if (bitmap) + { + if (doBase) // base classes + { + image->drawHorzArrow(y,x,x+cellWidth/2+labelHorSpacing, + protToColor(di->protection()), + protToMask(di->protection())); + y -= cellHeight+labelVertSpacing; + } + else // super classes + { + image->drawHorzLine(y,x,x+cellWidth/2+labelHorSpacing, + protToColor(di->protection()), + protToMask(di->protection())); + y += cellHeight+labelVertSpacing; + } + } + else + { + t << protToString(di->protection()) << endl; + if (doBase) + { + t << "1 " << xf << " " << yf << " hedge\n"; + yf += 1.0; + } + else + { + t << "0 " << xf << " " << yf << " hedge\n"; + yf -= 1.0; + } + } + di=dr->next(); + } + // add last horizonal line and a vertical connection line + if (bitmap) + { + if (doBase) // base classes + { + image->drawHorzArrow(y,x,x+cellWidth/2+labelHorSpacing, + protToColor(di->protection()), + protToMask(di->protection())); + image->drawVertLine(x,y,ys+labelVertSpacing/2, + protToColor(getMinProtectionLevel(dil)), + protToMask(getMinProtectionLevel(dil))); + } + else // super classes + { + image->drawHorzLine(y,x,x+cellWidth/2+labelHorSpacing, + protToColor(di->protection()), + protToMask(di->protection())); + image->drawVertLine(x,ys-labelVertSpacing/2,y, + protToColor(getMinProtectionLevel(dil)), + protToMask(getMinProtectionLevel(dil))); + } + } + else + { + t << protToString(di->protection()) << endl; + if (doBase) + { + t << "1 " << xf << " " << yf << " hedge\n"; + } + else + { + t << "0 " << xf << " " << yf << " hedge\n"; + } + t << protToString(getMinProtectionLevel(dil)) << endl; + if (doBase) + { + t << xf << " " << ysf << " " << yf << " vedge\n"; + } + else + { + t << xf << " " << (ysf + 0.25) << " " << yf << " vedge\n"; + } + } + } + di=dr->next(); + } + done=TRUE; // the tree is drawn now + } + else // normal tree connector + { + while (di) + { + int x=0,y=0; + DiagramItemList *dil = di->getChildren(); + DiagramItem *parent = di->parentItem(); + if (parent) // item has a parent -> connect to it + { + if (bitmap) // draw pixels + { + x = di->xPos()*(cellWidth+labelHorSpacing)/gridWidth + cellWidth/2; + if (doBase) // base classes + { + y = image->getHeight()- + (superRows-1)*(cellHeight+labelVertSpacing)- + di->yPos()*(cellHeight+labelVertSpacing)/gridHeight; + /* write input line */ + image->drawVertArrow(x,y,y+labelVertSpacing/2, + protToColor(di->protection()), + protToMask(di->protection())); + } + else // super classes + { + y = (baseRows-1)*(cellHeight+labelVertSpacing)- + labelVertSpacing/2+ + di->yPos()*(cellHeight+labelVertSpacing)/gridHeight; + /* write output line */ + image->drawVertLine(x,y,y+labelVertSpacing/2, + protToColor(di->protection()), + protToMask(di->protection())); + } + } + else // draw pixels + { + t << protToString(di->protection()) << endl; + if (doBase) + { + t << "1 " << di->xPos()/(float)gridWidth << " " + << (di->yPos()/(float)gridHeight+superRows-1) << " in\n"; + } + else + { + t << "0 " << di->xPos()/(float)gridWidth << " " + << ((float)superRows-0.25-di->yPos()/(float)gridHeight) + << " in\n"; + } + } + } + if (dil->count()>0) + { + Protection p=getMinProtectionLevel(dil); + uint mask=protToMask(p); + uint col=protToColor(p); + if (bitmap) + { + x = di->xPos()*(cellWidth+labelHorSpacing)/gridWidth + cellWidth/2; + if (doBase) // base classes + { + y = image->getHeight()- + (superRows-1)*(cellHeight+labelVertSpacing)- + cellHeight-labelVertSpacing/2- + di->yPos()*(cellHeight+labelVertSpacing)/gridHeight; + image->drawVertLine(x,y,y+labelVertSpacing/2-1,col,mask); + } + else // super classes + { + y = (baseRows-1)*(cellHeight+labelVertSpacing)+ + cellHeight+ + di->yPos()*(cellHeight+labelVertSpacing)/gridHeight; + image->drawVertArrow(x,y,y+labelVertSpacing/2-1,col,mask); + } + } + else + { + t << protToString(p) << endl; + if (doBase) + { + t << "0 " << di->xPos()/(float)gridWidth << " " + << (di->yPos()/(float)gridHeight+superRows-1) << " out\n"; + } + else + { + t << "1 " << di->xPos()/(float)gridWidth << " " + << ((float)superRows-1.75-di->yPos()/(float)gridHeight) + << " out\n"; + } + } + /* write input line */ + DiagramItem *first = dil->first(); + DiagramItem *last = dil->last(); + if (first!=last && !first->isInList()) /* connect with all base classes */ + { + if (bitmap) + { + int xs = first->xPos()*(cellWidth+labelHorSpacing)/gridWidth + + cellWidth/2; + int xe = last->xPos()*(cellWidth+labelHorSpacing)/gridWidth + + cellWidth/2; + if (doBase) // base classes + { + image->drawHorzLine(y,xs,xe,col,mask); + } + else // super classes + { + image->drawHorzLine(y+labelVertSpacing/2,xs,xe,col,mask); + } + } + else + { + t << protToString(p) << endl; + if (doBase) + { + t << first->xPos()/(float)gridWidth << " " + << last->xPos()/(float)gridWidth << " " + << (first->yPos()/(float)gridHeight+superRows-1) + << " conn\n"; + } + else + { + t << first->xPos()/(float)gridWidth << " " + << last->xPos()/(float)gridWidth << " " + << ((float)superRows-first->yPos()/(float)gridHeight) + << " conn\n"; + } + } + } + } + di=dr->next(); + } + dr=next(); + } + } +} + + +void clearVisitFlags() +{ + ClassSDict::Iterator cli(*Doxygen::classSDict); + ClassDef *cd; + for (;(cd=cli.current());++cli) + { + cd->visited=FALSE; + } +} + +ClassDiagram::ClassDiagram(ClassDef *root) +{ + clearVisitFlags(); + base = new TreeDiagram(root,TRUE); + base->computeLayout(); + clearVisitFlags(); + super = new TreeDiagram(root,FALSE); + super->computeLayout(); + DiagramItem *baseItem = base->first()->first(); + DiagramItem *superItem = super->first()->first(); + int xbase = baseItem->xPos(); + int xsuper = superItem->xPos(); + if (xbase>xsuper) + { + superItem->move(xbase-xsuper,0); + super->moveChildren(superItem,xbase-xsuper); + } + else if (xbase<xsuper) + { + baseItem->move(xsuper-xbase,0); + base->moveChildren(baseItem,xsuper-xbase); + } +} + +ClassDiagram::~ClassDiagram() +{ + delete base; + delete super; +} + +void ClassDiagram::writeFigure(FTextStream &output,const char *path, + const char *fileName) const +{ + uint baseRows=base->computeRows(); + uint superRows=super->computeRows(); + uint baseMaxX, baseMaxLabelWidth, superMaxX, superMaxLabelWidth; + base->computeExtremes(&baseMaxLabelWidth,&baseMaxX); + super->computeExtremes(&superMaxLabelWidth,&superMaxX); + + uint rows=baseRows+superRows-1; + uint cols=(QMAX(baseMaxX,superMaxX)+gridWidth*2-1)/gridWidth; + + // Estimate the image aspect width and height in pixels. + uint estHeight = rows*40; + uint estWidth = cols*(20+QMAX(baseMaxLabelWidth,superMaxLabelWidth)); + //printf("Estimated size %d x %d\n",estWidth,estHeight); + + const float pageWidth = 14.0; // estimated page width in cm. + // Somewhat lower to deal with estimation + // errors. + + // compute the image height in centimeters based on the estimates + float realHeight = QMIN(rows,12); // real height in cm + float realWidth = realHeight * estWidth/(float)estHeight; + if (realWidth>pageWidth) // assume that the page width is about 15 cm + { + realHeight*=pageWidth/realWidth; + realWidth=pageWidth; + } + + //output << "}\n"; + output << "\\begin{figure}[H]\n" + "\\begin{center}\n" + "\\leavevmode\n"; + output << "\\includegraphics[height=" << realHeight << "cm]{" + << fileName << "}" << endl; + output << "\\end{center}\n" + "\\end{figure}\n"; + + //printf("writeFigure rows=%d cols=%d\n",rows,cols); + + QCString epsBaseName=(QCString)path+"/"+fileName; + QCString epsName=epsBaseName+".eps"; + QFile f1; + f1.setName(epsName.data()); + if (!f1.open(IO_WriteOnly)) + { + err("Could not open file %s for writing\n",convertToQCString(f1.name()).data()); + exit(1); + } + FTextStream t(&f1); + + //printf("writeEPS() rows=%d cols=%d\n",rows,cols); + + // generate EPS header and postscript variables and procedures + + t << "%!PS-Adobe-2.0 EPSF-2.0\n"; + t << "%%Title: ClassName\n"; + t << "%%Creator: Doxygen\n"; + t << "%%CreationDate: Time\n"; + t << "%%For: \n"; + t << "%Magnification: 1.00\n"; + t << "%%Orientation: Portrait\n"; + t << "%%BoundingBox: 0 0 500 " << estHeight*500.0/(float)estWidth << "\n"; + t << "%%Pages: 0\n"; + t << "%%BeginSetup\n"; + t << "%%EndSetup\n"; + t << "%%EndComments\n"; + t << "\n"; + t << "% ----- variables -----\n"; + t << "\n"; + t << "/boxwidth 0 def\n"; + t << "/boxheight 40 def\n"; + t << "/fontheight 24 def\n"; + t << "/marginwidth 10 def\n"; + t << "/distx 20 def\n"; + t << "/disty 40 def\n"; + t << "/boundaspect " << estWidth/(float)estHeight << " def % aspect ratio of the BoundingBox (width/height)\n"; + t << "/boundx 500 def\n"; + t << "/boundy boundx boundaspect div def\n"; + t << "/xspacing 0 def\n"; + t << "/yspacing 0 def\n"; + t << "/rows " << rows << " def\n"; + t << "/cols " << cols << " def\n"; + t << "/scalefactor 0 def\n"; + t << "/boxfont /Times-Roman findfont fontheight scalefont def\n"; + t << "\n"; + t << "% ----- procedures -----\n"; + t << "\n"; + t << "/dotted { [1 4] 0 setdash } def\n"; + t << "/dashed { [5] 0 setdash } def\n"; + t << "/solid { [] 0 setdash } def\n"; + t << "\n"; + t << "/max % result = MAX(arg1,arg2)\n"; + t << "{\n"; + t << " /a exch def\n"; + t << " /b exch def\n"; + t << " a b gt {a} {b} ifelse\n"; + t << "} def\n"; + t << "\n"; + t << "/xoffset % result = MAX(0,(scalefactor-(boxwidth*cols+distx*(cols-1)))/2)\n"; + t << "{\n"; + t << " 0 scalefactor boxwidth cols mul distx cols 1 sub mul add sub 2 div max\n"; + t << "} def\n"; + t << "\n"; + t << "/cw % boxwidth = MAX(boxwidth, stringwidth(arg1))\n"; + t << "{\n"; + t << " /str exch def\n"; + t << " /boxwidth boxwidth str stringwidth pop max def\n"; + t << "} def\n"; + t << "\n"; + t << "/box % draws a box with text `arg1' at grid pos (arg2,arg3)\n"; + t << "{ gsave\n"; + t << " 2 setlinewidth\n"; + t << " newpath\n"; + t << " exch xspacing mul xoffset add\n"; + t << " exch yspacing mul\n"; + t << " moveto\n"; + t << " boxwidth 0 rlineto \n"; + t << " 0 boxheight rlineto \n"; + t << " boxwidth neg 0 rlineto \n"; + t << " 0 boxheight neg rlineto \n"; + t << " closepath\n"; + t << " dup stringwidth pop neg boxwidth add 2 div\n"; + t << " boxheight fontheight 2 div sub 2 div\n"; + t << " rmoveto show stroke\n"; + t << " grestore\n"; + t << "} def \n"; + t << "\n"; + t << "/mark\n"; + t << "{ newpath\n"; + t << " exch xspacing mul xoffset add boxwidth add\n"; + t << " exch yspacing mul\n"; + t << " moveto\n"; + t << " 0 boxheight 4 div rlineto\n"; + t << " boxheight neg 4 div boxheight neg 4 div rlineto\n"; + t << " closepath\n"; + t << " eofill\n"; + t << " stroke\n"; + t << "} def\n"; + t << "\n"; + t << "/arrow\n"; + t << "{ newpath\n"; + t << " moveto\n"; + t << " 3 -8 rlineto\n"; + t << " -6 0 rlineto\n"; + t << " 3 8 rlineto\n"; + t << " closepath\n"; + t << " eofill\n"; + t << " stroke\n"; + t << "} def\n"; + t << "\n"; + t << "/out % draws an output connector for the block at (arg1,arg2)\n"; + t << "{\n"; + t << " newpath\n"; + t << " exch xspacing mul xoffset add boxwidth 2 div add\n"; + t << " exch yspacing mul boxheight add\n"; + t << " /y exch def\n"; + t << " /x exch def\n"; + t << " x y moveto\n"; + t << " 0 disty 2 div rlineto \n"; + t << " stroke\n"; + t << " 1 eq { x y disty 2 div add arrow } if\n"; + t << "} def\n"; + t << "\n"; + t << "/in % draws an input connector for the block at (arg1,arg2)\n"; + t << "{\n"; + t << " newpath\n"; + t << " exch xspacing mul xoffset add boxwidth 2 div add\n"; + t << " exch yspacing mul disty 2 div sub\n"; + t << " /y exch def\n"; + t << " /x exch def\n"; + t << " x y moveto\n"; + t << " 0 disty 2 div rlineto\n"; + t << " stroke\n"; + t << " 1 eq { x y disty 2 div add arrow } if\n"; + t << "} def\n"; + t << "\n"; + t << "/hedge\n"; + t << "{\n"; + t << " exch xspacing mul xoffset add boxwidth 2 div add\n"; + t << " exch yspacing mul boxheight 2 div sub\n"; + t << " /y exch def\n"; + t << " /x exch def\n"; + t << " newpath\n"; + t << " x y moveto\n"; + t << " boxwidth 2 div distx add 0 rlineto\n"; + t << " stroke\n"; + t << " 1 eq\n"; + t << " { newpath x boxwidth 2 div distx add add y moveto\n"; + t << " -8 3 rlineto\n"; + t << " 0 -6 rlineto\n"; + t << " 8 3 rlineto\n"; + t << " closepath\n"; + t << " eofill\n"; + t << " stroke\n"; + t << " } if\n"; + t << "} def\n"; + t << "\n"; + t << "/vedge\n"; + t << "{\n"; + t << " /ye exch def\n"; + t << " /ys exch def\n"; + t << " /xs exch def\n"; + t << " newpath\n"; + t << " xs xspacing mul xoffset add boxwidth 2 div add dup\n"; + t << " ys yspacing mul boxheight 2 div sub\n"; + t << " moveto\n"; + t << " ye yspacing mul boxheight 2 div sub\n"; + t << " lineto\n"; + t << " stroke\n"; + t << "} def\n"; + t << "\n"; + t << "/conn % connections the blocks from col `arg1' to `arg2' of row `arg3'\n"; + t << "{\n"; + t << " /ys exch def\n"; + t << " /xe exch def\n"; + t << " /xs exch def\n"; + t << " newpath\n"; + t << " xs xspacing mul xoffset add boxwidth 2 div add\n"; + t << " ys yspacing mul disty 2 div sub\n"; + t << " moveto\n"; + t << " xspacing xe xs sub mul 0\n"; + t << " rlineto\n"; + t << " stroke\n"; + t << "} def\n"; + t << "\n"; + t << "% ----- main ------\n"; + t << "\n"; + t << "boxfont setfont\n"; + t << "1 boundaspect scale\n"; + + + bool done=FALSE; + DiagramRow *dr=base->first(); + while (dr && !done) + { + DiagramItem *di=dr->first(); + while (di) + { + done=di->isInList(); + t << "(" << di->label() << ") cw\n"; + di=dr->next(); + } + dr=base->next(); + } + dr=super->first(); + dr=super->next(); + done=FALSE; + while (dr && !done) + { + DiagramItem *di=dr->first(); + while (di) + { + done=di->isInList(); + t << "(" << di->label() << ") cw\n"; + di=dr->next(); + } + dr=super->next(); + } + + t << "/boxwidth boxwidth marginwidth 2 mul add def\n" + << "/xspacing boxwidth distx add def\n" + << "/yspacing boxheight disty add def\n" + << "/scalefactor \n" + << " boxwidth cols mul distx cols 1 sub mul add\n" + << " boxheight rows mul disty rows 1 sub mul add boundaspect mul \n" + << " max def\n" + << "boundx scalefactor div boundy scalefactor div scale\n"; + + t << "\n% ----- classes -----\n\n"; + base->drawBoxes(t,0,TRUE,FALSE,baseRows,superRows,0,0); + super->drawBoxes(t,0,FALSE,FALSE,baseRows,superRows,0,0); + + t << "\n% ----- relations -----\n\n"; + base->drawConnectors(t,0,TRUE,FALSE,baseRows,superRows,0,0); + super->drawConnectors(t,0,FALSE,FALSE,baseRows,superRows,0,0); + + f1.close(); + if (Config_getBool("USE_PDFLATEX")) + { + QCString epstopdfArgs(4096); + epstopdfArgs.sprintf("\"%s.eps\" --outfile=\"%s.pdf\"", + epsBaseName.data(),epsBaseName.data()); + //printf("Converting eps using `%s'\n",epstopdfCmd.data()); + portable_sysTimerStart(); + if (portable_system("epstopdf",epstopdfArgs)!=0) + { + err("error: Problems running epstopdf. Check your TeX installation!\n"); + portable_sysTimerStop(); + return; + } + portable_sysTimerStop(); + } +} + + +void ClassDiagram::writeImage(FTextStream &t,const char *path, + const char *relPath,const char *fileName, + bool generateMap) const +{ + uint baseRows=base->computeRows(); + uint superRows=super->computeRows(); + uint rows=baseRows+superRows-1; + + uint lb,ls,xb,xs; + base->computeExtremes(&lb,&xb); + super->computeExtremes(&ls,&xs); + + uint cellWidth = QMAX(lb,ls)+labelHorMargin*2; + uint maxXPos = QMAX(xb,xs); + uint labelVertMargin = 6; //QMAX(6,(cellWidth-fontHeight)/6); // aspect at least 1:3 + uint cellHeight = labelVertMargin*2+fontHeight; + uint imageWidth = (maxXPos+gridWidth)*cellWidth/gridWidth+ + (maxXPos*labelHorSpacing)/gridWidth; + uint imageHeight = rows*cellHeight+(rows-1)*labelVertSpacing; + + Image image(imageWidth,imageHeight); + + base->drawBoxes(t,&image,TRUE,TRUE,baseRows,superRows,cellWidth,cellHeight,relPath,generateMap); + super->drawBoxes(t,&image,FALSE,TRUE,baseRows,superRows,cellWidth,cellHeight,relPath,generateMap); + base->drawConnectors(t,&image,TRUE,TRUE,baseRows,superRows,cellWidth,cellHeight); + super->drawConnectors(t,&image,FALSE,TRUE,baseRows,superRows,cellWidth,cellHeight); + +#define IMAGE_EXT ".png" + image.save((QCString)path+"/"+fileName+IMAGE_EXT); + Doxygen::indexList.addImageFile(QCString(fileName)+IMAGE_EXT); + + if (generateMap) t << "</map>" << endl; +} + diff --git a/trunk/src/diagram.h b/trunk/src/diagram.h new file mode 100644 index 0000000..3e2cac2 --- /dev/null +++ b/trunk/src/diagram.h @@ -0,0 +1,133 @@ +/****************************************************************************** + * + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#include "qtbc.h" +#include "types.h" + +class ClassDef; +class DiagramRow; +class TreeDiagram; +class ClassDiagram; +class DiagramItemList; +class Image; +class FTextStream; + +class DiagramItem +{ + public: + DiagramItem(DiagramItem *p,int number,ClassDef *cd, + Protection prot,Specifier virt,const char *ts); + ~DiagramItem(); + QCString label() const; + QCString fileName() const; + DiagramItem *parentItem() { return parent; } + DiagramItemList *getChildren() { return children; } + void move(int dx,int dy) { x+=dx; y+=dy; } + int xPos() const { return x; } + int yPos() const { return y; } + int avgChildPos() const; + int numChildren() const; + void addChild(DiagramItem *di); + int number() const { return num; } + Protection protection() const { return prot; } + Specifier virtualness() const { return virt; } + void putInList() { inList=TRUE; } + bool isInList() const { return inList; } + ClassDef *getClassDef() const { return classDef; } + private: + DiagramItemList *children; + DiagramItem *parent; + int x,y; + int num; + Protection prot; + Specifier virt; + QCString templSpec; + bool inList; + ClassDef *classDef; +}; + +class DiagramItemList : public QList<DiagramItem> +{ + public: + DiagramItemList() : QList<DiagramItem>() {} + ~DiagramItemList() {} +}; + +class DiagramRow : public QList<DiagramItem> +{ + public: + DiagramRow(TreeDiagram *d,int l) : QList<DiagramItem>() + { + diagram=d; + level=l; + setAutoDelete(TRUE); + } + void insertClass(DiagramItem *parent,ClassDef *cd,bool doBases, + Protection prot,Specifier virt,const char *ts); + uint number() { return level; } + private: + TreeDiagram *diagram; + uint level; +}; + +class DiagramRowIterator : public QListIterator<DiagramRow> +{ + public: + DiagramRowIterator(const QList<DiagramRow> &d) + : QListIterator<DiagramRow>(d) {} +}; + +class TreeDiagram : public QList<DiagramRow> +{ + public: + TreeDiagram(ClassDef *root,bool doBases); + ~TreeDiagram(); + void computeLayout(); + uint computeRows(); + //uint computeCols(); + void moveChildren(DiagramItem *root,int dx); + void computeExtremes(uint *labelWidth,uint *xpos); + void drawBoxes(FTextStream &t,Image *image, + bool doBase,bool bitmap, + uint baseRows,uint superRows, + uint cellWidth,uint cellHeight, + QCString relPath="", + bool generateMap=TRUE); + void drawConnectors(FTextStream &t,Image *image, + bool doBase,bool bitmap, + uint baseRows,uint superRows, + uint cellWidth,uint cellheight); + private: + bool layoutTree(DiagramItem *root,int row); + TreeDiagram &operator=(const TreeDiagram &); + TreeDiagram(const TreeDiagram &); +}; + +class ClassDiagram +{ + public: + ClassDiagram(ClassDef *root); + ~ClassDiagram(); + void writeFigure(FTextStream &t,const char *path, + const char *file) const; + void writeImage(FTextStream &t,const char *path,const char *relPath, + const char *file,bool generateMap=TRUE) const; + private: + TreeDiagram *base; + TreeDiagram *super; +}; diff --git a/trunk/src/dirdef.cpp b/trunk/src/dirdef.cpp new file mode 100644 index 0000000..c2739f2 --- /dev/null +++ b/trunk/src/dirdef.cpp @@ -0,0 +1,982 @@ +#include "md5.h" + +#include "dirdef.h" +#include "filename.h" +#include "doxygen.h" +#include "util.h" +#include "outputlist.h" +#include "language.h" +#include "message.h" +#include "dot.h" +#include "layout.h" +#include "ftextstream.h" + +//---------------------------------------------------------------------- +// method implementation + +static int g_dirCount=0; + +DirDef::DirDef(const char *path) : Definition(path,1,path) +{ + // get display name (stipping the paths mentioned in STRIP_FROM_PATH) + m_dispName = stripFromPath(path); + // get short name (last part of path) + m_shortName = path; + m_diskName = path; + if (m_shortName.at(m_shortName.length()-1)=='/') + { // strip trailing / + m_shortName = m_shortName.left(m_shortName.length()-1); + } + int pi=m_shortName.findRev('/'); + if (pi!=-1) + { // remove everything till the last / + m_shortName = m_shortName.mid(pi+1); + } + setLocalName(m_shortName); + + m_fileList = new FileList; + m_usedDirs = new QDict<UsedDir>(257); + m_usedDirs->setAutoDelete(TRUE); + m_dirCount = g_dirCount++; + m_level=-1; + m_parent=0; +} + +DirDef::~DirDef() +{ + delete m_fileList; + delete m_usedDirs; +} + +bool DirDef::isLinkableInProject() const +{ + return !isReference() && Config_getBool("SHOW_DIRECTORIES"); +} + +bool DirDef::isLinkable() const +{ + return isReference() || isLinkableInProject(); +} + +void DirDef::addSubDir(DirDef *subdir) +{ + m_subdirs.inSort(subdir); + subdir->setOuterScope(this); + subdir->m_parent=this; +} + +void DirDef::addFile(FileDef *fd) +{ + m_fileList->inSort(fd); + fd->setDirDef(this); +} + +static QCString encodeDirName(const QCString &anchor) +{ + QCString result; + + // convert to md5 hash + uchar md5_sig[16]; + QCString sigStr(33); + MD5Buffer((const unsigned char *)anchor.data(),anchor.length(),md5_sig); + MD5SigToString(md5_sig,sigStr.data(),33); + return sigStr; + + // old algorithm + +// int l = anchor.length(),i; +// for (i=0;i<l;i++) +// { +// char c = anchor.at(i); +// if ((c>='a' && c<='z') || (c>='A' && c<='Z') || (c>='0' && c<='9')) +// { +// result+=c; +// } +// else +// { +// static char hexStr[]="0123456789ABCDEF"; +// char escChar[]={ '_', 0, 0, 0 }; +// escChar[1]=hexStr[c>>4]; +// escChar[2]=hexStr[c&0xf]; +// result+=escChar; +// } +// } +// return result; +} + +QCString DirDef::getOutputFileBase() const +{ + //printf("DirDef::getOutputFileBase() %s->dir_%s\n", + // m_diskName.data(),encodeDirName(m_diskName).data()); + return "dir_"+encodeDirName(m_diskName); +} + +void DirDef::writeDetailedDescription(OutputList &ol,const QCString &title) +{ + if ((!briefDescription().isEmpty() && Config_getBool("REPEAT_BRIEF")) || + !documentation().isEmpty()) + { + ol.writeRuler(); + ol.pushGeneratorState(); + ol.disableAllBut(OutputGenerator::Html); + ol.writeAnchor(0,"details"); + ol.popGeneratorState(); + ol.startGroupHeader(); + ol.parseText(title); + ol.endGroupHeader(); + + // repeat brief description + if (!briefDescription().isEmpty() && Config_getBool("REPEAT_BRIEF")) + { + ol.parseDoc(briefFile(),briefLine(),this,0,briefDescription(),FALSE,FALSE); + } + // separator between brief and details + if (!briefDescription().isEmpty() && Config_getBool("REPEAT_BRIEF") && + !documentation().isEmpty()) + { + ol.pushGeneratorState(); + ol.disable(OutputGenerator::Man); + ol.disable(OutputGenerator::RTF); + // ol.newParagraph(); // FIXME:PARA + ol.enableAll(); + ol.disableAllBut(OutputGenerator::Man); + ol.writeString("\n\n"); + ol.popGeneratorState(); + } + + // write documentation + if (!documentation().isEmpty()) + { + ol.parseDoc(docFile(),docLine(),this,0,documentation()+"\n",TRUE,FALSE); + } + } +} + +void DirDef::writeBriefDescription(OutputList &ol) +{ + if (!briefDescription().isEmpty() && Config_getBool("BRIEF_MEMBER_DESC")) + { + ol.startParagraph(); + ol.parseDoc(briefFile(),briefLine(),this,0,briefDescription(),TRUE,FALSE); + ol.pushGeneratorState(); + ol.disable(OutputGenerator::RTF); + ol.writeString(" \n"); + ol.enable(OutputGenerator::RTF); + + if (Config_getBool("REPEAT_BRIEF") || + !documentation().isEmpty() + ) + { + ol.disableAllBut(OutputGenerator::Html); + ol.startTextLink(0,"details"); + ol.parseText(theTranslator->trMore()); + ol.endTextLink(); + } + ol.popGeneratorState(); + + //ol.pushGeneratorState(); + //ol.disable(OutputGenerator::RTF); + //ol.newParagraph(); + //ol.popGeneratorState(); + ol.endParagraph(); + } + ol.writeSynopsis(); +} + +void DirDef::writeDirectoryGraph(OutputList &ol) +{ + // write graph dependency graph + if (Config_getBool("DIRECTORY_GRAPH") && Config_getBool("HAVE_DOT")) + { + DotDirDeps dirDep(this); + if (!dirDep.isTrivial()) + { + msg("Generating dependency graph for directory %s\n",displayName().data()); + ol.disable(OutputGenerator::Man); + //ol.startParagraph(); + ol.startDirDepGraph(); + ol.parseText(theTranslator->trDirDepGraph(displayName())); + ol.endDirDepGraph(dirDep); + //ol.endParagraph(); + ol.enableAll(); + } + } +} + +void DirDef::writeSubDirList(OutputList &ol) +{ + // write subdir list + if (m_subdirs.count()>0) + { + ol.startMemberHeader("subdirs"); + ol.parseText(theTranslator->trDir(TRUE,FALSE)); + ol.endMemberHeader(); + ol.startMemberList(); + DirDef *dd=m_subdirs.first(); + while (dd) + { + ol.startMemberItem(dd->getOutputFileBase(),0); + ol.parseText(theTranslator->trDir(FALSE,TRUE)+" "); + ol.insertMemberAlign(); + ol.writeObjectLink(dd->getReference(),dd->getOutputFileBase(),0,dd->shortName()); + ol.endMemberItem(); + if (!Config_getString("GENERATE_TAGFILE").isEmpty()) + { + Doxygen::tagFile << " <dir>" << convertToXML(dd->displayName()) << "</dir>" << endl; + } + if (!dd->briefDescription().isEmpty() && Config_getBool("BRIEF_MEMBER_DESC")) + { + ol.startMemberDescription(dd->getOutputFileBase()); + ol.parseDoc(briefFile(),briefLine(),dd,0,dd->briefDescription(), + FALSE, // indexWords + FALSE, // isExample + 0, // exampleName + FALSE, // single line + TRUE // link from index + ); + ol.endMemberDescription(); + } + dd=m_subdirs.next(); + } + + ol.endMemberList(); + } +} + +void DirDef::writeFileList(OutputList &ol) +{ + // write file list + if (m_fileList->count()>0) + { + ol.startMemberHeader("files"); + ol.parseText(theTranslator->trFile(TRUE,FALSE)); + ol.endMemberHeader(); + ol.startMemberList(); + FileDef *fd=m_fileList->first(); + while (fd) + { + ol.startMemberItem(fd->getOutputFileBase(),0); + ol.docify(theTranslator->trFile(FALSE,TRUE)+" "); + ol.insertMemberAlign(); + if (fd->isLinkable()) + { + ol.writeObjectLink(fd->getReference(),fd->getOutputFileBase(),0,fd->name()); + } + else + { + ol.startBold(); + ol.docify(fd->name()); + ol.endBold(); + } + if (fd->generateSourceFile()) + { + ol.pushGeneratorState(); + ol.disableAllBut(OutputGenerator::Html); + ol.docify(" "); + ol.startTextLink(fd->includeName(),0); + ol.docify("["); + ol.parseText(theTranslator->trCode()); + ol.docify("]"); + ol.endTextLink(); + ol.popGeneratorState(); + } + if (!Config_getString("GENERATE_TAGFILE").isEmpty()) + { + Doxygen::tagFile << " <file>" << convertToXML(fd->name()) << "</file>" << endl; + } + ol.endMemberItem(); + if (!fd->briefDescription().isEmpty() && Config_getBool("BRIEF_MEMBER_DESC")) + { + ol.startMemberDescription(fd->getOutputFileBase()); + ol.parseDoc(briefFile(),briefLine(),fd,0,fd->briefDescription(), + FALSE, // indexWords + FALSE, // isExample + 0, // exampleName + FALSE, // single line + TRUE // link from index + ); + ol.endMemberDescription(); + } + fd=m_fileList->next(); + } + ol.endMemberList(); + } +} + +void DirDef::startMemberDeclarations(OutputList &ol) +{ + ol.startMemberSections(); +} + +void DirDef::endMemberDeclarations(OutputList &ol) +{ + ol.endMemberSections(); +} + +void DirDef::writeDocumentation(OutputList &ol) +{ + static bool generateTreeView = Config_getBool("GENERATE_TREEVIEW"); + ol.pushGeneratorState(); + + QCString shortTitle=theTranslator->trDirReference(m_shortName); + QCString title=theTranslator->trDirReference(m_dispName); + startFile(ol,getOutputFileBase(),name(),title,HLI_None,!generateTreeView); + + if (!generateTreeView) + { + // write navigation path + writeNavigationPath(ol); + ol.endQuickIndices(); + } + + startTitle(ol,getOutputFileBase()); + ol.pushGeneratorState(); + ol.disableAllBut(OutputGenerator::Html); + ol.parseText(shortTitle); + ol.enableAll(); + ol.disable(OutputGenerator::Html); + ol.parseText(title); + ol.popGeneratorState(); + endTitle(ol,getOutputFileBase(),title); + ol.startContents(); + + if (!Config_getString("GENERATE_TAGFILE").isEmpty()) + { + Doxygen::tagFile << " <compound kind=\"dir\">" << endl; + Doxygen::tagFile << " <name>" << convertToXML(displayName()) << "</name>" << endl; + Doxygen::tagFile << " <path>" << convertToXML(name()) << "</path>" << endl; + Doxygen::tagFile << " <filename>" << convertToXML(getOutputFileBase()) << Doxygen::htmlFileExtension << "</filename>" << endl; + } + + //---------------------------------------- start flexible part ------------------------------- + + QListIterator<LayoutDocEntry> eli( + LayoutDocManager::instance().docEntries(LayoutDocManager::Directory)); + LayoutDocEntry *lde; + for (eli.toFirst();(lde=eli.current());++eli) + { + switch (lde->kind()) + { + case LayoutDocEntry::BriefDesc: + writeBriefDescription(ol); + break; + case LayoutDocEntry::DirGraph: + writeDirectoryGraph(ol); + break; + case LayoutDocEntry::MemberDeclStart: + startMemberDeclarations(ol); + break; + case LayoutDocEntry::DirSubDirs: + writeSubDirList(ol); + break; + case LayoutDocEntry::DirFiles: + writeFileList(ol); + break; + case LayoutDocEntry::MemberDeclEnd: + endMemberDeclarations(ol); + break; + case LayoutDocEntry::DetailedDesc: + { + LayoutDocEntrySection *ls = (LayoutDocEntrySection*)lde; + writeDetailedDescription(ol,ls->title); + } + break; + case LayoutDocEntry::ClassIncludes: + case LayoutDocEntry::ClassInlineClasses: + case LayoutDocEntry::ClassInheritanceGraph: + case LayoutDocEntry::ClassNestedClasses: + case LayoutDocEntry::ClassCollaborationGraph: + case LayoutDocEntry::ClassAllMembersLink: + case LayoutDocEntry::ClassUsedFiles: + case LayoutDocEntry::NamespaceNestedNamespaces: + case LayoutDocEntry::NamespaceClasses: + case LayoutDocEntry::NamespaceInlineClasses: + case LayoutDocEntry::FileClasses: + case LayoutDocEntry::FileNamespaces: + case LayoutDocEntry::FileIncludes: + case LayoutDocEntry::FileIncludeGraph: + case LayoutDocEntry::FileIncludedByGraph: + case LayoutDocEntry::FileSourceLink: + case LayoutDocEntry::FileInlineClasses: + case LayoutDocEntry::GroupClasses: + case LayoutDocEntry::GroupInlineClasses: + case LayoutDocEntry::GroupNamespaces: + case LayoutDocEntry::GroupDirs: + case LayoutDocEntry::GroupNestedGroups: + case LayoutDocEntry::GroupFiles: + case LayoutDocEntry::GroupGraph: + case LayoutDocEntry::GroupPageDocs: + case LayoutDocEntry::AuthorSection: + case LayoutDocEntry::MemberGroups: + case LayoutDocEntry::MemberDecl: + case LayoutDocEntry::MemberDef: + case LayoutDocEntry::MemberDefStart: + case LayoutDocEntry::MemberDefEnd: + err("Internal inconsistency: member %d should not be part of " + "LayoutDocManager::Directory entry list\n",lde->kind()); + break; + } + } + + //---------------------------------------- end flexible part ------------------------------- + + if (!Config_getString("GENERATE_TAGFILE").isEmpty()) + { + writeDocAnchorsToTagFile(); + Doxygen::tagFile << " </compound>" << endl; + } + + ol.endContents(); + + endFileWithNavPath(this,ol); + + ol.popGeneratorState(); +} + +void DirDef::setLevel() +{ + if (m_level==-1) // level not set before + { + DirDef *p = parent(); + if (p) + { + p->setLevel(); + m_level = p->level()+1; + } + else + { + m_level = 0; + } + } +} + +/** Add as "uses" dependency between \a this dir and \a dir, + * that was caused by a dependency on file \a fd. + */ +void DirDef::addUsesDependency(DirDef *dir,FileDef *srcFd, + FileDef *dstFd,bool inherited) +{ + if (this==dir) return; // do not add self-dependencies + //static int count=0; + //printf(" %d add dependency %s->%s due to %s->%s\n", + // count++,shortName().data(), + // dir->shortName().data(), + // srcFd->name().data(), + // dstFd->name().data()); + + // levels match => add direct dependency + bool added=FALSE; + UsedDir *usedDir = m_usedDirs->find(dir->getOutputFileBase()); + if (usedDir) // dir dependency already present + { + FilePair *usedPair = usedDir->findFilePair( + srcFd->getOutputFileBase()+dstFd->getOutputFileBase()); + if (usedPair==0) // new file dependency + { + //printf(" => new file\n"); + usedDir->addFileDep(srcFd,dstFd); + added=TRUE; + } + else + { + // dir & file dependency already added + } + } + else // new directory dependency + { + //printf(" => new file\n"); + usedDir = new UsedDir(dir,inherited); + usedDir->addFileDep(srcFd,dstFd); + m_usedDirs->insert(dir->getOutputFileBase(),usedDir); + added=TRUE; + } + if (added) + { + if (dir->parent()) + { + // add relation to parent of used dir + addUsesDependency(dir->parent(),srcFd,dstFd,inherited); + } + if (parent()) + { + // add relation for the parent of this dir as well + parent()->addUsesDependency(dir,srcFd,dstFd,TRUE); + } + } +} + +/** Computes the dependencies between directories + */ +void DirDef::computeDependencies() +{ + FileList *fl = m_fileList; + if (fl) + { + QListIterator<FileDef> fli(*fl); + FileDef *fd; + for (fli.toFirst();(fd=fli.current());++fli) // foreach file in dir dd + { + //printf(" File %s\n",fd->name().data()); + //printf("** dir=%s file=%s\n",shortName().data(),fd->name().data()); + QList<IncludeInfo> *ifl = fd->includeFileList(); + if (ifl) + { + QListIterator<IncludeInfo> ifli(*ifl); + IncludeInfo *ii; + for (ifli.toFirst();(ii=ifli.current());++ifli) // foreach include file + { + //printf(" > %s\n",ii->includeName.data()); + //printf(" #include %s\n",ii->includeName.data()); + if (ii->fileDef && ii->fileDef->isLinkable()) // linkable file + { + DirDef *usedDir = ii->fileDef->getDirDef(); + if (usedDir) + { + // add dependency: thisDir->usedDir + //static int count=0; + //printf(" %d: add dependency %s->%s\n",count++,name().data(),usedDir->name().data()); + addUsesDependency(usedDir,fd,ii->fileDef,FALSE); + } + } + } + } + } + } +} + +bool DirDef::isParentOf(DirDef *dir) const +{ + if (dir->parent()==this) // this is a parent of dir + return TRUE; + else if (dir->parent()) // repeat for the parent of dir + return isParentOf(dir->parent()); + else + return FALSE; +} + +bool DirDef::depGraphIsTrivial() const +{ + return FALSE; +} + +//---------------------------------------------------------------------- + +int FilePairDict::compareItems(GCI item1,GCI item2) +{ + FilePair *left = (FilePair*)item1; + FilePair *right = (FilePair*)item2; + int orderHi = stricmp(left->source()->name(),right->source()->name()); + int orderLo = stricmp(left->destination()->name(),right->destination()->name()); + return orderHi==0 ? orderLo : orderHi; +} + +//---------------------------------------------------------------------- + +UsedDir::UsedDir(DirDef *dir,bool inherited) : + m_dir(dir), m_filePairs(7), m_inherited(inherited) +{ + m_filePairs.setAutoDelete(TRUE); +} + +UsedDir::~UsedDir() +{ +} + + +void UsedDir::addFileDep(FileDef *srcFd,FileDef *dstFd) +{ + m_filePairs.inSort(srcFd->getOutputFileBase()+dstFd->getOutputFileBase(), + new FilePair(srcFd,dstFd)); +} + +FilePair *UsedDir::findFilePair(const char *name) +{ + QCString n=name; + return n.isEmpty() ? 0 : m_filePairs.find(n); +} + +DirDef *DirDef::createNewDir(const char *path) +{ + ASSERT(path!=0); + DirDef *dir = Doxygen::directories->find(path); + if (dir==0) // new dir + { + //printf("Adding new dir %s\n",path); + dir = new DirDef(path); + //printf("createNewDir %s short=%s\n",path,dir->shortName().data()); + Doxygen::directories->inSort(path,dir); + } + return dir; +} + +bool DirDef::matchPath(const QCString &path,QStrList &l) +{ + const char *s=l.first(); + while (s) + { + QCString prefix = s; + if (stricmp(prefix.left(path.length()),path)==0) // case insensitive compare + { + return TRUE; + } + s = l.next(); + } + return FALSE; +} + +/*! strip part of \a path if it matches + * one of the paths in the Config_getList("STRIP_FROM_PATH") list + */ +DirDef *DirDef::mergeDirectoryInTree(const QCString &path) +{ + //printf("DirDef::mergeDirectoryInTree(%s)\n",path.data()); + int p=0,i=0; + DirDef *dir=0; + while ((i=path.find('/',p))!=-1) + { + QCString part=path.left(i+1); + if (!matchPath(part,Config_getList("STRIP_FROM_PATH")) && part!="/") + { + dir=createNewDir(part); + } + p=i+1; + } + return dir; +} + +void DirDef::writeDepGraph(FTextStream &t) +{ + writeDotDirDepGraph(t,this); +} + +//---------------------------------------------------------------------- + +static void writePartialDirPath(OutputList &ol,const DirDef *root,const DirDef *target) +{ + if (target->parent()!=root) + { + writePartialDirPath(ol,root,target->parent()); + ol.writeString(" / "); + } + ol.writeObjectLink(target->getReference(),target->getOutputFileBase(),0,target->shortName()); +} + +static void writePartialFilePath(OutputList &ol,const DirDef *root,const FileDef *fd) +{ + if (fd->getDirDef() && fd->getDirDef()!=root) + { + writePartialDirPath(ol,root,fd->getDirDef()); + ol.writeString(" / "); + } + if (fd->isLinkable()) + { + ol.writeObjectLink(fd->getReference(),fd->getOutputFileBase(),0,fd->name()); + } + else + { + ol.startBold(); + ol.docify(fd->name()); + ol.endBold(); + } +} + +void DirRelation::writeDocumentation(OutputList &ol) +{ + static bool generateTreeView = Config_getBool("GENERATE_TREEVIEW"); + ol.pushGeneratorState(); + ol.disableAllBut(OutputGenerator::Html); + + QCString shortTitle=theTranslator->trDirRelation( + m_src->shortName()+" → "+ + m_dst->dir()->shortName()); + QCString title=theTranslator->trDirRelation( + m_src->displayName()+" -> "+ + m_dst->dir()->shortName()); + startFile(ol,getOutputFileBase(),getOutputFileBase(), + title,HLI_None,!generateTreeView,m_src->getOutputFileBase()); + + if (!generateTreeView) + { + // write navigation path + m_src->writeNavigationPath(ol); + ol.endQuickIndices(); + } + ol.startContents(); + + ol.writeString("<h3>"+shortTitle+"</h3>"); + ol.writeString("<table class=\"dirtab\">"); + ol.writeString("<tr class=\"dirtab\">"); + ol.writeString("<th class=\"dirtab\">"); + ol.parseText(theTranslator->trFileIn(m_src->pathFragment())); + ol.writeString("</th>"); + ol.writeString("<th class=\"dirtab\">"); + ol.parseText(theTranslator->trIncludesFileIn(m_dst->dir()->pathFragment())); + ol.writeString("</th>"); + ol.writeString("</tr>"); + + SDict<FilePair>::Iterator fpi(m_dst->filePairs()); + FilePair *fp; + for (fpi.toFirst();(fp=fpi.current());++fpi) + { + ol.writeString("<tr class=\"dirtab\">"); + ol.writeString("<td class=\"dirtab\">"); + writePartialFilePath(ol,m_src,fp->source()); + ol.writeString("</td>"); + ol.writeString("<td class=\"dirtab\">"); + writePartialFilePath(ol,m_dst->dir(),fp->destination()); + ol.writeString("</td>"); + ol.writeString("</tr>"); + } + ol.writeString("</table>"); + + ol.endContents(); + + endFileWithNavPath(m_src,ol); + + ol.popGeneratorState(); +} + +//---------------------------------------------------------------------- +// external functions + +/** In order to create stable, but unique directory names, + * we compute the common part of the path shared by all directories. + */ +static void computeCommonDirPrefix() +{ + QCString path; + DirDef *dir; + DirSDict::Iterator sdi(*Doxygen::directories); + if (Doxygen::directories->count()>0) // we have at least one dir + { + // start will full path of first dir + sdi.toFirst(); + dir=sdi.current(); + path=dir->name(); + int i=path.findRev('/',path.length()-2); + path=path.left(i+1); + bool done=FALSE; + if (i==-1) + { + path=""; + } + else + { + while (!done) + { + int l = path.length(); + int count=0; + for (sdi.toFirst();(dir=sdi.current());++sdi) + { + QCString dirName = dir->name(); + if (dirName.length()>path.length()) + { + if (strncmp(dirName,path,l)!=0) // dirName does not start with path + { + int i=path.findRev('/',l-2); + if (i==-1) // no unique prefix -> stop + { + path=""; + done=TRUE; + } + else // restart with shorter path + { + path=path.left(i+1); + break; + } + } + } + else // dir is shorter than path -> take path of dir as new start + { + path=dir->name(); + int i=path.findRev('/',l-2); + if (i==-1) // no unique prefix -> stop + { + path=""; + done=TRUE; + } + else // restart with shorter path + { + path=path.left(i+1); + } + break; + } + count++; + } + if (count==Doxygen::directories->count()) + // path matches for all directories -> found the common prefix + { + done=TRUE; + } + } + } + } + for (sdi.toFirst();(dir=sdi.current());++sdi) + { + QCString diskName = dir->name().right(dir->name().length()-path.length()); + dir->setDiskName(diskName); + //printf("set disk name: %s -> %s\n",dir->name().data(),diskName.data()); + } +} + +void buildDirectories() +{ + // for each input file + FileNameListIterator fnli(*Doxygen::inputNameList); + FileName *fn; + for (fnli.toFirst();(fn=fnli.current());++fnli) + { + FileNameIterator fni(*fn); + FileDef *fd; + for (;(fd=fni.current());++fni) + { + //printf("buildDirectories %s\n",fd->name().data()); + if (fd->getReference().isEmpty() && !fd->isDocumentationFile()) + { + DirDef *dir; + if ((dir=Doxygen::directories->find(fd->getPath()))==0) // new directory + { + dir = DirDef::mergeDirectoryInTree(fd->getPath()); + } + if (dir) dir->addFile(fd); + } + else + { + // do something for file imported via tag files. + } + } + } + + //DirDef *root = new DirDef("root:"); + // compute relations between directories => introduce container dirs. + DirDef *dir; + DirSDict::Iterator sdi(*Doxygen::directories); + for (sdi.toFirst();(dir=sdi.current());++sdi) + { + //printf("New dir %s\n",dir->displayName().data()); + QCString name = dir->name(); + int i=name.findRev('/',name.length()-2); + if (i>0) + { + DirDef *parent = Doxygen::directories->find(name.left(i+1)); + //if (parent==0) parent=root; + if (parent) + { + parent->addSubDir(dir); + //printf("DirDef::addSubdir(): Adding subdir\n%s to\n%s\n", + // dir->displayName().data(), parent->displayName().data()); + } + } + } + computeCommonDirPrefix(); +} + +void computeDirDependencies() +{ + DirDef *dir; + DirSDict::Iterator sdi(*Doxygen::directories); + // compute nesting level for each directory + for (sdi.toFirst();(dir=sdi.current());++sdi) + { + dir->setLevel(); + } + // compute uses dependencies between directories + for (sdi.toFirst();(dir=sdi.current());++sdi) + { + //printf("computeDependencies for %s: #dirs=%d\n",dir->name().data(),Doxygen::directories.count()); + dir->computeDependencies(); + } + +#if 0 + printf("-------------------------------------------------------------\n"); + // print dependencies (for debugging) + for (sdi.toFirst();(dir=sdi.current());++sdi) + { + if (dir->usedDirs()) + { + QDictIterator<UsedDir> udi(*dir->usedDirs()); + UsedDir *usedDir; + for (udi.toFirst();(usedDir=udi.current());++udi) + { + printf("%s depends on %s due to ", + dir->shortName().data(),usedDir->dir()->shortName().data()); + QDictIterator<FileDef> fdi(usedDir->files()); + FileDef *fd; + for (fdi.toFirst();(fd=fdi.current());++fdi) + { + printf("%s ",fd->name().data()); + } + printf("\n"); + } + } + } + printf("^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^\n"); +#endif +} + +#if 0 +void writeDirDependencyGraph(const char *dirName) +{ + QString path; + DirDef *dir; + DirSDict::Iterator sdi(*Doxygen::directories); + QFile htmlPage(QCString(dirName)+"/dirdeps.html"); + if (htmlPage.open(IO_WriteOnly)) + { + QTextStream out(&htmlPage); + out << "<html><body>"; + for (sdi.toFirst();(dir=sdi.current());++sdi) + { + path=dirName; + path+="/"; + path+=dir->getOutputFileBase(); + path+="_dep.dot"; + out << "<h4>" << dir->displayName() << "</h4>" << endl; + out << "<img src=\"" << dir->getOutputFileBase() << "_dep.gif\">" << endl; + QFile f(path); + if (f.open(IO_WriteOnly)) + { + QTextStream t(&f); + dir->writeDepGraph(t); + } + f.close(); + + QCString imgExt = Config_getEnum("DOT_IMAGE_FORMAT"); + QCString outFile = QCString(dirName)+"/"+ + dir->getOutputFileBase()+"_dep."+imgExt; + DotRunner dotRun(path); + dotRun.addJob(imgExt,outFile); + dotRun.run(); + + //QCString dotArgs(4096); + //dotArgs.sprintf("%s -Tgif -o %s",path.data(),outFile.data()); + //if (portable_system(Config_getString("DOT_PATH")+"dot",dotArgs,FALSE)!=0) + //{ + // err("Problems running dot. Check your installation!\n"); + //} + } + out << "</body></html>"; + } + htmlPage.close(); +} +#endif + +void generateDirDocs(OutputList &ol) +{ + DirDef *dir; + DirSDict::Iterator sdi(*Doxygen::directories); + for (sdi.toFirst();(dir=sdi.current());++sdi) + { + dir->writeDocumentation(ol); + } + if (Config_getBool("DIRECTORY_GRAPH")) + { + SDict<DirRelation>::Iterator rdi(Doxygen::dirRelations); + DirRelation *dr; + for (rdi.toFirst();(dr=rdi.current());++rdi) + { + dr->writeDocumentation(ol); + } + } +} + diff --git a/trunk/src/dirdef.h b/trunk/src/dirdef.h new file mode 100644 index 0000000..e7a6b0e --- /dev/null +++ b/trunk/src/dirdef.h @@ -0,0 +1,182 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#ifndef DIRDEF_H +#define DIRDEF_H + +#include "qtbc.h" +#include "sortdict.h" +#include "definition.h" + +#include <qlist.h> + +class FileList; +class ClassSDict; +class QStrList; +class FileDef; +class OutputList; +class UsedDir; +class FTextStream; + +class DirDef; + +/** A list of directories */ +class DirList : public QList<DirDef> +{ + public: + int compareItems(GCI item1,GCI item2); +}; + +/** A directory */ +class DirDef : public Definition +{ + public: + DirDef(const char *path); + virtual ~DirDef(); + + // accessors + DefType definitionType() const { return TypeDir; } + QCString getOutputFileBase() const; + QCString anchor() const { return QCString(); } + bool isLinkableInProject() const; + bool isLinkable() const; + QCString displayName() const { return m_dispName; } + QCString shortName() const { return m_shortName; } + void addSubDir(DirDef *subdir); + FileList * getFiles() const { return m_fileList; } + void addFile(FileDef *fd); + const DirList &subDirs() const { return m_subdirs; } + bool isCluster() const { return m_subdirs.count()>0; } + int level() const { return m_level; } + DirDef *parent() const { return m_parent; } + int dirCount() const { return m_dirCount; } + const QDict<UsedDir> *usedDirs() const { return m_usedDirs; } + bool isParentOf(DirDef *dir) const; + bool depGraphIsTrivial() const; + + // generate output + void writeDocumentation(OutputList &ol); + void writeDepGraph(FTextStream &t); + + static DirDef *mergeDirectoryInTree(const QCString &path); + bool visited; + void setDiskName(const QCString &name) { m_diskName = name; } + + private: + friend void computeDirDependencies(); + + void writeDetailedDescription(OutputList &ol,const QCString &title); + void writeBriefDescription(OutputList &ol); + void writeDirectoryGraph(OutputList &ol); + void writeSubDirList(OutputList &ol); + void writeFileList(OutputList &ol); + void startMemberDeclarations(OutputList &ol); + void endMemberDeclarations(OutputList &ol); + + void setLevel(); + static DirDef *createNewDir(const char *path); + static bool matchPath(const QCString &path,QStrList &l); + void addUsesDependency(DirDef *usedDir,FileDef *srcFd, + FileDef *dstFd,bool inherited); + void computeDependencies(); + + DirList m_subdirs; + QCString m_dispName; + QCString m_shortName; + QCString m_diskName; + FileList *m_fileList; // list of files in the group + int m_dirCount; + int m_level; + DirDef *m_parent; + QDict<UsedDir> *m_usedDirs; +}; + +class FilePair +{ + public: + FilePair(FileDef *src,FileDef *dst) : m_src(src), m_dst(dst) {} + const FileDef *source() const { return m_src; } + const FileDef *destination() const { return m_dst; } + private: + FileDef *m_src; + FileDef *m_dst; +}; + +class FilePairDict : public SDict<FilePair> +{ + public: + FilePairDict(int size) : SDict<FilePair>(size) {} + int compareItems(GCI item1,GCI item2); +}; + +/** Usage information of a directory . */ +class UsedDir +{ + public: + UsedDir(DirDef *dir,bool inherited); + virtual ~UsedDir(); + void addFileDep(FileDef *srcFd,FileDef *dstFd); + FilePair *findFilePair(const char *name); + const FilePairDict &filePairs() const { return m_filePairs; } + const DirDef *dir() const { return m_dir; } + bool inherited() const { return m_inherited; } + + private: + DirDef *m_dir; + FilePairDict m_filePairs; + bool m_inherited; +}; + +/** A usage relation between two direction. */ +class DirRelation +{ + public: + DirRelation(const QCString &name,DirDef *src,UsedDir *dst) + : m_name(name), m_src(src), m_dst(dst) {} + DirDef *source() const { return m_src; } + UsedDir *destination() const { return m_dst; } + void writeDocumentation(OutputList &ol); + QCString getOutputFileBase() const { return m_name; } + + private: + QCString m_name; + DirDef *m_src; + UsedDir *m_dst; +}; + +inline int DirList::compareItems(GCI item1,GCI item2) +{ + return stricmp(((DirDef *)item1)->shortName(),((DirDef *)item2)->shortName()); +} + +class DirSDict : public SDict<DirDef> +{ + public: + DirSDict(int size) : SDict<DirDef>(size) {} + int compareItems(GCI item1,GCI item2) + { + return stricmp(((DirDef *)item1)->shortName(),((DirDef *)item2)->shortName()); + } +}; + + +void buildDirectories(); +void generateDirDocs(OutputList &ol); +void computeDirDependencies(); +void writeDirDependencyGraph(const char *file); + +#endif diff --git a/trunk/src/docparser.cpp b/trunk/src/docparser.cpp new file mode 100644 index 0000000..17d9685 --- /dev/null +++ b/trunk/src/docparser.cpp @@ -0,0 +1,6970 @@ +/****************************************************************************** + * + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#include <stdio.h> +#include <stdlib.h> + +#include <qfile.h> +#include <qfileinfo.h> +#include <qcstring.h> +#include <qstack.h> +#include <qdict.h> +#include <qregexp.h> +#include <ctype.h> + +#include "doxygen.h" +#include "debug.h" +#include "util.h" +#include "pagedef.h" + +#include "docparser.h" +#include "doctokenizer.h" +#include "cmdmapper.h" +#include "printdocvisitor.h" +#include "message.h" +#include "section.h" +#include "searchindex.h" +#include "language.h" +#include "portable.h" +#include "cite.h" +#include "arguments.h" + +// debug off +#define DBG(x) do {} while(0) + +// debug to stdout +//#define DBG(x) printf x + +// debug to stderr +//#define myprintf(x...) fprintf(stderr,x) +//#define DBG(x) myprintf x + +#define INTERNAL_ASSERT(x) do {} while(0) +//#define INTERNAL_ASSERT(x) if (!(x)) DBG(("INTERNAL_ASSERT(%s) failed retval=0x%x: file=%s line=%d\n",#x,retval,__FILE__,__LINE__)); + +//--------------------------------------------------------------------------- + +static const char *sectionLevelToName[] = +{ + "page", + "section", + "subsection", + "subsubsection", + "paragraph" +}; + +//--------------------------------------------------------------------------- + +// Parser state: global variables during a call to validatingParseDoc +static Definition * g_scope; +static QCString g_context; +static bool g_inSeeBlock; +static bool g_insideHtmlLink; +static QStack<DocNode> g_nodeStack; +static QStack<DocStyleChange> g_styleStack; +static QStack<DocStyleChange> g_initialStyleStack; +static QList<Definition> g_copyStack; +static QCString g_fileName; +static QCString g_relPath; + +static bool g_hasParamCommand; +static bool g_hasReturnCommand; +static QDict<void> g_paramsFound; +static MemberDef * g_memberDef; +static bool g_isExample; +static QCString g_exampleName; +static SectionDict * g_sectionDict; +static QCString g_searchUrl; + +static QCString g_includeFileText; +static uint g_includeFileOffset; +static uint g_includeFileLength; + +// parser's context to store all global variables +struct DocParserContext +{ + Definition *scope; + QCString context; + bool inSeeBlock; + bool insideHtmlLink; + QStack<DocNode> nodeStack; + QStack<DocStyleChange> styleStack; + QStack<DocStyleChange> initialStyleStack; + QList<Definition> copyStack; + QCString fileName; + QCString relPath; + + bool hasParamCommand; + bool hasReturnCommand; + MemberDef * memberDef; + QDict<void> paramsFound; + bool isExample; + QCString exampleName; + SectionDict *sectionDict; + QCString searchUrl; + + QCString includeFileText; + uint includeFileOffset; + uint includeFileLength; + + TokenInfo *token; +}; + +static QStack<DocParserContext> g_parserStack; + +//--------------------------------------------------------------------------- + +static void docParserPushContext(bool saveParamInfo=TRUE) +{ + //QCString indent; + //indent.fill(' ',g_parserStack.count()*2+2); + //printf("%sdocParserPushContext() count=%d\n",indent.data(),g_nodeStack.count()); + + doctokenizerYYpushContext(); + DocParserContext *ctx = new DocParserContext; + ctx->scope = g_scope; + ctx->context = g_context; + ctx->inSeeBlock = g_inSeeBlock; + ctx->insideHtmlLink = g_insideHtmlLink; + ctx->nodeStack = g_nodeStack; + ctx->styleStack = g_styleStack; + ctx->initialStyleStack = g_initialStyleStack; + ctx->copyStack = g_copyStack; + ctx->fileName = g_fileName; + ctx->relPath = g_relPath; + + if (saveParamInfo) + { + ctx->hasParamCommand = g_hasParamCommand; + ctx->hasReturnCommand = g_hasReturnCommand; + ctx->paramsFound = g_paramsFound; + } + + ctx->memberDef = g_memberDef; + ctx->isExample = g_isExample; + ctx->exampleName = g_exampleName; + ctx->sectionDict = g_sectionDict; + ctx->searchUrl = g_searchUrl; + + ctx->includeFileText = g_includeFileText; + ctx->includeFileOffset = g_includeFileOffset; + ctx->includeFileLength = g_includeFileLength; + + ctx->token = g_token; + g_token = new TokenInfo; + + g_parserStack.push(ctx); +} + +static void docParserPopContext(bool keepParamInfo=FALSE) +{ + DocParserContext *ctx = g_parserStack.pop(); + g_scope = ctx->scope; + g_context = ctx->context; + g_inSeeBlock = ctx->inSeeBlock; + g_insideHtmlLink = ctx->insideHtmlLink; + g_nodeStack = ctx->nodeStack; + g_styleStack = ctx->styleStack; + g_initialStyleStack = ctx->initialStyleStack; + g_copyStack = ctx->copyStack; + g_fileName = ctx->fileName; + g_relPath = ctx->relPath; + + if (!keepParamInfo) + { + g_hasParamCommand = ctx->hasParamCommand; + g_hasReturnCommand = ctx->hasReturnCommand; + g_paramsFound = ctx->paramsFound; + } + g_memberDef = ctx->memberDef; + g_isExample = ctx->isExample; + g_exampleName = ctx->exampleName; + g_sectionDict = ctx->sectionDict; + g_searchUrl = ctx->searchUrl; + + g_includeFileText = ctx->includeFileText; + g_includeFileOffset = ctx->includeFileOffset; + g_includeFileLength = ctx->includeFileLength; + + delete g_token; + g_token = ctx->token; + + delete ctx; + doctokenizerYYpopContext(); + + //QCString indent; + //indent.fill(' ',g_parserStack.count()*2+2); + //printf("%sdocParserPopContext() count=%d\n",indent.data(),g_nodeStack.count()); +} + +//--------------------------------------------------------------------------- + +/*! search for an image in the imageNameDict and if found + * copies the image to the output directory (which depends on the \a type + * parameter). + */ +static QCString findAndCopyImage(const char *fileName,DocImage::Type type) +{ + QCString result; + bool ambig; + FileDef *fd; + //printf("Search for %s\n",fileName); + if ((fd=findFileDef(Doxygen::imageNameDict,fileName,ambig))) + { + QCString inputFile = fd->absFilePath(); + QFile inImage(inputFile); + if (inImage.open(IO_ReadOnly)) + { + result = fileName; + int i; + if ((i=result.findRev('/'))!=-1 || (i=result.findRev('\\'))!=-1) + { + result = result.right(result.length()-i-1); + } + //printf("fileName=%s result=%s\n",fileName,result.data()); + QCString outputDir; + switch(type) + { + case DocImage::Html: + if (!Config_getBool("GENERATE_HTML")) return result; + outputDir = Config_getString("HTML_OUTPUT"); + break; + case DocImage::Latex: + if (!Config_getBool("GENERATE_LATEX")) return result; + outputDir = Config_getString("LATEX_OUTPUT"); + break; + case DocImage::Rtf: + if (!Config_getBool("GENERATE_RTF")) return result; + outputDir = Config_getString("RTF_OUTPUT"); + break; + } + QCString outputFile = outputDir+"/"+result; + if (outputFile!=inputFile) // prevent copying to ourself + { + QFile outImage(outputFile.data()); + if (outImage.open(IO_WriteOnly)) // copy the image + { + char *buffer = new char[inImage.size()]; + inImage.readBlock(buffer,inImage.size()); + outImage.writeBlock(buffer,inImage.size()); + outImage.flush(); + delete[] buffer; + if (type==DocImage::Html) Doxygen::indexList.addImageFile(result); + } + else + { + warn_doc_error(g_fileName,doctokenizerYYlineno, + "warning: could not write output image %s",qPrint(outputFile)); + } + } + } + else + { + warn_doc_error(g_fileName,doctokenizerYYlineno, + "warning: could not open image %s",qPrint(fileName)); + } + + if (type==DocImage::Latex && Config_getBool("USE_PDFLATEX") && + fd->name().right(4)==".eps" + ) + { // we have an .eps image in pdflatex mode => convert it to a pdf. + QCString outputDir = Config_getString("LATEX_OUTPUT"); + QCString baseName = fd->name().left(fd->name().length()-4); + QCString epstopdfArgs(4096); + epstopdfArgs.sprintf("\"%s/%s.eps\" --outfile=\"%s/%s.pdf\"", + outputDir.data(), baseName.data(), + outputDir.data(), baseName.data()); + portable_sysTimerStart(); + if (portable_system("epstopdf",epstopdfArgs)!=0) + { + err("error: Problems running epstopdf. Check your TeX installation!\n"); + } + portable_sysTimerStop(); + return baseName; + } + } + else if (ambig) + { + QCString text; + text.sprintf("warning: image file name %s is ambiguous.\n",qPrint(fileName)); + text+="Possible candidates:\n"; + text+=showFileDefMatches(Doxygen::imageNameDict,fileName); + warn_doc_error(g_fileName,doctokenizerYYlineno,text); + } + else + { + result=fileName; + if (result.left(5)!="http:" && result.left(6)!="https:") + { + warn_doc_error(g_fileName,doctokenizerYYlineno, + "warning: image file %s is not found in IMAGE_PATH: " + "assuming external image.",qPrint(fileName) + ); + } + } + return result; +} + +/*! Collects the parameters found with \@param or \@retval commands + * in a global list g_paramsFound. If \a isParam is set to TRUE + * and the parameter is not an actual parameter of the current + * member g_memberDef, then a warning is raised (unless warnings + * are disabled altogether). + */ +static void checkArgumentName(const QCString &name,bool isParam) +{ + if (!Config_getBool("WARN_IF_DOC_ERROR")) return; + if (g_memberDef==0) return; // not a member + LockingPtr<ArgumentList> al=g_memberDef->isDocsForDefinition() ? + g_memberDef->argumentList() : + g_memberDef->declArgumentList(); + SrcLangExt lang = g_memberDef->getLanguage(); + //printf("isDocsForDefinition()=%d\n",g_memberDef->isDocsForDefinition()); + if (al==0) return; // no argument list + + static QRegExp re("[a-zA-Z0-9_\\x80-\\xFF]+\\.*"); + int p=0,i=0,l; + while ((i=re.match(name,p,&l))!=-1) // to handle @param x,y + { + QCString aName=name.mid(i,l); + if (lang==SrcLangExt_Fortran) aName=aName.lower(); + //printf("aName=`%s'\n",aName.data()); + ArgumentListIterator ali(*al); + Argument *a; + bool found=FALSE; + for (ali.toFirst();(a=ali.current());++ali) + { + QCString argName = g_memberDef->isDefine() ? a->type : a->name; + if (lang==SrcLangExt_Fortran) argName=argName.lower(); + argName=argName.stripWhiteSpace(); + //printf("argName=`%s'\n",argName.data()); + if (argName.right(3)=="...") argName=argName.left(argName.length()-3); + if (aName==argName) + { + //printf("adding `%s'\n",aName.data()); + g_paramsFound.insert(aName,(void *)(0x8)); + found=TRUE; + break; + } + } + if (!found && isParam) + { + //printf("member type=%d\n",memberDef->memberType()); + QCString scope=g_memberDef->getScopeString(); + if (!scope.isEmpty()) scope+="::"; else scope=""; + QCString inheritedFrom = ""; + QCString docFile = g_memberDef->docFile(); + int docLine = g_memberDef->docLine(); + MemberDef *inheritedMd = g_memberDef->inheritsDocsFrom(); + if (inheritedMd) // documentation was inherited + { + inheritedFrom.sprintf(" inherited from member %s at line " + "%d in file %s",qPrint(inheritedMd->name()), + inheritedMd->docLine(),qPrint(inheritedMd->docFile())); + docFile = g_memberDef->getDefFileName(); + docLine = g_memberDef->getDefLine(); + + } + QCString alStr = argListToString(al.pointer()); + warn_doc_error(docFile,docLine, + "warning: argument '%s' of command @param " + "is not found in the argument list of %s%s%s%s", + qPrint(aName), qPrint(scope), qPrint(g_memberDef->name()), + qPrint(alStr), qPrint(inheritedFrom)); + } + p=i+l; + } +} + +/*! Checks if the parameters that have been specified using \@param are + * indeed all paramters. + * Must be called after checkArgumentName() has been called for each + * argument. + */ +static void checkUndocumentedParams() +{ + if (g_memberDef && g_hasParamCommand && Config_getBool("WARN_IF_DOC_ERROR")) + { + LockingPtr<ArgumentList> al=g_memberDef->isDocsForDefinition() ? + g_memberDef->argumentList() : + g_memberDef->declArgumentList(); + SrcLangExt lang = g_memberDef->getLanguage(); + if (al!=0) + { + ArgumentListIterator ali(*al); + Argument *a; + bool found=FALSE; + for (ali.toFirst();(a=ali.current());++ali) + { + QCString argName = g_memberDef->isDefine() ? a->type : a->name; + if (lang==SrcLangExt_Fortran) argName = argName.lower(); + argName=argName.stripWhiteSpace(); + if (argName.right(3)=="...") argName=argName.left(argName.length()-3); + if (g_memberDef->getLanguage()==SrcLangExt_Python && argName=="self") + { + // allow undocumented self parameter for Python + } + else if (!argName.isEmpty() && g_paramsFound.find(argName)==0 && a->docs.isEmpty()) + { + found = TRUE; + break; + } + } + if (found) + { + bool first=TRUE; + QCString errMsg= + "warning: The following parameters of "+ + QCString(g_memberDef->qualifiedName()) + + QCString(argListToString(al.pointer())) + + " are not documented:\n"; + for (ali.toFirst();(a=ali.current());++ali) + { + QCString argName = g_memberDef->isDefine() ? a->type : a->name; + if (lang==SrcLangExt_Fortran) argName = argName.lower(); + argName=argName.stripWhiteSpace(); + if (g_memberDef->getLanguage()==SrcLangExt_Python && argName=="self") + { + // allow undocumented self parameter for Python + } + else if (!argName.isEmpty() && g_paramsFound.find(argName)==0) + { + if (!first) + { + errMsg+="\n"; + } + else + { + first=FALSE; + } + errMsg+=" parameter '"+argName+"'"; + } + } + if (g_memberDef->inheritsDocsFrom()) + { + warn_doc_error(g_memberDef->getDefFileName(), + g_memberDef->getDefLine(), + substitute(errMsg,"%","%%")); + } + else + { + warn_doc_error(g_memberDef->docFile(), + g_memberDef->docLine(), + substitute(errMsg,"%","%%")); + } + } + } + } +} + +/*! Check if a member has documentation for its parameter and or return + * type, if applicable. If found this will be stored in the member, this + * is needed as a member can have brief and detailed documentation, while + * only one of these needs to document the parameters. + */ +static void detectNoDocumentedParams() +{ + if (g_memberDef && Config_getBool("WARN_NO_PARAMDOC")) + { + LockingPtr<ArgumentList> al = g_memberDef->argumentList(); + LockingPtr<ArgumentList> declAl = g_memberDef->declArgumentList(); + QCString returnType = g_memberDef->typeString(); + bool isPython = g_memberDef->getLanguage()==SrcLangExt_Python; + + if (!g_memberDef->hasDocumentedParams() && + g_hasParamCommand) + { + //printf("%s->setHasDocumentedParams(TRUE);\n",g_memberDef->name().data()); + g_memberDef->setHasDocumentedParams(TRUE); + } + else if (!g_memberDef->hasDocumentedParams()) + { + bool allDoc=TRUE; // no paramater => all parameters are documented + if ( // member has parameters + al!=0 && // but the member has a parameter list + al->count()>0 // with at least one parameter (that is not void) + ) + { + ArgumentListIterator ali(*al); + Argument *a; + + // see if all parameters have documentation + for (ali.toFirst();(a=ali.current()) && allDoc;++ali) + { + if (!a->name.isEmpty() && a->type!="void" && + !(isPython && a->name=="self") + ) + { + allDoc = !a->docs.isEmpty(); + } + //printf("a->type=%s a->name=%s doc=%s\n", + // a->type.data(),a->name.data(),a->docs.data()); + } + if (!allDoc && declAl!=0) // try declaration arguments as well + { + allDoc=TRUE; + ArgumentListIterator ali(*declAl); + Argument *a; + for (ali.toFirst();(a=ali.current()) && allDoc;++ali) + { + if (!a->name.isEmpty() && a->type!="void" && + !(isPython && a->name=="self") + ) + { + allDoc = !a->docs.isEmpty(); + } + //printf("a->name=%s doc=%s\n",a->name.data(),a->docs.data()); + } + } + } + if (allDoc) + { + //printf("%s->setHasDocumentedParams(TRUE);\n",g_memberDef->name().data()); + g_memberDef->setHasDocumentedParams(TRUE); + } + } + //printf("Member %s hasReturnCommand=%d\n",g_memberDef->name().data(),g_hasReturnCommand); + if (!g_memberDef->hasDocumentedReturnType() && // docs not yet found + g_hasReturnCommand) + { + g_memberDef->setHasDocumentedReturnType(TRUE); + } + else if ( // see if return needs to documented + g_memberDef->hasDocumentedReturnType() || + returnType.isEmpty() || // empty return type + returnType.find("void")!=-1 || // void return type + returnType.find("subroutine")!=-1 || // fortran subroutine + g_memberDef->isConstructor() || // a constructor + g_memberDef->isDestructor() // or destructor + ) + { + g_memberDef->setHasDocumentedReturnType(TRUE); + } + + } +} + + +//--------------------------------------------------------------------------- + +/*! Strips known html and tex extensions from \a text. */ +static QCString stripKnownExtensions(const char *text) +{ + QCString result=text; + if (result.right(4)==".tex") + { + result=result.left(result.length()-4); + } + else if (result.right(Doxygen::htmlFileExtension.length())== + QCString(Doxygen::htmlFileExtension)) + { + result=result.left(result.length()-Doxygen::htmlFileExtension.length()); + } + return result; +} + + +//--------------------------------------------------------------------------- + +/*! Returns TRUE iff node n is a child of a preformatted node */ +static bool insidePRE(DocNode *n) +{ + while (n) + { + if (n->isPreformatted()) return TRUE; + n=n->parent(); + } + return FALSE; +} + +//--------------------------------------------------------------------------- + +/*! Returns TRUE iff node n is a child of a html list item node */ +static bool insideLI(DocNode *n) +{ + while (n) + { + if (n->kind()==DocNode::Kind_HtmlListItem) return TRUE; + n=n->parent(); + } + return FALSE; +} + +//--------------------------------------------------------------------------- + +/*! Returns TRUE iff node n is a child of a unordered html list node */ +static bool insideUL(DocNode *n) +{ + while (n) + { + if (n->kind()==DocNode::Kind_HtmlList && + ((DocHtmlList *)n)->type()==DocHtmlList::Unordered) return TRUE; + n=n->parent(); + } + return FALSE; +} + +//--------------------------------------------------------------------------- + +/*! Returns TRUE iff node n is a child of a ordered html list node */ +static bool insideOL(DocNode *n) +{ + while (n) + { + if (n->kind()==DocNode::Kind_HtmlList && + ((DocHtmlList *)n)->type()==DocHtmlList::Ordered) return TRUE; + n=n->parent(); + } + return FALSE; +} + +//--------------------------------------------------------------------------- + +static bool insideTable(DocNode *n) +{ + while (n) + { + if (n->kind()==DocNode::Kind_HtmlTable) return TRUE; + n=n->parent(); + } + return FALSE; +} + +//--------------------------------------------------------------------------- + +///*! Returns TRUE iff node n is a child of a language node */ +//static bool insideLang(DocNode *n) +//{ +// while (n) +// { +// if (n->kind()==DocNode::Kind_Language) return TRUE; +// n=n->parent(); +// } +// return FALSE; +//} + + +//--------------------------------------------------------------------------- + +/*! Looks for a documentation block with name commandName in the current + * context (g_context). The resulting documentation string is + * put in pDoc, the definition in which the documentation was found is + * put in pDef. + * @retval TRUE if name was found. + * @retval FALSE if name was not found. + */ +static bool findDocsForMemberOrCompound(const char *commandName, + QCString *pDoc, + QCString *pBrief, + Definition **pDef) +{ + //printf("findDocsForMemberOrCompound(%s)\n",commandName); + *pDoc=""; + *pBrief=""; + *pDef=0; + QCString cmdArg=substitute(commandName,"#","::"); + int l=cmdArg.length(); + if (l==0) return FALSE; + + int funcStart=cmdArg.find('('); + if (funcStart==-1) + { + funcStart=l; + } + else + { + // Check for the case of operator() and the like. + // beware of scenarios like operator()((foo)bar) + int secondParen = cmdArg.find('(', funcStart+1); + int leftParen = cmdArg.find(')', funcStart+1); + if (leftParen!=-1 && secondParen!=-1) + { + if (leftParen<secondParen) + { + funcStart=secondParen; + } + } + } + + QCString name=removeRedundantWhiteSpace(cmdArg.left(funcStart)); + QCString args=cmdArg.right(l-funcStart); + + // try if the link is to a member + MemberDef *md=0; + ClassDef *cd=0; + FileDef *fd=0; + NamespaceDef *nd=0; + GroupDef *gd=0; + PageDef *pd=0; + bool found = getDefs( + g_context.find('.')==-1?g_context.data():"", // `find('.') is a hack to detect files + name, + args.isEmpty()?0:args.data(), + md,cd,fd,nd,gd,FALSE,0,TRUE); + //printf("found=%d context=%s name=%s\n",found,g_context.data(),name.data()); + if (found && md) + { + *pDoc=md->documentation(); + *pBrief=md->briefDescription(); + *pDef=md; + return TRUE; + } + + + int scopeOffset=g_context.length(); + do // for each scope + { + QCString fullName=cmdArg; + if (scopeOffset>0) + { + fullName.prepend(g_context.left(scopeOffset)+"::"); + } + //printf("Trying fullName=`%s'\n",fullName.data()); + + // try class, namespace, group, page, file reference + cd = Doxygen::classSDict->find(fullName); + if (cd) // class + { + *pDoc=cd->documentation(); + *pBrief=cd->briefDescription(); + *pDef=cd; + return TRUE; + } + nd = Doxygen::namespaceSDict->find(fullName); + if (nd) // namespace + { + *pDoc=nd->documentation(); + *pBrief=nd->briefDescription(); + *pDef=nd; + return TRUE; + } + gd = Doxygen::groupSDict->find(cmdArg); + if (gd) // group + { + *pDoc=gd->documentation(); + *pBrief=gd->briefDescription(); + *pDef=gd; + return TRUE; + } + pd = Doxygen::pageSDict->find(cmdArg); + if (pd) // page + { + *pDoc=pd->documentation(); + *pBrief=pd->briefDescription(); + *pDef=pd; + return TRUE; + } + bool ambig; + fd = findFileDef(Doxygen::inputNameDict,cmdArg,ambig); + if (fd && !ambig) // file + { + *pDoc=fd->documentation(); + *pBrief=fd->briefDescription(); + *pDef=fd; + return TRUE; + } + + if (scopeOffset==0) + { + scopeOffset=-1; + } + else + { + scopeOffset = g_context.findRev("::",scopeOffset-1); + if (scopeOffset==-1) scopeOffset=0; + } + } while (scopeOffset>=0); + + + return FALSE; +} +//--------------------------------------------------------------------------- + +// forward declaration +static bool defaultHandleToken(DocNode *parent,int tok, + QList<DocNode> &children,bool + handleWord=TRUE); + + +static int handleStyleArgument(DocNode *parent,QList<DocNode> &children, + const QCString &cmdName) +{ + DBG(("handleStyleArgument(%s)\n",qPrint(cmdName))); + QCString tokenName = g_token->name; + int tok=doctokenizerYYlex(); + if (tok!=TK_WHITESPACE) + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected whitespace after %s command", + qPrint(cmdName)); + return tok; + } + while ((tok=doctokenizerYYlex()) && + tok!=TK_WHITESPACE && + tok!=TK_NEWPARA && + tok!=TK_LISTITEM && + tok!=TK_ENDLIST + ) + { + static QRegExp specialChar("[.,|()\\[\\]:;\\?]"); + if (tok==TK_WORD && g_token->name.length()==1 && + g_token->name.find(specialChar)!=-1) + { + // special character that ends the markup command + return tok; + } + if (!defaultHandleToken(parent,tok,children)) + { + switch (tok) + { + case TK_COMMAND: + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Illegal command \\%s as the argument of a \\%s command", + qPrint(g_token->name),qPrint(cmdName)); + break; + case TK_SYMBOL: + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unsupported symbol %s found while handling command %s", + qPrint(g_token->name),qPrint(cmdName)); + break; + case TK_HTMLTAG: + if (insideLI(parent) && Mappers::htmlTagMapper->map(g_token->name) && g_token->endTag) + { // ignore </li> as the end of a style command + continue; + } + return tok; + break; + default: + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected token %s while handling command %s", + tokToString(tok),qPrint(cmdName)); + break; + } + break; + } + } + DBG(("handleStyleArgument(%s) end tok=%x\n",qPrint(cmdName),tok)); + return (tok==TK_NEWPARA || tok==TK_LISTITEM || tok==TK_ENDLIST + ) ? tok : RetVal_OK; +} + +/*! Called when a style change starts. For instance a \<b\> command is + * encountered. + */ +static void handleStyleEnter(DocNode *parent,QList<DocNode> &children, + DocStyleChange::Style s,const HtmlAttribList *attribs) +{ + DBG(("HandleStyleEnter\n")); + DocStyleChange *sc= new DocStyleChange(parent,g_nodeStack.count(),s,TRUE,attribs); + children.append(sc); + g_styleStack.push(sc); +} + +/*! Called when a style change ends. For instance a \</b\> command is + * encountered. + */ +static void handleStyleLeave(DocNode *parent,QList<DocNode> &children, + DocStyleChange::Style s,const char *tagName) +{ + DBG(("HandleStyleLeave\n")); + if (g_styleStack.isEmpty() || // no style change + g_styleStack.top()->style()!=s || // wrong style change + g_styleStack.top()->position()!=g_nodeStack.count() // wrong position + ) + { + if (g_styleStack.isEmpty()) + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: found </%s> tag without matching <%s>", + qPrint(tagName),qPrint(tagName)); + } + else if (g_styleStack.top()->style()!=s) + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: found </%s> tag while expecting </%s>", + qPrint(tagName),qPrint(g_styleStack.top()->styleString())); + } + else + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: found </%s> at different nesting level (%d) than expected (%d)", + qPrint(tagName),g_nodeStack.count(),g_styleStack.top()->position()); + } + } + else // end the section + { + DocStyleChange *sc= new DocStyleChange(parent,g_nodeStack.count(),s,FALSE); + children.append(sc); + g_styleStack.pop(); + } +} + +/*! Called at the end of a paragraph to close all open style changes + * (e.g. a <b> without a </b>). The closed styles are pushed onto a stack + * and entered again at the start of a new paragraph. + */ +static void handlePendingStyleCommands(DocNode *parent,QList<DocNode> &children) +{ + if (!g_styleStack.isEmpty()) + { + DocStyleChange *sc = g_styleStack.top(); + while (sc && sc->position()>=g_nodeStack.count()) + { // there are unclosed style modifiers in the paragraph + children.append(new DocStyleChange(parent,g_nodeStack.count(),sc->style(),FALSE)); + g_initialStyleStack.push(sc); + g_styleStack.pop(); + sc = g_styleStack.top(); + } + } +} + +static void handleInitialStyleCommands(DocPara *parent,QList<DocNode> &children) +{ + DocStyleChange *sc; + while ((sc=g_initialStyleStack.pop())) + { + handleStyleEnter(parent,children,sc->style(),&sc->attribs()); + } +} + +static int handleAHref(DocNode *parent,QList<DocNode> &children,const HtmlAttribList &tagHtmlAttribs) +{ + HtmlAttribListIterator li(tagHtmlAttribs); + HtmlAttrib *opt; + int index=0; + int retval = RetVal_OK; + for (li.toFirst();(opt=li.current());++li,++index) + { + if (opt->name=="name") // <a name=label> tag + { + if (!opt->value.isEmpty()) + { + DocAnchor *anc = new DocAnchor(parent,opt->value,TRUE); + children.append(anc); + break; // stop looking for other tag attribs + } + else + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: found <a> tag with name option but without value!"); + } + } + else if (opt->name=="href") // <a href=url>..</a> tag + { + // copy attributes + HtmlAttribList attrList = tagHtmlAttribs; + // and remove the href attribute + bool result = attrList.remove(index); + ASSERT(result); + DocHRef *href = new DocHRef(parent,attrList,opt->value,g_relPath); + children.append(href); + g_insideHtmlLink=TRUE; + retval = href->parse(); + g_insideHtmlLink=FALSE; + break; + } + else // unsupported option for tag a + { + } + } + return retval; +} + +const char *DocStyleChange::styleString() const +{ + switch (m_style) + { + case DocStyleChange::Bold: return "b"; + case DocStyleChange::Italic: return "em"; + case DocStyleChange::Code: return "code"; + case DocStyleChange::Center: return "center"; + case DocStyleChange::Small: return "small"; + case DocStyleChange::Subscript: return "subscript"; + case DocStyleChange::Superscript: return "superscript"; + case DocStyleChange::Preformatted: return "pre"; + case DocStyleChange::Div: return "div"; + case DocStyleChange::Span: return "span"; + } + return "<invalid>"; +} + +static void handleUnclosedStyleCommands() +{ + if (!g_initialStyleStack.isEmpty()) + { + DocStyleChange *sc = g_initialStyleStack.top(); + g_initialStyleStack.pop(); + handleUnclosedStyleCommands(); + warn_doc_error(g_fileName,doctokenizerYYlineno, + "warning: end of comment block while expecting " + "command </%s>",qPrint(sc->styleString())); + } +} + +static void handleLinkedWord(DocNode *parent,QList<DocNode> &children) +{ + Definition *compound=0; + MemberDef *member=0; + QCString name = linkToText(SrcLangExt_Unknown,g_token->name,TRUE); + int len = g_token->name.length(); + ClassDef *cd=0; + bool ambig; + FileDef *fd = findFileDef(Doxygen::inputNameDict,g_fileName,ambig); + //printf("handleLinkedWord(%s) g_context=%s\n",g_token->name.data(),g_context.data()); + if (!g_insideHtmlLink && + (resolveRef(g_context,g_token->name,g_inSeeBlock,&compound,&member,TRUE,fd,TRUE) + || (!g_context.isEmpty() && // also try with global scope + resolveRef("",g_token->name,g_inSeeBlock,&compound,&member,FALSE,0,TRUE)) + ) + ) + { + //printf("resolveRef %s = %p (linkable?=%d)\n",qPrint(g_token->name),member,member ? member->isLinkable() : FALSE); + if (member && member->isLinkable()) // member link + { + if (member->isObjCMethod()) + { + bool localLink = g_memberDef ? member->getClassDef()==g_memberDef->getClassDef() : FALSE; + name = member->objCMethodName(localLink,g_inSeeBlock); + } + children.append(new + DocLinkedWord(parent,name, + member->getReference(), + member->getOutputFileBase(), + member->anchor(), + member->briefDescriptionAsTooltip() + ) + ); + } + else if (compound->isLinkable()) // compound link + { + QCString anchor = compound->anchor(); + if (compound->definitionType()==Definition::TypeFile) + { + name=g_token->name; + } + else if (compound->definitionType()==Definition::TypeGroup) + { + name=((GroupDef*)compound)->groupTitle(); + } + children.append(new + DocLinkedWord(parent,name, + compound->getReference(), + compound->getOutputFileBase(), + anchor, + compound->briefDescriptionAsTooltip() + ) + ); + } + else if (compound->definitionType()==Definition::TypeFile && + ((FileDef*)compound)->generateSourceFile() + ) // undocumented file that has source code we can link to + { + children.append(new + DocLinkedWord(parent,g_token->name, + compound->getReference(), + compound->getSourceFileBase(), + "", + compound->briefDescriptionAsTooltip() + ) + ); + } + else // not linkable + { + children.append(new DocWord(parent,name)); + } + } + else if (!g_insideHtmlLink && len>1 && g_token->name.at(len-1)==':') + { + // special case, where matching Foo: fails to be an Obj-C reference, + // but Foo itself might be linkable. + g_token->name=g_token->name.left(len-1); + handleLinkedWord(parent,children); + children.append(new DocWord(parent,":")); + } + else if (!g_insideHtmlLink && (cd=getClass(g_token->name+"-p"))) + { + // special case 2, where the token name is not a class, but could + // be a Obj-C protocol + children.append(new + DocLinkedWord(parent,name, + cd->getReference(), + cd->getOutputFileBase(), + cd->anchor(), + cd->briefDescriptionAsTooltip() + )); + } + else if (!g_insideHtmlLink && (cd=getClass(g_token->name+"-g"))) + { + // special case 3, where the token name is not a class, but could + // be a C# generic + children.append(new + DocLinkedWord(parent,name, + cd->getReference(), + cd->getOutputFileBase(), + cd->anchor(), + cd->briefDescriptionAsTooltip() + )); + } + else // normal non-linkable word + { + if (g_token->name.left(1)=="#" || g_token->name.left(2)=="::") + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: explicit link request to '%s' could not be resolved",qPrint(name)); + children.append(new DocWord(parent,g_token->name)); + } + else + { + children.append(new DocWord(parent,name)); + } + } +} + +static void handleParameterType(DocNode *parent,QList<DocNode> &children,const QCString ¶mTypes) +{ + QCString name = g_token->name; + int p=0,i; + QCString type; + while ((i=paramTypes.find('|',p))!=-1) + { + g_token->name = paramTypes.mid(p,i-p); + handleLinkedWord(parent,children); + p=i+1; + } + g_token->name = paramTypes.mid(p); + handleLinkedWord(parent,children); + g_token->name = name; +} + +static DocInternalRef *handleInternalRef(DocNode *parent) +{ + //printf("CMD_INTERNALREF\n"); + int tok=doctokenizerYYlex(); + QCString tokenName = g_token->name; + if (tok!=TK_WHITESPACE) + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected whitespace after %s command", + qPrint(tokenName)); + return 0; + } + doctokenizerYYsetStateInternalRef(); + tok=doctokenizerYYlex(); // get the reference id + if (tok!=TK_WORD && tok!=TK_LNKWORD) + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected token %s as the argument of %s", + tokToString(tok),qPrint(tokenName)); + return 0; + } + return new DocInternalRef(parent,g_token->name); +} + +static DocAnchor *handleAnchor(DocNode *parent) +{ + int tok=doctokenizerYYlex(); + if (tok!=TK_WHITESPACE) + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected whitespace after %s command", + qPrint(g_token->name)); + return 0; + } + doctokenizerYYsetStateAnchor(); + tok=doctokenizerYYlex(); + if (tok==0) + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected end of comment block while parsing the " + "argument of command %s",qPrint(g_token->name)); + return 0; + } + else if (tok!=TK_WORD && tok!=TK_LNKWORD) + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected token %s as the argument of %s", + tokToString(tok),qPrint(g_token->name)); + return 0; + } + doctokenizerYYsetStatePara(); + return new DocAnchor(parent,g_token->name,FALSE); +} + + +/* Helper function that deals with the most common tokens allowed in + * title like sections. + * @param parent Parent node, owner of the children list passed as + * the third argument. + * @param tok The token to process. + * @param children The list of child nodes to which the node representing + * the token can be added. + * @param handleWord Indicates if word token should be processed + * @retval TRUE The token was handled. + * @retval FALSE The token was not handled. + */ +static bool defaultHandleToken(DocNode *parent,int tok, QList<DocNode> &children,bool + handleWord) +{ + DBG(("token %s at %d",tokToString(tok),doctokenizerYYlineno)); + if (tok==TK_WORD || tok==TK_LNKWORD || tok==TK_SYMBOL || tok==TK_URL || + tok==TK_COMMAND || tok==TK_HTMLTAG + ) + { + DBG((" name=%s",qPrint(g_token->name))); + } + DBG(("\n")); +reparsetoken: + QCString tokenName = g_token->name; + switch (tok) + { + case TK_COMMAND: + switch (Mappers::cmdMapper->map(tokenName)) + { + case CMD_BSLASH: + children.append(new DocSymbol(parent,DocSymbol::BSlash)); + break; + case CMD_AT: + children.append(new DocSymbol(parent,DocSymbol::At)); + break; + case CMD_LESS: + children.append(new DocSymbol(parent,DocSymbol::Less)); + break; + case CMD_GREATER: + children.append(new DocSymbol(parent,DocSymbol::Greater)); + break; + case CMD_AMP: + children.append(new DocSymbol(parent,DocSymbol::Amp)); + break; + case CMD_DOLLAR: + children.append(new DocSymbol(parent,DocSymbol::Dollar)); + break; + case CMD_HASH: + children.append(new DocSymbol(parent,DocSymbol::Hash)); + break; + case CMD_DCOLON: + children.append(new DocSymbol(parent,DocSymbol::DoubleColon)); + break; + case CMD_PERCENT: + children.append(new DocSymbol(parent,DocSymbol::Percent)); + break; + case CMD_QUOTE: + children.append(new DocSymbol(parent,DocSymbol::Quot)); + break; + case CMD_EMPHASIS: + { + children.append(new DocStyleChange(parent,g_nodeStack.count(),DocStyleChange::Italic,TRUE)); + tok=handleStyleArgument(parent,children,tokenName); + children.append(new DocStyleChange(parent,g_nodeStack.count(),DocStyleChange::Italic,FALSE)); + if (tok!=TK_WORD) children.append(new DocWhiteSpace(parent," ")); + if (tok==TK_NEWPARA) goto handlepara; + else if (tok==TK_WORD || tok==TK_HTMLTAG) + { + DBG(("CMD_EMPHASIS: reparsing command %s\n",qPrint(g_token->name))); + goto reparsetoken; + } + } + break; + case CMD_BOLD: + { + children.append(new DocStyleChange(parent,g_nodeStack.count(),DocStyleChange::Bold,TRUE)); + tok=handleStyleArgument(parent,children,tokenName); + children.append(new DocStyleChange(parent,g_nodeStack.count(),DocStyleChange::Bold,FALSE)); + if (tok!=TK_WORD) children.append(new DocWhiteSpace(parent," ")); + if (tok==TK_NEWPARA) goto handlepara; + else if (tok==TK_WORD || tok==TK_HTMLTAG) + { + DBG(("CMD_BOLD: reparsing command %s\n",qPrint(g_token->name))); + goto reparsetoken; + } + } + break; + case CMD_CODE: + { + children.append(new DocStyleChange(parent,g_nodeStack.count(),DocStyleChange::Code,TRUE)); + tok=handleStyleArgument(parent,children,tokenName); + children.append(new DocStyleChange(parent,g_nodeStack.count(),DocStyleChange::Code,FALSE)); + if (tok!=TK_WORD) children.append(new DocWhiteSpace(parent," ")); + if (tok==TK_NEWPARA) goto handlepara; + else if (tok==TK_WORD || tok==TK_HTMLTAG) + { + DBG(("CMD_CODE: reparsing command %s\n",qPrint(g_token->name))); + goto reparsetoken; + } + } + break; + case CMD_HTMLONLY: + { + doctokenizerYYsetStateHtmlOnly(); + tok = doctokenizerYYlex(); + children.append(new DocVerbatim(parent,g_context,g_token->verb,DocVerbatim::HtmlOnly,g_isExample,g_exampleName)); + if (tok==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: htmlonly section ended without end marker"); + doctokenizerYYsetStatePara(); + } + break; + case CMD_MANONLY: + { + doctokenizerYYsetStateManOnly(); + tok = doctokenizerYYlex(); + children.append(new DocVerbatim(parent,g_context,g_token->verb,DocVerbatim::ManOnly,g_isExample,g_exampleName)); + if (tok==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: manonly section ended without end marker"); + doctokenizerYYsetStatePara(); + } + break; + case CMD_LATEXONLY: + { + doctokenizerYYsetStateLatexOnly(); + tok = doctokenizerYYlex(); + children.append(new DocVerbatim(parent,g_context,g_token->verb,DocVerbatim::LatexOnly,g_isExample,g_exampleName)); + if (tok==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: latexonly section ended without end marker",doctokenizerYYlineno); + doctokenizerYYsetStatePara(); + } + break; + case CMD_XMLONLY: + { + doctokenizerYYsetStateXmlOnly(); + tok = doctokenizerYYlex(); + children.append(new DocVerbatim(parent,g_context,g_token->verb,DocVerbatim::XmlOnly,g_isExample,g_exampleName)); + if (tok==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: xmlonly section ended without end marker",doctokenizerYYlineno); + doctokenizerYYsetStatePara(); + } + break; + case CMD_FORMULA: + { + DocFormula *form=new DocFormula(parent,g_token->id); + children.append(form); + } + break; + case CMD_ANCHOR: + { + DocAnchor *anchor = handleAnchor(parent); + if (anchor) + { + children.append(anchor); + } + } + break; + case CMD_INTERNALREF: + { + DocInternalRef *ref = handleInternalRef(parent); + if (ref) + { + children.append(ref); + ref->parse(); + } + doctokenizerYYsetStatePara(); + } + break; + default: + return FALSE; + } + break; + case TK_HTMLTAG: + { + switch (Mappers::htmlTagMapper->map(tokenName)) + { + case HTML_DIV: + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: found <div> tag in heading\n"); + break; + case HTML_PRE: + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: found <pre> tag in heading\n"); + break; + case HTML_BOLD: + if (!g_token->endTag) + { + handleStyleEnter(parent,children,DocStyleChange::Bold,&g_token->attribs); + } + else + { + handleStyleLeave(parent,children,DocStyleChange::Bold,tokenName); + } + break; + case HTML_CODE: + case XML_C: + if (!g_token->endTag) + { + handleStyleEnter(parent,children,DocStyleChange::Code,&g_token->attribs); + } + else + { + handleStyleLeave(parent,children,DocStyleChange::Code,tokenName); + } + break; + case HTML_EMPHASIS: + if (!g_token->endTag) + { + handleStyleEnter(parent,children,DocStyleChange::Italic,&g_token->attribs); + } + else + { + handleStyleLeave(parent,children,DocStyleChange::Italic,tokenName); + } + break; + case HTML_SUB: + if (!g_token->endTag) + { + handleStyleEnter(parent,children,DocStyleChange::Subscript,&g_token->attribs); + } + else + { + handleStyleLeave(parent,children,DocStyleChange::Subscript,tokenName); + } + break; + case HTML_SUP: + if (!g_token->endTag) + { + handleStyleEnter(parent,children,DocStyleChange::Superscript,&g_token->attribs); + } + else + { + handleStyleLeave(parent,children,DocStyleChange::Superscript,tokenName); + } + break; + case HTML_CENTER: + if (!g_token->endTag) + { + handleStyleEnter(parent,children,DocStyleChange::Center,&g_token->attribs); + } + else + { + handleStyleLeave(parent,children,DocStyleChange::Center,tokenName); + } + break; + case HTML_SMALL: + if (!g_token->endTag) + { + handleStyleEnter(parent,children,DocStyleChange::Small,&g_token->attribs); + } + else + { + handleStyleLeave(parent,children,DocStyleChange::Small,tokenName); + } + break; + default: + return FALSE; + break; + } + } + break; + case TK_SYMBOL: + { + char letter='\0'; + DocSymbol::SymType s = DocSymbol::decodeSymbol(tokenName,&letter); + if (s!=DocSymbol::Unknown) + { + children.append(new DocSymbol(parent,s,letter)); + } + else + { + return FALSE; + } + } + break; + case TK_WHITESPACE: + case TK_NEWPARA: +handlepara: + if (insidePRE(parent) || !children.isEmpty()) + { + children.append(new DocWhiteSpace(parent,g_token->chars)); + } + break; + case TK_LNKWORD: + if (handleWord) + { + handleLinkedWord(parent,children); + } + else + return FALSE; + break; + case TK_WORD: + if (handleWord) + { + children.append(new DocWord(parent,g_token->name)); + } + else + return FALSE; + break; + case TK_URL: + if (g_insideHtmlLink) + { + children.append(new DocWord(parent,g_token->name)); + } + else + { + children.append(new DocURL(parent,g_token->name,g_token->isEMailAddr)); + } + break; + default: + return FALSE; + } + return TRUE; +} + + +//--------------------------------------------------------------------------- + +DocSymbol::SymType DocSymbol::decodeSymbol(const QCString &symName,char *letter) +{ + int l=symName.length(); + DBG(("decodeSymbol(%s) l=%d\n",qPrint(symName),l)); + if (symName=="©") return DocSymbol::Copy; + else if (symName=="™") return DocSymbol::Tm; + else if (symName=="&tm;") return DocSymbol::Tm; // alias for ™ + else if (symName=="®") return DocSymbol::Reg; + else if (symName=="<") return DocSymbol::Less; + else if (symName==">") return DocSymbol::Greater; + else if (symName=="&") return DocSymbol::Amp; + else if (symName=="'") return DocSymbol::Apos; + else if (symName==""") return DocSymbol::Quot; + else if (symName=="‘") return DocSymbol::Lsquo; + else if (symName=="’") return DocSymbol::Rsquo; + else if (symName=="“") return DocSymbol::Ldquo; + else if (symName=="”") return DocSymbol::Rdquo; + else if (symName=="–") return DocSymbol::Ndash; + else if (symName=="—") return DocSymbol::Mdash; + else if (symName=="ß") return DocSymbol::Szlig; + else if (symName==" ") return DocSymbol::Nbsp; + else if (symName=="Æ") return DocSymbol::AElig; + else if (symName=="æ") return DocSymbol::Aelig; + else if (l==6 && symName.right(4)=="uml;") + { + *letter=symName.at(1); + return DocSymbol::Uml; + } + else if (l==8 && symName.right(6)=="acute;") + { + *letter=symName.at(1); + return DocSymbol::Acute; + } + else if (l==8 && symName.right(6)=="grave;") + { + *letter=symName.at(1); + return DocSymbol::Grave; + } + else if (l==7 && symName.right(5)=="circ;") + { + *letter=symName.at(1); + return DocSymbol::Circ; + } + else if (l==8 && symName.right(6)=="tilde;") + { + *letter=symName.at(1); + return DocSymbol::Tilde; + } + else if (l==8 && symName.right(6)=="cedil;") + { + *letter=symName.at(1); + return DocSymbol::Cedil; + } + else if (l==7 && symName.right(5)=="ring;") + { + *letter=symName.at(1); + return DocSymbol::Ring; + } + else if (l==8 && symName.right(6)=="slash;") + { + *letter=symName.at(1); + return DocSymbol::Slash; + } + return DocSymbol::Unknown; +} + +//--------------------------------------------------------------------------- + +static int internalValidatingParseDoc(DocNode *parent,QList<DocNode> &children, + const QCString &doc) +{ + int retval = RetVal_OK; + + if (doc.isEmpty()) return retval; + + doctokenizerYYinit(doc,g_fileName); + + // first parse any number of paragraphs + bool isFirst=TRUE; + DocPara *lastPar=0; + if (!children.isEmpty() && children.last()->kind()==DocNode::Kind_Para) + { // last child item was a paragraph + lastPar = (DocPara*)children.last(); + isFirst=FALSE; + } + do + { + DocPara *par = new DocPara(parent); + if (isFirst) { par->markFirst(); isFirst=FALSE; } + retval=par->parse(); + if (!par->isEmpty()) + { + children.append(par); + if (lastPar) lastPar->markLast(FALSE); + lastPar=par; + } + else + { + delete par; + } + } while (retval==TK_NEWPARA); + if (lastPar) lastPar->markLast(); + + //printf("internalValidateParsingDoc: %p: isFirst=%d isLast=%d\n", + // lastPar,lastPar?lastPar->isFirst():-1,lastPar?lastPar->isLast():-1); + + return retval; +} + +//--------------------------------------------------------------------------- + +static void readTextFileByName(const QCString &file,QCString &text) +{ + QStrList &examplePathList = Config_getList("EXAMPLE_PATH"); + char *s=examplePathList.first(); + while (s) + { + QCString absFileName = QCString(s)+portable_pathSeparator()+file; + QFileInfo fi(absFileName); + if (fi.exists()) + { + text = fileToString(absFileName,Config_getBool("FILTER_SOURCE_FILES")); + return; + } + s=examplePathList.next(); + } + + // as a fallback we also look in the exampleNameDict + bool ambig; + FileDef *fd; + if ((fd=findFileDef(Doxygen::exampleNameDict,file,ambig))) + { + text = fileToString(fd->absFilePath(),Config_getBool("FILTER_SOURCE_FILES")); + } + else if (ambig) + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: included file name %s is ambiguous" + "Possible candidates:\n%s",qPrint(file), + qPrint(showFileDefMatches(Doxygen::exampleNameDict,file)) + ); + } + else + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: included file %s is not found. " + "Check your EXAMPLE_PATH",qPrint(file)); + } +} + +//--------------------------------------------------------------------------- + +DocWord::DocWord(DocNode *parent,const QCString &word) : + m_word(word) +{ + m_parent = parent; + //printf("new word %s url=%s\n",word.data(),g_searchUrl.data()); + if (Doxygen::searchIndex && !g_searchUrl.isEmpty()) + { + Doxygen::searchIndex->addWord(word,FALSE); + } +} + +//--------------------------------------------------------------------------- + +DocLinkedWord::DocLinkedWord(DocNode *parent,const QCString &word, + const QCString &ref,const QCString &file, + const QCString &anchor,const QCString &tooltip) : + m_word(word), m_ref(ref), + m_file(file), m_relPath(g_relPath), m_anchor(anchor), + m_tooltip(tooltip) +{ + m_parent = parent; + //printf("DocLinkedWord: new word %s url=%s tooltip='%s'\n", + // word.data(),g_searchUrl.data(),tooltip.data()); + if (Doxygen::searchIndex && !g_searchUrl.isEmpty()) + { + Doxygen::searchIndex->addWord(word,FALSE); + } +} + +//--------------------------------------------------------------------------- + +DocAnchor::DocAnchor(DocNode *parent,const QCString &id,bool newAnchor) +{ + m_parent = parent; + if (id.isEmpty()) + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Empty anchor label"); + } + if (newAnchor) // found <a name="label"> + { + m_anchor = id; + } + else if (id.left(CiteConsts::anchorPrefix.length()) == CiteConsts::anchorPrefix) + { + CiteInfo *cite = Doxygen::citeDict->find(id.mid(CiteConsts::anchorPrefix.length())); + if (cite) + { + m_file = convertNameToFile(CiteConsts::fileName,FALSE,TRUE); + m_anchor = id; + } + else + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Invalid cite anchor id `%s'",qPrint(id)); + m_anchor = "invalid"; + m_file = "invalid"; + } + } + else // found \anchor label + { + SectionInfo *sec = Doxygen::sectionDict[id]; + if (sec) + { + //printf("Found anchor %s\n",id.data()); + m_file = sec->fileName; + m_anchor = sec->label; + if (g_sectionDict && g_sectionDict->find(id)==0) + { + //printf("Inserting in dictionary!\n"); + g_sectionDict->append(id,sec); + } + } + else + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Invalid anchor id `%s'",qPrint(id)); + m_anchor = "invalid"; + m_file = "invalid"; + } + } +} + +//--------------------------------------------------------------------------- + +DocVerbatim::DocVerbatim(DocNode *parent,const QCString &context, + const QCString &text, Type t,bool isExample, + const QCString &exampleFile,const QCString &lang) + : m_context(context), m_text(text), m_type(t), + m_isExample(isExample), m_exampleFile(exampleFile), + m_relPath(g_relPath), m_lang(lang) +{ + m_parent = parent; +} + + +//--------------------------------------------------------------------------- + +void DocInclude::parse() +{ + DBG(("DocInclude::parse(file=%s,text=%s)\n",qPrint(m_file),qPrint(m_text))); + switch(m_type) + { + case IncWithLines: + // fall through + case Include: + // fall through + case DontInclude: + readTextFileByName(m_file,m_text); + g_includeFileText = m_text; + g_includeFileOffset = 0; + g_includeFileLength = m_text.length(); + //printf("g_includeFile=<<%s>>\n",g_includeFileText.data()); + break; + case VerbInclude: + // fall through + case HtmlInclude: + readTextFileByName(m_file,m_text); + break; + case Snippet: + readTextFileByName(m_file,m_text); + // check here for the existance of the blockId inside the file, so we + // only generate the warning once. + int count; + if (!m_blockId.isEmpty() && (count=m_text.contains(m_blockId.data()))!=2) + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: block marked with %s for \\snippet should appear twice in file %s, found it %d times\n", + m_blockId.data(),m_file.data(),count); + } + break; + } +} + +//--------------------------------------------------------------------------- + +void DocIncOperator::parse() +{ + const char *p = g_includeFileText; + uint l = g_includeFileLength; + uint o = g_includeFileOffset; + DBG(("DocIncOperator::parse() text=%s off=%d len=%d\n",qPrint(p),o,l)); + uint so = o,bo; + bool nonEmpty = FALSE; + switch(type()) + { + case Line: + while (o<l) + { + char c = p[o]; + if (c=='\n') + { + if (nonEmpty) break; // we have a pattern to match + so=o+1; // no pattern, skip empty line + } + else if (!isspace((uchar)c)) // no white space char + { + nonEmpty=TRUE; + } + o++; + } + if (g_includeFileText.mid(so,o-so).find(m_pattern)!=-1) + { + m_text = g_includeFileText.mid(so,o-so); + DBG(("DocIncOperator::parse() Line: %s\n",qPrint(m_text))); + } + g_includeFileOffset = QMIN(l,o+1); // set pointer to start of new line + break; + case SkipLine: + while (o<l) + { + so=o; + while (o<l) + { + char c = p[o]; + if (c=='\n') + { + if (nonEmpty) break; // we have a pattern to match + so=o+1; // no pattern, skip empty line + } + else if (!isspace((uchar)c)) // no white space char + { + nonEmpty=TRUE; + } + o++; + } + if (g_includeFileText.mid(so,o-so).find(m_pattern)!=-1) + { + m_text = g_includeFileText.mid(so,o-so); + DBG(("DocIncOperator::parse() SkipLine: %s\n",qPrint(m_text))); + break; + } + o++; // skip new line + } + g_includeFileOffset = QMIN(l,o+1); // set pointer to start of new line + break; + case Skip: + while (o<l) + { + so=o; + while (o<l) + { + char c = p[o]; + if (c=='\n') + { + if (nonEmpty) break; // we have a pattern to match + so=o+1; // no pattern, skip empty line + } + else if (!isspace((uchar)c)) // no white space char + { + nonEmpty=TRUE; + } + o++; + } + if (g_includeFileText.mid(so,o-so).find(m_pattern)!=-1) + { + break; + } + o++; // skip new line + } + g_includeFileOffset = so; // set pointer to start of new line + break; + case Until: + bo=o; + while (o<l) + { + so=o; + while (o<l) + { + char c = p[o]; + if (c=='\n') + { + if (nonEmpty) break; // we have a pattern to match + so=o+1; // no pattern, skip empty line + } + else if (!isspace((uchar)c)) // no white space char + { + nonEmpty=TRUE; + } + o++; + } + if (g_includeFileText.mid(so,o-so).find(m_pattern)!=-1) + { + m_text = g_includeFileText.mid(bo,o-bo); + DBG(("DocIncOperator::parse() Until: %s\n",qPrint(m_text))); + break; + } + o++; // skip new line + } + g_includeFileOffset = QMIN(l,o+1); // set pointer to start of new line + break; + } +} + +//--------------------------------------------------------------------------- + +void DocCopy::parse(QList<DocNode> &children) +{ + QCString doc,brief; + Definition *def; + if (findDocsForMemberOrCompound(m_link,&doc,&brief,&def)) + { + if (g_copyStack.findRef(def)==-1) // definition not parsed earlier + { + bool hasParamCommand = g_hasParamCommand; + bool hasReturnCommand = g_hasReturnCommand; + QDict<void> paramsFound = g_paramsFound; + //printf("..1 hasParamCommand=%d hasReturnCommand=%d paramsFound=%d\n", + // g_hasParamCommand,g_hasReturnCommand,g_paramsFound.count()); + + docParserPushContext(FALSE); + g_scope = def; + if (def->definitionType()==Definition::TypeMember && def->getOuterScope()) + { + if (def->getOuterScope()!=Doxygen::globalScope) + { + g_context=def->getOuterScope()->name(); + } + } + else if (def!=Doxygen::globalScope) + { + g_context=def->name(); + } + g_styleStack.clear(); + g_nodeStack.clear(); + g_paramsFound.clear(); + g_copyStack.append(def); + // make sure the descriptions end with a newline, so the parser will correctly + // handle them in all cases. + //printf("doc='%s'\n",doc.data()); + //printf("brief='%s'\n",brief.data()); + if (m_copyBrief) + { + brief+='\n'; + internalValidatingParseDoc(m_parent,children,brief); + + //printf("..2 hasParamCommand=%d hasReturnCommand=%d paramsFound=%d\n", + // g_hasParamCommand,g_hasReturnCommand,g_paramsFound.count()); + hasParamCommand = hasParamCommand || g_hasParamCommand; + hasReturnCommand = hasReturnCommand || g_hasReturnCommand; + QDictIterator<void> it(g_paramsFound); + void *item; + for (;(item=it.current());++it) + { + paramsFound.insert(it.currentKey(),it.current()); + } + } + if (m_copyDetails) + { + doc+='\n'; + internalValidatingParseDoc(m_parent,children,doc); + + //printf("..3 hasParamCommand=%d hasReturnCommand=%d paramsFound=%d\n", + // g_hasParamCommand,g_hasReturnCommand,g_paramsFound.count()); + hasParamCommand = hasParamCommand || g_hasParamCommand; + hasReturnCommand = hasReturnCommand || g_hasReturnCommand; + QDictIterator<void> it(g_paramsFound); + void *item; + for (;(item=it.current());++it) + { + paramsFound.insert(it.currentKey(),it.current()); + } + } + g_copyStack.remove(def); + ASSERT(g_styleStack.isEmpty()); + ASSERT(g_nodeStack.isEmpty()); + docParserPopContext(TRUE); + + g_hasParamCommand = hasParamCommand; + g_hasReturnCommand = hasReturnCommand; + g_paramsFound = paramsFound; + + //printf("..4 hasParamCommand=%d hasReturnCommand=%d paramsFound=%d\n", + // g_hasParamCommand,g_hasReturnCommand,g_paramsFound.count()); + } + else // oops, recursion + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: recursive call chain of \\copydoc commands detected at %d\n", + doctokenizerYYlineno); + } + } + else + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: target %s of \\copydoc command not found", + qPrint(m_link)); + } +} + +//--------------------------------------------------------------------------- + +DocXRefItem::DocXRefItem(DocNode *parent,int id,const char *key) : + m_id(id), m_key(key), m_relPath(g_relPath) +{ + m_parent = parent; +} + +bool DocXRefItem::parse() +{ + QCString listName; + RefList *refList = Doxygen::xrefLists->find(m_key); + if (refList && + ( + // either not a built-in list or the list is enabled + (m_key!="todo" || Config_getBool("GENERATE_TODOLIST")) && + (m_key!="test" || Config_getBool("GENERATE_TESTLIST")) && + (m_key!="bug" || Config_getBool("GENERATE_BUGLIST")) && + (m_key!="deprecated" || Config_getBool("GENERATE_DEPRECATEDLIST")) + ) + ) + { + RefItem *item = refList->getRefItem(m_id); + ASSERT(item!=0); + if (item) + { + if (g_memberDef && g_memberDef->name().at(0)=='@') + { + m_file = "@"; // can't cross reference anonymous enum + m_anchor = "@"; + } + else + { + m_file = convertNameToFile(refList->listName(),FALSE,TRUE); + m_anchor = item->listAnchor; + } + m_title = refList->sectionTitle(); + //printf("DocXRefItem: file=%s anchor=%s title=%s\n", + // m_file.data(),m_anchor.data(),m_title.data()); + + if (!item->text.isEmpty()) + { + docParserPushContext(); + internalValidatingParseDoc(this,m_children,item->text); + docParserPopContext(); + } + } + return TRUE; + } + return FALSE; +} + +//--------------------------------------------------------------------------- + +DocFormula::DocFormula(DocNode *parent,int id) : + m_relPath(g_relPath) +{ + m_parent = parent; + QCString formCmd; + formCmd.sprintf("\\form#%d",id); + Formula *formula=Doxygen::formulaNameDict[formCmd]; + if (formula) + { + m_id = formula->getId(); + m_name.sprintf("form_%d",m_id); + m_text = formula->getFormulaText(); + } +} + +//--------------------------------------------------------------------------- + +//int DocLanguage::parse() +//{ +// int retval; +// DBG(("DocLanguage::parse() start\n")); +// g_nodeStack.push(this); +// +// // parse one or more paragraphs +// bool isFirst=TRUE; +// DocPara *par=0; +// do +// { +// par = new DocPara(this); +// if (isFirst) { par->markFirst(); isFirst=FALSE; } +// m_children.append(par); +// retval=par->parse(); +// } +// while (retval==TK_NEWPARA); +// if (par) par->markLast(); +// +// DBG(("DocLanguage::parse() end\n")); +// DocNode *n = g_nodeStack.pop(); +// ASSERT(n==this); +// return retval; +//} + +//--------------------------------------------------------------------------- + +void DocSecRefItem::parse() +{ + DBG(("DocSecRefItem::parse() start\n")); + g_nodeStack.push(this); + + doctokenizerYYsetStateTitle(); + int tok; + while ((tok=doctokenizerYYlex())) + { + if (!defaultHandleToken(this,tok,m_children)) + { + switch (tok) + { + case TK_COMMAND: + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Illegal command %s as part of a \\refitem", + qPrint(g_token->name)); + break; + case TK_SYMBOL: + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unsupported symbol %s found", + qPrint(g_token->name)); + break; + default: + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected token %s", + tokToString(tok)); + break; + } + } + } + doctokenizerYYsetStatePara(); + handlePendingStyleCommands(this,m_children); + + SectionInfo *sec=0; + if (!m_target.isEmpty()) + { + sec=Doxygen::sectionDict[m_target]; + if (sec) + { + m_file = sec->fileName; + m_anchor = sec->label; + if (g_sectionDict && g_sectionDict->find(m_target)==0) + { + g_sectionDict->append(m_target,sec); + } + } + else + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: reference to unknown section %s", + qPrint(m_target)); + } + } + else + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: reference to empty target"); + } + + DBG(("DocSecRefItem::parse() end\n")); + DocNode *n = g_nodeStack.pop(); + ASSERT(n==this); +} + +//--------------------------------------------------------------------------- + +void DocSecRefList::parse() +{ + DBG(("DocSecRefList::parse() start\n")); + g_nodeStack.push(this); + + int tok=doctokenizerYYlex(); + // skip white space + while (tok==TK_WHITESPACE || tok==TK_NEWPARA) tok=doctokenizerYYlex(); + // handle items + while (tok) + { + if (tok==TK_COMMAND) + { + switch (Mappers::cmdMapper->map(g_token->name)) + { + case CMD_SECREFITEM: + { + int tok=doctokenizerYYlex(); + if (tok!=TK_WHITESPACE) + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected whitespace after \\refitem command"); + break; + } + tok=doctokenizerYYlex(); + if (tok!=TK_WORD && tok!=TK_LNKWORD) + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected token %s as the argument of \\refitem", + tokToString(tok)); + break; + } + + DocSecRefItem *item = new DocSecRefItem(this,g_token->name); + m_children.append(item); + item->parse(); + } + break; + case CMD_ENDSECREFLIST: + goto endsecreflist; + default: + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Illegal command %s as part of a \\secreflist", + qPrint(g_token->name)); + goto endsecreflist; + } + } + else if (tok==TK_WHITESPACE) + { + // ignore whitespace + } + else + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected token %s inside section reference list", + tokToString(tok)); + goto endsecreflist; + } + tok=doctokenizerYYlex(); + } + +endsecreflist: + DBG(("DocSecRefList::parse() end\n")); + DocNode *n = g_nodeStack.pop(); + ASSERT(n==this); +} + +//--------------------------------------------------------------------------- + +DocInternalRef::DocInternalRef(DocNode *parent,const QCString &ref) + : m_relPath(g_relPath) +{ + m_parent = parent; + int i=ref.find('#'); + if (i!=-1) + { + m_anchor = ref.right(ref.length()-i-1); + m_file = ref.left(i); + } + else + { + m_file = ref; + } +} + +void DocInternalRef::parse() +{ + g_nodeStack.push(this); + DBG(("DocInternalRef::parse() start\n")); + + int tok; + while ((tok=doctokenizerYYlex())) + { + if (!defaultHandleToken(this,tok,m_children)) + { + switch (tok) + { + case TK_COMMAND: + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Illegal command %s as part of a \\ref", + qPrint(g_token->name)); + break; + case TK_SYMBOL: + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unsupported symbol %s found", + qPrint(g_token->name)); + break; + default: + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected token %s", + tokToString(tok)); + break; + } + } + } + + handlePendingStyleCommands(this,m_children); + DBG(("DocInternalRef::parse() end\n")); + DocNode *n=g_nodeStack.pop(); + ASSERT(n==this); +} + +//--------------------------------------------------------------------------- + +DocRef::DocRef(DocNode *parent,const QCString &target,const QCString &context) : + m_refToSection(FALSE), m_refToAnchor(FALSE), m_isSubPage(FALSE) +{ + m_parent = parent; + Definition *compound = 0; + QCString anchor; + //printf("DocRef::DocRef(target=%s,context=%s)\n",target.data(),context.data()); + ASSERT(!target.isEmpty()); + m_relPath = g_relPath; + SectionInfo *sec = Doxygen::sectionDict[target]; + if (sec) // ref to section or anchor + { + PageDef *pd = 0; + if (sec->type==SectionInfo::Page) + { + pd = Doxygen::pageSDict->find(target); + } + m_text = sec->title; + if (m_text.isEmpty()) m_text = sec->label; + + m_ref = sec->ref; + m_file = stripKnownExtensions(sec->fileName); + m_refToAnchor = sec->type==SectionInfo::Anchor; + m_refToSection = sec->type!=SectionInfo::Anchor; + m_isSubPage = pd && pd->hasParentPage(); + if (sec->type!=SectionInfo::Page || m_isSubPage) m_anchor = sec->label; + //printf("m_text=%s,m_ref=%s,m_file=%s,m_refToAnchor=%d type=%d\n", + // m_text.data(),m_ref.data(),m_file.data(),m_refToAnchor,sec->type); + return; + } + else if (resolveLink(context,target,TRUE,&compound,anchor)) + { + bool isFile = compound ? + (compound->definitionType()==Definition::TypeFile || + compound->definitionType()==Definition::TypePage ? TRUE : FALSE) : + FALSE; + m_text = linkToText(compound?compound->getLanguage():SrcLangExt_Unknown,target,isFile); + m_anchor = anchor; + if (compound && compound->isLinkable()) // ref to compound + { + if (anchor.isEmpty() && /* compound link */ + compound->definitionType()==Definition::TypeGroup && /* is group */ + ((GroupDef *)compound)->groupTitle() /* with title */ + ) + { + m_text=((GroupDef *)compound)->groupTitle(); // use group's title as link + } + else if (compound->definitionType()==Definition::TypeMember && + ((MemberDef*)compound)->isObjCMethod()) + { + // Objective C Method + MemberDef *member = (MemberDef*)compound; + bool localLink = g_memberDef ? member->getClassDef()==g_memberDef->getClassDef() : FALSE; + m_text = member->objCMethodName(localLink,g_inSeeBlock); + } + + m_file = compound->getOutputFileBase(); + m_ref = compound->getReference(); + //printf("isFile=%d compound=%s (%d)\n",isFile,compound->name().data(), + // compound->definitionType()); + return; + } + else if (compound->definitionType()==Definition::TypeFile && + ((FileDef*)compound)->generateSourceFile() + ) // undocumented file that has source code we can link to + { + m_file = compound->getSourceFileBase(); + m_ref = compound->getReference(); + return; + } + } + m_text = target; + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unable to resolve reference to `%s' for \\ref command", + qPrint(target)); +} + +static void flattenParagraphs(DocNode *root,QList<DocNode> &children) +{ + QListIterator<DocNode> li(children); + QList<DocNode> newChildren; + DocNode *dn; + for (li.toFirst();(dn=li.current());++li) + { + if (dn->kind()==DocNode::Kind_Para) + { + DocPara *para = (DocPara*)dn; + QList<DocNode> ¶Children = para->children(); + paraChildren.setAutoDelete(FALSE); // unlink children from paragraph node + QListIterator<DocNode> li2(paraChildren); + DocNode *dn2; + for (li2.toFirst();(dn2=li2.current());++li2) + { + newChildren.append(dn2); // add them to new node + } + } + } + children.clear(); + QListIterator<DocNode> li3(newChildren); + for (li3.toFirst();(dn=li3.current());++li3) + { + children.append(dn); + dn->setParent(root); + } +} + +void DocRef::parse() +{ + g_nodeStack.push(this); + DBG(("DocRef::parse() start\n")); + + int tok; + while ((tok=doctokenizerYYlex())) + { + if (!defaultHandleToken(this,tok,m_children)) + { + switch (tok) + { + case TK_COMMAND: + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Illegal command %s as part of a \\ref", + qPrint(g_token->name)); + break; + case TK_SYMBOL: + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unsupported symbol %s found", + qPrint(g_token->name)); + break; + case TK_HTMLTAG: + break; + default: + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected token %s", + tokToString(tok)); + break; + } + } + } + + if (m_children.isEmpty() && !m_text.isEmpty()) + { + g_insideHtmlLink=TRUE; + docParserPushContext(); + internalValidatingParseDoc(this,m_children,m_text); + docParserPopContext(); + g_insideHtmlLink=FALSE; + flattenParagraphs(this,m_children); + } + + handlePendingStyleCommands(this,m_children); + + DocNode *n=g_nodeStack.pop(); + ASSERT(n==this); +} + +//--------------------------------------------------------------------------- + +DocCite::DocCite(DocNode *parent,const QCString &target,const QCString &) //context) +{ + static uint numBibFiles = Config_getList("CITE_BIB_FILES").count(); + m_parent = parent; + QCString anchor; + //printf("DocCite::DocCite(target=%s)\n",target.data()); + ASSERT(!target.isEmpty()); + m_relPath = g_relPath; + CiteInfo *cite = Doxygen::citeDict->find(target); + if (numBibFiles>0 && cite) // ref to citation + { + m_text = cite->text; + if (m_text.isEmpty()) m_text = cite->label; + m_ref = cite->ref; + m_anchor = CiteConsts::anchorPrefix+cite->label; + m_file = convertNameToFile(CiteConsts::fileName,FALSE,TRUE); + //printf("CITE ==> m_text=%s,m_ref=%s,m_file=%s,m_anchor=%s\n", + // m_text.data(),m_ref.data(),m_file.data(),m_anchor.data()); + return; + } + m_text = linkToText(SrcLangExt_Unknown,target,FALSE); + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unable to resolve reference to `%s' for \\cite command", + qPrint(target)); +} + +//--------------------------------------------------------------------------- + +DocLink::DocLink(DocNode *parent,const QCString &target) +{ + m_parent = parent; + Definition *compound; + //PageInfo *page; + QCString anchor; + m_refText = target; + m_relPath = g_relPath; + if (!m_refText.isEmpty() && m_refText.at(0)=='#') + { + m_refText = m_refText.right(m_refText.length()-1); + } + if (resolveLink(g_context,stripKnownExtensions(target),g_inSeeBlock, + &compound,anchor)) + { + m_anchor = anchor; + if (compound && compound->isLinkable()) + { + m_file = compound->getOutputFileBase(); + m_ref = compound->getReference(); + } + else if (compound->definitionType()==Definition::TypeFile && + ((FileDef*)compound)->generateSourceFile() + ) // undocumented file that has source code we can link to + { + m_file = compound->getSourceFileBase(); + m_ref = compound->getReference(); + } + return; + } + + // bogus link target + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unable to resolve link to `%s' for \\link command", + qPrint(target)); +} + + +QCString DocLink::parse(bool isJavaLink,bool isXmlLink) +{ + QCString result; + g_nodeStack.push(this); + DBG(("DocLink::parse() start\n")); + + int tok; + while ((tok=doctokenizerYYlex())) + { + if (!defaultHandleToken(this,tok,m_children,FALSE)) + { + switch (tok) + { + case TK_COMMAND: + switch (Mappers::cmdMapper->map(g_token->name)) + { + case CMD_ENDLINK: + if (isJavaLink) + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: {@link.. ended with @endlink command"); + } + goto endlink; + default: + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Illegal command %s as part of a \\link", + qPrint(g_token->name)); + break; + } + break; + case TK_SYMBOL: + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unsupported symbol %s found", + qPrint(g_token->name)); + break; + case TK_HTMLTAG: + if (g_token->name!="see" || !isXmlLink) + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected xml/html command %s found", + qPrint(g_token->name)); + } + goto endlink; + case TK_LNKWORD: + case TK_WORD: + if (isJavaLink) // special case to detect closing } + { + QCString w = g_token->name; + int p; + if (w=="}") + { + goto endlink; + } + else if ((p=w.find('}'))!=-1) + { + uint l=w.length(); + m_children.append(new DocWord(this,w.left(p))); + if ((uint)p<l-1) // something left after the } (for instance a .) + { + result=w.right(l-p-1); + } + goto endlink; + } + } + m_children.append(new DocWord(this,g_token->name)); + break; + default: + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected token %s", + tokToString(tok)); + break; + } + } + } + if (tok==0) + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected end of comment while inside" + " link command\n"); + } +endlink: + + if (m_children.isEmpty()) // no link text + { + m_children.append(new DocWord(this,m_refText)); + } + + handlePendingStyleCommands(this,m_children); + DBG(("DocLink::parse() end\n")); + DocNode *n=g_nodeStack.pop(); + ASSERT(n==this); + return result; +} + + +//--------------------------------------------------------------------------- + +DocDotFile::DocDotFile(DocNode *parent,const QCString &name,const QCString &context) : + m_name(name), m_relPath(g_relPath), m_context(context) +{ + m_parent = parent; +} + +void DocDotFile::parse() +{ + g_nodeStack.push(this); + DBG(("DocDotFile::parse() start\n")); + + doctokenizerYYsetStateTitle(); + int tok; + while ((tok=doctokenizerYYlex())) + { + if (!defaultHandleToken(this,tok,m_children)) + { + switch (tok) + { + case TK_COMMAND: + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Illegal command %s as part of a \\dotfile", + qPrint(g_token->name)); + break; + case TK_SYMBOL: + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unsupported symbol %s found", + qPrint(g_token->name)); + break; + default: + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected token %s", + tokToString(tok)); + break; + } + } + } + tok=doctokenizerYYlex(); + while (tok==TK_WORD) // there are values following the title + { + if (g_token->name=="width") + { + m_width=g_token->chars; + } + else if (g_token->name=="height") + { + m_height=g_token->chars; + } + else + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unknown option %s after image title", + qPrint(g_token->name)); + } + tok=doctokenizerYYlex(); + } + ASSERT(tok==0); + doctokenizerYYsetStatePara(); + handlePendingStyleCommands(this,m_children); + + bool ambig; + FileDef *fd = findFileDef(Doxygen::dotFileNameDict,m_name,ambig); + if (fd==0 && m_name.right(4)!=".dot") // try with .dot extension as well + { + fd = findFileDef(Doxygen::dotFileNameDict,m_name+".dot",ambig); + } + if (fd) + { + m_file = fd->absFilePath(); + } + else if (ambig) + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: included dot file name %s is ambiguous.\n" + "Possible candidates:\n%s",qPrint(m_name), + qPrint(showFileDefMatches(Doxygen::exampleNameDict,m_name)) + ); + } + else + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: included dot file %s is not found " + "in any of the paths specified via DOTFILE_DIRS!",qPrint(m_name)); + } + + DBG(("DocDotFile::parse() end\n")); + DocNode *n=g_nodeStack.pop(); + ASSERT(n==this); +} + +DocMscFile::DocMscFile(DocNode *parent,const QCString &name,const QCString &context) : + m_name(name), m_relPath(g_relPath), m_context(context) +{ + m_parent = parent; +} + +void DocMscFile::parse() +{ + g_nodeStack.push(this); + DBG(("DocMscFile::parse() start\n")); + + doctokenizerYYsetStateTitle(); + int tok; + while ((tok=doctokenizerYYlex())) + { + if (!defaultHandleToken(this,tok,m_children)) + { + switch (tok) + { + case TK_COMMAND: + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Illegal command %s as part of a \\mscfile", + qPrint(g_token->name)); + break; + case TK_SYMBOL: + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unsupported symbol %s found", + qPrint(g_token->name)); + break; + default: + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected token %s", + tokToString(tok)); + break; + } + } + } + tok=doctokenizerYYlex(); + while (tok==TK_WORD) // there are values following the title + { + if (g_token->name=="width") + { + m_width=g_token->chars; + } + else if (g_token->name=="height") + { + m_height=g_token->chars; + } + else + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unknown option %s after image title", + qPrint(g_token->name)); + } + tok=doctokenizerYYlex(); + } + ASSERT(tok==0); + doctokenizerYYsetStatePara(); + handlePendingStyleCommands(this,m_children); + + bool ambig; + FileDef *fd = findFileDef(Doxygen::mscFileNameDict,m_name,ambig); + if (fd==0 && m_name.right(4)!=".msc") // try with .msc extension as well + { + fd = findFileDef(Doxygen::mscFileNameDict,m_name+".msc",ambig); + } + if (fd) + { + m_file = fd->absFilePath(); + } + else if (ambig) + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: included msc file name %s is ambiguous.\n" + "Possible candidates:\n%s",qPrint(m_name), + qPrint(showFileDefMatches(Doxygen::exampleNameDict,m_name)) + ); + } + else + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: included msc file %s is not found " + "in any of the paths specified via MSCFILE_DIRS!",qPrint(m_name)); + } + + DBG(("DocMscFile::parse() end\n")); + DocNode *n=g_nodeStack.pop(); + ASSERT(n==this); +} + + + +//--------------------------------------------------------------------------- + +DocImage::DocImage(DocNode *parent,const HtmlAttribList &attribs,const QCString &name, + Type t,const QCString &url) : + m_attribs(attribs), m_name(name), + m_type(t), m_relPath(g_relPath), + m_url(url) +{ + m_parent = parent; +} + +void DocImage::parse() +{ + g_nodeStack.push(this); + DBG(("DocImage::parse() start\n")); + + // parse title + doctokenizerYYsetStateTitle(); + int tok; + while ((tok=doctokenizerYYlex())) + { + if (tok==TK_WORD && (g_token->name=="width=" || g_token->name=="height=")) + { + // special case: no title, but we do have a size indicator + doctokenizerYYsetStateTitleAttrValue(); + // strip = + g_token->name=g_token->name.left(g_token->name.length()-1); + break; + } + if (!defaultHandleToken(this,tok,m_children)) + { + switch (tok) + { + case TK_COMMAND: + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Illegal command %s as part of a \\image", + qPrint(g_token->name)); + break; + case TK_SYMBOL: + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unsupported symbol %s found", + qPrint(g_token->name)); + break; + default: + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected token %s", + tokToString(tok)); + break; + } + } + } + // parse size attributes + tok=doctokenizerYYlex(); + while (tok==TK_WORD) // there are values following the title + { + if (g_token->name=="width") + { + m_width=g_token->chars; + } + else if (g_token->name=="height") + { + m_height=g_token->chars; + } + else + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unknown option %s after image title", + qPrint(g_token->name)); + } + tok=doctokenizerYYlex(); + } + doctokenizerYYsetStatePara(); + + handlePendingStyleCommands(this,m_children); + DBG(("DocImage::parse() end\n")); + DocNode *n=g_nodeStack.pop(); + ASSERT(n==this); +} + + +//--------------------------------------------------------------------------- + +int DocHtmlHeader::parse() +{ + int retval=RetVal_OK; + g_nodeStack.push(this); + DBG(("DocHtmlHeader::parse() start\n")); + + int tok; + while ((tok=doctokenizerYYlex())) + { + if (!defaultHandleToken(this,tok,m_children)) + { + switch (tok) + { + case TK_COMMAND: + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Illegal command %s as part of a <h%d> tag", + qPrint(g_token->name),m_level); + break; + case TK_HTMLTAG: + { + int tagId=Mappers::htmlTagMapper->map(g_token->name); + if (tagId==HTML_H1 && g_token->endTag) // found </h1> tag + { + if (m_level!=1) + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: <h%d> ended with </h1>", + m_level); + } + goto endheader; + } + else if (tagId==HTML_H2 && g_token->endTag) // found </h2> tag + { + if (m_level!=2) + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: <h%d> ended with </h2>", + m_level); + } + goto endheader; + } + else if (tagId==HTML_H3 && g_token->endTag) // found </h3> tag + { + if (m_level!=3) + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: <h%d> ended with </h3>", + m_level); + } + goto endheader; + } + else if (tagId==HTML_H4 && g_token->endTag) // found </h4> tag + { + if (m_level!=4) + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: <h%d> ended with </h4>", + m_level); + } + goto endheader; + } + else if (tagId==HTML_H5 && g_token->endTag) // found </h5> tag + { + if (m_level!=5) + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: <h%d> ended with </h5>", + m_level); + } + goto endheader; + } + else if (tagId==HTML_H6 && g_token->endTag) // found </h6> tag + { + if (m_level!=6) + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: <h%d> ended with </h6>", + m_level); + } + goto endheader; + } + else if (tagId==HTML_A) + { + if (!g_token->endTag) + { + handleAHref(this,m_children,g_token->attribs); + } + } + else if (tagId==HTML_BR) + { + DocLineBreak *lb = new DocLineBreak(this); + m_children.append(lb); + } + else + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected html tag <%s%s> found within <h%d> context", + g_token->endTag?"/":"",qPrint(g_token->name),m_level); + } + + } + break; + case TK_SYMBOL: + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unsupported symbol %s found", + qPrint(g_token->name)); + break; + default: + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected token %s", + tokToString(tok)); + break; + } + } + } + if (tok==0) + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected end of comment while inside" + " <h%d> tag\n",m_level); + } +endheader: + handlePendingStyleCommands(this,m_children); + DBG(("DocHtmlHeader::parse() end\n")); + DocNode *n=g_nodeStack.pop(); + ASSERT(n==this); + return retval; +} + +//--------------------------------------------------------------------------- + +int DocHRef::parse() +{ + int retval=RetVal_OK; + g_nodeStack.push(this); + DBG(("DocHRef::parse() start\n")); + + int tok; + while ((tok=doctokenizerYYlex())) + { + if (!defaultHandleToken(this,tok,m_children)) + { + switch (tok) + { + case TK_COMMAND: + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Illegal command %s as part of a <a>..</a> block", + qPrint(g_token->name)); + break; + case TK_SYMBOL: + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unsupported symbol %s found", + qPrint(g_token->name)); + break; + case TK_HTMLTAG: + { + int tagId=Mappers::htmlTagMapper->map(g_token->name); + if (tagId==HTML_A && g_token->endTag) // found </a> tag + { + goto endhref; + } + else + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected html tag <%s%s> found within <a href=...> context", + g_token->endTag?"/":"",qPrint(g_token->name),doctokenizerYYlineno); + } + } + break; + default: + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected token %s", + tokToString(tok),doctokenizerYYlineno); + break; + } + } + } + if (tok==0) + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected end of comment while inside" + " <a href=...> tag",doctokenizerYYlineno); + } +endhref: + handlePendingStyleCommands(this,m_children); + DBG(("DocHRef::parse() end\n")); + DocNode *n=g_nodeStack.pop(); + ASSERT(n==this); + return retval; +} + +//--------------------------------------------------------------------------- + +int DocInternal::parse(int level) +{ + int retval=RetVal_OK; + g_nodeStack.push(this); + DBG(("DocInternal::parse() start\n")); + + // first parse any number of paragraphs + bool isFirst=TRUE; + DocPara *lastPar=0; + do + { + DocPara *par = new DocPara(this); + if (isFirst) { par->markFirst(); isFirst=FALSE; } + retval=par->parse(); + if (!par->isEmpty()) + { + m_children.append(par); + lastPar=par; + } + else + { + delete par; + } + if (retval==TK_LISTITEM) + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Invalid list item found",doctokenizerYYlineno); + } + } while (retval!=0 && + retval!=RetVal_Section && + retval!=RetVal_Subsection && + retval!=RetVal_Subsubsection && + retval!=RetVal_Paragraph + ); + if (lastPar) lastPar->markLast(); + + // then parse any number of level-n sections + while ((level==1 && retval==RetVal_Section) || + (level==2 && retval==RetVal_Subsection) || + (level==3 && retval==RetVal_Subsubsection) || + (level==4 && retval==RetVal_Paragraph) + ) + { + DocSection *s=new DocSection(this, + QMIN(level+Doxygen::subpageNestingLevel,5),g_token->sectionId); + m_children.append(s); + retval = s->parse(); + } + + if (retval==RetVal_Internal) + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: \\internal command found inside internal section"); + } + + DBG(("DocInternal::parse() end\n")); + DocNode *n=g_nodeStack.pop(); + ASSERT(n==this); + return retval; +} + +//--------------------------------------------------------------------------- + +int DocIndexEntry::parse() +{ + int retval=RetVal_OK; + g_nodeStack.push(this); + DBG(("DocIndexEntry::parse() start\n")); + int tok=doctokenizerYYlex(); + if (tok!=TK_WHITESPACE) + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected whitespace after \\addindex command"); + goto endindexentry; + } + doctokenizerYYsetStateTitle(); + m_entry=""; + while ((tok=doctokenizerYYlex())) + { + switch (tok) + { + case TK_WHITESPACE: + m_entry+=" "; + break; + case TK_WORD: + case TK_LNKWORD: + m_entry+=g_token->name; + break; + case TK_SYMBOL: + { + char letter='\0'; + DocSymbol::SymType s = DocSymbol::decodeSymbol(g_token->name,&letter); + switch (s) + { + case DocSymbol::BSlash: m_entry+='\\'; break; + case DocSymbol::At: m_entry+='@'; break; + case DocSymbol::Less: m_entry+='<'; break; + case DocSymbol::Greater: m_entry+='>'; break; + case DocSymbol::Amp: m_entry+='&'; break; + case DocSymbol::Dollar: m_entry+='$'; break; + case DocSymbol::Hash: m_entry+='#'; break; + case DocSymbol::Percent: m_entry+='%'; break; + case DocSymbol::Apos: m_entry+='\''; break; + case DocSymbol::Quot: m_entry+='"'; break; + case DocSymbol::Lsquo: m_entry+='`'; break; + case DocSymbol::Rsquo: m_entry+='\''; break; + case DocSymbol::Ldquo: m_entry+="``"; break; + case DocSymbol::Rdquo: m_entry+="''"; break; + case DocSymbol::Ndash: m_entry+="--"; break; + case DocSymbol::Mdash: m_entry+="---"; break; + default: + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected symbol found as argument of \\addindex"); + break; + } + } + break; + case TK_COMMAND: + switch (Mappers::cmdMapper->map(g_token->name)) + { + case CMD_BSLASH: m_entry+='\\'; break; + case CMD_AT: m_entry+='@'; break; + case CMD_LESS: m_entry+='<'; break; + case CMD_GREATER: m_entry+='>'; break; + case CMD_AMP: m_entry+='&'; break; + case CMD_DOLLAR: m_entry+='$'; break; + case CMD_HASH: m_entry+='#'; break; + case CMD_DCOLON: m_entry+="::"; break; + case CMD_PERCENT: m_entry+='%'; break; + case CMD_QUOTE: m_entry+='"'; break; + default: + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected command %s found as argument of \\addindex", + qPrint(g_token->name)); + break; + } + break; + default: + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected token %s", + tokToString(tok)); + break; + } + } + if (tok!=0) retval=tok; + doctokenizerYYsetStatePara(); + m_entry = m_entry.stripWhiteSpace(); +endindexentry: + DBG(("DocIndexEntry::parse() end retval=%x\n",retval)); + DocNode *n=g_nodeStack.pop(); + ASSERT(n==this); + return retval; +} + +//--------------------------------------------------------------------------- + +int DocHtmlCaption::parse() +{ + int retval=0; + g_nodeStack.push(this); + DBG(("DocHtmlCaption::parse() start\n")); + int tok; + while ((tok=doctokenizerYYlex())) + { + if (!defaultHandleToken(this,tok,m_children)) + { + switch (tok) + { + case TK_COMMAND: + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Illegal command %s as part of a <caption> tag", + qPrint(g_token->name)); + break; + case TK_SYMBOL: + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unsupported symbol %s found", + qPrint(g_token->name)); + break; + case TK_HTMLTAG: + { + int tagId=Mappers::htmlTagMapper->map(g_token->name); + if (tagId==HTML_CAPTION && g_token->endTag) // found </caption> tag + { + retval = RetVal_OK; + goto endcaption; + } + else + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected html tag <%s%s> found within <caption> context", + g_token->endTag?"/":"",qPrint(g_token->name)); + } + } + break; + default: + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected token %s", + tokToString(tok)); + break; + } + } + } + if (tok==0) + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected end of comment while inside" + " <caption> tag",doctokenizerYYlineno); + } +endcaption: + handlePendingStyleCommands(this,m_children); + DBG(("DocHtmlCaption::parse() end\n")); + DocNode *n=g_nodeStack.pop(); + ASSERT(n==this); + return retval; +} + +//--------------------------------------------------------------------------- + +int DocHtmlCell::parse() +{ + int retval=RetVal_OK; + g_nodeStack.push(this); + DBG(("DocHtmlCell::parse() start\n")); + + // parse one or more paragraphs + bool isFirst=TRUE; + DocPara *par=0; + do + { + par = new DocPara(this); + if (isFirst) { par->markFirst(); isFirst=FALSE; } + m_children.append(par); + retval=par->parse(); + if (retval==TK_HTMLTAG) + { + int tagId=Mappers::htmlTagMapper->map(g_token->name); + if (tagId==HTML_TD && g_token->endTag) // found </dt> tag + { + retval=TK_NEWPARA; // ignore the tag + } + else if (tagId==HTML_TH && g_token->endTag) // found </th> tag + { + retval=TK_NEWPARA; // ignore the tag + } + } + } + while (retval==TK_NEWPARA); + if (par) par->markLast(); + + DBG(("DocHtmlCell::parse() end\n")); + DocNode *n=g_nodeStack.pop(); + ASSERT(n==this); + return retval; +} + +int DocHtmlCell::parseXml() +{ + int retval=RetVal_OK; + g_nodeStack.push(this); + DBG(("DocHtmlCell::parseXml() start\n")); + + // parse one or more paragraphs + bool isFirst=TRUE; + DocPara *par=0; + do + { + par = new DocPara(this); + if (isFirst) { par->markFirst(); isFirst=FALSE; } + m_children.append(par); + retval=par->parse(); + if (retval==TK_HTMLTAG) + { + int tagId=Mappers::htmlTagMapper->map(g_token->name); + if (tagId==XML_ITEM && g_token->endTag) // found </item> tag + { + retval=TK_NEWPARA; // ignore the tag + } + else if (tagId==XML_DESCRIPTION && g_token->endTag) // found </description> tag + { + retval=TK_NEWPARA; // ignore the tag + } + } + } + while (retval==TK_NEWPARA); + if (par) par->markLast(); + + DBG(("DocHtmlCell::parseXml() end\n")); + DocNode *n=g_nodeStack.pop(); + ASSERT(n==this); + return retval; +} + +int DocHtmlCell::rowSpan() const +{ + int retval = 0; + HtmlAttribList attrs = attribs(); + uint i; + for (i=0; i<attrs.count(); ++i) + { + if (attrs.at(i)->name.lower()=="rowspan") + { + retval = attrs.at(i)->value.toInt(); + break; + } + } + return retval; +} + +int DocHtmlCell::colSpan() const +{ + int retval = 1; + HtmlAttribList attrs = attribs(); + uint i; + for (i=0; i<attrs.count(); ++i) + { + if (attrs.at(i)->name.lower()=="colspan") + { + retval = QMAX(1,attrs.at(i)->value.toInt()); + break; + } + } + return retval; +} + +DocHtmlCell::Alignment DocHtmlCell::alignment() const +{ + HtmlAttribList attrs = attribs(); + uint i; + for (i=0; i<attrs.count(); ++i) + { + if (attrs.at(i)->name.lower()=="align") + { + if (attrs.at(i)->value.lower()=="center") + return Center; + else if (attrs.at(i)->value.lower()=="right") + return Right; + else return Left; + } + } + return Left; +} + + +//--------------------------------------------------------------------------- + +int DocHtmlRow::parse() +{ + int retval=RetVal_OK; + g_nodeStack.push(this); + DBG(("DocHtmlRow::parse() start\n")); + + bool isHeading=FALSE; + bool isFirst=TRUE; + DocHtmlCell *cell=0; + + // get next token + int tok=doctokenizerYYlex(); + // skip whitespace + while (tok==TK_WHITESPACE || tok==TK_NEWPARA) tok=doctokenizerYYlex(); + // should find a html tag now + if (tok==TK_HTMLTAG) + { + int tagId=Mappers::htmlTagMapper->map(g_token->name); + if (tagId==HTML_TD && !g_token->endTag) // found <td> tag + { + } + else if (tagId==HTML_TH && !g_token->endTag) // found <th> tag + { + isHeading=TRUE; + } + else // found some other tag + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected <td> or <th> tag but " + "found <%s> instead!",qPrint(g_token->name)); + doctokenizerYYpushBackHtmlTag(g_token->name); + goto endrow; + } + } + else if (tok==0) // premature end of comment + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected end of comment while looking" + " for a html description title"); + goto endrow; + } + else // token other than html token + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected <td> or <th> tag but found %s token instead!", + tokToString(tok)); + goto endrow; + } + + // parse one or more cells + do + { + cell=new DocHtmlCell(this,g_token->attribs,isHeading); + cell->markFirst(isFirst); + isFirst=FALSE; + m_children.append(cell); + retval=cell->parse(); + isHeading = retval==RetVal_TableHCell; + } + while (retval==RetVal_TableCell || retval==RetVal_TableHCell); + if (cell) cell->markLast(TRUE); + +endrow: + DBG(("DocHtmlRow::parse() end\n")); + DocNode *n=g_nodeStack.pop(); + ASSERT(n==this); + return retval; +} + +int DocHtmlRow::parseXml(bool isHeading) +{ + int retval=RetVal_OK; + g_nodeStack.push(this); + DBG(("DocHtmlRow::parseXml() start\n")); + + bool isFirst=TRUE; + DocHtmlCell *cell=0; + + // get next token + int tok=doctokenizerYYlex(); + // skip whitespace + while (tok==TK_WHITESPACE || tok==TK_NEWPARA) tok=doctokenizerYYlex(); + // should find a html tag now + if (tok==TK_HTMLTAG) + { + int tagId=Mappers::htmlTagMapper->map(g_token->name); + if (tagId==XML_TERM && !g_token->endTag) // found <term> tag + { + } + else if (tagId==XML_DESCRIPTION && !g_token->endTag) // found <description> tag + { + } + else // found some other tag + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected <term> or <description> tag but " + "found <%s> instead!",qPrint(g_token->name)); + doctokenizerYYpushBackHtmlTag(g_token->name); + goto endrow; + } + } + else if (tok==0) // premature end of comment + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected end of comment while looking" + " for a html description title"); + goto endrow; + } + else // token other than html token + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected <td> or <th> tag but found %s token instead!", + tokToString(tok)); + goto endrow; + } + + do + { + cell=new DocHtmlCell(this,g_token->attribs,isHeading); + cell->markFirst(isFirst); + isFirst=FALSE; + m_children.append(cell); + retval=cell->parseXml(); + } + while (retval==RetVal_TableCell || retval==RetVal_TableHCell); + if (cell) cell->markLast(TRUE); + +endrow: + DBG(("DocHtmlRow::parseXml() end\n")); + DocNode *n=g_nodeStack.pop(); + ASSERT(n==this); + return retval; +} + +//--------------------------------------------------------------------------- + +int DocHtmlTable::parse() +{ + int retval=RetVal_OK; + g_nodeStack.push(this); + DBG(("DocHtmlTable::parse() start\n")); + +getrow: + // get next token + int tok=doctokenizerYYlex(); + // skip whitespace + while (tok==TK_WHITESPACE || tok==TK_NEWPARA) tok=doctokenizerYYlex(); + // should find a html tag now + if (tok==TK_HTMLTAG) + { + int tagId=Mappers::htmlTagMapper->map(g_token->name); + if (tagId==HTML_TR && !g_token->endTag) // found <tr> tag + { + // no caption, just rows + retval=RetVal_TableRow; + } + else if (tagId==HTML_CAPTION && !g_token->endTag) // found <caption> tag + { + if (m_caption) + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: table already has a caption, found another one"); + } + else + { + m_caption = new DocHtmlCaption(this,g_token->attribs); + retval=m_caption->parse(); + + if (retval==RetVal_OK) // caption was parsed ok + { + goto getrow; + } + } + } + else // found wrong token + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected <tr> or <caption> tag but " + "found <%s%s> instead!", g_token->endTag ? "/" : "", qPrint(g_token->name)); + } + } + else if (tok==0) // premature end of comment + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected end of comment while looking" + " for a <tr> or <caption> tag"); + } + else // token other than html token + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected <tr> tag but found %s token instead!", + tokToString(tok)); + } + + // parse one or more rows + while (retval==RetVal_TableRow) + { + DocHtmlRow *tr=new DocHtmlRow(this,g_token->attribs); + m_children.append(tr); + retval=tr->parse(); + } + + computeTableGrid(); + + DBG(("DocHtmlTable::parse() end\n")); + DocNode *n=g_nodeStack.pop(); + ASSERT(n==this); + return retval==RetVal_EndTable ? RetVal_OK : retval; +} + +int DocHtmlTable::parseXml() +{ + int retval=RetVal_OK; + g_nodeStack.push(this); + DBG(("DocHtmlTable::parseXml() start\n")); + + // get next token + int tok=doctokenizerYYlex(); + // skip whitespace + while (tok==TK_WHITESPACE || tok==TK_NEWPARA) tok=doctokenizerYYlex(); + // should find a html tag now + int tagId=0; + bool isHeader=FALSE; + if (tok==TK_HTMLTAG) + { + tagId=Mappers::htmlTagMapper->map(g_token->name); + if (tagId==XML_ITEM && !g_token->endTag) // found <item> tag + { + retval=RetVal_TableRow; + } + if (tagId==XML_LISTHEADER && !g_token->endTag) // found <listheader> tag + { + retval=RetVal_TableRow; + isHeader=TRUE; + } + } + + // parse one or more rows + while (retval==RetVal_TableRow) + { + DocHtmlRow *tr=new DocHtmlRow(this,g_token->attribs); + m_children.append(tr); + retval=tr->parseXml(isHeader); + isHeader=FALSE; + } + + computeTableGrid(); + + DBG(("DocHtmlTable::parseXml() end\n")); + DocNode *n=g_nodeStack.pop(); + ASSERT(n==this); + return retval==RetVal_EndTable ? RetVal_OK : retval; +} + +struct ActiveRowSpan +{ + ActiveRowSpan(int rows,int col) : rowsLeft(rows), column(col) {} + int rowsLeft; + int column; +}; + +typedef QList<ActiveRowSpan> RowSpanList; + +/** determines the location of all cells in a grid, resolving row and + column spans. For each the total number of visible cells is computed, + and the total number of visible columns over all rows is stored. + */ +void DocHtmlTable::computeTableGrid() +{ + //printf("computeTableGrid()\n"); + RowSpanList rowSpans; + rowSpans.setAutoDelete(TRUE); + int maxCols=0; + int rowIdx=1; + QListIterator<DocNode> li(children()); + DocNode *rowNode; + for (li.toFirst();(rowNode=li.current());++li) + { + int colIdx=1; + int cells=0; + if (rowNode->kind()==DocNode::Kind_HtmlRow) + { + uint i; + DocHtmlRow *row = (DocHtmlRow*)rowNode; + QListIterator<DocNode> rli(row->children()); + DocNode *cellNode; + for (rli.toFirst();(cellNode=rli.current());++rli) + { + if (cellNode->kind()==DocNode::Kind_HtmlCell) + { + DocHtmlCell *cell = (DocHtmlCell*)cellNode; + int rs = cell->rowSpan(); + int cs = cell->colSpan(); + + for (i=0;i<rowSpans.count();i++) + { + if (rowSpans.at(i)->rowsLeft>0 && + rowSpans.at(i)->column==colIdx) + { + colIdx=rowSpans.at(i)->column+1; + cells++; + } + } + if (rs>0) rowSpans.append(new ActiveRowSpan(rs,colIdx)); + //printf("found cell at (%d,%d)\n",rowIdx,colIdx); + cell->setRowIndex(rowIdx); + cell->setColumnIndex(colIdx); + colIdx+=cs; + cells++; + } + } + for (i=0;i<rowSpans.count();i++) + { + if (rowSpans.at(i)->rowsLeft>0) rowSpans.at(i)->rowsLeft--; + } + row->setVisibleCells(cells); + row->setRowIndex(rowIdx); + rowIdx++; + } + if (colIdx-1>maxCols) maxCols=colIdx-1; + } + m_numCols = maxCols; +} + +void DocHtmlTable::accept(DocVisitor *v) +{ + v->visitPre(this); + // for HTML output we put the caption first + if (m_caption && v->id()==DocVisitor_Html) m_caption->accept(v); + QListIterator<DocNode> cli(m_children); + DocNode *n; + for (cli.toFirst();(n=cli.current());++cli) n->accept(v); + // for other output formats we put the caption last + if (m_caption && v->id()!=DocVisitor_Html) m_caption->accept(v); + v->visitPost(this); +} + +//--------------------------------------------------------------------------- + +int DocHtmlDescTitle::parse() +{ + int retval=0; + g_nodeStack.push(this); + DBG(("DocHtmlDescTitle::parse() start\n")); + + int tok; + while ((tok=doctokenizerYYlex())) + { + if (!defaultHandleToken(this,tok,m_children)) + { + switch (tok) + { + case TK_COMMAND: + { + QCString cmdName=g_token->name; + bool isJavaLink=FALSE; + switch (Mappers::cmdMapper->map(cmdName)) + { + case CMD_REF: + { + int tok=doctokenizerYYlex(); + if (tok!=TK_WHITESPACE) + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected whitespace after %s command", + qPrint(g_token->name)); + } + else + { + doctokenizerYYsetStateRef(); + tok=doctokenizerYYlex(); // get the reference id + if (tok!=TK_WORD) + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected token %s as the argument of %s", + tokToString(tok),qPrint(cmdName)); + } + else + { + DocRef *ref = new DocRef(this,g_token->name,g_context); + m_children.append(ref); + ref->parse(); + } + doctokenizerYYsetStatePara(); + } + } + break; + case CMD_JAVALINK: + isJavaLink=TRUE; + // fall through + case CMD_LINK: + { + int tok=doctokenizerYYlex(); + if (tok!=TK_WHITESPACE) + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected whitespace after %s command", + qPrint(cmdName)); + } + else + { + doctokenizerYYsetStateLink(); + tok=doctokenizerYYlex(); + if (tok!=TK_WORD) + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected token %s as the argument of %s", + tokToString(tok),qPrint(cmdName)); + } + else + { + doctokenizerYYsetStatePara(); + DocLink *lnk = new DocLink(this,g_token->name); + m_children.append(lnk); + QCString leftOver = lnk->parse(isJavaLink); + if (!leftOver.isEmpty()) + { + m_children.append(new DocWord(this,leftOver)); + } + } + } + } + + break; + default: + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Illegal command %s as part of a <dt> tag", + qPrint(g_token->name)); + } + } + break; + case TK_SYMBOL: + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unsupported symbol %s found", + qPrint(g_token->name)); + break; + case TK_HTMLTAG: + { + int tagId=Mappers::htmlTagMapper->map(g_token->name); + if (tagId==HTML_DD && !g_token->endTag) // found <dd> tag + { + retval = RetVal_DescData; + goto endtitle; + } + else if (tagId==HTML_DT && g_token->endTag) + { + // ignore </dt> tag. + } + else if (tagId==HTML_DT) + { + // missing <dt> tag. + retval = RetVal_DescTitle; + goto endtitle; + } + else if (tagId==HTML_DL && g_token->endTag) + { + retval=RetVal_EndDesc; + goto endtitle; + } + else if (tagId==HTML_A) + { + if (!g_token->endTag) + { + handleAHref(this,m_children,g_token->attribs); + } + } + else + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected html tag <%s%s> found within <dt> context", + g_token->endTag?"/":"",qPrint(g_token->name)); + } + } + break; + default: + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected token %s", + tokToString(tok)); + break; + } + } + } + if (tok==0) + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected end of comment while inside" + " <dt> tag"); + } +endtitle: + handlePendingStyleCommands(this,m_children); + DBG(("DocHtmlDescTitle::parse() end\n")); + DocNode *n=g_nodeStack.pop(); + ASSERT(n==this); + return retval; +} + +//--------------------------------------------------------------------------- + +int DocHtmlDescData::parse() +{ + m_attribs = g_token->attribs; + int retval=0; + g_nodeStack.push(this); + DBG(("DocHtmlDescData::parse() start\n")); + + bool isFirst=TRUE; + DocPara *par=0; + do + { + par = new DocPara(this); + if (isFirst) { par->markFirst(); isFirst=FALSE; } + m_children.append(par); + retval=par->parse(); + } + while (retval==TK_NEWPARA); + if (par) par->markLast(); + + DBG(("DocHtmlDescData::parse() end\n")); + DocNode *n=g_nodeStack.pop(); + ASSERT(n==this); + return retval; +} + +//--------------------------------------------------------------------------- + +int DocHtmlDescList::parse() +{ + int retval=RetVal_OK; + g_nodeStack.push(this); + DBG(("DocHtmlDescList::parse() start\n")); + + // get next token + int tok=doctokenizerYYlex(); + // skip whitespace + while (tok==TK_WHITESPACE || tok==TK_NEWPARA) tok=doctokenizerYYlex(); + // should find a html tag now + if (tok==TK_HTMLTAG) + { + int tagId=Mappers::htmlTagMapper->map(g_token->name); + if (tagId==HTML_DT && !g_token->endTag) // found <dt> tag + { + // continue + } + else // found some other tag + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected <dt> tag but " + "found <%s> instead!",qPrint(g_token->name)); + doctokenizerYYpushBackHtmlTag(g_token->name); + goto enddesclist; + } + } + else if (tok==0) // premature end of comment + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected end of comment while looking" + " for a html description title"); + goto enddesclist; + } + else // token other than html token + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected <dt> tag but found %s token instead!", + tokToString(tok)); + goto enddesclist; + } + + do + { + DocHtmlDescTitle *dt=new DocHtmlDescTitle(this,g_token->attribs); + m_children.append(dt); + DocHtmlDescData *dd=new DocHtmlDescData(this); + m_children.append(dd); + retval=dt->parse(); + if (retval==RetVal_DescData) + { + retval=dd->parse(); + } + else if (retval!=RetVal_DescTitle) + { + // error + break; + } + } while (retval==RetVal_DescTitle); + + if (retval==0) + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected end of comment while inside <dl> block"); + } + +enddesclist: + + DocNode *n=g_nodeStack.pop(); + ASSERT(n==this); + DBG(("DocHtmlDescList::parse() end\n")); + return retval==RetVal_EndDesc ? RetVal_OK : retval; +} + +//--------------------------------------------------------------------------- + +int DocHtmlListItem::parse() +{ + DBG(("DocHtmlListItem::parse() start\n")); + int retval=0; + g_nodeStack.push(this); + + // parse one or more paragraphs + bool isFirst=TRUE; + DocPara *par=0; + do + { + par = new DocPara(this); + if (isFirst) { par->markFirst(); isFirst=FALSE; } + m_children.append(par); + retval=par->parse(); + } + while (retval==TK_NEWPARA); + if (par) par->markLast(); + + DocNode *n=g_nodeStack.pop(); + ASSERT(n==this); + DBG(("DocHtmlListItem::parse() end retval=%x\n",retval)); + return retval; +} + +int DocHtmlListItem::parseXml() +{ + DBG(("DocHtmlListItem::parseXml() start\n")); + int retval=0; + g_nodeStack.push(this); + + // parse one or more paragraphs + bool isFirst=TRUE; + DocPara *par=0; + do + { + par = new DocPara(this); + if (isFirst) { par->markFirst(); isFirst=FALSE; } + m_children.append(par); + retval=par->parse(); + if (retval==0) break; + + //printf("new item: retval=%x g_token->name=%s g_token->endTag=%d\n", + // retval,qPrint(g_token->name),g_token->endTag); + if (retval==RetVal_ListItem) + { + break; + } + } + while (retval!=RetVal_CloseXml); + + if (par) par->markLast(); + + DocNode *n=g_nodeStack.pop(); + ASSERT(n==this); + DBG(("DocHtmlListItem::parseXml() end retval=%x\n",retval)); + return retval; +} + +//--------------------------------------------------------------------------- + +int DocHtmlList::parse() +{ + DBG(("DocHtmlList::parse() start\n")); + int retval=RetVal_OK; + int num=1; + g_nodeStack.push(this); + + // get next token + int tok=doctokenizerYYlex(); + // skip whitespace and paragraph breaks + while (tok==TK_WHITESPACE || tok==TK_NEWPARA) tok=doctokenizerYYlex(); + // should find a html tag now + if (tok==TK_HTMLTAG) + { + int tagId=Mappers::htmlTagMapper->map(g_token->name); + if (tagId==HTML_LI && !g_token->endTag) // found <li> tag + { + // ok, we can go on. + } + else if (((m_type==Unordered && tagId==HTML_UL) || + (m_type==Ordered && tagId==HTML_OL) + ) && g_token->endTag + ) // found empty list + { + // add dummy item to obtain valid HTML + m_children.append(new DocHtmlListItem(this,HtmlAttribList(),1)); + warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: empty list!"); + retval = RetVal_EndList; + goto endlist; + } + else // found some other tag + { + // add dummy item to obtain valid HTML + m_children.append(new DocHtmlListItem(this,HtmlAttribList(),1)); + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected <li> tag but " + "found <%s%s> instead!",g_token->endTag?"/":"",qPrint(g_token->name)); + doctokenizerYYpushBackHtmlTag(g_token->name); + goto endlist; + } + } + else if (tok==0) // premature end of comment + { + // add dummy item to obtain valid HTML + m_children.append(new DocHtmlListItem(this,HtmlAttribList(),1)); + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected end of comment while looking" + " for a html list item"); + goto endlist; + } + else // token other than html token + { + // add dummy item to obtain valid HTML + m_children.append(new DocHtmlListItem(this,HtmlAttribList(),1)); + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected <li> tag but found %s token instead!", + tokToString(tok)); + goto endlist; + } + + do + { + DocHtmlListItem *li=new DocHtmlListItem(this,g_token->attribs,num++); + m_children.append(li); + retval=li->parse(); + } while (retval==RetVal_ListItem); + + if (retval==0) + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected end of comment while inside <%cl> block", + m_type==Unordered ? 'u' : 'o'); + } + +endlist: + DBG(("DocHtmlList::parse() end retval=%x\n",retval)); + DocNode *n=g_nodeStack.pop(); + ASSERT(n==this); + return retval==RetVal_EndList ? RetVal_OK : retval; +} + +int DocHtmlList::parseXml() +{ + DBG(("DocHtmlList::parseXml() start\n")); + int retval=RetVal_OK; + int num=1; + g_nodeStack.push(this); + + // get next token + int tok=doctokenizerYYlex(); + // skip whitespace and paragraph breaks + while (tok==TK_WHITESPACE || tok==TK_NEWPARA) tok=doctokenizerYYlex(); + // should find a html tag now + if (tok==TK_HTMLTAG) + { + int tagId=Mappers::htmlTagMapper->map(g_token->name); + //printf("g_token->name=%s g_token->endTag=%d\n",qPrint(g_token->name),g_token->endTag); + if (tagId==XML_ITEM && !g_token->endTag) // found <item> tag + { + // ok, we can go on. + } + else // found some other tag + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected <item> tag but " + "found <%s> instead!",qPrint(g_token->name)); + doctokenizerYYpushBackHtmlTag(g_token->name); + goto endlist; + } + } + else if (tok==0) // premature end of comment + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected end of comment while looking" + " for a html list item"); + goto endlist; + } + else // token other than html token + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected <item> tag but found %s token instead!", + tokToString(tok)); + goto endlist; + } + + do + { + DocHtmlListItem *li=new DocHtmlListItem(this,g_token->attribs,num++); + m_children.append(li); + retval=li->parseXml(); + if (retval==0) break; + //printf("retval=%x g_token->name=%s\n",retval,qPrint(g_token->name)); + } while (retval==RetVal_ListItem); + + if (retval==0) + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected end of comment while inside <list type=\"%s\"> block", + m_type==Unordered ? "bullet" : "number"); + } + +endlist: + DBG(("DocHtmlList::parseXml() end retval=%x\n",retval)); + DocNode *n=g_nodeStack.pop(); + ASSERT(n==this); + return retval==RetVal_EndList || + (retval==RetVal_CloseXml || g_token->name=="list") ? + RetVal_OK : retval; +} + +//-------------------------------------------------------------------------- + +int DocHtmlBlockQuote::parse() +{ + DBG(("DocHtmlBlockQuote::parse() start\n")); + int retval=0; + g_nodeStack.push(this); + + // parse one or more paragraphs + bool isFirst=TRUE; + DocPara *par=0; + do + { + par = new DocPara(this); + if (isFirst) { par->markFirst(); isFirst=FALSE; } + m_children.append(par); + retval=par->parse(); + } + while (retval==TK_NEWPARA); + if (par) par->markLast(); + + DocNode *n=g_nodeStack.pop(); + ASSERT(n==this); + DBG(("DocHtmlBlockQuote::parse() end retval=%x\n",retval)); + return (retval==RetVal_EndBlockQuote) ? RetVal_OK : retval; +} + +//--------------------------------------------------------------------------- + +int DocSimpleListItem::parse() +{ + g_nodeStack.push(this); + int rv=m_paragraph->parse(); + m_paragraph->markFirst(); + m_paragraph->markLast(); + DocNode *n=g_nodeStack.pop(); + ASSERT(n==this); + return rv; +} + +//-------------------------------------------------------------------------- + +int DocSimpleList::parse() +{ + g_nodeStack.push(this); + int rv; + do + { + DocSimpleListItem *li=new DocSimpleListItem(this); + m_children.append(li); + rv=li->parse(); + } while (rv==RetVal_ListItem); + DocNode *n=g_nodeStack.pop(); + ASSERT(n==this); + return (rv!=TK_NEWPARA) ? rv : RetVal_OK; +} + +//-------------------------------------------------------------------------- + +DocAutoListItem::DocAutoListItem(DocNode *parent,int indent,int num) + : m_indent(indent), m_itemNum(num) +{ + m_parent = parent; +} + +int DocAutoListItem::parse() +{ + int retval = RetVal_OK; + g_nodeStack.push(this); + + //retval=m_paragraph->parse(); + //m_paragraph->markFirst(); + //m_paragraph->markLast(); + + // first parse any number of paragraphs + bool isFirst=TRUE; + DocPara *lastPar=0; + do + { + DocPara *par = new DocPara(this); + if (isFirst) { par->markFirst(); isFirst=FALSE; } + retval=par->parse(); + if (!par->isEmpty()) + { + m_children.append(par); + if (lastPar) lastPar->markLast(FALSE); + lastPar=par; + } + else + { + delete par; + } + // next paragraph should be more indented than the - marker to belong + // to this item + } while (retval==TK_NEWPARA && g_token->indent>m_indent); + if (lastPar) lastPar->markLast(); + + DocNode *n=g_nodeStack.pop(); + ASSERT(n==this); + //printf("DocAutoListItem: retval=%d indent=%d\n",retval,g_token->indent); + return retval; +} + +//-------------------------------------------------------------------------- + +DocAutoList::DocAutoList(DocNode *parent,int indent,bool isEnumList, + int depth) : + m_indent(indent), m_isEnumList(isEnumList), + m_depth(depth) +{ + m_parent = parent; +} + +int DocAutoList::parse() +{ + int retval = RetVal_OK; + int num=1; + g_nodeStack.push(this); + // first item or sub list => create new list + do + { + if (g_token->id!=-1) // explicitly numbered list + { + num=g_token->id; // override num with real number given + } + DocAutoListItem *li = new DocAutoListItem(this,m_indent,num++); + m_children.append(li); + retval=li->parse(); + //printf("DocAutoList::parse(): retval=0x%x g_token->indent=%d m_indent=%d " + // "m_isEnumList=%d g_token->isEnumList=%d g_token->name=%s\n", + // retval,g_token->indent,m_indent,m_isEnumList,g_token->isEnumList, + // g_token->name.data()); + //printf("num=%d g_token->id=%d\n",num,g_token->id); + } + while (retval==TK_LISTITEM && // new list item + m_indent==g_token->indent && // at same indent level + m_isEnumList==g_token->isEnumList && // of the same kind + (g_token->id==-1 || g_token->id>=num) // increasing number (or no number) + ); + + DocNode *n=g_nodeStack.pop(); + ASSERT(n==this); + return retval; +} + +//-------------------------------------------------------------------------- + +void DocTitle::parse() +{ + DBG(("DocTitle::parse() start\n")); + g_nodeStack.push(this); + doctokenizerYYsetStateTitle(); + int tok; + while ((tok=doctokenizerYYlex())) + { + if (!defaultHandleToken(this,tok,m_children)) + { + switch (tok) + { + case TK_COMMAND: + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Illegal command %s as part of a title section", + qPrint(g_token->name)); + break; + case TK_SYMBOL: + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unsupported symbol %s found", + qPrint(g_token->name)); + break; + default: + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected token %s", + tokToString(tok)); + break; + } + } + } + doctokenizerYYsetStatePara(); + handlePendingStyleCommands(this,m_children); + DBG(("DocTitle::parse() end\n")); + DocNode *n = g_nodeStack.pop(); + ASSERT(n==this); +} + +void DocTitle::parseFromString(const QCString &text) +{ + m_children.append(new DocWord(this,text)); +} + +//-------------------------------------------------------------------------- + +DocSimpleSect::DocSimpleSect(DocNode *parent,Type t) : + m_type(t) +{ + m_parent = parent; + m_title=0; +} + +DocSimpleSect::~DocSimpleSect() +{ + delete m_title; +} + +void DocSimpleSect::accept(DocVisitor *v) +{ + v->visitPre(this); + if (m_title) m_title->accept(v); + QListIterator<DocNode> cli(m_children); + DocNode *n; + for (cli.toFirst();(n=cli.current());++cli) n->accept(v); + v->visitPost(this); +} + +int DocSimpleSect::parse(bool userTitle,bool needsSeparator) +{ + DBG(("DocSimpleSect::parse() start\n")); + g_nodeStack.push(this); + + // handle case for user defined title + if (userTitle) + { + m_title = new DocTitle(this); + m_title->parse(); + } + + // add new paragraph as child + DocPara *par = new DocPara(this); + if (m_children.isEmpty()) + { + par->markFirst(); + } + else + { + ASSERT(m_children.last()->kind()==DocNode::Kind_Para); + ((DocPara *)m_children.last())->markLast(FALSE); + } + par->markLast(); + if (needsSeparator) m_children.append(new DocSimpleSectSep(this)); + m_children.append(par); + + // parse the contents of the paragraph + int retval = par->parse(); + + DBG(("DocSimpleSect::parse() end retval=%d\n",retval)); + DocNode *n=g_nodeStack.pop(); + ASSERT(n==this); + return retval; // 0==EOF, TK_NEWPARA, TK_LISTITEM, TK_ENDLIST, RetVal_SimpleSec +} + +int DocSimpleSect::parseRcs() +{ + DBG(("DocSimpleSect::parseRcs() start\n")); + g_nodeStack.push(this); + + m_title = new DocTitle(this); + m_title->parseFromString(g_token->name); + + QCString text = g_token->text; + docParserPushContext(); // this will create a new g_token + internalValidatingParseDoc(this,m_children,text); + docParserPopContext(); // this will restore the old g_token + + DBG(("DocSimpleSect::parseRcs()\n")); + DocNode *n=g_nodeStack.pop(); + ASSERT(n==this); + return RetVal_OK; +} + +int DocSimpleSect::parseXml() +{ + DBG(("DocSimpleSect::parse() start\n")); + g_nodeStack.push(this); + + int retval = RetVal_OK; + for (;;) + { + // add new paragraph as child + DocPara *par = new DocPara(this); + if (m_children.isEmpty()) + { + par->markFirst(); + } + else + { + ASSERT(m_children.last()->kind()==DocNode::Kind_Para); + ((DocPara *)m_children.last())->markLast(FALSE); + } + par->markLast(); + m_children.append(par); + + // parse the contents of the paragraph + retval = par->parse(); + if (retval == 0) break; + if (retval == RetVal_CloseXml) + { + retval = RetVal_OK; + break; + } + } + + DBG(("DocSimpleSect::parseXml() end retval=%d\n",retval)); + DocNode *n=g_nodeStack.pop(); + ASSERT(n==this); + return retval; +} + +void DocSimpleSect::appendLinkWord(const QCString &word) +{ + DocPara *p; + if (m_children.isEmpty() || m_children.last()->kind()!=DocNode::Kind_Para) + { + p = new DocPara(this); + m_children.append(p); + } + else + { + p = (DocPara *)m_children.last(); + + // Comma-seperate <seealso> links. + p->injectToken(TK_WORD,","); + p->injectToken(TK_WHITESPACE," "); + } + + g_inSeeBlock=TRUE; + p->injectToken(TK_LNKWORD,word); + g_inSeeBlock=FALSE; +} + +QCString DocSimpleSect::typeString() const +{ + switch (m_type) + { + case Unknown: break; + case See: return "see"; + case Return: return "return"; + case Author: // fall through + case Authors: return "author"; + case Version: return "version"; + case Since: return "since"; + case Date: return "date"; + case Note: return "note"; + case Warning: return "warning"; + case Pre: return "pre"; + case Post: return "post"; + case Copyright: return "copyright"; + case Invar: return "invariant"; + case Remark: return "remark"; + case Attention: return "attention"; + case User: return "user"; + case Rcs: return "rcs"; + } + return "unknown"; +} + +//-------------------------------------------------------------------------- + +int DocParamList::parse(const QCString &cmdName) +{ + int retval=RetVal_OK; + DBG(("DocParamList::parse() start\n")); + g_nodeStack.push(this); + DocPara *par=0; + + int tok=doctokenizerYYlex(); + if (tok!=TK_WHITESPACE) + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected whitespace after %s command", + qPrint(cmdName)); + } + doctokenizerYYsetStateParam(); + tok=doctokenizerYYlex(); + while (tok==TK_WORD) /* there is a parameter name */ + { + if (m_type==DocParamSect::Param) + { + int typeSeparator = g_token->name.find('#'); // explicit type position + if (typeSeparator!=-1) + { + handleParameterType(this,m_paramTypes,g_token->name.left(typeSeparator)); + g_token->name = g_token->name.mid(typeSeparator+1); + g_hasParamCommand=TRUE; + checkArgumentName(g_token->name,TRUE); + ((DocParamSect*)parent())->m_hasTypeSpecifier=TRUE; + } + else + { + g_hasParamCommand=TRUE; + checkArgumentName(g_token->name,TRUE); + } + } + else if (m_type==DocParamSect::RetVal) + { + g_hasReturnCommand=TRUE; + checkArgumentName(g_token->name,FALSE); + } + //m_params.append(g_token->name); + handleLinkedWord(this,m_params); + tok=doctokenizerYYlex(); + } + doctokenizerYYsetStatePara(); + if (tok==0) /* premature end of comment block */ + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected end of comment block while parsing the " + "argument of command %s",qPrint(cmdName)); + retval=0; + goto endparamlist; + } + ASSERT(tok==TK_WHITESPACE); + + par = new DocPara(this); + m_paragraphs.append(par); + retval = par->parse(); + par->markFirst(); + par->markLast(); + +endparamlist: + DBG(("DocParamList::parse() end retval=%d\n",retval)); + DocNode *n=g_nodeStack.pop(); + ASSERT(n==this); + return retval; +} + +int DocParamList::parseXml(const QCString ¶mName) +{ + int retval=RetVal_OK; + DBG(("DocParamList::parseXml() start\n")); + g_nodeStack.push(this); + + g_token->name = paramName; + if (m_type==DocParamSect::Param) + { + g_hasParamCommand=TRUE; + checkArgumentName(g_token->name,TRUE); + } + else if (m_type==DocParamSect::RetVal) + { + g_hasReturnCommand=TRUE; + checkArgumentName(g_token->name,FALSE); + } + + handleLinkedWord(this,m_params); + + do + { + DocPara *par = new DocPara(this); + retval = par->parse(); + if (par->isEmpty()) // avoid adding an empty paragraph for the whitespace + // after </para> and before </param> + { + delete par; + break; + } + else // append the paragraph to the list + { + if (m_paragraphs.isEmpty()) + { + par->markFirst(); + } + else + { + m_paragraphs.last()->markLast(FALSE); + } + par->markLast(); + m_paragraphs.append(par); + } + + if (retval == 0) break; + + } while (retval==RetVal_CloseXml && + Mappers::htmlTagMapper->map(g_token->name)!=XML_PARAM && + Mappers::htmlTagMapper->map(g_token->name)!=XML_TYPEPARAM && + Mappers::htmlTagMapper->map(g_token->name)!=XML_EXCEPTION); + + + if (retval==0) /* premature end of comment block */ + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unterminated param or exception tag"); + } + else + { + retval=RetVal_OK; + } + + + DBG(("DocParamList::parse() end retval=%d\n",retval)); + DocNode *n=g_nodeStack.pop(); + ASSERT(n==this); + return retval; +} + +//-------------------------------------------------------------------------- + +int DocParamSect::parse(const QCString &cmdName,bool xmlContext, Direction d) +{ + int retval=RetVal_OK; + DBG(("DocParamSect::parse() start\n")); + g_nodeStack.push(this); + + if (d!=Unspecified) + { + m_hasInOutSpecifier=TRUE; + } + + DocParamList *pl = new DocParamList(this,m_type,d); + if (m_children.isEmpty()) + { + pl->markFirst(); + pl->markLast(); + } + else + { + ASSERT(m_children.last()->kind()==DocNode::Kind_ParamList); + ((DocParamList *)m_children.last())->markLast(FALSE); + pl->markLast(); + } + m_children.append(pl); + if (xmlContext) + { + retval = pl->parseXml(cmdName); + } + else + { + retval = pl->parse(cmdName); + } + + DBG(("DocParamSect::parse() end retval=%d\n",retval)); + DocNode *n=g_nodeStack.pop(); + ASSERT(n==this); + return retval; +} + +//-------------------------------------------------------------------------- + +int DocPara::handleSimpleSection(DocSimpleSect::Type t, bool xmlContext) +{ + DocSimpleSect *ss=0; + bool needsSeparator = FALSE; + if (!m_children.isEmpty() && // previous element + m_children.last()->kind()==Kind_SimpleSect && // was a simple sect + ((DocSimpleSect *)m_children.last())->type()==t && // of same type + t!=DocSimpleSect::User) // but not user defined + { + // append to previous section + ss=(DocSimpleSect *)m_children.last(); + needsSeparator = TRUE; + } + else // start new section + { + ss=new DocSimpleSect(this,t); + m_children.append(ss); + } + int rv = RetVal_OK; + if (xmlContext) + { + return ss->parseXml(); + } + else + { + rv = ss->parse(t==DocSimpleSect::User,needsSeparator); + } + return (rv!=TK_NEWPARA) ? rv : RetVal_OK; +} + +int DocPara::handleParamSection(const QCString &cmdName, + DocParamSect::Type t, + bool xmlContext=FALSE, + int direction=DocParamSect::Unspecified) +{ + DocParamSect *ps=0; + if (!m_children.isEmpty() && // previous element + m_children.last()->kind()==Kind_ParamSect && // was a param sect + ((DocParamSect *)m_children.last())->type()==t) // of same type + { + // append to previous section + ps=(DocParamSect *)m_children.last(); + } + else // start new section + { + ps=new DocParamSect(this,t); + m_children.append(ps); + } + int rv=ps->parse(cmdName,xmlContext,(DocParamSect::Direction)direction); + return (rv!=TK_NEWPARA) ? rv : RetVal_OK; +} + +void DocPara::handleCite() +{ + // get the argument of the cite command. + int tok=doctokenizerYYlex(); + if (tok!=TK_WHITESPACE) + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected whitespace after %s command", + qPrint("cite")); + return; + } + doctokenizerYYsetStateCite(); + tok=doctokenizerYYlex(); + if (tok==0) + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected end of comment block while parsing the " + "argument of command %s\n", qPrint("cite")); + return; + } + else if (tok!=TK_WORD && tok!=TK_LNKWORD) + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected token %s as the argument of %s", + tokToString(tok),qPrint("cite")); + return; + } + g_token->sectionId = g_token->name; + DocCite *cite = new DocCite(this,g_token->name,g_context); + m_children.append(cite); + //cite->parse(); + + doctokenizerYYsetStatePara(); +} + +int DocPara::handleXRefItem() +{ + int retval=doctokenizerYYlex(); + ASSERT(retval==TK_WHITESPACE); + doctokenizerYYsetStateXRefItem(); + retval=doctokenizerYYlex(); + if (retval==RetVal_OK) + { + DocXRefItem *ref = new DocXRefItem(this,g_token->id,g_token->name); + if (ref->parse()) + { + m_children.append(ref); + } + else + { + delete ref; + } + } + doctokenizerYYsetStatePara(); + return retval; +} + +void DocPara::handleIncludeOperator(const QCString &cmdName,DocIncOperator::Type t) +{ + DBG(("handleIncludeOperator(%s)\n",qPrint(cmdName))); + int tok=doctokenizerYYlex(); + if (tok!=TK_WHITESPACE) + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected whitespace after %s command", + qPrint(cmdName)); + return; + } + doctokenizerYYsetStatePattern(); + tok=doctokenizerYYlex(); + doctokenizerYYsetStatePara(); + if (tok==0) + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected end of comment block while parsing the " + "argument of command %s", qPrint(cmdName)); + return; + } + else if (tok!=TK_WORD) + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected token %s as the argument of %s", + tokToString(tok),qPrint(cmdName)); + return; + } + DocIncOperator *op = new DocIncOperator(this,t,g_token->name,g_context,g_isExample,g_exampleName); + DocNode *n1 = m_children.last(); + DocNode *n2 = n1!=0 ? m_children.prev() : 0; + bool isFirst = n1==0 || // no last node + (n1->kind()!=DocNode::Kind_IncOperator && + n1->kind()!=DocNode::Kind_WhiteSpace + ) || // last node is not operator or whitespace + (n1->kind()==DocNode::Kind_WhiteSpace && + n2!=0 && n2->kind()!=DocNode::Kind_IncOperator + ); // previous not is not operator + op->markFirst(isFirst); + op->markLast(TRUE); + if (n1!=0 && n1->kind()==DocNode::Kind_IncOperator) + { + ((DocIncOperator *)n1)->markLast(FALSE); + } + else if (n1!=0 && n1->kind()==DocNode::Kind_WhiteSpace && + n2!=0 && n2->kind()==DocNode::Kind_IncOperator + ) + { + ((DocIncOperator *)n2)->markLast(FALSE); + } + m_children.append(op); + op->parse(); +} + +void DocPara::handleImage(const QCString &cmdName) +{ + int tok=doctokenizerYYlex(); + if (tok!=TK_WHITESPACE) + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected whitespace after %s command", + qPrint(cmdName)); + return; + } + tok=doctokenizerYYlex(); + if (tok!=TK_WORD && tok!=TK_LNKWORD) + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected token %s as the argument of %s", + tokToString(tok),qPrint(cmdName)); + return; + } + tok=doctokenizerYYlex(); + if (tok!=TK_WHITESPACE) + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected whitespace after %s command", + qPrint(cmdName)); + return; + } + DocImage::Type t; + QCString imgType = g_token->name.lower(); + if (imgType=="html") t=DocImage::Html; + else if (imgType=="latex") t=DocImage::Latex; + else if (imgType=="rtf") t=DocImage::Rtf; + else + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: image type %s specified as the first argument of " + "%s is not valid", + qPrint(imgType),qPrint(cmdName)); + return; + } + doctokenizerYYsetStateFile(); + tok=doctokenizerYYlex(); + doctokenizerYYsetStatePara(); + if (tok!=TK_WORD) + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected token %s as the argument of %s", + tokToString(tok),qPrint(cmdName)); + return; + } + HtmlAttribList attrList; + DocImage *img = new DocImage(this,attrList,findAndCopyImage(g_token->name,t),t); + m_children.append(img); + img->parse(); +} + +void DocPara::handleDotFile(const QCString &cmdName) +{ + int tok=doctokenizerYYlex(); + if (tok!=TK_WHITESPACE) + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected whitespace after %s command", + qPrint(cmdName)); + return; + } + doctokenizerYYsetStateFile(); + tok=doctokenizerYYlex(); + doctokenizerYYsetStatePara(); + if (tok!=TK_WORD) + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected token %s as the argument of %s", + tokToString(tok),qPrint(cmdName)); + return; + } + QCString name = g_token->name; + DocDotFile *df = new DocDotFile(this,name,g_context); + m_children.append(df); + df->parse(); +} + +void DocPara::handleMscFile(const QCString &cmdName) +{ + int tok=doctokenizerYYlex(); + if (tok!=TK_WHITESPACE) + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected whitespace after %s command", + qPrint(cmdName)); + return; + } + doctokenizerYYsetStateFile(); + tok=doctokenizerYYlex(); + doctokenizerYYsetStatePara(); + if (tok!=TK_WORD) + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected token %s as the argument of %s", + tokToString(tok),qPrint(cmdName)); + return; + } + QCString name = g_token->name; + DocMscFile *df = new DocMscFile(this,name,g_context); + m_children.append(df); + df->parse(); +} + +void DocPara::handleLink(const QCString &cmdName,bool isJavaLink) +{ + int tok=doctokenizerYYlex(); + if (tok!=TK_WHITESPACE) + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected whitespace after %s command", + qPrint(cmdName)); + return; + } + doctokenizerYYsetStateLink(); + tok=doctokenizerYYlex(); + if (tok!=TK_WORD) + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected token %s as the argument of %s", + tokToString(tok),qPrint(cmdName)); + return; + } + doctokenizerYYsetStatePara(); + DocLink *lnk = new DocLink(this,g_token->name); + m_children.append(lnk); + QCString leftOver = lnk->parse(isJavaLink); + if (!leftOver.isEmpty()) + { + m_children.append(new DocWord(this,leftOver)); + } +} + +void DocPara::handleRef(const QCString &cmdName) +{ + DBG(("handleRef(%s)\n",qPrint(cmdName))); + int tok=doctokenizerYYlex(); + if (tok!=TK_WHITESPACE) + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected whitespace after %s command", + qPrint(cmdName)); + return; + } + doctokenizerYYsetStateRef(); + tok=doctokenizerYYlex(); // get the reference id + DocRef *ref=0; + if (tok!=TK_WORD) + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected token %s as the argument of %s", + tokToString(tok),qPrint(cmdName)); + goto endref; + } + ref = new DocRef(this,g_token->name,g_context); + m_children.append(ref); + ref->parse(); +endref: + doctokenizerYYsetStatePara(); +} + + +void DocPara::handleInclude(const QCString &cmdName,DocInclude::Type t) +{ + DBG(("handleInclude(%s)\n",qPrint(cmdName))); + int tok=doctokenizerYYlex(); + if (tok!=TK_WHITESPACE) + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected whitespace after %s command", + qPrint(cmdName)); + return; + } + doctokenizerYYsetStateFile(); + tok=doctokenizerYYlex(); + doctokenizerYYsetStatePara(); + if (tok==0) + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected end of comment block while parsing the " + "argument of command %s",qPrint(cmdName)); + return; + } + else if (tok!=TK_WORD) + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected token %s as the argument of %s", + tokToString(tok),qPrint(cmdName)); + return; + } + QCString fileName = g_token->name; + QCString blockId; + if (t==DocInclude::Snippet) + { + doctokenizerYYsetStateSnippet(); + tok=doctokenizerYYlex(); + doctokenizerYYsetStatePara(); + if (tok!=TK_WORD) + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected block identifier, but found token %s instead while parsing the %s command", + tokToString(tok),qPrint(cmdName)); + return; + } + blockId = "["+g_token->name+"]"; + } + DocInclude *inc = new DocInclude(this,fileName,g_context,t,g_isExample,g_exampleName,blockId); + m_children.append(inc); + inc->parse(); +} + +void DocPara::handleSection(const QCString &cmdName) +{ + // get the argument of the section command. + int tok=doctokenizerYYlex(); + if (tok!=TK_WHITESPACE) + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected whitespace after %s command", + qPrint(cmdName)); + return; + } + tok=doctokenizerYYlex(); + if (tok==0) + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected end of comment block while parsing the " + "argument of command %s\n", qPrint(cmdName)); + return; + } + else if (tok!=TK_WORD && tok!=TK_LNKWORD) + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected token %s as the argument of %s", + tokToString(tok),qPrint(cmdName)); + return; + } + g_token->sectionId = g_token->name; + doctokenizerYYsetStateSkipTitle(); + doctokenizerYYlex(); + doctokenizerYYsetStatePara(); +} + +int DocPara::handleHtmlHeader(const HtmlAttribList &tagHtmlAttribs,int level) +{ + DocHtmlHeader *header = new DocHtmlHeader(this,tagHtmlAttribs,level); + m_children.append(header); + int retval = header->parse(); + return (retval==RetVal_OK) ? TK_NEWPARA : retval; +} + +// For XML tags whose content is stored in attributes rather than +// contained within the element, we need a way to inject the attribute +// text into the current paragraph. +bool DocPara::injectToken(int tok,const QCString &tokText) +{ + g_token->name = tokText; + return defaultHandleToken(this,tok,m_children); +} + +int DocPara::handleStartCode() +{ + int retval = doctokenizerYYlex(); + QCString lang = g_token->name; + if (!lang.isEmpty() && lang.at(0)!='.') + { + lang="."+lang; + } + // search for the first non-whitespace line, index is stored in li + int i=0,li=0,l=g_token->verb.length(); + while (i<l && (g_token->verb.at(i)==' ' || g_token->verb.at(i)=='\n')) + { + if (g_token->verb.at(i)=='\n') li=i+1; + i++; + } + m_children.append(new DocVerbatim(this,g_context,g_token->verb.mid(li),DocVerbatim::Code,g_isExample,g_exampleName,lang)); + if (retval==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: code section ended without end marker"); + doctokenizerYYsetStatePara(); + return retval; +} + +void DocPara::handleInheritDoc() +{ + if (g_memberDef) // inheriting docs from a member + { + MemberDef *reMd = g_memberDef->reimplements(); + if (reMd) // member from which was inherited. + { + MemberDef *thisMd = g_memberDef; + //printf("{InheritDocs:%s=>%s}\n",g_memberDef->qualifiedName().data(),reMd->qualifiedName().data()); + docParserPushContext(); + g_scope=reMd->getOuterScope(); + if (g_scope!=Doxygen::globalScope) + { + g_context=g_scope->name(); + } + g_memberDef=reMd; + g_styleStack.clear(); + g_nodeStack.clear(); + g_copyStack.append(reMd); + internalValidatingParseDoc(this,m_children,reMd->briefDescription()); + internalValidatingParseDoc(this,m_children,reMd->documentation()); + g_copyStack.remove(reMd); + docParserPopContext(TRUE); + g_memberDef = thisMd; + } + } +} + + +int DocPara::handleCommand(const QCString &cmdName) +{ + DBG(("handleCommand(%s)\n",qPrint(cmdName))); + int retval = RetVal_OK; + int cmdId = Mappers::cmdMapper->map(cmdName); + switch (cmdId) + { + case CMD_UNKNOWN: + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Found unknown command `\\%s'",qPrint(cmdName)); + break; + case CMD_EMPHASIS: + m_children.append(new DocStyleChange(this,g_nodeStack.count(),DocStyleChange::Italic,TRUE)); + retval=handleStyleArgument(this,m_children,cmdName); + m_children.append(new DocStyleChange(this,g_nodeStack.count(),DocStyleChange::Italic,FALSE)); + if (retval!=TK_WORD) m_children.append(new DocWhiteSpace(this," ")); + break; + case CMD_BOLD: + m_children.append(new DocStyleChange(this,g_nodeStack.count(),DocStyleChange::Bold,TRUE)); + retval=handleStyleArgument(this,m_children,cmdName); + m_children.append(new DocStyleChange(this,g_nodeStack.count(),DocStyleChange::Bold,FALSE)); + if (retval!=TK_WORD) m_children.append(new DocWhiteSpace(this," ")); + break; + case CMD_CODE: + m_children.append(new DocStyleChange(this,g_nodeStack.count(),DocStyleChange::Code,TRUE)); + retval=handleStyleArgument(this,m_children,cmdName); + m_children.append(new DocStyleChange(this,g_nodeStack.count(),DocStyleChange::Code,FALSE)); + if (retval!=TK_WORD) m_children.append(new DocWhiteSpace(this," ")); + break; + case CMD_BSLASH: + m_children.append(new DocSymbol(this,DocSymbol::BSlash)); + break; + case CMD_AT: + m_children.append(new DocSymbol(this,DocSymbol::At)); + break; + case CMD_LESS: + m_children.append(new DocSymbol(this,DocSymbol::Less)); + break; + case CMD_GREATER: + m_children.append(new DocSymbol(this,DocSymbol::Greater)); + break; + case CMD_AMP: + m_children.append(new DocSymbol(this,DocSymbol::Amp)); + break; + case CMD_DOLLAR: + m_children.append(new DocSymbol(this,DocSymbol::Dollar)); + break; + case CMD_HASH: + m_children.append(new DocSymbol(this,DocSymbol::Hash)); + break; + case CMD_DCOLON: + m_children.append(new DocSymbol(this,DocSymbol::DoubleColon)); + break; + case CMD_PERCENT: + m_children.append(new DocSymbol(this,DocSymbol::Percent)); + break; + case CMD_QUOTE: + m_children.append(new DocSymbol(this,DocSymbol::Quot)); + break; + case CMD_SA: + g_inSeeBlock=TRUE; + retval = handleSimpleSection(DocSimpleSect::See); + g_inSeeBlock=FALSE; + break; + case CMD_RETURN: + retval = handleSimpleSection(DocSimpleSect::Return); + g_hasReturnCommand=TRUE; + break; + case CMD_AUTHOR: + retval = handleSimpleSection(DocSimpleSect::Author); + break; + case CMD_AUTHORS: + retval = handleSimpleSection(DocSimpleSect::Authors); + break; + case CMD_VERSION: + retval = handleSimpleSection(DocSimpleSect::Version); + break; + case CMD_SINCE: + retval = handleSimpleSection(DocSimpleSect::Since); + break; + case CMD_DATE: + retval = handleSimpleSection(DocSimpleSect::Date); + break; + case CMD_NOTE: + retval = handleSimpleSection(DocSimpleSect::Note); + break; + case CMD_WARNING: + retval = handleSimpleSection(DocSimpleSect::Warning); + break; + case CMD_PRE: + retval = handleSimpleSection(DocSimpleSect::Pre); + break; + case CMD_POST: + retval = handleSimpleSection(DocSimpleSect::Post); + break; + case CMD_COPYRIGHT: + retval = handleSimpleSection(DocSimpleSect::Copyright); + break; + case CMD_INVARIANT: + retval = handleSimpleSection(DocSimpleSect::Invar); + break; + case CMD_REMARK: + retval = handleSimpleSection(DocSimpleSect::Remark); + break; + case CMD_ATTENTION: + retval = handleSimpleSection(DocSimpleSect::Attention); + break; + case CMD_PAR: + retval = handleSimpleSection(DocSimpleSect::User); + break; + case CMD_LI: + { + DocSimpleList *sl=new DocSimpleList(this); + m_children.append(sl); + retval = sl->parse(); + } + break; + case CMD_SECTION: + { + handleSection(cmdName); + retval = RetVal_Section; + } + break; + case CMD_SUBSECTION: + { + handleSection(cmdName); + retval = RetVal_Subsection; + } + break; + case CMD_SUBSUBSECTION: + { + handleSection(cmdName); + retval = RetVal_Subsubsection; + } + break; + case CMD_PARAGRAPH: + { + handleSection(cmdName); + retval = RetVal_Paragraph; + } + break; + case CMD_STARTCODE: + { + doctokenizerYYsetStateCode(); + retval = handleStartCode(); + } + break; + case CMD_HTMLONLY: + { + doctokenizerYYsetStateHtmlOnly(); + retval = doctokenizerYYlex(); + m_children.append(new DocVerbatim(this,g_context,g_token->verb,DocVerbatim::HtmlOnly,g_isExample,g_exampleName)); + if (retval==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: htmlonly section ended without end marker"); + doctokenizerYYsetStatePara(); + } + break; + case CMD_MANONLY: + { + doctokenizerYYsetStateManOnly(); + retval = doctokenizerYYlex(); + m_children.append(new DocVerbatim(this,g_context,g_token->verb,DocVerbatim::ManOnly,g_isExample,g_exampleName)); + if (retval==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: manonly section ended without end marker"); + doctokenizerYYsetStatePara(); + } + break; + case CMD_LATEXONLY: + { + doctokenizerYYsetStateLatexOnly(); + retval = doctokenizerYYlex(); + m_children.append(new DocVerbatim(this,g_context,g_token->verb,DocVerbatim::LatexOnly,g_isExample,g_exampleName)); + if (retval==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: latexonly section ended without end marker"); + doctokenizerYYsetStatePara(); + } + break; + case CMD_XMLONLY: + { + doctokenizerYYsetStateXmlOnly(); + retval = doctokenizerYYlex(); + m_children.append(new DocVerbatim(this,g_context,g_token->verb,DocVerbatim::XmlOnly,g_isExample,g_exampleName)); + if (retval==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: xmlonly section ended without end marker"); + doctokenizerYYsetStatePara(); + } + break; + case CMD_VERBATIM: + { + doctokenizerYYsetStateVerbatim(); + retval = doctokenizerYYlex(); + m_children.append(new DocVerbatim(this,g_context,g_token->verb,DocVerbatim::Verbatim,g_isExample,g_exampleName)); + if (retval==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: verbatim section ended without end marker"); + doctokenizerYYsetStatePara(); + } + break; + case CMD_DOT: + { + doctokenizerYYsetStateDot(); + retval = doctokenizerYYlex(); + m_children.append(new DocVerbatim(this,g_context,g_token->verb,DocVerbatim::Dot,g_isExample,g_exampleName)); + if (retval==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: dot section ended without end marker"); + doctokenizerYYsetStatePara(); + } + break; + case CMD_MSC: + { + doctokenizerYYsetStateMsc(); + retval = doctokenizerYYlex(); + m_children.append(new DocVerbatim(this,g_context,g_token->verb,DocVerbatim::Msc,g_isExample,g_exampleName)); + if (retval==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: msc section ended without end marker"); + doctokenizerYYsetStatePara(); + } + break; + case CMD_ENDCODE: + case CMD_ENDHTMLONLY: + case CMD_ENDMANONLY: + case CMD_ENDLATEXONLY: + case CMD_ENDXMLONLY: + case CMD_ENDLINK: + case CMD_ENDVERBATIM: + case CMD_ENDDOT: + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected command %s",qPrint(g_token->name)); + break; + case CMD_ENDMSC: + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected command %s",qPrint(g_token->name)); + break; + case CMD_PARAM: + retval = handleParamSection(cmdName,DocParamSect::Param,FALSE,g_token->paramDir); + break; + case CMD_TPARAM: + retval = handleParamSection(cmdName,DocParamSect::TemplateParam,FALSE,g_token->paramDir); + break; + case CMD_RETVAL: + retval = handleParamSection(cmdName,DocParamSect::RetVal); + break; + case CMD_EXCEPTION: + retval = handleParamSection(cmdName,DocParamSect::Exception); + break; + case CMD_XREFITEM: + retval = handleXRefItem(); + break; + case CMD_LINEBREAK: + { + DocLineBreak *lb = new DocLineBreak(this); + m_children.append(lb); + } + break; + case CMD_ANCHOR: + { + DocAnchor *anchor = handleAnchor(this); + if (anchor) + { + m_children.append(anchor); + } + } + break; + case CMD_ADDINDEX: + { + DocIndexEntry *ie = new DocIndexEntry(this, + g_scope!=Doxygen::globalScope?g_scope:0, + g_memberDef); + m_children.append(ie); + retval = ie->parse(); + } + break; + case CMD_INTERNAL: + retval = RetVal_Internal; + break; + case CMD_COPYDOC: // fall through + case CMD_COPYBRIEF: // fall through + case CMD_COPYDETAILS: + { + int tok=doctokenizerYYlex(); + if (tok!=TK_WHITESPACE) + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected whitespace after %s command", + qPrint(cmdName)); + break; + } + tok=doctokenizerYYlex(); + if (tok==0) + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected end of comment block while parsing the " + "argument of command %s\n", qPrint(cmdName)); + break; + } + else if (tok!=TK_WORD && tok!=TK_LNKWORD) + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected token %s as the argument of %s", + tokToString(tok),qPrint(cmdName)); + break; + } + DocCopy *cpy = new DocCopy(this,g_token->name, + cmdId==CMD_COPYDOC || cmdId==CMD_COPYBRIEF, + cmdId==CMD_COPYDOC || cmdId==CMD_COPYDETAILS); + //m_children.append(cpy); + cpy->parse(m_children); + delete cpy; + } + break; + case CMD_INCLUDE: + handleInclude(cmdName,DocInclude::Include); + break; + case CMD_INCWITHLINES: + handleInclude(cmdName,DocInclude::IncWithLines); + break; + case CMD_DONTINCLUDE: + handleInclude(cmdName,DocInclude::DontInclude); + break; + case CMD_HTMLINCLUDE: + handleInclude(cmdName,DocInclude::HtmlInclude); + break; + case CMD_VERBINCLUDE: + handleInclude(cmdName,DocInclude::VerbInclude); + break; + case CMD_SNIPPET: + handleInclude(cmdName,DocInclude::Snippet); + break; + case CMD_SKIP: + handleIncludeOperator(cmdName,DocIncOperator::Skip); + break; + case CMD_UNTIL: + handleIncludeOperator(cmdName,DocIncOperator::Until); + break; + case CMD_SKIPLINE: + handleIncludeOperator(cmdName,DocIncOperator::SkipLine); + break; + case CMD_LINE: + handleIncludeOperator(cmdName,DocIncOperator::Line); + break; + case CMD_IMAGE: + handleImage(cmdName); + break; + case CMD_DOTFILE: + handleDotFile(cmdName); + break; + case CMD_MSCFILE: + handleMscFile(cmdName); + break; + case CMD_LINK: + handleLink(cmdName,FALSE); + break; + case CMD_JAVALINK: + handleLink(cmdName,TRUE); + break; + case CMD_CITE: + handleCite(); + break; + case CMD_REF: // fall through + case CMD_SUBPAGE: + handleRef(cmdName); + break; + case CMD_SECREFLIST: + { + DocSecRefList *list = new DocSecRefList(this); + m_children.append(list); + list->parse(); + } + break; + case CMD_SECREFITEM: + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected command %s",qPrint(g_token->name)); + break; + case CMD_ENDSECREFLIST: + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected command %s",qPrint(g_token->name)); + break; + case CMD_FORMULA: + { + DocFormula *form=new DocFormula(this,g_token->id); + m_children.append(form); + } + break; + //case CMD_LANGSWITCH: + // retval = handleLanguageSwitch(); + // break; + case CMD_INTERNALREF: + //warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected command %s",qPrint(g_token->name)); + { + DocInternalRef *ref = handleInternalRef(this); + if (ref) + { + m_children.append(ref); + ref->parse(); + } + doctokenizerYYsetStatePara(); + } + break; + case CMD_INHERITDOC: + handleInheritDoc(); + break; + default: + // we should not get here! + ASSERT(0); + break; + } + INTERNAL_ASSERT(retval==0 || retval==RetVal_OK || retval==RetVal_SimpleSec || + retval==TK_LISTITEM || retval==TK_ENDLIST || retval==TK_NEWPARA || + retval==RetVal_Section || retval==RetVal_EndList || + retval==RetVal_Internal || retval==RetVal_SwitchLang + ); + DBG(("handleCommand(%s) end retval=%x\n",qPrint(cmdName),retval)); + return retval; +} + +static bool findAttribute(const HtmlAttribList &tagHtmlAttribs, + const char *attrName, + QCString *result) +{ + + HtmlAttribListIterator li(tagHtmlAttribs); + HtmlAttrib *opt; + for (li.toFirst();(opt=li.current());++li) + { + if (opt->name==attrName) + { + *result = opt->value; + return TRUE; + } + } + return FALSE; +} + +int DocPara::handleHtmlStartTag(const QCString &tagName,const HtmlAttribList &tagHtmlAttribs) +{ + DBG(("handleHtmlStartTag(%s,%d)\n",qPrint(tagName),tagHtmlAttribs.count())); + int retval=RetVal_OK; + int tagId = Mappers::htmlTagMapper->map(tagName); + if (g_token->emptyTag && !(tagId&XML_CmdMask) && + tagId!=HTML_UNKNOWN && tagId!=HTML_IMG && tagId!=HTML_BR) + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: HTML tags may not use the 'empty tag' XHTML syntax."); + } + switch (tagId) + { + case HTML_UL: + { + DocHtmlList *list = new DocHtmlList(this,tagHtmlAttribs,DocHtmlList::Unordered); + m_children.append(list); + retval=list->parse(); + } + break; + case HTML_OL: + { + DocHtmlList *list = new DocHtmlList(this,tagHtmlAttribs,DocHtmlList::Ordered); + m_children.append(list); + retval=list->parse(); + } + break; + case HTML_LI: + if (!insideUL(this) && !insideOL(this)) + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: lonely <li> tag found"); + } + else + { + retval=RetVal_ListItem; + } + break; + case HTML_BOLD: + handleStyleEnter(this,m_children,DocStyleChange::Bold,&g_token->attribs); + break; + case HTML_CODE: + if (getLanguageFromFileName(g_fileName)==SrcLangExt_CSharp) + // for C# code we treat <code> as an XML tag + { + doctokenizerYYsetStateXmlCode(); + retval = handleStartCode(); + } + else // normal HTML markup + { + handleStyleEnter(this,m_children,DocStyleChange::Code,&g_token->attribs); + } + break; + case HTML_EMPHASIS: + handleStyleEnter(this,m_children,DocStyleChange::Italic,&g_token->attribs); + break; + case HTML_DIV: + handleStyleEnter(this,m_children,DocStyleChange::Div,&g_token->attribs); + break; + case HTML_SPAN: + handleStyleEnter(this,m_children,DocStyleChange::Span,&g_token->attribs); + break; + case HTML_SUB: + handleStyleEnter(this,m_children,DocStyleChange::Subscript,&g_token->attribs); + break; + case HTML_SUP: + handleStyleEnter(this,m_children,DocStyleChange::Superscript,&g_token->attribs); + break; + case HTML_CENTER: + handleStyleEnter(this,m_children,DocStyleChange::Center,&g_token->attribs); + break; + case HTML_SMALL: + handleStyleEnter(this,m_children,DocStyleChange::Small,&g_token->attribs); + break; + case HTML_PRE: + handleStyleEnter(this,m_children,DocStyleChange::Preformatted,&g_token->attribs); + setInsidePreformatted(TRUE); + //doctokenizerYYsetInsidePre(TRUE); + break; + case HTML_P: + retval=TK_NEWPARA; + break; + case HTML_DL: + { + DocHtmlDescList *list = new DocHtmlDescList(this,tagHtmlAttribs); + m_children.append(list); + retval=list->parse(); + } + break; + case HTML_DT: + retval = RetVal_DescTitle; + break; + case HTML_DD: + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected tag <dd> found"); + break; + case HTML_TABLE: + { + DocHtmlTable *table = new DocHtmlTable(this,tagHtmlAttribs); + m_children.append(table); + retval=table->parse(); + } + break; + case HTML_TR: + retval = RetVal_TableRow; + break; + case HTML_TD: + retval = RetVal_TableCell; + break; + case HTML_TH: + retval = RetVal_TableHCell; + break; + case HTML_CAPTION: + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected tag <caption> found"); + break; + case HTML_BR: + { + DocLineBreak *lb = new DocLineBreak(this); + m_children.append(lb); + } + break; + case HTML_HR: + { + DocHorRuler *hr = new DocHorRuler(this); + m_children.append(hr); + } + break; + case HTML_A: + retval=handleAHref(this,m_children,tagHtmlAttribs); + break; + case HTML_H1: + retval=handleHtmlHeader(tagHtmlAttribs,1); + break; + case HTML_H2: + retval=handleHtmlHeader(tagHtmlAttribs,2); + break; + case HTML_H3: + retval=handleHtmlHeader(tagHtmlAttribs,3); + break; + case HTML_H4: + retval=handleHtmlHeader(tagHtmlAttribs,4); + break; + case HTML_H5: + retval=handleHtmlHeader(tagHtmlAttribs,5); + break; + case HTML_H6: + retval=handleHtmlHeader(tagHtmlAttribs,6); + break; + case HTML_IMG: + { + HtmlAttribListIterator li(tagHtmlAttribs); + HtmlAttrib *opt; + bool found=FALSE; + int index=0; + for (li.toFirst();(opt=li.current());++li,++index) + { + //printf("option name=%s value=%s\n",opt->name.data(),opt->value.data()); + if (opt->name=="src" && !opt->value.isEmpty()) + { + // copy attributes + HtmlAttribList attrList = tagHtmlAttribs; + // and remove the src attribute + bool result = attrList.remove(index); + ASSERT(result); + DocImage *img = new DocImage(this,attrList,opt->value,DocImage::Html,opt->value); + m_children.append(img); + found = TRUE; + } + } + if (!found) + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: IMG tag does not have a SRC attribute!\n"); + } + } + break; + case HTML_BLOCKQUOTE: + { + DocHtmlBlockQuote *block = new DocHtmlBlockQuote(this,tagHtmlAttribs); + m_children.append(block); + retval = block->parse(); + } + break; + + case XML_SUMMARY: + case XML_REMARKS: + case XML_VALUE: + case XML_PARA: + if (!m_children.isEmpty()) + { + retval = TK_NEWPARA; + } + break; + case XML_EXAMPLE: + case XML_DESCRIPTION: + if (insideTable(this)) + { + retval=RetVal_TableCell; + } + break; + case XML_C: + handleStyleEnter(this,m_children,DocStyleChange::Code,&g_token->attribs); + break; + case XML_PARAM: + case XML_TYPEPARAM: + { + QCString paramName; + if (findAttribute(tagHtmlAttribs,"name",¶mName)) + { + if (paramName.isEmpty()) + { + if (Config_getBool("WARN_NO_PARAMDOC")) + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: empty 'name' attribute for <param> tag."); + } + } + else + { + retval = handleParamSection(paramName, + tagId==XML_PARAM ? DocParamSect::Param : DocParamSect::TemplateParam, + TRUE); + } + } + else + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Missing 'name' attribute from <param> tag."); + } + } + break; + case XML_PARAMREF: + case XML_TYPEPARAMREF: + { + QCString paramName; + if (findAttribute(tagHtmlAttribs,"name",¶mName)) + { + //printf("paramName=%s\n",paramName.data()); + m_children.append(new DocStyleChange(this,g_nodeStack.count(),DocStyleChange::Italic,TRUE)); + m_children.append(new DocWord(this,paramName)); + m_children.append(new DocStyleChange(this,g_nodeStack.count(),DocStyleChange::Italic,FALSE)); + if (retval!=TK_WORD) m_children.append(new DocWhiteSpace(this," ")); + } + else + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Missing 'name' attribute from <param%sref> tag.",tagId==XML_PARAMREF?"":"type"); + } + } + break; + case XML_EXCEPTION: + { + QCString exceptName; + if (findAttribute(tagHtmlAttribs,"cref",&exceptName)) + { + retval = handleParamSection(exceptName,DocParamSect::Exception,TRUE); + } + else + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Missing 'name' attribute from <exception> tag."); + } + } + break; + case XML_ITEM: + case XML_LISTHEADER: + if (insideTable(this)) + { + retval=RetVal_TableRow; + } + else if (insideUL(this) || insideOL(this)) + { + retval=RetVal_ListItem; + } + else + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: lonely <item> tag found"); + } + break; + case XML_RETURNS: + retval = handleSimpleSection(DocSimpleSect::Return,TRUE); + g_hasReturnCommand=TRUE; + break; + case XML_TERM: + //m_children.append(new DocStyleChange(this,g_nodeStack.count(),DocStyleChange::Bold,TRUE)); + if (insideTable(this)) + { + retval=RetVal_TableCell; + } + break; + case XML_SEE: + // I'm not sure if <see> is the same as <seealso> or if it + // should you link a member without producing a section. The + // C# specification is extremely vague about this (but what else + // can we expect from Microsoft...) + { + QCString cref; + //printf("XML_SEE: empty tag=%d\n",g_token->emptyTag); + if (findAttribute(tagHtmlAttribs,"cref",&cref)) + { + if (g_token->emptyTag) // <see cref="..."/> style + { + bool inSeeBlock = g_inSeeBlock; + g_token->name = cref; + g_inSeeBlock = TRUE; + handleLinkedWord(this,m_children); + g_inSeeBlock = inSeeBlock; + } + else // <see cref="...">...</see> style + { + //DocRef *ref = new DocRef(this,cref); + //m_children.append(ref); + //ref->parse(); + doctokenizerYYsetStatePara(); + DocLink *lnk = new DocLink(this,cref); + m_children.append(lnk); + QCString leftOver = lnk->parse(FALSE,TRUE); + if (!leftOver.isEmpty()) + { + m_children.append(new DocWord(this,leftOver)); + } + } + } + else + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Missing 'cref' attribute from <see> tag."); + } + } + break; + case XML_SEEALSO: + { + QCString cref; + if (findAttribute(tagHtmlAttribs,"cref",&cref)) + { + // Look for an existing "see" section + DocSimpleSect *ss=0; + QListIterator<DocNode> cli(m_children); + DocNode *n; + for (cli.toFirst();(n=cli.current());++cli) + { + if (n->kind()==Kind_SimpleSect && ((DocSimpleSect *)n)->type()==DocSimpleSect::See) + { + ss = (DocSimpleSect *)n; + } + } + + if (!ss) // start new section + { + ss=new DocSimpleSect(this,DocSimpleSect::See); + m_children.append(ss); + } + + ss->appendLinkWord(cref); + retval = RetVal_OK; + } + else + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Missing 'cref' attribute from <seealso> tag."); + } + } + break; + case XML_LIST: + { + QCString type; + findAttribute(tagHtmlAttribs,"type",&type); + DocHtmlList::Type listType = DocHtmlList::Unordered; + HtmlAttribList emptyList; + if (type=="number") + { + listType=DocHtmlList::Ordered; + } + if (type=="table") + { + DocHtmlTable *table = new DocHtmlTable(this,emptyList); + m_children.append(table); + retval=table->parseXml(); + } + else + { + DocHtmlList *list = new DocHtmlList(this,emptyList,listType); + m_children.append(list); + retval=list->parseXml(); + } + } + break; + case XML_INCLUDE: + case XML_PERMISSION: + // These tags are defined in .Net but are currently unsupported + break; + case HTML_UNKNOWN: + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unsupported xml/html tag <%s> found", qPrint(tagName)); + m_children.append(new DocWord(this, "<"+tagName+tagHtmlAttribs.toString()+">")); + break; + case XML_INHERITDOC: + handleInheritDoc(); + break; + + default: + // we should not get here! + ASSERT(0); + break; + } + return retval; +} + +int DocPara::handleHtmlEndTag(const QCString &tagName) +{ + DBG(("handleHtmlEndTag(%s)\n",qPrint(tagName))); + int tagId = Mappers::htmlTagMapper->map(tagName); + int retval=RetVal_OK; + switch (tagId) + { + case HTML_UL: + if (!insideUL(this)) + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: found </ul> tag without matching <ul>"); + } + else + { + retval=RetVal_EndList; + } + break; + case HTML_OL: + if (!insideOL(this)) + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: found </ol> tag without matching <ol>"); + } + else + { + retval=RetVal_EndList; + } + break; + case HTML_LI: + if (!insideLI(this)) + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: found </li> tag without matching <li>"); + } + else + { + // ignore </li> tags + } + break; + case HTML_BLOCKQUOTE: + retval=RetVal_EndBlockQuote; + break; + //case HTML_PRE: + // if (!insidePRE(this)) + // { + // warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: found </pre> tag without matching <pre>"); + // } + // else + // { + // retval=RetVal_EndPre; + // } + // break; + case HTML_BOLD: + handleStyleLeave(this,m_children,DocStyleChange::Bold,"b"); + break; + case HTML_CODE: + handleStyleLeave(this,m_children,DocStyleChange::Code,"code"); + break; + case HTML_EMPHASIS: + handleStyleLeave(this,m_children,DocStyleChange::Italic,"em"); + break; + case HTML_DIV: + handleStyleLeave(this,m_children,DocStyleChange::Div,"div"); + break; + case HTML_SPAN: + handleStyleLeave(this,m_children,DocStyleChange::Span,"span"); + break; + case HTML_SUB: + handleStyleLeave(this,m_children,DocStyleChange::Subscript,"sub"); + break; + case HTML_SUP: + handleStyleLeave(this,m_children,DocStyleChange::Superscript,"sup"); + break; + case HTML_CENTER: + handleStyleLeave(this,m_children,DocStyleChange::Center,"center"); + break; + case HTML_SMALL: + handleStyleLeave(this,m_children,DocStyleChange::Small,"small"); + break; + case HTML_PRE: + handleStyleLeave(this,m_children,DocStyleChange::Preformatted,"pre"); + setInsidePreformatted(FALSE); + //doctokenizerYYsetInsidePre(FALSE); + break; + case HTML_P: + retval=TK_NEWPARA; + break; + case HTML_DL: + retval=RetVal_EndDesc; + break; + case HTML_DT: + // ignore </dt> tag + break; + case HTML_DD: + // ignore </dd> tag + break; + case HTML_TABLE: + retval=RetVal_EndTable; + break; + case HTML_TR: + // ignore </tr> tag + break; + case HTML_TD: + // ignore </td> tag + break; + case HTML_TH: + // ignore </th> tag + break; + case HTML_CAPTION: + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected tag </caption> found"); + break; + case HTML_BR: + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Illegal </br> tag found\n"); + break; + case HTML_H1: + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected tag </h1> found"); + break; + case HTML_H2: + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected tag </h2> found"); + break; + case HTML_H3: + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected tag </h3> found"); + break; + case HTML_IMG: + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected tag </img> found"); + break; + case HTML_HR: + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected tag </hr> found"); + break; + case HTML_A: + //warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected tag </a> found"); + // ignore </a> tag (can be part of <a name=...></a> + break; + + case XML_TERM: + //m_children.append(new DocStyleChange(this,g_nodeStack.count(),DocStyleChange::Bold,FALSE)); + break; + case XML_SUMMARY: + case XML_REMARKS: + case XML_PARA: + case XML_VALUE: + case XML_LIST: + case XML_EXAMPLE: + case XML_PARAM: + case XML_TYPEPARAM: + case XML_RETURNS: + case XML_SEE: + case XML_SEEALSO: + case XML_EXCEPTION: + case XML_INHERITDOC: + retval = RetVal_CloseXml; + break; + case XML_C: + handleStyleLeave(this,m_children,DocStyleChange::Code,"c"); + break; + case XML_ITEM: + case XML_LISTHEADER: + case XML_INCLUDE: + case XML_PERMISSION: + case XML_DESCRIPTION: + case XML_PARAMREF: + case XML_TYPEPARAMREF: + // These tags are defined in .Net but are currently unsupported + break; + case HTML_UNKNOWN: + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unsupported xml/html tag </%s> found", qPrint(tagName)); + m_children.append(new DocWord(this,"</"+tagName+">")); + break; + default: + // we should not get here! + warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected end tag %s\n",qPrint(tagName)); + ASSERT(0); + break; + } + return retval; +} + +int DocPara::parse() +{ + DBG(("DocPara::parse() start\n")); + g_nodeStack.push(this); + // handle style commands "inherited" from the previous paragraph + handleInitialStyleCommands(this,m_children); + int tok; + int retval=0; + while ((tok=doctokenizerYYlex())) // get the next token + { +reparsetoken: + DBG(("token %s at %d",tokToString(tok),doctokenizerYYlineno)); + if (tok==TK_WORD || tok==TK_LNKWORD || tok==TK_SYMBOL || tok==TK_URL || + tok==TK_COMMAND || tok==TK_HTMLTAG + ) + { + DBG((" name=%s",qPrint(g_token->name))); + } + DBG(("\n")); + switch(tok) + { + case TK_WORD: + m_children.append(new DocWord(this,g_token->name)); + break; + case TK_LNKWORD: + handleLinkedWord(this,m_children); + break; + case TK_URL: + m_children.append(new DocURL(this,g_token->name,g_token->isEMailAddr)); + break; + case TK_WHITESPACE: + { + // prevent leading whitespace and collapse multiple whitespace areas + DocNode::Kind k; + if (insidePRE(this) || // all whitespace is relevant + ( + // remove leading whitespace + !m_children.isEmpty() && + // and whitespace after certain constructs + (k=m_children.last()->kind())!=DocNode::Kind_HtmlDescList && + k!=DocNode::Kind_HtmlTable && + k!=DocNode::Kind_HtmlList && + k!=DocNode::Kind_SimpleSect && + k!=DocNode::Kind_AutoList && + k!=DocNode::Kind_SimpleList && + /*k!=DocNode::Kind_Verbatim &&*/ + k!=DocNode::Kind_HtmlHeader && + k!=DocNode::Kind_HtmlBlockQuote && + k!=DocNode::Kind_ParamSect && + k!=DocNode::Kind_XRefItem + ) + ) + { + m_children.append(new DocWhiteSpace(this,g_token->chars)); + } + } + break; + case TK_LISTITEM: + { + DBG(("found list item at %d parent=%d\n",g_token->indent,parent()->kind())); + DocNode *n=parent(); + while (n && n->kind()!=DocNode::Kind_AutoList) n=n->parent(); + if (n) // we found an auto list up in the hierarchy + { + DocAutoList *al = (DocAutoList *)n; + DBG(("previous list item at %d\n",al->indent())); + if (al->indent()>=g_token->indent) + // new item at the same or lower indent level + { + retval=TK_LISTITEM; + goto endparagraph; + } + } + + // determine list depth + int depth = 0; + n=parent(); + while(n) + { + if (n->kind() == DocNode::Kind_AutoList && + ((DocAutoList*)n)->isEnumList()) depth++; + n=n->parent(); + } + + // first item or sub list => create new list + DocAutoList *al=0; + do + { + al = new DocAutoList(this,g_token->indent, + g_token->isEnumList,depth); + m_children.append(al); + retval = al->parse(); + } while (retval==TK_LISTITEM && // new list + al->indent()==g_token->indent // at same indent level + ); + + // check the return value + if (retval==RetVal_SimpleSec) // auto list ended due to simple section command + { + // Reparse the token that ended the section at this level, + // so a new simple section will be started at this level. + // This is the same as unputting the last read token and continuing. + g_token->name = g_token->simpleSectName; + if (g_token->name.left(4)=="rcs:") // RCS section + { + g_token->name = g_token->name.mid(4); + g_token->text = g_token->simpleSectText; + tok = TK_RCSTAG; + } + else // other section + { + tok = TK_COMMAND; + } + DBG(("reparsing command %s\n",qPrint(g_token->name))); + goto reparsetoken; + } + else if (retval==TK_ENDLIST) + { + if (al->indent()>g_token->indent) // end list + { + goto endparagraph; + } + else // continue with current paragraph + { + } + } + else // paragraph ended due to TK_NEWPARA, TK_LISTITEM, or EOF + { + goto endparagraph; + } + } + break; + case TK_ENDLIST: + DBG(("Found end of list inside of paragraph at line %d\n",doctokenizerYYlineno)); + if (parent()->kind()==DocNode::Kind_AutoListItem) + { + ASSERT(parent()->parent()->kind()==DocNode::Kind_AutoList); + DocAutoList *al = (DocAutoList *)parent()->parent(); + if (al->indent()>=g_token->indent) + { + // end of list marker ends this paragraph + retval=TK_ENDLIST; + goto endparagraph; + } + else + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: End of list marker found " + "has invalid indent level"); + } + } + else + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: End of list marker found without any preceding " + "list items"); + } + break; + case TK_COMMAND: + { + // see if we have to start a simple section + int cmd = Mappers::cmdMapper->map(g_token->name); + DocNode *n=parent(); + while (n && + n->kind()!=DocNode::Kind_SimpleSect && + n->kind()!=DocNode::Kind_ParamSect + ) + { + n=n->parent(); + } + if (cmd&SIMPLESECT_BIT) + { + if (n) // already in a simple section + { + // simple section cannot start in this paragraph, need + // to unwind the stack and remember the command. + g_token->simpleSectName = g_token->name.copy(); + retval=RetVal_SimpleSec; + goto endparagraph; + } + } + // see if we are in a simple list + n=parent(); + while (n && n->kind()!=DocNode::Kind_SimpleListItem) n=n->parent(); + if (n) + { + if (cmd==CMD_LI) + { + retval=RetVal_ListItem; + goto endparagraph; + } + } + + // handle the command + retval=handleCommand(g_token->name.copy()); + DBG(("handleCommand returns %x\n",retval)); + + // check the return value + if (retval==RetVal_SimpleSec) + { + // Reparse the token that ended the section at this level, + // so a new simple section will be started at this level. + // This is the same as unputting the last read token and continuing. + g_token->name = g_token->simpleSectName; + if (g_token->name.left(4)=="rcs:") // RCS section + { + g_token->name = g_token->name.mid(4); + g_token->text = g_token->simpleSectText; + tok = TK_RCSTAG; + } + else // other section + { + tok = TK_COMMAND; + } + DBG(("reparsing command %s\n",qPrint(g_token->name))); + goto reparsetoken; + } + else if (retval==RetVal_OK) + { + // the command ended normally, keep scanning for new tokens. + retval = 0; + } + else if (retval>0 && retval<RetVal_OK) + { + // the command ended with a new command, reparse this token + tok = retval; + goto reparsetoken; + } + else // end of file, end of paragraph, start or end of section + // or some auto list marker + { + goto endparagraph; + } + } + break; + case TK_HTMLTAG: + { + if (!g_token->endTag) // found a start tag + { + retval = handleHtmlStartTag(g_token->name,g_token->attribs); + } + else // found an end tag + { + retval = handleHtmlEndTag(g_token->name); + } + if (retval==RetVal_OK) + { + // the command ended normally, keep scanner for new tokens. + retval = 0; + } + else + { + goto endparagraph; + } + } + break; + case TK_SYMBOL: + { + char letter='\0'; + DocSymbol::SymType s = DocSymbol::decodeSymbol(g_token->name,&letter); + if (s!=DocSymbol::Unknown) + { + m_children.append(new DocSymbol(this,s,letter)); + } + else + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unsupported symbol %s found", + qPrint(g_token->name)); + } + break; + } + case TK_NEWPARA: + retval=TK_NEWPARA; + goto endparagraph; + case TK_RCSTAG: + { + DocNode *n=parent(); + while (n && + n->kind()!=DocNode::Kind_SimpleSect && + n->kind()!=DocNode::Kind_ParamSect + ) + { + n=n->parent(); + } + if (n) // already in a simple section + { + // simple section cannot start in this paragraph, need + // to unwind the stack and remember the command. + g_token->simpleSectName = "rcs:"+g_token->name; + g_token->simpleSectText = g_token->text; + retval=RetVal_SimpleSec; + goto endparagraph; + } + + // see if we are in a simple list + DocSimpleSect *ss=new DocSimpleSect(this,DocSimpleSect::Rcs); + m_children.append(ss); + ss->parseRcs(); + } + break; + default: + warn_doc_error(g_fileName,doctokenizerYYlineno, + "warning: Found unexpected token (id=%x)\n",tok); + break; + } + } + retval=0; +endparagraph: + handlePendingStyleCommands(this,m_children); + DocNode *n = g_nodeStack.pop(); + ASSERT(n==this); + DBG(("DocPara::parse() end retval=%x\n",retval)); + INTERNAL_ASSERT(retval==0 || retval==TK_NEWPARA || retval==TK_LISTITEM || + retval==TK_ENDLIST || retval>RetVal_OK + ); + + return retval; +} + +//-------------------------------------------------------------------------- + +int DocSection::parse() +{ + DBG(("DocSection::parse() start %s level=%d\n",qPrint(g_token->sectionId),m_level)); + int retval=RetVal_OK; + g_nodeStack.push(this); + + SectionInfo *sec; + if (!m_id.isEmpty()) + { + sec=Doxygen::sectionDict[m_id]; + if (sec) + { + m_file = sec->fileName; + m_anchor = sec->label; + m_title = sec->title; + if (m_title.isEmpty()) m_title = sec->label; + if (g_sectionDict && g_sectionDict->find(m_id)==0) + { + g_sectionDict->append(m_id,sec); + } + } + } + + // first parse any number of paragraphs + bool isFirst=TRUE; + DocPara *lastPar=0; + do + { + DocPara *par = new DocPara(this); + if (isFirst) { par->markFirst(); isFirst=FALSE; } + retval=par->parse(); + if (!par->isEmpty()) + { + m_children.append(par); + lastPar=par; + } + else + { + delete par; + } + if (retval==TK_LISTITEM) + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Invalid list item found"); + } + } while (retval!=0 && + retval!=RetVal_Internal && + retval!=RetVal_Section && + retval!=RetVal_Subsection && + retval!=RetVal_Subsubsection && + retval!=RetVal_Paragraph + ); + + if (lastPar) lastPar->markLast(); + + //printf("m_level=%d <-> %d\n",m_level,Doxygen::subpageNestingLevel); + + if (retval==RetVal_Subsection && m_level==Doxygen::subpageNestingLevel+1) + { + // then parse any number of nested sections + while (retval==RetVal_Subsection) // more sections follow + { + //SectionInfo *sec=Doxygen::sectionDict[g_token->sectionId]; + DocSection *s=new DocSection(this, + QMIN(2+Doxygen::subpageNestingLevel,5),g_token->sectionId); + m_children.append(s); + retval = s->parse(); + } + } + else if (retval==RetVal_Subsubsection && m_level==Doxygen::subpageNestingLevel+2) + { + // then parse any number of nested sections + while (retval==RetVal_Subsubsection) // more sections follow + { + //SectionInfo *sec=Doxygen::sectionDict[g_token->sectionId]; + DocSection *s=new DocSection(this, + QMIN(3+Doxygen::subpageNestingLevel,5),g_token->sectionId); + m_children.append(s); + retval = s->parse(); + } + } + else if (retval==RetVal_Paragraph && m_level==QMIN(5,Doxygen::subpageNestingLevel+3)) + { + // then parse any number of nested sections + while (retval==RetVal_Paragraph) // more sections follow + { + //SectionInfo *sec=Doxygen::sectionDict[g_token->sectionId]; + DocSection *s=new DocSection(this, + QMIN(4+Doxygen::subpageNestingLevel,5),g_token->sectionId); + m_children.append(s); + retval = s->parse(); + } + } + else if ((m_level<=1+Doxygen::subpageNestingLevel && retval==RetVal_Subsubsection) || + (m_level<=2+Doxygen::subpageNestingLevel && retval==RetVal_Paragraph) + ) + { + int level; + if (retval==RetVal_Subsection) level=2; + else if (retval==RetVal_Subsubsection) level=3; + else level=4; + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected %s " + "command found inside %s!", + sectionLevelToName[level],sectionLevelToName[m_level]); + retval=0; // stop parsing + + } + else if (retval==RetVal_Internal) + { + DocInternal *in = new DocInternal(this); + m_children.append(in); + retval = in->parse(m_level+1); + } + else + { + } + + INTERNAL_ASSERT(retval==0 || + retval==RetVal_Section || + retval==RetVal_Subsection || + retval==RetVal_Subsubsection || + retval==RetVal_Paragraph || + retval==RetVal_Internal + ); + + DBG(("DocSection::parse() end\n")); + DocNode *n = g_nodeStack.pop(); + ASSERT(n==this); + return retval; +} + +//-------------------------------------------------------------------------- + +void DocText::parse() +{ + DBG(("DocText::parse() start\n")); + g_nodeStack.push(this); + doctokenizerYYsetStateText(); + + int tok; + while ((tok=doctokenizerYYlex())) // get the next token + { + switch(tok) + { + case TK_WORD: + m_children.append(new DocWord(this,g_token->name)); + break; + case TK_WHITESPACE: + m_children.append(new DocWhiteSpace(this,g_token->chars)); + break; + case TK_SYMBOL: + { + char letter='\0'; + DocSymbol::SymType s = DocSymbol::decodeSymbol(g_token->name,&letter); + if (s!=DocSymbol::Unknown) + { + m_children.append(new DocSymbol(this,s,letter)); + } + else + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unsupported symbol %s found", + qPrint(g_token->name)); + } + } + break; + case TK_COMMAND: + switch (Mappers::cmdMapper->map(g_token->name)) + { + case CMD_BSLASH: + m_children.append(new DocSymbol(this,DocSymbol::BSlash)); + break; + case CMD_AT: + m_children.append(new DocSymbol(this,DocSymbol::At)); + break; + case CMD_LESS: + m_children.append(new DocSymbol(this,DocSymbol::Less)); + break; + case CMD_GREATER: + m_children.append(new DocSymbol(this,DocSymbol::Greater)); + break; + case CMD_AMP: + m_children.append(new DocSymbol(this,DocSymbol::Amp)); + break; + case CMD_DOLLAR: + m_children.append(new DocSymbol(this,DocSymbol::Dollar)); + break; + case CMD_HASH: + m_children.append(new DocSymbol(this,DocSymbol::Hash)); + break; + case CMD_DCOLON: + m_children.append(new DocSymbol(this,DocSymbol::DoubleColon)); + break; + case CMD_PERCENT: + m_children.append(new DocSymbol(this,DocSymbol::Percent)); + break; + case CMD_QUOTE: + m_children.append(new DocSymbol(this,DocSymbol::Quot)); + break; + default: + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected command `%s' found", + qPrint(g_token->name)); + break; + } + break; + default: + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected token %s", + tokToString(tok)); + break; + } + } + + handleUnclosedStyleCommands(); + + DocNode *n = g_nodeStack.pop(); + ASSERT(n==this); + DBG(("DocText::parse() end\n")); +} + + +//-------------------------------------------------------------------------- + +void DocRoot::parse() +{ + DBG(("DocRoot::parse() start\n")); + g_nodeStack.push(this); + doctokenizerYYsetStatePara(); + int retval=0; + + // first parse any number of paragraphs + bool isFirst=TRUE; + DocPara *lastPar=0; + do + { + DocPara *par = new DocPara(this); + if (isFirst) { par->markFirst(); isFirst=FALSE; } + retval=par->parse(); + if (!par->isEmpty()) + { + m_children.append(par); + lastPar=par; + } + else + { + delete par; + } + if (retval==TK_LISTITEM) + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Invalid list item found"); + } + else if (retval==RetVal_Subsection) + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: found subsection command outside of section context!"); + } + else if (retval==RetVal_Subsubsection) + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: found subsubsection command outside of subsection context!"); + } + else if (retval==RetVal_Paragraph) + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: found paragraph command outside of subsubsection context!"); + } + } while (retval!=0 && retval!=RetVal_Section && retval!=RetVal_Internal); + if (lastPar) lastPar->markLast(); + + //printf("DocRoot::parse() retval=%d %d\n",retval,RetVal_Section); + // then parse any number of level1 sections + while (retval==RetVal_Section) + { + SectionInfo *sec=Doxygen::sectionDict[g_token->sectionId]; + if (sec) + { + DocSection *s=new DocSection(this, + QMIN(1+Doxygen::subpageNestingLevel,5),g_token->sectionId); + m_children.append(s); + retval = s->parse(); + } + else + { + warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Invalid section id `%s'; ignoring section",qPrint(g_token->sectionId)); + retval = 0; + } + } + + if (retval==RetVal_Internal) + { + DocInternal *in = new DocInternal(this); + m_children.append(in); + retval = in->parse(1); + } + + + handleUnclosedStyleCommands(); + + DocNode *n = g_nodeStack.pop(); + ASSERT(n==this); + DBG(("DocRoot::parse() end\n")); +} + +//-------------------------------------------------------------------------- + +DocNode *validatingParseDoc(const char *fileName,int startLine, + Definition *ctx,MemberDef *md, + const char *input,bool indexWords, + bool isExample, const char *exampleName, + bool singleLine, bool linkFromIndex) +{ + //printf("validatingParseDoc(%s,%s)=[%s]\n",ctx?ctx->name().data():"<none>", + // md?md->name().data():"<none>", + // input); + //printf("========== validating %s at line %d\n",fileName,startLine); + //printf("---------------- input --------------------\n%s\n----------- end input -------------------\n",input); + //g_token = new TokenInfo; + + // store parser state so we can re-enter this function if needed + //bool fortranOpt = Config_getBool("OPTIMIZE_FOR_FORTRAN"); + docParserPushContext(); + + if (ctx && ctx!=Doxygen::globalScope && + (ctx->definitionType()==Definition::TypeClass || + ctx->definitionType()==Definition::TypeNamespace + ) + ) + { + g_context = ctx->name(); + } + else if (ctx && ctx->definitionType()==Definition::TypePage) + { + Definition *scope = ((PageDef*)ctx)->getPageScope(); + if (scope && scope!=Doxygen::globalScope) g_context = scope->name(); + } + else if (ctx && ctx->definitionType()==Definition::TypeGroup) + { + Definition *scope = ((GroupDef*)ctx)->getGroupScope(); + if (scope && scope!=Doxygen::globalScope) g_context = scope->name(); + } + else + { + g_context = ""; + } + g_scope = ctx; + + if (indexWords && md && Doxygen::searchIndex) + { + g_searchUrl=md->getOutputFileBase(); + Doxygen::searchIndex->setCurrentDoc( + (md->getLanguage()==SrcLangExt_Fortran ? + theTranslator->trSubprogram(TRUE,TRUE): + theTranslator->trMember(TRUE,TRUE))+" "+md->qualifiedName(), + g_searchUrl, + md->anchor()); + } + else if (indexWords && ctx && Doxygen::searchIndex) + { + g_searchUrl=ctx->getOutputFileBase(); + QCString name = ctx->qualifiedName(); + + SrcLangExt lang = ctx->getLanguage(); + QCString sep = getLanguageSpecificSeparator(lang); + if (sep!="::") + { + name = substitute(name,"::",sep); + } + + switch (ctx->definitionType()) + { + case Definition::TypePage: + { + PageDef *pd = (PageDef *)ctx; + if (!pd->title().isEmpty()) + { + name = theTranslator->trPage(TRUE,TRUE)+" "+pd->title(); + } + else + { + name = theTranslator->trPage(TRUE,TRUE)+" "+pd->name(); + } + } + break; + case Definition::TypeClass: + { + ClassDef *cd = (ClassDef *)ctx; + name.prepend(cd->compoundTypeString()+" "); + } + break; + case Definition::TypeNamespace: + { + if (lang==SrcLangExt_Java || lang==SrcLangExt_CSharp) + { + name = theTranslator->trPackage(name); + } + else if (lang==SrcLangExt_Fortran) + { + name.prepend(theTranslator->trModule(TRUE,TRUE)+" "); + } + else + { + name.prepend(theTranslator->trNamespace(TRUE,TRUE)+" "); + } + } + break; + case Definition::TypeGroup: + { + GroupDef *gd = (GroupDef *)ctx; + if (gd->groupTitle()) + { + name = theTranslator->trGroup(TRUE,TRUE)+" "+gd->groupTitle(); + } + else + { + name.prepend(theTranslator->trGroup(TRUE,TRUE)+" "); + } + } + break; + default: + break; + } + Doxygen::searchIndex->setCurrentDoc(name,g_searchUrl); + } + else + { + g_searchUrl=""; + } + + g_fileName = fileName; + g_relPath = (!linkFromIndex && ctx) ? + QCString(relativePathToRoot(ctx->getOutputFileBase())) : + QCString(""); + //printf("ctx->name=%s relPath=%s\n",ctx->name().data(),g_relPath.data()); + g_memberDef = md; + g_nodeStack.clear(); + g_styleStack.clear(); + g_initialStyleStack.clear(); + g_inSeeBlock = FALSE; + g_insideHtmlLink = FALSE; + g_includeFileText = ""; + g_includeFileOffset = 0; + g_includeFileLength = 0; + g_isExample = isExample; + g_exampleName = exampleName; + g_hasParamCommand = FALSE; + g_hasReturnCommand = FALSE; + g_paramsFound.setAutoDelete(FALSE); + g_paramsFound.clear(); + g_sectionDict = 0; //sections; + + //printf("Starting comment block at %s:%d\n",g_fileName.data(),startLine); + doctokenizerYYlineno=startLine; + doctokenizerYYinit(input,g_fileName); + + + // build abstract syntax tree + DocRoot *root = new DocRoot(md!=0,singleLine); + root->parse(); + + + if (Debug::isFlagSet(Debug::PrintTree)) + { + // pretty print the result + PrintDocVisitor *v = new PrintDocVisitor; + root->accept(v); + delete v; + } + + checkUndocumentedParams(); + detectNoDocumentedParams(); + + // TODO: These should be called at the end of the program. + //doctokenizerYYcleanup(); + //Mappers::cmdMapper->freeInstance(); + //Mappers::htmlTagMapper->freeInstance(); + + // restore original parser state + docParserPopContext(); + + //printf(">>>>>> end validatingParseDoc(%s,%s)\n",ctx?ctx->name().data():"<none>", + // md?md->name().data():"<none>"); + + return root; +} + +DocNode *validatingParseText(const char *input) +{ + // store parser state so we can re-enter this function if needed + docParserPushContext(); + + //printf("------------ input ---------\n%s\n" + // "------------ end input -----\n",input); + //g_token = new TokenInfo; + g_context = ""; + g_fileName = "<parseText>"; + g_relPath = ""; + g_memberDef = 0; + g_nodeStack.clear(); + g_styleStack.clear(); + g_initialStyleStack.clear(); + g_inSeeBlock = FALSE; + g_insideHtmlLink = FALSE; + g_includeFileText = ""; + g_includeFileOffset = 0; + g_includeFileLength = 0; + g_isExample = FALSE; + g_exampleName = ""; + g_hasParamCommand = FALSE; + g_hasReturnCommand = FALSE; + g_paramsFound.setAutoDelete(FALSE); + g_paramsFound.clear(); + g_searchUrl=""; + + DocText *txt = new DocText; + + if (input) + { + doctokenizerYYlineno=1; + doctokenizerYYinit(input,g_fileName); + + // build abstract syntax tree + txt->parse(); + + if (Debug::isFlagSet(Debug::PrintTree)) + { + // pretty print the result + PrintDocVisitor *v = new PrintDocVisitor; + txt->accept(v); + delete v; + } + } + + // restore original parser state + docParserPopContext(); + return txt; +} + +void docFindSections(const char *input, + Definition *d, + MemberGroup *mg, + const char *fileName) +{ + doctokenizerYYFindSections(input,d,mg,fileName); +} + +void initDocParser() +{ + static bool searchEngine = Config_getBool("SEARCHENGINE"); + static bool serverBasedSearch = Config_getBool("SERVER_BASED_SEARCH"); + if (searchEngine && serverBasedSearch) + { + Doxygen::searchIndex = new SearchIndex; + } + else // no search engine or pure javascript based search function + { + Doxygen::searchIndex = 0; + } +} + +void finializeDocParser() +{ + delete Doxygen::searchIndex; +} + diff --git a/trunk/src/docparser.h b/trunk/src/docparser.h new file mode 100644 index 0000000..8e2fae2 --- /dev/null +++ b/trunk/src/docparser.h @@ -0,0 +1,1284 @@ +/****************************************************************************** + * + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#ifndef _DOCPARSER_H +#define _DOCPARSER_H + +#include <stdio.h> + +#include <qlist.h> +#include <qcstring.h> + +#include "docvisitor.h" +#include "htmlattrib.h" + +class DocNode; +class MemberDef; +class Definition; +class MemberGroup; +class SectionDict; + +//--------------------------------------------------------------------------- + +/*! Initialize the documentation parser */ +void initDocParser(); +/*! Cleanup the documentation parser */ +void finializeDocParser(); + +/*! Main entry point for the documentation parser. + * @param fileName File in which the documentation block is found (or the + * name of the example file in case isExample is TRUE). + * @param startLine Line at which the documentation block is found. + * @param context Class or namespace to which this block belongs. + * @param md Member definition to which the documentation belongs. + * Can be 0. + * @param input String representation of the documentation block. + * @param indexWords Indicates whether or not words should be put in the + * search index. + * @param isExample TRUE if the documentation belongs to an example. + * @param exampleName Base name of the example file (0 if isExample is FALSE). + * @param singleLine Output should be presented on a single line, so without + * starting a new paragraph at the end. + * @param linkFromIndex TRUE if the documentation is generated from an + * index page. In this case context is not used to determine + * the relative path when making a link. + * @returns Root node of the abstract syntax tree. Ownership of the + * pointer is handed over to the caller. + */ +DocNode *validatingParseDoc(const char *fileName,int startLine, + Definition *context, MemberDef *md, + const char *input,bool indexWords, + bool isExample,const char *exampleName=0, + bool singleLine=FALSE,bool linkFromIndex=FALSE); + +/*! Main entry point for parsing simple text fragments. These + * fragments are limited to words, whitespace and symbols. + */ +DocNode *validatingParseText(const char *input); + +/*! Searches for section and anchor commands in the input */ +void docFindSections(const char *input, + Definition *d, + MemberGroup *m, + const char *fileName); + +//--------------------------------------------------------------------------- + +/*! @brief Abstract node interface with type information. */ +class DocNode +{ + public: + /*! Available node types. */ + enum Kind { Kind_Root = 0, + Kind_Word = 1, + Kind_WhiteSpace = 2, + Kind_Para = 3, + Kind_AutoList = 4, + Kind_AutoListItem = 5, + Kind_Symbol = 6, + Kind_URL = 7, + Kind_StyleChange = 8, + Kind_SimpleSect = 9, + Kind_Title = 10, + Kind_SimpleList = 11, + Kind_SimpleListItem = 12, + Kind_Section = 13, + Kind_Verbatim = 14, + Kind_XRefItem = 15, + Kind_HtmlList = 16, + Kind_HtmlListItem = 17, + Kind_HtmlDescList = 18, + Kind_HtmlDescData = 19, + Kind_HtmlDescTitle = 20, + Kind_HtmlTable = 21, + Kind_HtmlRow = 22, + Kind_HtmlCell = 23, + Kind_HtmlCaption = 24, + Kind_LineBreak = 25, + Kind_HorRuler = 26, + Kind_Anchor = 27, + Kind_IndexEntry = 28, + Kind_Internal = 29, + Kind_HRef = 30, + Kind_Include = 31, + Kind_IncOperator = 32, + Kind_HtmlHeader = 33, + Kind_Image = 34, + Kind_DotFile = 35, + Kind_Link = 36, + Kind_Ref = 37, + Kind_Formula = 38, + Kind_SecRefItem = 39, + Kind_SecRefList = 40, + Kind_SimpleSectSep = 41, + Kind_LinkedWord = 42, + Kind_ParamSect = 43, + Kind_ParamList = 44, + Kind_InternalRef = 45, + Kind_Copy = 46, + Kind_Text = 47, + Kind_MscFile = 48, + Kind_HtmlBlockQuote = 49 + }; + /*! Creates a new node */ + DocNode() : m_parent(0), m_insidePre(FALSE) {} + + /*! Destroys a node. */ + virtual ~DocNode() {} + + /*! Returns the kind of node. Provides runtime type information */ + virtual Kind kind() const = 0; + + /*! Returns the parent of this node or 0 for the root node. */ + DocNode *parent() const { return m_parent; } + + /*! Sets a new parent for this node. */ + void setParent(DocNode *parent) { m_parent = parent; } + + /*! Acceptor function for node visitors. Part of the visitor pattern. + * @param v Abstract visitor. + */ + virtual void accept(DocVisitor *v) = 0; + + /*! Returns TRUE iff this node is inside a preformatted section */ + bool isPreformatted() const { return m_insidePre; } + + protected: + /*! Sets whether or not this item is inside a preformatted section */ + void setInsidePreformatted(bool p) { m_insidePre = p; } + DocNode *m_parent; + private: + + bool m_insidePre; +}; + +/*! @brief Default accept implementation for compound nodes in the abstract + * syntax tree. + */ +template<class T> class CompAccept +{ + public: + CompAccept() { m_children.setAutoDelete(TRUE); } + virtual ~CompAccept() {} + void accept(T *obj, DocVisitor *v) + { + v->visitPre(obj); + QListIterator<DocNode> cli(m_children); + DocNode *n; + for (cli.toFirst();(n=cli.current());++cli) n->accept(v); + v->visitPost(obj); + } + const QList<DocNode> &children() const { return m_children; } + QList<DocNode> &children() { return m_children; } + + protected: + QList<DocNode> m_children; +}; + + +/*! @brief Node representing a word + */ +class DocWord : public DocNode +{ + public: + DocWord(DocNode *parent,const QCString &word); + QCString word() const { return m_word; } + Kind kind() const { return Kind_Word; } + void accept(DocVisitor *v) { v->visit(this); } + + private: + QCString m_word; +}; + +/*! @brief Node representing a word that can be linked to something + */ +class DocLinkedWord : public DocNode +{ + public: + DocLinkedWord(DocNode *parent,const QCString &word, + const QCString &ref,const QCString &file, + const QCString &anchor,const QCString &tooltip); + QCString word() const { return m_word; } + Kind kind() const { return Kind_LinkedWord; } + QCString file() const { return m_file; } + QCString relPath() const { return m_relPath; } + QCString ref() const { return m_ref; } + QCString anchor() const { return m_anchor; } + QCString tooltip() const { return m_tooltip; } + void accept(DocVisitor *v) { v->visit(this); } + + private: + QCString m_word; + QCString m_ref; + QCString m_file; + QCString m_relPath; + QCString m_anchor; + QCString m_tooltip; +}; + +/*! @brief Node representing an URL (or email address) */ +class DocURL : public DocNode +{ + public: + DocURL(DocNode *parent,const QCString &url,bool isEmail) : + m_url(url), m_isEmail(isEmail) { m_parent=parent; } + QCString url() const { return m_url; } + Kind kind() const { return Kind_URL; } + void accept(DocVisitor *v) { v->visit(this); } + bool isEmail() const { return m_isEmail; } + + private: + QCString m_url; + bool m_isEmail; +}; + +/*! @brief Node representing a line break */ +class DocLineBreak : public DocNode +{ + public: + DocLineBreak(DocNode *parent) { m_parent=parent; } + Kind kind() const { return Kind_LineBreak; } + void accept(DocVisitor *v) { v->visit(this); } + + private: +}; + +/*! @brief Node representing a horizonal ruler */ +class DocHorRuler : public DocNode +{ + public: + DocHorRuler(DocNode *parent) { m_parent = parent; } + Kind kind() const { return Kind_HorRuler; } + void accept(DocVisitor *v) { v->visit(this); } + + private: +}; + +/*! @brief Node representing an anchor */ +class DocAnchor : public DocNode +{ + public: + DocAnchor(DocNode *parent,const QCString &id,bool newAnchor); + Kind kind() const { return Kind_Anchor; } + QCString anchor() const { return m_anchor; } + QCString file() const { return m_file; } + void accept(DocVisitor *v) { v->visit(this); } + + private: + QCString m_anchor; + QCString m_file; +}; + +/*! @brief Node representing a citation of some bibliographic reference */ +class DocCite : public DocNode +{ + public: + DocCite(DocNode *parent,const QCString &target,const QCString &context); + Kind kind() const { return Kind_Ref; } + QCString file() const { return m_file; } + QCString relPath() const { return m_relPath; } + QCString ref() const { return m_ref; } + QCString anchor() const { return m_anchor; } + QCString text() const { return m_text; } + void accept(DocVisitor *v) { v->visit(this); } + + private: + QCString m_file; + QCString m_relPath; + QCString m_ref; + QCString m_anchor; + QCString m_text; +}; + + +/*! @brief Node representing a style change */ +class DocStyleChange : public DocNode +{ + public: + enum Style { Bold, Italic, Code, Center, Small, + Subscript, Superscript, Preformatted, + Span, Div + }; + DocStyleChange(DocNode *parent,uint position,Style s,bool enable, + const HtmlAttribList *attribs=0) : + m_position(position), m_style(s), m_enable(enable) + { m_parent = parent; if (attribs) m_attribs=*attribs; } + Kind kind() const { return Kind_StyleChange; } + Style style() const { return m_style; } + const char *styleString() const; + bool enable() const { return m_enable; } + uint position() const { return m_position; } + void accept(DocVisitor *v) { v->visit(this); } + const HtmlAttribList &attribs() const { return m_attribs; } + + private: + uint m_position; + Style m_style; + bool m_enable; + HtmlAttribList m_attribs; +}; + +/*! @brief Node representing a special symbol */ +class DocSymbol : public DocNode +{ + public: + enum SymType { Unknown=0, BSlash, At, Less, Greater, Amp, Dollar, Hash, + DoubleColon, Percent, Copy, Tm, Reg, Apos, Quot, Uml, Acute, + Grave, Circ, Tilde, Szlig, Cedil, Ring, Nbsp, Slash, + Lsquo, Rsquo, Ldquo, Rdquo, Ndash, Mdash, Aelig, AElig + }; + DocSymbol(DocNode *parent,SymType s,char letter='\0') : + m_symbol(s), m_letter(letter) { m_parent = parent; } + SymType symbol() const { return m_symbol; } + char letter() const { return m_letter; } + Kind kind() const { return Kind_Symbol; } + void accept(DocVisitor *v) { v->visit(this); } + static SymType decodeSymbol(const QCString &symName,char *letter); + + private: + SymType m_symbol; + char m_letter; +}; + +/*! @brief Node representing some amount of white space */ +class DocWhiteSpace : public DocNode +{ + public: + DocWhiteSpace(DocNode *parent,const QCString &chars) : + m_chars(chars) { m_parent = parent; } + Kind kind() const { return Kind_WhiteSpace; } + QCString chars() const { return m_chars; } + void accept(DocVisitor *v) { v->visit(this); } + private: + QCString m_chars; +}; + +/*! @brief Node representing a verbatim, unparsed text fragment */ +class DocVerbatim : public DocNode +{ + public: + enum Type { Code, HtmlOnly, ManOnly, LatexOnly, XmlOnly, Verbatim, Dot, Msc }; + DocVerbatim(DocNode *parent,const QCString &context, + const QCString &text, Type t,bool isExample, + const QCString &exampleFile,const QCString &lang=QCString()); + Kind kind() const { return Kind_Verbatim; } + Type type() const { return m_type; } + QCString text() const { return m_text; } + QCString context() const { return m_context; } + void accept(DocVisitor *v) { v->visit(this); } + bool isExample() const { return m_isExample; } + QCString exampleFile() const { return m_exampleFile; } + QCString relPath() const { return m_relPath; } + QCString language() const { return m_lang; } + + private: + QCString m_context; + QCString m_text; + Type m_type; + bool m_isExample; + QCString m_exampleFile; + QCString m_relPath; + QCString m_lang; +}; + + +/*! @brief Node representing an included text block from file */ +class DocInclude : public DocNode +{ + public: + enum Type { Include, DontInclude, VerbInclude, HtmlInclude, IncWithLines, Snippet }; + DocInclude(DocNode *parent,const QCString &file, + const QCString context, Type t, + bool isExample,const QCString exampleFile, + const QCString blockId) : + m_file(file), m_context(context), m_type(t), + m_isExample(isExample), m_exampleFile(exampleFile), + m_blockId(blockId) { m_parent = parent; } + Kind kind() const { return Kind_Include; } + QCString file() const { return m_file; } + QCString extension() const { int i=m_file.findRev('.'); + if (i!=-1) + return m_file.right(m_file.length()-i); + else + return ""; + } + Type type() const { return m_type; } + QCString text() const { return m_text; } + QCString context() const { return m_context; } + QCString blockId() const { return m_blockId; } + bool isExample() const { return m_isExample; } + QCString exampleFile() const { return m_exampleFile; } + void accept(DocVisitor *v) { v->visit(this); } + void parse(); + + private: + QCString m_file; + QCString m_context; + QCString m_text; + Type m_type; + bool m_isExample; + QCString m_exampleFile; + QCString m_blockId; +}; + +/*! @brief Node representing a include/dontinclude operator block */ +class DocIncOperator : public DocNode +{ + public: + enum Type { Line, SkipLine, Skip, Until }; + DocIncOperator(DocNode *parent,Type t,const QCString &pat, + const QCString &context,bool isExample,const QCString &exampleFile) : + m_type(t), m_pattern(pat), m_context(context), + m_isFirst(FALSE), m_isLast(FALSE), + m_isExample(isExample), m_exampleFile(exampleFile) { m_parent = parent; } + Kind kind() const { return Kind_IncOperator; } + Type type() const { return m_type; } + QCString text() const { return m_text; } + QCString pattern() const { return m_pattern; } + QCString context() const { return m_context; } + void accept(DocVisitor *v) { v->visit(this); } + bool isFirst() const { return m_isFirst; } + bool isLast() const { return m_isLast; } + void markFirst(bool v=TRUE) { m_isFirst = v; } + void markLast(bool v=TRUE) { m_isLast = v; } + bool isExample() const { return m_isExample; } + QCString exampleFile() const { return m_exampleFile; } + void parse(); + + private: + Type m_type; + QCString m_text; + QCString m_pattern; + QCString m_context; + bool m_isFirst; + bool m_isLast; + bool m_isExample; + QCString m_exampleFile; +}; + +/*! @brief Node representing an item of a cross-referenced list */ +class DocFormula : public DocNode +{ + public: + DocFormula(DocNode *parent,int id); + Kind kind() const { return Kind_Formula; } + QCString name() const { return m_name; } + QCString text() const { return m_text; } + QCString relPath() const { return m_relPath; } + int id() const { return m_id; } + void accept(DocVisitor *v) { v->visit(this); } + bool isInline() { return m_text.length()>0 ? m_text.at(0)!='\\' : TRUE; } + + private: + QCString m_name; + QCString m_text; + QCString m_relPath; + int m_id; +}; + +/*! @brief Node representing an entry in the index. */ +class DocIndexEntry : public DocNode +{ + public: + DocIndexEntry(DocNode *parent,Definition *scope,MemberDef *md) + : m_scope(scope), m_member(md) { m_parent = parent; } + Kind kind() const { return Kind_IndexEntry; } + int parse(); + Definition *scope() const { return m_scope; } + MemberDef *member() const { return m_member; } + QCString entry() const { return m_entry; } + void accept(DocVisitor *v) { v->visit(this); } + + private: + QCString m_entry; + Definition *m_scope; + MemberDef *m_member; +}; + +//----------------------------------------------------------------------- + +/*! @brief Node representing a copy of documentation block. */ +class DocCopy : /*public CompAccept<DocCopy>,*/ public DocNode +{ + public: + DocCopy(DocNode *parent,const QCString &link,bool copyBrief,bool copyDetails) + : m_link(link), + m_copyBrief(copyBrief), m_copyDetails(copyDetails) { m_parent = parent; } + Kind kind() const { return Kind_Copy; } + QCString link() const { return m_link; } + void accept(DocVisitor * /*v*/) { /*CompAccept<DocCopy>::accept(this,v);*/ } + void parse(QList<DocNode> &children); + + private: + QCString m_link; + bool m_copyBrief; + bool m_copyDetails; +}; + +/*! @brief Node representing an auto List */ +class DocAutoList : public CompAccept<DocAutoList>, public DocNode +{ + public: + DocAutoList(DocNode *parent,int indent,bool isEnumList,int depth); + Kind kind() const { return Kind_AutoList; } + bool isEnumList() const { return m_isEnumList; } + int indent() const { return m_indent; } + int depth() const { return m_depth; } + void accept(DocVisitor *v) { CompAccept<DocAutoList>::accept(this,v); } + int parse(); + + private: + int m_indent; + bool m_isEnumList; + int m_depth; +}; + +/*! @brief Node representing an item of a auto list */ +class DocAutoListItem : public CompAccept<DocAutoListItem>, public DocNode +{ + public: + DocAutoListItem(DocNode *parent,int indent,int num); + Kind kind() const { return Kind_AutoListItem; } + int itemNumber() const { return m_itemNum; } + void accept(DocVisitor *v) { CompAccept<DocAutoListItem>::accept(this,v); } + int parse(); + + private: + int m_indent; + int m_itemNum; +}; + + + +/*! @brief Node representing a simple section title */ +class DocTitle : public CompAccept<DocTitle>, public DocNode +{ + public: + DocTitle(DocNode *parent) { m_parent = parent; } + void parse(); + void parseFromString(const QCString &title); + Kind kind() const { return Kind_Title; } + void accept(DocVisitor *v) { CompAccept<DocTitle>::accept(this,v); } + + private: +}; + +/*! @brief Node representing an item of a cross-referenced list */ +class DocXRefItem : public CompAccept<DocXRefItem>, public DocNode +{ + public: + //enum Type { Bug, Test, Todo, Deprecated }; + DocXRefItem(DocNode *parent,int id,const char *key); + Kind kind() const { return Kind_XRefItem; } + QCString file() const { return m_file; } + QCString anchor() const { return m_anchor; } + QCString title() const { return m_title; } + QCString relPath() const { return m_relPath; } + QCString key() const { return m_key; } + void accept(DocVisitor *v) { CompAccept<DocXRefItem>::accept(this,v); } + bool parse(); + + private: + int m_id; + QCString m_key; + QCString m_file; + QCString m_anchor; + QCString m_title; + QCString m_relPath; +}; + +/*! @brief Node representing an image */ +class DocImage : public CompAccept<DocImage>, public DocNode +{ + public: + enum Type { Html, Latex, Rtf }; + DocImage(DocNode *parent,const HtmlAttribList &attribs, + const QCString &name,Type t,const QCString &url=QCString()); + Kind kind() const { return Kind_Image; } + Type type() const { return m_type; } + QCString name() const { return m_name; } + bool hasCaption() const { return !m_children.isEmpty(); } + QCString width() const { return m_width; } + QCString height() const { return m_height; } + QCString relPath() const { return m_relPath; } + QCString url() const { return m_url; } + const HtmlAttribList &attribs() const { return m_attribs; } + void accept(DocVisitor *v) { CompAccept<DocImage>::accept(this,v); } + void parse(); + + private: + HtmlAttribList m_attribs; + QCString m_name; + Type m_type; + QCString m_width; + QCString m_height; + QCString m_relPath; + QCString m_url; +}; + +/*! @brief Node representing a dot file */ +class DocDotFile : public CompAccept<DocDotFile>, public DocNode +{ + public: + DocDotFile(DocNode *parent,const QCString &name,const QCString &context); + void parse(); + Kind kind() const { return Kind_DotFile; } + QCString name() const { return m_name; } + QCString file() const { return m_file; } + QCString relPath() const { return m_relPath; } + bool hasCaption() const { return !m_children.isEmpty(); } + QCString width() const { return m_width; } + QCString height() const { return m_height; } + QCString context() const { return m_context; } + void accept(DocVisitor *v) { CompAccept<DocDotFile>::accept(this,v); } + private: + QCString m_name; + QCString m_file; + QCString m_relPath; + QCString m_width; + QCString m_height; + QCString m_context; +}; + +/*! @brief Node representing a msc file */ +class DocMscFile : public CompAccept<DocMscFile>, public DocNode +{ + public: + DocMscFile(DocNode *parent,const QCString &name,const QCString &context); + void parse(); + Kind kind() const { return Kind_MscFile; } + QCString name() const { return m_name; } + QCString file() const { return m_file; } + QCString relPath() const { return m_relPath; } + bool hasCaption() const { return !m_children.isEmpty(); } + QCString width() const { return m_width; } + QCString height() const { return m_height; } + QCString context() const { return m_context; } + void accept(DocVisitor *v) { CompAccept<DocMscFile>::accept(this,v); } + private: + QCString m_name; + QCString m_file; + QCString m_relPath; + QCString m_width; + QCString m_height; + QCString m_context; +}; + + +/*! @brief Node representing a link to some item */ +class DocLink : public CompAccept<DocLink>, public DocNode +{ + public: + DocLink(DocNode *parent,const QCString &target); + QCString parse(bool,bool isXmlLink=FALSE); + Kind kind() const { return Kind_Link; } + QCString file() const { return m_file; } + QCString relPath() const { return m_relPath; } + QCString ref() const { return m_ref; } + QCString anchor() const { return m_anchor; } + void accept(DocVisitor *v) { CompAccept<DocLink>::accept(this,v); } + + private: + QCString m_file; + QCString m_relPath; + QCString m_ref; + QCString m_anchor; + QCString m_refText; +}; + +/*! @brief Node representing a reference to some item */ +class DocRef : public CompAccept<DocRef>, public DocNode +{ + public: + DocRef(DocNode *parent,const QCString &target,const QCString &context); + void parse(); + Kind kind() const { return Kind_Ref; } + QCString file() const { return m_file; } + QCString relPath() const { return m_relPath; } + QCString ref() const { return m_ref; } + QCString anchor() const { return m_anchor; } + QCString targetTitle() const { return m_text; } + bool hasLinkText() const { return !m_children.isEmpty(); } + bool refToAnchor() const { return m_refToAnchor; } + bool refToSection() const { return m_refToSection; } + bool isSubPage() const { return m_isSubPage; } + void accept(DocVisitor *v) { CompAccept<DocRef>::accept(this,v); } + + private: + bool m_refToSection; + bool m_refToAnchor; + bool m_isSubPage; + QCString m_file; + QCString m_relPath; + QCString m_ref; + QCString m_anchor; + QCString m_text; +}; + +/*! @brief Node representing an internal reference to some item */ +class DocInternalRef : public CompAccept<DocInternalRef>, public DocNode +{ + public: + DocInternalRef(DocNode *parent,const QCString &target); + void parse(); + Kind kind() const { return Kind_Ref; } + QCString file() const { return m_file; } + QCString relPath() const { return m_relPath; } + QCString anchor() const { return m_anchor; } + void accept(DocVisitor *v) { CompAccept<DocInternalRef>::accept(this,v); } + + private: + QCString m_file; + QCString m_relPath; + QCString m_anchor; +}; + +/*! @brief Node representing a Language specific section */ +//class DocLanguage : public CompAccept<DocLanguage>, public DocNode +//{ +// public: +// DocLanguage(DocNode *parent,const QCString &id) : +// m_parent(parent), m_id(id) {} +// QCString id() const { return m_id; } +// Kind kind() const { return Kind_Language; } +// DocNode *parent() const { return m_parent; } +// void accept(DocVisitor *v) { CompAccept<DocLanguage>::accept(this,v); } +// int parse(); +// +// private: +// DocNode * m_parent; +// QCString m_id; +//}; + +/*! @brief Node representing a Hypertext reference */ +class DocHRef : public CompAccept<DocHRef>, public DocNode +{ + public: + DocHRef(DocNode *parent,const HtmlAttribList &attribs,const QCString &url, + const QCString &relPath) : + m_attribs(attribs), m_url(url), m_relPath(relPath) { m_parent = parent; } + int parse(); + QCString url() const { return m_url; } + QCString relPath() const { return m_relPath; } + Kind kind() const { return Kind_HRef; } + void accept(DocVisitor *v) { CompAccept<DocHRef>::accept(this,v); } + const HtmlAttribList &attribs() const { return m_attribs; } + + private: + HtmlAttribList m_attribs; + QCString m_url; + QCString m_relPath; +}; + +/*! @brief Node Html heading */ +class DocHtmlHeader : public CompAccept<DocHtmlHeader>, public DocNode +{ + public: + DocHtmlHeader(DocNode *parent,const HtmlAttribList &attribs,int level) : + m_level(level), m_attribs(attribs) { m_parent = parent; } + int level() const { return m_level; } + Kind kind() const { return Kind_HtmlHeader; } + const HtmlAttribList &attribs() const { return m_attribs; } + void accept(DocVisitor *v) { CompAccept<DocHtmlHeader>::accept(this,v); } + int parse(); + + private: + int m_level; + HtmlAttribList m_attribs; +}; + +/*! @brief Node representing a Html description item */ +class DocHtmlDescTitle : public CompAccept<DocHtmlDescTitle>, public DocNode +{ + public: + DocHtmlDescTitle(DocNode *parent,const HtmlAttribList &attribs) : + m_attribs(attribs) { m_parent = parent; } + Kind kind() const { return Kind_HtmlDescTitle; } + const HtmlAttribList &attribs() const { return m_attribs; } + void accept(DocVisitor *v) { CompAccept<DocHtmlDescTitle>::accept(this,v); } + int parse(); + + private: + HtmlAttribList m_attribs; +}; + +/*! @brief Node representing a Html description list */ +class DocHtmlDescList : public CompAccept<DocHtmlDescList>, public DocNode +{ + public: + DocHtmlDescList(DocNode *parent,const HtmlAttribList &attribs) : + m_attribs(attribs) { m_parent = parent; } + Kind kind() const { return Kind_HtmlDescList; } + const HtmlAttribList &attribs() const { return m_attribs; } + void accept(DocVisitor *v) { CompAccept<DocHtmlDescList>::accept(this,v); } + int parse(); + + private: + HtmlAttribList m_attribs; +}; + +/*! @brief Node representing a normal section */ +class DocSection : public CompAccept<DocSection>, public DocNode +{ + public: + DocSection(DocNode *parent,int level,const QCString &id) : + m_level(level), m_id(id) { m_parent = parent; } + Kind kind() const { return Kind_Section; } + int level() const { return m_level; } + QCString title() const { return m_title; } + QCString anchor() const { return m_anchor; } + QCString id() const { return m_id; } + QCString file() const { return m_file; } + void accept(DocVisitor *v) { CompAccept<DocSection>::accept(this,v); } + int parse(); + + private: + int m_level; + QCString m_id; + QCString m_title; + QCString m_anchor; + QCString m_file; +}; + +/*! @brief Node representing a reference to a section */ +class DocSecRefItem : public CompAccept<DocSecRefItem>, public DocNode +{ + public: + DocSecRefItem(DocNode *parent,const QCString &target) : + m_target(target) { m_parent = parent; } + Kind kind() const { return Kind_SecRefItem; } + QCString target() const { return m_target; } + QCString file() const { return m_file; } + QCString anchor() const { return m_anchor; } + void accept(DocVisitor *v) { CompAccept<DocSecRefItem>::accept(this,v); } + void parse(); + + private: + QCString m_target; + QCString m_file; + QCString m_anchor; +}; + +/*! @brief Node representing a list of section references */ +class DocSecRefList : public CompAccept<DocSecRefList>, public DocNode +{ + public: + DocSecRefList(DocNode *parent) { m_parent = parent; } + void parse(); + Kind kind() const { return Kind_SecRefList; } + void accept(DocVisitor *v) { CompAccept<DocSecRefList>::accept(this,v); } + + private: +}; + +/*! @brief Node representing an internal section of documentation */ +class DocInternal : public CompAccept<DocInternal>, public DocNode +{ + public: + DocInternal(DocNode *parent) { m_parent = parent; } + int parse(int); + Kind kind() const { return Kind_Internal; } + void accept(DocVisitor *v) { CompAccept<DocInternal>::accept(this,v); } + + private: +}; + +/*! @brief Node representing a simple list */ +class DocSimpleList : public CompAccept<DocSimpleList>, public DocNode +{ + public: + DocSimpleList(DocNode *parent) { m_parent = parent; } + Kind kind() const { return Kind_SimpleList; } + void accept(DocVisitor *v) { CompAccept<DocSimpleList>::accept(this,v); } + int parse(); + + private: +}; + +/*! @brief Node representing a Html list */ +class DocHtmlList : public CompAccept<DocHtmlList>, public DocNode +{ + public: + enum Type { Unordered, Ordered }; + DocHtmlList(DocNode *parent,const HtmlAttribList &attribs,Type t) : + m_type(t), m_attribs(attribs) { m_parent = parent; } + Kind kind() const { return Kind_HtmlList; } + Type type() const { return m_type; } + void accept(DocVisitor *v) { CompAccept<DocHtmlList>::accept(this,v); } + const HtmlAttribList &attribs() const { return m_attribs; } + int parse(); + int parseXml(); + + private: + Type m_type; + HtmlAttribList m_attribs; +}; + +/*! Node representing a simple section */ +class DocSimpleSect : public CompAccept<DocSimpleSect>, public DocNode +{ + public: + enum Type + { + Unknown, See, Return, Author, Authors, Version, Since, Date, + Note, Warning, Copyright, Pre, Post, Invar, Remark, Attention, User, Rcs + }; + DocSimpleSect(DocNode *parent,Type t); + virtual ~DocSimpleSect(); + Kind kind() const { return Kind_SimpleSect; } + Type type() const { return m_type; } + QCString typeString() const; + void accept(DocVisitor *v); + int parse(bool userTitle,bool needsSeparator); + int parseRcs(); + int parseXml(); + void appendLinkWord(const QCString &word); + + private: + Type m_type; + DocTitle * m_title; +}; + +/*! Node representing a separator between two simple sections of the + * same type. + */ +class DocSimpleSectSep : public DocNode +{ + public: + DocSimpleSectSep(DocNode *parent) { m_parent = parent; } + Kind kind() const { return Kind_SimpleSectSep; } + void accept(DocVisitor *v) { v->visit(this); } + + private: +}; + +/*! Node representing a parameter section */ +class DocParamSect : public CompAccept<DocParamSect>, public DocNode +{ + friend class DocParamList; + public: + enum Type + { + Unknown, Param, RetVal, Exception, TemplateParam + }; + enum Direction + { + In=1, Out=2, InOut=3, Unspecified=0 + }; + DocParamSect(DocNode *parent,Type t) + : m_type(t), m_dir(Unspecified), + m_hasInOutSpecifier(FALSE), m_hasTypeSpecifier(FALSE) + { m_parent = parent; } + int parse(const QCString &cmdName,bool xmlContext,Direction d); + Kind kind() const { return Kind_ParamSect; } + Type type() const { return m_type; } + void accept(DocVisitor *v) { CompAccept<DocParamSect>::accept(this,v); } + bool hasInOutSpecifier() const { return m_hasInOutSpecifier; } + bool hasTypeSpecifier() const { return m_hasTypeSpecifier; } + + private: + Type m_type; + Direction m_dir; + bool m_hasInOutSpecifier; + bool m_hasTypeSpecifier; +}; + +/*! Node representing a paragraph in the documentation tree */ +class DocPara : public CompAccept<DocPara>, public DocNode +{ + public: + DocPara(DocNode *parent) : + m_isFirst(FALSE), m_isLast(FALSE) { m_parent = parent; } + int parse(); + Kind kind() const { return Kind_Para; } + bool isEmpty() const { return m_children.isEmpty(); } + void accept(DocVisitor *v) { CompAccept<DocPara>::accept(this,v); } + void markFirst(bool v=TRUE) { m_isFirst=v; } + void markLast(bool v=TRUE) { m_isLast=v; } + bool isFirst() const { return m_isFirst; } + bool isLast() const { return m_isLast; } + + int handleCommand(const QCString &cmdName); + int handleHtmlStartTag(const QCString &tagName,const HtmlAttribList &tagHtmlAttribs); + int handleHtmlEndTag(const QCString &tagName); + int handleSimpleSection(DocSimpleSect::Type t,bool xmlContext=FALSE); + int handleXRefItem(); + int handleParamSection(const QCString &cmdName,DocParamSect::Type t, + bool xmlContext, + int direction); + void handleIncludeOperator(const QCString &cmdName,DocIncOperator::Type t); + void handleImage(const QCString &cmdName); + void handleDotFile(const QCString &cmdName); + void handleMscFile(const QCString &cmdName); + void handleInclude(const QCString &cmdName,DocInclude::Type t); + void handleLink(const QCString &cmdName,bool isJavaLink); + void handleCite(); + void handleRef(const QCString &cmdName); + void handleSection(const QCString &cmdName); + void handleInheritDoc(); + int handleStartCode(); + int handleHtmlHeader(const HtmlAttribList &tagHtmlAttribs,int level); + + bool injectToken(int tok,const QCString &tokText); + + private: + QCString m_sectionId; + bool m_isFirst; + bool m_isLast; +}; + +/*! @brief Node representing a parameter list. */ +class DocParamList : public DocNode +{ + public: + DocParamList(DocNode *parent,DocParamSect::Type t,DocParamSect::Direction d) + : m_type(t), m_dir(d), m_isFirst(TRUE), m_isLast(TRUE) + { m_paragraphs.setAutoDelete(TRUE); + m_params.setAutoDelete(TRUE); + m_paramTypes.setAutoDelete(TRUE); + m_parent = parent; + } + virtual ~DocParamList() { } + Kind kind() const { return Kind_ParamList; } + const QList<DocNode> ¶meters() { return m_params; } + const QList<DocNode> ¶mTypes() { return m_paramTypes; } + DocParamSect::Type type() const { return m_type; } + DocParamSect::Direction direction() const { return m_dir; } + void markFirst(bool b=TRUE) { m_isFirst=b; } + void markLast(bool b=TRUE) { m_isLast=b; } + bool isFirst() const { return m_isFirst; } + bool isLast() const { return m_isLast; } + void accept(DocVisitor *v) + { + v->visitPre(this); + QListIterator<DocPara> cli(m_paragraphs); + DocNode *n; + for (cli.toFirst();(n=cli.current());++cli) n->accept(v); + v->visitPost(this); + } + int parse(const QCString &cmdName); + int parseXml(const QCString ¶mName); + + private: + QList<DocPara> m_paragraphs; + QList<DocNode> m_params; + QList<DocNode> m_paramTypes; + DocParamSect::Type m_type; + DocParamSect::Direction m_dir; + bool m_isFirst; + bool m_isLast; +}; + +/*! @brief Node representing a simple list item */ +class DocSimpleListItem : public DocNode +{ + public: + DocSimpleListItem(DocNode *parent) + { m_paragraph=new DocPara(this); m_parent = parent; } + int parse(); + virtual ~DocSimpleListItem() { delete m_paragraph; } + Kind kind() const { return Kind_SimpleListItem; } + void accept(DocVisitor *v) + { + v->visitPre(this); + m_paragraph->accept(v); + v->visitPost(this); + } + + private: + DocPara *m_paragraph; +}; + +/*! @brief Node representing a HTML list item */ +class DocHtmlListItem : public CompAccept<DocHtmlListItem>, public DocNode +{ + public: + DocHtmlListItem(DocNode *parent,const HtmlAttribList &attribs,int num) : + m_attribs(attribs), m_itemNum(num) { m_parent = parent; } + Kind kind() const { return Kind_HtmlListItem; } + int itemNumber() const { return m_itemNum; } + const HtmlAttribList &attribs() const { return m_attribs; } + void accept(DocVisitor *v) { CompAccept<DocHtmlListItem>::accept(this,v); } + int parse(); + int parseXml(); + + private: + HtmlAttribList m_attribs; + int m_itemNum; +}; + +/*! @brief Node representing a HTML description data */ +class DocHtmlDescData : public CompAccept<DocHtmlDescData>, public DocNode +{ + public: + DocHtmlDescData(DocNode *parent) { m_parent = parent; } + Kind kind() const { return Kind_HtmlDescData; } + const HtmlAttribList &attribs() const { return m_attribs; } + void accept(DocVisitor *v) { CompAccept<DocHtmlDescData>::accept(this,v); } + int parse(); + + private: + HtmlAttribList m_attribs; +}; + +/*! @brief Node representing a HTML table cell */ +class DocHtmlCell : public CompAccept<DocHtmlCell>, public DocNode +{ + friend class DocHtmlTable; + public: + enum Alignment { Left, Right, Center }; + DocHtmlCell(DocNode *parent,const HtmlAttribList &attribs,bool isHeading) : + m_isHeading(isHeading), + m_isFirst(FALSE), m_isLast(FALSE), m_attribs(attribs), + m_rowIdx(-1), m_colIdx(-1) { m_parent = parent; } + bool isHeading() const { return m_isHeading; } + bool isFirst() const { return m_isFirst; } + bool isLast() const { return m_isLast; } + Kind kind() const { return Kind_HtmlCell; } + void accept(DocVisitor *v) { CompAccept<DocHtmlCell>::accept(this,v); } + void markFirst(bool v=TRUE) { m_isFirst=v; } + void markLast(bool v=TRUE) { m_isLast=v; } + const HtmlAttribList &attribs() const { return m_attribs; } + int parse(); + int parseXml(); + int rowIndex() const { return m_rowIdx; } + int columnIndex() const { return m_colIdx; } + int rowSpan() const; + int colSpan() const; + Alignment alignment() const; + + private: + void setRowIndex(int idx) { m_rowIdx = idx; } + void setColumnIndex(int idx) { m_colIdx = idx; } + bool m_isHeading; + bool m_isFirst; + bool m_isLast; + HtmlAttribList m_attribs; + int m_rowIdx; + int m_colIdx; +}; + +/*! @brief Node representing a HTML table caption */ +class DocHtmlCaption : public CompAccept<DocHtmlCaption>, public DocNode +{ + public: + DocHtmlCaption(DocNode *parent,const HtmlAttribList &attribs) : + m_attribs(attribs) { m_parent = parent; } + Kind kind() const { return Kind_HtmlCaption; } + void accept(DocVisitor *v) { CompAccept<DocHtmlCaption>::accept(this,v); } + const HtmlAttribList &attribs() const { return m_attribs; } + int parse(); + + private: + HtmlAttribList m_attribs; + bool m_atTop; +}; + +/*! @brief Node representing a HTML table row */ +class DocHtmlRow : public CompAccept<DocHtmlRow>, public DocNode +{ + friend class DocHtmlTable; + public: + DocHtmlRow(DocNode *parent,const HtmlAttribList &attribs) : + m_attribs(attribs), m_visibleCells(-1), m_rowIdx(-1) { m_parent = parent; } + Kind kind() const { return Kind_HtmlRow; } + uint numCells() const { return m_children.count(); } + void accept(DocVisitor *v) { CompAccept<DocHtmlRow>::accept(this,v); } + const HtmlAttribList &attribs() const { return m_attribs; } + int parse(); + int parseXml(bool header); + bool isHeading() const { return m_children.count()>0 && + ((DocHtmlCell*)m_children.getFirst())->isHeading(); + } + void setVisibleCells(int n) { m_visibleCells = n; } + int visibleCells() const { return m_visibleCells; } + int rowIndex() const { return m_rowIdx; } + + private: + void setRowIndex(int idx) { m_rowIdx = idx; } + HtmlAttribList m_attribs; + int m_visibleCells; + int m_rowIdx; +}; + +/*! @brief Node representing a HTML table */ +class DocHtmlTable : public CompAccept<DocHtmlTable>, public DocNode +{ + public: + DocHtmlTable(DocNode *parent,const HtmlAttribList &attribs) + : m_attribs(attribs) { m_caption=0; m_parent = parent; } + ~DocHtmlTable() { delete m_caption; } + Kind kind() const { return Kind_HtmlTable; } + uint numRows() const { return m_children.count(); } + bool hasCaption() { return m_caption!=0; } + const HtmlAttribList &attribs() const { return m_attribs; } + int parse(); + int parseXml(); + uint numColumns() const { return m_numCols; } + void accept(DocVisitor *v); + + private: + void computeTableGrid(); + DocHtmlCaption *m_caption; + HtmlAttribList m_attribs; + int m_numCols; +}; + +/*! @brief Node representing an HTML blockquote */ +class DocHtmlBlockQuote : public CompAccept<DocHtmlBlockQuote>, public DocNode +{ + public: + DocHtmlBlockQuote(DocNode *parent,const HtmlAttribList &attribs) + : m_attribs(attribs) { m_parent = parent; } + Kind kind() const { return Kind_HtmlBlockQuote; } + int parse(); + void accept(DocVisitor *v) { CompAccept<DocHtmlBlockQuote>::accept(this,v); } + const HtmlAttribList &attribs() const { return m_attribs; } + + private: + HtmlAttribList m_attribs; +}; + +/*! @brief Root node of a text fragment */ +class DocText : public CompAccept<DocText>, public DocNode +{ + public: + DocText() {} + Kind kind() const { return Kind_Text; } + void accept(DocVisitor *v) { CompAccept<DocText>::accept(this,v); } + void parse(); +}; + +/*! @brief Root node of documentation tree */ +class DocRoot : public CompAccept<DocRoot>, public DocNode +{ + public: + DocRoot(bool indent,bool sl) : m_indent(indent), m_singleLine(sl) {} + Kind kind() const { return Kind_Root; } + void accept(DocVisitor *v) { CompAccept<DocRoot>::accept(this,v); } + void parse(); + bool indent() const { return m_indent; } + bool singleLine() const { return m_singleLine; } + + private: + bool m_indent; + bool m_singleLine; +}; + + +#endif diff --git a/trunk/src/docsets.cpp b/trunk/src/docsets.cpp new file mode 100644 index 0000000..6852c41 --- /dev/null +++ b/trunk/src/docsets.cpp @@ -0,0 +1,488 @@ +/****************************************************************************** + * + * Copyright (C) 1997-2012 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. + * + */ + +#include "docsets.h" +#include "config.h" +#include "message.h" +#include "doxygen.h" +#include <qfile.h> + + +DocSets::DocSets() : m_nodes(17), m_scopes(17) +{ + m_nf = 0; + m_tf = 0; + m_dc = 0; + m_id = 0; + m_nodes.setAutoDelete(TRUE); +} + +DocSets::~DocSets() +{ + delete m_nf; + delete m_tf; +} + +void DocSets::initialize() +{ + // -- get config options + QCString projectName = Config_getString("PROJECT_NAME"); + if (projectName.isEmpty()) projectName="root"; + QCString bundleId = Config_getString("DOCSET_BUNDLE_ID"); + if (bundleId.isEmpty()) bundleId="org.doxygen.Project"; + QCString feedName = Config_getString("DOCSET_FEEDNAME"); + if (feedName.isEmpty()) feedName="FeedName"; + QCString publisherId = Config_getString("DOCSET_PUBLISHER_ID"); + if (publisherId.isEmpty()) publisherId="PublisherId"; + QCString publisherName = Config_getString("DOCSET_PUBLISHER_NAME"); + if (publisherName.isEmpty()) publisherName="PublisherName"; + + // -- write Makefile + { + QCString mfName = Config_getString("HTML_OUTPUT") + "/Makefile"; + QFile makefile(mfName); + if (!makefile.open(IO_WriteOnly)) + { + err("Could not open file %s for writing\n",mfName.data()); + exit(1); + } + FTextStream ts(&makefile); + + ts << "DOCSET_NAME=" << bundleId << ".docset\n" + "DOCSET_CONTENTS=$(DOCSET_NAME)/Contents\n" + "DOCSET_RESOURCES=$(DOCSET_CONTENTS)/Resources\n" + "DOCSET_DOCUMENTS=$(DOCSET_RESOURCES)/Documents\n" + "DESTDIR=~/Library/Developer/Shared/Documentation/DocSets\n" + "XCODE_INSTALL=$(shell xcode-select -print-path)\n" + "\n" + "all: docset\n" + "\n" + "docset:\n" + "\tmkdir -p $(DOCSET_DOCUMENTS)\n" + "\tcp Nodes.xml $(DOCSET_RESOURCES)\n" + "\tcp Tokens.xml $(DOCSET_RESOURCES)\n" + "\tcp Info.plist $(DOCSET_CONTENTS)\n" + "\ttar --exclude $(DOCSET_NAME) \\\n" + "\t --exclude Nodes.xml \\\n" + "\t --exclude Tokens.xml \\\n" + "\t --exclude Info.plist \\\n" + "\t --exclude Makefile -c -f - . \\\n" + "\t | (cd $(DOCSET_DOCUMENTS); tar xvf -)\n" + "\t$(XCODE_INSTALL)/usr/bin/docsetutil index $(DOCSET_NAME)\n" + "\trm -f $(DOCSET_DOCUMENTS)/Nodes.xml\n" + "\trm -f $(DOCSET_DOCUMENTS)/Info.plist\n" + "\trm -f $(DOCSET_DOCUMENTS)/Makefile\n" + "\trm -f $(DOCSET_RESOURCES)/Nodes.xml\n" + "\trm -f $(DOCSET_RESOURCES)/Tokens.xml\n" + "\n" + "install: docset\n" + "\tmkdir -p $(DESTDIR)\n" + "\tcp -R $(DOCSET_NAME) $(DESTDIR)\n" + "\n" + "uninstall:\n" + "\trm -rf $(DESTDIR)/$(DOCSET_NAME)\n" + "\n" + "always:\n"; + } + + // -- write Info.plist + { + QCString plName = Config_getString("HTML_OUTPUT") + "/Info.plist"; + QFile plist(plName); + if (!plist.open(IO_WriteOnly)) + { + err("Could not open file %s for writing\n",plName.data()); + exit(1); + } + FTextStream ts(&plist); + + ts << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + "<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\"\n" + "\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n" + "<plist version=\"1.0\">\n" + "<dict>\n" + " <key>CFBundleName</key>\n" + " <string>" << projectName << "</string>\n" + " <key>CFBundleIdentifier</key>\n" + " <string>" << bundleId << ".docset</string>\n" + " <key>DocSetFeedName</key>\n" + " <string>" << feedName << "</string>\n" + " <key>DocSetPublisherIdentifier</key>\n" + " <string>" << publisherId << "</string>\n" + " <key>DocSetPublisherName</key>\n" + " <string>" << publisherName << "</string>\n" + "</dict>\n" + "</plist>\n"; + } + + // -- start Nodes.xml + QCString notes = Config_getString("HTML_OUTPUT") + "/Nodes.xml"; + m_nf = new QFile(notes); + if (!m_nf->open(IO_WriteOnly)) + { + err("Could not open file %s for writing\n",notes.data()); + exit(1); + } + //QCString indexName=Config_getBool("GENERATE_TREEVIEW")?"main":"index"; + QCString indexName="index"; + m_nts.setDevice(m_nf); + m_nts << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << endl; + m_nts << "<DocSetNodes version=\"1.0\">" << endl; + m_nts << " <TOC>" << endl; + m_nts << " <Node>" << endl; + m_nts << " <Name>Root</Name>" << endl; + m_nts << " <Path>" << indexName << Doxygen::htmlFileExtension << "</Path>" << endl; + m_nts << " <Subnodes>" << endl; + m_dc = 1; + m_firstNode.resize(m_dc); + m_firstNode.at(0)=TRUE; + + QCString tokens = Config_getString("HTML_OUTPUT") + "/Tokens.xml"; + m_tf = new QFile(tokens); + if (!m_tf->open(IO_WriteOnly)) + { + err("Could not open file %s for writing\n",tokens.data()); + exit(1); + } + m_tts.setDevice(m_tf); + m_tts << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << endl; + m_tts << "<Tokens version=\"1.0\">" << endl; +} + +void DocSets::finalize() +{ + if (!m_firstNode.at(m_dc-1)) + { + m_nts << indent() << " </Node>" << endl; + } + m_dc--; + m_nts << " </Subnodes>" << endl; + m_nts << " </Node>" << endl; + m_nts << " </TOC>" << endl; + m_nts << "</DocSetNodes>" << endl; + m_nf->close(); + delete m_nf; + m_nf=0; + + m_tts << "</Tokens>" << endl; + m_tf->close(); + delete m_tf; + m_tf=0; +} + +QCString DocSets::indent() +{ + QCString result; + result.fill(' ',(m_dc+2)*2); + return result; +} + +void DocSets::incContentsDepth() +{ + ++m_dc; + m_nts << indent() << "<Subnodes>" << endl; + m_firstNode.resize(m_dc); + if (m_dc>0) + { + m_firstNode.at(m_dc-1)=TRUE; + } +} + +void DocSets::decContentsDepth() +{ + if (!m_firstNode.at(m_dc-1)) + { + m_nts << indent() << " </Node>" << endl; + } + m_nts << indent() << "</Subnodes>" << endl; + --m_dc; +} + +void DocSets::addContentsItem(bool isDir, + const char *name, + const char *ref, + const char *file, + const char *anchor, + bool /* separateIndex */, + bool /* addToNavIndex */) +{ + (void)isDir; + if (file && ref==0) + { + if (!m_firstNode.at(m_dc-1)) + { + m_nts << indent() << " </Node>" << endl; + } + m_firstNode.at(m_dc-1)=FALSE; + m_nts << indent() << " <Node>" << endl; + m_nts << indent() << " <Name>" << convertToXML(name) << "</Name>" << endl; + m_nts << indent() << " <Path>"; + m_nts << file << Doxygen::htmlFileExtension; + m_nts << "</Path>" << endl; + if (anchor) + { + m_nts << indent() << " <Anchor>" << anchor << "</Anchor>" << endl; + } + } +} + +void DocSets::addIndexItem(Definition *context,MemberDef *md,const char *) +{ + if (md==0 && context==0) return; + + FileDef *fd = 0; + ClassDef *cd = 0; + NamespaceDef *nd = 0; + + if (md) + { + fd = md->getFileDef(); + cd = md->getClassDef(); + nd = md->getNamespaceDef(); + if (!md->isLinkable()) return; // internal symbol + } + + QCString scope; + QCString type; + QCString decl; + + // determine language + QCString lang; + SrcLangExt langExt = SrcLangExt_Cpp; + if (md) + { + langExt = md->getLanguage(); + } + else if (context) + { + langExt = context->getLanguage(); + } + switch (langExt) + { + case SrcLangExt_Cpp: + case SrcLangExt_ObjC: + { + if (md && (md->isObjCMethod() || md->isObjCProperty())) + lang="occ"; // Objective C/C++ + else if (fd && fd->name().right(2).lower()==".c") + lang="c"; // Plain C + else if (cd==0 && nd==0) + lang="c"; // Plain C symbol outside any class or namespace + else + lang="cpp"; // C++ + } + break; + case SrcLangExt_IDL: lang="idl"; break; // IDL + case SrcLangExt_CSharp: lang="csharp"; break; // C# + case SrcLangExt_PHP: lang="php"; break; // PHP4/5 + case SrcLangExt_D: lang="d"; break; // D + case SrcLangExt_Java: lang="java"; break; // Java + case SrcLangExt_JS: lang="javascript"; break; // Javascript + case SrcLangExt_Python: lang="python"; break; // Python + case SrcLangExt_Fortran: lang="fortran"; break; // Fortran + case SrcLangExt_VHDL: lang="vhdl"; break; // VHDL + case SrcLangExt_XML: lang="xml"; break; // DBUS XML + case SrcLangExt_Tcl: lang="tcl"; break; // Tcl + case SrcLangExt_Markdown:lang="markdown"; break; // Markdown + case SrcLangExt_Unknown: lang="unknown"; break; // should not happen! + } + + if (md) + { + if (context==0) + { + if (md->getGroupDef()) + context = md->getGroupDef(); + else if (md->getFileDef()) + context = md->getFileDef(); + } + if (context==0) return; // should not happen + + switch (md->memberType()) + { + case MemberDef::Define: + type="macro"; break; + case MemberDef::Function: + if (cd && (cd->compoundType()==ClassDef::Interface || + cd->compoundType()==ClassDef::Class)) + { + if (md->isStatic()) + type="clm"; // class member + else + type="instm"; // instance member + } + else if (cd && cd->compoundType()==ClassDef::Protocol) + { + if (md->isStatic()) + type="intfcm"; // interface class member + else + type="intfm"; // interface member + } + else + type="func"; + break; + case MemberDef::Variable: + type="data"; break; + case MemberDef::Typedef: + type="tdef"; break; + case MemberDef::Enumeration: + type="enum"; break; + case MemberDef::EnumValue: + type="econst"; break; + //case MemberDef::Prototype: + // type="prototype"; break; + case MemberDef::Signal: + type="signal"; break; + case MemberDef::Slot: + type="slot"; break; + case MemberDef::Friend: + type="ffunc"; break; + case MemberDef::DCOP: + type="dcop"; break; + case MemberDef::Property: + if (cd && cd->compoundType()==ClassDef::Protocol) + type="intfp"; // interface property + else + type="instp"; // instance property + break; + case MemberDef::Event: + type="event"; break; + } + cd = md->getClassDef(); + nd = md->getNamespaceDef(); + if (cd) + { + scope = cd->qualifiedName(); + } + else if (nd) + { + scope = nd->name(); + } + writeToken(m_tts,md,type,lang,scope,md->anchor()); + } + else if (context && context->isLinkable()) + { + if (fd==0 && context->definitionType()==Definition::TypeFile) + { + fd = (FileDef*)context; + } + if (cd==0 && context->definitionType()==Definition::TypeClass) + { + cd = (ClassDef*)context; + } + if (nd==0 && context->definitionType()==Definition::TypeNamespace) + { + nd = (NamespaceDef*)context; + } + if (fd) + { + type="file"; + } + else if (cd) + { + scope = cd->qualifiedName(); + if (cd->isTemplate()) + { + type="tmplt"; + } + else if (cd->compoundType()==ClassDef::Protocol) + { + type="intf"; + if (scope.right(2)=="-p") scope=scope.left(scope.length()-2); + } + else if (cd->compoundType()==ClassDef::Interface) + { + type="cl"; + } + else if (cd->compoundType()==ClassDef::Category) + { + type="cat"; + } + else + { + type = "cl"; + } + IncludeInfo *ii = cd->includeInfo(); + if (ii) + { + decl=ii->includeName; + if (decl.isEmpty()) + { + decl=ii->local; + } + } + } + else if (nd) + { + scope = nd->name(); + type = "ns"; + } + if (m_scopes.find(context->getOutputFileBase())==0) + { + writeToken(m_tts,context,type,lang,scope,0,decl); + m_scopes.append(context->getOutputFileBase(),(void*)0x8); + } + } +} + +void DocSets::writeToken(FTextStream &t, + const Definition *d, + const QCString &type, + const QCString &lang, + const char *scope, + const char *anchor, + const char *decl) +{ + t << " <Token>" << endl; + t << " <TokenIdentifier>" << endl; + QString name = d->name(); + if (name.right(2)=="-p") name=name.left(name.length()-2); + t << " <Name>" << convertToXML(name) << "</Name>" << endl; + if (!lang.isEmpty()) + { + t << " <APILanguage>" << lang << "</APILanguage>" << endl; + } + if (!type.isEmpty()) + { + t << " <Type>" << type << "</Type>" << endl; + } + if (scope) + { + t << " <Scope>" << convertToXML(scope) << "</Scope>" << endl; + } + t << " </TokenIdentifier>" << endl; + t << " <Path>" << d->getOutputFileBase() + << Doxygen::htmlFileExtension << "</Path>" << endl; + if (anchor) + { + t << " <Anchor>" << anchor << "</Anchor>" << endl; + } + QCString tooltip = d->briefDescriptionAsTooltip(); + if (!tooltip.isEmpty()) + { + t << " <Abstract>" << convertToXML(tooltip) << "</Abstract>" << endl; + } + if (decl) + { + t << " <DeclaredIn>" << convertToXML(decl) << "</DeclaredIn>" << endl; + } + t << " </Token>" << endl; +} + +void DocSets::addIndexFile(const char *name) +{ + (void)name; +} + diff --git a/trunk/src/docsets.h b/trunk/src/docsets.h new file mode 100644 index 0000000..97457f6 --- /dev/null +++ b/trunk/src/docsets.h @@ -0,0 +1,85 @@ +/****************************************************************************** + * + * Copyright (C) 1997-2012 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. + * + */ + +#ifndef DOCSETS_H +#define DOCSETS_H + +#include "qtbc.h" +#include <qstrlist.h> +#include "sortdict.h" +#include "ftextstream.h" +#include "index.h" + +class QFile; +class Definition; + +/*! A class that generates docset files. + * These files can be used to create context help + * for use within Apple's Xcode 3.0 development environment + */ +class DocSets : public IndexIntf +{ + + public: + DocSets(); + ~DocSets(); + void initialize(); + void finalize(); + void incContentsDepth(); + void decContentsDepth(); + void addContentsItem(bool isDir, + const char *name, + const char *ref, + const char *file, + const char *anchor, + bool separateIndex, + bool addToNavIndex + ); + void addIndexItem(Definition *context,MemberDef *md,const char *title); + void addIndexFile(const char *name); + void addImageFile(const char *) {} + void addStyleSheetFile(const char *) {} + + private: + void writeToken(FTextStream &t, const Definition *d, + const QCString &type, const QCString &lang, + const char *scope=0, const char *anchor=0, + const char *decl=0); + struct NodeDef + { + NodeDef(bool d,const QCString &n,const QCString &r, + const QCString &f,const QCString &a,int i) : + isDir(d), name(n), ref(r), file(f), anchor(a),id(i) {} + bool isDir; + QCString name; + QCString ref; + QCString file; + QCString anchor; + int id; + }; + QCString indent(); + QFile *m_nf; + QFile *m_tf; + FTextStream m_nts; + FTextStream m_tts; + int m_dc; + int m_id; + QArray<bool> m_firstNode; + SDict<NodeDef> m_nodes; + SDict<void> m_scopes; +}; + +#endif /* DOCSETS_H */ + diff --git a/trunk/src/doctokenizer.h b/trunk/src/doctokenizer.h new file mode 100644 index 0000000..e5ae26a --- /dev/null +++ b/trunk/src/doctokenizer.h @@ -0,0 +1,155 @@ +/****************************************************************************** + * + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#ifndef _DOCTOKENIZER_H +#define _DOCTOKENIZER_H + +#include <qcstring.h> +#include <qlist.h> +#include "htmlattrib.h" + +class Definition; +class MemberGroup; + +enum Tokens +{ + TK_WORD = 1, + TK_LNKWORD = 2, + TK_WHITESPACE = 3, + TK_LISTITEM = 4, + TK_ENDLIST = 5, + TK_COMMAND = 6, + TK_HTMLTAG = 7, + TK_SYMBOL = 8, + TK_NEWPARA = 9, + TK_RCSTAG = 10, + TK_URL = 11, + + RetVal_OK = 0x10000, + RetVal_SimpleSec = 0x10001, + RetVal_ListItem = 0x10002, + RetVal_Section = 0x10003, + RetVal_Subsection = 0x10004, + RetVal_Subsubsection = 0x10005, + RetVal_Paragraph = 0x10006, + RetVal_SubParagraph = 0x10007, + RetVal_EndList = 0x10008, + RetVal_EndPre = 0x10009, + RetVal_DescData = 0x1000A, + RetVal_DescTitle = 0x1000B, + RetVal_EndDesc = 0x1000C, + RetVal_TableRow = 0x1000D, + RetVal_TableCell = 0x1000E, + RetVal_TableHCell = 0x1000F, + RetVal_EndTable = 0x10010, + RetVal_Internal = 0x10011, + RetVal_SwitchLang = 0x10012, + RetVal_CloseXml = 0x10013, + RetVal_EndBlockQuote = 0x10014 +}; + +struct TokenInfo +{ + // unknown token + char unknownChar; + + // command token + QCString name; + + // command text (RCS tag) + QCString text; + + // comment blocks + + // list token info + bool isEnumList; + int indent; + + // sections + QCString sectionId; + + // simple section + QCString simpleSectName; + QCString simpleSectText; + + // verbatim fragment + QCString verb; + + // xrefitem + int id; + + // html tag + HtmlAttribList attribs; + bool endTag; + bool emptyTag; + + // whitespace + QCString chars; + + // url + bool isEMailAddr; + + // param attributes + enum ParamDir { In=1, Out=2, InOut=3, Unspecified=0 }; + ParamDir paramDir; +}; + +// globals +extern TokenInfo *g_token; +extern int doctokenizerYYlineno; +extern FILE *doctokenizerYYin; + +// helper functions +const char *tokToString(int token); + +// operations on the scanner +void doctokenizerYYFindSections(const char *input,Definition *d, + MemberGroup *mg,const char *fileName); +void doctokenizerYYinit(const char *input,const char *fileName); +void doctokenizerYYcleanup(); +void doctokenizerYYpushContext(); +bool doctokenizerYYpopContext(); +int doctokenizerYYlex(); +void doctokenizerYYsetStatePara(); +void doctokenizerYYsetStateTitle(); +void doctokenizerYYsetStateTitleAttrValue(); +void doctokenizerYYsetStateCode(); +void doctokenizerYYsetStateXmlCode(); +void doctokenizerYYsetStateHtmlOnly(); +void doctokenizerYYsetStateManOnly(); +void doctokenizerYYsetStateLatexOnly(); +void doctokenizerYYsetStateXmlOnly(); +void doctokenizerYYsetStateVerbatim(); +void doctokenizerYYsetStateDot(); +void doctokenizerYYsetStateMsc(); +void doctokenizerYYsetStateParam(); +void doctokenizerYYsetStateXRefItem(); +void doctokenizerYYsetStateFile(); +void doctokenizerYYsetStatePattern(); +void doctokenizerYYsetStateLink(); +void doctokenizerYYsetStateCite(); +void doctokenizerYYsetStateRef(); +void doctokenizerYYsetStateInternalRef(); +void doctokenizerYYsetStateText(); +void doctokenizerYYsetStateSkipTitle(); +void doctokenizerYYsetStateAnchor(); +void doctokenizerYYsetInsidePre(bool b); +void doctokenizerYYpushBackHtmlTag(const char *tag); +void doctokenizerYYsetStateSnippet(); + +#endif diff --git a/trunk/src/doctokenizer.l b/trunk/src/doctokenizer.l new file mode 100644 index 0000000..7f11aca --- /dev/null +++ b/trunk/src/doctokenizer.l @@ -0,0 +1,1319 @@ +/****************************************************************************** + * + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + + +%{ + +#include <qfile.h> +#include <qstring.h> +#include <qstack.h> +#include <qdict.h> +#include <qregexp.h> + +#include "doctokenizer.h" +#include "cmdmapper.h" +#include "config.h" +#include "message.h" +#include "section.h" +#include "membergroup.h" +#include "definition.h" +#include "doxygen.h" +#include "portable.h" + +#define YY_NEVER_INTERACTIVE 1 + +//-------------------------------------------------------------------------- + +// context for tokenizer phase +static int g_commentState; +TokenInfo *g_token = 0; +static int g_inputPos = 0; +static const char *g_inputString; +static QCString g_fileName; +static bool g_insidePre; + +// context for section finding phase +static Definition *g_definition; +static MemberGroup *g_memberGroup; +static QCString g_secLabel; +static QCString g_secTitle; +static SectionInfo::SectionType g_secType; +static QCString g_endMarker; + +struct DocLexerContext +{ + TokenInfo *token; + int rule; + int inputPos; + const char *inputString; + YY_BUFFER_STATE state; +}; + +static QStack<DocLexerContext> g_lexerStack; + +//-------------------------------------------------------------------------- + +void doctokenizerYYpushContext() +{ + DocLexerContext *ctx = new DocLexerContext; + ctx->rule = YY_START; + ctx->token = g_token; + ctx->inputPos = g_inputPos; + ctx->inputString = g_inputString; + ctx->state = YY_CURRENT_BUFFER; + g_lexerStack.push(ctx); + yy_switch_to_buffer(yy_create_buffer(doctokenizerYYin, YY_BUF_SIZE)); +} + +bool doctokenizerYYpopContext() +{ + if (g_lexerStack.isEmpty()) return FALSE; + DocLexerContext *ctx = g_lexerStack.pop(); + g_inputPos = ctx->inputPos; + g_inputString = ctx->inputString; + yy_delete_buffer(YY_CURRENT_BUFFER); + yy_switch_to_buffer(ctx->state); + BEGIN(ctx->rule); + delete ctx; + return TRUE; +} + + +//-------------------------------------------------------------------------- + +const char *tokToString(int token) +{ + switch (token) + { + case 0: return "TK_EOF"; + case TK_WORD: return "TK_WORD"; + case TK_LNKWORD: return "TK_LNKWORD"; + case TK_WHITESPACE: return "TK_WHITESPACE"; + case TK_LISTITEM: return "TK_LISTITEM"; + case TK_ENDLIST: return "TK_ENDLIST"; + case TK_COMMAND: return "TK_COMMAND"; + case TK_HTMLTAG: return "TK_HTMLTAG"; + case TK_SYMBOL: return "TK_SYMBOL"; + case TK_NEWPARA: return "TK_NEWPARA"; + case TK_RCSTAG: return "TK_RCSTAG"; + case TK_URL: return "TK_URL"; + } + return "ERROR"; +} + +static int computeIndent(const char *str,int length) +{ + int i; + int indent=0; + int tabSize=Config_getInt("TAB_SIZE"); + for (i=0;i<length;i++) + { + if (str[i]=='\t') + { + indent+=tabSize - (indent%tabSize); + } + else if (str[i]=='\n') + { + indent=0; + } + else + { + indent++; + } + } + return indent; +} + +//-------------------------------------------------------------------------- + +static void processSection() +{ + //printf("%s: found section/anchor with name `%s'\n",g_fileName.data(),g_secLabel.data()); + QCString file; + if (g_memberGroup) + { + file = g_memberGroup->parent()->getOutputFileBase(); + } + else if (g_definition) + { + file = g_definition->getOutputFileBase(); + } + else + { + warn(g_fileName,yylineno,"Found section/anchor %s without context\n",g_secLabel.data()); + } + SectionInfo *si=0; + if ((si=Doxygen::sectionDict.find(g_secLabel))) + { + si->fileName = file; + //si = new SectionInfo(file,g_secLabel,g_secTitle,g_secType); + //Doxygen::sectionDict.insert(g_secLabel,si); + } +} + +static void handleHtmlTag() +{ + QCString tagText=yytext; + g_token->attribs.clear(); + g_token->endTag = FALSE; + g_token->emptyTag = FALSE; + + // Check for end tag + int startNamePos=1; + if (tagText.at(1)=='/') + { + g_token->endTag = TRUE; + startNamePos++; + } + + // Parse the name portion + int i = startNamePos; + for (i=startNamePos; i < (int)yyleng; i++) + { + // Check for valid HTML/XML name chars (including namespaces) + char c = tagText.at(i); + if (!(isalnum(c) || c=='-' || c=='_' || c==':')) break; + } + g_token->name = tagText.mid(startNamePos,i-startNamePos); + + // Parse the attributes. Each attribute is a name, value pair + // The result is stored in g_token->attribs. + int startName,endName,startAttrib,endAttrib; + while (i<(int)yyleng) + { + char c=tagText.at(i); + // skip spaces + while (i<(int)yyleng && isspace(c)) { c=tagText.at(++i); } + // check for end of the tag + if (c == '>') break; + // Check for XML style "empty" tag. + if (c == '/') + { + g_token->emptyTag = TRUE; + break; + } + startName=i; + // search for end of name + while (i<(int)yyleng && !isspace(c) && c!='=') { c=tagText.at(++i); } + endName=i; + HtmlAttrib opt; + opt.name = tagText.mid(startName,endName-startName).lower(); + // skip spaces + while (i<(int)yyleng && isspace(c)) { c=tagText.at(++i); } + if (tagText.at(i)=='=') // option has value + { + c=tagText.at(++i); + // skip spaces + while (i<(int)yyleng && isspace(c)) { c=tagText.at(++i); } + if (tagText.at(i)=='\'') // option '...' + { + c=tagText.at(++i); + startAttrib=i; + + // search for matching quote + while (i<(int)yyleng && c!='\'') { c=tagText.at(++i); } + endAttrib=i; + if (i<(int)yyleng) c=tagText.at(++i); + } + else if (tagText.at(i)=='"') // option "..." + { + c=tagText.at(++i); + startAttrib=i; + // search for matching quote + while (i<(int)yyleng && c!='"') { c=tagText.at(++i); } + endAttrib=i; + if (i<(int)yyleng) c=tagText.at(++i); + } + else // value without any quotes + { + startAttrib=i; + // search for separator or end symbol + while (i<(int)yyleng && !isspace(c) && c!='>') { c=tagText.at(++i); } + endAttrib=i; + if (i<(int)yyleng) c=tagText.at(++i); + } + opt.value = tagText.mid(startAttrib,endAttrib-startAttrib); + } + else // start next option + { + } + //printf("=====> Adding option name=<%s> value=<%s>\n", + // opt.name.data(),opt.value.data()); + g_token->attribs.append(&opt); + } +} + +static QCString stripEmptyLines(const QCString &s) +{ + if (s.isEmpty()) return QCString(); + int end=s.length(); + int start=0,p=0; + // skip leading empty lines + for (;;) + { + int c; + while ((c=s[p]) && (c==' ' || c=='\t')) p++; + if (s[p]=='\n') + { + start=++p; + } + else + { + break; + } + } + // skip trailing empty lines + p=end-1; + if (p>=start && s.at(p)=='\n') p--; + while (p>=start) + { + int c; + while ((c=s[p]) && (c==' ' || c=='\t')) p--; + if (s[p]=='\n') + { + end=p; + } + else + { + break; + } + p--; + } + //printf("stripEmptyLines(%d-%d)\n",start,end); + return s.mid(start,end-start); +} + +//-------------------------------------------------------------------------- + +#undef YY_INPUT +#define YY_INPUT(buf,result,max_size) result=yyread(buf,max_size); + +static int yyread(char *buf,int max_size) +{ + int c=0; + const char *src=g_inputString+g_inputPos; + while ( c < max_size && *src ) *buf++ = *src++, c++; + g_inputPos+=c; + return c; +} + +//-------------------------------------------------------------------------- + +%} + +CMD ("\\"|"@") +WS [ \t\r\n] +NONWS [^ \t\r\n] +BLANK [ \t\r] +ID "$"?[a-z_A-Z\x80-\xFF][a-z_A-Z0-9\x80-\xFF]* +LABELID [a-z_A-Z\x80-\xFF][a-z_A-Z0-9\x80-\xFF\-]* +PHPTYPE [\\:a-z_A-Z0-9\x80-\xFF\-]+ +CITEID [a-z_A-Z\x80-\xFF][a-z_A-Z0-9\x80-\xFF\-:/]* +MAILADR ("mailto:")?[a-z_A-Z0-9.+-]+"@"[a-z_A-Z0-9-]+("."[a-z_A-Z0-9\-]+)+[a-z_A-Z0-9\-]+ +OPTSTARS ("//"{BLANK}*)?"*"*{BLANK}* +LISTITEM {BLANK}*[-]("#")?{WS} +MLISTITEM {BLANK}*[+*]{WS} +OLISTITEM {BLANK}*[1-9][0-9]*"."{BLANK} +ENDLIST {BLANK}*"."{BLANK}*\n +ATTRIB {ID}{WS}*("="{WS}*(("\""[^\"]*"\"")|("'"[^\']*"'")|[^ \t\r\n'"><]+))? +URLCHAR [a-z_A-Z0-9\!\~\,\:\;\'\$\?\@\&\%\#\.\-\+\/\=] +URLMASK ({URLCHAR}+([({]{URLCHAR}*[)}])?)+ +FILESCHAR [a-z_A-Z0-9\\:\\\/\-\+] +FILEECHAR [a-z_A-Z0-9\-\+] +HFILEMASK ("."{FILESCHAR}*{FILEECHAR}+)* +FILEMASK ({FILESCHAR}*{FILEECHAR}+("."{FILESCHAR}*{FILEECHAR}+)*)|{HFILEMASK} +LINKMASK [^ \t\n\r\\@<&${}]+("("[^\n)]*")")?({BLANK}*("const"|"volatile"){BLANK}+)? +VERBATIM "verbatim"{BLANK}* +SPCMD1 {CMD}([a-z_A-Z][a-z_A-Z0-9]*|{VERBATIM}) +SPCMD2 {CMD}[\\@<>&$#%~".] +SPCMD3 {CMD}form#[0-9]+ +SPCMD4 {CMD}"::" +INOUT "in"|"out"|("in"{BLANK}*","{BLANK}*"out")|("out"{BLANK}*","{BLANK}*"in") +PARAMIO {CMD}param{BLANK}*"["{BLANK}*{INOUT}{BLANK}*"]" +TEMPCHAR [a-z_A-Z0-9,: \t\*\&] +FUNCCHAR [a-z_A-Z0-9,:\<\> \t\*\&\[\]] +SCOPESEP "::"|"#"|"." +TEMPLPART "<"{TEMPCHAR}*">" +SCOPEPRE {ID}{TEMPLPART}?{SCOPESEP} +SCOPEKEYS ":"({ID}":")* +SCOPECPP {SCOPEPRE}*(~)?{ID}("<"{TEMPCHAR}*">")? +SCOPEOBJC {SCOPEPRE}?{ID}{SCOPEKEYS}? +SCOPEMASK {SCOPECPP}|{SCOPEOBJC} +FUNCARG "("{FUNCCHAR}*")"({BLANK}*("volatile"|"const"){BLANK})? +OPNEW {BLANK}+"new"({BLANK}*"[]")? +OPDEL {BLANK}+"delete"({BLANK}*"[]")? +OPNORM {OPNEW}|{OPDEL}|"+"|"-"|"*"|"/"|"%"|"^"|"&"|"|"|"~"|"!"|"="|"<"|">"|"+="|"-="|"*="|"/="|"%="|"^="|"&="|"|="|"<<"|">>"|"<<="|">>="|"=="|"!="|"<="|">="|"&&"|"||"|"++"|"--"|","|"->*"|"->"|"[]"|"()" +OPCAST {BLANK}+[^<(\r\n.,][^(\r\n.,]* +OPMASK ({BLANK}*{OPNORM}{FUNCARG}) +OPMASKOPT ({BLANK}*{OPNORM}{FUNCARG}?)|({OPCAST}{FUNCARG}) +LNKWORD1 ("::"|"#")?{SCOPEMASK} +CVSPEC {BLANK}*("const"|"volatile") +LNKWORD2 (({SCOPEPRE}*"operator"{OPMASK})|({SCOPEPRE}"operator"{OPMASKOPT})|(("::"|"#"){SCOPEPRE}*"operator"{OPMASKOPT})){CVSPEC}? +LNKWORD3 ([0-9a-z_A-Z\-]+("/"|"\\"))*[0-9a-z_A-Z\-]+("."[0-9a-z_A-Z]+)+ +CHARWORDQ [^ \t\n\r\\@<>()\[\]:;\?{}&%$#,."='] +ESCWORD ("%"{ID}(("::"|"."){ID})*)|("%'") +WORD1 {ESCWORD}|{CHARWORDQ}+|"{"|"}"|"'\"'"|("\""[^"\n]*\n?[^"\n]*"\"") +WORD2 "."|","|"("|")"|"["|"]"|":"|";"|"\?"|"="|"'" +WORD1NQ {ESCWORD}|{CHARWORDQ}+|"{"|"}" +WORD2NQ "."|","|"("|")"|"["|"]"|":"|";"|"\?"|"="|"'" +HTMLTAG "<"(("/")?){ID}({WS}+{ATTRIB})*{WS}*(("/")?)">" +HTMLKEYL "strong"|"center"|"table"|"caption"|"small"|"code"|"dfn"|"var"|"img"|"pre"|"sub"|"sup"|"tr"|"td"|"th"|"ol"|"ul"|"li"|"tt"|"kbd"|"em"|"hr"|"dl"|"dt"|"dd"|"br"|"i"|"a"|"b"|"p" +HTMLKEYU "STRONG"|"CENTER"|"TABLE"|"CAPTION"|"SMALL"|"CODE"|"DFN"|"VAR"|"IMG"|"PRE"|"SUB"|"SUP"|"TR"|"TD"|"TH"|"OL"|"UL"|"LI"|"TT"|"KBD"|"EM"|"HR"|"DL"|"DT"|"DD"|"BR"|"I"|"A"|"B"|"P" +HTMLKEYW {HTMLKEYL}|{HTMLKEYU} +REFWORD2 ("#"|"::")?({ID}{TEMPLPART}?("."|"#"|"::"|"-"|"/"))*({ID}(":")?){FUNCARG}? +REFWORD3 ({ID}":")*{ID}":"? +REFWORD {LABELID}|{REFWORD2}|{REFWORD3} + +%option noyywrap +%option yylineno + +%x St_Para +%x St_Comment +%x St_Title +%x St_TitleN +%x St_TitleQ +%x St_TitleA +%x St_TitleV +%x St_Code +%x St_CodeOpt +%x St_XmlCode +%x St_HtmlOnly +%x St_ManOnly +%x St_LatexOnly +%x St_XmlOnly +%x St_Verbatim +%x St_Dot +%x St_Msc +%x St_Param +%x St_XRefItem +%x St_XRefItem2 +%x St_File +%x St_Pattern +%x St_Link +%x St_Cite +%x St_Ref +%x St_Ref2 +%x St_IntRef +%x St_Text +%x St_SkipTitle +%x St_Anchor +%x St_Snippet + +%x St_Sections +%s St_SecLabel1 +%s St_SecLabel2 +%s St_SecTitle +%x St_SecSkip + +%% +<St_Para>\r /* skip carriage return */ +<St_Para>^{LISTITEM} { /* list item */ + QCString text=yytext; + int dashPos = text.findRev('-'); + g_token->isEnumList = text.at(dashPos+1)=='#'; + g_token->id = -1; + g_token->indent = computeIndent(yytext,dashPos); + return TK_LISTITEM; + } +<St_Para>^{MLISTITEM} { /* list item */ + if (!Doxygen::markdownSupport) + { + REJECT; + } + else + { + QCString text=yytext; + static QRegExp re("[*+]"); + int listPos = text.findRev(re); + g_token->isEnumList = FALSE; + g_token->id = -1; + g_token->indent = computeIndent(yytext,listPos); + return TK_LISTITEM; + } + } +<St_Para>^{OLISTITEM} { /* numbered list item */ + if (!Doxygen::markdownSupport) + { + REJECT; + } + else + { + QCString text=yytext; + static QRegExp re("[1-9]"); + int digitPos = text.find(re); + int dotPos = text.find('.',digitPos); + g_token->isEnumList = TRUE; + g_token->id = atoi(QCString(yytext).mid(digitPos,dotPos-digitPos)); + g_token->indent = computeIndent(yytext,digitPos); + return TK_LISTITEM; + } + } +<St_Para>{BLANK}*\n{LISTITEM} { /* list item on next line */ + QCString text=yytext; + text=text.right(text.length()-text.find('\n')-1); + int dashPos = text.findRev('-'); + g_token->isEnumList = text.at(dashPos+1)=='#'; + g_token->id = -1; + g_token->indent = computeIndent(text,dashPos); + return TK_LISTITEM; + } +<St_Para>{BLANK}*\n{MLISTITEM} { /* list item on next line */ + if (!Doxygen::markdownSupport) + { + REJECT; + } + else + { + QCString text=yytext; + static QRegExp re("[*+]"); + text=text.right(text.length()-text.find('\n')-1); + int markPos = text.findRev(re); + g_token->isEnumList = FALSE; + g_token->id = -1; + g_token->indent = computeIndent(text,markPos); + return TK_LISTITEM; + } + } +<St_Para>({BLANK}*\n)+{OLISTITEM} { /* list item on next line */ + if (!Doxygen::markdownSupport) + { + REJECT; + } + else + { + QCString text=yytext; + int nl=text.findRev('\n'); + int len=text.length(); + text=text.right(len-nl-1); + static QRegExp re("[1-9]"); + int digitPos = text.find(re); + int dotPos = text.find('.',digitPos); + g_token->isEnumList = TRUE; + g_token->id = atoi(QCString(text).mid(digitPos,dotPos-digitPos)); + g_token->indent = computeIndent(text,digitPos); + return TK_LISTITEM; + } + } +<St_Para>^{ENDLIST} { /* end list */ + int dotPos = QCString(yytext).findRev('.'); + g_token->indent = computeIndent(yytext,dotPos); + return TK_ENDLIST; + } +<St_Para>{BLANK}*\n{ENDLIST} { /* end list on next line */ + QCString text=yytext; + text=text.right(text.length()-text.find('\n')-1); + int dotPos = text.findRev('.'); + g_token->indent = computeIndent(text,dotPos); + return TK_ENDLIST; + } +<St_Para>"{"{BLANK}*"@link" { + g_token->name = "javalink"; + return TK_COMMAND; + } +<St_Para>"{"{BLANK}*"@inheritDoc"{BLANK}*"}" { + g_token->name = "inheritdoc"; + return TK_COMMAND; + } +<St_Para>"@_fakenl" { // artificial new line + yylineno++; + } +<St_Para>{SPCMD3} { + g_token->name = "form"; + bool ok; + g_token->id = QCString(yytext).right((int)yyleng-6).toInt(&ok); + ASSERT(ok); + return TK_COMMAND; + } +<St_Para>{SPCMD1} | +<St_Para>{SPCMD2} | +<St_Para>{SPCMD4} { /* special command */ + g_token->name = yytext+1; + g_token->name = g_token->name.stripWhiteSpace(); + g_token->paramDir=TokenInfo::Unspecified; + return TK_COMMAND; + } +<St_Para>{PARAMIO} { /* param [in,out] command */ + g_token->name = "param"; + QCString s(yytext); + bool isIn = s.find("in")!=-1; + bool isOut = s.find("out")!=-1; + if (isIn) + { + if (isOut) + { + g_token->paramDir=TokenInfo::InOut; + } + else + { + g_token->paramDir=TokenInfo::In; + } + } + else if (isOut) + { + g_token->paramDir=TokenInfo::Out; + } + else + { + g_token->paramDir=TokenInfo::Unspecified; + } + return TK_COMMAND; + } +<St_Para>("http:"|"https:"|"ftp:"|"file:"|"news:"){URLMASK}/\. { // URL. + g_token->name=yytext; + g_token->isEMailAddr=FALSE; + return TK_URL; + } +<St_Para>("http:"|"https:"|"ftp:"|"file:"|"news:"){URLMASK} { // URL + g_token->name=yytext; + g_token->isEMailAddr=FALSE; + return TK_URL; + } +<St_Para>"<"("http:"|"https:"|"ftp:"|"file:"|"news:"){URLMASK}">" { // URL + g_token->name=yytext; + g_token->name = g_token->name.mid(1,g_token->name.length()-2); + g_token->isEMailAddr=FALSE; + return TK_URL; + } +<St_Para>{MAILADR} { // Mail address + g_token->name=yytext; + g_token->name.stripPrefix("mailto:"); + g_token->isEMailAddr=TRUE; + return TK_URL; + } +<St_Para>"<"{MAILADR}">" { // Mail address + g_token->name=yytext; + g_token->name = g_token->name.mid(1,g_token->name.length()-2); + g_token->name.stripPrefix("mailto:"); + g_token->isEMailAddr=TRUE; + return TK_URL; + } +<St_Para>"$"{ID}":"[^\n$]+"$" { /* RCS tag */ + QCString tagName(yytext+1); + int index=tagName.find(':'); + g_token->name = tagName.left(index+1); + g_token->text = tagName.mid(index+2,tagName.length()-index-3); + return TK_RCSTAG; + } +<St_Para,St_HtmlOnly>"$("{ID}")" { /* environment variable */ + QCString name = &yytext[2]; + name = name.left(name.length()-1); + QCString value = portable_getenv(name); + for (int i=value.length()-1;i>=0;i--) unput(value.at(i)); + } +<St_Para>{HTMLTAG} { /* html tag */ + handleHtmlTag(); + return TK_HTMLTAG; + } +<St_Para,St_Text>"&"{ID}";" { /* special symbol */ + g_token->name = yytext; + return TK_SYMBOL; + } + + /********* patterns for linkable words ******************/ + +<St_Para>{ID}/"<"{HTMLKEYW}">" { /* this rule is to prevent opening html + * tag to be recognized as a templated classes + */ + g_token->name = yytext; + return TK_LNKWORD; + } +<St_Para>{LNKWORD1}/"<br>" | // prevent <br> html tag to be parsed as template arguments +<St_Para>{LNKWORD1} | +<St_Para>{LNKWORD1}{FUNCARG} | +<St_Para>{LNKWORD2} | +<St_Para>{LNKWORD3} { + g_token->name = yytext; + return TK_LNKWORD; + } +<St_Para>{LNKWORD1}{FUNCARG}{CVSPEC}[^a-z_A-Z0-9] { + g_token->name = yytext; + g_token->name = g_token->name.left(g_token->name.length()-1); + unput(yytext[(int)yyleng-1]); + return TK_LNKWORD; + } + /********* patterns for normal words ******************/ + +<St_Para,St_Text>{WORD1} | +<St_Para,St_Text>{WORD2} { /* function call */ + if (yytext[0]=='%') // strip % if present + g_token->name = &yytext[1]; + else + g_token->name = yytext; + return TK_WORD; + + /* the following is dummy code to please the + * compiler, removing this results in a warning + * on my machine + */ + goto find_rule; + } +<St_Text>({ID}".")+{ID} { + g_token->name = yytext; + return TK_WORD; + } +<St_Para,St_Text>"operator"/{BLANK}*"<"[a-zA-Z_0-9]+">" { // Special case: word "operator" followed by a HTML command + // avoid interpretation as "operator <" + g_token->name = yytext; + return TK_WORD; + } + + /*******************************************************/ + +<St_Para,St_Text>{BLANK}+ | +<St_Para,St_Text>{BLANK}*\n{BLANK}* { /* white space */ + g_token->chars=yytext; + return TK_WHITESPACE; + } +<St_Text>[\\@<>&$#%~] { + g_token->name = yytext; + return TK_COMMAND; + } +<St_Para>({BLANK}*\n)+{BLANK}*\n{BLANK}* { + if (g_insidePre) + { + /* Inside a <pre>..</pre> blank lines are treated + * as whitespace. + */ + g_token->chars=yytext; + return TK_WHITESPACE; + } + else // found end of a paragraph + { + g_token->indent=computeIndent(yytext,(int)yyleng); + int i; + // put back the indentation (needed for list items) + for (i=0;i<g_token->indent;i++) + { + unput(' '); + } + // tell flex that after putting the last indent + // back we are at the beginning of the line + YY_CURRENT_BUFFER->yy_at_bol=1; + // start of a new paragraph + return TK_NEWPARA; + } + } +<St_CodeOpt>"{"{LABELID}"}" { + g_token->name = yytext; + g_token->name = g_token->name.mid(1,g_token->name.length()-2); + BEGIN(St_Code); + } +<St_CodeOpt>\n | +<St_CodeOpt>. { + unput(*yytext); + BEGIN(St_Code); + } +<St_Code>{WS}*{CMD}"endcode" { + return RetVal_OK; + } +<St_XmlCode>{WS}*"</code>" { + return RetVal_OK; + } +<St_Code,St_XmlCode>[^\\@\n<]+ | +<St_Code,St_XmlCode>\n | +<St_Code,St_XmlCode>. { + g_token->verb+=yytext; + } +<St_HtmlOnly>{CMD}"endhtmlonly" { + return RetVal_OK; + } +<St_HtmlOnly>[^\\@\n$]+ | +<St_HtmlOnly>\n | +<St_HtmlOnly>. { + g_token->verb+=yytext; + } +<St_ManOnly>{CMD}"endmanonly" { + return RetVal_OK; + } +<St_ManOnly>[^\\@\n$]+ | +<St_ManOnly>\n | +<St_ManOnly>. { + g_token->verb+=yytext; + } +<St_LatexOnly>{CMD}"endlatexonly" { + return RetVal_OK; + } +<St_LatexOnly>[^\\@\n]+ | +<St_LatexOnly>\n | +<St_LatexOnly>. { + g_token->verb+=yytext; + } +<St_XmlOnly>{CMD}"endxmlonly" { + return RetVal_OK; + } +<St_XmlOnly>[^\\@\n]+ | +<St_XmlOnly>\n | +<St_XmlOnly>. { + g_token->verb+=yytext; + } +<St_Verbatim>{CMD}"endverbatim" { + g_token->verb=stripEmptyLines(g_token->verb); + return RetVal_OK; + } +<St_Verbatim>[^\\@\n]+ | +<St_Verbatim>\n | +<St_Verbatim>. { /* Verbatim text */ + g_token->verb+=yytext; + } +<St_Dot>{CMD}"enddot" { + return RetVal_OK; + } +<St_Dot>[^\\@\n]+ | +<St_Dot>\n | +<St_Dot>. { /* dot text */ + g_token->verb+=yytext; + } +<St_Msc>{CMD}"endmsc" { + return RetVal_OK; + } +<St_Msc>[^\\@\n]+ | +<St_Msc>\n | +<St_Msc>. { /* msc text */ + g_token->verb+=yytext; + } +<St_Title>"\"" { // quoted title + BEGIN(St_TitleQ); + } +<St_Title>[ \t]+ { + g_token->chars=yytext; + return TK_WHITESPACE; + } +<St_Title>. { // non-quoted title + unput(*yytext); + BEGIN(St_TitleN); + } +<St_Title>\n { + unput(*yytext); + return 0; + } +<St_TitleN>"&"{ID}";" { /* symbol */ + g_token->name = yytext; + return TK_SYMBOL; + } +<St_TitleN>{HTMLTAG} { + } +<St_TitleN>{SPCMD1} | +<St_TitleN>{SPCMD2} { /* special command */ + g_token->name = yytext+1; + g_token->paramDir=TokenInfo::Unspecified; + return TK_COMMAND; + } +<St_TitleN>{WORD1} | +<St_TitleN>{WORD2} { /* word */ + if (yytext[0]=='%') // strip % if present + g_token->name = &yytext[1]; + else + g_token->name = yytext; + return TK_WORD; + } +<St_TitleN>[ \t]+ { + g_token->chars=yytext; + return TK_WHITESPACE; + } +<St_TitleN>\n { /* new line => end of title */ + unput(*yytext); + return 0; + } +<St_TitleQ>"&"{ID}";" { /* symbol */ + g_token->name = yytext; + return TK_SYMBOL; + } +<St_TitleQ>{SPCMD1} | +<St_TitleQ>{SPCMD2} { /* special command */ + g_token->name = yytext+1; + g_token->paramDir=TokenInfo::Unspecified; + return TK_COMMAND; + } +<St_TitleQ>{WORD1NQ} | +<St_TitleQ>{WORD2NQ} { /* word */ + g_token->name = yytext; + return TK_WORD; + } +<St_TitleQ>[ \t]+ { + g_token->chars=yytext; + return TK_WHITESPACE; + } +<St_TitleQ>"\"" { /* closing quote => end of title */ + BEGIN(St_TitleA); + return 0; + } +<St_TitleQ>\n { /* new line => end of title */ + unput(*yytext); + return 0; + } +<St_TitleA>{BLANK}*{ID}{BLANK}*"="{BLANK}* { // title attribute + g_token->name = yytext; + g_token->name = g_token->name.left( + g_token->name.find('=')).stripWhiteSpace(); + BEGIN(St_TitleV); + } +<St_TitleV>[^ \t\r\n]+ { // attribute value + g_token->chars = yytext; + BEGIN(St_TitleN); + return TK_WORD; + } +<St_TitleV,St_TitleA>. { + unput(*yytext); + return 0; + } +<St_TitleV,St_TitleA>\n { + return 0; + } + +<St_Anchor>{LABELID}{WS}? { // anchor + g_token->name = QCString(yytext).stripWhiteSpace(); + return TK_WORD; + } +<St_Anchor>. { + unput(*yytext); + return 0; + } +<St_Cite>{CITEID} { // label to cite + g_token->name=yytext; + return TK_WORD; + } +<St_Cite>{BLANK} { // white space + unput(' '); + return 0; + } +<St_Cite>\n { // new line + unput(*yytext); + return 0; + } +<St_Cite>. { // any other character + unput(*yytext); + return 0; + } +<St_Ref>{REFWORD} { // label to refer to + g_token->name=yytext; + return TK_WORD; + } +<St_Ref>{BLANK} { // white space + unput(' '); + return 0; + } +<St_Ref>{WS}+"\""{WS}* { // white space following by quoted string + BEGIN(St_Ref2); + } +<St_Ref>\n { // new line + unput(*yytext); + return 0; + } +<St_Ref>. { // any other character + unput(*yytext); + return 0; + } +<St_IntRef>[A-Z_a-z0-9.:/#\-\+\(\)]+ { + g_token->name = yytext; + return TK_WORD; + } +<St_IntRef>{BLANK}+"\"" { + BEGIN(St_Ref2); + } +<St_Ref2>"&"{ID}";" { /* symbol */ + g_token->name = yytext; + return TK_SYMBOL; + } +<St_Ref2>{SPCMD1} | +<St_Ref2>{SPCMD2} { /* special command */ + g_token->name = yytext+1; + g_token->paramDir=TokenInfo::Unspecified; + return TK_COMMAND; + } +<St_Ref2>{WORD1NQ} | +<St_Ref2>{WORD2NQ} { + /* word */ + g_token->name = yytext; + return TK_WORD; + } +<St_Ref2>[ \t]+ { + g_token->chars=yytext; + return TK_WHITESPACE; + } +<St_Ref2>"\""|\n { /* " or \n => end of title */ + return 0; + } +<St_XRefItem>{LABELID} { + g_token->name=yytext; + } +<St_XRefItem>" " { + BEGIN(St_XRefItem2); + } +<St_XRefItem2>[0-9]+"." { + QCString numStr=yytext; + numStr=numStr.left((int)yyleng-1); + g_token->id=numStr.toInt(); + return RetVal_OK; + } +<St_Para,St_Title,St_Ref2>"<!--" { /* html style comment block */ + g_commentState = YY_START; + BEGIN(St_Comment); + } +<St_Param>"\""[^\n\"]+"\"" { + g_token->name = yytext+1; + g_token->name = g_token->name.left((int)yyleng-2); + return TK_WORD; + } +<St_Param>({PHPTYPE}{BLANK}*"|"{BLANK}*)*{PHPTYPE}{WS}+("&")?"$"{LABELID} { + QCString params = yytext; + int j = params.find('&'); + int i = params.find('$'); + if (j<i && j!=-1) i=j; + QCString types = params.left(i).stripWhiteSpace(); + g_token->name = types+"#"+params.mid(i); + return TK_WORD; + } +<St_Param>[^ \t\n,]+ { + g_token->name = yytext; + return TK_WORD; + } +<St_Param>{WS}*","{WS}* /* param separator */ +<St_Param>{WS} { + g_token->chars=yytext; + return TK_WHITESPACE; + } +<St_File>{FILEMASK} { + g_token->name = yytext; + return TK_WORD; + } +<St_File>"\""[^\n\"]+"\"" { + QCString text=yytext; + g_token->name = text.mid(1,text.length()-2); + return TK_WORD; + } +<St_Pattern>[^\r\n]+ { + g_token->name = yytext; + g_token->name = g_token->name.stripWhiteSpace(); + return TK_WORD; + } +<St_Link>{LINKMASK}|{REFWORD} { + g_token->name = yytext; + return TK_WORD; + } +<St_Comment>"-->" { /* end of html comment */ + BEGIN(g_commentState); + } +<St_Comment>[^-\n]+ /* inside html comment */ +<St_Comment>. /* inside html comment */ + + /* State for skipping title (all chars until the end of the line) */ + +<St_SkipTitle>. +<St_SkipTitle>\n { return 0; } + + /* State for the pass used to find the anchors and sections */ + +<St_Sections>[^\n@\\]+ +<St_Sections>"@@"|"\\\\" +<St_Sections>{CMD}"anchor"{BLANK}+ { + g_secType = SectionInfo::Anchor; + BEGIN(St_SecLabel1); + } +<St_Sections>{CMD}"section"{BLANK}+ { + g_secType = SectionInfo::Section; + BEGIN(St_SecLabel2); + } +<St_Sections>{CMD}"subsection"{BLANK}+ { + g_secType = SectionInfo::Subsection; + BEGIN(St_SecLabel2); + } +<St_Sections>{CMD}"subsubsection"{BLANK}+ { + g_secType = SectionInfo::Subsubsection; + BEGIN(St_SecLabel2); + } +<St_Sections>{CMD}"paragraph"{BLANK}+ { + g_secType = SectionInfo::Paragraph; + BEGIN(St_SecLabel2); + } +<St_Sections>{CMD}"verbatim"/[^a-z_A-Z0-9] { + g_endMarker="endverbatim"; + BEGIN(St_SecSkip); + } +<St_Sections>{CMD}"dot"/[^a-z_A-Z0-9] { + g_endMarker="enddot"; + BEGIN(St_SecSkip); + } +<St_Sections>{CMD}"msc"/[^a-z_A-Z0-9] { + g_endMarker="endmsc"; + BEGIN(St_SecSkip); + } +<St_Sections>{CMD}"htmlonly"/[^a-z_A-Z0-9] { + g_endMarker="endhtmlonly"; + BEGIN(St_SecSkip); + } +<St_Sections>{CMD}"latexonly"/[^a-z_A-Z0-9] { + g_endMarker="endlatexonly"; + BEGIN(St_SecSkip); + } +<St_Sections>{CMD}"xmlonly"/[^a-z_A-Z0-9] { + g_endMarker="endxmlonly"; + BEGIN(St_SecSkip); + } +<St_Sections>{CMD}"code"/[^a-z_A-Z0-9] { + g_endMarker="endcode"; + BEGIN(St_SecSkip); + } +<St_Sections>"<!--" { + g_endMarker="-->"; + BEGIN(St_SecSkip); + } +<St_SecSkip>{CMD}{ID} { + if (strcmp(yytext+1,g_endMarker)==0) + { + BEGIN(St_Sections); + } + } +<St_SecSkip>"-->" { + if (strcmp(yytext,g_endMarker)==0) + { + BEGIN(St_Sections); + } + } +<St_SecSkip>[^a-z_A-Z0-9\-\\\@]+ +<St_SecSkip>. +<St_SecSkip>\n +<St_Sections>. +<St_Sections>\n +<St_SecLabel1>{LABELID} { + g_secLabel = yytext; + processSection(); + BEGIN(St_Sections); + } +<St_SecLabel2>{LABELID}{BLANK}+ | +<St_SecLabel2>{LABELID} { + g_secLabel = yytext; + g_secLabel = g_secLabel.stripWhiteSpace(); + BEGIN(St_SecTitle); + } +<St_SecTitle>[^\n]+ | +<St_SecTitle>[^\n]*\n { + g_secTitle = yytext; + g_secTitle = g_secTitle.stripWhiteSpace(); + processSection(); + BEGIN(St_Sections); + } +<St_SecTitle,St_SecLabel1,St_SecLabel2>. { + warn(g_fileName,yylineno,"warning: Unexpected character `%s' while looking for section label or title",yytext); + } + +<St_Snippet>[^\n]+ | +<St_Snippet>[^\n]*\n { + g_token->name = yytext; + g_token->name = g_token->name.stripWhiteSpace(); + return TK_WORD; + } + + /* Generic rules that work for all states */ +<*>\n { + warn(g_fileName,yylineno,"warning: Unexpected new line character"); + } +<*>[\\@<>&$#%~"=] { /* unescaped special character */ + //warn(g_fileName,yylineno,"warning: Unexpected character `%s', assuming command \\%s was meant.",yytext,yytext); + g_token->name = yytext; + return TK_COMMAND; + } +<*>. { + warn(g_fileName,yylineno,"warning: Unexpected character `%s'",yytext); + } +%% + +//-------------------------------------------------------------------------- + +void doctokenizerYYFindSections(const char *input,Definition *d, + MemberGroup *mg,const char *fileName) +{ + if (input==0) return; + g_inputString = input; + //printf("parsing --->`%s'<---\n",input); + g_inputPos = 0; + g_definition = d; + g_memberGroup = mg; + g_fileName = fileName; + BEGIN(St_Sections); + doctokenizerYYlineno = 1; + doctokenizerYYlex(); +} + +void doctokenizerYYinit(const char *input,const char *fileName) +{ + g_inputString = input; + g_inputPos = 0; + g_fileName = fileName; + g_insidePre = FALSE; + BEGIN(St_Para); +} + +void doctokenizerYYsetStatePara() +{ + BEGIN(St_Para); +} + +void doctokenizerYYsetStateTitle() +{ + BEGIN(St_Title); +} + +void doctokenizerYYsetStateTitleAttrValue() +{ + BEGIN(St_TitleV); +} + +void doctokenizerYYsetStateCode() +{ + g_token->verb=""; + g_token->name=""; + BEGIN(St_CodeOpt); +} + +void doctokenizerYYsetStateXmlCode() +{ + g_token->verb=""; + g_token->name=""; + BEGIN(St_XmlCode); +} + +void doctokenizerYYsetStateHtmlOnly() +{ + g_token->verb=""; + BEGIN(St_HtmlOnly); +} + +void doctokenizerYYsetStateManOnly() +{ + g_token->verb=""; + BEGIN(St_ManOnly); +} + +void doctokenizerYYsetStateXmlOnly() +{ + g_token->verb=""; + BEGIN(St_XmlOnly); +} + +void doctokenizerYYsetStateLatexOnly() +{ + g_token->verb=""; + BEGIN(St_LatexOnly); +} + +void doctokenizerYYsetStateVerbatim() +{ + g_token->verb=""; + BEGIN(St_Verbatim); +} + +void doctokenizerYYsetStateDot() +{ + g_token->verb=""; + BEGIN(St_Dot); +} + +void doctokenizerYYsetStateMsc() +{ + g_token->verb=""; + BEGIN(St_Msc); +} + +void doctokenizerYYsetStateParam() +{ + BEGIN(St_Param); +} + +void doctokenizerYYsetStateXRefItem() +{ + BEGIN(St_XRefItem); +} + +void doctokenizerYYsetStateFile() +{ + BEGIN(St_File); +} + +void doctokenizerYYsetStatePattern() +{ + BEGIN(St_Pattern); +} + +void doctokenizerYYsetStateLink() +{ + BEGIN(St_Link); +} + +void doctokenizerYYsetStateCite() +{ + BEGIN(St_Cite); +} + +void doctokenizerYYsetStateRef() +{ + BEGIN(St_Ref); +} + +void doctokenizerYYsetStateInternalRef() +{ + BEGIN(St_IntRef); +} + +void doctokenizerYYsetStateText() +{ + BEGIN(St_Text); +} + +void doctokenizerYYsetStateSkipTitle() +{ + BEGIN(St_SkipTitle); +} + +void doctokenizerYYsetStateAnchor() +{ + BEGIN(St_Anchor); +} + +void doctokenizerYYsetStateSnippet() +{ + BEGIN(St_Snippet); +} + +void doctokenizerYYcleanup() +{ + yy_delete_buffer( YY_CURRENT_BUFFER ); +} + +void doctokenizerYYsetInsidePre(bool b) +{ + g_insidePre = b; +} + +void doctokenizerYYpushBackHtmlTag(const char *tag) +{ + QCString tagName = tag; + int i,l = tagName.length(); + unput('>'); + for (i=l-1;i>=0;i--) + { + unput(tag[i]); + } + unput('<'); +} + +#if !defined(YY_FLEX_SUBMINOR_VERSION) +extern "C" { // some bogus code to keep the compiler happy + void doctokenizerYYdummy() { yy_flex_realloc(0,0); } +} +#endif + diff --git a/trunk/src/docvisitor.h b/trunk/src/docvisitor.h new file mode 100644 index 0000000..c9acf64 --- /dev/null +++ b/trunk/src/docvisitor.h @@ -0,0 +1,191 @@ +/****************************************************************************** + * + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#ifndef _DOCVISITOR_H +#define _DOCVISITOR_H + +// ids +const int DocVisitor_Html = 0; +const int DocVisitor_Latex = 1; +const int DocVisitor_XML = 2; +const int DocVisitor_RTF = 3; +const int DocVisitor_Man = 4; +const int DocVisitor_Text = 5; +const int DocVisitor_Other = 6; + +// forward declarations +class DocWord; +class DocWhiteSpace; +class DocAutoList; +class DocAutoListItem; +class DocPara; +class DocRoot; +class DocSymbol; +class DocURL; +class DocStyleChange; +class DocSimpleSect; +class DocTitle; +class DocSimpleList; +class DocSimpleListItem; +class DocSection; +class DocVerbatim; +class DocXRefItem; +class DocHtmlList; +class DocHtmlListItem; +class DocHtmlDescList; +class DocHtmlDescTitle; +class DocHtmlDescData; +class DocHtmlTable; +class DocHtmlRow; +class DocHtmlCell; +class DocHtmlCaption; +class DocLineBreak; +class DocHorRuler; +class DocAnchor; +class DocIndexEntry; +class DocInternal; +class DocHRef; +class DocInclude; +class DocIncOperator; +class DocHtmlHeader; +class DocImage; +class DocDotFile; +class DocMscFile; +class DocLink; +class DocCite; +class DocRef; +class DocFormula; +class DocSecRefItem; +class DocSecRefList; +class DocLinkedWord; +class DocParamSect; +class DocParamList; +class DocInternalRef; +class DocCopy; // TODO: no longer generated => remove +class DocText; +class DocSimpleSectSep; +class DocHtmlBlockQuote; + +/*! @brief Abstract visitor that participates in the visitor pattern. + */ +class DocVisitor +{ + int m_id; + public: + DocVisitor(int id) : m_id(id) {} + virtual ~DocVisitor() {} + int id() const { return m_id; } + + /*! @name Visitor functions for leaf nodes + * @{ + */ + virtual void visit(DocWord *) = 0; + virtual void visit(DocWhiteSpace *) = 0; + virtual void visit(DocSymbol *) = 0; + virtual void visit(DocURL *) = 0; + virtual void visit(DocStyleChange *) = 0; + virtual void visit(DocVerbatim *) = 0; + virtual void visit(DocLineBreak *) = 0; + virtual void visit(DocHorRuler *) = 0; + virtual void visit(DocAnchor *) = 0; + virtual void visit(DocInclude *) = 0; + virtual void visit(DocIncOperator *) = 0; + virtual void visit(DocFormula *) = 0; + virtual void visit(DocLinkedWord *) = 0; + virtual void visit(DocIndexEntry *) = 0; + virtual void visit(DocSimpleSectSep *) = 0; + virtual void visit(DocCite *) = 0; + /*! @} */ + + /*! @name Visitor functions for internal nodes + * @{ + */ + virtual void visitPre(DocAutoList *) = 0; + virtual void visitPost(DocAutoList *) = 0; + virtual void visitPre(DocAutoListItem *) = 0; + virtual void visitPost(DocAutoListItem *) = 0; + virtual void visitPre(DocPara *) = 0; + virtual void visitPost(DocPara *) = 0; + virtual void visitPre(DocRoot *) = 0; + virtual void visitPost(DocRoot *) = 0; + virtual void visitPre(DocSimpleSect *) = 0; + virtual void visitPost(DocSimpleSect *) = 0; + virtual void visitPre(DocTitle *) = 0; + virtual void visitPost(DocTitle *) = 0; + virtual void visitPre(DocSimpleList *) = 0; + virtual void visitPost(DocSimpleList *) = 0; + virtual void visitPre(DocSimpleListItem *) = 0; + virtual void visitPost(DocSimpleListItem *) = 0; + virtual void visitPre(DocSection *) = 0; + virtual void visitPost(DocSection *) = 0; + virtual void visitPre(DocHtmlList *) = 0; + virtual void visitPost(DocHtmlListItem *) = 0; + virtual void visitPre(DocHtmlListItem *) = 0; + virtual void visitPost(DocHtmlList *) = 0; + virtual void visitPre(DocHtmlDescList *) = 0; + virtual void visitPost(DocHtmlDescList *) = 0; + virtual void visitPre(DocHtmlDescTitle *) = 0; + virtual void visitPost(DocHtmlDescTitle *) = 0; + virtual void visitPre(DocHtmlDescData *) = 0; + virtual void visitPost(DocHtmlDescData *) = 0; + virtual void visitPre(DocHtmlTable *) = 0; + virtual void visitPost(DocHtmlRow *) = 0; + virtual void visitPre(DocHtmlCell *) = 0; + virtual void visitPost(DocHtmlCell *) = 0; + virtual void visitPre(DocHtmlRow *) = 0; + virtual void visitPost(DocHtmlTable *) = 0; + virtual void visitPre(DocHtmlCaption *) = 0; + virtual void visitPost(DocHtmlCaption *) = 0; + virtual void visitPre(DocInternal *) = 0; + virtual void visitPost(DocInternal *) = 0; + virtual void visitPre(DocHRef *) = 0; + virtual void visitPost(DocHRef *) = 0; + virtual void visitPre(DocHtmlHeader *) = 0; + virtual void visitPost(DocHtmlHeader *) = 0; + virtual void visitPre(DocImage *) = 0; + virtual void visitPost(DocImage *) = 0; + virtual void visitPre(DocDotFile *) = 0; + virtual void visitPost(DocDotFile *) = 0; + virtual void visitPre(DocMscFile *) = 0; + virtual void visitPost(DocMscFile *) = 0; + virtual void visitPre(DocLink *) = 0; + virtual void visitPost(DocLink *) = 0; + virtual void visitPre(DocRef *) = 0; + virtual void visitPost(DocRef *) = 0; + virtual void visitPre(DocSecRefItem *) = 0; + virtual void visitPost(DocSecRefItem *) = 0; + virtual void visitPre(DocSecRefList *) = 0; + virtual void visitPost(DocSecRefList *) = 0; + virtual void visitPre(DocParamSect *) = 0; + virtual void visitPost(DocParamSect *) = 0; + virtual void visitPre(DocParamList *) = 0; + virtual void visitPost(DocParamList *) = 0; + virtual void visitPre(DocXRefItem *) = 0; + virtual void visitPost(DocXRefItem *) = 0; + virtual void visitPre(DocInternalRef *) = 0; + virtual void visitPost(DocInternalRef *) = 0; + virtual void visitPre(DocCopy *) = 0; + virtual void visitPost(DocCopy *) = 0; + virtual void visitPre(DocText *) = 0; + virtual void visitPost(DocText *) = 0; + virtual void visitPre(DocHtmlBlockQuote *) = 0; + virtual void visitPost(DocHtmlBlockQuote *) = 0; + /*! @} */ +}; + +#endif diff --git a/trunk/src/dot.cpp b/trunk/src/dot.cpp new file mode 100644 index 0000000..e178ef1 --- /dev/null +++ b/trunk/src/dot.cpp @@ -0,0 +1,4576 @@ +/***************************************************************************** + * + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#ifdef _WIN32 +#include <windows.h> +#define BITMAP W_BITMAP +#endif + +#include <stdlib.h> + +#include "dot.h" +#include "doxygen.h" +#include "message.h" +#include "util.h" +#include "config.h" +#include "language.h" +#include "defargs.h" +#include "docparser.h" +#include "debug.h" +#include "pagedef.h" +#include "portable.h" +#include "dirdef.h" +#include "vhdldocgen.h" +#include <qdir.h> +#include <qfile.h> +#include "ftextstream.h" +#include "md5.h" +#include <qqueue.h> + +#include <qthread.h> +#include <qmutex.h> +#include <qwaitcondition.h> + +#define MAP_CMD "cmapx" + +//#define FONTNAME "Helvetica" +#define FONTNAME getDotFontName() +#define FONTSIZE getDotFontSize() + +//-------------------------------------------------------------------- + +static const char svgZoomHeader[] = +"<svg id=\"main\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xml:space=\"preserve\" onload=\"init(evt)\">\n" +" <defs>\n" +" <circle id=\"rim\" cx=\"0\" cy=\"0\" r=\"7\"/>\n" +" <circle id=\"rim2\" cx=\"0\" cy=\"0\" r=\"3.5\"/>\n" +" <g id=\"zoomPlus\">\n" +" <use xlink:href=\"#rim\" fill=\"#404040\">\n" +" <set attributeName=\"fill\" to=\"#808080\" begin=\"zoomplus.mouseover\" end=\"zoomplus.mouseout\"/>\n" +" </use>\n" +" <path d=\"M-4,0h8M0,-4v8\" fill=\"none\" stroke=\"white\" stroke-width=\"1.5\" pointer-events=\"none\"/>\n" +" </g>\n" +" <g id=\"zoomMin\">\n" +" <use xlink:href=\"#rim\" fill=\"#404040\">\n" +" <set attributeName=\"fill\" to=\"#808080\" begin=\"zoomminus.mouseover\" end=\"zoomminus.mouseout\"/>\n" +" </use>\n" +" <path d=\"M-4,0h8\" fill=\"none\" stroke=\"white\" stroke-width=\"1.5\" pointer-events=\"none\"/>\n" +" </g>\n" +" <g id=\"dirArrow\">\n" +" <path fill=\"none\" stroke=\"white\" stroke-width=\"1.5\" d=\"M0,-3.0v7 M-2.5,-0.5L0,-3.0L2.5,-0.5\"/>\n" +" </g>\n" +" <g id=\"resetDef\">\n" +" <use xlink:href=\"#rim2\" fill=\"#404040\">\n" +" <set attributeName=\"fill\" to=\"#808080\" begin=\"reset.mouseover\" end=\"reset.mouseout\"/>\n" +" </use>\n" +" </g>\n" +" </defs>\n" +"\n" +"<script type=\"text/javascript\">\n" +; + +static const char svgZoomFooter[] = +" <g id=\"navigator\" transform=\"translate(0 0)\" fill=\"#404254\">\n" +" <rect fill=\"#f2f5e9\" fill-opacity=\"0.5\" stroke=\"#606060\" stroke-width=\".5\" x=\"0\" y=\"0\" width=\"60\" height=\"60\"/>\n" +" <use id=\"zoomplus\" xlink:href=\"#zoomPlus\" x=\"17\" y=\"9\" onmousedown=\"handleZoom(evt,'in')\"/>\n" +" <use id=\"zoomminus\" xlink:href=\"#zoomMin\" x=\"42\" y=\"9\" onmousedown=\"handleZoom(evt,'out')\"/>\n" +" <use id=\"reset\" xlink:href=\"#resetDef\" x=\"30\" y=\"36\" onmousedown=\"handleReset()\"/>\n" +" <g id=\"arrowUp\" xlink:href=\"#dirArrow\" transform=\"translate(30 24)\" onmousedown=\"handlePan(0,-1)\">\n" +" <use xlink:href=\"#rim\" fill=\"#404040\">\n" +" <set attributeName=\"fill\" to=\"#808080\" begin=\"arrowUp.mouseover\" end=\"arrowUp.mouseout\"/>\n" +" </use>\n" +" <path fill=\"none\" stroke=\"white\" stroke-width=\"1.5\" d=\"M0,-3.0v7 M-2.5,-0.5L0,-3.0L2.5,-0.5\"/>\n" +" </g>\n" +" <g id=\"arrowRight\" xlink:href=\"#dirArrow\" transform=\"rotate(90) translate(36 -43)\" onmousedown=\"handlePan(1,0)\">\n" +" <use xlink:href=\"#rim\" fill=\"#404040\">\n" +" <set attributeName=\"fill\" to=\"#808080\" begin=\"arrowRight.mouseover\" end=\"arrowRight.mouseout\"/>\n" +" </use>\n" +" <path fill=\"none\" stroke=\"white\" stroke-width=\"1.5\" d=\"M0,-3.0v7 M-2.5,-0.5L0,-3.0L2.5,-0.5\"/>\n" +" </g>\n" +" <g id=\"arrowDown\" xlink:href=\"#dirArrow\" transform=\"rotate(180) translate(-30 -48)\" onmousedown=\"handlePan(0,1)\">\n" +" <use xlink:href=\"#rim\" fill=\"#404040\">\n" +" <set attributeName=\"fill\" to=\"#808080\" begin=\"arrowDown.mouseover\" end=\"arrowDown.mouseout\"/>\n" +" </use>\n" +" <path fill=\"none\" stroke=\"white\" stroke-width=\"1.5\" d=\"M0,-3.0v7 M-2.5,-0.5L0,-3.0L2.5,-0.5\"/>\n" +" </g>\n" +" <g id=\"arrowLeft\" xlink:href=\"#dirArrow\" transform=\"rotate(270) translate(-36 17)\" onmousedown=\"handlePan(-1,0)\">\n" +" <use xlink:href=\"#rim\" fill=\"#404040\">\n" +" <set attributeName=\"fill\" to=\"#808080\" begin=\"arrowLeft.mouseover\" end=\"arrowLeft.mouseout\"/>\n" +" </use>\n" +" <path fill=\"none\" stroke=\"white\" stroke-width=\"1.5\" d=\"M0,-3.0v7 M-2.5,-0.5L0,-3.0L2.5,-0.5\"/>\n" +" </g>\n" +" </g>\n" +" <svg viewBox=\"0 0 25 25\" width=\"100%\" height=\"30px\" preserveAspectRatio=\"xMaxYMin meet\"> \n" +" <g id=\"printButton\" transform=\"scale(0.4 0.4)\" onmousedown=\"handlePrint(evt)\">\n" +" <rect height=\"23.33753581\" id=\"paper\" rx=\"2\" style=\"fill:#f2f5e9;fill-rule:evenodd;stroke:#111111;stroke-width:3.224;stroke-linejoin:round;\" transform=\"matrix(1.000000,0.000000,-0.339266,0.940691,0.000000,0.000000)\" width=\"25.55231285\" x=\"26.69387353\" y=\"7.36162977\"/>\n" +" <rect height=\"26.272097\" id=\"body\" rx=\"2\" style=\"fill:#404040;fill-rule:evenodd;stroke:#111111;stroke-width:3.125;stroke-linejoin:round;\" width=\"50\" x=\"4.5295201\" y=\"27.078951\"/>\n" +" <rect height=\"8.27750969\" id=\"tray\" style=\"fill:#d2d5c9;fill-rule:evenodd;stroke:#111111;stroke-width:3.125;stroke-linecap:round;stroke-linejoin:round;\" width=\"40\" x=\"10.28778839\" y=\"44.96812282\"/>\n" +" </g>\n" +" </svg>\n" +"</svg>\n" +; + +//-------------------------------------------------------------------- + +static const int maxCmdLine = 40960; + +/*! mapping from protection levels to color names */ +static const char *normalEdgeColorMap[] = +{ + "midnightblue", // Public + "darkgreen", // Protected + "firebrick4", // Private + "darkorchid3", // "use" relation + "grey75", // Undocumented + "orange" // template relation +}; + +static const char *normalArrowStyleMap[] = +{ + "empty", // Public + "empty", // Protected + "empty", // Private + "open", // "use" relation + 0, // Undocumented + 0 // template relation +}; + +static const char *normalEdgeStyleMap[] = +{ + "solid", // inheritance + "dashed" // usage +}; + +static const char *umlEdgeColorMap[] = +{ + "midnightblue", // Public + "darkgreen", // Protected + "firebrick4", // Private + "grey25", // "use" relation + "grey75", // Undocumented + "orange" // template relation +}; + +static const char *umlArrowStyleMap[] = +{ + "onormal", // Public + "onormal", // Protected + "onormal", // Private + "odiamond", // "use" relation + 0, // Undocumented + 0 // template relation +}; + +static const char *umlEdgeStyleMap[] = +{ + "solid", // inheritance + "solid" // usage +}; + +struct EdgeProperties +{ + const char * const *edgeColorMap; + const char * const *arrowStyleMap; + const char * const *edgeStyleMap; +}; + +static EdgeProperties normalEdgeProps = +{ + normalEdgeColorMap, normalArrowStyleMap, normalEdgeStyleMap +}; + +static EdgeProperties umlEdgeProps = +{ + umlEdgeColorMap, umlArrowStyleMap, umlEdgeStyleMap +}; + + +static QCString getDotFontName() +{ + static QCString dotFontName = Config_getString("DOT_FONTNAME"); + if (dotFontName.isEmpty()) + { + //dotFontName="FreeSans.ttf"; + dotFontName="Helvetica"; + } + return dotFontName; +} + +static int getDotFontSize() +{ + static int dotFontSize = Config_getInt("DOT_FONTSIZE"); + if (dotFontSize<4) dotFontSize=4; + return dotFontSize; +} + +static void writeGraphHeader(FTextStream &t) +{ + static bool interactiveSVG = Config_getBool("INTERACTIVE_SVG"); + t << "digraph G" << endl; + t << "{" << endl; + if (interactiveSVG) // insert a comment to force regeneration when this + // option is toggled + { + t << " // INTERACTIVE_SVG=YES\n"; + } + if (Config_getBool("DOT_TRANSPARENT")) + { + t << " bgcolor=\"transparent\";" << endl; + } + t << " edge [fontname=\"" << FONTNAME << "\"," + "fontsize=\"" << FONTSIZE << "\"," + "labelfontname=\"" << FONTNAME << "\"," + "labelfontsize=\"" << FONTSIZE << "\"];\n"; + t << " node [fontname=\"" << FONTNAME << "\"," + "fontsize=\"" << FONTSIZE << "\",shape=record];\n"; +} + +static void writeGraphFooter(FTextStream &t) +{ + t << "}" << endl; +} + +static QCString replaceRef(const QCString &buf,const QCString relPath, + bool urlOnly,const QCString &context,const QCString &target=QCString()) +{ + // search for href="...", store ... part in link + QCString href = "href"; + //bool isXLink=FALSE; + int len = 6; + int indexS = buf.find("href=\""), indexE; + if (indexS>5 && buf.find("xlink:href=\"")!=-1) // XLink href (for SVG) + { + indexS-=6; + len+=6; + href.prepend("xlink:"); + //isXLink=TRUE; + } + if (indexS>=0 && (indexE=buf.find('"',indexS+len))!=-1) + { + QCString link = buf.mid(indexS+len,indexE-indexS-len); + QCString result; + if (urlOnly) // for user defined dot graphs + { + if (link.left(5)=="\\ref " || link.left(5)=="@ref ") // \ref url + { + result=href+"=\""; + // fake ref node to resolve the url + DocRef *df = new DocRef( (DocNode*) 0, link.mid(5), context ); + result+=externalRef(relPath,df->ref(),TRUE); + if (!df->file().isEmpty()) + result += df->file().data() + Doxygen::htmlFileExtension; + if (!df->anchor().isEmpty()) + result += "#" + df->anchor(); + delete df; + result += "\""; + } + else + { + result = href+"=\"" + link + "\""; + } + } + else // ref$url (external ref via tag file), or $url (local ref) + { + int marker = link.find('$'); + if (marker!=-1) + { + QCString ref = link.left(marker); + QCString url = link.mid(marker+1); + if (!ref.isEmpty()) + { + result = externalLinkTarget() + externalRef(relPath,ref,FALSE); + } + result+= href+"=\""; + result+=externalRef(relPath,ref,TRUE); + result+= url + "\""; + } + else // should not happen, but handle properly anyway + { + result = href+"=\"" + link + "\""; + } + } + if (!target.isEmpty()) + { + result+=" target=\""+target+"\""; + } + QCString leftPart = buf.left(indexS); + QCString rightPart = buf.mid(indexE+1); + return leftPart + result + rightPart; + } + else + { + return buf; + } +} + +/*! converts the rectangles in a client site image map into a stream + * \param t the stream to which the result is written. + * \param mapName the name of the map file. + * \param relPath the relative path to the root of the output directory + * (used in case CREATE_SUBDIRS is enabled). + * \param urlOnly if FALSE the url field in the map contains an external + * references followed by a $ and then the URL. + * \param context the context (file, class, or namespace) in which the + * map file was found + * \returns TRUE if succesful. + */ +static bool convertMapFile(FTextStream &t,const char *mapName, + const QCString relPath, bool urlOnly=FALSE, + const QCString &context=QCString()) +{ + QFile f(mapName); + if (!f.open(IO_ReadOnly)) + { + err("error: problems opening map file %s for inclusion in the docs!\n" + "If you installed Graphviz/dot after a previous failing run, \n" + "try deleting the output directory and rerun doxygen.\n",mapName); + return FALSE; + } + const int maxLineLen=10240; + while (!f.atEnd()) // foreach line + { + QCString buf(maxLineLen); + int numBytes = f.readLine(buf.data(),maxLineLen); + buf[numBytes-1]='\0'; + + if (buf.left(5)=="<area") + { + t << replaceRef(buf,relPath,urlOnly,context); + } + } + return TRUE; +} + +static QArray<int> s_newNumber; +static int s_max_newNumber=0; + +inline int reNumberNode(int number, bool doReNumbering) +{ + if (!doReNumbering) + { + return number; + } + else + { + int s = s_newNumber.size(); + if (number>=s) + { + int ns=0; + ns = s * 3 / 2 + 5; // new size + if (number>=ns) // number still doesn't fit + { + ns = number * 3 / 2 + 5; + } + s_newNumber.resize(ns); + for (int i=s;i<ns;i++) // clear new part of the array + { + s_newNumber.at(i)=0; + } + } + int i = s_newNumber.at(number); + if (i == 0) // not yet mapped + { + i = ++s_max_newNumber; // start from 1 + s_newNumber.at(number) = i; + } + return i; + } +} + +static void resetReNumbering() +{ + s_max_newNumber=0; + s_newNumber.resize(s_max_newNumber); +} + +static QCString g_dotFontPath; + +static void setDotFontPath(const char *path) +{ + ASSERT(g_dotFontPath.isEmpty()); + g_dotFontPath = portable_getenv("DOTFONTPATH"); + QCString newFontPath = Config_getString("DOT_FONTPATH"); + QCString spath = path; + if (!newFontPath.isEmpty() && !spath.isEmpty()) + { + newFontPath.prepend(spath+portable_pathListSeparator()); + } + else if (newFontPath.isEmpty() && !spath.isEmpty()) + { + newFontPath=path; + } + else + { + portable_unsetenv("DOTFONTPATH"); + return; + } + portable_setenv("DOTFONTPATH",newFontPath); +} + +static void unsetDotFontPath() +{ + if (g_dotFontPath.isEmpty()) + { + portable_unsetenv("DOTFONTPATH"); + } + else + { + portable_setenv("DOTFONTPATH",g_dotFontPath); + } + g_dotFontPath=""; +} + +static bool readBoundingBox(const char *fileName,int *width,int *height,bool isEps) +{ + QCString bb = isEps ? QCString("%%PageBoundingBox:") : QCString("/MediaBox ["); + QFile f(fileName); + if (!f.open(IO_ReadOnly|IO_Raw)) + { + //printf("readBoundingBox: could not open %s\n",fileName); + return FALSE; + } + const int maxLineLen=1024; + char buf[maxLineLen]; + while (!f.atEnd()) + { + int numBytes = f.readLine(buf,maxLineLen-1); // read line + if (numBytes>0) + { + buf[numBytes]='\0'; + const char *p = strstr(buf,bb); + if (p) // found PageBoundingBox or /MediaBox string + { + int x,y; + if (sscanf(p+bb.length(),"%d %d %d %d",&x,&y,width,height)!=4) + { + //printf("readBoundingBox sscanf fail\n"); + return FALSE; + } + return TRUE; + } + } + else // read error! + { + //printf("Read error %d!\n",numBytes); + return FALSE; + } + } + err("Failed to extract bounding box from generated diagram file %s\n",fileName); + return FALSE; +} + +static bool writeVecGfxFigure(FTextStream &out,const QCString &baseName, + const QCString &figureName) +{ + int width=400,height=550; + static bool usePdfLatex = Config_getBool("USE_PDFLATEX"); + if (usePdfLatex) + { + if (!readBoundingBox(figureName+".pdf",&width,&height,FALSE)) + { + //printf("writeVecGfxFigure()=0\n"); + return FALSE; + } + } + else + { + if (!readBoundingBox(figureName+".eps",&width,&height,TRUE)) + { + //printf("writeVecGfxFigure()=0\n"); + return FALSE; + } + } + //printf("Got PDF/EPS size %d,%d\n",width,height); + int maxWidth = 350; /* approx. page width in points, excl. margins */ + int maxHeight = 550; /* approx. page height in points, excl. margins */ + out << "\\nopagebreak\n" + "\\begin{figure}[H]\n" + "\\begin{center}\n" + "\\leavevmode\n"; + if (width>maxWidth || height>maxHeight) // figure too big for page + { + // c*width/maxWidth > c*height/maxHeight, where c=maxWidth*maxHeight>0 + if (width*maxHeight>height*maxWidth) + { + out << "\\includegraphics[width=" << maxWidth << "pt]"; + } + else + { + out << "\\includegraphics[height=" << maxHeight << "pt]"; + } + } + else + { + out << "\\includegraphics[width=" << width << "pt]"; + } + + out << "{" << baseName << "}\n" + "\\end{center}\n" + "\\end{figure}\n"; + + //printf("writeVecGfxFigure()=1\n"); + return TRUE; +} + +// extract size from a dot generated SVG file +static bool readSVGSize(const QCString &fileName,int *width,int *height) +{ + bool found=FALSE; + QFile f(fileName); + if (!f.open(IO_ReadOnly)) + { + return FALSE; + } + const int maxLineLen=4096; + char buf[maxLineLen]; + while (!f.atEnd() && !found) + { + int numBytes = f.readLine(buf,maxLineLen-1); // read line + if (numBytes>0) + { + buf[numBytes]='\0'; + if (strncmp(buf,"<!--zoomable ",13)==0) + { + *width=-1; + *height=-1; + sscanf(buf,"<!--zoomable %d",height); + //printf("Found zoomable for %s!\n",fileName.data()); + found=TRUE; + } + else if (sscanf(buf,"<svg width=\"%dpt\" height=\"%dpt\"",width,height)==2) + { + //printf("Found fixed size %dx%d for %s!\n",*width,*height,fileName.data()); + found=TRUE; + } + } + else // read error! + { + //printf("Read error %d!\n",numBytes); + return FALSE; + } + } + return TRUE; +} + +static void writeSVGNotSupported(FTextStream &out) +{ + out << "<p><b>This browser is not able to show SVG: try Firefox, Chrome, Safari, or Opera instead.</b></p>"; +} + +// check if a reference to a SVG figure can be written and does so if possible. +// return FALSE if not possible (for instance because the SVG file is not yet generated). +static bool writeSVGFigureLink(FTextStream &out,const QCString &relPath, + const QCString &baseName,const QCString &absImgName) +{ + int width=600,height=600; + if (!readSVGSize(absImgName,&width,&height)) + { + return FALSE; + } + if (width==-1) + { + if (height<=60) + height=60; + else + height+=40; // add some extra space for zooming + if (height>600) height=600; // clip to maximum height of 600 pixels + out << "<div class=\"zoom\">"; + //out << "<object type=\"image/svg+xml\" data=\"" + //out << "<embed type=\"image/svg+xml\" src=\"" + out << "<iframe scrolling=\"no\" frameborder=\"0\" src=\"" + << relPath << baseName << ".svg\" width=\"100%\" height=\"" << height << "\">"; + } + else + { + //out << "<object type=\"image/svg+xml\" data=\"" + //out << "<embed type=\"image/svg+xml\" src=\"" + out << "<iframe scrolling=\"no\" frameborder=\"0\" src=\"" + << relPath << baseName << ".svg\" width=\"" + << ((width*96+48)/72) << "\" height=\"" + << ((height*96+48)/72) << "\">"; + } + writeSVGNotSupported(out); + //out << "</object>"; + //out << "</embed>"; + out << "</iframe>"; + if (width==-1) + { + out << "</div>"; + } + + return TRUE; +} + +// since dot silently reproduces the input file when it does not +// support the PNG format, we need to check the result. +static void checkDotResult(const QCString &imgName) +{ + if (Config_getEnum("DOT_IMAGE_FORMAT")=="png") + { + FILE *f = fopen(imgName,"rb"); + if (f) + { + char data[4]; + if (fread(data,1,4,f)==4) + { + if (!(data[1]=='P' && data[2]=='N' && data[3]=='G')) + { + err("error: Image `%s' produced by dot is not a valid PNG!\n" + "You should either select a different format " + "(DOT_IMAGE_FORMAT in the config file) or install a more " + "recent version of graphviz (1.7+)\n",imgName.data() + ); + } + } + else + { + err("error: Could not read image `%s' generated by dot!\n",imgName.data()); + } + fclose(f); + } + else + { + err("error: Could not open image `%s' generated by dot!\n",imgName.data()); + } + } +} + +static bool insertMapFile(FTextStream &out,const QCString &mapFile, + const QCString &relPath,const QCString &mapLabel) +{ + QFileInfo fi(mapFile); + if (fi.exists() && fi.size()>0) // reuse existing map file + { + QGString tmpstr; + FTextStream tmpout(&tmpstr); + convertMapFile(tmpout,mapFile,relPath); + if (!tmpstr.isEmpty()) + { + out << "<map name=\"" << mapLabel << "\" id=\"" << mapLabel << "\">" << endl; + out << tmpstr; + out << "</map>" << endl; + } + return TRUE; + } + return FALSE; // no map file yet, need to generate it +} + +static void removeDotGraph(const QCString &dotName) +{ + static bool dotCleanUp = Config_getBool("DOT_CLEANUP"); + if (dotCleanUp) + { + QDir d; + d.remove(dotName); + } +} + + + +/*! Checks if a file "baseName".md5 exists. If so the contents + * are compared with \a md5. If equal FALSE is returned. If the .md5 + * file does not exist or its contents are not equal to \a md5, + * a new .md5 is generated with the \a md5 string as contents. + */ +static bool checkAndUpdateMd5Signature(const QCString &baseName,const QCString &md5) +{ + QFile f(baseName+".md5"); + if (f.open(IO_ReadOnly)) + { + // read checksum + QCString md5stored(33); + int bytesRead=f.readBlock(md5stored.data(),32); + md5stored[32]='\0'; + // compare checksum + if (bytesRead==32 && md5==md5stored) + { + // bail out if equal + return FALSE; + } + } + f.close(); + // create checksum file + if (f.open(IO_WriteOnly)) + { + f.writeBlock(md5.data(),32); + f.close(); + } + return TRUE; +} + +static bool checkDeliverables(const QCString &file1, + const QCString &file2=QCString()) +{ + bool file1Ok = TRUE; + bool file2Ok = TRUE; + if (!file1.isEmpty()) + { + QFileInfo fi(file1); + file1Ok = (fi.exists() && fi.size()>0); + } + if (!file2.isEmpty()) + { + QFileInfo fi(file2); + file2Ok = (fi.exists() && fi.size()>0); + } + return file1Ok && file2Ok; +} + +//-------------------------------------------------------------------- + +class DotNodeList : public QList<DotNode> +{ + public: + DotNodeList() : QList<DotNode>() {} + ~DotNodeList() {} + int compareItems(GCI item1,GCI item2) + { + return stricmp(((DotNode *)item1)->m_label,((DotNode *)item2)->m_label); + } +}; + +//-------------------------------------------------------------------- + +DotRunner::DotRunner(const QCString &file,const QCString &path, + bool checkResult,const QCString &imageName) + : m_file(file), m_path(path), + m_checkResult(checkResult), m_imageName(imageName) +{ + static bool dotCleanUp = Config_getBool("DOT_CLEANUP"); + m_cleanUp = dotCleanUp; + m_jobs.setAutoDelete(TRUE); +} + +void DotRunner::addJob(const char *format,const char *output) +{ + QCString args = QCString("-T")+format+" -o \""+output+"\""; + m_jobs.append(new QCString(args)); +} + +void DotRunner::addPostProcessing(const char *cmd,const char *args) +{ + m_postCmd = cmd; + m_postArgs = args; +} + +bool DotRunner::run() +{ + int exitCode=0; + QCString dotExe = Config_getString("DOT_PATH")+"dot"; + bool multiTargets = Config_getBool("DOT_MULTI_TARGETS"); + QCString dotArgs; + QListIterator<QCString> li(m_jobs); + QCString *s; + QCString file = m_file; + QCString path = m_path; + QCString imageName = m_imageName; + QCString postCmd = m_postCmd; + QCString postArgs = m_postArgs; + bool checkResult = m_checkResult; + bool cleanUp = m_cleanUp; + if (multiTargets) + { + dotArgs="\""+file+"\""; + for (li.toFirst();(s=li.current());++li) + { + dotArgs+=' '; + dotArgs+=*s; + } + if ((exitCode=portable_system(dotExe,dotArgs,FALSE))!=0) + { + goto error; + } + } + else + { + for (li.toFirst();(s=li.current());++li) + { + dotArgs="\""+file+"\" "+*s; + if ((exitCode=portable_system(dotExe,dotArgs,FALSE))!=0) + { + goto error; + } + } + } + if (!postCmd.isEmpty() && portable_system(postCmd,postArgs)!=0) + { + err("error: Problems running '%s' as a post-processing step for dot output\n",m_postCmd.data()); + return FALSE; + } + if (checkResult) checkDotResult(imageName); + if (cleanUp) + { + //printf("removing dot file %s\n",m_file.data()); + //QDir(path).remove(file); + m_cleanupItem.file = file; + m_cleanupItem.path = path; + } + return TRUE; +error: + err("Problems running dot: exit code=%d, command='%s', arguments='%s'\n", + exitCode,dotExe.data(),dotArgs.data()); + return FALSE; +} + +//-------------------------------------------------------------------- + +DotFilePatcher::DotFilePatcher(const char *patchFile) + : m_patchFile(patchFile) +{ + m_maps.setAutoDelete(TRUE); +} + +QCString DotFilePatcher::file() const +{ + return m_patchFile; +} + +int DotFilePatcher::addMap(const QCString &mapFile,const QCString &relPath, + bool urlOnly,const QCString &context,const QCString &label) +{ + int id = m_maps.count(); + Map *map = new Map; + map->mapFile = mapFile; + map->relPath = relPath; + map->urlOnly = urlOnly; + map->context = context; + map->label = label; + map->zoomable = FALSE; + map->graphId = -1; + m_maps.append(map); + return id; +} + +int DotFilePatcher::addFigure(const QCString &baseName, + const QCString &figureName,bool heightCheck) +{ + int id = m_maps.count(); + Map *map = new Map; + map->mapFile = figureName; + map->urlOnly = heightCheck; + map->label = baseName; + map->zoomable = FALSE; + map->graphId = -1; + m_maps.append(map); + return id; +} + +int DotFilePatcher::addSVGConversion(const QCString &relPath,bool urlOnly, + const QCString &context,bool zoomable, + int graphId) +{ + int id = m_maps.count(); + Map *map = new Map; + map->relPath = relPath; + map->urlOnly = urlOnly; + map->context = context; + map->zoomable = zoomable; + map->graphId = graphId; + m_maps.append(map); + return id; +} + +int DotFilePatcher::addSVGObject(const QCString &baseName, + const QCString &absImgName, + const QCString &relPath) +{ + int id = m_maps.count(); + Map *map = new Map; + map->mapFile = absImgName; + map->relPath = relPath; + map->label = baseName; + map->zoomable = FALSE; + map->graphId = -1; + m_maps.append(map); + return id; +} + +bool DotFilePatcher::run() +{ + //printf("DotFilePatcher::run(): %s\n",m_patchFile.data()); + static bool interactiveSVG = Config_getBool("INTERACTIVE_SVG"); + bool isSVGFile = m_patchFile.right(4)==".svg"; + int graphId = -1; + QCString relPath; + if (isSVGFile) + { + Map *map = m_maps.at(0); // there is only one 'map' for a SVG file + interactiveSVG = interactiveSVG && map->zoomable; + graphId = map->graphId; + relPath = map->relPath; + //printf("DotFilePatcher::addSVGConversion: file=%s zoomable=%d\n", + // m_patchFile.data(),map->zoomable); + } + QCString tmpName = m_patchFile+".tmp"; + if (!QDir::current().rename(m_patchFile,tmpName)) + { + err("Failed to rename file %s to %s!\n",m_patchFile.data(),tmpName.data()); + return FALSE; + } + QFile fi(tmpName); + QFile fo(m_patchFile); + if (!fi.open(IO_ReadOnly)) + { + err("error: problem opening file %s for patching!\n",tmpName.data()); + QDir::current().rename(tmpName,m_patchFile); + return FALSE; + } + if (!fo.open(IO_WriteOnly)) + { + err("error: problem opening file %s for patching!\n",m_patchFile.data()); + QDir::current().rename(tmpName,m_patchFile); + return FALSE; + } + FTextStream t(&fo); + const int maxLineLen=100*1024; + int lineNr=1; + int width,height; + bool insideHeader=FALSE; + bool replacedHeader=FALSE; + bool foundSize=FALSE; + while (!fi.atEnd()) // foreach line + { + QCString line(maxLineLen); + int numBytes = fi.readLine(line.data(),maxLineLen); + if (numBytes<=0) + { + break; + } + + //printf("line=[%s]\n",line.stripWhiteSpace().data()); + int i; + ASSERT(numBytes<maxLineLen); + if (isSVGFile) + { + if (interactiveSVG) + { + if (line.find("<svg")!=-1 && !replacedHeader) + { + int count; + count = sscanf(line.data(),"<svg width=\"%dpt\" height=\"%dpt\"",&width,&height); + //printf("width=%d height=%d\n",width,height); + foundSize = count==2 && (width>500 || height>450); + if (foundSize) insideHeader=TRUE; + } + else if (insideHeader && !replacedHeader && line.find("<title>")!=-1) + { + if (foundSize) + { + // insert special replacement header for interactive SVGs + t << "<!--zoomable " << height << " -->\n"; + t << svgZoomHeader; + t << "var viewWidth = " << width << ";\n"; + t << "var viewHeight = " << height << ";\n"; + if (graphId>=0) + { + t << "var sectionId = 'dynsection-" << graphId << "';\n"; + } + t << "</script>\n"; + t << "<script xlink:href=\"" << relPath << "svgpan.js\"/>\n"; + t << "<svg id=\"graph\" class=\"graph\">\n"; + t << "<g id=\"viewport\">\n"; + } + insideHeader=FALSE; + replacedHeader=TRUE; + } + } + if (!insideHeader || !foundSize) // copy SVG and replace refs, + // unless we are inside the header of the SVG. + // Then we replace it with another header. + { + Map *map = m_maps.at(0); // there is only one 'map' for a SVG file + t << replaceRef(line,map->relPath,map->urlOnly,map->context,"_top"); + } + } + else if ((i=line.find("<!-- SVG"))!=-1 || (i=line.find("[!-- SVG"))!=-1) + { + //printf("Found marker at %d\n",i); + int mapId=-1; + t << line.left(i); + int n = sscanf(line.data()+i+1,"!-- SVG %d",&mapId); + if (n==1 && mapId>=0 && mapId<(int)m_maps.count()) + { + int e = QMAX(line.find("--]"),line.find("-->")); + Map *map = m_maps.at(mapId); + //printf("DotFilePatcher::writeSVGFigure: file=%s zoomable=%d\n", + // m_patchFile.data(),map->zoomable); + if (!writeSVGFigureLink(t,map->relPath,map->label,map->mapFile)) + { + err("Problem extracting size from SVG file %s\n",map->mapFile.data()); + } + if (e!=-1) t << line.mid(e+3); + } + else // error invalid map id! + { + err("Found invalid SVG id in file %s!\n",m_patchFile.data()); + t << line.mid(i); + } + } + else if ((i=line.find("<!-- MAP"))!=-1) + { + int mapId=-1; + t << line.left(i); + int n = sscanf(line.data()+i,"<!-- MAP %d",&mapId); + if (n==1 && mapId>=0 && mapId<(int)m_maps.count()) + { + Map *map = m_maps.at(mapId); + //printf("patching MAP %d in file %s with contents of %s\n", + // mapId,m_patchFile.data(),map->mapFile.data()); + t << "<map name=\"" << map->label << "\" id=\"" << map->label << "\">" << endl; + convertMapFile(t,map->mapFile,map->relPath,map->urlOnly,map->context); + t << "</map>" << endl; + } + else // error invalid map id! + { + err("Found invalid MAP id in file %s!\n",m_patchFile.data()); + t << line.mid(i); + } + } + else if ((i=line.find("% FIG"))!=-1) + { + int mapId=-1; + int n = sscanf(line.data()+i+2,"FIG %d",&mapId); + //printf("line='%s' n=%d\n",line.data()+i,n); + if (n==1 && mapId>=0 && mapId<(int)m_maps.count()) + { + Map *map = m_maps.at(mapId); + //printf("patching FIG %d in file %s with contents of %s\n", + // mapId,m_patchFile.data(),map->mapFile.data()); + writeVecGfxFigure(t,map->label,map->mapFile); + } + else // error invalid map id! + { + err("Found invalid bounding FIG id in file %s!\n",mapId,m_patchFile.data()); + t << line; + } + } + else + { + t << line; + } + lineNr++; + } + if (isSVGFile && interactiveSVG && replacedHeader) + { + t << svgZoomFooter; + } + fi.close(); + QDir::current().remove(tmpName); + return TRUE; +} + +//-------------------------------------------------------------------- + +void DotRunnerQueue::enqueue(DotRunner *runner) +{ + QMutexLocker locker(&m_mutex); + m_queue.enqueue(runner); + m_bufferNotEmpty.wakeAll(); +} + +DotRunner *DotRunnerQueue::dequeue() +{ + QMutexLocker locker(&m_mutex); + while (m_queue.isEmpty()) + { + // wait until something is added to the queue + m_bufferNotEmpty.wait(&m_mutex); + } + DotRunner *result = m_queue.dequeue(); + return result; +} + +uint DotRunnerQueue::count() const +{ + QMutexLocker locker(&m_mutex); + return m_queue.count(); +} + +//-------------------------------------------------------------------- + +DotWorkerThread::DotWorkerThread(int id,DotRunnerQueue *queue) + : m_id(id), m_queue(queue) +{ + m_cleanupItems.setAutoDelete(TRUE); +} + +void DotWorkerThread::run() +{ + DotRunner *runner; + while ((runner=m_queue->dequeue())) + { + runner->run(); + DotRunner::CleanupItem cleanup = runner->cleanup(); + if (!cleanup.file.isEmpty()) + { + m_cleanupItems.append(new DotRunner::CleanupItem(cleanup)); + } + } +} + +void DotWorkerThread::cleanup() +{ + QListIterator<DotRunner::CleanupItem> it(m_cleanupItems); + DotRunner::CleanupItem *ci; + for (;(ci=it.current());++it) + { + QDir(ci->path).remove(ci->file); + } +} + +//-------------------------------------------------------------------- + +DotManager *DotManager::m_theInstance = 0; + +DotManager *DotManager::instance() +{ + if (!m_theInstance) + { + m_theInstance = new DotManager; + } + return m_theInstance; +} + +DotManager::DotManager() : m_dotMaps(1007) +{ + m_dotRuns.setAutoDelete(TRUE); + m_dotMaps.setAutoDelete(TRUE); + m_queue = new DotRunnerQueue; + int i; + int numThreads = QMIN(32,Config_getInt("DOT_NUM_THREADS")); + if (numThreads!=1) + { + if (numThreads==0) numThreads = QMAX(2,QThread::idealThreadCount()+1); + for (i=0;i<numThreads;i++) + { + DotWorkerThread *thread = new DotWorkerThread(i,m_queue); + thread->start(); + if (thread->isRunning()) + { + m_workers.append(thread); + } + else // no more threads available! + { + delete thread; + } + } + ASSERT(m_workers.count()>0); + } +} + +DotManager::~DotManager() +{ + delete m_queue; +} + +void DotManager::addRun(DotRunner *run) +{ + m_dotRuns.append(run); +} + +int DotManager::addMap(const QCString &file,const QCString &mapFile, + const QCString &relPath,bool urlOnly,const QCString &context, + const QCString &label) +{ + DotFilePatcher *map = m_dotMaps.find(file); + if (map==0) + { + map = new DotFilePatcher(file); + m_dotMaps.append(file,map); + } + return map->addMap(mapFile,relPath,urlOnly,context,label); +} + +int DotManager::addFigure(const QCString &file,const QCString &baseName, + const QCString &figureName,bool heightCheck) +{ + DotFilePatcher *map = m_dotMaps.find(file); + if (map==0) + { + map = new DotFilePatcher(file); + m_dotMaps.append(file,map); + } + return map->addFigure(baseName,figureName,heightCheck); +} + +int DotManager::addSVGConversion(const QCString &file,const QCString &relPath, + bool urlOnly,const QCString &context,bool zoomable, + int graphId) +{ + DotFilePatcher *map = m_dotMaps.find(file); + if (map==0) + { + map = new DotFilePatcher(file); + m_dotMaps.append(file,map); + } + return map->addSVGConversion(relPath,urlOnly,context,zoomable,graphId); +} + +int DotManager::addSVGObject(const QCString &file,const QCString &baseName, + const QCString &absImgName,const QCString &relPath) +{ + DotFilePatcher *map = m_dotMaps.find(file); + if (map==0) + { + map = new DotFilePatcher(file); + m_dotMaps.append(file,map); + } + return map->addSVGObject(baseName,absImgName,relPath); +} + +bool DotManager::run() +{ + uint numDotRuns = m_dotRuns.count(); + uint numDotMaps = m_dotMaps.count(); + if (numDotRuns+numDotMaps>1) + { + if (m_workers.count()==0) + { + msg("Generating dot graphs in single threaded mode...\n"); + } + else + { + msg("Generating dot graphs using %d parallel threads...\n",QMIN(numDotRuns+numDotMaps,m_workers.count())); + } + } + int i=1; + QListIterator<DotRunner> li(m_dotRuns); + + bool setPath=FALSE; + if (Config_getBool("GENERATE_HTML")) + { + setDotFontPath(Config_getString("HTML_OUTPUT")); + setPath=TRUE; + } + else if (Config_getBool("GENERATE_LATEX")) + { + setDotFontPath(Config_getString("LATEX_OUTPUT")); + setPath=TRUE; + } + else if (Config_getBool("GENERATE_RTF")) + { + setDotFontPath(Config_getString("RTF_OUTPUT")); + setPath=TRUE; + } + portable_sysTimerStart(); + // fill work queue with dot operations + DotRunner *dr; + int prev=1; + if (m_workers.count()==0) // no threads to work with + { + for (li.toFirst();(dr=li.current());++li) + { + msg("Running dot for graph %d/%d\n",prev,numDotRuns); + dr->run(); + prev++; + } + } + else // use multiple threads to run instances of dot in parallel + { + for (li.toFirst();(dr=li.current());++li) + { + m_queue->enqueue(dr); + } + // wait for the queue to become empty + while ((i=m_queue->count())>0) + { + i = numDotRuns - i; + while (i>=prev) + { + msg("Running dot for graph %d/%d\n",prev,numDotRuns); + prev++; + } + portable_sleep(100); + } + while ((int)numDotRuns>=prev) + { + msg("Running dot for graph %d/%d\n",prev,numDotRuns); + prev++; + } + // signal the workers we are done + for (i=0;i<(int)m_workers.count();i++) + { + m_queue->enqueue(0); // add terminator for each worker + } + // wait for the workers to finish + for (i=0;i<(int)m_workers.count();i++) + { + m_workers.at(i)->wait(); + } + // clean up dot files from main thread + for (i=0;i<(int)m_workers.count();i++) + { + m_workers.at(i)->cleanup(); + } + } + portable_sysTimerStop(); + if (setPath) + { + unsetDotFontPath(); + } + + // patch the output file and insert the maps and figures + i=1; + SDict<DotFilePatcher>::Iterator di(m_dotMaps); + DotFilePatcher *map; + // since patching the svg files may involve patching the header of the SVG + // (for zoomable SVGs), and patching the .html files requires reading that + // header after the SVG is patched, we first process the .svg files and + // then the other files. + for (di.toFirst();(map=di.current());++di) + { + if (map->file().right(4)==".svg") + { + msg("Patching output file %d/%d\n",i,numDotMaps); + if (!map->run()) return FALSE; + i++; + } + } + for (di.toFirst();(map=di.current());++di) + { + if (map->file().right(4)!=".svg") + { + msg("Patching output file %d/%d\n",i,numDotMaps); + if (!map->run()) return FALSE; + i++; + } + } + return TRUE; +} + + +//-------------------------------------------------------------------- + + +/*! helper function that deletes all nodes in a connected graph, given + * one of the graph's nodes + */ +static void deleteNodes(DotNode *node,SDict<DotNode> *skipNodes=0) +{ + //printf("deleteNodes skipNodes=%p\n",skipNodes); + static DotNodeList deletedNodes; + deletedNodes.setAutoDelete(TRUE); + node->deleteNode(deletedNodes,skipNodes); // collect nodes to be deleted. + deletedNodes.clear(); // actually remove the nodes. +} + +DotNode::DotNode(int n,const char *lab,const char *tip, const char *url, + bool isRoot,ClassDef *cd) + : m_subgraphId(-1) + , m_number(n) + , m_label(lab) + , m_tooltip(tip) + , m_url(url) + , m_parents(0) + , m_children(0) + , m_edgeInfo(0) + , m_deleted(FALSE) + , m_written(FALSE) + , m_hasDoc(FALSE) + , m_isRoot(isRoot) + , m_classDef(cd) + , m_visible(FALSE) + , m_truncated(Unknown) + , m_distance(1000) +{ +} + +DotNode::~DotNode() +{ + delete m_children; + delete m_parents; + delete m_edgeInfo; +} + +void DotNode::addChild(DotNode *n, + int edgeColor, + int edgeStyle, + const char *edgeLab, + const char *edgeURL, + int edgeLabCol + ) +{ + if (m_children==0) + { + m_children = new QList<DotNode>; + m_edgeInfo = new QList<EdgeInfo>; + m_edgeInfo->setAutoDelete(TRUE); + } + m_children->append(n); + EdgeInfo *ei = new EdgeInfo; + ei->m_color = edgeColor; + ei->m_style = edgeStyle; + ei->m_label = edgeLab; + ei->m_url = edgeURL; + if (edgeLabCol==-1) + ei->m_labColor=edgeColor; + else + ei->m_labColor=edgeLabCol; + m_edgeInfo->append(ei); +} + +void DotNode::addParent(DotNode *n) +{ + if (m_parents==0) + { + m_parents = new QList<DotNode>; + } + m_parents->append(n); +} + +void DotNode::removeChild(DotNode *n) +{ + if (m_children) m_children->remove(n); +} + +void DotNode::removeParent(DotNode *n) +{ + if (m_parents) m_parents->remove(n); +} + +void DotNode::deleteNode(DotNodeList &deletedList,SDict<DotNode> *skipNodes) +{ + if (m_deleted) return; // avoid recursive loops in case the graph has cycles + m_deleted=TRUE; + if (m_parents!=0) // delete all parent nodes of this node + { + QListIterator<DotNode> dnlip(*m_parents); + DotNode *pn; + for (dnlip.toFirst();(pn=dnlip.current());++dnlip) + { + //pn->removeChild(this); + pn->deleteNode(deletedList,skipNodes); + } + } + if (m_children!=0) // delete all child nodes of this node + { + QListIterator<DotNode> dnlic(*m_children); + DotNode *cn; + for (dnlic.toFirst();(cn=dnlic.current());++dnlic) + { + //cn->removeParent(this); + cn->deleteNode(deletedList,skipNodes); + } + } + // add this node to the list of deleted nodes. + //printf("skipNodes=%p find(%p)=%p\n",skipNodes,this,skipNodes ? skipNodes->find((int)this) : 0); + if (skipNodes==0 || skipNodes->find((char*)this)==0) + { + //printf("deleting\n"); + deletedList.append(this); + } +} + +void DotNode::setDistance(int distance) +{ + if (distance<m_distance) m_distance = distance; +} + +static QCString convertLabel(const QCString &l) +{ + QCString result; + QCString bBefore("\\_/<({[: =-+@%#~?$"); + QCString bAfter(">]),;|"); + const char *p=l.data(); + if (p==0) return result; + char c; + char cs[2]; + cs[1]=0; + int len=l.length(); + int charsLeft=len; + int sinceLast=0; + int foldLen=17; // ideal text length + while ((c=*p++)) + { + QCString replacement; + switch(c) + { + case '\\': replacement="\\\\"; break; + case '\n': replacement="\\n"; break; + case '<': replacement="\\<"; break; + case '>': replacement="\\>"; break; + case '|': replacement="\\|"; break; + case '{': replacement="\\{"; break; + case '}': replacement="\\}"; break; + case '"': replacement="\\\""; break; + default: cs[0]=c; replacement=cs; break; + } + // Some heuristics to insert newlines to prevent too long + // boxes and at the same time prevent ugly breaks + if (c=='\n') + { + result+=replacement; + foldLen = (3*foldLen+sinceLast+2)/4; + sinceLast=1; + } + else if (charsLeft>foldLen/3 && sinceLast>foldLen && bBefore.contains(c)) + { + result+="\\n"; + result+=replacement; + foldLen = (foldLen+sinceLast+1)/2; + sinceLast=1; + } + else if (charsLeft>1+foldLen/4 && sinceLast>foldLen+foldLen/3 && + !isupper(c) && isupper(*p)) + { + result+=replacement; + result+="\\n"; + foldLen = (foldLen+sinceLast+1)/2; + sinceLast=0; + } + else if (charsLeft>foldLen/3 && sinceLast>foldLen && bAfter.contains(c)) + { + result+=replacement; + result+="\\n"; + foldLen = (foldLen+sinceLast+1)/2; + sinceLast=0; + } + else + { + result+=replacement; + sinceLast++; + } + charsLeft--; + } + return result; +} + +static QCString escapeTooltip(const QCString &tooltip) +{ + QCString result; + const char *p=tooltip.data(); + if (p==0) return result; + char c; + while ((c=*p++)) + { + switch(c) + { + case '"': result+="\\\""; break; + default: result+=c; break; + } + } + return result; +} + +static void writeBoxMemberList(FTextStream &t, + char prot,MemberList *ml,ClassDef *scope, + bool isStatic=FALSE,const QDict<void> *skipNames=0) +{ + (void)isStatic; + if (ml) + { + MemberListIterator mlia(*ml); + MemberDef *mma; + int totalCount=0; + for (mlia.toFirst();(mma = mlia.current());++mlia) + { + if (mma->getClassDef()==scope && + (skipNames==0 || skipNames->find(mma->name())==0)) + { + totalCount++; + } + } + + int count=0; + for (mlia.toFirst();(mma = mlia.current());++mlia) + { + if (mma->getClassDef() == scope && + (skipNames==0 || skipNames->find(mma->name())==0)) + { + static int limit = Config_getInt("UML_LIMIT_NUM_FIELDS"); + if (limit==0 || (totalCount>=limit*3/2 && count>=limit)) + { + t << "and " << (totalCount-count-1) << " more..."; + // TODO: TRANSLATE ME + break; + } + else + { + t << prot << " "; + t << convertLabel(mma->name()); + if (!mma->isObjCMethod() && + (mma->isFunction() || mma->isSlot() || mma->isSignal())) t << "()"; + t << "\\l"; + count++; + } + } + } + // write member groups within the memberlist + MemberGroupList *mgl = ml->getMemberGroupList(); + if (mgl) + { + MemberGroupListIterator mgli(*mgl); + MemberGroup *mg; + for (mgli.toFirst();(mg=mgli.current());++mgli) + { + if (mg->members()) + { + writeBoxMemberList(t,prot,mg->members(),scope,isStatic,skipNames); + } + } + } + } +} + +void DotNode::writeBox(FTextStream &t, + GraphType gt, + GraphOutputFormat /*format*/, + bool hasNonReachableChildren, + bool reNumber) +{ + const char *labCol = + m_url.isEmpty() ? "grey75" : // non link + ( + (hasNonReachableChildren) ? "red" : "black" + ); + t << " Node" << reNumberNode(m_number,reNumber) << " [label=\""; + static bool umlLook = Config_getBool("UML_LOOK"); + + if (m_classDef && umlLook && (gt==Inheritance || gt==Collaboration)) + { + // add names shown as relation to a dictionary, so we don't show + // them as attributes as well + QDict<void> arrowNames(17); + if (m_edgeInfo) + { + QListIterator<EdgeInfo> li(*m_edgeInfo); + EdgeInfo *ei; + for (li.toFirst();(ei=li.current());++li) + { + if (!ei->m_label.isEmpty()) + { + arrowNames.insert(ei->m_label,(void*)0x8); + } + } + } + + //printf("DotNode::writeBox for %s\n",m_classDef->name().data()); + static bool extractPrivate = Config_getBool("EXTRACT_PRIVATE"); + t << "{" << convertLabel(m_label); + t << "\\n|"; + writeBoxMemberList(t,'+',m_classDef->getMemberList(MemberList::pubAttribs),m_classDef,FALSE,&arrowNames); + writeBoxMemberList(t,'+',m_classDef->getMemberList(MemberList::pubStaticAttribs),m_classDef,TRUE,&arrowNames); + writeBoxMemberList(t,'+',m_classDef->getMemberList(MemberList::properties),m_classDef,FALSE,&arrowNames); + writeBoxMemberList(t,'~',m_classDef->getMemberList(MemberList::pacAttribs),m_classDef,FALSE,&arrowNames); + writeBoxMemberList(t,'~',m_classDef->getMemberList(MemberList::pacStaticAttribs),m_classDef,TRUE,&arrowNames); + writeBoxMemberList(t,'#',m_classDef->getMemberList(MemberList::proAttribs),m_classDef,FALSE,&arrowNames); + writeBoxMemberList(t,'#',m_classDef->getMemberList(MemberList::proStaticAttribs),m_classDef,TRUE,&arrowNames); + if (extractPrivate) + { + writeBoxMemberList(t,'-',m_classDef->getMemberList(MemberList::priAttribs),m_classDef,FALSE,&arrowNames); + writeBoxMemberList(t,'-',m_classDef->getMemberList(MemberList::priStaticAttribs),m_classDef,TRUE,&arrowNames); + } + t << "|"; + writeBoxMemberList(t,'+',m_classDef->getMemberList(MemberList::pubMethods),m_classDef); + writeBoxMemberList(t,'+',m_classDef->getMemberList(MemberList::pubStaticMethods),m_classDef,TRUE); + writeBoxMemberList(t,'+',m_classDef->getMemberList(MemberList::pubSlots),m_classDef); + writeBoxMemberList(t,'~',m_classDef->getMemberList(MemberList::pacMethods),m_classDef); + writeBoxMemberList(t,'~',m_classDef->getMemberList(MemberList::pacStaticMethods),m_classDef,TRUE); + writeBoxMemberList(t,'#',m_classDef->getMemberList(MemberList::proMethods),m_classDef); + writeBoxMemberList(t,'#',m_classDef->getMemberList(MemberList::proStaticMethods),m_classDef,TRUE); + writeBoxMemberList(t,'#',m_classDef->getMemberList(MemberList::proSlots),m_classDef); + if (extractPrivate) + { + writeBoxMemberList(t,'-',m_classDef->getMemberList(MemberList::priMethods),m_classDef); + writeBoxMemberList(t,'-',m_classDef->getMemberList(MemberList::priStaticMethods),m_classDef,TRUE); + writeBoxMemberList(t,'-',m_classDef->getMemberList(MemberList::priSlots),m_classDef); + } + if (m_classDef->getLanguage()!=SrcLangExt_Fortran && + m_classDef->getMemberGroupSDict()) + { + MemberGroupSDict::Iterator mgdi(*m_classDef->getMemberGroupSDict()); + MemberGroup *mg; + for (mgdi.toFirst();(mg=mgdi.current());++mgdi) + { + if (mg->members()) + { + writeBoxMemberList(t,'*',mg->members(),m_classDef,FALSE,&arrowNames); + } + } + } + t << "}"; + } + else // standard look + { + t << convertLabel(m_label); + } + t << "\",height=0.2,width=0.4"; + if (m_isRoot) + { + t << ",color=\"black\", fillcolor=\"grey75\", style=\"filled\" fontcolor=\"black\""; + } + else + { + static bool dotTransparent = Config_getBool("DOT_TRANSPARENT"); + static bool vhdlOpt = Config_getBool("OPTIMIZE_OUTPUT_VHDL"); + if (!dotTransparent) + { + ClassDef* ccd=this->m_classDef; + + t << ",color=\"" << labCol << "\", fillcolor=\""; + if (ccd && vhdlOpt && (VhdlDocGen::VhdlClasses)ccd->protection()==VhdlDocGen::ARCHITECTURECLASS) + t << "khaki"; + else + t << "white"; + t << "\", style=\"filled\""; + } + else + { + t << ",color=\"" << labCol << "\""; + } + if (!m_url.isEmpty()) + { + int anchorPos = m_url.findRev('#'); + if (anchorPos==-1) + { + t << ",URL=\"" << m_url << Doxygen::htmlFileExtension << "\""; + } + else + { + t << ",URL=\"" << m_url.left(anchorPos) << Doxygen::htmlFileExtension + << m_url.right(m_url.length()-anchorPos) << "\""; + } + } + if (!m_tooltip.isEmpty()) + { + t << ",tooltip=\"" << escapeTooltip(m_tooltip) << "\""; + } + } + t << "];" << endl; +} + +void DotNode::writeArrow(FTextStream &t, + GraphType gt, + GraphOutputFormat format, + DotNode *cn, + EdgeInfo *ei, + bool topDown, + bool pointBack, + bool reNumber + ) +{ + t << " Node"; + if (topDown) + t << reNumberNode(cn->number(),reNumber); + else + t << reNumberNode(m_number,reNumber); + t << " -> Node"; + if (topDown) + t << reNumberNode(m_number,reNumber); + else + t << reNumberNode(cn->number(),reNumber); + t << " ["; + + static bool umlLook = Config_getBool("UML_LOOK"); + const EdgeProperties *eProps = umlLook ? ¨EdgeProps : &normalEdgeProps; + QCString aStyle = eProps->arrowStyleMap[ei->m_color]; + bool umlUseArrow = aStyle=="odiamond"; + + if (pointBack && !umlUseArrow) t << "dir=\"back\","; + t << "color=\"" << eProps->edgeColorMap[ei->m_color] + << "\",fontsize=\"" << FONTSIZE << "\","; + t << "style=\"" << eProps->edgeStyleMap[ei->m_style] << "\""; + if (!ei->m_label.isEmpty()) + { + t << ",label=\" " << convertLabel(ei->m_label) << "\" "; + } + if (umlLook && + eProps->arrowStyleMap[ei->m_color] && + (gt==Inheritance || gt==Collaboration) + ) + { + bool rev = pointBack; + if (umlUseArrow) rev=!rev; // UML use relates has arrow on the start side + if (rev) + t << ",arrowtail=\"" << eProps->arrowStyleMap[ei->m_color] << "\""; + else + t << ",arrowhead=\"" << eProps->arrowStyleMap[ei->m_color] << "\""; + } + + if (format==BITMAP) t << ",fontname=\"" << FONTNAME << "\""; + t << "];" << endl; +} + +void DotNode::write(FTextStream &t, + GraphType gt, + GraphOutputFormat format, + bool topDown, + bool toChildren, + bool backArrows, + bool reNumber + ) +{ + //printf("DotNode::write(%d) name=%s this=%p written=%d\n",distance,m_label.data(),this,m_written); + if (m_written) return; // node already written to the output + if (!m_visible) return; // node is not visible + writeBox(t,gt,format,m_truncated==Truncated,reNumber); + m_written=TRUE; + QList<DotNode> *nl = toChildren ? m_children : m_parents; + if (nl) + { + if (toChildren) + { + QListIterator<DotNode> dnli1(*nl); + QListIterator<EdgeInfo> dnli2(*m_edgeInfo); + DotNode *cn; + for (dnli1.toFirst();(cn=dnli1.current());++dnli1,++dnli2) + { + if (cn->isVisible()) + { + //printf("write arrow %s%s%s\n",label().data(),backArrows?"<-":"->",cn->label().data()); + writeArrow(t,gt,format,cn,dnli2.current(),topDown,backArrows,reNumber); + } + cn->write(t,gt,format,topDown,toChildren,backArrows,reNumber); + } + } + else // render parents + { + QListIterator<DotNode> dnli(*nl); + DotNode *pn; + for (dnli.toFirst();(pn=dnli.current());++dnli) + { + if (pn->isVisible()) + { + //printf("write arrow %s%s%s\n",label().data(),backArrows?"<-":"->",pn->label().data()); + writeArrow(t, + gt, + format, + pn, + pn->m_edgeInfo->at(pn->m_children->findRef(this)), + FALSE, + backArrows, + reNumber + ); + } + pn->write(t,gt,format,TRUE,FALSE,backArrows,reNumber); + } + } + } + //printf("end DotNode::write(%d) name=%s\n",distance,m_label.data()); +} + +void DotNode::writeXML(FTextStream &t,bool isClassGraph) +{ + t << " <node id=\"" << m_number << "\">" << endl; + t << " <label>" << convertToXML(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 refid=\"" << convertToXML(urlPtr) << "\""; + if (*refPtr!='\0') + { + t << " external=\"" << convertToXML(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 refid=\"" << childNode->m_number << "\" relation=\""; + if (isClassGraph) + { + 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; + } + } + else // include graph + { + t << "include"; + } + t << "\">" << endl; + if (!edgeInfo->m_label.isEmpty()) + { + int p=0; + int ni; + while ((ni=edgeInfo->m_label.find('\n',p))!=-1) + { + t << " <edgelabel>" + << convertToXML(edgeInfo->m_label.mid(p,ni-p)) + << "</edgelabel>" << endl; + p=ni+1; + } + t << " <edgelabel>" + << convertToXML(edgeInfo->m_label.right(edgeInfo->m_label.length()-p)) + << "</edgelabel>" << endl; + } + t << " </childnode>" << endl; + } + } + t << " </node>" << endl; +} + + +void DotNode::writeDEF(FTextStream &t) +{ + const char* nodePrefix = " node-"; + + t << " node = {" << endl; + t << nodePrefix << "id = " << m_number << ';' << endl; + t << nodePrefix << "label = '" << m_label << "';" << endl; + + if (!m_url.isEmpty()) + { + QCString url(m_url); + char *refPtr = url.data(); + char *urlPtr = strchr(url.data(),'$'); + if (urlPtr) + { + *urlPtr++='\0'; + t << nodePrefix << "link = {" << endl << " " + << nodePrefix << "link-id = '" << urlPtr << "';" << endl; + + if (*refPtr!='\0') + { + t << " " << nodePrefix << "link-external = '" + << refPtr << "';" << endl; + } + 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 << " node-child = {" << endl; + t << " child-id = '" << childNode->m_number << "';" << endl; + t << " 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()) + { + t << " edgelabel = <<_EnD_oF_dEf_TeXt_" << endl + << edgeInfo->m_label << endl + << "_EnD_oF_dEf_TeXt_;" << endl; + } + t << " }; /* node-child */" << endl; + } /* for (;childNode...) */ + } + t << " }; /* node */" << endl; +} + + +void DotNode::clearWriteFlag() +{ + m_written=FALSE; + if (m_parents!=0) + { + QListIterator<DotNode> dnlip(*m_parents); + DotNode *pn; + for (dnlip.toFirst();(pn=dnlip.current());++dnlip) + { + if (pn->m_written) + { + pn->clearWriteFlag(); + } + } + } + if (m_children!=0) + { + QListIterator<DotNode> dnlic(*m_children); + DotNode *cn; + for (dnlic.toFirst();(cn=dnlic.current());++dnlic) + { + if (cn->m_written) + { + cn->clearWriteFlag(); + } + } + } +} + +void DotNode::colorConnectedNodes(int curColor) +{ + if (m_children) + { + QListIterator<DotNode> dnlic(*m_children); + DotNode *cn; + for (dnlic.toFirst();(cn=dnlic.current());++dnlic) + { + if (cn->m_subgraphId==-1) // uncolored child node + { + cn->m_subgraphId=curColor; + cn->markAsVisible(); + cn->colorConnectedNodes(curColor); + //printf("coloring node %s (%p): %d\n",cn->m_label.data(),cn,cn->m_subgraphId); + } + } + } + + if (m_parents) + { + QListIterator<DotNode> dnlip(*m_parents); + DotNode *pn; + for (dnlip.toFirst();(pn=dnlip.current());++dnlip) + { + if (pn->m_subgraphId==-1) // uncolored parent node + { + pn->m_subgraphId=curColor; + pn->markAsVisible(); + pn->colorConnectedNodes(curColor); + //printf("coloring node %s (%p): %d\n",pn->m_label.data(),pn,pn->m_subgraphId); + } + } + } +} + +const DotNode *DotNode::findDocNode() const +{ + if (!m_url.isEmpty()) return this; + //printf("findDocNode(): `%s'\n",m_label.data()); + if (m_parents) + { + QListIterator<DotNode> dnli(*m_parents); + DotNode *pn; + for (dnli.toFirst();(pn=dnli.current());++dnli) + { + if (!pn->m_hasDoc) + { + pn->m_hasDoc=TRUE; + const DotNode *dn = pn->findDocNode(); + if (dn) return dn; + } + } + } + if (m_children) + { + QListIterator<DotNode> dnli(*m_children); + DotNode *cn; + for (dnli.toFirst();(cn=dnli.current());++dnli) + { + if (!cn->m_hasDoc) + { + cn->m_hasDoc=TRUE; + const DotNode *dn = cn->findDocNode(); + if (dn) return dn; + } + } + } + return 0; +} + +//-------------------------------------------------------------------- + +int DotGfxHierarchyTable::m_curNodeNumber; + +void DotGfxHierarchyTable::writeGraph(FTextStream &out, + const char *path,const char *fileName) const +{ + //printf("DotGfxHierarchyTable::writeGraph(%s)\n",name); + //printf("m_rootNodes=%p count=%d\n",m_rootNodes,m_rootNodes->count()); + + static bool vhdl = Config_getBool("OPTIMIZE_OUTPUT_VHDL"); + + if (m_rootSubgraphs->count()==0) return; + + QDir d(path); + // store the original directory + if (!d.exists()) + { + err("error: Output dir %s does not exist!\n",path); exit(1); + } + + // put each connected subgraph of the hierarchy in a row of the HTML output + out << "<table border=\"0\" cellspacing=\"10\" cellpadding=\"0\">" << endl; + + QListIterator<DotNode> dnli(*m_rootSubgraphs); + DotNode *n; + int count=0; + for (dnli.toFirst();(n=dnli.current());++dnli) + { + QCString baseName; + + if (vhdl) + { + QCString l=n->m_url; + l=VhdlDocGen::convertFileNameToClassName(l); + ClassDef *cd=Doxygen::classSDict->find(l); + if (cd==0) continue; + // only entities are shown + if ((VhdlDocGen::VhdlClasses)cd->protection()!=VhdlDocGen::ENTITYCLASS) + continue; + } + + QCString imgExt = Config_getEnum("DOT_IMAGE_FORMAT"); + baseName.sprintf("inherit_graph_%d",count++); + //baseName = convertNameToFile(baseName); + QCString imgName = baseName+"."+ imgExt; + QCString mapName = baseName+".map"; + QCString absImgName = QCString(d.absPath().data())+"/"+imgName; + QCString absMapName = QCString(d.absPath().data())+"/"+mapName; + QCString absBaseName = QCString(d.absPath().data())+"/"+baseName; + QListIterator<DotNode> dnli2(*m_rootNodes); + DotNode *node; + + // compute md5 checksum of the graph were are about to generate + QGString theGraph; + FTextStream md5stream(&theGraph); + writeGraphHeader(md5stream); + md5stream << " rankdir=\"LR\";" << endl; + for (dnli2.toFirst();(node=dnli2.current());++dnli2) + { + if (node->m_subgraphId==n->m_subgraphId) + { + node->clearWriteFlag(); + } + } + for (dnli2.toFirst();(node=dnli2.current());++dnli2) + { + if (node->m_subgraphId==n->m_subgraphId) + { + node->write(md5stream,DotNode::Hierarchy,BITMAP,FALSE,TRUE,TRUE,TRUE); + } + } + writeGraphFooter(md5stream); + resetReNumbering(); + uchar md5_sig[16]; + QCString sigStr(33); + MD5Buffer((const unsigned char *)theGraph.data(),theGraph.length(),md5_sig); + MD5SigToString(md5_sig,sigStr.data(),33); + bool regenerate=FALSE; + if (checkAndUpdateMd5Signature(absBaseName,sigStr) || + !checkDeliverables(absImgName,absMapName)) + { + regenerate=TRUE; + // image was new or has changed + QCString dotName=absBaseName+".dot"; + QFile f(dotName); + if (!f.open(IO_WriteOnly)) return; + FTextStream t(&f); + t << theGraph; + f.close(); + resetReNumbering(); + + DotRunner *dotRun = new DotRunner(dotName,d.absPath().data(),TRUE,absImgName); + dotRun->addJob(imgExt,absImgName); + dotRun->addJob(MAP_CMD,absMapName); + DotManager::instance()->addRun(dotRun); + } + else + { + removeDotGraph(absBaseName+".dot"); + } + Doxygen::indexList.addImageFile(imgName); + // write image and map in a table row + QCString mapLabel = escapeCharsInString(n->m_label,FALSE); + out << "<tr><td>"; + if (imgExt=="svg") // vector graphics + { + if (regenerate || !writeSVGFigureLink(out,QCString(),baseName,absImgName)) + { + if (regenerate) + { + DotManager::instance()->addSVGConversion(absImgName,QCString(), + FALSE,QCString(),FALSE,0); + } + int mapId = DotManager::instance()->addSVGObject(fileName,baseName, + absImgName,QCString()); + out << "<!-- SVG " << mapId << " -->" << endl; + } + } + else // normal bitmap + { + out << "<img src=\"" << imgName << "\" border=\"0\" alt=\"\" usemap=\"#" + << mapLabel << "\"/>" << endl; + + if (regenerate || !insertMapFile(out,absMapName,QCString(),mapLabel)) + { + int mapId = DotManager::instance()->addMap(fileName,absMapName,QCString(), + FALSE,QCString(),mapLabel); + out << "<!-- MAP " << mapId << " -->" << endl; + } + } + + out << "</td></tr>" << endl; + } + out << "</table>" << endl; +} + +void DotGfxHierarchyTable::addHierarchy(DotNode *n,ClassDef *cd,bool hideSuper) +{ + //printf("addHierarchy `%s' baseClasses=%d\n",cd->name().data(),cd->baseClasses()->count()); + if (cd->subClasses()) + { + BaseClassListIterator bcli(*cd->subClasses()); + BaseClassDef *bcd; + for ( ; (bcd=bcli.current()) ; ++bcli ) + { + ClassDef *bClass=bcd->classDef; + //printf(" Trying sub class=`%s' usedNodes=%d\n",bClass->name().data(),m_usedNodes->count()); + if (bClass->isVisibleInHierarchy() && hasVisibleRoot(bClass->baseClasses())) + { + DotNode *bn; + //printf(" Node `%s' Found visible class=`%s'\n",n->m_label.data(), + // bClass->name().data()); + if ((bn=m_usedNodes->find(bClass->name()))) // node already present + { + if (n->m_children==0 || n->m_children->findRef(bn)==-1) // no arrow yet + { + n->addChild(bn,bcd->prot); + bn->addParent(n); + //printf(" Adding node %s to existing base node %s (c=%d,p=%d)\n", + // n->m_label.data(), + // bn->m_label.data(), + // bn->m_children ? bn->m_children->count() : 0, + // bn->m_parents ? bn->m_parents->count() : 0 + // ); + } + //else + //{ + // printf(" Class already has an arrow!\n"); + //} + } + else + { + QCString tmp_url=""; + if (bClass->isLinkable() && !bClass->isHidden()) + { + tmp_url=bClass->getReference()+"$"+bClass->getOutputFileBase(); + if (!bClass->anchor().isEmpty()) + { + tmp_url+="#"+bClass->anchor(); + } + } + QCString tooltip = bClass->briefDescriptionAsTooltip(); + bn = new DotNode(m_curNodeNumber++, + bClass->displayName(), + tooltip, + tmp_url.data() + ); + n->addChild(bn,bcd->prot); + bn->addParent(n); + //printf(" Adding node %s to new base node %s (c=%d,p=%d)\n", + // n->m_label.data(), + // bn->m_label.data(), + // bn->m_children ? bn->m_children->count() : 0, + // bn->m_parents ? bn->m_parents->count() : 0 + // ); + //printf(" inserting %s (%p)\n",bClass->name().data(),bn); + m_usedNodes->insert(bClass->name(),bn); // add node to the used list + } + if (!bClass->visited && !hideSuper && bClass->subClasses()) + { + bool wasVisited=bClass->visited; + bClass->visited=TRUE; + addHierarchy(bn,bClass,wasVisited); + } + } + } + } + //printf("end addHierarchy\n"); +} + +void DotGfxHierarchyTable::addClassList(ClassSDict *cl) +{ + ClassSDict::Iterator cli(*cl); + ClassDef *cd; + for (cli.toLast();(cd=cli.current());--cli) + { + //printf("Trying %s subClasses=%d\n",cd->name().data(),cd->subClasses()->count()); + if (!hasVisibleRoot(cd->baseClasses()) && + cd->isVisibleInHierarchy() + ) // root node in the forest + { + QCString tmp_url=""; + if (cd->isLinkable() && !cd->isHidden()) + { + tmp_url=cd->getReference()+"$"+cd->getOutputFileBase(); + if (!cd->anchor().isEmpty()) + { + tmp_url+="#"+cd->anchor(); + } + } + //printf("Inserting root class %s\n",cd->name().data()); + QCString tooltip = cd->briefDescriptionAsTooltip(); + DotNode *n = new DotNode(m_curNodeNumber++, + cd->displayName(), + tooltip, + tmp_url.data()); + + //m_usedNodes->clear(); + m_usedNodes->insert(cd->name(),n); + m_rootNodes->insert(0,n); + if (!cd->visited && cd->subClasses()) + { + addHierarchy(n,cd,cd->visited); + cd->visited=TRUE; + } + } + } +} + +DotGfxHierarchyTable::DotGfxHierarchyTable() +{ + m_curNodeNumber=0; + m_rootNodes = new QList<DotNode>; + m_usedNodes = new QDict<DotNode>(1009); + m_usedNodes->setAutoDelete(TRUE); + 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 + bool done=FALSE; + int curColor=0; + QListIterator<DotNode> dnli(*m_rootNodes); + while (!done) // there are still nodes to color + { + DotNode *n; + done=TRUE; // we are done unless there are still uncolored nodes + for (dnli.toLast();(n=dnli.current());--dnli) + { + if (n->m_subgraphId==-1) // not yet colored + { + //printf("Starting at node %s (%p): %d\n",n->m_label.data(),n,curColor); + done=FALSE; // still uncolored nodes + n->m_subgraphId=curColor; + n->markAsVisible(); + n->colorConnectedNodes(curColor); + curColor++; + const DotNode *dn=n->findDocNode(); + if (dn!=0) + m_rootSubgraphs->inSort(dn); + else + m_rootSubgraphs->inSort(n); + } + } + } + + //printf("Number of independent subgraphs: %d\n",curColor); + //QListIterator<DotNode> dnli2(*m_rootSubgraphs); + //DotNode *n; + //for (dnli2.toFirst();(n=dnli2.current());++dnli2) + //{ + // printf("Node %s color=%d (c=%d,p=%d)\n", + // n->m_label.data(),n->m_subgraphId, + // n->m_children?n->m_children->count():0, + // n->m_parents?n->m_parents->count():0); + //} +} + +DotGfxHierarchyTable::~DotGfxHierarchyTable() +{ + //printf("DotGfxHierarchyTable::~DotGfxHierarchyTable\n"); + + //QDictIterator<DotNode> di(*m_usedNodes); + //DotNode *n; + //for (;(n=di.current());++di) + //{ + // printf("Node %p: %s\n",n,n->label().data()); + //} + + delete m_rootNodes; + delete m_usedNodes; + delete m_rootSubgraphs; +} + +//-------------------------------------------------------------------- + +int DotClassGraph::m_curNodeNumber = 0; + +void DotClassGraph::addClass(ClassDef *cd,DotNode *n,int prot, + const char *label,const char *usedName,const char *templSpec,bool base,int distance) +{ + if (Config_getBool("HIDE_UNDOC_CLASSES") && !cd->isLinkable()) return; + + int edgeStyle = (label || prot==EdgeInfo::Orange) ? EdgeInfo::Dashed : EdgeInfo::Solid; + QCString className; + if (usedName) // name is a typedef + { + className=usedName; + } + else if (templSpec) // name has a template part + { + className=insertTemplateSpecifierInScope(cd->name(),templSpec); + } + else // just a normal 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 + { + if (base) + { + n->addChild(bn,prot,edgeStyle,label); + bn->addParent(n); + } + else + { + bn->addChild(n,prot,edgeStyle,label); + n->addParent(bn); + } + bn->setDistance(distance); + //printf(" add exiting node %s of %s\n",bn->m_label.data(),n->m_label.data()); + } + else // new class + { + QCString displayName=className; + if (Config_getBool("HIDE_SCOPE_NAMES")) displayName=stripScope(displayName); + QCString tmp_url; + if (cd->isLinkable() && !cd->isHidden()) + { + tmp_url=cd->getReference()+"$"+cd->getOutputFileBase(); + if (!cd->anchor().isEmpty()) + { + tmp_url+="#"+cd->anchor(); + } + } + QCString tooltip = cd->briefDescriptionAsTooltip(); + bn = new DotNode(m_curNodeNumber++, + displayName, + tooltip, + tmp_url.data(), + FALSE, // rootNode + cd + ); + if (base) + { + n->addChild(bn,prot,edgeStyle,label); + bn->addParent(n); + } + else + { + bn->addChild(n,prot,edgeStyle,label); + n->addParent(bn); + } + bn->setDistance(distance); + m_usedNodes->insert(className,bn); + //printf(" add new child node `%s' to %s hidden=%d url=%s\n", + // className.data(),n->m_label.data(),cd->isHidden(),tmp_url.data()); + + buildGraph(cd,bn,base,distance+1); + } +} + +void DotClassGraph::determineTruncatedNodes(QList<DotNode> &queue,bool includeParents) +{ + while (queue.count()>0) + { + DotNode *n = queue.take(0); + if (n->isVisible() && n->isTruncated()==DotNode::Unknown) + { + bool truncated = FALSE; + if (n->m_children) + { + QListIterator<DotNode> li(*n->m_children); + DotNode *dn; + for (li.toFirst();(dn=li.current());++li) + { + if (!dn->isVisible()) + truncated = TRUE; + else + queue.append(dn); + } + } + if (n->m_parents && includeParents) + { + QListIterator<DotNode> li(*n->m_parents); + DotNode *dn; + for (li.toFirst();(dn=li.current());++li) + { + if (!dn->isVisible()) + truncated = TRUE; + else + queue.append(dn); + } + } + n->markAsTruncated(truncated); + } + } +} + +bool DotClassGraph::determineVisibleNodes(DotNode *rootNode, + int maxNodes,bool includeParents) +{ + QList<DotNode> childQueue; + QList<DotNode> parentQueue; + QArray<int> childTreeWidth; + QArray<int> parentTreeWidth; + childQueue.append(rootNode); + if (includeParents) parentQueue.append(rootNode); + bool firstNode=TRUE; // flag to force reprocessing rootNode in the parent loop + // despite being marked visible in the child loop + while ((childQueue.count()>0 || parentQueue.count()>0) && maxNodes>0) + { + static int maxDistance = Config_getInt("MAX_DOT_GRAPH_DEPTH"); + if (childQueue.count()>0) + { + DotNode *n = childQueue.take(0); + int distance = n->distance(); + if (!n->isVisible() && distance<maxDistance) // not yet processed + { + if (distance>0) + { + int oldSize=(int)childTreeWidth.size(); + if (distance>oldSize) + { + childTreeWidth.resize(QMAX(childTreeWidth.size(),(uint)distance)); + int i; for (i=oldSize;i<distance;i++) childTreeWidth[i]=0; + } + childTreeWidth[distance-1]+=n->label().length(); + } + n->markAsVisible(); + maxNodes--; + // add direct children + if (n->m_children) + { + QListIterator<DotNode> li(*n->m_children); + DotNode *dn; + for (li.toFirst();(dn=li.current());++li) + { + childQueue.append(dn); + } + } + } + } + if (includeParents && parentQueue.count()>0) + { + DotNode *n = parentQueue.take(0); + if ((!n->isVisible() || firstNode) && n->distance()<maxDistance) // not yet processed + { + firstNode=FALSE; + int distance = n->distance(); + if (distance>0) + { + int oldSize = (int)parentTreeWidth.size(); + if (distance>oldSize) + { + parentTreeWidth.resize(QMAX(parentTreeWidth.size(),(uint)distance)); + int i; for (i=oldSize;i<distance;i++) parentTreeWidth[i]=0; + } + parentTreeWidth[distance-1]+=n->label().length(); + } + n->markAsVisible(); + maxNodes--; + // add direct parents + if (n->m_parents) + { + QListIterator<DotNode> li(*n->m_parents); + DotNode *dn; + for (li.toFirst();(dn=li.current());++li) + { + parentQueue.append(dn); + } + } + } + } + } + if (Config_getBool("UML_LOOK")) return FALSE; // UML graph are always top to bottom + int maxWidth=0; + int maxHeight=(int)QMAX(childTreeWidth.size(),parentTreeWidth.size()); + uint i; + for (i=0;i<childTreeWidth.size();i++) + { + if (childTreeWidth.at(i)>maxWidth) maxWidth=childTreeWidth.at(i); + } + for (i=0;i<parentTreeWidth.size();i++) + { + if (parentTreeWidth.at(i)>maxWidth) maxWidth=parentTreeWidth.at(i); + } + //printf("max tree width=%d, max tree height=%d\n",maxWidth,maxHeight); + return maxWidth>80 && maxHeight<12; // used metric to decide to render the tree + // from left to right instead of top to bottom, + // with the idea to render very wide trees in + // left to right order. +} + +void DotClassGraph::buildGraph(ClassDef *cd,DotNode *n,bool base,int distance) +{ + //printf("DocClassGraph::buildGraph(%s,distance=%d,base=%d)\n", + // cd->name().data(),distance,base); + // ---- Add inheritance relations + + if (m_graphType == DotNode::Inheritance || m_graphType==DotNode::Collaboration) + { + BaseClassList *bcl = base ? cd->baseClasses() : cd->subClasses(); + if (bcl) + { + BaseClassListIterator bcli(*bcl); + BaseClassDef *bcd; + for ( ; (bcd=bcli.current()) ; ++bcli ) + { + //printf("-------- inheritance relation %s->%s templ=`%s'\n", + // cd->name().data(),bcd->classDef->name().data(),bcd->templSpecifiers.data()); + addClass(bcd->classDef,n,bcd->prot,0,bcd->usedName, + bcd->templSpecifiers,base,distance); + } + } + } + if (m_graphType == DotNode::Collaboration) + { + // ---- Add usage relations + + UsesClassDict *dict = + base ? cd->usedImplementationClasses() : + cd->usedByImplementationClasses() + ; + if (dict) + { + UsesClassDictIterator ucdi(*dict); + UsesClassDef *ucd; + for (;(ucd=ucdi.current());++ucdi) + { + QCString label; + QDictIterator<void> dvi(*ucd->accessors); + const char *s; + bool first=TRUE; + int count=0; + int maxLabels=10; + for (;(s=dvi.currentKey()) && count<maxLabels;++dvi,++count) + { + if (first) + { + label=s; + first=FALSE; + } + else + { + label+=QCString("\n")+s; + } + } + if (count==maxLabels) label+="\n..."; + //printf("addClass: %s templSpec=%s\n",ucd->classDef->name().data(),ucd->templSpecifiers.data()); + addClass(ucd->classDef,n,EdgeInfo::Purple,label,0, + ucd->templSpecifiers,base,distance); + } + } + } + + // ---- Add template instantiation relations + + static bool templateRelations = Config_getBool("TEMPLATE_RELATIONS"); + if (templateRelations) + { + if (base) // template relations for base classes + { + ClassDef *templMaster=cd->templateMaster(); + if (templMaster) + { + QDictIterator<ClassDef> cli(*templMaster->getTemplateInstances()); + ClassDef *templInstance; + for (;(templInstance=cli.current());++cli) + { + if (templInstance==cd) + { + addClass(templMaster,n,EdgeInfo::Orange,cli.currentKey(),0, + 0,TRUE,distance); + } + } + } + } + else // template relations for super classes + { + QDict<ClassDef> *templInstances = cd->getTemplateInstances(); + if (templInstances) + { + QDictIterator<ClassDef> cli(*templInstances); + ClassDef *templInstance; + for (;(templInstance=cli.current());++cli) + { + addClass(templInstance,n,EdgeInfo::Orange,cli.currentKey(),0, + 0,FALSE,distance); + } + } + } + } +} + +DotClassGraph::DotClassGraph(ClassDef *cd,DotNode::GraphType t) +{ + //printf("--------------- DotClassGraph::DotClassGraph `%s'\n",cd->displayName().data()); + m_graphType = t; + QCString tmp_url=""; + if (cd->isLinkable() && !cd->isHidden()) + { + tmp_url=cd->getReference()+"$"+cd->getOutputFileBase(); + if (!cd->anchor().isEmpty()) + { + tmp_url+="#"+cd->anchor(); + } + } + QCString className = cd->displayName(); + QCString tooltip = cd->briefDescriptionAsTooltip(); + m_startNode = new DotNode(m_curNodeNumber++, + className, + tooltip, + tmp_url.data(), + TRUE, // is a root node + cd + ); + m_startNode->setDistance(0); + m_usedNodes = new QDict<DotNode>(1009); + m_usedNodes->insert(className,m_startNode); + + //printf("Root node %s\n",cd->name().data()); + //if (m_recDepth>0) + //{ + buildGraph(cd,m_startNode,TRUE,1); + if (t==DotNode::Inheritance) buildGraph(cd,m_startNode,FALSE,1); + //} + + static int maxNodes = Config_getInt("DOT_GRAPH_MAX_NODES"); + //int directChildNodes = 1; + //if (m_startNode->m_children!=0) + // directChildNodes+=m_startNode->m_children->count(); + //if (t==DotNode::Inheritance && m_startNode->m_parents!=0) + // directChildNodes+=m_startNode->m_parents->count(); + //if (directChildNodes>maxNodes) maxNodes=directChildNodes; + //openNodeQueue.append(m_startNode); + m_lrRank = determineVisibleNodes(m_startNode,maxNodes,t==DotNode::Inheritance); + QList<DotNode> openNodeQueue; + openNodeQueue.append(m_startNode); + determineTruncatedNodes(openNodeQueue,t==DotNode::Inheritance); + + m_diskName = cd->getFileBase().copy(); +} + +bool DotClassGraph::isTrivial() const +{ + if (m_graphType==DotNode::Inheritance) + return m_startNode->m_children==0 && m_startNode->m_parents==0; + else + return m_startNode->m_children==0; +} + +bool DotClassGraph::isTooBig() const +{ + static int maxNodes = Config_getInt("DOT_GRAPH_MAX_NODES"); + int numNodes = 0; + numNodes+= m_startNode->m_children ? m_startNode->m_children->count() : 0; + if (m_graphType==DotNode::Inheritance) + { + numNodes+= m_startNode->m_parents ? m_startNode->m_parents->count() : 0; + } + return numNodes>=maxNodes; +} + +DotClassGraph::~DotClassGraph() +{ + deleteNodes(m_startNode); + delete m_usedNodes; +} + +/*! Computes a 16 byte md5 checksum for a given dot graph. + * The md5 checksum is returned as a 32 character ASCII string. + */ +QCString computeMd5Signature(DotNode *root, + DotNode::GraphType gt, + GraphOutputFormat format, + bool lrRank, + bool renderParents, + bool backArrows, + QCString &graphStr + ) +{ + bool reNumber=TRUE; + + //printf("computeMd5Signature\n"); + QGString buf; + FTextStream md5stream(&buf); + writeGraphHeader(md5stream); + if (lrRank) + { + md5stream << " rankdir=\"LR\";" << endl; + } + root->clearWriteFlag(); + root->write(md5stream, + gt, + format, + gt!=DotNode::CallGraph && gt!=DotNode::Dependency, + TRUE, + backArrows, + reNumber); + if (renderParents && root->m_parents) + { + QListIterator<DotNode> dnli(*root->m_parents); + DotNode *pn; + for (dnli.toFirst();(pn=dnli.current());++dnli) + { + if (pn->isVisible()) + { + root->writeArrow(md5stream, // stream + gt, // graph type + format, // output format + pn, // child node + pn->m_edgeInfo->at(pn->m_children->findRef(root)), // edge info + FALSE, // topDown? + backArrows, // point back? + reNumber // renumber nodes + ); + } + pn->write(md5stream, // stream + gt, // graph type + format, // output format + TRUE, // topDown? + FALSE, // toChildren? + backArrows, // backward pointing arrows? + reNumber // renumber nodes? + ); + } + } + writeGraphFooter(md5stream); + uchar md5_sig[16]; + QCString sigStr(33); + MD5Buffer((const unsigned char *)buf.data(),buf.length(),md5_sig); + MD5SigToString(md5_sig,sigStr.data(),33); + if (reNumber) + { + resetReNumbering(); + } + graphStr=buf.data(); + //printf("md5: %s | file: %s\n",sigStr,baseName.data()); + return sigStr; +} + +static bool updateDotGraph(DotNode *root, + DotNode::GraphType gt, + const QCString &baseName, + GraphOutputFormat format, + bool lrRank, + bool renderParents, + bool backArrows + ) +{ + QCString theGraph; + // TODO: write graph to theGraph, then compute md5 checksum + QCString md5 = computeMd5Signature( + root,gt,format,lrRank,renderParents,backArrows,theGraph); + QFile f(baseName+".dot"); + if (f.open(IO_WriteOnly)) + { + FTextStream t(&f); + t << theGraph; + } + return checkAndUpdateMd5Signature(baseName,md5); // graph needs to be regenerated +} + +QCString DotClassGraph::diskName() const +{ + QCString result=m_diskName.copy(); + switch (m_graphType) + { + case DotNode::Collaboration: + result+="_coll_graph"; + break; + //case Interface: + // result+="_intf_graph"; + // break; + case DotNode::Inheritance: + result+="_inherit_graph"; + break; + default: + ASSERT(0); + break; + } + return result; +} + +QCString DotClassGraph::writeGraph(FTextStream &out, + GraphOutputFormat format, + const char *path, + const char *fileName, + const char *relPath, + bool /*isTBRank*/, + bool generateImageMap, + int graphId) const +{ + QDir d(path); + // store the original directory + if (!d.exists()) + { + err("error: Output dir %s does not exist!\n",path); exit(1); + } + static bool usePDFLatex = Config_getBool("USE_PDFLATEX"); + + QCString baseName; + QCString mapName; + switch (m_graphType) + { + case DotNode::Collaboration: + mapName="coll_map"; + break; + //case Interface: + // mapName="intf_map"; + // break; + case DotNode::Inheritance: + mapName="inherit_map"; + break; + default: + ASSERT(0); + break; + } + baseName = convertNameToFile(diskName()); + + // derive target file names from baseName + QCString imgExt = Config_getEnum("DOT_IMAGE_FORMAT"); + QCString absBaseName = QCString(d.absPath())+"/"+baseName; + QCString absDotName = absBaseName+".dot"; + QCString absMapName = absBaseName+".map"; + QCString absPdfName = absBaseName+".pdf"; + QCString absEpsName = absBaseName+".eps"; + QCString absImgName = absBaseName+"."+imgExt; + + bool regenerate = FALSE; + if (updateDotGraph(m_startNode, + m_graphType, + absBaseName, + format, + m_lrRank, + m_graphType==DotNode::Inheritance, + TRUE + ) || + !checkDeliverables(format==BITMAP ? absImgName : + usePDFLatex ? absPdfName : absEpsName, + format==BITMAP && generateImageMap ? absMapName : QCString()) + ) + { + regenerate=TRUE; + if (format==BITMAP) // run dot to create a bitmap image + { + QCString dotArgs(maxCmdLine); + + DotRunner *dotRun = new DotRunner(absDotName, + d.absPath().data(),TRUE,absImgName); + dotRun->addJob(imgExt,absImgName); + if (generateImageMap) dotRun->addJob(MAP_CMD,absMapName); + DotManager::instance()->addRun(dotRun); + + } + else if (format==EPS) // run dot to create a .eps image + { + DotRunner *dotRun = new DotRunner(absDotName,d.absPath().data(),FALSE); + if (usePDFLatex) + { + dotRun->addJob("pdf",absPdfName); + } + else + { + dotRun->addJob("ps",absEpsName); + } + DotManager::instance()->addRun(dotRun); + } + } + Doxygen::indexList.addImageFile(baseName+"."+imgExt); + + if (format==BITMAP && generateImageMap) // produce HTML to include the image + { + QCString mapLabel = escapeCharsInString(m_startNode->m_label,FALSE)+"_"+ + escapeCharsInString(mapName,FALSE); + if (imgExt=="svg") // add link to SVG file without map file + { + out << "<div class=\"center\">"; + if (regenerate || !writeSVGFigureLink(out,relPath,baseName,absImgName)) // need to patch the links in the generated SVG file + { + if (regenerate) + { + DotManager::instance()->addSVGConversion(absImgName,relPath,FALSE,QCString(),TRUE,graphId); + } + int mapId = DotManager::instance()->addSVGObject(fileName,baseName,absImgName,relPath); + out << "<!-- SVG " << mapId << " -->" << endl; + } + out << "</div>" << endl; + } + else // add link to bitmap file with image map + { + out << "<div class=\"center\">"; + out << "<img src=\"" << relPath << baseName << "." + << imgExt << "\" border=\"0\" usemap=\"#" + << mapLabel << "\" alt=\""; + switch (m_graphType) + { + case DotNode::Collaboration: + out << "Collaboration graph"; + break; + case DotNode::Inheritance: + out << "Inheritance graph"; + break; + default: + ASSERT(0); + break; + } + out << "\"/>"; + out << "</div>" << endl; + + if (regenerate || !insertMapFile(out,absMapName,relPath,mapLabel)) + { + int mapId = DotManager::instance()->addMap(fileName,absMapName,relPath, + FALSE,QCString(),mapLabel); + out << "<!-- MAP " << mapId << " -->" << endl; + } + } + } + else if (format==EPS) // produce tex to include the .eps image + { + if (regenerate || !writeVecGfxFigure(out,baseName,absBaseName)) + { + int figId = DotManager::instance()->addFigure(fileName,baseName,absBaseName,FALSE /*TRUE*/); + out << endl << "% FIG " << figId << endl; + } + } + if (!regenerate) removeDotGraph(absDotName); + + return baseName; +} + +//-------------------------------------------------------------------- + +void DotClassGraph::writeXML(FTextStream &t) +{ + QDictIterator<DotNode> dni(*m_usedNodes); + DotNode *node; + for (;(node=dni.current());++dni) + { + node->writeXML(t,TRUE); + } +} + +void DotClassGraph::writeDEF(FTextStream &t) +{ + QDictIterator<DotNode> dni(*m_usedNodes); + DotNode *node; + for (;(node=dni.current());++dni) + { + node->writeDEF(t); + } +} + +//-------------------------------------------------------------------- + +int DotInclDepGraph::m_curNodeNumber = 0; + +void DotInclDepGraph::buildGraph(DotNode *n,FileDef *fd,int distance) +{ + QList<IncludeInfo> *includeFiles = + m_inverse ? fd->includedByFileList() : fd->includeFileList(); + if (includeFiles) + { + QListIterator<IncludeInfo> ili(*includeFiles); + IncludeInfo *ii; + for (;(ii=ili.current());++ili) + { + FileDef *bfd = ii->fileDef; + QCString in = ii->includeName; + //printf(">>>> in=`%s' bfd=%p\n",ii->includeName.data(),bfd); + bool doc=TRUE,src=FALSE; + if (bfd) + { + in = bfd->absFilePath(); + doc = bfd->isLinkable() && !bfd->isHidden(); + src = bfd->generateSourceFile(); + } + if (doc || src || !Config_getBool("HIDE_UNDOC_RELATIONS")) + { + QCString url=""; + if (bfd) url=bfd->getOutputFileBase().copy(); + if (!doc && src) + { + url=bfd->getSourceFileBase(); + } + DotNode *bn = m_usedNodes->find(in); + if (bn) // file is already a node in the graph + { + n->addChild(bn,0,0,0); + bn->addParent(n); + bn->setDistance(distance); + } + else + { + QCString tmp_url; + QCString tooltip; + if (bfd) + { + tmp_url=doc || src ? bfd->getReference()+"$"+url : QCString(); + tooltip = bfd->briefDescriptionAsTooltip(); + } + bn = new DotNode( + m_curNodeNumber++, // n + ii->includeName, // label + tooltip, // tip + tmp_url, // url + FALSE, // rootNode + 0 // cd + ); + n->addChild(bn,0,0,0); + bn->addParent(n); + m_usedNodes->insert(in,bn); + bn->setDistance(distance); + + if (bfd) buildGraph(bn,bfd,distance+1); + } + } + } + } +} + +void DotInclDepGraph::determineVisibleNodes(QList<DotNode> &queue, int &maxNodes) +{ + while (queue.count()>0 && maxNodes>0) + { + static int maxDistance = Config_getInt("MAX_DOT_GRAPH_DEPTH"); + DotNode *n = queue.take(0); + if (!n->isVisible() && n->distance()<maxDistance) // not yet processed + { + n->markAsVisible(); + maxNodes--; + // add direct children + if (n->m_children) + { + QListIterator<DotNode> li(*n->m_children); + DotNode *dn; + for (li.toFirst();(dn=li.current());++li) + { + queue.append(dn); + } + } + } + } +} + +void DotInclDepGraph::determineTruncatedNodes(QList<DotNode> &queue) +{ + while (queue.count()>0) + { + DotNode *n = queue.take(0); + if (n->isVisible() && n->isTruncated()==DotNode::Unknown) + { + bool truncated = FALSE; + if (n->m_children) + { + QListIterator<DotNode> li(*n->m_children); + DotNode *dn; + for (li.toFirst();(dn=li.current());++li) + { + if (!dn->isVisible()) + truncated = TRUE; + else + queue.append(dn); + } + } + n->markAsTruncated(truncated); + } + } +} + + +DotInclDepGraph::DotInclDepGraph(FileDef *fd,bool inverse) +{ + m_maxDistance = 0; + m_inverse = inverse; + ASSERT(fd!=0); + m_diskName = fd->getFileBase().copy(); + QCString tmp_url=fd->getReference()+"$"+fd->getFileBase(); + m_startNode = new DotNode(m_curNodeNumber++, + fd->docName(), + "", + tmp_url.data(), + TRUE // root node + ); + m_startNode->setDistance(0); + m_usedNodes = new QDict<DotNode>(1009); + m_usedNodes->insert(fd->absFilePath(),m_startNode); + buildGraph(m_startNode,fd,1); + + static int nodes = Config_getInt("DOT_GRAPH_MAX_NODES"); + int maxNodes = nodes; + //int directChildNodes = 1; + //if (m_startNode->m_children!=0) + // directChildNodes+=m_startNode->m_children->count(); + //if (directChildNodes>maxNodes) maxNodes=directChildNodes; + QList<DotNode> openNodeQueue; + openNodeQueue.append(m_startNode); + determineVisibleNodes(openNodeQueue,maxNodes); + openNodeQueue.clear(); + openNodeQueue.append(m_startNode); + determineTruncatedNodes(openNodeQueue); +} + +DotInclDepGraph::~DotInclDepGraph() +{ + deleteNodes(m_startNode); + delete m_usedNodes; +} + +QCString DotInclDepGraph::diskName() const +{ + QCString result=m_diskName.copy(); + if (m_inverse) result+="_dep"; + result+="_incl"; + return convertNameToFile(result); +} + +QCString DotInclDepGraph::writeGraph(FTextStream &out, + GraphOutputFormat format, + const char *path, + const char *fileName, + const char *relPath, + bool generateImageMap, + int graphId + ) const +{ + QDir d(path); + // store the original directory + if (!d.exists()) + { + err("error: Output dir %s does not exist!\n",path); exit(1); + } + static bool usePDFLatex = Config_getBool("USE_PDFLATEX"); + + QCString baseName=m_diskName; + if (m_inverse) baseName+="_dep"; + baseName+="_incl"; + baseName=convertNameToFile(baseName); + QCString mapName=escapeCharsInString(m_startNode->m_label,FALSE); + if (m_inverse) mapName+="dep"; + + QCString imgExt = Config_getEnum("DOT_IMAGE_FORMAT"); + QCString absBaseName = QCString(d.absPath())+"/"+baseName; + QCString absDotName = absBaseName+".dot"; + QCString absMapName = absBaseName+".map"; + QCString absPdfName = absBaseName+".pdf"; + QCString absEpsName = absBaseName+".eps"; + QCString absImgName = absBaseName+"."+imgExt; + + bool regenerate = FALSE; + if (updateDotGraph(m_startNode, + DotNode::Dependency, + absBaseName, + format, + FALSE, // lrRank + FALSE, // renderParents + m_inverse // backArrows + ) || + !checkDeliverables(format==BITMAP ? absImgName : + usePDFLatex ? absPdfName : absEpsName, + format==BITMAP && generateImageMap ? absMapName : QCString()) + ) + { + regenerate=TRUE; + if (format==BITMAP) + { + // run dot to create a bitmap image + QCString dotArgs(maxCmdLine); + DotRunner *dotRun = new DotRunner(absDotName,d.absPath().data(),TRUE,absImgName); + dotRun->addJob(imgExt,absImgName); + if (generateImageMap) dotRun->addJob(MAP_CMD,absMapName); + DotManager::instance()->addRun(dotRun); + } + else if (format==EPS) + { + DotRunner *dotRun = new DotRunner(absDotName,d.absPath().data(),FALSE); + if (usePDFLatex) + { + dotRun->addJob("pdf",absPdfName); + } + else + { + dotRun->addJob("ps",absEpsName); + } + DotManager::instance()->addRun(dotRun); + + } + } + Doxygen::indexList.addImageFile(baseName+"."+imgExt); + + if (format==BITMAP && generateImageMap) + { + if (imgExt=="svg") // Scalable vector graphics + { + out << "<div class=\"center\">"; + if (regenerate || !writeSVGFigureLink(out,relPath,baseName,absImgName)) // need to patch the links in the generated SVG file + { + if (regenerate) + { + DotManager::instance()->addSVGConversion(absImgName,relPath,FALSE,QCString(),TRUE,graphId); + } + int mapId = DotManager::instance()->addSVGObject(fileName,baseName,absImgName,relPath); + out << "<!-- SVG " << mapId << " -->" << endl; + } + out << "</div>" << endl; + } + else // bitmap graphics + { + out << "<div class=\"center\"><img src=\"" << relPath << baseName << "." + << imgExt << "\" border=\"0\" usemap=\"#" + << mapName << "\" alt=\"\"/>"; + out << "</div>" << endl; + + QCString absMapName = absBaseName+".map"; + if (regenerate || !insertMapFile(out,absMapName,relPath,mapName)) + { + int mapId = DotManager::instance()->addMap(fileName,absMapName,relPath, + FALSE,QCString(),mapName); + out << "<!-- MAP " << mapId << " -->" << endl; + } + } + } + else if (format==EPS) // encapsulated postscript + { + if (regenerate || !writeVecGfxFigure(out,baseName,absBaseName)) + { + int figId = DotManager::instance()->addFigure(fileName,baseName,absBaseName,FALSE); + out << endl << "% FIG " << figId << endl; + } + } + if (!regenerate) removeDotGraph(absDotName); + + return baseName; +} + +bool DotInclDepGraph::isTrivial() const +{ + return m_startNode->m_children==0; +} + +bool DotInclDepGraph::isTooBig() const +{ + static int maxNodes = Config_getInt("DOT_GRAPH_MAX_NODES"); + int numNodes = m_startNode->m_children ? m_startNode->m_children->count() : 0; + return numNodes>=maxNodes; +} + +void DotInclDepGraph::writeXML(FTextStream &t) +{ + QDictIterator<DotNode> dni(*m_usedNodes); + DotNode *node; + for (;(node=dni.current());++dni) + { + node->writeXML(t,FALSE); + } +} + +//------------------------------------------------------------- + +int DotCallGraph::m_curNodeNumber = 0; + +void DotCallGraph::buildGraph(DotNode *n,MemberDef *md,int distance) +{ + LockingPtr<MemberSDict> refs = m_inverse ? md->getReferencedByMembers() : md->getReferencesMembers(); + if (!refs.isNull()) + { + MemberSDict::Iterator mri(*refs); + MemberDef *rmd; + for (;(rmd=mri.current());++mri) + { + if (rmd->isFunction() || rmd->isSlot() || rmd->isSignal()) + { + QCString uniqueId; + uniqueId=rmd->getReference()+"$"+ + rmd->getOutputFileBase()+"#"+rmd->anchor(); + DotNode *bn = m_usedNodes->find(uniqueId); + if (bn) // file is already a node in the graph + { + n->addChild(bn,0,0,0); + bn->addParent(n); + bn->setDistance(distance); + } + else + { + QCString name; + if (Config_getBool("HIDE_SCOPE_NAMES")) + { + name = rmd->getOuterScope()==m_scope ? + rmd->name() : rmd->qualifiedName(); + } + else + { + name = rmd->qualifiedName(); + } + QCString tooltip = rmd->briefDescriptionAsTooltip(); + bn = new DotNode( + m_curNodeNumber++, + linkToText(rmd->getLanguage(),name,FALSE), + tooltip, + uniqueId, + 0 //distance + ); + n->addChild(bn,0,0,0); + bn->addParent(n); + bn->setDistance(distance); + m_usedNodes->insert(uniqueId,bn); + + buildGraph(bn,rmd,distance+1); + } + } + } + } +} + +void DotCallGraph::determineVisibleNodes(QList<DotNode> &queue, int &maxNodes) +{ + while (queue.count()>0 && maxNodes>0) + { + static int maxDistance = Config_getInt("MAX_DOT_GRAPH_DEPTH"); + DotNode *n = queue.take(0); + if (!n->isVisible() && n->distance()<maxDistance) // not yet processed + { + n->markAsVisible(); + maxNodes--; + // add direct children + if (n->m_children) + { + QListIterator<DotNode> li(*n->m_children); + DotNode *dn; + for (li.toFirst();(dn=li.current());++li) + { + queue.append(dn); + } + } + } + } +} + +void DotCallGraph::determineTruncatedNodes(QList<DotNode> &queue) +{ + while (queue.count()>0) + { + DotNode *n = queue.take(0); + if (n->isVisible() && n->isTruncated()==DotNode::Unknown) + { + bool truncated = FALSE; + if (n->m_children) + { + QListIterator<DotNode> li(*n->m_children); + DotNode *dn; + for (li.toFirst();(dn=li.current());++li) + { + if (!dn->isVisible()) + truncated = TRUE; + else + queue.append(dn); + } + } + n->markAsTruncated(truncated); + } + } +} + + + +DotCallGraph::DotCallGraph(MemberDef *md,bool inverse) +{ + m_maxDistance = 0; + m_inverse = inverse; + m_diskName = md->getOutputFileBase()+"_"+md->anchor(); + m_scope = md->getOuterScope(); + QCString uniqueId; + uniqueId = md->getReference()+"$"+ + md->getOutputFileBase()+"#"+md->anchor(); + QCString name; + if (Config_getBool("HIDE_SCOPE_NAMES")) + { + name = md->name(); + } + else + { + name = md->qualifiedName(); + } + m_startNode = new DotNode(m_curNodeNumber++, + linkToText(md->getLanguage(),name,FALSE), + "", + uniqueId.data(), + TRUE // root node + ); + m_startNode->setDistance(0); + m_usedNodes = new QDict<DotNode>(1009); + m_usedNodes->insert(uniqueId,m_startNode); + buildGraph(m_startNode,md,1); + + static int nodes = Config_getInt("DOT_GRAPH_MAX_NODES"); + int maxNodes = nodes; + //int directChildNodes = 1; + //if (m_startNode->m_children!=0) + // directChildNodes+=m_startNode->m_children->count(); + //if (directChildNodes>maxNodes) maxNodes=directChildNodes; + QList<DotNode> openNodeQueue; + openNodeQueue.append(m_startNode); + determineVisibleNodes(openNodeQueue,maxNodes); + openNodeQueue.clear(); + openNodeQueue.append(m_startNode); + determineTruncatedNodes(openNodeQueue); +} + +DotCallGraph::~DotCallGraph() +{ + deleteNodes(m_startNode); + delete m_usedNodes; +} + +QCString DotCallGraph::writeGraph(FTextStream &out, GraphOutputFormat format, + const char *path,const char *fileName, + const char *relPath,bool generateImageMap,int + graphId) const +{ + QDir d(path); + // store the original directory + if (!d.exists()) + { + err("error: Output dir %s does not exist!\n",path); exit(1); + } + static bool usePDFLatex = Config_getBool("USE_PDFLATEX"); + + QCString baseName = m_diskName + (m_inverse ? "_icgraph" : "_cgraph"); + QCString mapName = baseName; + + QCString imgExt = Config_getEnum("DOT_IMAGE_FORMAT"); + QCString absBaseName = QCString(d.absPath())+"/"+baseName; + QCString absDotName = absBaseName+".dot"; + QCString absMapName = absBaseName+".map"; + QCString absPdfName = absBaseName+".pdf"; + QCString absEpsName = absBaseName+".eps"; + QCString absImgName = absBaseName+"."+imgExt; + + bool regenerate=FALSE; + if (updateDotGraph(m_startNode, + DotNode::CallGraph, + absBaseName, + format, + TRUE, // lrRank + FALSE, // renderParents + m_inverse // backArrows + ) || + !checkDeliverables(format==BITMAP ? absImgName : + usePDFLatex ? absPdfName : absEpsName, + format==BITMAP && generateImageMap ? absMapName : QCString()) + ) + { + regenerate=TRUE; + if (format==BITMAP) + { + // run dot to create a bitmap image + QCString dotArgs(maxCmdLine); + DotRunner *dotRun = new DotRunner(absDotName,d.absPath().data(),TRUE,absImgName); + dotRun->addJob(imgExt,absImgName); + if (generateImageMap) dotRun->addJob(MAP_CMD,absMapName); + DotManager::instance()->addRun(dotRun); + + } + else if (format==EPS) + { + // run dot to create a .eps image + DotRunner *dotRun = new DotRunner(absDotName,d.absPath().data(),FALSE); + if (usePDFLatex) + { + dotRun->addJob("pdf",absPdfName); + } + else + { + dotRun->addJob("ps",absEpsName); + } + DotManager::instance()->addRun(dotRun); + + } + } + Doxygen::indexList.addImageFile(baseName+"."+imgExt); + + if (format==BITMAP && generateImageMap) + { + if (imgExt=="svg") // Scalable vector graphics + { + out << "<div class=\"center\">"; + if (regenerate || !writeSVGFigureLink(out,relPath,baseName,absImgName)) // need to patch the links in the generated SVG file + { + if (regenerate) + { + DotManager::instance()->addSVGConversion(absImgName,relPath,FALSE,QCString(),TRUE,graphId); + } + int mapId = DotManager::instance()->addSVGObject(fileName,baseName,absImgName,relPath); + out << "<!-- SVG " << mapId << " -->" << endl; + } + out << "</div>" << endl; + } + else // bitmap graphics + { + out << "<div class=\"center\"><img src=\"" << relPath << baseName << "." + << imgExt << "\" border=\"0\" usemap=\"#" + << mapName << "\" alt=\""; + out << "\"/>"; + out << "</div>" << endl; + + if (regenerate || !insertMapFile(out,absMapName,relPath,mapName)) + { + int mapId = DotManager::instance()->addMap(fileName,absMapName,relPath, + FALSE,QCString(),mapName); + out << "<!-- MAP " << mapId << " -->" << endl; + } + } + } + else if (format==EPS) // encapsulated postscript + { + if (regenerate || !writeVecGfxFigure(out,baseName,absBaseName)) + { + int figId = DotManager::instance()->addFigure(fileName,baseName,absBaseName,FALSE); + out << endl << "% FIG " << figId << endl; + } + } + if (!regenerate) removeDotGraph(absDotName); + + return baseName; +} + +bool DotCallGraph::isTrivial() const +{ + return m_startNode->m_children==0; +} + +bool DotCallGraph::isTooBig() const +{ + static int maxNodes = Config_getInt("DOT_GRAPH_MAX_NODES"); + int numNodes = m_startNode->m_children ? m_startNode->m_children->count() : 0; + return numNodes>=maxNodes; +} + +//------------------------------------------------------------- + +DotDirDeps::DotDirDeps(DirDef *dir) : m_dir(dir) +{ +} + +DotDirDeps::~DotDirDeps() +{ +} + +QCString DotDirDeps::writeGraph(FTextStream &out, + GraphOutputFormat format, + const char *path, + const char *fileName, + const char *relPath, + bool generateImageMap, + int graphId) const +{ + QDir d(path); + // store the original directory + if (!d.exists()) + { + err("error: Output dir %s does not exist!\n",path); exit(1); + } + static bool usePDFLatex = Config_getBool("USE_PDFLATEX"); + + QCString baseName=m_dir->getOutputFileBase()+"_dep"; + QCString mapName=escapeCharsInString(baseName,FALSE); + + QCString imgExt = Config_getEnum("DOT_IMAGE_FORMAT"); + QCString absBaseName = QCString(d.absPath())+"/"+baseName; + QCString absDotName = absBaseName+".dot"; + QCString absMapName = absBaseName+".map"; + QCString absPdfName = absBaseName+".pdf"; + QCString absEpsName = absBaseName+".eps"; + QCString absImgName = absBaseName+"."+imgExt; + + // compute md5 checksum of the graph were are about to generate + QGString theGraph; + FTextStream md5stream(&theGraph); + m_dir->writeDepGraph(md5stream); + uchar md5_sig[16]; + QCString sigStr(33); + MD5Buffer((const unsigned char *)theGraph.data(),theGraph.length(),md5_sig); + MD5SigToString(md5_sig,sigStr.data(),33); + bool regenerate=FALSE; + if (checkAndUpdateMd5Signature(absBaseName,sigStr) || + !checkDeliverables(format==BITMAP ? absImgName : + usePDFLatex ? absPdfName : absEpsName, + format==BITMAP && generateImageMap ? absMapName : QCString()) + ) + { + regenerate=TRUE; + + QFile f(absDotName); + if (!f.open(IO_WriteOnly)) + { + err("Cannot create file %s.dot for writing!\n",baseName.data()); + } + FTextStream t(&f); + t << theGraph.data(); + f.close(); + + if (format==BITMAP) + { + // run dot to create a bitmap image + QCString dotArgs(maxCmdLine); + DotRunner *dotRun = new DotRunner(absDotName,d.absPath().data(),TRUE,absImgName); + dotRun->addJob(imgExt,absImgName); + if (generateImageMap) dotRun->addJob(MAP_CMD,absMapName); + DotManager::instance()->addRun(dotRun); + } + else if (format==EPS) + { + DotRunner *dotRun = new DotRunner(absDotName,d.absPath().data(),FALSE); + if (usePDFLatex) + { + dotRun->addJob("pdf",absPdfName); + } + else + { + dotRun->addJob("ps",absEpsName); + } + DotManager::instance()->addRun(dotRun); + } + } + Doxygen::indexList.addImageFile(baseName+"."+imgExt); + + if (format==BITMAP && generateImageMap) + { + if (imgExt=="svg") // Scalable vector graphics + { + out << "<div class=\"center\">"; + if (regenerate || !writeSVGFigureLink(out,relPath,baseName,absImgName)) // need to patch the links in the generated SVG file + { + if (regenerate) + { + DotManager::instance()->addSVGConversion(absImgName,relPath,FALSE,QCString(),TRUE,graphId); + } + int mapId = DotManager::instance()->addSVGObject(fileName,baseName,absImgName,relPath); + out << "<!-- SVG " << mapId << " -->" << endl; + } + out << "</div>" << endl; + } + else // bitmap graphics + { + out << "<div class=\"center\"><img src=\"" << relPath << baseName << "." + << imgExt << "\" border=\"0\" usemap=\"#" + << mapName << "\" alt=\""; + out << convertToXML(m_dir->displayName()); + out << "\"/>"; + out << "</div>" << endl; + + if (regenerate || !insertMapFile(out,absMapName,relPath,mapName)) + { + int mapId = DotManager::instance()->addMap(fileName,absMapName,relPath, + TRUE,QCString(),mapName); + out << "<!-- MAP " << mapId << " -->" << endl; + } + } + } + else if (format==EPS) + { + if (regenerate || !writeVecGfxFigure(out,baseName,absBaseName)) + { + int figId = DotManager::instance()->addFigure(fileName,baseName,absBaseName,FALSE); + out << endl << "% FIG " << figId << endl; + } + } + if (!regenerate) removeDotGraph(absDotName); + + return baseName; +} + +bool DotDirDeps::isTrivial() const +{ + return m_dir->depGraphIsTrivial(); +} + +//------------------------------------------------------------- + +void generateGraphLegend(const char *path) +{ + QDir d(path); + // store the original directory + if (!d.exists()) + { + err("error: Output dir %s does not exist!\n",path); exit(1); + } + + QGString theGraph; + FTextStream md5stream(&theGraph); + writeGraphHeader(md5stream); + md5stream << " Node9 [shape=\"box\",label=\"Inherited\",fontsize=\"" << FONTSIZE << "\",height=0.2,width=0.4,fontname=\"" << FONTNAME << "\",fillcolor=\"grey75\",style=\"filled\" fontcolor=\"black\"];\n"; + md5stream << " Node10 -> Node9 [dir=\"back\",color=\"midnightblue\",fontsize=\"" << FONTSIZE << "\",style=\"solid\",fontname=\"" << FONTNAME << "\"];\n"; + md5stream << " Node10 [shape=\"box\",label=\"PublicBase\",fontsize=\"" << FONTSIZE << "\",height=0.2,width=0.4,fontname=\"" << FONTNAME << "\",color=\"black\",URL=\"$classPublicBase" << Doxygen::htmlFileExtension << "\"];\n"; + md5stream << " Node11 -> Node10 [dir=\"back\",color=\"midnightblue\",fontsize=\"" << FONTSIZE << "\",style=\"solid\",fontname=\"" << FONTNAME << "\"];\n"; + md5stream << " Node11 [shape=\"box\",label=\"Truncated\",fontsize=\"" << FONTSIZE << "\",height=0.2,width=0.4,fontname=\"" << FONTNAME << "\",color=\"red\",URL=\"$classTruncated" << Doxygen::htmlFileExtension << "\"];\n"; + md5stream << " Node13 -> Node9 [dir=\"back\",color=\"darkgreen\",fontsize=\"" << FONTSIZE << "\",style=\"solid\",fontname=\"" << FONTNAME << "\"];\n"; + md5stream << " Node13 [shape=\"box\",label=\"ProtectedBase\",fontsize=\"" << FONTSIZE << "\",height=0.2,width=0.4,fontname=\"" << FONTNAME << "\",color=\"black\",URL=\"$classProtectedBase" << Doxygen::htmlFileExtension << "\"];\n"; + md5stream << " Node14 -> Node9 [dir=\"back\",color=\"firebrick4\",fontsize=\"" << FONTSIZE << "\",style=\"solid\",fontname=\"" << FONTNAME << "\"];\n"; + md5stream << " Node14 [shape=\"box\",label=\"PrivateBase\",fontsize=\"" << FONTSIZE << "\",height=0.2,width=0.4,fontname=\"" << FONTNAME << "\",color=\"black\",URL=\"$classPrivateBase" << Doxygen::htmlFileExtension << "\"];\n"; + md5stream << " Node15 -> Node9 [dir=\"back\",color=\"midnightblue\",fontsize=\"" << FONTSIZE << "\",style=\"solid\",fontname=\"" << FONTNAME << "\"];\n"; + md5stream << " Node15 [shape=\"box\",label=\"Undocumented\",fontsize=\"" << FONTSIZE << "\",height=0.2,width=0.4,fontname=\"" << FONTNAME << "\",color=\"grey75\"];\n"; + md5stream << " Node16 -> Node9 [dir=\"back\",color=\"midnightblue\",fontsize=\"" << FONTSIZE << "\",style=\"solid\",fontname=\"" << FONTNAME << "\"];\n"; + md5stream << " Node16 [shape=\"box\",label=\"Templ< int >\",fontsize=\"" << FONTSIZE << "\",height=0.2,width=0.4,fontname=\"" << FONTNAME << "\",color=\"black\",URL=\"$classTempl" << Doxygen::htmlFileExtension << "\"];\n"; + md5stream << " Node17 -> Node16 [dir=\"back\",color=\"orange\",fontsize=\"" << FONTSIZE << "\",style=\"dashed\",label=\"< int >\",fontname=\"" << FONTNAME << "\"];\n"; + md5stream << " Node17 [shape=\"box\",label=\"Templ< T >\",fontsize=\"" << FONTSIZE << "\",height=0.2,width=0.4,fontname=\"" << FONTNAME << "\",color=\"black\",URL=\"$classTempl" << Doxygen::htmlFileExtension << "\"];\n"; + md5stream << " Node18 -> Node9 [dir=\"back\",color=\"darkorchid3\",fontsize=\"" << FONTSIZE << "\",style=\"dashed\",label=\"m_usedClass\",fontname=\"" << FONTNAME << "\"];\n"; + md5stream << " Node18 [shape=\"box\",label=\"Used\",fontsize=\"" << FONTSIZE << "\",height=0.2,width=0.4,fontname=\"" << FONTNAME << "\",color=\"black\",URL=\"$classUsed" << Doxygen::htmlFileExtension << "\"];\n"; + writeGraphFooter(md5stream); + uchar md5_sig[16]; + QCString sigStr(33); + MD5Buffer((const unsigned char *)theGraph.data(),theGraph.length(),md5_sig); + MD5SigToString(md5_sig,sigStr.data(),33); + QCString absBaseName = (QCString)path+"/graph_legend"; + QCString absDotName = absBaseName+".dot"; + QCString imgExt = Config_getEnum("DOT_IMAGE_FORMAT"); + QCString imgName = "graph_legend."+imgExt; + QCString absImgName = absBaseName+"."+imgExt; + if (checkAndUpdateMd5Signature(absBaseName,sigStr) || + !checkDeliverables(absImgName)) + { + QFile dotFile(absDotName); + if (!dotFile.open(IO_WriteOnly)) + { + err("Could not open file %s for writing\n", + convertToQCString(dotFile.name()).data()); + return; + } + + FTextStream dotText(&dotFile); + dotText << theGraph; + dotFile.close(); + + // run dot to generate the a bitmap image from the graph + + DotRunner *dotRun = new DotRunner(absDotName,d.absPath().data(),TRUE,absImgName); + dotRun->addJob(imgExt,absImgName); + DotManager::instance()->addRun(dotRun); + } + else + { + removeDotGraph(absDotName); + } + Doxygen::indexList.addImageFile(imgName); + + if (imgExt=="svg") + { + DotManager::instance()->addSVGObject( + absBaseName+Config_getString("HTML_FILE_EXTENSION"), + "graph_legend", + absImgName,QCString()); + } + +} + +void writeDotGraphFromFile(const char *inFile,const char *outDir, + const char *outFile,GraphOutputFormat format) +{ + QDir d(outDir); + if (!d.exists()) + { + err("error: Output dir %s does not exist!\n",outDir); exit(1); + } + + QCString imgExt = Config_getEnum("DOT_IMAGE_FORMAT"); + QCString imgName = (QCString)outFile+"."+imgExt; + QCString absImgName = QCString(d.absPath())+"/"+imgName; + QCString absOutFile = QCString(d.absPath())+"/"+outFile; + + DotRunner dotRun(inFile,d.absPath().data(),FALSE,absImgName); + if (format==BITMAP) + dotRun.addJob(imgExt,absImgName); + else // format==EPS + { + if (Config_getBool("USE_PDFLATEX")) + { + dotRun.addJob("pdf",absOutFile+".pdf"); + } + else + { + dotRun.addJob("ps",absOutFile+".eps"); + } + } + + dotRun.preventCleanUp(); + if (!dotRun.run()) + { + return; + } + + if (format==BITMAP) checkDotResult(absImgName); + + Doxygen::indexList.addImageFile(imgName); + +} + + +/*! Writes user defined image map to the output. + * \param t text stream to write to + * \param inFile just the basename part of the filename + * \param outDir output directory + * \param relPath relative path the to root of the output dir + * \param baseName the base name of the output files + * \param context the scope in which this graph is found (for resolving links) + * \param graphId a unique id for this graph, use for dynamic sections + */ +void writeDotImageMapFromFile(FTextStream &t, + const QCString &inFile, const QCString &outDir, + const QCString &relPath, const QCString &baseName, + const QCString &context,int graphId) +{ + + QDir d(outDir); + if (!d.exists()) + { + err("error: Output dir %s does not exist!\n",outDir.data()); exit(1); + } + + QCString mapName = baseName+".map"; + QCString imgExt = Config_getEnum("DOT_IMAGE_FORMAT"); + QCString imgName = baseName+"."+imgExt; + QCString absOutFile = QCString(d.absPath())+"/"+mapName; + + DotRunner dotRun(inFile,d.absPath().data(),FALSE); + dotRun.addJob(MAP_CMD,absOutFile); + dotRun.preventCleanUp(); + if (!dotRun.run()) + { + return; + } + + if (imgExt=="svg") // vector graphics + { + //writeSVGFigureLink(t,relPath,inFile,inFile+".svg"); + //DotFilePatcher patcher(inFile+".svg"); + QCString svgName=outDir+"/"+baseName+".svg"; + writeSVGFigureLink(t,relPath,baseName,svgName); + DotFilePatcher patcher(svgName); + patcher.addSVGConversion(relPath,TRUE,context,TRUE,graphId); + patcher.run(); + } + else // bitmap graphics + { + t << "<img src=\"" << relPath << imgName << "\" alt=\"" + << imgName << "\" border=\"0\" usemap=\"#" << mapName << "\"/>" << endl + << "<map name=\"" << mapName << "\" id=\"" << mapName << "\">"; + + convertMapFile(t, absOutFile, relPath ,TRUE, context); + + t << "</map>" << endl; + } + d.remove(absOutFile); +} + +//------------------------------------------------------------- + +DotGroupCollaboration::DotGroupCollaboration(GroupDef* gd) +{ + m_curNodeId = 0; + QCString tmp_url = gd->getReference()+"$"+gd->getOutputFileBase(); + m_usedNodes = new QDict<DotNode>(1009); + m_rootNode = new DotNode(m_curNodeId++, gd->groupTitle(), "", tmp_url, TRUE ); + m_rootNode->markAsVisible(); + m_usedNodes->insert(gd->name(), m_rootNode ); + m_edges.setAutoDelete(TRUE); + + m_diskName = gd->getOutputFileBase(); + + buildGraph( gd ); +} + +DotGroupCollaboration::~DotGroupCollaboration() +{ + delete m_usedNodes; +} + +void DotGroupCollaboration::buildGraph(GroupDef* gd) +{ + QCString tmp_url; + //=========================== + // hierarchy. + + // Write parents + LockingPtr<GroupList> groups = gd->partOfGroups(); + if ( groups!=0 ) + { + GroupListIterator gli(*groups); + GroupDef *d; + for (gli.toFirst();(d=gli.current());++gli) + { + DotNode* nnode = m_usedNodes->find(d->name()); + if ( !nnode ) + { // add node + tmp_url = d->getReference()+"$"+d->getOutputFileBase(); + QCString tooltip = d->briefDescriptionAsTooltip(); + nnode = new DotNode(m_curNodeId++, d->groupTitle(), tooltip, tmp_url ); + nnode->markAsVisible(); + m_usedNodes->insert(d->name(), nnode ); + } + tmp_url = ""; + addEdge( nnode, m_rootNode, DotGroupCollaboration::thierarchy, tmp_url, tmp_url ); + } + } + + // Add subgroups + if ( gd->getSubGroups() && gd->getSubGroups()->count() ) + { + QListIterator<GroupDef> defli(*gd->getSubGroups()); + GroupDef *def; + for (;(def=defli.current());++defli) + { + DotNode* nnode = m_usedNodes->find(def->name()); + if ( !nnode ) + { // add node + tmp_url = def->getReference()+"$"+def->getOutputFileBase(); + QCString tooltip = def->briefDescriptionAsTooltip(); + nnode = new DotNode(m_curNodeId++, def->groupTitle(), tooltip, tmp_url ); + nnode->markAsVisible(); + m_usedNodes->insert(def->name(), nnode ); + } + tmp_url = ""; + addEdge( m_rootNode, nnode, DotGroupCollaboration::thierarchy, tmp_url, tmp_url ); + } + } + + //======================= + // Write collaboration + + // Add members + addMemberList( gd->getMemberList(MemberList::allMembersList) ); + + // Add classes + if ( gd->getClasses() && gd->getClasses()->count() ) + { + ClassSDict::Iterator defli(*gd->getClasses()); + ClassDef *def; + for (;(def=defli.current());++defli) + { + tmp_url = def->getReference()+"$"+def->getOutputFileBase()+Doxygen::htmlFileExtension; + if (!def->anchor().isEmpty()) + { + tmp_url+="#"+def->anchor(); + } + addCollaborationMember( def, tmp_url, DotGroupCollaboration::tclass ); + } + } + + // Add namespaces + if ( gd->getNamespaces() && gd->getNamespaces()->count() ) + { + NamespaceSDict::Iterator defli(*gd->getNamespaces()); + NamespaceDef *def; + for (;(def=defli.current());++defli) + { + tmp_url = def->getReference()+"$"+def->getOutputFileBase()+Doxygen::htmlFileExtension; + addCollaborationMember( def, tmp_url, DotGroupCollaboration::tnamespace ); + } + } + + // Add files + if ( gd->getFiles() && gd->getFiles()->count() ) + { + QListIterator<FileDef> defli(*gd->getFiles()); + FileDef *def; + for (;(def=defli.current());++defli) + { + tmp_url = def->getReference()+"$"+def->getOutputFileBase()+Doxygen::htmlFileExtension; + addCollaborationMember( def, tmp_url, DotGroupCollaboration::tfile ); + } + } + + // Add pages + if ( gd->getPages() && gd->getPages()->count() ) + { + PageSDict::Iterator defli(*gd->getPages()); + PageDef *def; + for (;(def=defli.current());++defli) + { + tmp_url = def->getReference()+"$"+def->getOutputFileBase()+Doxygen::htmlFileExtension; + addCollaborationMember( def, tmp_url, DotGroupCollaboration::tpages ); + } + } + + // Add directories + if ( gd->getDirs() && gd->getDirs()->count() ) + { + QListIterator<DirDef> defli(*gd->getDirs()); + DirDef *def; + for (;(def=defli.current());++defli) + { + tmp_url = def->getReference()+"$"+def->getOutputFileBase()+Doxygen::htmlFileExtension; + addCollaborationMember( def, tmp_url, DotGroupCollaboration::tdir ); + } + } +} + +void DotGroupCollaboration::addMemberList( MemberList* ml ) +{ + if ( !( ml && ml->count()) ) return; + MemberListIterator defli(*ml); + MemberDef *def; + for (;(def=defli.current());++defli) + { + QCString tmp_url = def->getReference()+"$"+def->getOutputFileBase()+Doxygen::htmlFileExtension + +"#"+def->anchor(); + addCollaborationMember( def, tmp_url, DotGroupCollaboration::tmember ); + } +} + +DotGroupCollaboration::Edge* DotGroupCollaboration::addEdge( + DotNode* _pNStart, DotNode* _pNEnd, EdgeType _eType, + const QCString& _label, const QCString& _url ) +{ + // search a existing link. + QListIterator<Edge> lli(m_edges); + Edge* newEdge = 0; + for ( lli.toFirst(); (newEdge=lli.current()); ++lli) + { + if ( newEdge->pNStart==_pNStart && + newEdge->pNEnd==_pNEnd && + newEdge->eType==_eType + ) + { // edge already found + break; + } + } + if ( newEdge==0 ) // new link + { + newEdge = new Edge(_pNStart,_pNEnd,_eType); + m_edges.append( newEdge ); + } + + if (!_label.isEmpty()) + { + newEdge->links.append(new Link(_label,_url)); + } + + return newEdge; +} + +void DotGroupCollaboration::addCollaborationMember( + Definition* def, QCString& url, EdgeType eType ) +{ + // Create group nodes + if ( !def->partOfGroups() ) + return; + GroupListIterator gli(*def->partOfGroups()); + GroupDef *d; + QCString tmp_str; + for (;(d=gli.current());++gli) + { + DotNode* nnode = m_usedNodes->find(d->name()); + if ( nnode != m_rootNode ) + { + if ( nnode==0 ) + { // add node + tmp_str = d->getReference()+"$"+d->getOutputFileBase(); + QCString tooltip = d->briefDescriptionAsTooltip(); + nnode = new DotNode(m_curNodeId++, d->groupTitle(), tooltip, tmp_str ); + nnode->markAsVisible(); + m_usedNodes->insert(d->name(), nnode ); + } + tmp_str = def->qualifiedName(); + addEdge( m_rootNode, nnode, eType, tmp_str, url ); + } + } +} + + +QCString DotGroupCollaboration::writeGraph( FTextStream &t, GraphOutputFormat format, + const char *path, const char *fileName, const char *relPath, + bool writeImageMap,int graphId) const +{ + QDir d(path); + // store the original directory + if (!d.exists()) + { + err("error: Output dir %s does not exist!\n",path); exit(1); + } + static bool usePDFLatex = Config_getBool("USE_PDFLATEX"); + + QGString theGraph; + FTextStream md5stream(&theGraph); + writeGraphHeader(md5stream); + + // clean write flags + QDictIterator<DotNode> dni(*m_usedNodes); + DotNode *pn; + for (dni.toFirst();(pn=dni.current());++dni) + { + pn->clearWriteFlag(); + } + + // write other nodes. + for (dni.toFirst();(pn=dni.current());++dni) + { + pn->write(md5stream,DotNode::Inheritance,format,TRUE,FALSE,FALSE,FALSE); + } + + // write edges + QListIterator<Edge> eli(m_edges); + Edge* edge; + for (eli.toFirst();(edge=eli.current());++eli) + { + edge->write( md5stream ); + } + + writeGraphFooter(md5stream); + resetReNumbering(); + uchar md5_sig[16]; + QCString sigStr(33); + MD5Buffer((const unsigned char *)theGraph.data(),theGraph.length(),md5_sig); + MD5SigToString(md5_sig,sigStr.data(),33); + QCString imgExt = Config_getEnum("DOT_IMAGE_FORMAT"); + QCString baseName = m_diskName; + QCString imgName = baseName+"."+imgExt; + QCString mapName = baseName+".map"; + QCString absPath = d.absPath().data(); + QCString absBaseName = absPath+"/"+baseName; + QCString absDotName = absBaseName+".dot"; + QCString absImgName = absBaseName+"."+imgExt; + QCString absMapName = absBaseName+".map"; + QCString absPdfName = absBaseName+".pdf"; + QCString absEpsName = absBaseName+".eps"; + bool regenerate=FALSE; + if (checkAndUpdateMd5Signature(absBaseName,sigStr) || + !checkDeliverables(format==BITMAP ? absImgName : + usePDFLatex ? absPdfName : absEpsName, + format==BITMAP /*&& generateImageMap*/ ? absMapName : QCString()) + ) + { + regenerate=TRUE; + + QFile dotfile(absDotName); + if (dotfile.open(IO_WriteOnly)) + { + FTextStream tdot(&dotfile); + tdot << theGraph; + dotfile.close(); + } + + if (format==BITMAP) // run dot to create a bitmap image + { + QCString dotArgs(maxCmdLine); + + DotRunner *dotRun = new DotRunner(absDotName,d.absPath().data(),FALSE); + dotRun->addJob(imgExt,absImgName); + if (writeImageMap) dotRun->addJob(MAP_CMD,absMapName); + DotManager::instance()->addRun(dotRun); + + } + else if (format==EPS) + { + DotRunner *dotRun = new DotRunner(absDotName,d.absPath().data(),FALSE); + if (usePDFLatex) + { + dotRun->addJob("pdf",absPdfName); + } + else + { + dotRun->addJob("ps",absEpsName); + } + DotManager::instance()->addRun(dotRun); + } + + } + if (format==BITMAP && writeImageMap) + { + QCString mapLabel = escapeCharsInString(baseName,FALSE); + t << "<center><table><tr><td>"; + + if (imgExt=="svg") + { + t << "<div class=\"center\">"; + if (regenerate || !writeSVGFigureLink(t,relPath,baseName,absImgName)) // need to patch the links in the generated SVG file + { + if (regenerate) + { + DotManager::instance()->addSVGConversion(absImgName,relPath,FALSE,QCString(),TRUE,graphId); + } + int mapId = DotManager::instance()->addSVGObject(fileName,baseName,absImgName,relPath); + t << "<!-- SVG " << mapId << " -->" << endl; + } + t << "</div>" << endl; + } + else + { + t << "<img src=\"" << relPath << imgName + << "\" border=\"0\" alt=\"\" usemap=\"#" + << mapLabel << "\"/>" << endl; + if (regenerate || !insertMapFile(t,absMapName,relPath,mapLabel)) + { + int mapId = DotManager::instance()->addMap(fileName,absMapName,relPath, + FALSE,QCString(),mapLabel); + t << "<!-- MAP " << mapId << " -->" << endl; + } + } + + t << "</td></tr></table></center>" << endl; + } + else if (format==EPS) + { + if (regenerate || !writeVecGfxFigure(t,baseName,absBaseName)) + { + int figId = DotManager::instance()->addFigure(fileName,baseName,absBaseName,FALSE); + t << endl << "% FIG " << figId << endl; + } + } + if (!regenerate) removeDotGraph(absDotName); + + return baseName; +} + +void DotGroupCollaboration::Edge::write( FTextStream &t ) const +{ + const char* linkTypeColor[] = { + "darkorchid3" + ,"orange" + ,"blueviolet" + ,"darkgreen" + ,"firebrick4" + ,"grey75" + ,"midnightblue" + }; + QCString arrowStyle = "dir=\"none\", style=\"dashed\""; + t << " Node" << pNStart->number(); + t << "->"; + t << "Node" << pNEnd->number(); + + t << " [shape=plaintext"; + if (links.count()>0) // there are links + { + t << ", "; + // HTML-like edge labels crash on my Mac with Graphviz 2.0! and + // are not supported by older version of dot. + // + //t << label=<<TABLE BORDER=\"0\" CELLBORDER=\"0\">"; + //QListIterator<Link> lli(links); + //Link *link; + //for( lli.toFirst(); (link=lli.current()); ++lli) + //{ + // t << "<TR><TD"; + // if ( !link->url.isEmpty() ) + // t << " HREF=\"" << link->url << "\""; + // t << ">" << link->label << "</TD></TR>"; + //} + //t << "</TABLE>>"; + + t << "label=\""; + QListIterator<Link> lli(links); + Link *link; + bool first=TRUE; + int count=0; + const int maxLabels = 10; + for( lli.toFirst(); (link=lli.current()) && count<maxLabels; ++lli,++count) + { + if (first) first=FALSE; else t << "\\n"; + t << convertLabel(link->label); + } + if (count==maxLabels) t << "\\n..."; + t << "\""; + + } + switch( eType ) + { + case thierarchy : + arrowStyle = "dir=\"back\", style=\"solid\""; + default : + t << ", color=\"" << linkTypeColor[(int)eType] << "\""; + break; + } + t << ", " << arrowStyle; + t << "];" << endl; +} + +bool DotGroupCollaboration::isTrivial() const +{ + return m_usedNodes->count() <= 1; +} + +void DotGroupCollaboration::writeGraphHeader(FTextStream &t) const +{ + t << "digraph structs" << endl; + t << "{" << endl; + if (Config_getBool("DOT_TRANSPARENT")) + { + t << " bgcolor=\"transparent\";" << endl; + } + t << " edge [fontname=\"" << FONTNAME << "\",fontsize=\"" << FONTSIZE << "\"," + "labelfontname=\"" << FONTNAME << "\",labelfontsize=\"" << FONTSIZE << "\"];\n"; + t << " node [fontname=\"" << FONTNAME << "\",fontsize=\"" << FONTSIZE << "\",shape=record];\n"; + t << " rankdir=LR;\n"; +} + +void writeDotDirDepGraph(FTextStream &t,DirDef *dd) +{ + t << "digraph G {\n"; + if (Config_getBool("DOT_TRANSPARENT")) + { + t << " bgcolor=transparent;\n"; + } + t << " compound=true\n"; + t << " node [ fontsize=\"" << FONTSIZE << "\", fontname=\"" << FONTNAME << "\"];\n"; + t << " edge [ labelfontsize=\"" << FONTSIZE << "\", labelfontname=\"" << FONTNAME << "\"];\n"; + + QDict<DirDef> dirsInGraph(257); + + dirsInGraph.insert(dd->getOutputFileBase(),dd); + if (dd->parent()) + { + t << " subgraph cluster" << dd->parent()->getOutputFileBase() << " {\n"; + t << " graph [ bgcolor=\"#ddddee\", pencolor=\"black\", label=\"" + << dd->parent()->shortName() + << "\" fontname=\"" << FONTNAME << "\", fontsize=\"" << FONTSIZE << "\", URL=\""; + t << dd->parent()->getOutputFileBase() << Doxygen::htmlFileExtension; + t << "\"]\n"; + } + if (dd->isCluster()) + { + t << " subgraph cluster" << dd->getOutputFileBase() << " {\n"; + t << " graph [ bgcolor=\"#eeeeff\", pencolor=\"black\", label=\"\"" + << " URL=\"" << dd->getOutputFileBase() << Doxygen::htmlFileExtension + << "\"];\n"; + t << " " << dd->getOutputFileBase() << " [shape=plaintext label=\"" + << dd->shortName() << "\"];\n"; + + // add nodes for sub directories + QListIterator<DirDef> sdi(dd->subDirs()); + DirDef *sdir; + for (sdi.toFirst();(sdir=sdi.current());++sdi) + { + t << " " << sdir->getOutputFileBase() << " [shape=box label=\"" + << sdir->shortName() << "\""; + if (sdir->isCluster()) + { + t << " color=\"red\""; + } + else + { + t << " color=\"black\""; + } + t << " fillcolor=\"white\" style=\"filled\""; + t << " URL=\"" << sdir->getOutputFileBase() + << Doxygen::htmlFileExtension << "\""; + t << "];\n"; + dirsInGraph.insert(sdir->getOutputFileBase(),sdir); + } + t << " }\n"; + } + else + { + t << " " << dd->getOutputFileBase() << " [shape=box, label=\"" + << dd->shortName() << "\", style=\"filled\", fillcolor=\"#eeeeff\"," + << " pencolor=\"black\", URL=\"" << dd->getOutputFileBase() + << Doxygen::htmlFileExtension << "\"];\n"; + } + if (dd->parent()) + { + t << " }\n"; + } + + // add nodes for other used directories + QDictIterator<UsedDir> udi(*dd->usedDirs()); + UsedDir *udir; + //printf("*** For dir %s\n",shortName().data()); + for (udi.toFirst();(udir=udi.current());++udi) + // for each used dir (=directly used or a parent of a directly used dir) + { + const DirDef *usedDir=udir->dir(); + DirDef *dir=dd; + while (dir) + { + //printf("*** check relation %s->%s same_parent=%d !%s->isParentOf(%s)=%d\n", + // dir->shortName().data(),usedDir->shortName().data(), + // dir->parent()==usedDir->parent(), + // usedDir->shortName().data(), + // shortName().data(), + // !usedDir->isParentOf(this) + // ); + if (dir!=usedDir && dir->parent()==usedDir->parent() && + !usedDir->isParentOf(dd)) + // include if both have the same parent (or no parent) + { + t << " " << usedDir->getOutputFileBase() << " [shape=box label=\"" + << usedDir->shortName() << "\""; + if (usedDir->isCluster()) + { + if (!Config_getBool("DOT_TRANSPARENT")) + { + t << " fillcolor=\"white\" style=\"filled\""; + } + t << " color=\"red\""; + } + t << " URL=\"" << usedDir->getOutputFileBase() + << Doxygen::htmlFileExtension << "\"];\n"; + dirsInGraph.insert(usedDir->getOutputFileBase(),usedDir); + break; + } + dir=dir->parent(); + } + } + + // add relations between all selected directories + DirDef *dir; + QDictIterator<DirDef> di(dirsInGraph); + for (di.toFirst();(dir=di.current());++di) // foreach dir in the graph + { + QDictIterator<UsedDir> udi(*dir->usedDirs()); + UsedDir *udir; + for (udi.toFirst();(udir=udi.current());++udi) // foreach used dir + { + const DirDef *usedDir=udir->dir(); + if ((dir!=dd || !udir->inherited()) && // only show direct dependendies for this dir + (usedDir!=dd || !udir->inherited()) && // only show direct dependendies for this dir + !usedDir->isParentOf(dir) && // don't point to own parent + dirsInGraph.find(usedDir->getOutputFileBase())) // only point to nodes that are in the graph + { + QCString relationName; + relationName.sprintf("dir_%06d_%06d",dir->dirCount(),usedDir->dirCount()); + if (Doxygen::dirRelations.find(relationName)==0) + { + // new relation + Doxygen::dirRelations.append(relationName, + new DirRelation(relationName,dir,udir)); + } + int nrefs = udir->filePairs().count(); + t << " " << dir->getOutputFileBase() << "->" + << usedDir->getOutputFileBase(); + t << " [headlabel=\"" << nrefs << "\", labeldistance=1.5"; + t << " headhref=\"" << relationName << Doxygen::htmlFileExtension + << "\"];\n"; + } + } + } + + t << "}\n"; +} diff --git a/trunk/src/dot.h b/trunk/src/dot.h new file mode 100644 index 0000000..e4acd5a --- /dev/null +++ b/trunk/src/dot.h @@ -0,0 +1,456 @@ +/****************************************************************************** + * + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#ifndef _DOT_H +#define _DOT_H + +#include "qtbc.h" +#include <qlist.h> +#include <qdict.h> +#include <qwaitcondition.h> +#include <qmutex.h> +#include <qqueue.h> +#include <qthread.h> +#include "sortdict.h" + +class ClassDef; +class FileDef; +class FTextStream; +class DotNodeList; +class ClassSDict; +class MemberDef; +class Definition; +class DirDef; +class GroupDef; +class DotGroupCollaboration; +class DotRunnerQueue; + +enum GraphOutputFormat { BITMAP , EPS }; + +/** @brief Attributes of an edge of a dot graph */ +struct EdgeInfo +{ + enum Colors { Blue=0, Green=1, Red=2, Purple=3, Grey=4, Orange=5 }; + enum Styles { Solid=0, Dashed=1 }; + EdgeInfo() : m_color(0), m_style(0), m_labColor(0) {} + ~EdgeInfo() {} + int m_color; + int m_style; + QCString m_label; + QCString m_url; + int m_labColor; +}; + +/** @brief A node in a dot graph */ +class DotNode +{ + public: + enum GraphType { Dependency, Inheritance, Collaboration, Hierarchy, CallGraph }; + enum TruncState { Unknown, Truncated, Untruncated }; + DotNode(int n,const char *lab,const char *tip,const char *url, + bool rootNode=FALSE,ClassDef *cd=0); + ~DotNode(); + void addChild(DotNode *n, + int edgeColor=EdgeInfo::Purple, + int edgeStyle=EdgeInfo::Solid, + const char *edgeLab=0, + const char *edgeURL=0, + int edgeLabCol=-1 + ); + void addParent(DotNode *n); + void deleteNode(DotNodeList &deletedList,SDict<DotNode> *skipNodes=0); + void removeChild(DotNode *n); + void removeParent(DotNode *n); + int findParent( DotNode *n ); + void write(FTextStream &t,GraphType gt,GraphOutputFormat f, + bool topDown,bool toChildren,bool backArrows,bool reNumber); + int m_subgraphId; + void clearWriteFlag(); + void writeXML(FTextStream &t,bool isClassGraph); + void writeDEF(FTextStream &t); + QCString label() const { return m_label; } + int number() const { return m_number; } + bool isVisible() const { return m_visible; } + TruncState isTruncated() const { return m_truncated; } + int distance() const { return m_distance; } + + private: + void colorConnectedNodes(int curColor); + void writeBox(FTextStream &t,GraphType gt,GraphOutputFormat f, + bool hasNonReachableChildren, bool reNumber=FALSE); + void writeArrow(FTextStream &t,GraphType gt,GraphOutputFormat f,DotNode *cn, + EdgeInfo *ei,bool topDown, bool pointBack=TRUE, bool reNumber=FALSE); + void setDistance(int distance); + const DotNode *findDocNode() const; // only works for acyclic graphs! + void markAsVisible(bool b=TRUE) { m_visible=b; } + void markAsTruncated(bool b=TRUE) { m_truncated=b ? Truncated : Untruncated; } + int m_number; + QCString m_label; //!< label text + QCString m_tooltip; //!< node's tooltip + 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 + bool m_deleted; //!< used to mark a node as deleted + bool m_written; //!< used to mark a node as written + bool m_hasDoc; //!< used to mark a node as documented + bool m_isRoot; //!< indicates if this is a root node + ClassDef * m_classDef; //!< class representing this node (can be 0) + bool m_visible; //!< is the node visible in the output + TruncState m_truncated; //!< does the node have non-visible children/parents + int m_distance; //!< shortest path to the root node + + friend class DotGfxHierarchyTable; + friend class DotClassGraph; + friend class DotInclDepGraph; + friend class DotNodeList; + friend class DotCallGraph; + friend class DotGroupCollaboration; + + friend QCString computeMd5Signature( + DotNode *root, GraphType gt, + GraphOutputFormat f, + bool lrRank, bool renderParents, + bool backArrows, + QCString &graphStr + ); +}; + +inline int DotNode::findParent( DotNode *n ) +{ + if( !m_parents ) + return -1; + return m_parents->find(n); +} + +/** @brief Represents a graphical class hierarchy */ +class DotGfxHierarchyTable +{ + public: + DotGfxHierarchyTable(); + ~DotGfxHierarchyTable(); + void writeGraph(FTextStream &t,const char *path, const char *fileName) const; + + private: + void addHierarchy(DotNode *n,ClassDef *cd,bool hide); + void addClassList(ClassSDict *cl); + + QList<DotNode> *m_rootNodes; + QDict<DotNode> *m_usedNodes; + static int m_curNodeNumber; + DotNodeList *m_rootSubgraphs; +}; + +/** @brief Representation of a class inheritance or dependency graph */ +class DotClassGraph +{ + public: + DotClassGraph(ClassDef *cd,DotNode::GraphType t); + ~DotClassGraph(); + bool isTrivial() const; + bool isTooBig() const; + QCString writeGraph(FTextStream &t,GraphOutputFormat f,const char *path, + const char *fileName, const char *relPath, + bool TBRank=TRUE,bool imageMap=TRUE,int graphId=-1) const; + + void writeXML(FTextStream &t); + void writeDEF(FTextStream &t); + QCString diskName() const; + + private: + void buildGraph(ClassDef *cd,DotNode *n,bool base,int distance); + bool determineVisibleNodes(DotNode *rootNode,int maxNodes,bool includeParents); + void determineTruncatedNodes(QList<DotNode> &queue,bool includeParents); + void addClass(ClassDef *cd,DotNode *n,int prot,const char *label, + const char *usedName,const char *templSpec, + bool base,int distance); + + DotNode * m_startNode; + QDict<DotNode> * m_usedNodes; + static int m_curNodeNumber; + DotNode::GraphType m_graphType; + QCString m_diskName; + bool m_lrRank; +}; + +/** @brief Representation of an include dependency graph */ +class DotInclDepGraph +{ + public: + DotInclDepGraph(FileDef *fd,bool inverse); + ~DotInclDepGraph(); + QCString writeGraph(FTextStream &t, GraphOutputFormat f, + const char *path,const char *fileName,const char *relPath, + bool writeImageMap=TRUE,int graphId=-1) const; + bool isTrivial() const; + bool isTooBig() const; + QCString diskName() const; + void writeXML(FTextStream &t); + + private: + void buildGraph(DotNode *n,FileDef *fd,int distance); + void determineVisibleNodes(QList<DotNode> &queue,int &maxNodes); + void determineTruncatedNodes(QList<DotNode> &queue); + + DotNode *m_startNode; + QDict<DotNode> *m_usedNodes; + static int m_curNodeNumber; + QCString m_diskName; + int m_maxDistance; + bool m_inverse; +}; + +/** @brief Representation of an call graph */ +class DotCallGraph +{ + public: + DotCallGraph(MemberDef *md,bool inverse); + ~DotCallGraph(); + QCString writeGraph(FTextStream &t, GraphOutputFormat f, + const char *path,const char *fileName, + const char *relPath,bool writeImageMap=TRUE, + int graphId=-1) const; + void buildGraph(DotNode *n,MemberDef *md,int distance); + bool isTrivial() const; + bool isTooBig() const; + void determineVisibleNodes(QList<DotNode> &queue, int &maxNodes); + void determineTruncatedNodes(QList<DotNode> &queue); + + private: + DotNode *m_startNode; + static int m_curNodeNumber; + QDict<DotNode> *m_usedNodes; + int m_maxDistance; + int m_recDepth; + bool m_inverse; + QCString m_diskName; + Definition * m_scope; +}; + +/** @brief Representation of an directory dependency graph */ +class DotDirDeps +{ + public: + DotDirDeps(DirDef *dir); + ~DotDirDeps(); + bool isTrivial() const; + QCString writeGraph(FTextStream &out, + GraphOutputFormat format, + const char *path, + const char *fileName, + const char *relPath, + bool writeImageMap=TRUE, + int graphId=-1) const; + private: + DirDef *m_dir; +}; + +/** @brief Representation of a group collaboration graph */ +class DotGroupCollaboration +{ + public : + enum EdgeType + { tmember = 0, + tclass, + tnamespace, + tfile, + tpages, + tdir, + thierarchy + }; + + class Link + { + public: + Link(const QCString lab,const QCString &u) : label(lab), url(u) {} + QCString label; + QCString url; + }; + + class Edge + { + public : + Edge(DotNode *start,DotNode *end,EdgeType type) + : pNStart(start), pNEnd(end), eType(type) + { links.setAutoDelete(TRUE); } + + DotNode* pNStart; + DotNode* pNEnd; + EdgeType eType; + + QList<Link> links; + void write( FTextStream &t ) const; + }; + + DotGroupCollaboration(GroupDef* gd); + ~DotGroupCollaboration(); + QCString writeGraph(FTextStream &t, GraphOutputFormat format, + const char *path,const char *fileName,const char *relPath, + bool writeImageMap=TRUE,int graphId=-1) const; + void buildGraph(GroupDef* gd); + bool isTrivial() const; + private : + void addCollaborationMember( Definition* def, QCString& url, EdgeType eType ); + void addMemberList( class MemberList* ml ); + void writeGraphHeader(FTextStream &t) const; + Edge* addEdge( DotNode* _pNStart, DotNode* _pNEnd, EdgeType _eType, + const QCString& _label, const QCString& _url ); + + DotNode *m_rootNode; + int m_curNodeId; + QDict<DotNode> *m_usedNodes; + QCString m_diskName; + QList<Edge> m_edges; +}; + +/** @brief Helper class to run dot from doxygen. + */ +class DotRunner +{ + public: + struct CleanupItem + { + QCString path; + QCString file; + }; + + /** Creates a runner for a dot \a file. */ + DotRunner(const QCString &file,const QCString &fontPath,bool checkResult, + const QCString &imageName = QCString()); + + /** Adds an additional job to the run. + * Performing multiple jobs one file can be faster. + */ + void addJob(const char *format,const char *output); + + void addPostProcessing(const char *cmd,const char *args); + + void preventCleanUp() { m_cleanUp = FALSE; } + + /** Runs dot for all jobs added. */ + bool run(); + CleanupItem cleanup() const { return m_cleanupItem; } + + private: + QList<QCString> m_jobs; + QCString m_postArgs; + QCString m_postCmd; + QCString m_file; + QCString m_path; + bool m_checkResult; + QCString m_imageName; + bool m_cleanUp; + CleanupItem m_cleanupItem; +}; + +/** @brief Helper class to insert a set of map file into an output file */ +class DotFilePatcher +{ + public: + struct Map + { + QCString mapFile; + QCString relPath; + bool urlOnly; + QCString context; + QCString label; + bool zoomable; + int graphId; + }; + DotFilePatcher(const char *patchFile); + int addMap(const QCString &mapFile,const QCString &relPath, + bool urlOnly,const QCString &context,const QCString &label); + int addFigure(const QCString &baseName, + const QCString &figureName,bool heightCheck); + int addSVGConversion(const QCString &relPath,bool urlOnly, + const QCString &context,bool zoomable,int graphId); + int addSVGObject(const QCString &baseName, const QCString &figureName, + const QCString &relPath); + bool run(); + QCString file() const; + + private: + QList<Map> m_maps; + QCString m_patchFile; +}; + +class DotRunnerQueue +{ + public: + void enqueue(DotRunner *runner); + DotRunner *dequeue(); + uint count() const; + private: + QWaitCondition m_bufferNotEmpty; + QQueue<DotRunner> m_queue; + mutable QMutex m_mutex; +}; + +class DotWorkerThread : public QThread +{ + public: + DotWorkerThread(int id,DotRunnerQueue *queue); + void run(); + void cleanup(); + private: + int m_id; + DotRunnerQueue *m_queue; + QList<DotRunner::CleanupItem> m_cleanupItems; +}; + +/** @brief singleton that manages dot relation actions */ +class DotManager +{ + public: + static DotManager *instance(); + void addRun(DotRunner *run); + int addMap(const QCString &file,const QCString &mapFile, + const QCString &relPath,bool urlOnly, + const QCString &context,const QCString &label); + int addFigure(const QCString &file,const QCString &baseName, + const QCString &figureName,bool heightCheck); + int addSVGConversion(const QCString &file,const QCString &relPath, + bool urlOnly,const QCString &context,bool zoomable,int graphId); + int addSVGObject(const QCString &file,const QCString &baseName, + const QCString &figureNAme,const QCString &relPath); + bool run(); + + private: + DotManager(); + virtual ~DotManager(); + QList<DotRunner> m_dotRuns; + SDict<DotFilePatcher> m_dotMaps; + static DotManager *m_theInstance; + DotRunnerQueue *m_queue; + QList<DotWorkerThread> m_workers; +}; + + +/** Generated a graphs legend page */ +void generateGraphLegend(const char *path); + +void writeDotGraphFromFile(const char *inFile,const char *outDir, + const char *outFile,GraphOutputFormat format); +void writeDotImageMapFromFile(FTextStream &t, + const QCString& inFile, const QCString& outDir, + const QCString& relPath,const QCString& baseName, + const QCString& context,int graphId=-1); + +void writeDotDirDepGraph(FTextStream &t,DirDef *dd); + +#endif diff --git a/trunk/src/doxygen.bst b/trunk/src/doxygen.bst new file mode 100644 index 0000000..c6ae7a8 --- /dev/null +++ b/trunk/src/doxygen.bst @@ -0,0 +1,1388 @@ + % $Id: html-btxbst.doc 1.5 2010/12/08 19:02:34 dds Exp $ + % + % This file is either "html-btxbst.doc" or was derived from + % "html-btxbst.doc" using cpp. "html-btxbst.doc" itself was edited + % from "btxbst.doc" and "named.bst". + % The following copyright information is from btxbst.doc: + % version 0.99b for BibTeX versions 0.99a or later, LaTeX version 2.09. + % Copyright (C) 1985, all rights reserved. + % Copying of this file is authorized only if either + % (1) you make absolutely no changes to your copy, including name, or + % (2) if you do make changes, you name it something other than + % btxbst.doc, plain.bst, unsrt.bst, alpha.bst, and abbrv.bst. + % This restriction helps ensure that all standard styles are identical. + % The file btxbst.doc has the documentation for this style. + % "named" style (sorted keys of the form [name, year]) + % Some code for this was taken from "named.bst". + +ENTRY + { address + author + booktitle + chapter + edition + editor + howpublished + institution + journal + key + month + note + number + organization + pages + publisher + school + series + title + type + volume + year + dvi + html + keywords + pdf + postscript + url + doi + mailto + } + {} + { label extra.label sort.label } + +INTEGERS { output.state before.all mid.sentence after.sentence after.block } + +FUNCTION {init.state.consts} +{ #0 'before.all := + #1 'mid.sentence := + #2 'after.sentence := + #3 'after.block := +} + +STRINGS { s t } + +FUNCTION {output.nonnull} +{ 's := + output.state mid.sentence = + { ", " * write$ } + { output.state after.block = + { add.period$ write$ + newline$ + } + { output.state before.all = + 'write$ + { add.period$ " " * write$ } + if$ + } + if$ + mid.sentence 'output.state := + } + if$ + s +} + +FUNCTION {output} +{ duplicate$ empty$ + 'pop$ + 'output.nonnull + if$ +} + +FUNCTION {output.check} +{ 't := + duplicate$ empty$ + { pop$ "empty " t * " in " * cite$ * warning$ } + 'output.nonnull + if$ +} + +FUNCTION {output.bibitem} +{ newline$ + author empty$ + { editor empty$ + { organization empty$ + 'skip$ + { "<!-- Authors: " organization purify$ * " -->" * write$ newline$ } + if$ + } + { "<!-- Authors: " editor purify$ * " -->" * write$ newline$ } + if$ + } + { "<!-- Authors: " author purify$ * " -->" * write$ newline$ } + if$ + keywords empty$ + 'skip$ + { "<!-- Keywords: " keywords * " -->" * write$ newline$ } + if$ + "<dt><a name=" quote$ * "CITEREF_" * cite$ * quote$ * ">[" * label * "]</a></dt><dd>" * write$ + "" + before.all 'output.state := +} + +FUNCTION {fin.entry} +{ add.period$ + write$ + postscript empty$ + 'skip$ + { newline$ "<!-- PostScript: " postscript * " -->" * write$ } + if$ + pdf empty$ + 'skip$ + { newline$ "<!-- PDF: " pdf * " -->" * write$ } + if$ + dvi empty$ + 'skip$ + { newline$ "<!-- DVI: " dvi * " -->" * write$ } + if$ + doi empty$ + 'skip$ + { newline$ "<!-- DOI: " doi * " -->" * write$ } + if$ + "</dd>" write$ + newline$ + newline$ +} + +FUNCTION {new.block} +{ output.state before.all = + 'skip$ + { after.block 'output.state := } + if$ +} + +FUNCTION {new.sentence} +{ output.state after.block = + 'skip$ + { output.state before.all = + 'skip$ + { after.sentence 'output.state := } + if$ + } + if$ +} + +FUNCTION {not} +{ { #0 } + { #1 } + if$ +} + +FUNCTION {and} +{ 'skip$ + { pop$ #0 } + if$ +} + +FUNCTION {or} +{ { pop$ #1 } + 'skip$ + if$ +} + +FUNCTION {str.to.int} +{ + 's := + #0 + { s empty$ not } + { % Multiply the number on the top of the stack by 10 = 1010 binary + duplicate$ + % x2 + duplicate$ % x2 x2 + duplicate$ + duplicate$ + % x2 x8 + + + s #1 #1 substring$ chr.to.int$ #48 - + % #48 is ascii for '0' + s #2 global.max$ substring$ 's := + } + while$ +} + +FUNCTION {new.block.checka} +{ empty$ + 'skip$ + 'new.block + if$ +} + +FUNCTION {new.block.checkb} +{ empty$ + swap$ empty$ + and + 'skip$ + 'new.block + if$ +} + +FUNCTION {new.sentence.checka} +{ empty$ + 'skip$ + 'new.sentence + if$ +} + +FUNCTION {new.sentence.checkb} +{ empty$ + swap$ empty$ + and + 'skip$ + 'new.sentence + if$ +} + +FUNCTION {field.or.null} +{ duplicate$ empty$ + { pop$ "" } + 'skip$ + if$ +} + +FUNCTION {emphasize} +{ duplicate$ empty$ + { pop$ "" } + { "<em>" swap$ * "</em>" * } + if$ +} + +FUNCTION {add.link} % title +{ + 't := + t empty$ + { "" } + { url empty$ + { html empty$ + { t } + { "<a href=" quote$ * html * quote$ * ">" * t * "</a>" * } + if$ } + { "<a href=" quote$ * url * quote$ * ">" * t * "</a>" * } + if$ + } + if$ +} + +FUNCTION {add.mailto} % authors +{ + 't := + t empty$ + { "" } + { mailto empty$ + { t } + { "<a href=" quote$ * "mailto:" * mailto * quote$ * ">" * t * "</a>" * } + if$ + } + if$ +} + +INTEGERS { nameptr namesleft numnames } + +FUNCTION {format.names} +{ 's := + #1 'nameptr := + s num.names$ 'numnames := + numnames 'namesleft := + { namesleft #0 > } + { s nameptr "{ff~}{vv~}{ll}{, jj}" format.name$ 't := + "\bibxhtmlname{" t * "}" * 't := + nameptr #1 > + { namesleft #1 > + { ", " * t * } + { numnames #2 > + { "," * } + 'skip$ + if$ + t "others" = + { " et~al." * } + { " and " * t * } + if$ + } + if$ + } + 't + if$ + nameptr #1 + 'nameptr := + namesleft #1 - 'namesleft := + } + while$ +} + +FUNCTION {format.authors} +{ author empty$ + { "" } + { author format.names } + if$ + add.mailto +} + +FUNCTION {format.editors} +{ editor empty$ + { "" } + { editor format.names + editor num.names$ #1 > + { ", editors" * } + { ", editor" * } + if$ + } + if$ +} + +FUNCTION {format.title} +{ title empty$ + { "" } + { title "t" change.case$ } + if$ + add.link +} + +FUNCTION {n.dashify} +{ 't := + "" + { t empty$ not } + { t #1 #1 substring$ "-" = + { t #1 #2 substring$ "--" = not + { "--" * + t #2 global.max$ substring$ 't := + } + { { t #1 #1 substring$ "-" = } + { "-" * + t #2 global.max$ substring$ 't := + } + while$ + } + if$ + } + { t #1 #1 substring$ * + t #2 global.max$ substring$ 't := + } + if$ + } + while$ +} + +FUNCTION {format.date} +{ year empty$ + { month empty$ + { "" } + { "there's a month but no year in " cite$ * warning$ + month + } + if$ + } + { month empty$ + 'year + { month " " * year * } + if$ + } + if$ +} + +FUNCTION {format.btitle} +{ title emphasize + add.link +} + +FUNCTION {tie.or.space.connect} +{ duplicate$ text.length$ #3 < + { "~" } + { " " } + if$ + swap$ * * +} + +FUNCTION {either.or.check} +{ empty$ + 'pop$ + { "can't use both " swap$ * " fields in " * cite$ * warning$ } + if$ +} + +FUNCTION {format.bvolume} +{ volume empty$ + { "" } + { "volume" volume tie.or.space.connect + series empty$ + 'skip$ + { " of " * series emphasize * } + if$ + "volume and number" number either.or.check + } + if$ +} + +FUNCTION {format.number.series} +{ volume empty$ + { number empty$ + { series field.or.null } + { output.state mid.sentence = + { "number" } + { "Number" } + if$ + number tie.or.space.connect + series empty$ + { "there's a number but no series in " cite$ * warning$ } + { " in " * series * } + if$ + } + if$ + } + { "" } + if$ +} + +FUNCTION {format.edition} +{ edition empty$ + { "" } + { output.state mid.sentence = + { edition "l" change.case$ " edition" * } + { edition "t" change.case$ " edition" * } + if$ + } + if$ +} + +INTEGERS { multiresult } + +FUNCTION {multi.page.check} +{ 't := + #0 'multiresult := + { multiresult not + t empty$ not + and + } + { t #1 #1 substring$ + duplicate$ "-" = + swap$ duplicate$ "," = + swap$ "+" = + or or + { #1 'multiresult := } + { t #2 global.max$ substring$ 't := } + if$ + } + while$ + multiresult +} + +FUNCTION {format.pages} +{ pages empty$ + { "" } + { pages multi.page.check + { "pages" pages n.dashify tie.or.space.connect } + { "page" pages tie.or.space.connect } + if$ + } + if$ +} + +FUNCTION {format.vol.num.pages} +{ volume field.or.null + number empty$ + 'skip$ + { "(" number * ")" * * + volume empty$ + { "there's a number but no volume in " cite$ * warning$ } + 'skip$ + if$ + } + if$ + pages empty$ + 'skip$ + { duplicate$ empty$ + { pop$ format.pages } + { ":" * pages n.dashify * } + if$ + } + if$ +} + +FUNCTION {format.chapter.pages} +{ chapter empty$ + 'format.pages + { type empty$ + { "chapter" } + { type "l" change.case$ } + if$ + chapter tie.or.space.connect + pages empty$ + 'skip$ + { ", " * format.pages * } + if$ + } + if$ +} + +FUNCTION {format.in.ed.booktitle} +{ booktitle empty$ + { "" } + { editor empty$ + { "In " booktitle emphasize * } + { "In " format.editors * ", " * booktitle emphasize * } + if$ + } + if$ +} + +FUNCTION {empty.misc.check} +{ author empty$ title empty$ howpublished empty$ + month empty$ year empty$ note empty$ + and and and and and + key empty$ not and + { "all relevant fields are empty in " cite$ * warning$ } + 'skip$ + if$ +} + +FUNCTION {format.thesis.type} +{ type empty$ + 'skip$ + { pop$ + type "t" change.case$ + } + if$ +} + +FUNCTION {format.tr.number} +{ type empty$ + { "Technical Report" } + 'type + if$ + number empty$ + { "t" change.case$ } + { number tie.or.space.connect } + if$ +} + +FUNCTION {format.article.crossref} +{ + "In <a href=" quote$ * "#" * crossref * quote$ * ">" * + key empty$ + { journal empty$ + { "need key or journal for " cite$ * " to crossref " * crossref * + warning$ + "" + } + { "<cite>" * journal * "</cite>" * } + if$ + } + { key * } + if$ + "</a> \citelabel{" * crossref * "}" * +} + +FUNCTION {format.crossref.editor} +{ editor #1 "{vv~}{ll}" format.name$ + editor num.names$ duplicate$ + #2 > + { pop$ " et~al." * } + { #2 < + 'skip$ + { editor #2 "{ff }{vv }{ll}{ jj}" format.name$ "others" = + { " et~al." * } + { " and " * editor #2 "{vv~}{ll}" format.name$ * } + if$ + } + if$ + } + if$ +} + +FUNCTION {format.book.crossref} +{ volume empty$ + { "empty volume in " cite$ * "'s crossref of " * crossref * warning$ + "In " + } + { "Volume" volume tie.or.space.connect + " of " * + } + if$ + "<a href=" * quote$ * "#" * crossref * quote$ * ">" * + editor empty$ + editor field.or.null author field.or.null = + or + { key empty$ + { series empty$ + { "need editor, key, or series for " cite$ * " to crossref " * + crossref * warning$ + "" * + } + { "<cite>" * series * "</cite>" * } + if$ + } + { key * } + if$ + } + { format.crossref.editor * } + if$ + "</a> \citelabel{" * crossref * "}" * +} + +FUNCTION {format.incoll.inproc.crossref} +{ + "In <a href=" quote$ * "#" * crossref * quote$ * ">" * + editor empty$ + editor field.or.null author field.or.null = + or + { key empty$ + { booktitle empty$ + { "need editor, key, or booktitle for " cite$ * " to crossref " * + crossref * warning$ + "" + } + { "<cite>" * booktitle * "</cite>" * } + if$ + } + { key * } + if$ + } + { format.crossref.editor * } + if$ + "</a> \citelabel{" * crossref * "}" * +} + +FUNCTION {article} +{ output.bibitem + format.authors "author" output.check + new.block + format.title "title" output.check + new.block + crossref missing$ + { journal emphasize "journal" output.check + format.vol.num.pages output + format.date "year" output.check + } + { format.article.crossref output.nonnull + format.pages output + } + if$ + new.block + note output + fin.entry +} + +FUNCTION {book} +{ output.bibitem + author empty$ + { format.editors "author and editor" output.check } + { format.authors output.nonnull + crossref missing$ + { "author and editor" editor either.or.check } + 'skip$ + if$ + } + if$ + new.block + format.btitle "title" output.check + crossref missing$ + { format.bvolume output + new.block + format.number.series output + new.sentence + publisher "publisher" output.check + address output + } + { new.block + format.book.crossref output.nonnull + } + if$ + format.edition output + format.date "year" output.check + new.block + note output + fin.entry +} + +FUNCTION {booklet} +{ output.bibitem + format.authors output + new.block + format.title "title" output.check + howpublished address new.block.checkb + howpublished output + address output + format.date output + new.block + note output + fin.entry +} + +FUNCTION {inbook} +{ output.bibitem + author empty$ + { format.editors "author and editor" output.check } + { format.authors output.nonnull + crossref missing$ + { "author and editor" editor either.or.check } + 'skip$ + if$ + } + if$ + new.block + format.btitle "title" output.check + crossref missing$ + { format.bvolume output + format.chapter.pages "chapter and pages" output.check + new.block + format.number.series output + new.sentence + publisher "publisher" output.check + address output + } + { format.chapter.pages "chapter and pages" output.check + new.block + format.book.crossref output.nonnull + } + if$ + format.edition output + format.date "year" output.check + new.block + note output + fin.entry +} + +FUNCTION {incollection} +{ output.bibitem + format.authors "author" output.check + new.block + format.title "title" output.check + new.block + crossref missing$ + { format.in.ed.booktitle "booktitle" output.check + format.bvolume output + format.number.series output + format.chapter.pages output + new.sentence + publisher "publisher" output.check + address output + format.edition output + format.date "year" output.check + } + { format.incoll.inproc.crossref output.nonnull + format.chapter.pages output + } + if$ + new.block + note output + fin.entry +} + +FUNCTION {inproceedings} +{ output.bibitem + format.authors "author" output.check + new.block + format.title "title" output.check + new.block + crossref missing$ + { format.in.ed.booktitle "booktitle" output.check + format.bvolume output + format.number.series output + format.pages output + address empty$ + { organization publisher new.sentence.checkb + organization output + publisher output + format.date "year" output.check + } + { address output.nonnull + format.date "year" output.check + new.sentence + organization output + publisher output + } + if$ + } + { format.incoll.inproc.crossref output.nonnull + format.pages output + } + if$ + new.block + note output + fin.entry +} + +FUNCTION {conference} { inproceedings } + +FUNCTION {manual} +{ output.bibitem + author empty$ + { organization empty$ + 'skip$ + { organization output.nonnull + address output + } + if$ + } + { format.authors output.nonnull } + if$ + new.block + format.btitle "title" output.check + author empty$ + { organization empty$ + { address new.block.checka + address output + } + 'skip$ + if$ + } + { organization address new.block.checkb + organization output + address output + } + if$ + format.edition output + format.date output + new.block + note output + fin.entry +} + +FUNCTION {mastersthesis} +{ output.bibitem + format.authors "author" output.check + new.block + format.title "title" output.check + new.block + "Master's thesis" format.thesis.type output.nonnull + school "school" output.check + address output + format.date "year" output.check + new.block + note output + fin.entry +} + +FUNCTION {misc} +{ output.bibitem + format.authors output + title howpublished new.block.checkb + format.title output + howpublished new.block.checka + howpublished output + format.date output + new.block + note output + fin.entry + empty.misc.check +} + +FUNCTION {phdthesis} +{ output.bibitem + format.authors "author" output.check + new.block + format.btitle "title" output.check + new.block + "PhD thesis" format.thesis.type output.nonnull + school "school" output.check + address output + format.date "year" output.check + new.block + note output + fin.entry +} + +FUNCTION {proceedings} +{ output.bibitem + editor empty$ + { organization output } + { format.editors output.nonnull } + if$ + new.block + format.btitle "title" output.check + format.bvolume output + format.number.series output + address empty$ + { editor empty$ + { publisher new.sentence.checka } + { organization publisher new.sentence.checkb + organization output + } + if$ + publisher output + format.date "year" output.check + } + { address output.nonnull + format.date "year" output.check + new.sentence + editor empty$ + 'skip$ + { organization output } + if$ + publisher output + } + if$ + new.block + note output + fin.entry +} + +FUNCTION {techreport} +{ output.bibitem + format.authors "author" output.check + new.block + format.title "title" output.check + new.block + format.tr.number output.nonnull + institution "institution" output.check + address output + format.date "year" output.check + new.block + note output + fin.entry +} + +FUNCTION {unpublished} +{ output.bibitem + format.authors "author" output.check + new.block + format.title "title" output.check + new.block + note "note" output.check + format.date output + fin.entry +} + +FUNCTION {default.type} { misc } + +MACRO {jan} {"January"} + +MACRO {feb} {"February"} + +MACRO {mar} {"March"} + +MACRO {apr} {"April"} + +MACRO {may} {"May"} + +MACRO {jun} {"June"} + +MACRO {jul} {"July"} + +MACRO {aug} {"August"} + +MACRO {sep} {"September"} + +MACRO {oct} {"October"} + +MACRO {nov} {"November"} + +MACRO {dec} {"December"} + +MACRO {acmcs} {"ACM Computing Surveys"} + +MACRO {acta} {"Acta Informatica"} + +MACRO {cacm} {"Communications of the ACM"} + +MACRO {ibmjrd} {"IBM Journal of Research and Development"} + +MACRO {ibmsj} {"IBM Systems Journal"} + +MACRO {ieeese} {"IEEE Transactions on Software Engineering"} + +MACRO {ieeetc} {"IEEE Transactions on Computers"} + +MACRO {ieeetcad} + {"IEEE Transactions on Computer-Aided Design of Integrated Circuits"} + +MACRO {ipl} {"Information Processing Letters"} + +MACRO {jacm} {"Journal of the ACM"} + +MACRO {jcss} {"Journal of Computer and System Sciences"} + +MACRO {scp} {"Science of Computer Programming"} + +MACRO {sicomp} {"SIAM Journal on Computing"} + +MACRO {tocs} {"ACM Transactions on Computer Systems"} + +MACRO {tods} {"ACM Transactions on Database Systems"} + +MACRO {tog} {"ACM Transactions on Graphics"} + +MACRO {toms} {"ACM Transactions on Mathematical Software"} + +MACRO {toois} {"ACM Transactions on Office Information Systems"} + +MACRO {toplas} {"ACM Transactions on Programming Languages and Systems"} + +MACRO {tcs} {"Theoretical Computer Science"} + +READ + +FUNCTION {sortify} +{ purify$ + "l" change.case$ +} + +INTEGERS { len } + +FUNCTION {chop.word} +{ 's := + 'len := + s #1 len substring$ = + { s len #1 + global.max$ substring$ } + 's + if$ +} + + +FUNCTION {format.lab.names} +{ 's := + s num.names$ 'numnames := + numnames #1 = + { s #1 "{vv }{ll}" format.name$ } + { numnames #2 = + { s #1 "{vv }{ll }and " format.name$ s #2 "{vv }{ll}" format.name$ * } + { s #1 "{vv }{ll }" format.name$ "et~al." * } + if$ + } + if$ +} + +FUNCTION {author.key.label} +{ author empty$ + { key empty$ + { cite$ #1 #3 substring$ } + { key } + if$ + } + { author format.lab.names } + if$ +} + +FUNCTION {author.editor.key.label} +{ author empty$ + { editor empty$ + { key empty$ + { cite$ #1 #3 substring$ } + { key } + if$ + } + { editor format.lab.names } + if$ + } + { author format.lab.names } + if$ +} + +FUNCTION {author.key.organization.label} +{ author empty$ + { key empty$ + { organization empty$ + { cite$ #1 #3 substring$ } + { "The " #4 organization chop.word #3 text.prefix$ } + if$ + } + { key } + if$ + } + { author format.lab.names } + if$ +} + +FUNCTION {editor.key.organization.label} +{ editor empty$ + { key empty$ + { organization empty$ + { cite$ #1 #3 substring$ } + { "The " #4 organization chop.word #3 text.prefix$ } + if$ + } + { key } + if$ + } + { editor format.lab.names } + if$ +} + +FUNCTION {month.to.int} +{ + "l" change.case$ #3 text.prefix$ + 's := + s "jan" = { #1 } { + s "feb" = { #2 } { + s "mar" = { #3 } { + s "apr" = { #4 } { + s "may" = { #5 } { + s "jun" = { #6 } { + s "jul" = { #7 } { + s "aug" = { #8 } { + s "sep" = { #9 } { + s "oct" = { #10 } { + s "nov" = { #11 } { + s "dec" = { #12 } { #13 } % 13 if nothing matches + if$}if$}if$}if$}if$}if$}if$}if$}if$}if$}if$}if$ +} + +INTEGERS { done c } +FUNCTION { get.day } +{ month field.or.null 's := + + % Strip out month name + #0 'done := + { s "" = not done not and } + { s #1 #1 substring$ " " = 'done := + s #2 global.max$ substring$ 's := + } + while$ + + % Build up first number in t + "0" 't := + #0 'done := + { s "" = not done not and } + { s #1 #1 substring$ chr.to.int$ 'c := + c #47 > c #58 < and + { t c int.to.chr$ * 't := } + { #1 'done := } + if$ + s #2 global.max$ substring$ 's := + } + while$ + + t str.to.int +} + +FUNCTION { sortify.fourdigit } +{ 's := + s empty$ + { "0000" } + { s + } + if$ +} + +FUNCTION { sortify.twodigit } +{ 's := + s empty$ + { "00" } + { s + str.to.int #10 + int.to.str$ + } + if$ +} + +FUNCTION {calc.label} +{ type$ "book" = + type$ "inbook" = + or + 'author.editor.key.label + { type$ "proceedings" = + 'editor.key.organization.label + { type$ "manual" = + 'author.key.organization.label + 'author.key.label + if$ + } + if$ + } + if$ + duplicate$ + + year empty$ + 'skip$ + { ", " * } + if$ + year field.or.null purify$ * % CHANGED - pfps - 15 Feb 1989 + 'label := + + year field.or.null purify$ + #-1 #4 substring$ + sortify.fourdigit + " " * + month field.or.null month.to.int int.to.str$ sortify.twodigit * + " " * + get.day int.to.str$ sortify.twodigit * + " " * + * sortify 'sort.label := +} + +FUNCTION {sort.format.names} +{ 's := + #1 'nameptr := + "" + s num.names$ 'numnames := + numnames 'namesleft := + { namesleft #0 > } + { nameptr #1 > + { " " * } + 'skip$ + if$ + s nameptr "{vv{ } }{ll{ }}{ ff{ }}{ jj{ }}" format.name$ 't := + nameptr numnames = t "others" = and + { "et al." * } + { t sortify * } + if$ + nameptr #1 + 'nameptr := + namesleft #1 - 'namesleft := + } + while$ +} + +FUNCTION {sort.format.title} +{ 't := + "A " #2 + "An " #3 + "The " #4 t chop.word + chop.word + chop.word + sortify + #1 global.max$ substring$ +} + +FUNCTION {author.sort} +{ author empty$ + { key empty$ + { "to sort, need author or key in " cite$ * warning$ + "" + } + { key sortify } + if$ + } + { author sort.format.names } + if$ +} + +FUNCTION {author.editor.sort} +{ author empty$ + { editor empty$ + { key empty$ + { "to sort, need author, editor, or key in " cite$ * warning$ + "" + } + { key sortify } + if$ + } + { editor sort.format.names } + if$ + } + { author sort.format.names } + if$ +} + +FUNCTION {author.organization.sort} +{ author empty$ + { organization empty$ + { key empty$ + { "to sort, need author, organization, or key in " cite$ * warning$ + "" + } + { key sortify } + if$ + } + { "The " #4 organization chop.word sortify } + if$ + } + { author sort.format.names } + if$ +} + +FUNCTION {editor.organization.sort} +{ editor empty$ + { organization empty$ + { key empty$ + { "to sort, need editor, organization, or key in " cite$ * warning$ + "" + } + { key sortify } + if$ + } + { "The " #4 organization chop.word sortify } + if$ + } + { editor sort.format.names } + if$ +} + +FUNCTION {presort} +{ calc.label + sort.label + " " + * + type$ "book" = + type$ "inbook" = + or + 'author.editor.sort + { type$ "proceedings" = + 'editor.organization.sort + { type$ "manual" = + 'author.organization.sort + 'author.sort + if$ + } + if$ + } + if$ + * + " " + * + year field.or.null sortify + * + " " + * + title field.or.null + sort.format.title + * + #1 entry.max$ substring$ + 'sort.key$ := +} + +ITERATE {presort} + +SORT + +STRINGS { longest.label last.sort.label next.extra } + +INTEGERS { longest.label.width last.extra.num } + +FUNCTION {initialize.longest.label} +{ "" 'longest.label := + #0 int.to.chr$ 'last.sort.label := + "" 'next.extra := + #0 'longest.label.width := + #0 'last.extra.num := +} + +FUNCTION {forward.pass} +{ last.sort.label sort.label = + { last.extra.num #1 + 'last.extra.num := + last.extra.num int.to.chr$ 'extra.label := + } + { "a" chr.to.int$ 'last.extra.num := + "" 'extra.label := + sort.label 'last.sort.label := + } + if$ +} + +FUNCTION {reverse.pass} +{ next.extra "b" = + { "a" 'extra.label := } + 'skip$ + if$ + label extra.label * 'label := + label width$ longest.label.width > + { label 'longest.label := + label width$ 'longest.label.width := + } + 'skip$ + if$ + extra.label 'next.extra := +} + +EXECUTE {initialize.longest.label} + +ITERATE {forward.pass} + +REVERSE {reverse.pass} + +FUNCTION {begin.bib} +{ + "# label-style: default" write$ newline$ +} + +EXECUTE {begin.bib} + +EXECUTE {init.state.consts} + +ITERATE {call.type$} + +FUNCTION {end.bib} +{ newline$ +} + +EXECUTE {end.bib} diff --git a/trunk/src/doxygen.cpp b/trunk/src/doxygen.cpp new file mode 100644 index 0000000..0759bfe --- /dev/null +++ b/trunk/src/doxygen.cpp @@ -0,0 +1,10844 @@ +/****************************************************************************** + * + * Copyright (C) 1997-2012 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. + * + */ + +#include "qtbc.h" +#include <qfileinfo.h> +#include <qfile.h> +#include <qdir.h> +#include <qdict.h> +#include <qregexp.h> +#include <qstrlist.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/stat.h> +#include <qtextcodec.h> +#include <unistd.h> +#include <errno.h> +#include <qptrdict.h> + +#include "version.h" +#include "doxygen.h" +#include "scanner.h" +#include "entry.h" +#include "index.h" +#include "logos.h" +#include "message.h" +#include "config.h" +#include "util.h" +#include "pre.h" +#include "tagreader.h" +#include "dot.h" +#include "msc.h" +#include "docparser.h" +#include "dirdef.h" +#include "outputlist.h" +#include "declinfo.h" +#include "htmlgen.h" +#include "latexgen.h" +#include "mangen.h" +#include "language.h" +#include "debug.h" +#include "htmlhelp.h" +#include "qhp.h" +#include "indexlog.h" +#include "ftvhelp.h" +#include "defargs.h" +#include "rtfgen.h" +#include "xmlgen.h" +#include "defgen.h" +#include "perlmodgen.h" +#include "reflist.h" +#include "pagedef.h" +#include "bufstr.h" +#include "commentcnv.h" +#include "cmdmapper.h" +#include "searchindex.h" +#include "parserintf.h" +#include "htags.h" +#include "pyscanner.h" +#include "fortranscanner.h" +#include "dbusxmlscanner.h" +#include "tclscanner.h" +#include "code.h" +#include "objcache.h" +#include "store.h" +#include "marshal.h" +#include "portable.h" +#include "vhdlscanner.h" +#include "vhdldocgen.h" +#include "eclipsehelp.h" +#include "cite.h" +#include "filestorage.h" +#include "markdown.h" +#include "arguments.h" + +#include "layout.h" + +#define RECURSE_ENTRYTREE(func,var) \ + do { if (var->children()) { \ + EntryNavListIterator eli(*var->children()); \ + for (;eli.current();++eli) func(eli.current()); \ + } } while(0) + + +#if !defined(_WIN32) || defined(__CYGWIN__) +#include <signal.h> +#define HAS_SIGNALS +#endif + +// globally accessible variables +ClassSDict *Doxygen::classSDict = 0; +ClassSDict *Doxygen::hiddenClasses = 0; +NamespaceSDict *Doxygen::namespaceSDict = 0; +MemberNameSDict *Doxygen::memberNameSDict = 0; +MemberNameSDict *Doxygen::functionNameSDict = 0; +FileNameList *Doxygen::inputNameList = 0; // all input files +FileNameDict *Doxygen::inputNameDict = 0; +GroupSDict *Doxygen::groupSDict = 0; +FormulaList Doxygen::formulaList; // all formulas +FormulaDict Doxygen::formulaDict(1009); // all formulas +FormulaDict Doxygen::formulaNameDict(1009); // the label name of all formulas +PageSDict *Doxygen::pageSDict = 0; +PageSDict *Doxygen::exampleSDict = 0; +SectionDict Doxygen::sectionDict(257); // all page sections +CiteDict *Doxygen::citeDict=0; // database of bibliographic references +StringDict Doxygen::aliasDict(257); // aliases +FileNameDict *Doxygen::includeNameDict = 0; // include names +FileNameDict *Doxygen::exampleNameDict = 0; // examples +FileNameDict *Doxygen::imageNameDict = 0; // images +FileNameDict *Doxygen::dotFileNameDict = 0; // dot files +FileNameDict *Doxygen::mscFileNameDict = 0; // dot files +StringDict Doxygen::namespaceAliasDict(257); // all namespace aliases +StringDict Doxygen::tagDestinationDict(257); // all tag locations +QDict<void> Doxygen::expandAsDefinedDict(257); // all macros that should be expanded +QIntDict<MemberGroupInfo> Doxygen::memGrpInfoDict(1009); // dictionary of the member groups heading +PageDef *Doxygen::mainPage = 0; +bool Doxygen::insideMainPage = FALSE; // are we generating docs for the main page? +FTextStream Doxygen::tagFile; +NamespaceDef *Doxygen::globalScope = 0; +QDict<RefList> *Doxygen::xrefLists = new QDict<RefList>; // dictionary of cross-referenced item lists +bool Doxygen::parseSourcesNeeded = FALSE; +QTime Doxygen::runningTime; +SearchIndex * Doxygen::searchIndex=0; +QDict<DefinitionIntf> *Doxygen::symbolMap; +bool Doxygen::outputToWizard=FALSE; +QDict<int> * Doxygen::htmlDirMap = 0; +QCache<LookupInfo> *Doxygen::lookupCache; +DirSDict *Doxygen::directories; +SDict<DirRelation> Doxygen::dirRelations(257); +ParserManager *Doxygen::parserManager = 0; +QCString Doxygen::htmlFileExtension; +bool Doxygen::suppressDocWarnings = FALSE; +ObjCache *Doxygen::symbolCache = 0; +Store *Doxygen::symbolStorage; +QCString Doxygen::objDBFileName; +QCString Doxygen::entryDBFileName; +bool Doxygen::gatherDefines = TRUE; +IndexList Doxygen::indexList; +int Doxygen::subpageNestingLevel = 0; +bool Doxygen::userComments = FALSE; +QCString Doxygen::spaces; +bool Doxygen::generatingXmlOutput = FALSE; +bool Doxygen::markdownSupport = TRUE; + +// locally accessible globals +static QDict<EntryNav> g_classEntries(1009); +static StringList g_inputFiles; +static QDict<void> g_compoundKeywordDict(7); // keywords recognised as compounds +static OutputList *g_outputList = 0; // list of output generating objects +static QDict<FileDef> g_usingDeclarations(1009); // used classes +static FileStorage *g_storage = 0; +static bool g_successfulRun = FALSE; +static bool g_dumpSymbolMap = FALSE; +static bool g_dumpConfigAsXML = FALSE; + +void clearAll() +{ + g_inputFiles.clear(); + //g_excludeNameDict.clear(); + //delete g_outputList; g_outputList=0; + + Doxygen::classSDict->clear(); + Doxygen::namespaceSDict->clear(); + Doxygen::pageSDict->clear(); + Doxygen::exampleSDict->clear(); + Doxygen::inputNameList->clear(); + Doxygen::formulaList.clear(); + Doxygen::sectionDict.clear(); + Doxygen::inputNameDict->clear(); + Doxygen::includeNameDict->clear(); + Doxygen::exampleNameDict->clear(); + Doxygen::imageNameDict->clear(); + Doxygen::dotFileNameDict->clear(); + Doxygen::mscFileNameDict->clear(); + Doxygen::formulaDict.clear(); + Doxygen::formulaNameDict.clear(); + Doxygen::tagDestinationDict.clear(); + delete Doxygen::citeDict; + delete Doxygen::mainPage; Doxygen::mainPage=0; +} + +void statistics() +{ + fprintf(stderr,"--- inputNameDict stats ----\n"); + Doxygen::inputNameDict->statistics(); + fprintf(stderr,"--- includeNameDict stats ----\n"); + Doxygen::includeNameDict->statistics(); + fprintf(stderr,"--- exampleNameDict stats ----\n"); + Doxygen::exampleNameDict->statistics(); + fprintf(stderr,"--- imageNameDict stats ----\n"); + Doxygen::imageNameDict->statistics(); + fprintf(stderr,"--- dotFileNameDict stats ----\n"); + Doxygen::dotFileNameDict->statistics(); + fprintf(stderr,"--- mscFileNameDict stats ----\n"); + Doxygen::mscFileNameDict->statistics(); + //fprintf(stderr,"--- g_excludeNameDict stats ----\n"); + //g_excludeNameDict.statistics(); + fprintf(stderr,"--- aliasDict stats ----\n"); + Doxygen::aliasDict.statistics(); + fprintf(stderr,"--- typedefDict stats ----\n"); + fprintf(stderr,"--- namespaceAliasDict stats ----\n"); + Doxygen::namespaceAliasDict.statistics(); + fprintf(stderr,"--- formulaDict stats ----\n"); + Doxygen::formulaDict.statistics(); + fprintf(stderr,"--- formulaNameDict stats ----\n"); + Doxygen::formulaNameDict.statistics(); + fprintf(stderr,"--- tagDestinationDict stats ----\n"); + Doxygen::tagDestinationDict.statistics(); + fprintf(stderr,"--- g_compoundKeywordDict stats ----\n"); + g_compoundKeywordDict.statistics(); + fprintf(stderr,"--- expandAsDefinedDict stats ----\n"); + Doxygen::expandAsDefinedDict.statistics(); + fprintf(stderr,"--- memGrpInfoDict stats ----\n"); + Doxygen::memGrpInfoDict.statistics(); +} + + + +static void addMemberDocs(EntryNav *rootNav,MemberDef *md, const char *funcDecl, + ArgumentList *al,bool over_load,NamespaceSDict *nl=0); +static void findMember(EntryNav *rootNav, + QCString funcDecl, + bool overloaded, + bool isFunc + ); + + +struct STLInfo +{ + const char *className; + const char *baseClass1; + const char *baseClass2; + const char *templType1; + const char *templName1; + const char *templType2; + const char *templName2; + bool virtualInheritance; + bool iterators; +}; + +static STLInfo g_stlinfo[] = +{ + // className baseClass1 baseClass2 templType1 templName1 templType2 templName2 virtInheritance // iterators + { "allocator", 0, 0, "T", "elements", 0, 0, FALSE, FALSE }, + { "auto_ptr", 0, 0, "T", "ptr", 0, 0, FALSE, FALSE }, // deprecated + { "smart_ptr", 0, 0, "T", "ptr", 0, 0, FALSE, FALSE }, // C++11 + { "unique_ptr", 0, 0, "T", "ptr", 0, 0, FALSE, FALSE }, // C++11 + { "weak_ptr", 0, 0, "T", "ptr", 0, 0, FALSE, FALSE }, // C++11 + { "ios_base", 0, 0, 0, 0, 0, 0, FALSE, FALSE }, // C++11 + { "basic_ios", "ios_base", 0, "Char", 0, 0, 0, FALSE, FALSE }, + { "basic_istream", "basic_ios<Char>", 0, "Char", 0, 0, 0, TRUE, FALSE }, + { "basic_ostream", "basic_ios<Char>", 0, "Char", 0, 0, 0, TRUE, FALSE }, + { "basic_iostream", "basic_istream<Char>", "basic_ostream<Char>", "Char", 0, 0, 0, FALSE, FALSE }, + { "basic_ifstream", "basic_istream<Char>", 0, "Char", 0, 0, 0, FALSE, FALSE }, + { "basic_ofstream", "basic_ostream<Char>", 0, "Char", 0, 0, 0, FALSE, FALSE }, + { "basic_fstream", "basic_iostream<Char>", 0, "Char", 0, 0, 0, FALSE, FALSE }, + { "basic_istringstream", "basic_istream<Char>", 0, "Char", 0, 0, 0, FALSE, FALSE }, + { "basic_ostringstream", "basic_ostream<Char>", 0, "Char", 0, 0, 0, FALSE, FALSE }, + { "basic_stringstream", "basic_iostream<Char>", 0, "Char", 0, 0, 0, FALSE, FALSE }, + { "ios", "basic_ios<char>", 0, 0, 0, 0, 0, FALSE, FALSE }, + { "wios", "basic_ios<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE }, + { "istream", "basic_istream<char>", 0, 0, 0, 0, 0, FALSE, FALSE }, + { "wistream", "basic_istream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE }, + { "ostream", "basic_ostream<char>", 0, 0, 0, 0, 0, FALSE, FALSE }, + { "wostream", "basic_ostream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE }, + { "ifstream", "basic_ifstream<char>", 0, 0, 0, 0, 0, FALSE, FALSE }, + { "wifstream", "basic_ifstream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE }, + { "ofstream", "basic_ofstream<char>", 0, 0, 0, 0, 0, FALSE, FALSE }, + { "wofstream", "basic_ofstream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE }, + { "fstream", "basic_fstream<char>", 0, 0, 0, 0, 0, FALSE, FALSE }, + { "wfstream", "basic_fstream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE }, + { "istringstream", "basic_istringstream<char>", 0, 0, 0, 0, 0, FALSE, FALSE }, + { "wistringstream", "basic_istringstream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE }, + { "ostringstream", "basic_ostringstream<char>", 0, 0, 0, 0, 0, FALSE, FALSE }, + { "wostringstream", "basic_ostringstream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE }, + { "stringstream", "basic_stringstream<char>", 0, 0, 0, 0, 0, FALSE, FALSE }, + { "wstringstream", "basic_stringstream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE }, + { "basic_string", 0, 0, "Char", 0, 0, 0, FALSE, TRUE }, + { "string", "basic_string<char>", 0, 0, 0, 0, 0, FALSE, TRUE }, + { "wstring", "basic_string<wchar_t>", 0, 0, 0, 0, 0, FALSE, TRUE }, + { "complex", 0, 0, 0, 0, 0, 0, FALSE, FALSE }, + { "bitset", 0, 0, "Bits", 0, 0, 0, FALSE, FALSE }, + { "deque", 0, 0, "T", "elements", 0, 0, FALSE, TRUE }, + { "list", 0, 0, "T", "elements", 0, 0, FALSE, TRUE }, + { "map", 0, 0, "K", "keys", "T", "elements", FALSE, TRUE }, + { "multimap", 0, 0, "K", "keys", "T", "elements", FALSE, TRUE }, + { "set", 0, 0, "K", "keys", 0, 0, FALSE, TRUE }, + { "multiset", 0, 0, "K", "keys", 0, 0, FALSE, TRUE }, + { "vector", 0, 0, "T", "elements", 0, 0, FALSE, TRUE }, + { "queue", 0, 0, "T", "elements", 0, 0, FALSE, FALSE }, + { "priority_queue", 0, 0, "T", "elements", 0, 0, FALSE, FALSE }, + { "stack", 0, 0, "T", "elements", 0, 0, FALSE, FALSE }, + { "valarray", 0, 0, "T", "elements", 0, 0, FALSE, FALSE }, + { "exception", 0, 0, 0, 0, 0, 0, FALSE, FALSE }, + { "bad_alloc", "exception", 0, 0, 0, 0, 0, FALSE, FALSE }, + { "bad_cast", "exception", 0, 0, 0, 0, 0, FALSE, FALSE }, + { "bad_typeid", "exception", 0, 0, 0, 0, 0, FALSE, FALSE }, + { "logic_error", "exception", 0, 0, 0, 0, 0, FALSE, FALSE }, + { "ios_base::failure", "exception", 0, 0, 0, 0, 0, FALSE, FALSE }, + { "runtime_error", "exception", 0, 0, 0, 0, 0, FALSE, FALSE }, + { "bad_exception", "exception", 0, 0, 0, 0, 0, FALSE, FALSE }, + { "domain_error", "logic_error", 0, 0, 0, 0, 0, FALSE, FALSE }, + { "invalid_argument", "logic_error", 0, 0, 0, 0, 0, FALSE, FALSE }, + { "length_error", "logic_error", 0, 0, 0, 0, 0, FALSE, FALSE }, + { "out_of_range", "logic_error", 0, 0, 0, 0, 0, FALSE, FALSE }, + { "range_error", "runtime_error", 0, 0, 0, 0, 0, FALSE, FALSE }, + { "overflow_error", "runtime_error", 0, 0, 0, 0, 0, FALSE, FALSE }, + { "underflow_error", "runtime_error", 0, 0, 0, 0, 0, FALSE, FALSE }, + { 0, 0, 0, 0, 0, 0, 0, FALSE, FALSE } +}; + +static void addSTLMember(EntryNav *rootNav,const char *type,const char *name) +{ + Entry *memEntry = new Entry; + memEntry->name = name; + memEntry->type = type; + memEntry->protection = Public; + memEntry->section = Entry::VARIABLE_SEC; + memEntry->brief = "STL member"; + memEntry->hidden = FALSE; + memEntry->artificial = TRUE; + //memEntry->parent = root; + //root->addSubEntry(memEntry); + EntryNav *memEntryNav = new EntryNav(rootNav,memEntry); + memEntryNav->setEntry(memEntry); + rootNav->addChild(memEntryNav); +} + +static void addSTLIterator(EntryNav *classEntryNav,const char *name) +{ + Entry *iteratorClassEntry = new Entry; + iteratorClassEntry->fileName = "[STL]"; + iteratorClassEntry->startLine = 1; + iteratorClassEntry->name = name; + iteratorClassEntry->section = Entry::CLASS_SEC; + iteratorClassEntry->brief = "STL iterator class"; + iteratorClassEntry->hidden = FALSE; + iteratorClassEntry->artificial= TRUE; + EntryNav *iteratorClassEntryNav = new EntryNav(classEntryNav,iteratorClassEntry); + iteratorClassEntryNav->setEntry(iteratorClassEntry); + classEntryNav->addChild(iteratorClassEntryNav); +} + + +static void addSTLClasses(EntryNav *rootNav) +{ + Entry *namespaceEntry = new Entry; + namespaceEntry->fileName = "[STL]"; + namespaceEntry->startLine = 1; + //namespaceEntry->parent = rootNav->entry(); + namespaceEntry->name = "std"; + namespaceEntry->section = Entry::NAMESPACE_SEC; + namespaceEntry->brief = "STL namespace"; + namespaceEntry->hidden = FALSE; + namespaceEntry->artificial= TRUE; + //root->addSubEntry(namespaceEntry); + EntryNav *namespaceEntryNav = new EntryNav(rootNav,namespaceEntry); + namespaceEntryNav->setEntry(namespaceEntry); + rootNav->addChild(namespaceEntryNav); + + STLInfo *info = g_stlinfo; + while (info->className) + { + //printf("Adding STL class %s\n",info->className); + QCString fullName = info->className; + fullName.prepend("std::"); + + // add fake Entry for the class + Entry *classEntry = new Entry; + classEntry->fileName = "[STL]"; + classEntry->startLine = 1; + classEntry->name = fullName; + //classEntry->parent = namespaceEntry; + classEntry->section = Entry::CLASS_SEC; + classEntry->brief = "STL class"; + classEntry->hidden = FALSE; + classEntry->artificial= TRUE; + //namespaceEntry->addSubEntry(classEntry); + EntryNav *classEntryNav = new EntryNav(namespaceEntryNav,classEntry); + classEntryNav->setEntry(classEntry); + namespaceEntryNav->addChild(classEntryNav); + + // add template arguments to class + if (info->templType1) + { + ArgumentList *al = new ArgumentList; + Argument *a=new Argument; + a->type="typename"; + a->name=info->templType1; + al->append(a); + if (info->templType2) // another template argument + { + a=new Argument; + a->type="typename"; + a->name=info->templType2; + al->append(a); + } + classEntry->tArgLists = new QList<ArgumentList>; + classEntry->tArgLists->setAutoDelete(TRUE); + classEntry->tArgLists->append(al); + } + // add member variables + if (info->templName1) + { + addSTLMember(classEntryNav,info->templType1,info->templName1); + } + if (info->templName2) + { + addSTLMember(classEntryNav,info->templType2,info->templName2); + } + if (fullName=="std::auto_ptr" || fullName=="std::smart_ptr" || + fullName=="std::unique_ptr" || fullName=="std::weak_ptr") + { + Entry *memEntry = new Entry; + memEntry->name = "operator->"; + memEntry->args = "()"; + memEntry->type = "T*"; + memEntry->protection = Public; + memEntry->section = Entry::FUNCTION_SEC; + memEntry->brief = "STL member"; + memEntry->hidden = FALSE; + memEntry->artificial = FALSE; + EntryNav *memEntryNav = new EntryNav(classEntryNav,memEntry); + memEntryNav->setEntry(memEntry); + classEntryNav->addChild(memEntryNav); + } + if (info->baseClass1) + { + classEntry->extends->append(new BaseInfo(info->baseClass1,Public,info->virtualInheritance?Virtual:Normal)); + } + if (info->baseClass2) + { + classEntry->extends->append(new BaseInfo(info->baseClass2,Public,info->virtualInheritance?Virtual:Normal)); + } + if (info->iterators) + { + // add iterator class + addSTLIterator(classEntryNav,fullName+"::iterator"); + addSTLIterator(classEntryNav,fullName+"::const_iterator"); + addSTLIterator(classEntryNav,fullName+"::reverse_iterator"); + addSTLIterator(classEntryNav,fullName+"::const_reverse_iterator"); + } + info++; + } +} + +//---------------------------------------------------------------------------- + +static Definition *findScopeFromQualifiedName(Definition *startScope,const QCString &n, + FileDef *fileScope=0); + +static void addPageToContext(PageDef *pd,EntryNav *rootNav) +{ + if (rootNav->parent()) // add the page to it's scope + { + QCString scope = rootNav->parent()->name(); + if (rootNav->parent()->section()==Entry::PACKAGEDOC_SEC) + { + scope=substitute(scope,".","::"); + } + scope = stripAnonymousNamespaceScope(scope); + scope+="::"+pd->name(); + Definition *d = findScopeFromQualifiedName(Doxygen::globalScope,scope); + if (d) + { + pd->setPageScope(d); + } + } +} + +static void addRelatedPage(EntryNav *rootNav) +{ + Entry *root = rootNav->entry(); + GroupDef *gd=0; + QListIterator<Grouping> gli(*root->groups); + Grouping *g; + for (;(g=gli.current());++gli) + { + if (!g->groupname.isEmpty() && (gd=Doxygen::groupSDict->find(g->groupname))) break; + } + //printf("---> addRelatedPage() %s gd=%p\n",root->name.data(),gd); + QCString doc; + if (root->brief.isEmpty()) + { + doc=root->doc+root->inbodyDocs; + } + else + { + doc=root->brief+"\n\n"+root->doc+root->inbodyDocs; + } + PageDef *pd = addRelatedPage(root->name,root->args,doc,root->anchors, + root->docFile,root->docLine, + root->sli, + gd,rootNav->tagInfo(), + root->lang + ); + if (pd) + { + pd->addSectionsToDefinition(root->anchors); + pd->setShowToc(root->stat); + addPageToContext(pd,rootNav); + } +} + +static void buildGroupListFiltered(EntryNav *rootNav,bool additional, bool includeExternal) +{ + if (rootNav->section()==Entry::GROUPDOC_SEC && !rootNav->name().isEmpty() && + ((!includeExternal && rootNav->tagInfo()==0) || + ( includeExternal && rootNav->tagInfo()!=0)) + ) + { + rootNav->loadEntry(g_storage); + Entry *root = rootNav->entry(); + + if ((root->groupDocType==Entry::GROUPDOC_NORMAL && !additional) || + (root->groupDocType!=Entry::GROUPDOC_NORMAL && additional)) + { + GroupDef *gd = Doxygen::groupSDict->find(root->name); + //printf("Processing group '%s': add=%d ext=%d gd=%p\n", + // root->type.data(),additional,includeExternal,gd); + + if (gd) + { + if ( !gd->hasGroupTitle() ) + { + gd->setGroupTitle( root->type ); + } + else if ( root->type.length() > 0 && root->name != root->type && gd->groupTitle() != root->type ) + { + warn( root->fileName,root->startLine, + "group %s: ignoring title \"%s\" that does not match old title \"%s\"\n", + qPrint(root->name), qPrint(root->type), qPrint(gd->groupTitle()) ); + } + gd->setBriefDescription(root->brief,root->briefFile,root->briefLine); + gd->setDocumentation( root->doc, root->docFile, root->docLine ); + gd->setInbodyDocumentation( root->inbodyDocs, root->inbodyFile, root->inbodyLine ); + gd->addSectionsToDefinition(root->anchors); + gd->setRefItems(root->sli); + gd->setLanguage(root->lang); + } + else + { + if (rootNav->tagInfo()) + { + gd = new GroupDef(root->fileName,root->startLine,root->name,root->type,rootNav->tagInfo()->fileName); + gd->setReference(rootNav->tagInfo()->tagName); + } + else + { + gd = new GroupDef(root->fileName,root->startLine,root->name,root->type); + } + gd->setBriefDescription(root->brief,root->briefFile,root->briefLine); + gd->setDocumentation(root->doc,root->docFile,root->docLine); + gd->setInbodyDocumentation( root->inbodyDocs, root->inbodyFile, root->inbodyLine ); + gd->addSectionsToDefinition(root->anchors); + Doxygen::groupSDict->append(root->name,gd); + gd->setRefItems(root->sli); + gd->setLanguage(root->lang); + } + } + + rootNav->releaseEntry(); + } + if (rootNav->children()) + { + EntryNavListIterator eli(*rootNav->children()); + EntryNav *e; + for (;(e=eli.current());++eli) + { + buildGroupListFiltered(e,additional,includeExternal); + } + } +} + +static void buildGroupList(EntryNav *rootNav) +{ + // --- first process only local groups + // first process the @defgroups blocks + buildGroupListFiltered(rootNav,FALSE,FALSE); + // then process the @addtogroup, @weakgroup blocks + buildGroupListFiltered(rootNav,TRUE,FALSE); + + // --- then also process external groups + // first process the @defgroups blocks + buildGroupListFiltered(rootNav,FALSE,TRUE); + // then process the @addtogroup, @weakgroup blocks + buildGroupListFiltered(rootNav,TRUE,TRUE); +} + +static void findGroupScope(EntryNav *rootNav) +{ + if (rootNav->section()==Entry::GROUPDOC_SEC && !rootNav->name().isEmpty() && + rootNav->parent() && !rootNav->parent()->name().isEmpty()) + { + GroupDef *gd; + if ((gd=Doxygen::groupSDict->find(rootNav->name()))) + { + QCString scope = rootNav->parent()->name(); + if (rootNav->parent()->section()==Entry::PACKAGEDOC_SEC) + { + scope=substitute(scope,".","::"); + } + scope = stripAnonymousNamespaceScope(scope); + scope+="::"+gd->name(); + Definition *d = findScopeFromQualifiedName(Doxygen::globalScope,scope); + if (d) + { + gd->setGroupScope(d); + } + } + } + RECURSE_ENTRYTREE(findGroupScope,rootNav); +} + +static void organizeSubGroupsFiltered(EntryNav *rootNav,bool additional) +{ + if (rootNav->section()==Entry::GROUPDOC_SEC && !rootNav->name().isEmpty()) + { + rootNav->loadEntry(g_storage); + Entry *root = rootNav->entry(); + + if ((root->groupDocType==Entry::GROUPDOC_NORMAL && !additional) || + (root->groupDocType!=Entry::GROUPDOC_NORMAL && additional)) + { + GroupDef *gd; + if ((gd=Doxygen::groupSDict->find(root->name))) + { + //printf("adding %s to group %s\n",root->name.data(),gd->name().data()); + addGroupToGroups(root,gd); + } + } + + rootNav->releaseEntry(); + } + if (rootNav->children()) + { + EntryNavListIterator eli(*rootNav->children()); + EntryNav *e; + for (;(e=eli.current());++eli) + { + organizeSubGroupsFiltered(e,additional); + } + } +} + +static void organizeSubGroups(EntryNav *rootNav) +{ + //printf("Defining groups\n"); + // first process the @defgroups blocks + organizeSubGroupsFiltered(rootNav,FALSE); + //printf("Additional groups\n"); + // then process the @addtogroup, @weakgroup blocks + organizeSubGroupsFiltered(rootNav,TRUE); +} + +//---------------------------------------------------------------------- + +static void buildFileList(EntryNav *rootNav) +{ + if (((rootNav->section()==Entry::FILEDOC_SEC) || + ((rootNav->section() & Entry::FILE_MASK) && Config_getBool("EXTRACT_ALL"))) && + !rootNav->name().isEmpty() && !rootNav->tagInfo() // skip any file coming from tag files + ) + { + rootNav->loadEntry(g_storage); + Entry *root = rootNav->entry(); + + bool ambig; + FileDef *fd=findFileDef(Doxygen::inputNameDict,root->name,ambig); + //printf("**************** root->name=%s fd=%p\n",root->name.data(),fd); + if (fd && !ambig) + { +#if 0 + if ((!root->doc.isEmpty() && !fd->documentation().isEmpty()) || + (!root->brief.isEmpty() && !fd->briefDescription().isEmpty())) + { + warn( + root->fileName,root->startLine, + "warning: file %s already documented. " + "Skipping documentation.", + root->name.data() + ); + } + else +#endif + { + //printf("Adding documentation!\n"); + // using FALSE in setDocumentation is small hack to make sure a file + // is documented even if a \file command is used without further + // documentation + fd->setDocumentation(root->doc,root->docFile,root->docLine,FALSE); + fd->setBriefDescription(root->brief,root->briefFile,root->briefLine); + fd->addSectionsToDefinition(root->anchors); + fd->setRefItems(root->sli); + QListIterator<Grouping> gli(*root->groups); + Grouping *g; + for (;(g=gli.current());++gli) + { + GroupDef *gd=0; + if (!g->groupname.isEmpty() && (gd=Doxygen::groupSDict->find(g->groupname))) + { + gd->addFile(fd); + fd->makePartOfGroup(gd); + //printf("File %s: in group %s\n",fd->name().data(),s->data()); + } + } + } + } + else + { + const char *fn = root->fileName.data(); + QCString text(4096); + text.sprintf("warning: the name `%s' supplied as " + "the second argument in the \\file statement ", + qPrint(root->name)); + if (ambig) // name is ambiguous + { + text+="matches the following input files:\n"; + text+=showFileDefMatches(Doxygen::inputNameDict,root->name); + text+="Please use a more specific name by " + "including a (larger) part of the path!"; + } + else // name is not an input file + { + text+="is not an input file"; + } + warn(fn,root->startLine,text); + } + + rootNav->releaseEntry(); + } + RECURSE_ENTRYTREE(buildFileList,rootNav); +} + +static void addIncludeFile(ClassDef *cd,FileDef *ifd,Entry *root) +{ + if ( + (!root->doc.stripWhiteSpace().isEmpty() || + !root->brief.stripWhiteSpace().isEmpty() || + Config_getBool("EXTRACT_ALL") + ) && root->protection!=Private + ) + { + //printf(">>>>>> includeFile=%s\n",root->includeFile.data()); + + bool local=Config_getBool("FORCE_LOCAL_INCLUDES"); + QCString includeFile = root->includeFile; + if (!includeFile.isEmpty() && includeFile.at(0)=='"') + { + local = TRUE; + includeFile=includeFile.mid(1,includeFile.length()-2); + } + else if (!includeFile.isEmpty() && includeFile.at(0)=='<') + { + local = FALSE; + includeFile=includeFile.mid(1,includeFile.length()-2); + } + + bool ambig; + FileDef *fd=0; + // see if we need to include a verbatim copy of the header file + //printf("root->includeFile=%s\n",root->includeFile.data()); + if (!includeFile.isEmpty() && + (fd=findFileDef(Doxygen::inputNameDict,includeFile,ambig))==0 + ) + { // explicit request + QCString text; + text.sprintf("warning: the name `%s' supplied as " + "the argument of the \\class, \\struct, \\union, or \\include command ", + qPrint(includeFile) + ); + if (ambig) // name is ambiguous + { + text+="matches the following input files:\n"; + text+=showFileDefMatches(Doxygen::inputNameDict,root->includeFile); + text+="Please use a more specific name by " + "including a (larger) part of the path!"; + } + else // name is not an input file + { + text+="is not an input file"; + } + warn(root->fileName,root->startLine,text); + } + else if (includeFile.isEmpty() && ifd && + // see if the file extension makes sense + guessSection(ifd->name())==Entry::HEADER_SEC) + { // implicit assumption + fd=ifd; + } + + // if a file is found, we mark it as a source file. + if (fd) + { + QCString iName = !root->includeName.isEmpty() ? + root->includeName : includeFile; + if (!iName.isEmpty()) // user specified include file + { + if (iName.at(0)=='<') local=FALSE; // explicit override + if (iName.at(0)=='"' || iName.at(0)=='<') + { + iName=iName.mid(1,iName.length()-2); // strip quotes or brackets + } + if (iName.isEmpty()) + { + iName=fd->name(); + } + } + else if (!Config_getList("STRIP_FROM_INC_PATH").isEmpty()) + { + iName=stripFromIncludePath(fd->absFilePath()); + } + else // use name of the file containing the class definition + { + iName=fd->name(); + } + if (fd->generateSourceFile()) // generate code for header + { + cd->setIncludeFile(fd,iName,local,!root->includeName.isEmpty()); + } + else // put #include in the class documentation without link + { + cd->setIncludeFile(0,iName,local,TRUE); + } + } + } +} + +#if 0 +static bool addNamespace(Entry *root,ClassDef *cd) +{ + // see if this class is defined inside a namespace + if (root->section & Entry::COMPOUND_MASK) + { + Entry *e = root->parent; + while (e) + { + if (e->section==Entry::NAMESPACE_SEC) + { + NamespaceDef *nd=0; + QCString nsName = stripAnonymousNamespaceScope(e->name); + //printf("addNameSpace() trying: %s\n",nsName.data()); + if (!nsName.isEmpty() && nsName.at(0)!='@' && + (nd=getResolvedNamespace(nsName)) + ) + { + cd->setNamespace(nd); + cd->setOuterScope(nd); + nd->insertClass(cd); + return TRUE; + } + } + e=e->parent; + } + } + return FALSE; +} +#endif + +#if 0 +static Definition *findScope(Entry *root,int level=0) +{ + if (root==0) return 0; + //printf("start findScope name=%s\n",root->name.data()); + Definition *result=0; + if (root->section&Entry::SCOPE_MASK) + { + result = findScope(root->parent,level+1); // traverse to the root of the tree + if (result) + { + //printf("Found %s inside %s at level %d\n",root->name.data(),result->name().data(),level); + // TODO: look at template arguments + result = result->findInnerCompound(root->name); + } + else // reached the global scope + { + // TODO: look at template arguments + result = Doxygen::globalScope->findInnerCompound(root->name); + //printf("Found in globalScope %s at level %d\n",result->name().data(),level); + } + } + //printf("end findScope(%s,%d)=%s\n",root->name.data(), + // level,result==0 ? "<none>" : result->name().data()); + return result; +} +#endif + +/*! returns the Definition object belonging to the first \a level levels of + * full qualified name \a name. Creates an artificial scope if the scope is + * not found and set the parent/child scope relation if the scope is found. + */ +static Definition *buildScopeFromQualifiedName(const QCString name,int level,SrcLangExt lang) +{ + int i=0; + int p=0,l; + Definition *prevScope=Doxygen::globalScope; + QCString fullScope; + while (i<level) + { + int idx=getScopeFragment(name,p,&l); + QCString nsName = name.mid(idx,l); + if (nsName.isEmpty()) return prevScope; + if (!fullScope.isEmpty()) fullScope+="::"; + fullScope+=nsName; + NamespaceDef *nd=Doxygen::namespaceSDict->find(fullScope); + Definition *innerScope = nd; + ClassDef *cd=0; + if (nd==0) cd = getClass(fullScope); + if (nd==0 && cd) // scope is a class + { + innerScope = cd; + } + else if (nd==0 && cd==0) // scope is not known! + { + // introduce bogus namespace + //printf("++ adding dummy namespace %s to %s\n",nsName.data(),prevScope->name().data()); + nd=new NamespaceDef( + "[generated]",1,fullScope); + nd->setLanguage(lang); + + // add namespace to the list + Doxygen::namespaceSDict->inSort(fullScope,nd); + innerScope = nd; + } + else // scope is a namespace + { + } + // make the parent/child scope relation + prevScope->addInnerCompound(innerScope); + innerScope->setOuterScope(prevScope); + // proceed to the next scope fragment + p=idx+l+2; + prevScope=innerScope; + i++; + } + return prevScope; +} + +static Definition *findScopeFromQualifiedName(Definition *startScope,const QCString &n, + FileDef *fileScope) +{ + //printf("<findScopeFromQualifiedName(%s,%s)\n",startScope ? startScope->name().data() : 0, n.data()); + Definition *resultScope=startScope; + if (resultScope==0) resultScope=Doxygen::globalScope; + QCString scope=stripTemplateSpecifiersFromScope(n,FALSE); + int l1=0,i1; + i1=getScopeFragment(scope,0,&l1); + if (i1==-1) + { + //printf(">no fragments!\n"); + return resultScope; + } + int p=i1+l1,l2=0,i2; + while ((i2=getScopeFragment(scope,p,&l2))!=-1) + { + QCString nestedNameSpecifier = scope.mid(i1,l1); + Definition *orgScope = resultScope; + //printf(" nestedNameSpecifier=%s\n",nestedNameSpecifier.data()); + resultScope = resultScope->findInnerCompound(nestedNameSpecifier); + //printf(" resultScope=%p\n",resultScope); + if (resultScope==0) + { + NamespaceSDict *usedNamespaces; + if (orgScope==Doxygen::globalScope && fileScope && + (usedNamespaces = fileScope->getUsedNamespaces())) + // also search for used namespaces + { + NamespaceSDict::Iterator ni(*usedNamespaces); + NamespaceDef *nd; + for (ni.toFirst();((nd=ni.current()) && resultScope==0);++ni) + { + // restart search within the used namespace + resultScope = findScopeFromQualifiedName(nd,n,fileScope); + } + if (resultScope) + { + // for a nested class A::I in used namespace N, we get + // N::A::I while looking for A, so we should compare + // resultScope->name() against scope.left(i2+l2) + //printf(" -> result=%s scope=%s\n",resultScope->name().data(),scope.data()); + if (rightScopeMatch(resultScope->name(),scope.left(i2+l2))) + { + break; + } + goto nextFragment; + } + } + + // also search for used classes. Complication: we haven't been able + // to put them in the right scope yet, because we are still resolving + // the scope relations! + // Therefore loop through all used classes and see if there is a right + // scope match between the used class and nestedNameSpecifier. + QDictIterator<FileDef> ui(g_usingDeclarations); + FileDef *usedFd; + for (ui.toFirst();(usedFd=ui.current());++ui) + { + //printf("Checking using class %s\n",ui.currentKey()); + if (rightScopeMatch(ui.currentKey(),nestedNameSpecifier)) + { + // ui.currentKey() is the fully qualified name of nestedNameSpecifier + // so use this instead. + QCString fqn = QCString(ui.currentKey())+ + scope.right(scope.length()-p); + resultScope = buildScopeFromQualifiedName(fqn,fqn.contains("::"),startScope->getLanguage()); + //printf("Creating scope from fqn=%s result %p\n",fqn.data(),resultScope); + if (resultScope) + { + //printf("> Match! resultScope=%s\n",resultScope->name().data()); + return resultScope; + } + } + } + + //printf("> name %s not found in scope %s\n",nestedNameSpecifier.data(),orgScope->name().data()); + return 0; + } + nextFragment: + i1=i2; + l1=l2; + p=i2+l2; + } + //printf(">findScopeFromQualifiedName scope %s\n",resultScope->name().data()); + return resultScope; +} + +ArgumentList *getTemplateArgumentsFromName( + const QCString &name, + const QList<ArgumentList> *tArgLists) +{ + if (tArgLists==0) return 0; + + QListIterator<ArgumentList> ali(*tArgLists); + // for each scope fragment, check if it is a template and advance through + // the list if so. + int i,p=0; + while ((i=name.find("::",p))!=-1) + { + NamespaceDef *nd = Doxygen::namespaceSDict->find(name.left(i)); + if (nd==0) + { + ClassDef *cd = getClass(name.left(i)); + if (cd) + { + if (cd->templateArguments()) + { + ++ali; + } + } + } + p=i+2; + } + return ali.current(); +} + +static ClassDef::CompoundType convertToCompoundType(int section,int specifier) +{ + ClassDef::CompoundType sec=ClassDef::Class; + if (specifier&Entry::Struct) + sec=ClassDef::Struct; + else if (specifier&Entry::Union) + sec=ClassDef::Union; + else if (specifier&Entry::Interface) + sec=ClassDef::Interface; + else if (specifier&Entry::Protocol) + sec=ClassDef::Protocol; + else if (specifier&Entry::Category) + sec=ClassDef::Category; + else if (specifier&Entry::Exception) + sec=ClassDef::Exception; + + switch(section) + { + //case Entry::UNION_SEC: + case Entry::UNIONDOC_SEC: + sec=ClassDef::Union; + break; + //case Entry::STRUCT_SEC: + case Entry::STRUCTDOC_SEC: + sec=ClassDef::Struct; + break; + //case Entry::INTERFACE_SEC: + case Entry::INTERFACEDOC_SEC: + sec=ClassDef::Interface; + break; + //case Entry::PROTOCOL_SEC: + case Entry::PROTOCOLDOC_SEC: + sec=ClassDef::Protocol; + break; + //case Entry::CATEGORY_SEC: + case Entry::CATEGORYDOC_SEC: + sec=ClassDef::Category; + break; + //case Entry::EXCEPTION_SEC: + case Entry::EXCEPTIONDOC_SEC: + sec=ClassDef::Exception; + break; + } + return sec; +} + + +static void addClassToContext(EntryNav *rootNav) +{ + //printf("Loading entry for rootNav=%p name=%s\n",rootNav,rootNav->name().data()); + rootNav->loadEntry(g_storage); + Entry *root = rootNav->entry(); + + //NamespaceDef *nd = 0; + FileDef *fd = rootNav->fileDef(); + + QCString scName; + if (rootNav->parent()->section()&Entry::SCOPE_MASK) + { + scName=rootNav->parent()->name(); + } + // name without parent's scope + QCString fullName = root->name; + + // strip off any template parameters (but not those for specializations) + fullName=stripTemplateSpecifiersFromScope(fullName); + + // name with scope (if not present already) + QCString qualifiedName = fullName; + if (!scName.isEmpty() && !leftScopeMatch(fullName,scName)) + { + qualifiedName.prepend(scName+"::"); + } + + // see if we already found the class before + ClassDef *cd = getClass(qualifiedName); + + Debug::print(Debug::Classes,0, " Found class with name %s (qualifiedName=%s -> cd=%p)\n", + cd ? cd->name().data() : root->name.data(), qualifiedName.data(),cd); + + if (cd) + { + fullName=cd->name(); + Debug::print(Debug::Classes,0," Existing class %s!\n",cd->name().data()); + //if (cd->templateArguments()==0) + //{ + // //printf("existing ClassDef tempArgList=%p specScope=%s\n",root->tArgList,root->scopeSpec.data()); + // cd->setTemplateArguments(tArgList); + //} + + cd->setDocumentation(root->doc,root->docFile,root->docLine); + cd->setBriefDescription(root->brief,root->briefFile,root->briefLine); + + if (root->bodyLine!=-1 && cd->getStartBodyLine()==-1) + { + cd->setBodySegment(root->bodyLine,root->endBodyLine); + cd->setBodyDef(fd); + } + //cd->setName(fullName); // change name to match docs + + if (cd->templateArguments()==0) + { + // this happens if a template class declared with @class is found + // before the actual definition. + ArgumentList *tArgList = + getTemplateArgumentsFromName(cd->name(),root->tArgLists); + cd->setTemplateArguments(tArgList); + } + + cd->setCompoundType(convertToCompoundType(root->section,root->spec)); + } + else // new class + { + ClassDef::CompoundType sec = convertToCompoundType(root->section,root->spec); + + QCString className; + QCString namespaceName; + extractNamespaceName(fullName,className,namespaceName); + + //printf("New class: fullname %s namespace `%s' name=`%s' brief=`%s' docs=`%s'\n", + // fullName.data(),namespaceName.data(),className.data(),root->brief.data(),root->doc.data()); + + QCString tagName; + QCString refFileName; + if (rootNav->tagInfo()) + { + tagName = rootNav->tagInfo()->tagName; + refFileName = rootNav->tagInfo()->fileName; + } + cd=new ClassDef(root->fileName,root->startLine,fullName,sec, + tagName,refFileName,TRUE,root->spec&Entry::Enum); + Debug::print(Debug::Classes,0," New class `%s' (sec=0x%08x)! #tArgLists=%d\n", + fullName.data(),root->section,root->tArgLists ? (int)root->tArgLists->count() : -1); + cd->setDocumentation(root->doc,root->docFile,root->docLine); // copy docs to definition + cd->setBriefDescription(root->brief,root->briefFile,root->briefLine); + cd->setLanguage(root->lang); + cd->setHidden(root->hidden); + cd->setArtificial(root->artificial); + cd->setTypeConstraints(root->typeConstr); + //printf("new ClassDef %s tempArgList=%p specScope=%s\n",fullName.data(),root->tArgList,root->scopeSpec.data()); + + ArgumentList *tArgList = + getTemplateArgumentsFromName(fullName,root->tArgLists); + //printf("class %s template args=%s\n",fullName.data(), + // tArgList ? tempArgListToString(tArgList).data() : "<none>"); + cd->setTemplateArguments(tArgList); + cd->setProtection(root->protection); + cd->setIsStatic(root->stat); + + // file definition containing the class cd + cd->setBodySegment(root->bodyLine,root->endBodyLine); + cd->setBodyDef(fd); + + // see if the class is found inside a namespace + //bool found=addNamespace(root,cd); + + // the empty string test is needed for extract all case + cd->setBriefDescription(root->brief,root->briefFile,root->briefLine); + cd->insertUsedFile(root->fileName); + + // add class to the list + //printf("ClassDict.insert(%s)\n",resolveDefines(fullName).data()); + Doxygen::classSDict->append(fullName,cd); + + } + + cd->addSectionsToDefinition(root->anchors); + if (!root->subGrouping) cd->setSubGrouping(FALSE); + if (cd->hasDocumentation()) + { + addIncludeFile(cd,fd,root); + } + if (fd && (root->section & Entry::COMPOUND_MASK)) + { + //printf(">> Inserting class `%s' in file `%s' (root->fileName=`%s')\n", + // cd->name().data(), + // fd->name().data(), + // root->fileName.data() + // ); + cd->setFileDef(fd); + fd->insertClass(cd); + } + addClassToGroups(root,cd); + cd->setRefItems(root->sli); + + rootNav->releaseEntry(); +} + +//---------------------------------------------------------------------- +// build a list of all classes mentioned in the documentation +// and all classes that have a documentation block before their definition. +static void buildClassList(EntryNav *rootNav) +{ + if ( + ((rootNav->section() & Entry::COMPOUND_MASK) || + rootNav->section()==Entry::OBJCIMPL_SEC) && !rootNav->name().isEmpty() + ) + { + addClassToContext(rootNav); + } + RECURSE_ENTRYTREE(buildClassList,rootNav); +} + +static void buildClassDocList(EntryNav *rootNav) +{ + if ( + (rootNav->section() & Entry::COMPOUNDDOC_MASK) && !rootNav->name().isEmpty() + ) + { + addClassToContext(rootNav); + } + RECURSE_ENTRYTREE(buildClassDocList,rootNav); +} + +static void resolveClassNestingRelations() +{ + ClassSDict::Iterator cli(*Doxygen::classSDict); + for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE; + + bool done=FALSE; + int iteration=0; + while (!done) + { + done=TRUE; + ++iteration; + ClassDef *cd=0; + for (cli.toFirst();(cd=cli.current());++cli) + { + if (!cd->visited) + { + QCString name = stripAnonymousNamespaceScope(cd->name()); + //printf("processing=%s, iteration=%d\n",cd->name().data(),iteration); + // also add class to the correct structural context + Definition *d = findScopeFromQualifiedName(Doxygen::globalScope, + name,cd->getFileDef()); + if (d) + { + //printf("****** adding %s to scope %s in iteration %d\n",cd->name().data(),d->name().data(),iteration); + d->addInnerCompound(cd); + cd->setOuterScope(d); + cd->visited=TRUE; + done=FALSE; + } + //else + //{ + // printf("****** ignoring %s: scope not (yet) found in iteration %d\n",cd->name().data(),iteration); + //} + } + } + } + + //give warnings for unresolved compounds + ClassDef *cd=0; + for (cli.toFirst();(cd=cli.current());++cli) + { + if (!cd->visited) + { + QCString name = stripAnonymousNamespaceScope(cd->name()); + //printf("processing unresolved=%s, iteration=%d\n",cd->name().data(),iteration); + /// create the scope artificially + // anyway, so we can at least relate scopes properly. + Definition *d = buildScopeFromQualifiedName(name,name.contains("::"),cd->getLanguage()); + if (d!=cd && !cd->getDefFileName().isEmpty()) + // avoid recursion in case of redundant scopes, i.e: namespace N { class N::C {}; } + // for this case doxygen assumes the exitance of a namespace N::N in which C is to be found! + // also avoid warning for stuff imported via a tagfile. + { + d->addInnerCompound(cd); + cd->setOuterScope(d); + warn(cd->getDefFileName(),cd->getDefLine(), + "warning: Internal inconsistency: scope for class %s not " + "found!",name.data() + ); + } + } + } +} + +void distributeClassGroupRelations() +{ + static bool inlineGroupedClasses = Config_getBool("INLINE_GROUPED_CLASSES"); + if (!inlineGroupedClasses) return; + //printf("** distributeClassGroupRelations()\n"); + + ClassSDict::Iterator cli(*Doxygen::classSDict); + for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE; + + ClassDef *cd; + for (cli.toFirst();(cd=cli.current());++cli) + { + //printf("Checking %s\n",cd->name().data()); + // distribute the group to nested classes as well + if (!cd->visited && cd->partOfGroups()!=0 && cd->getClassSDict()) + { + //printf(" Candidate for merging\n"); + ClassSDict::Iterator ncli(*cd->getClassSDict()); + ClassDef *ncd; + GroupDef *gd = cd->partOfGroups()->at(0); + for (ncli.toFirst();(ncd=ncli.current());++ncli) + { + if (ncd->partOfGroups()==0) + { + //printf(" Adding %s to group '%s'\n",ncd->name().data(), + // gd->groupTitle()); + ncd->makePartOfGroup(gd); + gd->addClass(ncd); + } + } + cd->visited=TRUE; // only visit every class once + } + } +} + +//---------------------------- + +static ClassDef *createTagLessInstance(ClassDef *rootCd,ClassDef *templ,const QCString &fieldName) +{ + QCString fullName = removeAnonymousScopes(templ->name()); + if (fullName.right(2)=="::") fullName=fullName.left(fullName.length()-2); + fullName+="."+fieldName; + ClassDef *cd = new ClassDef(templ->getDefFileName(), + templ->getDefLine(), + fullName, + templ->compoundType()); + cd->setDocumentation(templ->documentation(),templ->docFile(),templ->docLine()); // copy docs to definition + cd->setBriefDescription(templ->briefDescription(),templ->briefFile(),templ->briefLine()); + cd->setLanguage(templ->getLanguage()); + cd->setBodySegment(templ->getStartBodyLine(),templ->getEndBodyLine()); + cd->setBodyDef(templ->getBodyDef()); + cd->setOuterScope(rootCd->getOuterScope()); + if (rootCd->getOuterScope()!=Doxygen::globalScope) + { + rootCd->getOuterScope()->addInnerCompound(cd); + } + FileDef *fd = templ->getFileDef(); + if (fd) + { + cd->setFileDef(fd); + fd->insertClass(cd); + } + LockingPtr<GroupList> groups = rootCd->partOfGroups(); + if ( groups!=0 ) + { + GroupListIterator gli(*groups); + GroupDef *gd; + for (gli.toFirst();(gd=gli.current());++gli) + { + cd->makePartOfGroup(gd); + gd->addClass(cd); + } + } + //cd->insertUsedFile(root->fileName); + //printf("** adding class %s based on %s\n",fullName.data(),templ->name().data()); + Doxygen::classSDict->append(fullName,cd); + + MemberList *ml = templ->getMemberList(MemberList::pubAttribs); + if (ml) + { + MemberListIterator li(*ml); + MemberDef *md; + for (li.toFirst();(md=li.current());++li) + { + //printf(" Member %s type=%s\n",md->name().data(),md->typeString()); + MemberDef *imd = new MemberDef(md->getDefFileName(),md->getDefLine(), + md->typeString(),md->name(),md->argsString(),md->excpString(), + md->protection(),md->virtualness(),md->isStatic(),Member, + md->memberType(), + 0,0); + imd->setMemberClass(cd); + imd->setDocumentation(md->documentation(),md->docFile(),md->docLine()); + imd->setBriefDescription(md->briefDescription(),md->briefFile(),md->briefLine()); + imd->setInbodyDocumentation(md->inbodyDocumentation(),md->inbodyFile(),md->inbodyLine()); + imd->setMemberSpecifiers(md->getMemberSpecifiers()); + imd->setMemberGroupId(md->getMemberGroupId()); + imd->setInitializer(md->initializer()); + imd->setMaxInitLines(md->initializerLines()); + imd->setBitfields(md->bitfieldString()); + imd->setLanguage(md->getLanguage()); + cd->insertMember(imd); + } + } + return cd; +} + +/** Look through the members of class \a cd and its public members. + * If there is a member m of a tag less struct/union, + * then we create a duplicate of the struct/union with the name of the + * member to identify it. + * So if cd has name S, then the tag less struct/union will get name S.m + * Since tag less structs can be nested we need to call this function + * recursively. Later on we need to patch the member types so we keep + * track of the hierarchy of classes we create. + */ +static void processTagLessClasses(ClassDef *rootCd, + ClassDef *cd, + ClassDef *tagParentCd, + const QCString &prefix,int count) +{ + //printf("%d: processTagLessClasses %s\n",count,cd->name().data()); + //printf("checking members for %s\n",cd->name().data()); + if (cd->getClassSDict()) + { + MemberList *ml = cd->getMemberList(MemberList::pubAttribs); + if (ml) + { + MemberListIterator li(*ml); + MemberDef *md; + for (li.toFirst();(md=li.current());++li) + { + QCString type = md->typeString(); + if (type.find("::@")!=-1) // member of tag less struct/union + { + ClassSDict::Iterator it(*cd->getClassSDict()); + ClassDef *icd; + for (it.toFirst();(icd=it.current());++it) + { + //printf(" member %s: type='%s'\n",md->name().data(),type.data()); + //printf(" comparing '%s'<->'%s'\n",type.data(),icd->name().data()); + if (type.find(icd->name())!=-1) // matching tag less struct/union + { + QCString name = md->name(); + if (name.at(0)=='@') name = "__unnamed__"; + if (!prefix.isEmpty()) name.prepend(prefix+"."); + //printf(" found %s for class %s\n",name.data(),cd->name().data()); + ClassDef *ncd = createTagLessInstance(rootCd,icd,name); + processTagLessClasses(rootCd,icd,ncd,name,count+1); + //printf(" addTagged %s to %s\n",ncd->name().data(),cd->name().data()); + tagParentCd->addTaggedInnerClass(ncd); + ncd->setTagLessReference(icd); + + // replace tag-less type for generated/original member + // by newly created class name. + // note the difference between changing cd and tagParentCd. + // for the initial call this is the same pointer, but for + // recursive calls cd is the original tag-less struct (of which + // there is only one instance) and tagParentCd is the newly + // generated tagged struct of which there can be multiple instances! + MemberList *pml = tagParentCd->getMemberList(MemberList::pubAttribs); + if (pml) + { + MemberListIterator pli(*pml); + MemberDef *pmd; + for (pli.toFirst();(pmd=pli.current());++pli) + { + if (pmd->name()==md->name()) + { + pmd->setType(substitute(pmd->typeString(),icd->name(),ncd->name())); + } + } + } + } + } + } + } + } + } +} + +static void findTagLessClasses(ClassDef *cd) +{ + if (cd->getClassSDict()) + { + ClassSDict::Iterator it(*cd->getClassSDict()); + ClassDef *icd; + for (it.toFirst();(icd=it.current());++it) + { + if (icd->name().find("@")==-1) // process all non-anonymous inner classes + { + findTagLessClasses(icd); + } + } + } + + processTagLessClasses(cd,cd,cd,"",0); // process tag less inner struct/classes (if any) +} + +static void findTagLessClasses() +{ + ClassSDict::Iterator cli(*Doxygen::classSDict); + ClassDef *cd; + for (cli.toFirst();(cd=cli.current());++cli) // for each class + { + Definition *scope = cd->getOuterScope(); + if (scope && scope->definitionType()!=Definition::TypeClass) // that is not nested + { + findTagLessClasses(cd); + } + } +} + + +//---------------------------------------------------------------------- +// build a list of all namespaces mentioned in the documentation +// and all namespaces that have a documentation block before their definition. +static void buildNamespaceList(EntryNav *rootNav) +{ + if ( + (rootNav->section()==Entry::NAMESPACE_SEC || + rootNav->section()==Entry::NAMESPACEDOC_SEC || + rootNav->section()==Entry::PACKAGEDOC_SEC + ) && + !rootNav->name().isEmpty() + ) + { + rootNav->loadEntry(g_storage); + Entry *root = rootNav->entry(); + + //printf("** buildNamespaceList(%s)\n",root->name.data()); + + QCString fName = root->name; + if (root->section==Entry::PACKAGEDOC_SEC) + { + fName=substitute(fName,".","::"); + } + + QCString fullName = stripAnonymousNamespaceScope(fName); + if (!fullName.isEmpty()) + { + //printf("Found namespace %s in %s at line %d\n",root->name.data(), + // root->fileName.data(), root->startLine); + NamespaceDef *nd; + if ((nd=Doxygen::namespaceSDict->find(fullName))) // existing namespace + { + nd->setDocumentation(root->doc,root->docFile,root->docLine); + nd->setName(fullName); // change name to match docs + nd->addSectionsToDefinition(root->anchors); + nd->setBriefDescription(root->brief,root->briefFile,root->briefLine); + if (nd->getLanguage()==SrcLangExt_Unknown) + { + nd->setLanguage(root->lang); + } + + // file definition containing the namespace nd + FileDef *fd=rootNav->fileDef(); + // insert the namespace in the file definition + if (fd) fd->insertNamespace(nd); + addNamespaceToGroups(root,nd); + nd->setRefItems(root->sli); + } + else // fresh namespace + { + QCString tagName; + QCString tagFileName; + if (rootNav->tagInfo()) + { + tagName=rootNav->tagInfo()->tagName; + tagFileName=rootNav->tagInfo()->fileName; + } + //printf("++ new namespace %s lang=%s\n",fullName.data(),langToString(root->lang).data()); + NamespaceDef *nd=new NamespaceDef(root->fileName,root->startLine,fullName,tagName,tagFileName); + nd->setDocumentation(root->doc,root->docFile,root->docLine); // copy docs to definition + nd->setBriefDescription(root->brief,root->briefFile,root->briefLine); + nd->addSectionsToDefinition(root->anchors); + nd->setHidden(root->hidden); + nd->setArtificial(root->artificial); + nd->setLanguage(root->lang); + + //printf("Adding namespace to group\n"); + addNamespaceToGroups(root,nd); + nd->setRefItems(root->sli); + + // file definition containing the namespace nd + FileDef *fd=rootNav->fileDef(); + // insert the namespace in the file definition + if (fd) fd->insertNamespace(nd); + + // the empty string test is needed for extract all case + nd->setBriefDescription(root->brief,root->briefFile,root->briefLine); + nd->insertUsedFile(root->fileName); + nd->setBodySegment(root->bodyLine,root->endBodyLine); + nd->setBodyDef(fd); + // add class to the list + Doxygen::namespaceSDict->inSort(fullName,nd); + + // also add namespace to the correct structural context + Definition *d = findScopeFromQualifiedName(Doxygen::globalScope,fullName); + //printf("adding namespace %s to context %s\n",nd->name().data(),d?d->name().data():"<none>"); + if (d==0) // we didn't find anything, create the scope artificially + // anyway, so we can at least relate scopes properly. + { + Definition *d = buildScopeFromQualifiedName(fullName,fullName.contains("::"),nd->getLanguage()); + d->addInnerCompound(nd); + nd->setOuterScope(d); + // TODO: Due to the order in which the tag file is written + // a nested class can be found before its parent! + } + else + { + d->addInnerCompound(nd); + nd->setOuterScope(d); + } + } + } + + rootNav->releaseEntry(); + } + RECURSE_ENTRYTREE(buildNamespaceList,rootNav); +} + +//---------------------------------------------------------------------- + +static NamespaceDef *findUsedNamespace(NamespaceSDict *unl, + const QCString &name) +{ + NamespaceDef *usingNd =0; + if (unl) + { + //printf("Found namespace dict %d\n",unl->count()); + NamespaceSDict::Iterator unli(*unl); + NamespaceDef *und; + for (unli.toFirst();(und=unli.current());++unli) + { + QCString uScope=und->name()+"::"; + usingNd = getResolvedNamespace(uScope+name); + //printf("Also trying with scope=`%s' usingNd=%p\n",(uScope+name).data(),usingNd); + } + } + return usingNd; +} + +static void findUsingDirectives(EntryNav *rootNav) +{ + if (rootNav->section()==Entry::USINGDIR_SEC) + { + rootNav->loadEntry(g_storage); + Entry *root = rootNav->entry(); + + //printf("Found using directive %s at line %d of %s\n", + // root->name.data(),root->startLine,root->fileName.data()); + QCString name=substitute(root->name,".","::"); + if (!name.isEmpty()) + { + NamespaceDef *usingNd = 0; + NamespaceDef *nd = 0; + FileDef *fd = rootNav->fileDef(); + QCString nsName; + + // see if the using statement was found inside a namespace or inside + // the global file scope. + if (rootNav->parent() && rootNav->parent()->section()==Entry::NAMESPACE_SEC && + (fd==0 || fd->getLanguage()!=SrcLangExt_Java) // not a .java file + ) + { + nsName=stripAnonymousNamespaceScope(rootNav->parent()->name()); + if (!nsName.isEmpty()) + { + nd = getResolvedNamespace(nsName); + } + } + + // find the scope in which the `using' namespace is defined by prepending + // the possible scopes in which the using statement was found, starting + // with the most inner scope and going to the most outer scope (i.e. + // file scope). + int scopeOffset = nsName.length(); + do + { + QCString scope=scopeOffset>0 ? + nsName.left(scopeOffset)+"::" : QCString(); + usingNd = getResolvedNamespace(scope+name); + //printf("Trying with scope=`%s' usingNd=%p\n",(scope+name).data(),usingNd); + if (scopeOffset==0) + { + scopeOffset=-1; + } + else if ((scopeOffset=nsName.findRev("::",scopeOffset-1))==-1) + { + scopeOffset=0; + } + } while (scopeOffset>=0 && usingNd==0); + + if (usingNd==0 && nd) // not found, try used namespaces in this scope + // or in one of the parent namespace scopes + { + NamespaceDef *pnd = nd; + while (pnd && usingNd==0) + { + // also try with one of the used namespaces found earlier + usingNd = findUsedNamespace(pnd->getUsedNamespaces(),name); + + // goto the parent + Definition *s = pnd->getOuterScope(); + if (s && s->definitionType()==Definition::TypeNamespace) + { + pnd = (NamespaceDef*)s; + } + else + { + pnd = 0; + } + } + } + if (usingNd==0 && fd) // still nothing, also try used namespace in the + // global scope + { + usingNd = findUsedNamespace(fd->getUsedNamespaces(),name); + } + + //printf("%s -> %s\n",name.data(),usingNd?usingNd->name().data():"<none>"); + + // add the namespace the correct scope + if (usingNd) + { + //printf("using fd=%p nd=%p\n",fd,nd); + if (nd) + { + //printf("Inside namespace %s\n",nd->name().data()); + nd->addUsingDirective(usingNd); + } + else if (fd) + { + //printf("Inside file %s\n",fd->name().data()); + fd->addUsingDirective(usingNd); + } + } + else // unknown namespace, but add it anyway. + { + //printf("++ new unknown namespace %s lang=%s\n",name.data(),langToString(root->lang).data()); + NamespaceDef *nd=new NamespaceDef(root->fileName,root->startLine,name); + nd->setDocumentation(root->doc,root->docFile,root->docLine); // copy docs to definition + nd->setBriefDescription(root->brief,root->briefFile,root->briefLine); + nd->addSectionsToDefinition(root->anchors); + //printf("** Adding namespace %s hidden=%d\n",name.data(),root->hidden); + nd->setHidden(root->hidden); + nd->setArtificial(TRUE); + nd->setLanguage(root->lang); + + QListIterator<Grouping> gli(*root->groups); + Grouping *g; + for (;(g=gli.current());++gli) + { + GroupDef *gd=0; + if (!g->groupname.isEmpty() && (gd=Doxygen::groupSDict->find(g->groupname))) + gd->addNamespace(nd); + } + + // insert the namespace in the file definition + if (fd) + { + fd->insertNamespace(nd); + fd->addUsingDirective(nd); + } + + // the empty string test is needed for extract all case + nd->setBriefDescription(root->brief,root->briefFile,root->briefLine); + nd->insertUsedFile(root->fileName); + // add class to the list + Doxygen::namespaceSDict->inSort(name,nd); + nd->setRefItems(root->sli); + } + } + + rootNav->releaseEntry(); + } + RECURSE_ENTRYTREE(findUsingDirectives,rootNav); +} + +//---------------------------------------------------------------------- + +static void buildListOfUsingDecls(EntryNav *rootNav) +{ + if (rootNav->section()==Entry::USINGDECL_SEC && + !(rootNav->parent()->section()&Entry::COMPOUND_MASK) // not a class/struct member + ) + { + rootNav->loadEntry(g_storage); + Entry *root = rootNav->entry(); + + QCString name = substitute(root->name,".","::"); + if (g_usingDeclarations.find(name)==0) + { + FileDef *fd = rootNav->fileDef(); + if (fd) + { + g_usingDeclarations.insert(name,fd); + } + } + + rootNav->releaseEntry(); + } + RECURSE_ENTRYTREE(buildListOfUsingDecls,rootNav); +} + + +static void findUsingDeclarations(EntryNav *rootNav) +{ + if (rootNav->section()==Entry::USINGDECL_SEC && + !(rootNav->parent()->section()&Entry::COMPOUND_MASK) // not a class/struct member + ) + { + rootNav->loadEntry(g_storage); + Entry *root = rootNav->entry(); + + //printf("Found using declaration %s at line %d of %s inside section %x\n", + // root->name.data(),root->startLine,root->fileName.data(), + // rootNav->parent()->section()); + if (!root->name.isEmpty()) + { + ClassDef *usingCd = 0; + NamespaceDef *nd = 0; + FileDef *fd = rootNav->fileDef(); + QCString scName; + + // see if the using statement was found inside a namespace or inside + // the global file scope. + if (rootNav->parent()->section() == Entry::NAMESPACE_SEC) + { + scName=rootNav->parent()->name(); + if (!scName.isEmpty()) + { + nd = getResolvedNamespace(scName); + } + } + + // Assume the using statement was used to import a class. + // Find the scope in which the `using' namespace is defined by prepending + // the possible scopes in which the using statement was found, starting + // with the most inner scope and going to the most outer scope (i.e. + // file scope). + + QCString name = substitute(root->name,".","::"); //Java/C# scope->internal + usingCd = getClass(name); + if (usingCd==0) + { + usingCd = Doxygen::hiddenClasses->find(name); + } + + //printf("%s -> %p\n",root->name.data(),usingCd); + if (usingCd==0) // definition not in the input => add an artificial class + { + Debug::print(Debug::Classes,0," New using class `%s' (sec=0x%08x)! #tArgLists=%d\n", + name.data(),root->section,root->tArgLists ? (int)root->tArgLists->count() : -1); + usingCd = new ClassDef( + "<using>",1, + name,ClassDef::Class); + Doxygen::hiddenClasses->append(root->name,usingCd); + usingCd->setArtificial(TRUE); + usingCd->setLanguage(root->lang); + } + else + { + Debug::print(Debug::Classes,0," Found used class %s in scope=%s\n", + usingCd->name().data(),nd?nd->name().data():fd->name().data()); + } + + if (usingCd) // add the class to the correct scope + { + if (nd) + { + //printf("Inside namespace %s\n",nd->name().data()); + nd->addUsingDeclaration(usingCd); + } + else if (fd) + { + //printf("Inside file %s\n",fd->name().data()); + fd->addUsingDeclaration(usingCd); + } + } + } + + rootNav->releaseEntry(); + } + RECURSE_ENTRYTREE(findUsingDeclarations,rootNav); +} + +//---------------------------------------------------------------------- + +static void findUsingDeclImports(EntryNav *rootNav) +{ + if (rootNav->section()==Entry::USINGDECL_SEC && + (rootNav->parent()->section()&Entry::COMPOUND_MASK) // in a class/struct member + ) + { + //printf("Found using declaration %s at line %d of %s inside section %x\n", + // root->name.data(),root->startLine,root->fileName.data(), + // root->parent->section); + QCString fullName=removeRedundantWhiteSpace(rootNav->parent()->name()); + fullName=stripAnonymousNamespaceScope(fullName); + fullName=stripTemplateSpecifiersFromScope(fullName); + ClassDef *cd = getClass(fullName); + if (cd) + { + //printf("found class %s\n",cd->name().data()); + int i=rootNav->name().find("::"); + if (i!=-1) + { + QCString scope=rootNav->name().left(i); + QCString memName=rootNav->name().right(rootNav->name().length()-i-2); + ClassDef *bcd = getResolvedClass(cd,0,scope); // todo: file in fileScope parameter + if (bcd) + { + //printf("found class %s\n",bcd->name().data()); + MemberNameInfoSDict *mndict=bcd->memberNameInfoSDict(); + if (mndict) + { + MemberNameInfo *mni = mndict->find(memName); + if (mni) + { + MemberNameInfoIterator mnii(*mni); + MemberInfo *mi; + for ( ; (mi=mnii.current()) ; ++mnii ) + { + MemberDef *md = mi->memberDef; + if (md && md->protection()!=Private) + { + + rootNav->loadEntry(g_storage); + Entry *root = rootNav->entry(); + + //printf("found member %s\n",mni->memberName()); + MemberDef *newMd = 0; + { + LockingPtr<ArgumentList> templAl = md->templateArguments(); + LockingPtr<ArgumentList> al = md->templateArguments(); + newMd = new MemberDef( + root->fileName,root->startLine, + md->typeString(),memName,md->argsString(), + md->excpString(),root->protection,root->virt, + md->isStatic(),Member,md->memberType(), + templAl.pointer(),al.pointer() + ); + } + newMd->setMemberClass(cd); + cd->insertMember(newMd); + if (!root->doc.isEmpty() || !root->brief.isEmpty()) + { + newMd->setDocumentation(root->doc,root->docFile,root->docLine); + newMd->setBriefDescription(root->brief,root->briefFile,root->briefLine); + newMd->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine); + } + else + { + newMd->setDocumentation(md->documentation(),md->docFile(),md->docLine()); + newMd->setBriefDescription(md->briefDescription(),md->briefFile(),md->briefLine()); + newMd->setInbodyDocumentation(md->inbodyDocumentation(),md->inbodyFile(),md->inbodyLine()); + } + newMd->setDefinition(md->definition()); + newMd->enableCallGraph(root->callGraph); + newMd->enableCallerGraph(root->callerGraph); + newMd->setBitfields(md->bitfieldString()); + newMd->addSectionsToDefinition(root->anchors); + newMd->setBodySegment(md->getStartBodyLine(),md->getEndBodyLine()); + newMd->setBodyDef(md->getBodyDef()); + newMd->setInitializer(md->initializer()); + newMd->setMaxInitLines(md->initializerLines()); + newMd->setMemberGroupId(root->mGrpId); + newMd->setMemberSpecifiers(md->getMemberSpecifiers()); + newMd->setLanguage(root->lang); + + rootNav->releaseEntry(); + } + } + } + } + } + } + } + + } + RECURSE_ENTRYTREE(findUsingDeclImports,rootNav); +} + +//---------------------------------------------------------------------- + +static void findIncludedUsingDirectives() +{ + // first mark all files as not visited + FileNameListIterator fnli(*Doxygen::inputNameList); + FileName *fn; + for (fnli.toFirst();(fn=fnli.current());++fnli) + { + FileNameIterator fni(*fn); + FileDef *fd; + for (;(fd=fni.current());++fni) + { + fd->visited=FALSE; + } + } + // then recursively add using directives found in #include files + // to files that have not been visited. + for (fnli.toFirst();(fn=fnli.current());++fnli) + { + FileNameIterator fni(*fn); + FileDef *fd; + for (fni.toFirst();(fd=fni.current());++fni) + { + if (!fd->visited) + { + //printf("----- adding using directives for file %s\n",fd->name().data()); + fd->addIncludedUsingDirectives(); + } + } + } +} + +//---------------------------------------------------------------------- + +static MemberDef *addVariableToClass( + EntryNav *rootNav, + ClassDef *cd, + MemberDef::MemberType mtype, + const QCString &name, + bool fromAnnScope, + MemberDef *fromAnnMemb, + Protection prot, + Relationship related) +{ + Entry *root = rootNav->entry(); + + QCString qualScope = cd->qualifiedNameWithTemplateParameters(); + QCString scopeSeparator="::"; + SrcLangExt lang = cd->getLanguage(); + if (lang==SrcLangExt_Java || lang==SrcLangExt_CSharp) + { + qualScope = substitute(qualScope,"::","."); + scopeSeparator="."; + } + Debug::print(Debug::Variables,0, + " class variable:\n" + " `%s' `%s'::`%s' `%s' prot=`%d ann=%d init=`%s'\n", + root->type.data(), + qualScope.data(), + name.data(), + root->args.data(), + root->protection, + fromAnnScope, + root->initializer.data() + ); + + QCString def; + if (!root->type.isEmpty()) + { + if (related || mtype==MemberDef::Friend || Config_getBool("HIDE_SCOPE_NAMES")) + { + def=root->type+" "+name+root->args; + } + else + { + def=root->type+" "+qualScope+scopeSeparator+name+root->args; + } + } + else + { + if (Config_getBool("HIDE_SCOPE_NAMES")) + { + def=name+root->args; + } + else + { + def=qualScope+scopeSeparator+name+root->args; + } + } + def.stripPrefix("static "); + + // see if the member is already found in the same scope + // (this may be the case for a static member that is initialized + // outside the class) + MemberName *mn=Doxygen::memberNameSDict->find(name); + if (mn) + { + MemberNameIterator mni(*mn); + MemberDef *md; + for (mni.toFirst();(md=mni.current());++mni) + { + //printf("md->getClassDef()=%p cd=%p type=[%s] md->typeString()=[%s]\n", + // md->getClassDef(),cd,root->type.data(),md->typeString()); + if (md->getClassDef()==cd && + removeRedundantWhiteSpace(root->type)==md->typeString()) + // member already in the scope + { + + if (root->lang==SrcLangExt_ObjC && + root->mtype==Property && + md->memberType()==MemberDef::Variable) + { // Objective-C 2.0 property + // turn variable into a property + md->setProtection(root->protection); + cd->reclassifyMember(md,MemberDef::Property); + } + addMemberDocs(rootNav,md,def,0,FALSE); + //printf(" Member already found!\n"); + return md; + } + } + } + + // new member variable, typedef or enum value + MemberDef *md=new MemberDef( + root->fileName,root->startLine, + root->type,name,root->args,0, + prot,Normal,root->stat,related, + mtype,0,0); + md->setTagInfo(rootNav->tagInfo()); + md->setMemberClass(cd); // also sets outer scope (i.e. getOuterScope()) + //md->setDefFile(root->fileName); + //md->setDefLine(root->startLine); + md->setDocumentation(root->doc,root->docFile,root->docLine); + md->setBriefDescription(root->brief,root->briefFile,root->briefLine); + md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine); + md->setDefinition(def); + md->setBitfields(root->bitfields); + md->addSectionsToDefinition(root->anchors); + md->setFromAnonymousScope(fromAnnScope); + md->setFromAnonymousMember(fromAnnMemb); + //md->setIndentDepth(indentDepth); + md->setBodySegment(root->bodyLine,root->endBodyLine); + md->setInitializer(root->initializer); + md->setMaxInitLines(root->initLines); + md->setMemberGroupId(root->mGrpId); + md->setMemberSpecifiers(root->spec); + md->setReadAccessor(root->read); + md->setWriteAccessor(root->write); + md->enableCallGraph(root->callGraph); + md->enableCallerGraph(root->callerGraph); + md->setHidden(root->hidden); + md->setArtificial(root->artificial); + md->setLanguage(root->lang); + addMemberToGroups(root,md); + //if (root->mGrpId!=-1) + //{ + // printf("memberdef %s in memberGroup %d\n",name.data(),root->mGrpId); + // md->setMemberGroup(memberGroupDict[root->mGrpId]); + // + md->setBodyDef(rootNav->fileDef()); + + //printf(" Adding member=%s\n",md->name().data()); + // add the member to the global list + if (mn) + { + mn->append(md); + } + else // new variable name + { + mn = new MemberName(name); + mn->append(md); + //printf("Adding memberName=%s\n",mn->memberName()); + //Doxygen::memberNameDict.insert(name,mn); + //Doxygen::memberNameList.append(mn); + Doxygen::memberNameSDict->append(name,mn); + // add the member to the class + } + //printf(" New member adding to %s (%p)!\n",cd->name().data(),cd); + cd->insertMember(md); + md->setRefItems(root->sli); + + //TODO: insert FileDef instead of filename strings. + cd->insertUsedFile(root->fileName); + rootNav->changeSection(Entry::EMPTY_SEC); + return md; +} + +//---------------------------------------------------------------------- + +static MemberDef *addVariableToFile( + EntryNav *rootNav, + MemberDef::MemberType mtype, + const QCString &scope, + const QCString &name, + bool fromAnnScope, + /*int indentDepth,*/ + MemberDef *fromAnnMemb) +{ + Entry *root = rootNav->entry(); + Debug::print(Debug::Variables,0, + " global variable:\n" + " type=`%s' scope=`%s' name=`%s' args=`%s' prot=`%d mtype=%d lang=%d\n", + root->type.data(), + scope.data(), + name.data(), + root->args.data(), + root->protection, + mtype, + root->lang + ); + + FileDef *fd = rootNav->fileDef(); + + // see if we have a typedef that should hide a struct or union + if (mtype==MemberDef::Typedef && Config_getBool("TYPEDEF_HIDES_STRUCT")) + { + QCString type = root->type; + type.stripPrefix("typedef "); + if (type.left(7)=="struct " || type.left(6)=="union ") + { + type.stripPrefix("struct "); + type.stripPrefix("union "); + static QRegExp re("[a-z_A-Z][a-z_A-Z0-9]*"); + int l,s; + s = re.match(type,0,&l); + if (s>=0) + { + QCString typeValue = type.mid(s,l); + ClassDef *cd = getClass(typeValue); + if (cd) + { + // this typedef should hide compound name cd, so we + // change the name that is displayed from cd. + cd->setClassName(name); + cd->setDocumentation(root->doc,root->docFile,root->docLine); + cd->setBriefDescription(root->brief,root->briefFile,root->briefLine); + return 0; + } + } + } + } + + // see if the function is inside a namespace + NamespaceDef *nd = 0; + QCString nscope; + if (!scope.isEmpty()) + { + if (scope.find('@')!=-1) return 0; // anonymous scope! + //nscope=removeAnonymousScopes(scope); + //if (!nscope.isEmpty()) + //{ + nd = getResolvedNamespace(scope); + //} + } + QCString def; + + // determine the definition of the global variable + if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@' && + !Config_getBool("HIDE_SCOPE_NAMES") + ) + // variable is inside a namespace, so put the scope before the name + { + SrcLangExt lang = nd->getLanguage(); + QCString sep=getLanguageSpecificSeparator(lang); + + if (!root->type.isEmpty()) + { + def=root->type+" "+nd->name()+sep+name+root->args; + } + else + { + def=nd->name()+sep+name+root->args; + } + } + else + { + if (!root->type.isEmpty() && !root->name.isEmpty()) + { + if (name.at(0)=='@') // dummy variable representing anonymous union + def=root->type; + else + def=root->type+" "+name+root->args; + } + else + { + def=name+root->args; + } + } + def.stripPrefix("static "); + + MemberName *mn=Doxygen::functionNameSDict->find(name); + if (mn) + { + //QCString nscope=removeAnonymousScopes(scope); + //NamespaceDef *nd=0; + //if (!nscope.isEmpty()) + if (!scope.isEmpty()) + { + nd = getResolvedNamespace(scope); + } + MemberNameIterator mni(*mn); + MemberDef *md; + for (mni.toFirst();(md=mni.current());++mni) + { + if ( + ((nd==0 && md->getNamespaceDef()==0 && md->getFileDef() && + root->fileName==md->getFileDef()->absFilePath() + ) // both variable names in the same file + || (nd!=0 && md->getNamespaceDef()==nd) // both in same namespace + ) + && !md->isDefine() // function style #define's can be "overloaded" by typedefs or variables + && !md->isEnumerate() // in C# an enum value and enum can have the same name + ) + // variable already in the scope + { + if (md->getFileDef() && + ! // not a php array + ( + (md->getLanguage()==SrcLangExt_PHP) && + (md->argsString()!=root->args && root->args.find('[')!=-1) + ) + ) + // not a php array variable + { + + Debug::print(Debug::Variables,0, + " variable already found: scope=%s\n",md->getOuterScope()->name().data()); + addMemberDocs(rootNav,md,def,0,FALSE); + md->setRefItems(root->sli); + return md; + } + } + } + } + Debug::print(Debug::Variables,0, + " new variable, nd=%s!\n",nd?nd->name().data():"<global>"); + // new global variable, enum value or typedef + MemberDef *md=new MemberDef( + root->fileName,root->startLine, + root->type,name,root->args,0, + Public, Normal,root->stat,Member, + mtype,0,0); + md->setTagInfo(rootNav->tagInfo()); + md->setDocumentation(root->doc,root->docFile,root->docLine); + md->setBriefDescription(root->brief,root->briefFile,root->briefLine); + md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine); + md->addSectionsToDefinition(root->anchors); + md->setFromAnonymousScope(fromAnnScope); + md->setFromAnonymousMember(fromAnnMemb); + md->setInitializer(root->initializer); + md->setMaxInitLines(root->initLines); + md->setMemberGroupId(root->mGrpId); + md->setDefinition(def); + md->setLanguage(root->lang); + md->enableCallGraph(root->callGraph); + md->enableCallerGraph(root->callerGraph); + md->setExplicitExternal(root->explicitExternal); + //md->setOuterScope(fd); + if (!root->explicitExternal) + { + md->setBodySegment(root->bodyLine,root->endBodyLine); + md->setBodyDef(fd); + } + addMemberToGroups(root,md); + + md->setRefItems(root->sli); + if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@') + { + md->setNamespace(nd); + nd->insertMember(md); + } + + // add member to the file (we do this even if we have already inserted + // it into the namespace. + if (fd) + { + md->setFileDef(fd); + fd->insertMember(md); + } + + // add member definition to the list of globals + if (mn) + { + mn->append(md); + } + else + { + mn = new MemberName(name); + mn->append(md); + Doxygen::functionNameSDict->append(name,mn); + } + rootNav->changeSection(Entry::EMPTY_SEC); + return md; +} + +/*! See if the return type string \a type is that of a function pointer + * \returns -1 if this is not a function pointer variable or + * the index at which the closing brace of (...*name) was found. + */ +static int findFunctionPtr(const QCString &type,int lang, int *pLength=0) +{ + if (lang == SrcLangExt_Fortran) return -1; // Fortran does not have function pointers + static const QRegExp re("([^)]*[\\*\\^][^)]*)"); + int i=-1,l; + int bb=type.find('<'); + int be=type.findRev('>'); + if (!type.isEmpty() && // return type is non-empty + (i=re.match(type,0,&l))!=-1 && // contains (...*...) + type.find("operator")==-1 && // not an operator + (type.find(")(")==-1 || type.find("typedef ")!=-1) && + // not a function pointer return type + !(bb<i && i<be) // bug665855: avoid treating "typedef A<void (T*)> type" as a function pointer + ) + { + if (pLength) *pLength=l; + //printf("findFunctionPtr=%d\n",i); + return i; + } + else + { + //printf("findFunctionPtr=%d\n",-1); + return -1; + } +} + + +/*! Returns TRUE iff \a type is a class within scope \a context. + * Used to detect variable declarations that look like function prototypes. + */ +static bool isVarWithConstructor(EntryNav *rootNav) +{ + static QRegExp initChars("[0-9\"'&*!^]+"); + static QRegExp idChars("[a-z_A-Z][a-z_A-Z0-9]*"); + bool result=FALSE; + bool typeIsClass; + QCString type; + Definition *ctx = 0; + FileDef *fd = 0; + int ti; + + //printf("isVarWithConstructor(%s)\n",rootNav->name().data()); + rootNav->loadEntry(g_storage); + Entry *root = rootNav->entry(); + + if (rootNav->parent()->section() & Entry::COMPOUND_MASK) + { // inside a class + result=FALSE; + goto done; + } + else if ((fd = rootNav->fileDef()) && + (fd->name().right(2)==".c" || fd->name().right(2)==".h") + ) + { // inside a .c file + result=FALSE; + goto done; + } + if (root->type.isEmpty()) + { + result=FALSE; + goto done; + } + if (!rootNav->parent()->name().isEmpty()) + { + ctx=Doxygen::namespaceSDict->find(rootNav->parent()->name()); + } + type = root->type; + // remove qualifiers + findAndRemoveWord(type,"const"); + findAndRemoveWord(type,"static"); + findAndRemoveWord(type,"volatile"); + //if (type.left(6)=="const ") type=type.right(type.length()-6); + typeIsClass=getResolvedClass(ctx,fd,type)!=0; + if (!typeIsClass && (ti=type.find('<'))!=-1) + { + typeIsClass=getResolvedClass(ctx,fd,type.left(ti))!=0; + } + if (typeIsClass) // now we still have to check if the arguments are + // types or values. Since we do not have complete type info + // we need to rely on heuristics :-( + { + //printf("typeIsClass\n"); + ArgumentList *al = root->argList; + if (al==0 || al->isEmpty()) + { + result=FALSE; // empty arg list -> function prototype. + goto done; + } + ArgumentListIterator ali(*al); + Argument *a; + for (ali.toFirst();(a=ali.current());++ali) + { + if (!a->name.isEmpty() || !a->defval.isEmpty()) + { + if (a->name.find(initChars)==0) + { + result=TRUE; + } + else + { + result=FALSE; // arg has (type,name) pair -> function prototype + } + goto done; + } + if (a->type.isEmpty() || getResolvedClass(ctx,fd,a->type)!=0) + { + result=FALSE; // arg type is a known type + goto done; + } + if (checkIfTypedef(ctx,fd,a->type)) + { + //printf("%s:%d: false (arg is typedef)\n",__FILE__,__LINE__); + result=FALSE; // argument is a typedef + goto done; + } + if (a->type.at(a->type.length()-1)=='*' || + a->type.at(a->type.length()-1)=='&') + // type ends with * or & => pointer or reference + { + result=FALSE; + goto done; + } + if (a->type.find(initChars)==0) + { + result=TRUE; // argument type starts with typical initializer char + goto done; + } + QCString resType=resolveTypeDef(ctx,a->type); + if (resType.isEmpty()) resType=a->type; + int len; + if (idChars.match(resType,0,&len)==0) // resType starts with identifier + { + resType=resType.left(len); + //printf("resType=%s\n",resType.data()); + if (resType=="int" || resType=="long" || resType=="float" || + resType=="double" || resType=="char" || resType=="signed" || + resType=="const" || resType=="unsigned" || resType=="void") + { + result=FALSE; // type keyword -> function prototype + goto done; + } + } + } + result=TRUE; + } + +done: + //printf("isVarWithConstructor(%s,%s)=%d\n",rootNav->parent()->name().data(), + // root->type.data(),result); + rootNav->releaseEntry(); + return result; +} + +static void addVariable(EntryNav *rootNav,int isFuncPtr=-1) +{ + rootNav->loadEntry(g_storage); + Entry *root = rootNav->entry(); + + Debug::print(Debug::Variables,0, + "VARIABLE_SEC: \n" + " type=`%s' name=`%s' args=`%s' bodyLine=`%d' mGrpId=%d relates=%s\n", + root->type.data(), + root->name.data(), + root->args.data(), + root->bodyLine, + root->mGrpId, + root->relates.data() + ); + //printf("root->parent->name=%s\n",root->parent->name.data()); + + if (root->type.isEmpty() && root->name.find("operator")==-1 && + (root->name.find('*')!=-1 || root->name.find('&')!=-1)) + { + // recover from parse error caused by redundant braces + // like in "int *(var[10]);", which is parsed as + // type="" name="int *" args="(var[10])" + + root->type=root->name; + static const QRegExp reName("[a-z_A-Z][a-z_A-Z0-9]*"); + int l; + int i=root->args.isEmpty() ? -1 : reName.match(root->args,0,&l); + root->name=root->args.mid(i,l); + root->args=root->args.mid(i+l,root->args.find(')',i+l)-i-l); + //printf("new: type=`%s' name=`%s' args=`%s'\n", + // root->type.data(),root->name.data(),root->args.data()); + } + else + { + int i=isFuncPtr; + if (i==-1) i=findFunctionPtr(root->type,root->lang); // for typedefs isFuncPtr is not yet set + Debug::print(Debug::Variables,0," functionPtr? %s\n",i!=-1?"yes":"no"); + if (i!=-1) // function pointer + { + int ai = root->type.find('[',i); + if (ai>i) // function pointer array + { + root->args.prepend(root->type.right(root->type.length()-ai)); + root->type=root->type.left(ai); + } + else if (root->type.find(')',i)!=-1) // function ptr, not variable like "int (*bla)[10]" + { + root->type=root->type.left(root->type.length()-1); + root->args.prepend(")"); + //printf("root->type=%s root->args=%s\n",root->type.data(),root->args.data()); + } + } + else if (root->type.find("typedef ")!=-1 && root->type.right(2)=="()") // typedef void (func)(int) + { + root->type=root->type.left(root->type.length()-1); + root->args.prepend(")"); + } + } + + QCString scope,name=removeRedundantWhiteSpace(root->name); + + // find the scope of this variable + EntryNav *p = rootNav->parent(); + while ((p->section() & Entry::SCOPE_MASK)) + { + QCString scopeName = p->name(); + if (!scopeName.isEmpty()) + { + scope.prepend(scopeName); + break; + } + p=p->parent(); + } + + MemberDef::MemberType mtype; + QCString type=root->type.stripWhiteSpace(); + ClassDef *cd=0; + bool isRelated=FALSE; + bool isMemberOf=FALSE; + + QCString classScope=stripAnonymousNamespaceScope(scope); + classScope=stripTemplateSpecifiersFromScope(classScope,FALSE); + QCString annScopePrefix=scope.left(scope.length()-classScope.length()); + + if (root->name.findRev("::")!=-1) + { + if (root->type=="friend class" || root->type=="friend struct" || + root->type=="friend union") + { + cd=getClass(scope); + if (cd) + { + addVariableToClass(rootNav, // entry + cd, // class to add member to + MemberDef::Friend, // type of member + name, // name of the member + FALSE, // from Anonymous scope + 0, // anonymous member + Public, // protection + Member // related to a class + ); + } + } + 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; + else if (type.left(8)=="typedef ") + mtype=MemberDef::Typedef; + else if (type.left(7)=="friend ") + mtype=MemberDef::Friend; + else if (root->mtype==Property) + mtype=MemberDef::Property; + else if (root->mtype==Event) + mtype=MemberDef::Event; + else + mtype=MemberDef::Variable; + + if (!root->relates.isEmpty()) // related variable + { + isRelated=TRUE; + isMemberOf=(root->relatesType == MemberOf); + if (getClass(root->relates)==0 && !scope.isEmpty()) + scope=mergeScopes(scope,root->relates); + else + scope=root->relates; + } + + cd=getClass(scope); + if (cd==0 && classScope!=scope) cd=getClass(classScope); + if (cd) + { + MemberDef *md=0; + + // if cd is an anonymous (=tag less) scope we insert the member + // into a non-anonymous parent scope as well. This is needed to + // be able to refer to it using \var or \fn + + //int indentDepth=0; + int si=scope.find('@'); + //int anonyScopes = 0; + //bool added=FALSE; + + static bool inlineSimpleStructs = Config_getBool("INLINE_SIMPLE_STRUCTS"); + if (si!=-1 && !inlineSimpleStructs) // anonymous scope or type + { + QCString pScope; + ClassDef *pcd=0; + pScope = scope.left(QMAX(si-2,0)); // scope without tag less parts + if (!pScope.isEmpty()) + pScope.prepend(annScopePrefix); + else if (annScopePrefix.length()>2) + pScope=annScopePrefix.left(annScopePrefix.length()-2); + if (name.at(0)!='@') + { + if (!pScope.isEmpty() && (pcd=getClass(pScope))) + { + md=addVariableToClass(rootNav, // entry + pcd, // class to add member to + mtype, // member type + name, // member name + TRUE, // from anonymous scope + 0, // from anonymous member + root->protection, + isMemberOf ? Foreign : isRelated ? Related : Member + ); + //added=TRUE; + } + else // anonymous scope inside namespace or file => put variable in the global scope + { + if (mtype==MemberDef::Variable) + { + md=addVariableToFile(rootNav,mtype,pScope,name,TRUE,0); + } + //added=TRUE; + } + } + } + + //printf("name=`%s' scope=%s scope.right=%s\n", + // name.data(),scope.data(), + // scope.right(scope.length()-si).data()); + addVariableToClass(rootNav, // entry + cd, // class to add member to + mtype, // member type + name, // name of the member + FALSE, // from anonymous scope + md, // from anonymous member + root->protection, + isMemberOf ? Foreign : isRelated ? Related : Member); + } + else if (!name.isEmpty()) // global variable + { + //printf("Inserting member in global scope %s!\n",scope.data()); + addVariableToFile(rootNav,mtype,scope,name,FALSE,/*0,*/0); + } + +nextMember: + rootNav->releaseEntry(); +} + +//---------------------------------------------------------------------- +// Searches the Entry tree for typedef documentation sections. +// If found they are stored in their class or in the global list. +static void buildTypedefList(EntryNav *rootNav) +{ + //printf("buildVarList(%s)\n",rootNav->name().data()); + if (!rootNav->name().isEmpty() && + rootNav->section()==Entry::VARIABLE_SEC && + rootNav->type().find("typedef ")!=-1 // its a typedef + ) + { + addVariable(rootNav); + } + if (rootNav->children()) + { + EntryNavListIterator eli(*rootNav->children()); + EntryNav *e; + for (;(e=eli.current());++eli) + { + if (e->section()!=Entry::ENUM_SEC) + { + buildTypedefList(e); + } + } + } +} + +//---------------------------------------------------------------------- +// Searches the Entry tree for Variable documentation sections. +// If found they are stored in their class or in the global list. + +static void buildVarList(EntryNav *rootNav) +{ + //printf("buildVarList(%s)\n",rootNav->name().data()); + int isFuncPtr=-1; + if (!rootNav->name().isEmpty() && + (rootNav->type().isEmpty() || g_compoundKeywordDict.find(rootNav->type())==0) && + ( + (rootNav->section()==Entry::VARIABLE_SEC // it's a variable + ) || + (rootNav->section()==Entry::FUNCTION_SEC && // or maybe a function pointer variable + (isFuncPtr=findFunctionPtr(rootNav->type(),rootNav->lang()))!=-1 + ) || + (rootNav->section()==Entry::FUNCTION_SEC && // class variable initialized by constructor + isVarWithConstructor(rootNav) + ) + ) + ) // documented variable + { + addVariable(rootNav,isFuncPtr); + } + if (rootNav->children()) + { + EntryNavListIterator eli(*rootNav->children()); + EntryNav *e; + for (;(e=eli.current());++eli) + { + if (e->section()!=Entry::ENUM_SEC) + { + buildVarList(e); + } + } + } +} + +//---------------------------------------------------------------------- +// Searches the Entry tree for Function sections. +// If found they are stored in their class or in the global list. + +static void addMethodToClass(EntryNav *rootNav,ClassDef *cd, + const QCString &rname,bool isFriend) +{ + Entry *root = rootNav->entry(); + FileDef *fd=rootNav->fileDef(); + + int l,i=-1; + static QRegExp re("([a-z_A-Z0-9: ]*[ &*]+[ ]*"); + + if (cd->getLanguage()==SrcLangExt_Cpp && // only C has pointers + !root->type.isEmpty() && (i=re.match(root->type,0,&l))!=-1) // function variable + { + root->args+=root->type.right(root->type.length()-i-l); + root->type=root->type.left(i+l); + } + + QCString name=removeRedundantWhiteSpace(rname); + if (name.left(2)=="::") name=name.right(name.length()-2); + + MemberDef::MemberType mtype; + if (isFriend) mtype=MemberDef::Friend; + else if (root->mtype==Signal) mtype=MemberDef::Signal; + else if (root->mtype==Slot) mtype=MemberDef::Slot; + else if (root->mtype==DCOP) mtype=MemberDef::DCOP; + else mtype=MemberDef::Function; + + // strip redundant template specifier for constructors + if ((fd==0 || fd->getLanguage()==SrcLangExt_Cpp) && + name.left(9)!="operator " && (i=name.find('<'))!=-1 && name.find('>')!=-1) + { + name=name.left(i); + } + + //printf("root->name=`%s; root->args=`%s' root->argList=`%s'\n", + // root->name.data(),root->args.data(),argListToString(root->argList).data() + // ); + + // adding class member + MemberDef *md=new MemberDef( + root->fileName,root->startLine, + root->type,name,root->args,root->exception, + root->protection,root->virt, + root->stat && root->relatesType != MemberOf, + root->relates.isEmpty() ? Member : + root->relatesType == MemberOf ? Foreign : Related, + mtype,root->tArgLists ? root->tArgLists->last() : 0,root->argList); + md->setTagInfo(rootNav->tagInfo()); + md->setMemberClass(cd); + md->setDocumentation(root->doc,root->docFile,root->docLine); + md->setDocsForDefinition(!root->proto); + md->setBriefDescription(root->brief,root->briefFile,root->briefLine); + md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine); + md->setBodySegment(root->bodyLine,root->endBodyLine); + md->setMemberSpecifiers(root->spec); + md->setMemberGroupId(root->mGrpId); + md->setTypeConstraints(root->typeConstr); + md->setLanguage(root->lang); + md->setBodyDef(fd); + md->setFileDef(fd); + //md->setScopeTemplateArguments(root->tArgList); + md->addSectionsToDefinition(root->anchors); + QCString def; + QCString qualScope = cd->qualifiedNameWithTemplateParameters(); + SrcLangExt lang = cd->getLanguage(); + QCString scopeSeparator=getLanguageSpecificSeparator(lang); + if (scopeSeparator!="::") + { + qualScope = substitute(qualScope,"::",scopeSeparator); + } + if (lang==SrcLangExt_PHP) + { + // for PHP we use Class::method and Namespace\method + scopeSeparator="::"; + } + if (!root->relates.isEmpty() || isFriend || Config_getBool("HIDE_SCOPE_NAMES")) + { + if (!root->type.isEmpty()) + { + if (root->argList) + { + def=root->type+" "+name; + } + else + { + def=root->type+" "+name+root->args; + } + } + else + { + if (root->argList) + { + def=name; + } + else + { + def=name+root->args; + } + } + } + else + { + if (!root->type.isEmpty()) + { + if (root->argList) + { + def=root->type+" "+qualScope+scopeSeparator+name; + } + else + { + def=root->type+" "+qualScope+scopeSeparator+name+root->args; + } + } + else + { + if (root->argList) + { + def=qualScope+scopeSeparator+name; + } + else + { + def=qualScope+scopeSeparator+name+root->args; + } + } + } + if (def.left(7)=="friend ") def=def.right(def.length()-7); + md->setDefinition(def); + md->enableCallGraph(root->callGraph); + md->enableCallerGraph(root->callerGraph); + + Debug::print(Debug::Functions,0, + " Func Member:\n" + " `%s' `%s'::`%s' `%s' proto=%d\n" + " def=`%s'\n", + root->type.data(), + qualScope.data(), + rname.data(), + root->args.data(), + root->proto, + def.data() + ); + + // 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::memberNameSDict->find(name))) + { + mn->append(md); + } + else + { + mn = new MemberName(name); + mn->append(md); + Doxygen::memberNameSDict->append(name,mn); + } + + // add member to the class cd + cd->insertMember(md); + // add file to list of used files + cd->insertUsedFile(root->fileName); + + addMemberToGroups(root,md); + rootNav->changeSection(Entry::EMPTY_SEC); + md->setRefItems(root->sli); +} + + +static void buildFunctionList(EntryNav *rootNav) +{ + if (rootNav->section()==Entry::FUNCTION_SEC) + { + rootNav->loadEntry(g_storage); + Entry *root = rootNav->entry(); + + Debug::print(Debug::Functions,0, + "FUNCTION_SEC:\n" + " `%s' `%s'::`%s' `%s' relates=`%s' relatesType=`%d' file=`%s' line=`%d' bodyLine=`%d' #tArgLists=%d mGrpId=%d spec=%d proto=%d docFile=%s\n", + root->type.data(), + rootNav->parent()->name().data(), + root->name.data(), + root->args.data(), + root->relates.data(), + root->relatesType, + root->fileName.data(), + root->startLine, + root->bodyLine, + root->tArgLists ? (int)root->tArgLists->count() : -1, + root->mGrpId, + root->spec, + root->proto, + root->docFile.data() + ); + + bool isFriend=root->type.find("friend ")!=-1; + QCString rname = removeRedundantWhiteSpace(root->name); + //printf("rname=%s\n",rname.data()); + + QCString scope=rootNav->parent()->name(); //stripAnonymousNamespaceScope(root->parent->name); + if (!rname.isEmpty() && scope.find('@')==-1) + { + ClassDef *cd=0; + // check if this function's parent is a class + scope=stripTemplateSpecifiersFromScope(scope,FALSE); + + FileDef *rfd=rootNav->fileDef(); + + int memIndex=rname.findRev("::"); + + cd=getClass(scope); + if (cd && scope+"::"==rname.left(scope.length()+2)) // found A::f inside A + { + // strip scope from name + rname=rname.right(rname.length()-rootNav->parent()->name().length()-2); + } + + NamespaceDef *nd = 0; + bool isMember=FALSE; + if (memIndex!=-1) + { + int ts=rname.find('<'); + int te=rname.find('>'); + if (memIndex>0 && (ts==-1 || te==-1)) + { + // note: the following code was replaced by inMember=TRUE to deal with a + // function rname='X::foo' of class X inside a namespace also called X... + // bug id 548175 + //nd = Doxygen::namespaceSDict->find(rname.left(memIndex)); + //isMember = nd==0; + //if (nd) + //{ + // // strip namespace scope from name + // scope=rname.left(memIndex); + // rname=rname.right(rname.length()-memIndex-2); + //} + isMember = TRUE; + } + else + { + isMember=memIndex<ts || memIndex>te; + } + } + + static QRegExp re("([a-z_A-Z0-9: ]*[ &*]+[ ]*"); + if (!rootNav->parent()->name().isEmpty() && + (rootNav->parent()->section() & Entry::COMPOUND_MASK) && + cd && + // do some fuzzy things to exclude function pointers + (root->type.isEmpty() || + (root->type.find(re,0)==-1 || root->args.find(")[")!=-1) || // type contains ..(..* and args not )[.. -> function pointer + root->type.find(")(")!=-1 || root->type.find("operator")!=-1 || // type contains ..)(.. and not "operator" + cd->getLanguage()!=SrcLangExt_Cpp // language other than C + ) + ) + { + Debug::print(Debug::Functions,0," --> member %s of class %s!\n", + rname.data(),cd->name().data()); + addMethodToClass(rootNav,cd,rname,isFriend); + } + else if (!((rootNav->parent()->section() & Entry::COMPOUND_MASK) + || rootNav->parent()->section()==Entry::OBJCIMPL_SEC + ) && + !isMember && + (root->relates.isEmpty() || root->relatesType == Duplicate) && + root->type.left(7)!="extern " && root->type.left(8)!="typedef " + ) + // no member => unrelated function + { + /* check the uniqueness of the function name in the file. + * A file could contain a function prototype and a function definition + * or even multiple function prototypes. + */ + bool found=FALSE; + MemberName *mn; + MemberDef *md=0; + if ((mn=Doxygen::functionNameSDict->find(rname))) + { + Debug::print(Debug::Functions,0," --> function %s already found!\n",rname.data()); + MemberNameIterator mni(*mn); + for (mni.toFirst();(!found && (md=mni.current()));++mni) + { + NamespaceDef *mnd = md->getNamespaceDef(); + NamespaceDef *rnd = 0; + //printf("root namespace=%s\n",rootNav->parent()->name().data()); + QCString fullScope = scope; + QCString parentScope = rootNav->parent()->name(); + if (!parentScope.isEmpty() && !leftScopeMatch(parentScope,scope)) + { + if (!scope.isEmpty()) fullScope.prepend("::"); + fullScope.prepend(parentScope); + } + //printf("fullScope=%s\n",fullScope.data()); + rnd = getResolvedNamespace(fullScope); + FileDef *mfd = md->getFileDef(); + QCString nsName,rnsName; + if (mnd) nsName = mnd->name().copy(); + if (rnd) rnsName = rnd->name().copy(); + //printf("matching arguments for %s%s %s%s\n", + // md->name().data(),md->argsString(),rname.data(),argListToString(root->argList).data()); + LockingPtr<ArgumentList> mdAl = md->argumentList(); + LockingPtr<ArgumentList> mdTempl = md->templateArguments(); + + // in case of template functions, we need to check if the + // functions have the same number of template parameters + bool sameNumTemplateArgs = TRUE; + if (mdTempl!=0 && root->tArgLists) + { + if (mdTempl->count()!=root->tArgLists->getLast()->count()) + { + sameNumTemplateArgs = FALSE; + } + } + if ( + matchArguments2(md->getOuterScope(),mfd,mdAl.pointer(), + rnd ? rnd : Doxygen::globalScope,rfd,root->argList, + FALSE) && + sameNumTemplateArgs + ) + { + GroupDef *gd=0; + if (root->groups->first()!=0) + { + gd = Doxygen::groupSDict->find(root->groups->first()->groupname.data()); + } + //printf("match!\n"); + //printf("mnd=%p rnd=%p nsName=%s rnsName=%s\n",mnd,rnd,nsName.data(),rnsName.data()); + // see if we need to create a new member + found=(mnd && rnd && nsName==rnsName) || // members are in the same namespace + ((mnd==0 && rnd==0 && mfd!=0 && // no external reference and + mfd->absFilePath()==root->fileName // prototype in the same file + ) + ); + // otherwise, allow a duplicate global member with the same argument list + if (!found && gd && gd==md->getGroupDef() && nsName==rnsName) + { + // member is already in the group, so we don't want to add it again. + found=TRUE; + } + + //printf("combining function with prototype found=%d in namespace %s\n", + // found,nsName.data()); + + if (found) + { + // merge argument lists + mergeArguments(mdAl.pointer(),root->argList,!root->doc.isEmpty()); + // merge documentation + if (md->documentation().isEmpty() && !root->doc.isEmpty()) + { + ArgumentList *argList = new ArgumentList; + stringToArgumentList(root->args,argList); + if (root->proto) + { + //printf("setDeclArgumentList to %p\n",argList); + md->setDeclArgumentList(argList); + } + else + { + md->setArgumentList(argList); + } + } + + md->setDocumentation(root->doc,root->docFile,root->docLine); + md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine); + md->setDocsForDefinition(!root->proto); + if (md->getStartBodyLine()!=-1 && md->getStartBodyLine()==-1) + { + md->setBodySegment(root->bodyLine,root->endBodyLine); + md->setBodyDef(rfd); + } + + if (md->briefDescription().isEmpty() && !root->brief.isEmpty()) + { + md->setArgsString(root->args); + } + md->setBriefDescription(root->brief,root->briefFile,root->briefLine); + + md->addSectionsToDefinition(root->anchors); + + md->enableCallGraph(md->hasCallGraph() || root->callGraph); + md->enableCallerGraph(md->hasCallerGraph() || root->callerGraph); + + // merge ingroup specifiers + if (md->getGroupDef()==0 && root->groups->first()!=0) + { + addMemberToGroups(root,md); + } + else if (md->getGroupDef()!=0 && root->groups->count()==0) + { + //printf("existing member is grouped, new member not\n"); + root->groups->append(new Grouping(md->getGroupDef()->name(), md->getGroupPri())); + } + else if (md->getGroupDef()!=0 && root->groups->first()!=0) + { + //printf("both members are grouped\n"); + } + + // if md is a declaration and root is the corresponding + // definition, then turn md into a definition. + if (md->isPrototype() && !root->proto) + { + md->setPrototype(FALSE); + } + } + } + } + } + if (!found) /* global function is unique with respect to the file */ + { + Debug::print(Debug::Functions,0," --> new function %s found!\n",rname.data()); + //printf("New function type=`%s' name=`%s' args=`%s' bodyLine=%d\n", + // root->type.data(),rname.data(),root->args.data(),root->bodyLine); + + // new global function + ArgumentList *tArgList = root->tArgLists ? root->tArgLists->last() : 0; + QCString name=removeRedundantWhiteSpace(rname); + md=new MemberDef( + root->fileName,root->startLine, + root->type,name,root->args,root->exception, + root->protection,root->virt,root->stat,Member, + MemberDef::Function,tArgList,root->argList); + + md->setTagInfo(rootNav->tagInfo()); + md->setLanguage(root->lang); + //md->setDefFile(root->fileName); + //md->setDefLine(root->startLine); + md->setDocumentation(root->doc,root->docFile,root->docLine); + md->setBriefDescription(root->brief,root->briefFile,root->briefLine); + md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine); + md->setPrototype(root->proto); + md->setDocsForDefinition(!root->proto); + md->setTypeConstraints(root->typeConstr); + //md->setBody(root->body); + md->setBodySegment(root->bodyLine,root->endBodyLine); + FileDef *fd=rootNav->fileDef(); + md->setBodyDef(fd); + md->addSectionsToDefinition(root->anchors); + md->setMemberSpecifiers(root->spec); + md->setMemberGroupId(root->mGrpId); + + // see if the function is inside a namespace that was not part of + // the name already (in that case nd should be non-zero already) + if (nd==0 && rootNav->parent()->section() == Entry::NAMESPACE_SEC ) + { + //QCString nscope=removeAnonymousScopes(rootNav->parent()->name()); + QCString nscope=rootNav->parent()->name(); + if (!nscope.isEmpty()) + { + nd = getResolvedNamespace(nscope); + } + } + + if (!scope.isEmpty()) + { + QCString sep = getLanguageSpecificSeparator(root->lang); + if (sep!="::") + { + scope = substitute(scope,"::",sep); + } + scope+=sep; + } + + QCString def; + if (!root->type.isEmpty()) + { + if (root->argList) + { + def=root->type+" "+scope+name; + } + else + { + def=root->type+" "+scope+name+root->args; + } + } + else + { + if (root->argList) + { + def=scope+name.copy(); + } + else + { + def=scope+name+root->args; + } + } + Debug::print(Debug::Functions,0, + " Global Function:\n" + " `%s' `%s'::`%s' `%s' proto=%d\n" + " def=`%s'\n", + root->type.data(), + rootNav->parent()->name().data(), + rname.data(), + root->args.data(), + root->proto, + def.data() + ); + md->setDefinition(def); + md->enableCallGraph(root->callGraph); + md->enableCallerGraph(root->callerGraph); + //if (root->mGrpId!=-1) + //{ + // md->setMemberGroup(memberGroupDict[root->mGrpId]); + //} + + md->setRefItems(root->sli); + if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@') + { + // add member to namespace + md->setNamespace(nd); + nd->insertMember(md); + } + if (fd) + { + // add member to the file (we do this even if we have already + // inserted it into the namespace) + md->setFileDef(fd); + fd->insertMember(md); + } + + // add member to the list of file members + //printf("Adding member=%s\n",md->name().data()); + MemberName *mn; + if ((mn=Doxygen::functionNameSDict->find(name))) + { + mn->append(md); + } + else + { + mn = new MemberName(name); + mn->append(md); + Doxygen::functionNameSDict->append(name,mn); + } + addMemberToGroups(root,md); + if (root->relatesType == Simple) // if this is a relatesalso command, + // allow find Member to pick it up + { + rootNav->changeSection(Entry::EMPTY_SEC); // Otherwise we have finished + // with this entry. + + } + } + else + { + FileDef *fd=rootNav->fileDef(); + if (fd) + { + // add member to the file (we do this even if we have already + // inserted it into the namespace) + fd->insertMember(md); + } + } + + //printf("unrelated function %d `%s' `%s' `%s'\n", + // root->parent->section,root->type.data(),rname.data(),root->args.data()); + } + else + { + Debug::print(Debug::Functions,0," --> %s not processed!\n",rname.data()); + } + } + else if (rname.isEmpty()) + { + warn(root->fileName,root->startLine, + "warning: Illegal member name found." + ); + } + + rootNav->releaseEntry(); + } + RECURSE_ENTRYTREE(buildFunctionList,rootNav); +} + +//---------------------------------------------------------------------- + +static void findFriends() +{ + //printf("findFriends()\n"); + MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict); + MemberName *fn; + for (;(fn=fnli.current());++fnli) // for each global function name + { + //printf("Function name=`%s'\n",fn->memberName()); + MemberName *mn; + if ((mn=Doxygen::memberNameSDict->find(fn->memberName()))) + { // there are members with the same name + //printf("Function name is also a member name\n"); + MemberNameIterator fni(*fn); + MemberDef *fmd; + for (;(fmd=fni.current());++fni) // for each function with that name + { + MemberNameIterator mni(*mn); + MemberDef *mmd; + for (;(mmd=mni.current());++mni) // for each member with that name + { + //printf("Checking for matching arguments + // mmd->isRelated()=%d mmd->isFriend()=%d mmd->isFunction()=%d\n", + // mmd->isRelated(),mmd->isFriend(),mmd->isFunction()); + LockingPtr<ArgumentList> mmdAl = mmd->argumentList(); + LockingPtr<ArgumentList> fmdAl = fmd->argumentList(); + if ((mmd->isFriend() || (mmd->isRelated() && mmd->isFunction())) && + matchArguments2(mmd->getOuterScope(), mmd->getFileDef(), mmdAl.pointer(), + fmd->getOuterScope(), fmd->getFileDef(), fmdAl.pointer(), + TRUE + ) + + ) // if the member is related and the arguments match then the + // function is actually a friend. + { + mergeArguments(mmdAl.pointer(),fmdAl.pointer()); + if (!fmd->documentation().isEmpty()) + { + mmd->setDocumentation(fmd->documentation(),fmd->docFile(),fmd->docLine()); + } + else if (!mmd->documentation().isEmpty()) + { + fmd->setDocumentation(mmd->documentation(),mmd->docFile(),mmd->docLine()); + } + if (mmd->briefDescription().isEmpty() && !fmd->briefDescription().isEmpty()) + { + mmd->setBriefDescription(fmd->briefDescription(),fmd->briefFile(),fmd->briefLine()); + } + else if (!mmd->briefDescription().isEmpty() && !fmd->briefDescription().isEmpty()) + { + fmd->setBriefDescription(mmd->briefDescription(),mmd->briefFile(),mmd->briefLine()); + } + if (!fmd->inbodyDocumentation().isEmpty()) + { + mmd->setInbodyDocumentation(fmd->inbodyDocumentation(),fmd->inbodyFile(),fmd->inbodyLine()); + } + else if (!mmd->inbodyDocumentation().isEmpty()) + { + fmd->setInbodyDocumentation(mmd->inbodyDocumentation(),mmd->inbodyFile(),mmd->inbodyLine()); + } + //printf("body mmd %d fmd %d\n",mmd->getStartBodyLine(),fmd->getStartBodyLine()); + if (mmd->getStartBodyLine()==-1 && fmd->getStartBodyLine()!=-1) + { + mmd->setBodySegment(fmd->getStartBodyLine(),fmd->getEndBodyLine()); + mmd->setBodyDef(fmd->getBodyDef()); + //mmd->setBodyMember(fmd); + } + else if (mmd->getStartBodyLine()!=-1 && fmd->getStartBodyLine()==-1) + { + fmd->setBodySegment(mmd->getStartBodyLine(),mmd->getEndBodyLine()); + fmd->setBodyDef(mmd->getBodyDef()); + //fmd->setBodyMember(mmd); + } + mmd->setDocsForDefinition(fmd->isDocsForDefinition()); + + mmd->enableCallGraph(mmd->hasCallGraph() || fmd->hasCallGraph()); + mmd->enableCallerGraph(mmd->hasCallerGraph() || fmd->hasCallerGraph()); + fmd->enableCallGraph(mmd->hasCallGraph() || fmd->hasCallGraph()); + fmd->enableCallerGraph(mmd->hasCallerGraph() || fmd->hasCallerGraph()); + } + } + } + } + } +} + +//---------------------------------------------------------------------- + +static void transferArgumentDocumentation(ArgumentList *decAl,ArgumentList *defAl) +{ + if (decAl && defAl) + { + ArgumentListIterator decAli(*decAl); + ArgumentListIterator defAli(*defAl); + Argument *decA,*defA; + for (decAli.toFirst(),defAli.toFirst(); + (decA=decAli.current()) && (defA=defAli.current()); + ++decAli,++defAli) + { + //printf("Argument decA->name=%s (doc=%s) defA->name=%s (doc=%s)\n", + // decA->name.data(),decA->docs.data(), + // defA->name.data(),defA->docs.data() + // ); + if (decA->docs.isEmpty() && !defA->docs.isEmpty()) + { + decA->docs = defA->docs.copy(); + } + else if (defA->docs.isEmpty() && !decA->docs.isEmpty()) + { + defA->docs = decA->docs.copy(); + } + } + } +} + +static void transferFunctionDocumentation() +{ + //printf("---- transferFunctionDocumentation()\n"); + + // find matching function declaration and definitions. + MemberNameSDict::Iterator mnli(*Doxygen::functionNameSDict); + MemberName *mn; + for (;(mn=mnli.current());++mnli) + { + //printf("memberName=%s count=%d\n",mn->memberName(),mn->count()); + MemberDef *mdef=0,*mdec=0; + MemberNameIterator mni1(*mn); + /* find a matching function declaration and definition for this function */ + for (;(mdec=mni1.current());++mni1) + { + //printf("mdec=%s isPrototype()=%d\n",mdec->name().data(),mdec->isPrototype()); + if (mdec->isPrototype() || + (mdec->isVariable() && mdec->isExternal()) + ) + { + MemberNameIterator mni2(*mn); + for (;(mdef=mni2.current());++mni2) + { + if ( + (mdef->isFunction() && !mdef->isStatic() && !mdef->isPrototype()) || + (mdef->isVariable() && !mdef->isExternal() && !mdef->isStatic()) + ) + { + //printf("mdef=(%p,%s) mdec=(%p,%s)\n", + // mdef, mdef ? mdef->name().data() : "", + // mdec, mdec ? mdec->name().data() : ""); + + LockingPtr<ArgumentList> mdefAl = mdef->argumentList(); + LockingPtr<ArgumentList> mdecAl = mdec->argumentList(); + if (matchArguments2(mdef->getOuterScope(),mdef->getFileDef(),mdefAl.pointer(), + mdec->getOuterScope(),mdec->getFileDef(),mdecAl.pointer(), + TRUE + ) + ) /* match found */ + { + //printf("Found member %s: definition in %s (doc=`%s') and declaration in %s (doc=`%s')\n", + // mn->memberName(), + // mdef->getFileDef()->name().data(),mdef->documentation().data(), + // mdec->getFileDef()->name().data(),mdec->documentation().data() + // ); + + // first merge argument documentation + transferArgumentDocumentation(mdecAl.pointer(),mdefAl.pointer()); + + /* copy documentation between function definition and declaration */ + if (!mdec->briefDescription().isEmpty()) + { + mdef->setBriefDescription(mdec->briefDescription(),mdec->briefFile(),mdec->briefLine()); + } + else if (!mdef->briefDescription().isEmpty()) + { + mdec->setBriefDescription(mdef->briefDescription(),mdef->briefFile(),mdef->briefLine()); + } + if (!mdef->documentation().isEmpty()) + { + //printf("transfering docs mdef->mdec (%s->%s)\n",mdef->argsString(),mdec->argsString()); + mdec->setDocumentation(mdef->documentation(),mdef->docFile(),mdef->docLine()); + mdec->setDocsForDefinition(mdef->isDocsForDefinition()); + if (mdefAl!=0) + { + ArgumentList *mdefAlComb = new ArgumentList; + stringToArgumentList(mdef->argsString(),mdefAlComb); + transferArgumentDocumentation(mdefAl.pointer(),mdefAlComb); + mdec->setArgumentList(mdefAlComb); + } + } + else if (!mdec->documentation().isEmpty()) + { + //printf("transfering docs mdec->mdef (%s->%s)\n",mdec->argsString(),mdef->argsString()); + mdef->setDocumentation(mdec->documentation(),mdec->docFile(),mdec->docLine()); + mdef->setDocsForDefinition(mdec->isDocsForDefinition()); + if (mdecAl!=0) + { + ArgumentList *mdecAlComb = new ArgumentList; + stringToArgumentList(mdec->argsString(),mdecAlComb); + transferArgumentDocumentation(mdecAl.pointer(),mdecAlComb); + mdef->setDeclArgumentList(mdecAlComb); + } + } + if (!mdef->inbodyDocumentation().isEmpty()) + { + mdec->setInbodyDocumentation(mdef->inbodyDocumentation(),mdef->inbodyFile(),mdef->inbodyLine()); + } + else if (!mdec->inbodyDocumentation().isEmpty()) + { + mdef->setInbodyDocumentation(mdec->inbodyDocumentation(),mdec->inbodyFile(),mdec->inbodyLine()); + } + if (mdec->getStartBodyLine()!=-1 && mdef->getStartBodyLine()==-1) + { + //printf("body mdec->mdef %d-%d\n",mdec->getStartBodyLine(),mdef->getEndBodyLine()); + mdef->setBodySegment(mdec->getStartBodyLine(),mdec->getEndBodyLine()); + mdef->setBodyDef(mdec->getBodyDef()); + //mdef->setBodyMember(mdec); + } + else if (mdef->getStartBodyLine()!=-1 && mdec->getStartBodyLine()==-1) + { + //printf("body mdef->mdec %d-%d\n",mdef->getStartBodyLine(),mdec->getEndBodyLine()); + mdec->setBodySegment(mdef->getStartBodyLine(),mdef->getEndBodyLine()); + mdec->setBodyDef(mdef->getBodyDef()); + //mdec->setBodyMember(mdef); + } + mdec->mergeMemberSpecifiers(mdef->getMemberSpecifiers()); + mdef->mergeMemberSpecifiers(mdec->getMemberSpecifiers()); + + + // copy group info. + if (mdec->getGroupDef()==0 && mdef->getGroupDef()!=0) + { + mdec->setGroupDef(mdef->getGroupDef(), + mdef->getGroupPri(), + mdef->docFile(), + mdef->docLine(), + mdef->hasDocumentation(), + mdef + ); + } + else if (mdef->getGroupDef()==0 && mdec->getGroupDef()!=0) + { + mdef->setGroupDef(mdec->getGroupDef(), + mdec->getGroupPri(), + mdec->docFile(), + mdec->docLine(), + mdec->hasDocumentation(), + mdec + ); + } + + + mdec->mergeRefItems(mdef); + mdef->mergeRefItems(mdec); + + mdef->setMemberDeclaration(mdec); + mdec->setMemberDefinition(mdef); + + mdef->enableCallGraph(mdec->hasCallGraph() || mdef->hasCallGraph()); + mdef->enableCallerGraph(mdec->hasCallerGraph() || mdef->hasCallerGraph()); + mdec->enableCallGraph(mdec->hasCallGraph() || mdef->hasCallGraph()); + mdec->enableCallerGraph(mdec->hasCallerGraph() || mdef->hasCallerGraph()); + } + } + } + } + } + } +} + +//---------------------------------------------------------------------- + +static void transferFunctionReferences() +{ + MemberNameSDict::Iterator mnli(*Doxygen::functionNameSDict); + MemberName *mn; + for (;(mn=mnli.current());++mnli) + { + MemberDef *md,*mdef=0,*mdec=0; + MemberNameIterator mni(*mn); + /* find a matching function declaration and definition for this function */ + for (;(md=mni.current());++mni) + { + if (md->isPrototype()) + mdec=md; + else if (md->isVariable() && md->isExternal()) + mdec=md; + + if (md->isFunction() && !md->isStatic() && !md->isPrototype()) + mdef=md; + else if (md->isVariable() && !md->isExternal() && !md->isStatic()) + mdef=md; + } + if (mdef && mdec) + { + LockingPtr<ArgumentList> mdefAl = mdef->argumentList(); + LockingPtr<ArgumentList> mdecAl = mdec->argumentList(); + if ( + matchArguments2(mdef->getOuterScope(),mdef->getFileDef(),mdefAl.pointer(), + mdec->getOuterScope(),mdec->getFileDef(),mdecAl.pointer(), + TRUE + ) + ) /* match found */ + { + LockingPtr<MemberSDict> defDict = mdef->getReferencesMembers(); + LockingPtr<MemberSDict> decDict = mdec->getReferencesMembers(); + if (defDict!=0) + { + MemberSDict::Iterator msdi(*defDict); + MemberDef *rmd; + for (msdi.toFirst();(rmd=msdi.current());++msdi) + { + if (decDict==0 || decDict->find(rmd->name())==0) + { + mdec->addSourceReferences(rmd); + } + } + } + if (decDict!=0) + { + MemberSDict::Iterator msdi(*decDict); + MemberDef *rmd; + for (msdi.toFirst();(rmd=msdi.current());++msdi) + { + if (defDict==0 || defDict->find(rmd->name())==0) + { + mdef->addSourceReferences(rmd); + } + } + } + + defDict = mdef->getReferencedByMembers(); + decDict = mdec->getReferencedByMembers(); + if (defDict!=0) + { + MemberSDict::Iterator msdi(*defDict); + MemberDef *rmd; + for (msdi.toFirst();(rmd=msdi.current());++msdi) + { + if (decDict==0 || decDict->find(rmd->name())==0) + { + mdec->addSourceReferencedBy(rmd); + } + } + } + if (decDict!=0) + { + MemberSDict::Iterator msdi(*decDict); + MemberDef *rmd; + for (msdi.toFirst();(rmd=msdi.current());++msdi) + { + if (defDict==0 || defDict->find(rmd->name())==0) + { + mdef->addSourceReferencedBy(rmd); + } + } + } + } + } + } +} + +//---------------------------------------------------------------------- + +static void transferRelatedFunctionDocumentation() +{ + // find match between function declaration and definition for + // related functions + MemberNameSDict::Iterator mnli(*Doxygen::functionNameSDict); + MemberName *mn; + for (mnli.toFirst();(mn=mnli.current());++mnli) + { + MemberDef *md; + MemberNameIterator mni(*mn); + /* find a matching function declaration and definition for this function */ + for (mni.toFirst();(md=mni.current());++mni) // for each global function + { + //printf(" Function `%s'\n",md->name().data()); + MemberName *rmn; + if ((rmn=Doxygen::memberNameSDict->find(md->name()))) // check if there is a member with the same name + { + //printf(" Member name found\n"); + MemberDef *rmd; + MemberNameIterator rmni(*rmn); + for (rmni.toFirst();(rmd=rmni.current());++rmni) // for each member with the same name + { + LockingPtr<ArgumentList> mdAl = md->argumentList(); + LockingPtr<ArgumentList> rmdAl = rmd->argumentList(); + //printf(" Member found: related=`%d'\n",rmd->isRelated()); + if ((rmd->isRelated() || rmd->isForeign()) && // related function + matchArguments2( md->getOuterScope(), md->getFileDef(), mdAl.pointer(), + rmd->getOuterScope(),rmd->getFileDef(),rmdAl.pointer(), + TRUE + ) + ) + { + //printf(" Found related member `%s'\n",md->name().data()); + if (rmd->relatedAlso()) + md->setRelatedAlso(rmd->relatedAlso()); + else if (rmd->isForeign()) + md->makeForeign(); + else + md->makeRelated(); + } + } + } + } + } +} + +//---------------------------------------------------------------------- + +/*! 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; +} + +/*! Searches a class from within \a context and \a cd and returns its + * definition if found (otherwise 0 is returned). + */ +static ClassDef *findClassWithinClassContext(Definition *context,ClassDef *cd,const QCString &name) +{ + FileDef *fd=cd->getFileDef(); + ClassDef *result=0; + if (context && cd!=context) + { + result = getResolvedClass(context,0,name,0,0,TRUE,TRUE); + } + if (result==0) + { + result = getResolvedClass(cd,fd,name,0,0,TRUE,TRUE); + } + if (result==0) // try direct class, needed for namespaced classes imported via tag files (see bug624095) + { + result = getClass(name); + } + //printf("** Trying to find %s within context %s class %s result=%s lookup=%p\n", + // name.data(), + // context ? context->name().data() : "<none>", + // cd ? cd->name().data() : "<none>", + // result ? result->name().data() : "<none>", + // Doxygen::classSDict.find(name) + // ); + return result; +} + +enum FindBaseClassRelation_Mode +{ + TemplateInstances, + DocumentedOnly, + Undocumented +}; + +static bool findClassRelation( + EntryNav *rootNav, + Definition *context, + ClassDef *cd, + BaseInfo *bi, + QDict<int> *templateNames, + /*bool insertUndocumented*/ + FindBaseClassRelation_Mode mode, + bool isArtificial + ); + + +static void findUsedClassesForClass(EntryNav *rootNav, + Definition *context, + ClassDef *masterCd, + ClassDef *instanceCd, + bool isArtificial, + ArgumentList *actualArgs=0, + QDict<int> *templateNames=0 + ) +{ + masterCd->visited=TRUE; + ArgumentList *formalArgs = masterCd->templateArguments(); + if (masterCd->memberNameInfoSDict()) + { + 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() || md->isObjCProperty()) // for each member variable in this class + { + //printf(" Found variable %s in class %s\n",md->name().data(),masterCd->name().data()); + QCString type=removeRedundantWhiteSpace(md->typeString()); + QCString typedefValue = resolveTypeDef(masterCd,type); + if (!typedefValue.isEmpty()) + { + type = typedefValue; + } + int pos=0; + QCString usedClassName; + QCString templSpec; + bool found=FALSE; + // the type can contain template variables, replace them if present + if (actualArgs) + { + type = substituteTemplateArgumentsInString(type,formalArgs,actualArgs); + } + + //printf(" template substitution gives=%s\n",type.data()); + while (!found && extractClassNameFromType(type,pos,usedClassName,templSpec,rootNav->lang())!=-1) + { + // find the type (if any) that matches usedClassName + ClassDef *typeCd = getResolvedClass(masterCd, + masterCd->getFileDef(), + usedClassName, + 0,0, + FALSE,TRUE + ); + //printf("====> usedClassName=%s -> typeCd=%s\n", + // usedClassName.data(),typeCd?typeCd->name().data():"<none>"); + if (typeCd) + { + usedClassName = typeCd->name(); + } + + int sp=usedClassName.find('<'); + if (sp==-1) sp=0; + int si=usedClassName.findRev("::",sp); + if (si!=-1) + { + // replace any namespace aliases + replaceNamespaceAliases(usedClassName,si); + } + // add any template arguments to the class + QCString usedName = removeRedundantWhiteSpace(usedClassName+templSpec); + //printf(" usedName=%s\n",usedName.data()); + + bool delTempNames=FALSE; + if (templateNames==0) + { + templateNames = getTemplateArgumentsInName(formalArgs,usedName); + delTempNames=TRUE; + } + BaseInfo bi(usedName,Public,Normal); + findClassRelation(rootNav,context,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); + //printf("making %s a template argument!!!\n",usedCd->name().data()); + usedCd->makeTemplateArgument(); + usedCd->setUsedOnly(TRUE); + usedCd->setLanguage(masterCd->getLanguage()); + Doxygen::hiddenClasses->append(usedName,usedCd); + } + if (usedCd) + { + if (isArtificial) usedCd->setArtificial(TRUE); + Debug::print(Debug::Classes,0," Adding used class `%s' (1)\n", usedCd->name().data()); + instanceCd->addUsedClass(usedCd,md->name(),md->protection()); + usedCd->addUsedByClass(instanceCd,md->name(),md->protection()); + } + } + } + } + + if (!found) + { + ClassDef *usedCd=findClassWithinClassContext(context,masterCd,usedName); + //printf("Looking for used class %s: result=%s master=%s\n", + // usedName.data(),usedCd?usedCd->name().data():"<none>",masterCd?masterCd->name().data():"<none>"); + + if (usedCd) + { + found=TRUE; + Debug::print(Debug::Classes,0," Adding used class `%s' (2)\n", usedCd->name().data()); + instanceCd->addUsedClass(usedCd,md->name(),md->protection()); // class exists + usedCd->addUsedByClass(instanceCd,md->name(),md->protection()); + } + } + if (delTempNames) + { + delete templateNames; + templateNames=0; + } + } + if (!found && !type.isEmpty()) // used class is not documented in any scope + { + ClassDef *usedCd = Doxygen::hiddenClasses->find(type); + if (usedCd==0 && !Config_getBool("HIDE_UNDOC_RELATIONS")) + { + if (type.right(2)=="(*" || type.right(2)=="(^") // type is a function pointer + { + type+=md->argsString(); + } + Debug::print(Debug::Classes,0," New undocumented used class `%s'\n", type.data()); + usedCd = new ClassDef( + masterCd->getDefFileName(),masterCd->getDefLine(), + type,ClassDef::Class); + usedCd->setUsedOnly(TRUE); + usedCd->setLanguage(masterCd->getLanguage()); + Doxygen::hiddenClasses->append(type,usedCd); + } + if (usedCd) + { + if (isArtificial) usedCd->setArtificial(TRUE); + Debug::print(Debug::Classes,0," Adding used class `%s' (3)\n", usedCd->name().data()); + instanceCd->addUsedClass(usedCd,md->name(),md->protection()); + usedCd->addUsedByClass(instanceCd,md->name(),md->protection()); + } + } + } + } + } + } + else + { + //printf("no members for class %s (%p)\n",masterCd->name().data(),masterCd); + } +} + +static void findBaseClassesForClass( + EntryNav *rootNav, + Definition *context, + ClassDef *masterCd, + ClassDef *instanceCd, + FindBaseClassRelation_Mode mode, + bool isArtificial, + ArgumentList *actualArgs=0, + QDict<int> *templateNames=0 + ) +{ + Entry *root = rootNav->entry(); + //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) + { + //printf("masterCd=%s bi->name='%s' #actualArgs=%d\n", + // masterCd->localName().data(),bi->name.data(),actualArgs?(int)actualArgs->count():-1); + 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); + } + //printf("bi->name=%s tbi.name=%s\n",bi->name.data(),tbi.name.data()); + + if (mode==DocumentedOnly) + { + // find a documented base class in the correct scope + if (!findClassRelation(rootNav,context,instanceCd,&tbi,templateNames,DocumentedOnly,isArtificial)) + { + if (!Config_getBool("HIDE_UNDOC_RELATIONS")) + { + // no documented base class -> try to find an undocumented one + findClassRelation(rootNav,context,instanceCd,&tbi,templateNames,Undocumented,isArtificial); + } + } + } + else if (mode==TemplateInstances) + { + findClassRelation(rootNav,context,instanceCd,&tbi,templateNames,TemplateInstances,isArtificial); + } + if (delTempNames) + { + delete templateNames; + templateNames=0; + } + } +} + +//---------------------------------------------------------------------- + +static bool findTemplateInstanceRelation(Entry *root, + Definition *context, + 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(),*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->setArtificial(TRUE); + instanceClass->setLanguage(root->lang); + + if (freshInstance) + { + Debug::print(Debug::Classes,0," found fresh instance '%s'!\n",instanceClass->name().data()); + Doxygen::classSDict->append(instanceClass->name(),instanceClass); + instanceClass->setTemplateBaseClassNames(templateNames); + + // search for new template instances caused by base classes of + // instanceClass + EntryNav *templateRootNav = g_classEntries.find(templateClass->name()); + if (templateRootNav) + { + bool unloadNeeded=FALSE; + Entry *templateRoot = templateRootNav->entry(); + if (templateRoot==0) // not yet loaded + { + templateRootNav->loadEntry(g_storage); + templateRoot = templateRootNav->entry(); + ASSERT(templateRoot!=0); // now it should really be loaded + unloadNeeded=TRUE; + } + + Debug::print(Debug::Classes,0," template root found %s templSpec=%s!\n", + templateRoot->name.data(),templSpec.data()); + ArgumentList *templArgs = new ArgumentList; + stringToArgumentList(templSpec,templArgs); + findBaseClassesForClass(templateRootNav,context,templateClass,instanceClass, + TemplateInstances,isArtificial,templArgs,templateNames); + + findUsedClassesForClass(templateRootNav,context,templateClass,instanceClass, + isArtificial,templArgs,templateNames); + delete templArgs; + + if (unloadNeeded) // still cleanup to do + { + templateRootNav->releaseEntry(); + } + } + else + { + Debug::print(Debug::Classes,0," no template root entry found!\n"); + // TODO: what happened if we get here? + } + + //Debug::print(Debug::Classes,0," Template instance %s : \n",instanceClass->name().data()); + //ArgumentList *tl = templateClass->templateArguments(); + } + else + { + Debug::print(Debug::Classes,0," instance already exists!\n"); + } + return TRUE; +} + +static bool isRecursiveBaseClass(const QCString &scope,const QCString &name) +{ + QCString n=name; + int index=n.find('<'); + if (index!=-1) + { + n=n.left(index); + } + bool result = rightScopeMatch(scope,n); + return result; +} + +/*! Searches for the end of a template in prototype \a s starting from + * character position \a startPos. If the end was found the position + * of the closing \> is returned, otherwise -1 is returned. + * + * Handles exotic cases such as + * \code + * Class<(id<0)> + * Class<bits<<2> + * Class<"<"> + * Class<'<'> + * Class<(")<")> + * \endcode + */ +static int findEndOfTemplate(const QCString &s,int startPos) +{ + // locate end of template + int e=startPos; + int brCount=1; + int roundCount=0; + int len = s.length(); + bool insideString=FALSE; + bool insideChar=FALSE; + char pc = 0; + while (e<len && brCount!=0) + { + char c=s.at(e); + switch(c) + { + case '<': + if (!insideString && !insideChar) + { + if (e<len-1 && s.at(e+1)=='<') + e++; + else if (roundCount==0) + brCount++; + } + break; + case '>': + if (!insideString && !insideChar) + { + if (e<len-1 && s.at(e+1)=='>') + e++; + else if (roundCount==0) + brCount--; + } + break; + case '(': + if (!insideString && !insideChar) + roundCount++; + break; + case ')': + if (!insideString && !insideChar) + roundCount--; + break; + case '"': + if (!insideChar) + { + if (insideString && pc!='\\') + insideString=FALSE; + else + insideString=TRUE; + } + break; + case '\'': + if (!insideString) + { + if (insideChar && pc!='\\') + insideChar=FALSE; + else + insideChar=TRUE; + } + break; + } + pc = c; + e++; + } + return brCount==0 ? e : -1; +} + +static bool findClassRelation( + EntryNav *rootNav, + Definition *context, + 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(),*tempArgIndex); + // } + //} + //printf("\n"); + + Entry *root = rootNav->entry(); + + QCString biName=bi->name; + bool explicitGlobalScope=FALSE; + //printf("findClassRelation: biName=`%s'\n",biName.data()); + if (biName.left(2)=="::") // explicit global scope + { + biName=biName.right(biName.length()-2); + explicitGlobalScope=TRUE; + } + + EntryNav *parentNode=rootNav->parent(); + bool lastParent=FALSE; + do // for each parent scope, starting with the largest scope + // (in case of nested classes) + { + QCString scopeName= parentNode ? parentNode->name().data() : ""; + int scopeOffset=explicitGlobalScope ? 0 : scopeName.length(); + do // try all parent scope prefixes, starting with the largest scope + { + //printf("scopePrefix=`%s' biName=`%s'\n", + // scopeName.left(scopeOffset).data(),biName.data()); + + QCString baseClassName=biName; + if (scopeOffset>0) + { + baseClassName.prepend(scopeName.left(scopeOffset)+"::"); + } + //QCString stripped; + //baseClassName=stripTemplateSpecifiersFromScope + // (removeRedundantWhiteSpace(baseClassName),TRUE, + // &stripped); + MemberDef *baseClassTypeDef=0; + QCString templSpec; + ClassDef *baseClass=getResolvedClass(explicitGlobalScope ? Doxygen::globalScope : context, + cd->getFileDef(), + baseClassName, + &baseClassTypeDef, + &templSpec, + mode==Undocumented, + TRUE + ); + //printf("baseClassName=%s baseClass=%p cd=%p explicitGlobalScope=%d\n", + // baseClassName.data(),baseClass,cd,explicitGlobalScope); + //printf(" scope=`%s' baseClassName=`%s' baseClass=%s templSpec=%s\n", + // cd ? cd->name().data():"<none>", + // baseClassName.data(), + // baseClass?baseClass->name().data():"<none>", + // templSpec.data() + // ); + //if (baseClassName.left(root->name.length())!=root->name || + // baseClassName.at(root->name.length())!='<' + // ) // Check for base class with the same name. + // // If found then look in the outer scope for a match + // // and prevent recursion. + if (!isRecursiveBaseClass(rootNav->name(),baseClassName) || explicitGlobalScope) + { + Debug::print( + Debug::Classes,0," class relation %s inherited/used by %s found (%s and %s) templSpec='%s'\n", + baseClassName.data(), + rootNav->name().data(), + (bi->prot==Private)?"private":((bi->prot==Protected)?"protected":"public"), + (bi->virt==Normal)?"normal":"virtual", + templSpec.data() + ); + + int i=baseClassName.find('<'); + int si=baseClassName.findRev("::",i==-1 ? baseClassName.length() : i); + if (si==-1) si=0; + if (baseClass==0 && i!=-1) + // base class has template specifiers + { + // TODO: here we should try to find the correct template specialization + // but for now, we only look for the unspecializated base class. + int e=findEndOfTemplate(baseClassName,i+1); + //printf("baseClass==0 i=%d e=%d\n",i,e); + if (e!=-1) // end of template was found at e + { + templSpec=removeRedundantWhiteSpace(baseClassName.mid(i,e-i)); + baseClassName=baseClassName.left(i)+baseClassName.right(baseClassName.length()-e); + baseClass=getResolvedClass(explicitGlobalScope ? Doxygen::globalScope : context, + cd->getFileDef(), + baseClassName, + &baseClassTypeDef, + 0, //&templSpec, + mode==Undocumented, + TRUE + ); + //printf("baseClass=%p -> baseClass=%s templSpec=%s\n", + // baseClass,baseClassName.data(),templSpec.data()); + } + } + else if (baseClass && !templSpec.isEmpty()) // we have a known class, but also + // know it is a template, so see if + // we can also link to the explicit + // instance (for instance if a class + // derived from a template argument) + { + //printf("baseClass=%p templSpec=%s\n",baseClass,templSpec.data()); + ClassDef *templClass=getClass(baseClass->name()+templSpec); + if (templClass) + { + // use the template instance instead of the template base. + baseClass = templClass; + templSpec.resize(0); + } + } + + //printf("cd=%p baseClass=%p\n",cd,baseClass); + bool found=baseClass!=0 && (baseClass!=cd || mode==TemplateInstances); + //printf("1. found=%d\n",found); + if (!found && si!=-1) + { + QCString tmpTemplSpec; + // replace any namespace aliases + replaceNamespaceAliases(baseClassName,si); + baseClass=getResolvedClass(explicitGlobalScope ? Doxygen::globalScope : context, + cd->getFileDef(), + baseClassName, + &baseClassTypeDef, + &tmpTemplSpec, + mode==Undocumented, + TRUE + ); + found=baseClass!=0 && baseClass!=cd; + if (found) templSpec = tmpTemplSpec; + } + //printf("2. found=%d\n",found); + + //printf("root->name=%s biName=%s baseClassName=%s\n", + // root->name.data(),biName.data(),baseClassName.data()); + if (cd->isCSharp() && i!=-1) // C# generic -> add internal -g postfix + { + baseClassName+="-g"; + //templSpec.resize(0); + } + + if (!found) + { + baseClass=findClassWithinClassContext(context,cd,baseClassName); + //printf("findClassWithinClassContext(%s,%s)=%p\n", + // cd->name().data(),baseClassName.data(),baseClass); + found = baseClass!=0 && baseClass!=cd; + + } + if (!found) + { + // for PHP the "use A\B as C" construct map class C to A::B, so we lookup + // the class name also in the alias mapping. + QCString *aliasName = Doxygen::namespaceAliasDict[baseClassName]; + if (aliasName) // see if it is indeed a class. + { + baseClass=getClass(*aliasName); + found = baseClass!=0 && baseClass!=cd; + } + } + bool isATemplateArgument = templateNames!=0 && templateNames->find(biName)!=0; + // make templSpec canonical + // warning: the following line doesn't work for Mixin classes (see bug 560623) + // templSpec = getCanonicalTemplateSpec(cd, cd->getFileDef(), templSpec); + + //printf("3. found=%d\n",found); + if (found) + { + Debug::print(Debug::Classes,0," Documented base class `%s' templSpec=%s\n",biName.data(),templSpec.isEmpty()?"":templSpec.data()); + // add base class to this class + + // 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) + { + // if baseClass is actually a typedef then we should not + // instantiate it, since typedefs are in a different namespace + // see bug531637 for an example where this would otherwise hang + // doxygen + if (baseClassTypeDef==0) + { + //printf(" => findTemplateInstanceRelation: %p\n",baseClassTypeDef); + findTemplateInstanceRelation(root,context,baseClass,templSpec,templateNames,isArtificial); + } + } + else if (mode==DocumentedOnly || mode==Undocumented) + { + //printf(" => insert base class\n"); + QCString usedName; + if (baseClassTypeDef || cd->isCSharp()) + { + usedName=biName; + //printf("***** usedName=%s templSpec=%s\n",usedName.data(),templSpec.data()); + } + if (Config_getBool("SIP_SUPPORT")) bi->prot=Public; + 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 (mode==Undocumented && (scopeOffset==0 || isATemplateArgument)) + { + Debug::print(Debug::Classes,0, + " New undocumented base class `%s' baseClassName=%s templSpec=%s isArtificial=%d\n", + biName.data(),baseClassName.data(),templSpec.data(),isArtificial + ); + baseClass=0; + if (isATemplateArgument) + { + baseClass=Doxygen::hiddenClasses->find(baseClassName); + if (baseClass==0) + { + baseClass=new ClassDef(root->fileName,root->startLine, + baseClassName,ClassDef::Class); + Doxygen::hiddenClasses->append(baseClassName,baseClass); + if (isArtificial) baseClass->setArtificial(TRUE); + baseClass->setLanguage(root->lang); + } + } + else + { + baseClass=Doxygen::classSDict->find(baseClassName); + //printf("*** classDDict->find(%s)=%p biName=%s templSpec=%s\n", + // baseClassName.data(),baseClass,biName.data(),templSpec.data()); + if (baseClass==0) + { + baseClass=new ClassDef(root->fileName,root->startLine, + baseClassName,ClassDef::Class); + Doxygen::classSDict->append(baseClassName,baseClass); + if (isArtificial) baseClass->setArtificial(TRUE); + baseClass->setLanguage(root->lang); + } + } + // add base class to this class + cd->insertBaseClass(baseClass,biName,bi->prot,bi->virt,templSpec); + // add this class as super class to the base class + baseClass->insertSubClass(cd,bi->prot,bi->virt,templSpec); + // the undocumented base was found in this file + baseClass->insertUsedFile(root->fileName); + baseClass->setOuterScope(Doxygen::globalScope); + return TRUE; + } + else + { + Debug::print(Debug::Classes,0," Base class `%s' not found\n",biName.data()); + } + } + else + { + if (mode!=TemplateInstances) + { + warn(root->fileName,root->startLine, + "Detected potential recursive class relation " + "between class %s and base class %s!\n", + root->name.data(),baseClassName.data() + ); + } + // for mode==TemplateInstance this case is quite common and + // indicates a relation between a template class and a template + // instance with the same name. + } + if (scopeOffset==0) + { + scopeOffset=-1; + } + else if ((scopeOffset=scopeName.findRev("::",scopeOffset-1))==-1) + { + scopeOffset=0; + } + //printf("new scopeOffset=`%d'",scopeOffset); + } while (scopeOffset>=0); + + if (parentNode==0) + { + lastParent=TRUE; + } + else + { + parentNode=parentNode->parent(); + } + } while (lastParent); + + return FALSE; +} + +//---------------------------------------------------------------------- +// Computes the base and super classes for each class in the tree + +static bool isClassSection(EntryNav *rootNav) +{ + if ( !rootNav->name().isEmpty() ) + { + if (rootNav->section() & Entry::COMPOUND_MASK) + // is it a compound (class, struct, union, interface ...) + { + return TRUE; + } + else if (rootNav->section() & Entry::COMPOUNDDOC_MASK) + // is it a documentation block with inheritance info. + { + rootNav->loadEntry(g_storage); + Entry *root = rootNav->entry(); + bool extends = root->extends->count()>0; + rootNav->releaseEntry(); + if (extends) return TRUE; + } + } + return FALSE; +} + + +/*! Builds a dictionary of all entry nodes in the tree starting with \a root + */ +static void findClassEntries(EntryNav *rootNav) +{ + if (isClassSection(rootNav)) + { + g_classEntries.insert(rootNav->name(),rootNav); + } + RECURSE_ENTRYTREE(findClassEntries,rootNav); +} + +/*! 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<EntryNav> edi(g_classEntries); + EntryNav *rootNav; + for (;(rootNav=edi.current());++edi) + { + ClassDef *cd; + // strip any anonymous scopes first + QCString bName=stripAnonymousNamespaceScope(rootNav->name()); + bName=stripTemplateSpecifiersFromScope(bName); + Debug::print(Debug::Classes,0," Inheritance: Class %s : \n",bName.data()); + if ((cd=getClass(bName))) + { + rootNav->loadEntry(g_storage); + //printf("Class %s %d\n",cd->name().data(),root->extends->count()); + findBaseClassesForClass(rootNav,cd,cd,cd,TemplateInstances,FALSE); + rootNav->releaseEntry(); + } + } +} + +static void findUsedTemplateInstances() +{ + ClassSDict::Iterator cli(*Doxygen::classSDict); + for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE; + QDictIterator<EntryNav> edi(g_classEntries); + EntryNav *rootNav; + for (;(rootNav=edi.current());++edi) + { + ClassDef *cd; + // strip any anonymous scopes first + QCString bName=stripAnonymousNamespaceScope(rootNav->name()); + bName=stripTemplateSpecifiersFromScope(bName); + Debug::print(Debug::Classes,0," Usage: Class %s : \n",bName.data()); + if ((cd=getClass(bName))) + { + rootNav->loadEntry(g_storage); + findUsedClassesForClass(rootNav,cd,cd,cd,TRUE); + rootNav->releaseEntry(); + } + } +} + +static void computeClassRelations() +{ + ClassSDict::Iterator cli(*Doxygen::classSDict); + for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE; + QDictIterator<EntryNav> edi(g_classEntries); + EntryNav *rootNav; + for (;(rootNav=edi.current());++edi) + { + ClassDef *cd; + + rootNav->loadEntry(g_storage); + Entry *root = rootNav->entry(); + + // strip any anonymous scopes first + QCString bName=stripAnonymousNamespaceScope(rootNav->name()); + bName=stripTemplateSpecifiersFromScope(bName); + Debug::print(Debug::Classes,0," Relations: Class %s : \n",bName.data()); + if ((cd=getClass(bName))) + { + findBaseClassesForClass(rootNav,cd,cd,cd,DocumentedOnly,FALSE); + } + if ((cd==0 || (!cd->hasDocumentation() && !cd->isReference())) && + bName.right(2)!="::") + { + if (!root->name.isEmpty() && root->name.find('@')==-1 && // normal name + (guessSection(root->fileName)==Entry::HEADER_SEC || + Config_getBool("EXTRACT_LOCAL_CLASSES")) && // not defined in source file + protectionLevelVisible(root->protection) && // hidden by protection + !Config_getBool("HIDE_UNDOC_CLASSES") // undocumented class are visible + ) + warn_undoc( + root->fileName,root->startLine, + "warning: Compound %s is not documented.", + root->name.data() + ); + } + + rootNav->releaseEntry(); + } +} + +static void computeTemplateClassRelations() +{ + QDictIterator<EntryNav> edi(g_classEntries); + EntryNav *rootNav; + for (;(rootNav=edi.current());++edi) + { + rootNav->loadEntry(g_storage); + Entry *root = rootNav->entry(); + + QCString bName=stripAnonymousNamespaceScope(root->name); + bName=stripTemplateSpecifiersFromScope(bName); + ClassDef *cd=getClass(bName); + // strip any anonymous 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 + { + Debug::print(Debug::Classes,0," Template instance %s : \n",tcd->name().data()); + QCString templSpec = tdi.currentKey(); + 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 + { + // check if the base class is a template argument + BaseInfo tbi(bi->name,bi->prot,bi->virt); + 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) + { + int templIndex = *qdi.current(); + Argument *actArg = 0; + if (templIndex<(int)templArgs->count()) + { + 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 (!findClassRelation(rootNav,cd,tcd,&tbi,actualTemplateNames,DocumentedOnly,FALSE)) + { + // no documented base class -> try to find an undocumented one + findClassRelation(rootNav,cd,tcd,&tbi,actualTemplateNames,Undocumented,FALSE); + } + delete actualTemplateNames; + } + bi=baseList->next(); + } + delete templArgs; + } // class has no base classes + } + + rootNav->releaseEntry(); + } +} + +//----------------------------------------------------------------------- +// compute the references (anchors in HTML) for each function in the file + +static void computeMemberReferences() +{ + ClassSDict::Iterator cli(*Doxygen::classSDict); + ClassDef *cd=0; + for (cli.toFirst();(cd=cli.current());++cli) + { + cd->computeAnchors(); + } + FileName *fn=Doxygen::inputNameList->first(); + while (fn) + { + FileDef *fd=fn->first(); + while (fd) + { + fd->computeAnchors(); + fd=fn->next(); + } + fn=Doxygen::inputNameList->next(); + } + NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict); + NamespaceDef *nd=0; + for (nli.toFirst();(nd=nli.current());++nli) + { + nd->computeAnchors(); + } + GroupSDict::Iterator gli(*Doxygen::groupSDict); + GroupDef *gd; + for (gli.toFirst();(gd=gli.current());++gli) + { + gd->computeAnchors(); + } +} + +//---------------------------------------------------------------------- + +static void addListReferences() +{ + MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict); + MemberName *mn=0; + for (mnli.toFirst();(mn=mnli.current());++mnli) + { + MemberNameIterator mni(*mn); + MemberDef *md=0; + for (mni.toFirst();(md=mni.current());++mni) + { + md->visited=FALSE; + } + } + MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict); + for (fnli.toFirst();(mn=fnli.current());++fnli) + { + MemberNameIterator mni(*mn); + MemberDef *md=0; + for (mni.toFirst();(md=mni.current());++mni) + { + md->visited=FALSE; + } + } + + ClassSDict::Iterator cli(*Doxygen::classSDict); + ClassDef *cd=0; + for (cli.toFirst();(cd=cli.current());++cli) + { + cd->addListReferences(); + } + FileName *fn=Doxygen::inputNameList->first(); + while (fn) + { + FileDef *fd=fn->first(); + while (fd) + { + fd->addListReferences(); + fd=fn->next(); + } + fn=Doxygen::inputNameList->next(); + } + NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict); + NamespaceDef *nd=0; + for (nli.toFirst();(nd=nli.current());++nli) + { + nd->addListReferences(); + } + GroupSDict::Iterator gli(*Doxygen::groupSDict); + GroupDef *gd; + for (gli.toFirst();(gd=gli.current());++gli) + { + gd->addListReferences(); + } + PageSDict::Iterator pdi(*Doxygen::pageSDict); + PageDef *pd=0; + for (pdi.toFirst();(pd=pdi.current());++pdi) + { + QCString name = pd->getOutputFileBase(); + if (pd->getGroupDef()) + { + name = pd->getGroupDef()->getOutputFileBase(); + } + { + LockingPtr< QList<ListItemInfo> > xrefItems = pd->xrefListItems(); + addRefItem(xrefItems.pointer(), + name, + theTranslator->trPage(TRUE,TRUE), + name,pd->title(),0); + } + } + DirSDict::Iterator ddi(*Doxygen::directories); + DirDef *dd = 0; + for (ddi.toFirst();(dd=ddi.current());++ddi) + { + QCString name = dd->getOutputFileBase(); + //if (dd->getGroupDef()) + //{ + // name = dd->getGroupDef()->getOutputFileBase(); + //} + LockingPtr< QList<ListItemInfo> > xrefItems = dd->xrefListItems(); + addRefItem(xrefItems.pointer(), + name, + theTranslator->trDir(TRUE,TRUE), + name,dd->displayName(),0); + } +} + +//---------------------------------------------------------------------- + +static void generateXRefPages() +{ + QDictIterator<RefList> di(*Doxygen::xrefLists); + RefList *rl; + for (di.toFirst();(rl=di.current());++di) + { + rl->generatePage(); + } +} + +//---------------------------------------------------------------------- +// Copy the documentation in entry `root' to member definition `md' and +// set the function declaration of the member to `funcDecl'. If the boolean +// over_load is set the standard overload text is added. + +static void addMemberDocs(EntryNav *rootNav, + MemberDef *md, const char *funcDecl, + ArgumentList *al, + bool over_load, + NamespaceSDict * + ) +{ + Entry *root = rootNav->entry(); + //printf("addMemberDocs: `%s'::`%s' `%s' funcDecl=`%s' mSpec=%d\n", + // root->parent->name.data(),md->name().data(),md->argsString(),funcDecl,root->spec); + QCString fDecl=funcDecl; + // strip extern specifier + fDecl.stripPrefix("extern "); + md->setDefinition(fDecl); + md->enableCallGraph(root->callGraph); + md->enableCallerGraph(root->callerGraph); + ClassDef *cd=md->getClassDef(); + NamespaceDef *nd=md->getNamespaceDef(); + QCString fullName; + if (cd) + fullName = cd->name(); + else if (nd) + fullName = nd->name(); + + if (!fullName.isEmpty()) fullName+="::"; + fullName+=md->name(); + FileDef *rfd=rootNav->fileDef(); + + // TODO determine scope based on root not md + Definition *rscope = md->getOuterScope(); + + LockingPtr<ArgumentList> mdAl = md->argumentList(); + if (al) + { + //printf("merging arguments (1) docs=%d\n",root->doc.isEmpty()); + mergeArguments(mdAl.pointer(),al,!root->doc.isEmpty()); + } + else + { + if ( + matchArguments2( md->getOuterScope(), md->getFileDef(), mdAl.pointer(), + rscope,rfd,root->argList, + TRUE + ) + ) + { + //printf("merging arguments (2)\n"); + mergeArguments(mdAl.pointer(),root->argList,!root->doc.isEmpty()); + } + } + if (over_load) // the \overload keyword was used + { + QCString doc=getOverloadDocs(); + if (!root->doc.isEmpty()) + { + doc+="<p>"; + doc+=root->doc; + } + md->setDocumentation(doc,root->docFile,root->docLine); + md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine); + md->setDocsForDefinition(!root->proto); + } + else + { + //printf("overwrite!\n"); + md->setDocumentation(root->doc,root->docFile,root->docLine); + md->setDocsForDefinition(!root->proto); + + //printf("overwrite!\n"); + md->setBriefDescription(root->brief,root->briefFile,root->briefLine); + + if ( + (md->inbodyDocumentation().isEmpty() || + !rootNav->parent()->name().isEmpty() + ) && !root->inbodyDocs.isEmpty() + ) + { + md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine); + } + } + + //printf("initializer: '%s'(isEmpty=%d) '%s'(isEmpty=%d)\n", + // md->initializer().data(),md->initializer().isEmpty(), + // root->initializer.data(),root->initializer.isEmpty() + // ); + if (md->initializer().isEmpty() && !root->initializer.isEmpty()) + { + //printf("setInitializer\n"); + md->setInitializer(root->initializer); + } + + md->setMaxInitLines(root->initLines); + + if (rfd) + { + if ((md->getStartBodyLine()==-1 && root->bodyLine!=-1) + ) + { + //printf("Setting new body segment [%d,%d]\n",root->bodyLine,root->endBodyLine); + md->setBodySegment(root->bodyLine,root->endBodyLine); + md->setBodyDef(rfd); + } + + md->setRefItems(root->sli); + } + + md->enableCallGraph(md->hasCallGraph() || root->callGraph); + md->enableCallerGraph(md->hasCallerGraph() || root->callerGraph); + + md->mergeMemberSpecifiers(root->spec); + md->addSectionsToDefinition(root->anchors); + addMemberToGroups(root,md); + if (cd) cd->insertUsedFile(root->fileName); + //printf("root->mGrpId=%d\n",root->mGrpId); + if (root->mGrpId!=-1) + { + if (md->getMemberGroupId()!=-1) + { + if (md->getMemberGroupId()!=root->mGrpId) + { + warn( + root->fileName,root->startLine, + "warning: member %s belongs to two different groups. The second " + "one found here will be ignored.", + md->name().data() + ); + } + } + else // set group id + { + //printf("setMemberGroupId=%d md=%s\n",root->mGrpId,md->name().data()); + md->setMemberGroupId(root->mGrpId); + } + } +} + +//---------------------------------------------------------------------- +// find a class definition given the scope name and (optionally) a +// template list specifier + +static ClassDef *findClassDefinition(FileDef *fd,NamespaceDef *nd, + const char *scopeName) +{ + ClassDef *tcd = getResolvedClass(nd,fd,scopeName,0,0,TRUE,TRUE); + return tcd; +} + + +//---------------------------------------------------------------------- +// Adds the documentation contained in `root' to a global function +// with name `name' and argument list `args' (for overloading) and +// function declaration `decl' to the corresponding member definition. + +static bool findGlobalMember(EntryNav *rootNav, + const QCString &namespaceName, + const char *name, + const char *tempArg, + const char *, + const char *decl) +{ + Entry *root = rootNav->entry(); + Debug::print(Debug::FindMembers,0, + "2. findGlobalMember(namespace=%s,name=%s,tempArg=%s,decl=%s)\n", + namespaceName.data(),name,tempArg,decl); + QCString n=name; + if (n.isEmpty()) return FALSE; + if (n.find("::")!=-1) return FALSE; // skip undefined class members + MemberName *mn=Doxygen::functionNameSDict->find(n+tempArg); // look in function dictionary + if (mn==0) + { + mn=Doxygen::functionNameSDict->find(n); // try without template arguments + } + if (mn) // function name defined + { + Debug::print(Debug::FindMembers,0,"3. Found function scope\n"); + //int count=0; + MemberNameIterator mni(*mn); + MemberDef *md; + bool found=FALSE; + for (mni.toFirst();(md=mni.current()) && !found;++mni) + { + NamespaceDef *nd=md->getNamespaceDef(); + + //printf("Namespace namespaceName=%s nd=%s\n", + // namespaceName.data(),nd ? nd->name().data() : "<none>"); + + FileDef *fd=rootNav->fileDef(); + //printf("File %s\n",fd ? fd->name().data() : "<none>"); + NamespaceSDict *nl = fd ? fd->getUsedNamespaces() : 0; + //SDict<Definition> *cl = fd ? fd->getUsedClasses() : 0; + //printf("NamespaceList %p\n",nl); + + // search in the list of namespaces that are imported via a + // using declaration + bool viaUsingDirective = nl && nd && nl->find(nd->qualifiedName())!=0; + + if ((namespaceName.isEmpty() && nd==0) || // not in a namespace + (nd && nd->name()==namespaceName) || // or in the same namespace + viaUsingDirective // member in `using' namespace + ) + { + Debug::print(Debug::FindMembers,0,"4. Try to add member `%s' to scope `%s'\n", + md->name().data(),namespaceName.data()); + QCString nsName = nd ? nd->name().data() : ""; + + NamespaceDef *rnd = 0; + if (!namespaceName.isEmpty()) rnd = Doxygen::namespaceSDict->find(namespaceName); + + LockingPtr<ArgumentList> mdAl = md->argumentList(); + bool matching= + (mdAl==0 && root->argList->count()==0) || + md->isVariable() || md->isTypedef() || /* in case of function pointers */ + matchArguments2(md->getOuterScope(),md->getFileDef(),mdAl.pointer(), + rnd ? rnd : Doxygen::globalScope,fd,root->argList, + FALSE); + + // for template members we need to check if the number of + // template arguments is the same, otherwise we are dealing with + // different functions. + if (matching && root->tArgLists) + { + LockingPtr<ArgumentList> mdTempl = md->templateArguments(); + if (mdTempl!=0) + { + if (root->tArgLists->getLast()->count()!=mdTempl->count()) + { + matching=FALSE; + } + } + } + + + //printf("%s<->%s\n", + // argListToString(md->argumentList()).data(), + // argListToString(root->argList).data()); + + // for static members we also check if the comment block was found in + // the same file. This is needed because static members with the same + // name can be in different files. Thus it would be wrong to just + // put the comment block at the first syntactically matching member. + if (matching && md->isStatic() && + md->getDefFileName()!=root->fileName && + mn->count()>1) + { + matching = FALSE; + } + + if (matching) // add docs to the member + { + Debug::print(Debug::FindMembers,0,"5. Match found\n"); + addMemberDocs(rootNav,md,decl,root->argList,FALSE); + found=TRUE; + } + } + } + if (!found && root->relatesType != Duplicate) // no match + { + QCString fullFuncDecl=decl; + if (root->argList) fullFuncDecl+=argListToString(root->argList,TRUE); + QCString warnMsg = + QCString("warning: no matching file member found for \n")+substitute(fullFuncDecl,"%","%%"); + if (mn->count()>0) + { + warnMsg+="Possible candidates:\n"; + for (mni.toFirst();(md=mni.current());++mni) + { + warnMsg+=" "; + warnMsg+=substitute(md->declaration(),"%","%%"); + warnMsg+='\n'; + } + } + warn(root->fileName,root->startLine,warnMsg); + } + } + else // got docs for an undefined member! + { + if (root->type!="friend class" && + root->type!="friend struct" && + root->type!="friend union" && + (!Config_getBool("TYPEDEF_HIDES_STRUCT") || + root->type.find("typedef ")==-1) + ) + { + warn(root->fileName,root->startLine, + "warning: documented function `%s' was not declared or defined.",decl + ); + } + } + return TRUE; +} + +static bool isSpecialization( + const QList<ArgumentList> &srcTempArgLists, + const QList<ArgumentList> &dstTempArgLists + ) +{ + QListIterator<ArgumentList> srclali(srcTempArgLists); + QListIterator<ArgumentList> dstlali(dstTempArgLists); + for (;srclali.current();++srclali,++dstlali) + { + ArgumentList *sal = srclali.current(); + ArgumentList *dal = dstlali.current(); + if (!(sal && dal && sal->count()==dal->count())) return TRUE; + } + return FALSE; +} + + +static QCString substituteTemplatesInString( + const QList<ArgumentList> &srcTempArgLists, + const QList<ArgumentList> &dstTempArgLists, + ArgumentList *funcTempArgList, // can be used to match template specializations + const QCString &src + ) +{ + QCString dst; + QRegExp re( "[A-Za-z_][A-Za-z_0-9]*"); + //printf("type=%s\n",sa->type.data()); + int i,p=0,l; + while ((i=re.match(src,p,&l))!=-1) // for each word in srcType + { + bool found=FALSE; + dst+=src.mid(p,i-p); + QCString name=src.mid(i,l); + + QListIterator<ArgumentList> srclali(srcTempArgLists); + QListIterator<ArgumentList> dstlali(dstTempArgLists); + for (;srclali.current() && !found;++srclali,++dstlali) + { + ArgumentListIterator tsali(*srclali.current()); + ArgumentListIterator tdali(*dstlali.current()); + Argument *tsa =0,*tda=0, *fa=0; + if (funcTempArgList) + { + fa=funcTempArgList->first(); + } + + for (tsali.toFirst();(tsa=tsali.current()) && !found;++tsali) + { + tda = tdali.current(); + //if (tda) printf("tsa=%s|%s tda=%s|%s\n", + // tsa->type.data(),tsa->name.data(), + // tda->type.data(),tda->name.data()); + if (name==tsa->name) + { + if (tda && tda->name.isEmpty()) + { + int vc=0; + if (tda->type.left(6)=="class ") vc=6; + else if (tda->type.left(9)=="typename ") vc=9; + if (vc>0) // convert type=="class T" to type=="class" name=="T" + { + tda->name = tda->type.mid(vc); + tda->type = tda->type.left(vc-1); + } + } + if (tda && !tda->name.isEmpty()) + { + name=tda->name; // substitute + found=TRUE; + } + else if (fa) + { + name=fa->type; + found=TRUE; + } + } + if (tda) + ++tdali; + else if (fa) + fa=funcTempArgList->next(); + } + //printf(" srcList='%s' dstList='%s faList='%s'\n", + // argListToString(srclali.current()).data(), + // argListToString(dstlali.current()).data(), + // funcTempArgList ? argListToString(funcTempArgList).data() : "<none>"); + } + dst+=name; + p=i+l; + } + dst+=src.right(src.length()-p); + //printf(" substituteTemplatesInString(%s)=%s\n", + // src.data(),dst.data()); + return dst; +} + +static void substituteTemplatesInArgList( + const QList<ArgumentList> &srcTempArgLists, + const QList<ArgumentList> &dstTempArgLists, + ArgumentList *src, + ArgumentList *dst, + ArgumentList *funcTempArgs = 0 + ) +{ + ArgumentListIterator sali(*src); + Argument *sa=0; + Argument *da=dst->first(); + + for (sali.toFirst();(sa=sali.current());++sali) // for each member argument + { + QCString dstType = substituteTemplatesInString( + srcTempArgLists,dstTempArgLists,funcTempArgs, + sa->type); + QCString dstArray = substituteTemplatesInString( + srcTempArgLists,dstTempArgLists,funcTempArgs, + sa->array); + if (da==0) + { + da=new Argument(*sa); + dst->append(da); + da->type=dstType; + da->array=dstArray; + da=0; + } + else + { + da->type=dstType; + da->type=dstArray; + da=dst->next(); + } + } + dst->constSpecifier = src->constSpecifier; + dst->volatileSpecifier = src->volatileSpecifier; + dst->pureSpecifier = src->pureSpecifier; + //printf("substituteTemplatesInArgList: replacing %s with %s\n", + // argListToString(src).data(),argListToString(dst).data() + // ); +} + + + +/*! This function tries to find a member (in a documented class/file/namespace) + * that corresponds to the function/variable declaration given in \a funcDecl. + * + * The boolean \a overloaded is used to specify whether or not a standard + * overload documentation line should be generated. + * + * The boolean \a isFunc is a hint that indicates that this is a function + * instead of a variable or typedef. + */ +static void findMember(EntryNav *rootNav, + QCString funcDecl, + bool overloaded, + bool isFunc + ) +{ + Entry *root = rootNav->entry(); + + Debug::print(Debug::FindMembers,0, + "findMember(root=%p,funcDecl=`%s',related=`%s',overload=%d," + "isFunc=%d mGrpId=%d tArgList=%p (#=%d) " + "spec=%d lang=%x\n", + root,funcDecl.data(),root->relates.data(),overloaded,isFunc,root->mGrpId, + root->tArgLists,root->tArgLists ? root->tArgLists->count() : 0, + root->spec,root->lang + ); + + QCString scopeName; + QCString className; + QCString namespaceName; + QCString funcType; + QCString funcName; + QCString funcArgs; + QCString funcTempList; + QCString exceptions; + QCString funcSpec; + bool isRelated=FALSE; + bool isMemberOf=FALSE; + bool isFriend=FALSE; + bool done; + do + { + done=TRUE; + if (funcDecl.stripPrefix("friend ")) // treat friends as related members + { + isFriend=TRUE; + done=FALSE; + } + if (funcDecl.stripPrefix("inline ")) + { + root->spec|=Entry::Inline; + done=FALSE; + } + if (funcDecl.stripPrefix("explicit ")) + { + root->spec|=Entry::Explicit; + done=FALSE; + } + if (funcDecl.stripPrefix("mutable ")) + { + root->spec|=Entry::Mutable; + done=FALSE; + } + if (funcDecl.stripPrefix("virtual ")) + { + done=FALSE; + } + } while (!done); + + // delete any ; from the function declaration + int sep; + while ((sep=funcDecl.find(';'))!=-1) + { + funcDecl=(funcDecl.left(sep)+funcDecl.right(funcDecl.length()-sep-1)).stripWhiteSpace(); + } + + // make sure the first character is a space to simplify searching. + if (!funcDecl.isEmpty() && funcDecl[0]!=' ') funcDecl.prepend(" "); + + // remove some superfluous spaces + funcDecl= substitute( + substitute( + substitute(funcDecl,"~ ","~"), + ":: ","::" + ), + " ::","::" + ).stripWhiteSpace(); + + //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,root->lang==SrcLangExt_ObjC,scopeName,funcType,funcName, + funcArgs,funcTempList,exceptions + ); + } + //printf("scopeName=`%s' funcType=`%s' funcName=`%s' funcArgs=`%s'\n", + // scopeName.data(),funcType.data(),funcName.data(),funcArgs.data()); + + // the class name can also be a namespace name, we decide this later. + // if a related class name is specified and the class name could + // not be derived from the function declaration, then use the + // related field. + //printf("scopeName=`%s' className=`%s' namespaceName=`%s'\n", + // scopeName.data(),className.data(),namespaceName.data()); + if (!root->relates.isEmpty()) + { // related member, prefix user specified scope + isRelated=TRUE; + isMemberOf=(root->relatesType == MemberOf); + if (getClass(root->relates)==0 && !scopeName.isEmpty()) + { + scopeName= mergeScopes(scopeName,root->relates); + } + else + { + scopeName = root->relates; + } + } + + if (root->relates.isEmpty() && rootNav->parent() && + ((rootNav->parent()->section()&Entry::SCOPE_MASK) || + (rootNav->parent()->section()==Entry::OBJCIMPL_SEC) + ) && + !rootNav->parent()->name().isEmpty()) // see if we can combine scopeName + // with the scope in which it was found + { + QCString joinedName = rootNav->parent()->name()+"::"+scopeName; + if (!scopeName.isEmpty() && + (getClass(joinedName) || Doxygen::namespaceSDict->find(joinedName))) + { + scopeName = joinedName; + } + else + { + scopeName = mergeScopes(rootNav->parent()->name(),scopeName); + } + } + else // see if we can prefix a namespace or class that is used from the file + { + FileDef *fd=rootNav->fileDef(); + if (fd) + { + NamespaceSDict *fnl = fd->getUsedNamespaces(); + if (fnl) + { + QCString joinedName; + NamespaceDef *fnd; + NamespaceSDict::Iterator nsdi(*fnl); + for (nsdi.toFirst();(fnd=nsdi.current());++nsdi) + { + joinedName = fnd->name()+"::"+scopeName; + if (Doxygen::namespaceSDict->find(joinedName)) + { + scopeName=joinedName; + break; + } + } + } + } + } + scopeName=stripTemplateSpecifiersFromScope( + removeRedundantWhiteSpace(scopeName),FALSE,&funcSpec); + + // funcSpec contains the last template specifiers of the given scope. + // If this method does not have any template arguments or they are + // empty while funcSpec is not empty we assume this is a + // specialization of a method. If not, we clear the funcSpec and treat + // this as a normal method of a template class. + if (!(root->tArgLists && + root->tArgLists->count()>0 && + root->tArgLists->first()->count()==0 + ) + ) + { + funcSpec.resize(0); + } + + // split scope into a namespace and a class part + extractNamespaceName(scopeName,className,namespaceName,TRUE); + //printf("scopeName=`%s' className=`%s' namespaceName=`%s'\n", + // scopeName.data(),className.data(),namespaceName.data()); + + //namespaceName=removeAnonymousScopes(namespaceName); + if (namespaceName.find('@')!=-1) return; // skip stuff in anonymous namespace... + + //printf("namespaceName=`%s' className=`%s'\n",namespaceName.data(),className.data()); + // merge class and namespace scopes again + scopeName.resize(0); + if (!namespaceName.isEmpty()) + { + if (className.isEmpty()) + { + scopeName=namespaceName; + } + else if (!root->relates.isEmpty() || // relates command with explicit scope + !getClass(className)) // class name only exists in a namespace + { + scopeName=namespaceName+"::"+className; + } + else + { + scopeName=className; + } + } + else if (!className.isEmpty()) + { + scopeName=className; + } + //printf("new scope=`%s'\n",scopeName.data()); + + QCString tempScopeName=scopeName; + ClassDef *cd=getClass(scopeName); + if (cd) + { + if (root->tArgLists) root->tArgLists->first(); + if (funcSpec.isEmpty()) + { + tempScopeName=cd->qualifiedNameWithTemplateParameters(root->tArgLists); + } + else + { + tempScopeName=scopeName+funcSpec; + } + } + //printf("scopeName=%s cd=%p root->tArgLists=%p result=%s\n", + // scopeName.data(),cd,root->tArgLists,tempScopeName.data()); + + //printf("scopeName=`%s' className=`%s'\n",scopeName.data(),className.data()); + // rebuild the function declaration (needed to get the scope right). + if (!scopeName.isEmpty() && !isRelated && !isFriend && !Config_getBool("HIDE_SCOPE_NAMES")) + { + if (!funcType.isEmpty()) + { + if (isFunc) // a function -> we use argList for the arguments + { + funcDecl=funcType+" "+tempScopeName+"::"+funcName+funcTempList; + } + else + { + funcDecl=funcType+" "+tempScopeName+"::"+funcName+funcArgs; + } + } + else + { + if (isFunc) // a function => we use argList for the arguments + { + funcDecl=tempScopeName+"::"+funcName+funcTempList; + } + else // variable => add `argument' list + { + funcDecl=tempScopeName+"::"+funcName+funcArgs; + } + } + } + else // build declaration without scope + { + if (!funcType.isEmpty()) // but with a type + { + if (isFunc) // function => omit argument list + { + funcDecl=funcType+" "+funcName+funcTempList; + } + else // variable => add `argument' list + { + funcDecl=funcType+" "+funcName+funcArgs; + } + } + else // no type + { + if (isFunc) + { + funcDecl=funcName+funcTempList; + } + else + { + funcDecl=funcName+funcArgs; + } + } + } + + if (funcType=="template class" && !funcTempList.isEmpty()) + return; // ignore explicit template instantiations + + Debug::print(Debug::FindMembers,0, + "findMember() Parse results:\n" + " namespaceName=`%s'\n" + " className=`%s`\n" + " funcType=`%s'\n" + " funcSpec=`%s'\n" + " funcName=`%s'\n" + " funcArgs=`%s'\n" + " funcTempList=`%s'\n" + " funcDecl=`%s'\n" + " related=`%s'\n" + " exceptions=`%s'\n" + " isRelated=%d\n" + " isMemberOf=%d\n" + " isFriend=%d\n" + " isFunc=%d\n\n", + namespaceName.data(),className.data(), + funcType.data(),funcSpec.data(),funcName.data(),funcArgs.data(),funcTempList.data(), + funcDecl.data(),root->relates.data(),exceptions.data(),isRelated,isMemberOf,isFriend, + isFunc + ); + + MemberName *mn=0; + if (!funcName.isEmpty()) // function name is valid + { + Debug::print(Debug::FindMembers,0, + "1. funcName=`%s'\n",funcName.data()); + if (funcName.left(9)=="operator ") // strip class scope from cast operator + { + funcName = substitute(funcName,className+"::",""); + } + if (!funcTempList.isEmpty()) // try with member specialization + { + mn=Doxygen::memberNameSDict->find(funcName+funcTempList); + } + if (mn==0) // try without specialization + { + mn=Doxygen::memberNameSDict->find(funcName); + } + if (!isRelated && mn) // function name already found + { + Debug::print(Debug::FindMembers,0, + "2. member name exists (%d members with this name)\n",mn->count()); + if (!className.isEmpty()) // class name is valid + { + if (funcSpec.isEmpty()) // not a member specialization + { + int count=0; + int noMatchCount=0; + MemberNameIterator mni(*mn); + MemberDef *md; + bool memFound=FALSE; + for (mni.toFirst();!memFound && (md=mni.current());++mni) + { + ClassDef *cd=md->getClassDef(); + Debug::print(Debug::FindMembers,0, + "3. member definition found, " + "scope needed=`%s' scope=`%s' args=`%s' fileName=%s\n", + scopeName.data(),cd ? cd->name().data() : "<none>", + md->argsString(), + root->fileName.data()); + //printf("Member %s (member scopeName=%s) (this scopeName=%s) classTempList=%s\n",md->name().data(),cd->name().data(),scopeName.data(),classTempList.data()); + FileDef *fd=rootNav->fileDef(); + NamespaceDef *nd=0; + if (!namespaceName.isEmpty()) nd=getResolvedNamespace(namespaceName); + + //printf("scopeName %s->%s\n",scopeName.data(), + // stripTemplateSpecifiersFromScope(scopeName,FALSE).data()); + + ClassDef *tcd=findClassDefinition(fd,nd,scopeName); + if (tcd==0 && stripAnonymousNamespaceScope(cd->name())==scopeName) + { + // don't be fooled by anonymous scopes + tcd=cd; + } + //printf("Looking for %s inside nd=%s result=%p (%s) cd=%p\n", + // scopeName.data(),nd?nd->name().data():"<none>",tcd,tcd?tcd->name().data():"",cd); + + if (cd && tcd==cd) // member's classes match + { + Debug::print(Debug::FindMembers,0, + "4. class definition %s found\n",cd->name().data()); + + // get the template parameter lists found at the member declaration + QList<ArgumentList> declTemplArgs; + cd->getTemplateParameterLists(declTemplArgs); + LockingPtr<ArgumentList> templAl = md->templateArguments(); + if (templAl!=0) + { + declTemplArgs.append(templAl.pointer()); + } + + // get the template parameter lists found at the member definition + QList<ArgumentList> *defTemplArgs = root->tArgLists; + //printf("defTemplArgs=%p\n",defTemplArgs); + + // do we replace the decl argument lists with the def argument lists? + bool substDone=FALSE; + ArgumentList *argList=0; + + /* substitute the occurrences of class template names in the + * argument list before matching + */ + LockingPtr<ArgumentList> mdAl = md->argumentList(); + if (declTemplArgs.count()>0 && defTemplArgs && + declTemplArgs.count()==defTemplArgs->count() && + mdAl.pointer() + ) + { + /* the function definition has template arguments + * and the class definition also has template arguments, so + * we must substitute the template names of the class by that + * of the function definition before matching. + */ + argList = new ArgumentList; + substituteTemplatesInArgList(declTemplArgs,*defTemplArgs, + mdAl.pointer(),argList); + + substDone=TRUE; + } + else /* no template arguments, compare argument lists directly */ + { + argList = mdAl.pointer(); + } + + Debug::print(Debug::FindMembers,0, + "5. matching `%s'<=>`%s' className=%s namespaceName=%s\n", + argListToString(argList,TRUE).data(),argListToString(root->argList,TRUE).data(), + className.data(),namespaceName.data() + ); + + bool matching= + md->isVariable() || md->isTypedef() || // needed for function pointers + (mdAl.pointer()==0 && root->argList->count()==0) || + matchArguments2( + md->getClassDef(),md->getFileDef(),argList, + cd,fd,root->argList, + TRUE); + + Debug::print(Debug::FindMembers,0, + "6. match results of matchArguments2 = %d\n",matching); + + if (substDone) // found a new argument list + { + if (matching) // replace member's argument list + { + md->setDefinitionTemplateParameterLists(root->tArgLists); + md->setArgumentList(argList); // new owner of the list => no delete + } + else // no match + { + if (!funcTempList.isEmpty() && + isSpecialization(declTemplArgs,*defTemplArgs)) + { + // check if we are dealing with a partial template + // specialization. In this case we add it to the class + // even though the member arguments do not match. + + // TODO: copy other aspects? + root->protection=md->protection(); // copy protection level + addMethodToClass(rootNav,cd,md->name(),isFriend); + return; + } + delete argList; + } + } + if (matching) + { + addMemberDocs(rootNav,md,funcDecl,0,overloaded,0/* TODO */); + count++; + memFound=TRUE; + } + } + else if (cd && cd!=tcd) // we did find a class with the same name as cd + // but in a different namespace + { + noMatchCount++; + } + } + if (count==0 && rootNav->parent() && + rootNav->parent()->section()==Entry::OBJCIMPL_SEC) + { + goto localObjCMethod; + } + if (count==0 && !(isFriend && funcType=="class")) + { + int candidates=0; + ClassDef *ecd = 0, *ucd = 0; + MemberDef *emd = 0, *umd = 0; + if (mn->count()>0) + { + //printf("Assume template class\n"); + for (mni.toFirst();(md=mni.current());++mni) + { + ClassDef *ccd=md->getClassDef(); + MemberDef *cmd=md; + //printf("ccd->name()==%s className=%s\n",ccd->name().data(),className.data()); + if (ccd!=0 && rightScopeMatch(ccd->name(),className)) + { + LockingPtr<ArgumentList> templAl = md->templateArguments(); + if (root->tArgLists && templAl!=0 && + root->tArgLists->getLast()->count()<=templAl->count()) + { + addMethodToClass(rootNav,ccd,md->name(),isFriend); + return; + } + if (md->argsString()==argListToString(root->argList,TRUE,FALSE)) + { // exact argument list match -> remember + ucd = ecd = ccd; + umd = emd = cmd; + Debug::print(Debug::FindMembers,0, + "7. new candidate className=%s scope=%s args=%s exact match\n", + className.data(),ccd->name().data(),md->argsString()); + } + else // arguments do not match, but member name and scope do -> remember + { + ucd = ccd; + umd = cmd; + Debug::print(Debug::FindMembers,0, + "7. new candidate className=%s scope=%s args=%s no match\n", + className.data(),ccd->name().data(),md->argsString()); + } + candidates++; + } + } + } + static bool strictProtoMatching = Config_getBool("STRICT_PROTO_MATCHING"); + if (!strictProtoMatching) + { + if (candidates==1 && ucd && umd) + { + // we didn't find an actual match on argument lists, but there is only 1 member with this + // name in the same scope, so that has to be the one. + addMemberDocs(rootNav,umd,funcDecl,0,overloaded,0); + return; + } + else if (candidates>1 && ecd && emd) + { + // we didn't find a unique match using type resolution, + // but one of the matches has the exact same signature so + // we take that one. + addMemberDocs(rootNav,emd,funcDecl,0,overloaded,0); + return; + } + } + + QCString warnMsg = "warning: no "; + if (noMatchCount>1) warnMsg+="uniquely "; + warnMsg+="matching class member found for \n"; + + if (root->tArgLists) + { + QListIterator<ArgumentList> alli(*root->tArgLists); + ArgumentList *al; + for (;(al=alli.current());++alli) + { + warnMsg+=" template "; + warnMsg+=tempArgListToString(al); + warnMsg+='\n'; + } + } + QCString fullFuncDecl=funcDecl.copy(); + if (isFunc) fullFuncDecl+=argListToString(root->argList,TRUE); + + warnMsg+=" "; + warnMsg+=fullFuncDecl; + warnMsg+='\n'; + + if (candidates>0) + { + warnMsg+="Possible candidates:\n"; + for (mni.toFirst();(md=mni.current());++mni) + { + ClassDef *cd=md->getClassDef(); + if (cd!=0 && rightScopeMatch(cd->name(),className)) + { + LockingPtr<ArgumentList> templAl = md->templateArguments(); + if (templAl!=0) + { + warnMsg+=" template "; + warnMsg+=tempArgListToString(templAl.pointer()); + warnMsg+='\n'; + } + warnMsg+=" "; + if (md->typeString()) + { + warnMsg+=md->typeString(); + warnMsg+=' '; + } + QCString qScope = cd->qualifiedNameWithTemplateParameters(); + if (!qScope.isEmpty()) + warnMsg+=qScope+"::"+md->name(); + if (md->argsString()) + warnMsg+=md->argsString(); + if (noMatchCount>1) + { + QCString lineFile; + lineFile.sprintf(" at line %d of file ",md->getDefLine()); + warnMsg+=lineFile+md->getDefFileName(); + } + + warnMsg+='\n'; + } + } + } + warn_simple(root->fileName,root->startLine,warnMsg); + } + } + else if (cd) // member specialization + { + MemberNameIterator mni(*mn); + MemberDef *declMd=0; + MemberDef *md=0; + for (mni.toFirst();(md=mni.current());++mni) + { + if (md->getClassDef()==cd) + { + // TODO: we should probably also check for matching arguments + declMd = md; + break; + } + } + MemberDef::MemberType mtype=MemberDef::Function; + ArgumentList *tArgList = new ArgumentList; + // getTemplateArgumentsFromName(cd->name()+"::"+funcName,root->tArgLists); + md=new MemberDef( + root->fileName,root->startLine, + funcType,funcName,funcArgs,exceptions, + declMd ? declMd->protection() : root->protection, + root->virt,root->stat,Member, + mtype,tArgList,root->argList); + //printf("new specialized member %s args=`%s'\n",md->name().data(),funcArgs.data()); + md->setTagInfo(rootNav->tagInfo()); + md->setLanguage(root->lang); + md->setMemberClass(cd); + md->setTemplateSpecialization(TRUE); + md->setTypeConstraints(root->typeConstr); + md->setDefinition(funcDecl); + md->enableCallGraph(root->callGraph); + md->enableCallerGraph(root->callerGraph); + md->setDocumentation(root->doc,root->docFile,root->docLine); + md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine); + md->setDocsForDefinition(!root->proto); + md->setPrototype(root->proto); + md->addSectionsToDefinition(root->anchors); + md->setBodySegment(root->bodyLine,root->endBodyLine); + FileDef *fd=rootNav->fileDef(); + md->setBodyDef(fd); + md->setMemberSpecifiers(root->spec); + md->setMemberGroupId(root->mGrpId); + mn->append(md); + cd->insertMember(md); + md->setRefItems(root->sli); + delete tArgList; + } + else + { + //printf("*** Specialized member %s of unknown scope %s%s found!\n", + // scopeName.data(),funcName.data(),funcArgs.data()); + } + } + else if (overloaded) // check if the function belongs to only one class + { + // for unique overloaded member we allow the class to be + // omitted, this is to be Qt compatable. Using this should + // however be avoided, because it is error prone + MemberNameIterator mni(*mn); + MemberDef *md=mni.toFirst(); + ASSERT(md); + ClassDef *cd=md->getClassDef(); + ASSERT(cd); + QCString className=cd->name().copy(); + ++mni; + bool unique=TRUE; + for (;(md=mni.current());++mni) + { + ClassDef *cd=md->getClassDef(); + if (className!=cd->name()) unique=FALSE; + } + if (unique) + { + MemberDef::MemberType mtype; + if (root->mtype==Signal) mtype=MemberDef::Signal; + else if (root->mtype==Slot) mtype=MemberDef::Slot; + else if (root->mtype==DCOP) mtype=MemberDef::DCOP; + else mtype=MemberDef::Function; + + // new overloaded member function + ArgumentList *tArgList = + getTemplateArgumentsFromName(cd->name()+"::"+funcName,root->tArgLists); + //printf("new related member %s args=`%s'\n",md->name().data(),funcArgs.data()); + MemberDef *md=new MemberDef( + root->fileName,root->startLine, + funcType,funcName,funcArgs,exceptions, + root->protection,root->virt,root->stat,Related, + mtype,tArgList,root->argList); + md->setTagInfo(rootNav->tagInfo()); + md->setLanguage(root->lang); + md->setTypeConstraints(root->typeConstr); + md->setMemberClass(cd); + md->setDefinition(funcDecl); + md->enableCallGraph(root->callGraph); + md->enableCallerGraph(root->callerGraph); + QCString doc=getOverloadDocs(); + doc+="<p>"; + doc+=root->doc; + md->setDocumentation(doc,root->docFile,root->docLine); + md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine); + md->setDocsForDefinition(!root->proto); + md->setPrototype(root->proto); + md->addSectionsToDefinition(root->anchors); + md->setBodySegment(root->bodyLine,root->endBodyLine); + FileDef *fd=rootNav->fileDef(); + md->setBodyDef(fd); + md->setMemberSpecifiers(root->spec); + md->setMemberGroupId(root->mGrpId); + mn->append(md); + cd->insertMember(md); + cd->insertUsedFile(root->fileName); + md->setRefItems(root->sli); + } + } + else // unrelated function with the same name as a member + { + if (!findGlobalMember(rootNav,namespaceName,funcName,funcTempList,funcArgs,funcDecl)) + { + QCString fullFuncDecl=funcDecl.copy(); + if (isFunc) fullFuncDecl+=argListToString(root->argList,TRUE); + warn(root->fileName,root->startLine, + "warning: Cannot determine class for function\n%s", + fullFuncDecl.data() + ); + } + } + } + else if (isRelated && !root->relates.isEmpty()) + { + Debug::print(Debug::FindMembers,0,"2. related function\n" + " scopeName=%s className=%s\n",scopeName.data(),className.data()); + if (className.isEmpty()) className=root->relates; + ClassDef *cd; + //printf("scopeName=`%s' className=`%s'\n",scopeName.data(),className.data()); + if ((cd=getClass(scopeName))) + { + bool newMember=TRUE; // assume we have a new member + bool newMemberName=FALSE; + MemberDef *mdDefine=0; + bool isDefine=FALSE; + { + MemberName *mn = Doxygen::functionNameSDict->find(funcName); + if (mn) + { + mdDefine = mn->first(); + while (mdDefine && !isDefine) + { + isDefine = isDefine || mdDefine->isDefine(); + if (!isDefine) mdDefine = mn->next(); + } + } + } + + FileDef *fd=rootNav->fileDef(); + + if ((mn=Doxygen::memberNameSDict->find(funcName))==0) + { + mn=new MemberName(funcName); + newMemberName=TRUE; // we create a new member name + } + else + { + MemberDef *rmd=mn->first(); + while (rmd && newMember) // see if we got another member with matching arguments + { + LockingPtr<ArgumentList> rmdAl = rmd->argumentList(); + + newMember= + className!=rmd->getOuterScope()->name() || + !matchArguments2(rmd->getOuterScope(),rmd->getFileDef(),rmdAl.pointer(), + cd,fd,root->argList, + TRUE); + if (newMember) rmd=mn->next(); + } + if (!newMember && rmd) // member already exists as rmd -> add docs + { + //printf("addMemberDocs for related member %s\n",root->name.data()); + //rmd->setMemberDefTemplateArguments(root->mtArgList); + addMemberDocs(rootNav,rmd,funcDecl,0,overloaded); + } + } + + if (newMember) // need to create a new member + { + MemberDef::MemberType mtype; + if (isDefine) + mtype=MemberDef::Define; + else if (root->mtype==Signal) + mtype=MemberDef::Signal; + else if (root->mtype==Slot) + mtype=MemberDef::Slot; + else if (root->mtype==DCOP) + mtype=MemberDef::DCOP; + else + mtype=MemberDef::Function; + + if (isDefine && mdDefine) + { + mdDefine->setHidden(TRUE); + funcType="#define"; + funcArgs=mdDefine->argsString(); + funcDecl=funcType + " " + funcName; + } + + //printf("New related name `%s' `%d'\n",funcName.data(), + // root->argList ? (int)root->argList->count() : -1); + + // first note that we pass: + // (root->tArgLists ? root->tArgLists->last() : 0) + // for the template arguments fo the new "member." + // this accurately reflects the template arguments of + // the related function, which don't have to do with + // those of the related class. + MemberDef *md=new MemberDef( + root->fileName,root->startLine, + funcType,funcName,funcArgs,exceptions, + root->protection,root->virt, + root->stat && !isMemberOf, + isMemberOf ? Foreign : isRelated ? Related : Member, + mtype, + (root->tArgLists ? root->tArgLists->last() : 0), + funcArgs.isEmpty() ? 0 : root->argList); + + if (isDefine && mdDefine) + { + md->setInitializer(mdDefine->initializer()); + } + + // + // we still have the problem that + // MemberDef::writeDocumentation() in memberdef.cpp + // writes the template argument list for the class, + // as if this member is a member of the class. + // fortunately, MemberDef::writeDocumentation() has + // a special mechanism that allows us to totally + // override the set of template argument lists that + // are printed. We use that and set it to the + // template argument lists of the related function. + // + md->setDefinitionTemplateParameterLists(root->tArgLists); + + md->setTagInfo(rootNav->tagInfo()); + + + + //printf("Related member name=`%s' decl=`%s' bodyLine=`%d'\n", + // funcName.data(),funcDecl.data(),root->bodyLine); + + // try to find the matching line number of the body from the + // global function list + bool found=FALSE; + if (root->bodyLine==-1) + { + MemberName *rmn=Doxygen::functionNameSDict->find(funcName); + if (rmn) + { + MemberDef *rmd=rmn->first(); + while (rmd && !found) // see if we got another member with matching arguments + { + LockingPtr<ArgumentList> rmdAl = rmd->argumentList(); + // check for matching argument lists + if ( + matchArguments2(rmd->getOuterScope(),rmd->getFileDef(),rmdAl.pointer(), + cd,fd,root->argList, + TRUE) + ) + { + found=TRUE; + } + if (!found) rmd=rmn->next(); + } + if (rmd) // member found -> copy line number info + { + md->setBodySegment(rmd->getStartBodyLine(),rmd->getEndBodyLine()); + md->setBodyDef(rmd->getBodyDef()); + //md->setBodyMember(rmd); + } + } + } + if (!found) // line number could not be found or is available in this + // entry + { + md->setBodySegment(root->bodyLine,root->endBodyLine); + md->setBodyDef(fd); + } + + //if (root->mGrpId!=-1) + //{ + // md->setMemberGroup(memberGroupDict[root->mGrpId]); + //} + md->setMemberClass(cd); + md->setMemberSpecifiers(root->spec); + md->setDefinition(funcDecl); + md->enableCallGraph(root->callGraph); + md->enableCallerGraph(root->callerGraph); + md->setDocumentation(root->doc,root->docFile,root->docLine); + md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine); + md->setDocsForDefinition(!root->proto); + md->setPrototype(root->proto); + md->setBriefDescription(root->brief,root->briefFile,root->briefLine); + md->addSectionsToDefinition(root->anchors); + md->setMemberGroupId(root->mGrpId); + md->setLanguage(root->lang); + //md->setMemberDefTemplateArguments(root->mtArgList); + mn->append(md); + cd->insertMember(md); + cd->insertUsedFile(root->fileName); + md->setRefItems(root->sli); + if (root->relatesType == Duplicate) md->setRelatedAlso(cd); + if (!isDefine) + { + addMemberToGroups(root,md); + } + //printf("Adding member=%s\n",md->name().data()); + if (newMemberName) + { + //Doxygen::memberNameList.append(mn); + //Doxygen::memberNameDict.insert(funcName,mn); + Doxygen::memberNameSDict->append(funcName,mn); + } + } + if (root->relatesType == Duplicate) + { + if (!findGlobalMember(rootNav,namespaceName,funcName,funcTempList,funcArgs,funcDecl)) + { + QCString fullFuncDecl=funcDecl.copy(); + if (isFunc) fullFuncDecl+=argListToString(root->argList,TRUE); + warn(root->fileName,root->startLine, + "warning: Cannot determine file/namespace for relatedalso function\n%s", + fullFuncDecl.data() + ); + } + } + } + else + { + warn_undoc(root->fileName,root->startLine, + "warning: class `%s' for related function `%s' is not " + "documented.", + className.data(),funcName.data() + ); + } + } + else if (rootNav->parent() && rootNav->parent()->section()==Entry::OBJCIMPL_SEC) + { +localObjCMethod: + ClassDef *cd; + //printf("scopeName=`%s' className=`%s'\n",scopeName.data(),className.data()); + if (Config_getBool("EXTRACT_LOCAL_METHODS") && (cd=getClass(scopeName))) + { + Debug::print(Debug::FindMembers,0,"4. Local objective C method %s\n" + " scopeName=%s className=%s\n",root->name.data(),scopeName.data(),className.data()); + //printf("Local objective C method `%s' of class `%s' found\n",root->name.data(),cd->name().data()); + MemberDef *md=new MemberDef( + root->fileName,root->startLine, + funcType,funcName,funcArgs,exceptions, + root->protection,root->virt,root->stat,Member, + MemberDef::Function,0,root->argList); + md->setTagInfo(rootNav->tagInfo()); + md->setLanguage(root->lang); + md->makeImplementationDetail(); + md->setMemberClass(cd); + md->setDefinition(funcDecl); + md->enableCallGraph(root->callGraph); + md->enableCallerGraph(root->callerGraph); + md->setDocumentation(root->doc,root->docFile,root->docLine); + md->setBriefDescription(root->brief,root->briefFile,root->briefLine); + md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine); + md->setDocsForDefinition(!root->proto); + md->setPrototype(root->proto); + md->addSectionsToDefinition(root->anchors); + md->setBodySegment(root->bodyLine,root->endBodyLine); + FileDef *fd=rootNav->fileDef(); + md->setBodyDef(fd); + md->setMemberSpecifiers(root->spec); + md->setMemberGroupId(root->mGrpId); + cd->insertMember(md); + cd->insertUsedFile(root->fileName); + md->setRefItems(root->sli); + if ((mn=Doxygen::memberNameSDict->find(root->name))) + { + mn->append(md); + } + else + { + mn = new MemberName(root->name); + mn->append(md); + Doxygen::memberNameSDict->append(root->name,mn); + } + } + else + { + // local objective C method found for class without interface + } + } + else // unrelated not overloaded member found + { + bool globMem = findGlobalMember(rootNav,namespaceName,funcName,funcTempList,funcArgs,funcDecl); + if (className.isEmpty() && !globMem) + { + warn(root->fileName,root->startLine, + "warning: class for member `%s' cannot " + "be found.", funcName.data() + ); + } + else if (!className.isEmpty() && !globMem) + { + warn(root->fileName,root->startLine, + "warning: member `%s' of class `%s' cannot be found", + funcName.data(),className.data()); + } + } + } + else + { + // this should not be called + warn(root->fileName,root->startLine, + "warning: member with no name found."); + } + return; +} + +//---------------------------------------------------------------------- +// find the members corresponding to the different documentation blocks +// that are extracted from the sources. + +static void filterMemberDocumentation(EntryNav *rootNav) +{ + Entry *root = rootNav->entry(); + int i=-1,l; + Debug::print(Debug::FindMembers,0, + "findMemberDocumentation(): root->type=`%s' root->inside=`%s' root->name=`%s' root->args=`%s' section=%x root->spec=%d root->mGrpId=%d\n", + root->type.data(),root->inside.data(),root->name.data(),root->args.data(),root->section,root->spec,root->mGrpId + ); + //printf("rootNav->parent()->name()=%s\n",rootNav->parent()->name().data()); + bool isFunc=TRUE; + + if (root->relatesType == Duplicate && !root->relates.isEmpty()) + { + QCString tmp = root->relates; + root->relates.resize(0); + filterMemberDocumentation(rootNav); + root->relates = tmp; + } + + if ( // detect func variable/typedef to func ptr + (i=findFunctionPtr(root->type,root->lang,&l))!=-1 + ) + { + //printf("Fixing function pointer!\n"); + // fix type and argument + root->args.prepend(root->type.right(root->type.length()-i-l)); + root->type=root->type.left(i+l); + //printf("Results type=%s,name=%s,args=%s\n",root->type.data(),root->name.data(),root->args.data()); + isFunc=FALSE; + } + else if ((root->type.left(8)=="typedef " && root->args.find('(')!=-1)) + // detect function types marked as functions + { + isFunc=FALSE; + } + + //printf("Member %s isFunc=%d\n",root->name.data(),isFunc); + if (root->section==Entry::MEMBERDOC_SEC) + { + //printf("Documentation for inline member `%s' found args=`%s'\n", + // root->name.data(),root->args.data()); + //if (root->relates.length()) printf(" Relates %s\n",root->relates.data()); + if (root->type.isEmpty()) + { + findMember(rootNav,root->name+root->args+root->exception,FALSE,isFunc); + } + else + { + findMember(rootNav,root->type+" "+root->name+root->args+root->exception,FALSE,isFunc); + } + } + else if (root->section==Entry::OVERLOADDOC_SEC) + { + //printf("Overloaded member %s found\n",root->name.data()); + findMember(rootNav,root->name,TRUE,isFunc); + } + else if + ((root->section==Entry::FUNCTION_SEC // function + || + (root->section==Entry::VARIABLE_SEC && // variable + !root->type.isEmpty() && // with a type + g_compoundKeywordDict.find(root->type)==0 // that is not a keyword + // (to skip forward declaration of class etc.) + ) + ) + ) + { + //printf("Documentation for member `%s' found args=`%s' excp=`%s'\n", + // 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=="friend class" || root->type=="friend struct" || + root->type=="friend union") + { + findMember(rootNav, + root->type+" "+ + root->name, + FALSE,FALSE); + + } + else if (!root->type.isEmpty()) + { + findMember(rootNav, + root->type+" "+ + root->inside+ + root->name+ + root->args+ + root->exception, + FALSE,isFunc); + } + else + { + findMember(rootNav, + root->inside+ + root->name+ + root->args+ + root->exception, + FALSE,isFunc); + } + } + else if (root->section==Entry::DEFINE_SEC && !root->relates.isEmpty()) + { + findMember(rootNav,root->name+root->args,FALSE,!root->args.isEmpty()); + } + else if (root->section==Entry::VARIABLEDOC_SEC) + { + //printf("Documentation for variable %s found\n",root->name.data()); + //if (!root->relates.isEmpty()) printf(" Relates %s\n",root->relates.data()); + findMember(rootNav,root->name,FALSE,FALSE); + } + else + { + // skip section + //printf("skip section\n"); + } +} + +static void findMemberDocumentation(EntryNav *rootNav) +{ + if (rootNav->section()==Entry::MEMBERDOC_SEC || + rootNav->section()==Entry::OVERLOADDOC_SEC || + rootNav->section()==Entry::FUNCTION_SEC || + rootNav->section()==Entry::VARIABLE_SEC || + rootNav->section()==Entry::VARIABLEDOC_SEC || + rootNav->section()==Entry::DEFINE_SEC + ) + { + rootNav->loadEntry(g_storage); + + filterMemberDocumentation(rootNav); + + rootNav->releaseEntry(); + } + if (rootNav->children()) + { + EntryNavListIterator eli(*rootNav->children()); + EntryNav *e; + for (;(e=eli.current());++eli) + { + if (e->section()!=Entry::ENUM_SEC) findMemberDocumentation(e); + } + } +} + +//---------------------------------------------------------------------- + +static void findObjCMethodDefinitions(EntryNav *rootNav) +{ + if (rootNav->children()) + { + EntryNavListIterator eli(*rootNav->children()); + EntryNav *objCImplNav; + for (;(objCImplNav=eli.current());++eli) + { + if (objCImplNav->section()==Entry::OBJCIMPL_SEC && objCImplNav->children()) + { + EntryNavListIterator seli(*objCImplNav->children()); + EntryNav *objCMethodNav; + for (;(objCMethodNav=seli.current());++seli) + { + if (objCMethodNav->section()==Entry::FUNCTION_SEC) + { + objCMethodNav->loadEntry(g_storage); + Entry *objCMethod = objCMethodNav->entry(); + + //Printf(" Found ObjC method definition %s\n",objCMethod->name.data()); + findMember(objCMethodNav, objCMethod->type+" "+objCImplNav->name()+"::"+ + objCMethod->name+" "+objCMethod->args, FALSE,TRUE); + objCMethod->section=Entry::EMPTY_SEC; + + objCMethodNav->releaseEntry(); + } + } + } + } + } +} + +//---------------------------------------------------------------------- +// find and add the enumeration to their classes, namespaces or files + +static void findEnums(EntryNav *rootNav) +{ + if (rootNav->section()==Entry::ENUM_SEC) + // non anonymous enumeration + { + rootNav->loadEntry(g_storage); + Entry *root = rootNav->entry(); + + MemberDef *md=0; + ClassDef *cd=0; + FileDef *fd=0; + NamespaceDef *nd=0; + MemberNameSDict *mnsd=0; + bool isGlobal; + bool isRelated=FALSE; + bool isMemberOf=FALSE; + //printf("Found enum with name `%s' relates=%s\n",root->name.data(),root->relates.data()); + int i; + + QCString name; + QCString scope; + + if ((i=root->name.findRev("::"))!=-1) // scope is specified + { + scope=root->name.left(i); // extract scope + name=root->name.right(root->name.length()-i-2); // extract name + if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope); + } + else // no scope, check the scope in which the docs where found + { + if (( rootNav->parent()->section() & Entry::SCOPE_MASK ) + && !rootNav->parent()->name().isEmpty() + ) // found enum docs inside a compound + { + scope=rootNav->parent()->name(); + if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope); + } + name=root->name; + } + + if (!root->relates.isEmpty()) + { // related member, prefix user specified scope + isRelated=TRUE; + isMemberOf=(root->relatesType == MemberOf); + if (getClass(root->relates)==0 && !scope.isEmpty()) + scope=mergeScopes(scope,root->relates); + else + scope=root->relates.copy(); + if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope); + } + + if (cd && !name.isEmpty()) // found a enum inside a compound + { + //printf("Enum `%s'::`%s'\n",cd->name(),name.data()); + fd=0; + mnsd=Doxygen::memberNameSDict; + isGlobal=FALSE; + } + else if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@') // found enum inside namespace + { + mnsd=Doxygen::functionNameSDict; + isGlobal=TRUE; + } + else // found a global enum + { + fd=rootNav->fileDef(); + mnsd=Doxygen::functionNameSDict; + isGlobal=TRUE; + } + + if (!name.isEmpty()) + { + // new enum type + md = new MemberDef( + root->fileName,root->startLine, + 0,name,0,0, + root->protection,Normal,FALSE, + isMemberOf ? Foreign : isRelated ? Related : Member, + MemberDef::Enumeration, + 0,0); + md->setTagInfo(rootNav->tagInfo()); + md->setLanguage(root->lang); + if (!isGlobal) md->setMemberClass(cd); else md->setFileDef(fd); + md->setBodySegment(root->bodyLine,root->endBodyLine); + md->setBodyDef(rootNav->fileDef()); + //printf("Enum %s definition at line %d of %s: protection=%d\n", + // root->name.data(),root->bodyLine,root->fileName.data(),root->protection); + md->addSectionsToDefinition(root->anchors); + md->setMemberGroupId(root->mGrpId); + md->enableCallGraph(root->callGraph); + md->enableCallerGraph(root->callerGraph); + //printf("%s::setRefItems(%d)\n",md->name().data(),root->sli?root->sli->count():-1); + md->setRefItems(root->sli); + //printf("found enum %s nd=%p\n",name.data(),nd); + bool defSet=FALSE; + if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@') + { + if (isRelated || Config_getBool("HIDE_SCOPE_NAMES")) + { + md->setDefinition(name); + } + else + { + md->setDefinition(nd->name()+"::"+name); + } + //printf("definition=%s\n",md->definition()); + defSet=TRUE; + md->setNamespace(nd); + nd->insertMember(md); + } + + // even if we have already added the enum to a namespace, we still + // also want to add it to other appropriate places such as file + // or class. + if (isGlobal) + { + if (!defSet) md->setDefinition(name); + if (fd==0 && rootNav->parent()) + { + fd=rootNav->parent()->fileDef(); + } + if (fd) + { + md->setFileDef(fd); + fd->insertMember(md); + } + } + else if (cd) + { + if (isRelated || Config_getBool("HIDE_SCOPE_NAMES")) + { + md->setDefinition(name); + } + else + { + md->setDefinition(cd->name()+"::"+name); + } + cd->insertMember(md); + cd->insertUsedFile(root->fileName); + } + md->setDocumentation(root->doc,root->docFile,root->docLine); + md->setDocsForDefinition(!root->proto); + md->setBriefDescription(root->brief,root->briefFile,root->briefLine); + md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine); + + //printf("Adding member=%s\n",md->name().data()); + MemberName *mn; + if ((mn=(*mnsd)[name])) + { + // this is used if the same enum is in multiple namespaces/classes + mn->append(md); + } + else // new enum name + { + mn = new MemberName(name); + mn->append(md); + mnsd->append(name,mn); + //printf("add %s to new memberName. Now %d members\n", + // name.data(),mn->count()); + } + addMemberToGroups(root,md); + +#if 0 + if (rootNav->children()) + { + EntryNavListIterator eli(*rootNav->children()); + EntryNav *e; + for (;(e=eli.current());++eli) + { + //printf("e->name=%s isRelated=%d\n",e->name.data(),isRelated); + MemberName *fmn=0; + MemberNameSDict *emnsd = isRelated ? Doxygen::functionNameSDict : mnsd; + if (!e->name().isEmpty() && (fmn=(*emnsd)[e->name()])) + // get list of members with the same name as the field + { + MemberNameIterator fmni(*fmn); + MemberDef *fmd; + for (fmni.toFirst(); (fmd=fmni.current()) ; ++fmni) + { + if (fmd->isEnumValue()) + { + //printf("found enum value with same name\n"); + if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@') + { + NamespaceDef *fnd=fmd->getNamespaceDef(); + if (fnd==nd) // enum value is inside a namespace + { + md->insertEnumField(fmd); + fmd->setEnumScope(md); + } + } + else if (isGlobal) + { + FileDef *ffd=fmd->getFileDef(); + if (ffd==fd) // enum value has file scope + { + md->insertEnumField(fmd); + fmd->setEnumScope(md); + } + } + else if (isRelated && cd) // reparent enum value to + // match the enum's scope + { + md->insertEnumField(fmd); // add field def to list + fmd->setEnumScope(md); // cross ref with enum name + fmd->setEnumClassScope(cd); // cross ref with enum name + fmd->setOuterScope(cd); + fmd->makeRelated(); + cd->insertMember(fmd); + } + else + { + ClassDef *fcd=fmd->getClassDef(); + if (fcd==cd) // enum value is inside a class + { + //printf("Inserting enum field %s in enum scope %s\n", + // fmd->name().data(),md->name().data()); + md->insertEnumField(fmd); // add field def to list + fmd->setEnumScope(md); // cross ref with enum name + } + } + } + } + } + } + } +#endif + } + + rootNav->releaseEntry(); + } + else + { + RECURSE_ENTRYTREE(findEnums,rootNav); + } +} + +//---------------------------------------------------------------------- + +static void addEnumValuesToEnums(EntryNav *rootNav) +{ + if (rootNav->section()==Entry::ENUM_SEC) + // non anonymous enumeration + { + rootNav->loadEntry(g_storage); + Entry *root = rootNav->entry(); + + ClassDef *cd=0; + FileDef *fd=0; + NamespaceDef *nd=0; + MemberNameSDict *mnsd=0; + bool isGlobal; + bool isRelated=FALSE; + //printf("Found enum with name `%s' relates=%s\n",root->name.data(),root->relates.data()); + int i; + + QCString name; + QCString scope; + + if ((i=root->name.findRev("::"))!=-1) // scope is specified + { + scope=root->name.left(i); // extract scope + name=root->name.right(root->name.length()-i-2); // extract name + if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope); + } + else // no scope, check the scope in which the docs where found + { + if (( rootNav->parent()->section() & Entry::SCOPE_MASK ) + && !rootNav->parent()->name().isEmpty() + ) // found enum docs inside a compound + { + scope=rootNav->parent()->name(); + if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope); + } + name=root->name; + } + + if (!root->relates.isEmpty()) + { // related member, prefix user specified scope + isRelated=TRUE; + if (getClass(root->relates)==0 && !scope.isEmpty()) + scope=mergeScopes(scope,root->relates); + else + scope=root->relates.copy(); + if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope); + } + + if (cd && !name.isEmpty()) // found a enum inside a compound + { + //printf("Enum in class `%s'::`%s'\n",cd->name().data(),name.data()); + fd=0; + mnsd=Doxygen::memberNameSDict; + isGlobal=FALSE; + } + else if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@') // found enum inside namespace + { + //printf("Enum in namespace `%s'::`%s'\n",nd->name().data(),name.data()); + mnsd=Doxygen::functionNameSDict; + isGlobal=TRUE; + } + else // found a global enum + { + fd=rootNav->fileDef(); + //printf("Enum in file `%s': `%s'\n",fd->name().data(),name.data()); + mnsd=Doxygen::functionNameSDict; + isGlobal=TRUE; + } + + if (!name.isEmpty()) + { + //printf("** name=%s\n",name.data()); + MemberName *mn = mnsd->find(name); // for all members with this name + if (mn) + { + MemberNameIterator mni(*mn); + MemberDef *md; + for (mni.toFirst(); (md=mni.current()) ; ++mni) // for each enum in this list + { + if (md->isEnumerate() && rootNav->children()) + { + //printf(" enum with %d children\n",rootNav->children()->count()); + EntryNavListIterator eli(*rootNav->children()); // for each enum value + EntryNav *e; + for (;(e=eli.current());++eli) + { + SrcLangExt sle; + if ( + (sle=rootNav->lang())==SrcLangExt_CSharp || + sle==SrcLangExt_Java || + sle==SrcLangExt_XML + ) + { + // Unlike C++, for C# & Java enum values are only inside the enum + // scope, so we must create them here and only add them to the + // enum + e->loadEntry(g_storage); + Entry *root = e->entry(); + //printf("md->qualifiedName()=%s rootNav->name()=%s\n", + // md->qualifiedName().data(),rootNav->name().data()); + if (md->qualifiedName()==substitute(rootNav->name(),"::",".")) // enum value scope matches that of the enum + { + MemberDef *fmd=new MemberDef( + root->fileName,root->startLine, + root->type,root->name,root->args,0, + Public, Normal,root->stat,Member, + MemberDef::EnumValue,0,0); + if (md->getClassDef()) fmd->setMemberClass(md->getClassDef()); + else if (md->getNamespaceDef()) fmd->setNamespace(md->getNamespaceDef()); + else if (md->getFileDef()) fmd->setFileDef(md->getFileDef()); + fmd->setOuterScope(md->getOuterScope()); + fmd->setTagInfo(e->tagInfo()); + fmd->setLanguage(root->lang); + fmd->setDocumentation(root->doc,root->docFile,root->docLine); + fmd->setBriefDescription(root->brief,root->briefFile,root->briefLine); + fmd->addSectionsToDefinition(root->anchors); + fmd->setInitializer(root->initializer); + fmd->setMaxInitLines(root->initLines); + fmd->setMemberGroupId(root->mGrpId); + fmd->setExplicitExternal(root->explicitExternal); + fmd->setRefItems(root->sli); + if (fmd) + { + md->insertEnumField(fmd); + fmd->setEnumScope(md); + } + } + e->releaseEntry(); + } + else + { + //printf("e->name=%s isRelated=%d\n",e->name().data(),isRelated); + MemberName *fmn=0; + MemberNameSDict *emnsd = isRelated ? Doxygen::functionNameSDict : mnsd; + if (!e->name().isEmpty() && (fmn=(*emnsd)[e->name()])) + // get list of members with the same name as the field + { + MemberNameIterator fmni(*fmn); + MemberDef *fmd; + for (fmni.toFirst(); (fmd=fmni.current()) ; ++fmni) + { + if (fmd->isEnumValue() && fmd->getOuterScope()==md->getOuterScope()) // in same scope + { + //printf("found enum value with same name %s in scope %s\n", + // fmd->name().data(),fmd->getOuterScope()->name().data()); + if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@') + { + NamespaceDef *fnd=fmd->getNamespaceDef(); + if (fnd==nd) // enum value is inside a namespace + { + md->insertEnumField(fmd); + fmd->setEnumScope(md); + } + } + else if (isGlobal) + { + FileDef *ffd=fmd->getFileDef(); + if (ffd==fd) // enum value has file scope + { + md->insertEnumField(fmd); + fmd->setEnumScope(md); + } + } + else if (isRelated && cd) // reparent enum value to + // match the enum's scope + { + md->insertEnumField(fmd); // add field def to list + fmd->setEnumScope(md); // cross ref with enum name + fmd->setEnumClassScope(cd); // cross ref with enum name + fmd->setOuterScope(cd); + fmd->makeRelated(); + cd->insertMember(fmd); + } + else + { + ClassDef *fcd=fmd->getClassDef(); + if (fcd==cd) // enum value is inside a class + { + //printf("Inserting enum field %s in enum scope %s\n", + // fmd->name().data(),md->name().data()); + md->insertEnumField(fmd); // add field def to list + fmd->setEnumScope(md); // cross ref with enum name + } + } + } + } + } + } + } + } + } + } + } + + rootNav->releaseEntry(); + } + else + { + RECURSE_ENTRYTREE(addEnumValuesToEnums,rootNav); + } +} + + +//---------------------------------------------------------------------- +// find the documentation blocks for the enumerations + +static void findEnumDocumentation(EntryNav *rootNav) +{ + if (rootNav->section()==Entry::ENUMDOC_SEC + && !rootNav->name().isEmpty() + && rootNav->name().at(0)!='@' // skip anonymous enums + ) + { + rootNav->loadEntry(g_storage); + Entry *root = rootNav->entry(); + + //printf("Found docs for enum with name `%s' in context %s\n", + // root->name.data(),root->parent->name.data()); + int i; + QCString name; + QCString scope; + if ((i=root->name.findRev("::"))!=-1) // scope is specified as part of the name + { + name=root->name.right(root->name.length()-i-2); // extract name + scope=root->name.left(i); // extract scope + //printf("Scope=`%s' Name=`%s'\n",scope.data(),name.data()); + } + else // just the name + { + name=root->name; + } + if (( rootNav->parent()->section() & Entry::SCOPE_MASK ) + && !rootNav->parent()->name().isEmpty() + ) // found enum docs inside a compound + { + if (!scope.isEmpty()) scope.prepend("::"); + scope.prepend(rootNav->parent()->name()); + } + ClassDef *cd=getClass(scope); + + if (!name.isEmpty()) + { + bool found=FALSE; + if (cd) + { + //printf("Enum: scope=`%s' name=`%s'\n",cd->name(),name.data()); + QCString className=cd->name().copy(); + MemberName *mn=Doxygen::memberNameSDict->find(name); + if (mn) + { + MemberNameIterator mni(*mn); + MemberDef *md; + for (mni.toFirst();(md=mni.current()) && !found;++mni) + { + ClassDef *cd=md->getClassDef(); + if (cd && cd->name()==className && md->isEnumerate()) + { + // documentation outside a compound overrides the documentation inside it +#if 0 + if (!md->documentation() || rootNav->parent()->name().isEmpty()) +#endif + { + md->setDocumentation(root->doc,root->docFile,root->docLine); + md->setDocsForDefinition(!root->proto); + } + + // brief descriptions inside a compound override the documentation + // outside it +#if 0 + if (!md->briefDescription() || !rootNav->parent()->name().isEmpty()) +#endif + { + md->setBriefDescription(root->brief,root->briefFile,root->briefLine); + } + + if (!md->inbodyDocumentation() || !rootNav->parent()->name().isEmpty()) + { + md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine); + } + + if (root->mGrpId!=-1 && md->getMemberGroupId()==-1) + { + md->setMemberGroupId(root->mGrpId); + } + + md->addSectionsToDefinition(root->anchors); + md->setRefItems(root->sli); + + GroupDef *gd=md->getGroupDef(); + if (gd==0 &&root->groups->first()!=0) // member not grouped but out-of-line documentation is + { + addMemberToGroups(root,md); + } + + found=TRUE; + } + } + } + else + { + //printf("MemberName %s not found!\n",name.data()); + } + } + else // enum outside class + { + //printf("Enum outside class: %s grpId=%d\n",name.data(),root->mGrpId); + MemberName *mn=Doxygen::functionNameSDict->find(name); + if (mn) + { + MemberNameIterator mni(*mn); + MemberDef *md; + for (mni.toFirst();(md=mni.current()) && !found;++mni) + { + if (md->isEnumerate()) + { + md->setDocumentation(root->doc,root->docFile,root->docLine); + md->setDocsForDefinition(!root->proto); + md->setBriefDescription(root->brief,root->briefFile,root->briefLine); + md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine); + md->addSectionsToDefinition(root->anchors); + md->setMemberGroupId(root->mGrpId); + + GroupDef *gd=md->getGroupDef(); + if (gd==0 && root->groups->first()!=0) // member not grouped but out-of-line documentation is + { + addMemberToGroups(root,md); + } + + found=TRUE; + } + } + } + } + if (!found) + { + warn(root->fileName,root->startLine, + "warning: Documentation for undefined enum `%s' found.", + name.data() + ); + } + } + + rootNav->releaseEntry(); + } + RECURSE_ENTRYTREE(findEnumDocumentation,rootNav); +} + +// seach for each enum (member or function) in mnl if it has documented +// enum values. +static void findDEV(const MemberNameSDict &mnsd) +{ + MemberName *mn; + MemberNameSDict::Iterator mnli(mnsd); + // for each member name + for (mnli.toFirst();(mn=mnli.current());++mnli) + { + MemberDef *md; + MemberNameIterator mni(*mn); + // for each member definition + for (mni.toFirst();(md=mni.current());++mni) + { + if (md->isEnumerate()) // member is an enum + { + LockingPtr<MemberList> fmdl = md->enumFieldList(); + int documentedEnumValues=0; + if (fmdl!=0) // enum has values + { + MemberListIterator fmni(*fmdl); + MemberDef *fmd; + // for each enum value + for (fmni.toFirst();(fmd=fmni.current());++fmni) + { + if (fmd->isLinkableInProject()) documentedEnumValues++; + } + } + // at least one enum value is documented + if (documentedEnumValues>0) md->setDocumentedEnumValues(TRUE); + } + } + } +} + +// seach for each enum (member or function) if it has documented enum +// values. +static void findDocumentedEnumValues() +{ + findDEV(*Doxygen::memberNameSDict); + findDEV(*Doxygen::functionNameSDict); +} + +//---------------------------------------------------------------------- + +static void addMembersToIndex() +{ + MemberName *mn; + MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict); + // for each member name + for (mnli.toFirst();(mn=mnli.current());++mnli) + { + MemberDef *md; + MemberNameIterator mni(*mn); + // for each member definition + for (mni.toFirst();(md=mni.current());++mni) + { + addClassMemberNameToIndex(md); + } + } + MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict); + // for each member name + for (fnli.toFirst();(mn=fnli.current());++fnli) + { + MemberDef *md; + MemberNameIterator mni(*mn); + // for each member definition + for (mni.toFirst();(md=mni.current());++mni) + { + if (md->getNamespaceDef()) + { + addNamespaceMemberNameToIndex(md); + } + else + { + addFileMemberNameToIndex(md); + } + } + } +} + +//---------------------------------------------------------------------- +// computes the relation between all members. For each member `m' +// the members that override the implementation of `m' are searched and +// the member that `m' overrides is searched. + +static void computeMemberRelations() +{ + MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict); + MemberName *mn; + for ( ; (mn=mnli.current()) ; ++mnli ) // for each member name + { + MemberNameIterator mdi(*mn); + MemberDef *md; + for ( ; (md=mdi.current()) ; ++mdi ) // for each member with a specific name + { + MemberDef *bmd = mn->first(); // for each other member with the same name + while (bmd) + { + ClassDef *mcd = md->getClassDef(); + if (mcd && mcd->baseClasses()) + { + ClassDef *bmcd = bmd->getClassDef(); + //printf("Check relation between `%s'::`%s' (%p) and `%s'::`%s' (%p)\n", + // mcd->name().data(),md->name().data(),md, + // bmcd->name().data(),bmd->name().data(),bmd + // ); + if (md!=bmd && bmcd && mcd && bmcd!=mcd && mcd->isBaseClass(bmcd,TRUE)) + { + //printf(" derived scope\n"); + LockingPtr<ArgumentList> bmdAl = bmd->argumentList(); + LockingPtr<ArgumentList> mdAl = md->argumentList(); + //printf(" Base argList=`%s'\n Super argList=`%s'\n", + // argListToString(bmdAl.pointer()).data(), + // argListToString(mdAl.pointer()).data() + // ); + if ( + matchArguments2(bmd->getOuterScope(),bmd->getFileDef(),bmdAl.pointer(), + md->getOuterScope(), md->getFileDef(), mdAl.pointer(), + TRUE + ) + ) + { + //printf(" match found!\n"); + if (mcd && bmcd && + mcd->isLinkable() && bmcd->isLinkable() + ) + { + MemberDef *rmd; + if ((rmd=md->reimplements())==0 || + minClassDistance(mcd,bmcd)<minClassDistance(mcd,rmd->getClassDef()) + ) + { + //printf("setting (new) reimplements member\n"); + md->setReimplements(bmd); + } + //printf("%s: add reimplements member %s\n",mcd->name().data(),bmcd->name().data()); + //md->setImplements(bmd); + //printf("%s: add reimplementedBy member %s\n",bmcd->name().data(),mcd->name().data()); + bmd->insertReimplementedBy(md); + } + } + } + } + bmd = mn->next(); + } + } + } +} + + +//---------------------------------------------------------------------------- +//static void computeClassImplUsageRelations() +//{ +// ClassDef *cd; +// ClassSDict::Iterator cli(*Doxygen::classSDict); +// for (;(cd=cli.current());++cli) +// { +// cd->determineImplUsageRelation(); +// } +//} + +//---------------------------------------------------------------------------- + +static void createTemplateInstanceMembers() +{ + ClassSDict::Iterator cli(*Doxygen::classSDict); + ClassDef *cd; + // for each class + for (cli.toFirst();(cd=cli.current());++cli) + { + // 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()); + } + } + } +} + +//---------------------------------------------------------------------------- + +static void mergeCategories() +{ + ClassDef *cd; + ClassSDict::Iterator cli(*Doxygen::classSDict); + // merge members of categories into the class they extend + for (cli.toFirst();(cd=cli.current());++cli) + { + int i=cd->name().find('('); + if (i!=-1) // it is an Objective-C category + { + QCString baseName=cd->name().left(i); + ClassDef *baseClass=Doxygen::classSDict->find(baseName); + if (baseClass) + { + //printf("*** merging members of category %s into %s\n", + // cd->name().data(),baseClass->name().data()); + baseClass->mergeCategory(cd); + } + } + } +} + +// builds the list of all members for each class + +static void buildCompleteMemberLists() +{ + ClassDef *cd; + ClassSDict::Iterator cli(*Doxygen::classSDict); + // merge the member list of base classes into the inherited classes. + for (cli.toFirst();(cd=cli.current());++cli) + { + if (// !cd->isReference() && // not an external class + cd->subClasses()==0 && // is a root of the hierarchy + cd->baseClasses()) // and has at least one base class + { + //printf("*** merging members for %s\n",cd->name().data()); + cd->mergeMembers(); + } + } + // now sort the member list of all classes. + for (cli.toFirst();(cd=cli.current());++cli) + { + if (cd->memberNameInfoSDict()) cd->memberNameInfoSDict()->sort(); + } +} + +//---------------------------------------------------------------------------- + +static void generateFileSources() +{ + if (documentedHtmlFiles==0) return; + if (Doxygen::inputNameList->count()>0) + { + FileNameListIterator fnli(*Doxygen::inputNameList); + FileName *fn; + for (;(fn=fnli.current());++fnli) + { + FileNameIterator fni(*fn); + FileDef *fd; + for (;(fd=fni.current());++fni) + { + if (fd->generateSourceFile()) // sources need to be shown in the output + { + msg("Generating code for file %s...\n",fd->docName().data()); + fd->writeSource(*g_outputList); + } + else if (!fd->isReference() && Doxygen::parseSourcesNeeded) + // we needed to parse the sources even if we do not show them + { + msg("Parsing code for file %s...\n",fd->docName().data()); + fd->parseSource(); + } + } + } + } +} + +//---------------------------------------------------------------------------- + +static void generateFileDocs() +{ + if (documentedHtmlFiles==0) return; + + if (Doxygen::inputNameList->count()>0) + { + FileNameListIterator fnli(*Doxygen::inputNameList); + FileName *fn; + for (fnli.toFirst();(fn=fnli.current());++fnli) + { + FileNameIterator fni(*fn); + FileDef *fd; + for (fni.toFirst();(fd=fni.current());++fni) + { + bool doc = fd->isLinkableInProject(); + if (doc) + { + msg("Generating docs for file %s...\n",fd->docName().data()); + fd->writeDocumentation(*g_outputList); + } + } + } + } +} + +//---------------------------------------------------------------------------- + +static void addSourceReferences() +{ + // add source references for class definitions + ClassSDict::Iterator cli(*Doxygen::classSDict); + ClassDef *cd=0; + for (cli.toFirst();(cd=cli.current());++cli) + { + FileDef *fd=cd->getBodyDef(); + if (fd && cd->isLinkableInProject() && cd->getStartBodyLine()!=-1) + { + fd->addSourceRef(cd->getStartBodyLine(),cd,0); + } + } + // add source references for namespace definitions + NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict); + NamespaceDef *nd=0; + for (nli.toFirst();(nd=nli.current());++nli) + { + FileDef *fd=nd->getBodyDef(); + if (fd && nd->isLinkableInProject() && nd->getStartBodyLine()!=-1) + { + fd->addSourceRef(nd->getStartBodyLine(),nd,0); + } + } + + // add source references for member names + MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict); + MemberName *mn=0; + for (mnli.toFirst();(mn=mnli.current());++mnli) + { + MemberNameIterator mni(*mn); + MemberDef *md=0; + for (mni.toFirst();(md=mni.current());++mni) + { + //printf("class member %s: def=%s body=%d link?=%d\n", + // md->name().data(), + // md->getBodyDef()?md->getBodyDef()->name().data():"<none>", + // md->getStartBodyLine(),md->isLinkableInProject()); + FileDef *fd=md->getBodyDef(); + if (fd && + md->getStartBodyLine()!=-1 && + md->isLinkableInProject() && + (fd->generateSourceFile() || Doxygen::parseSourcesNeeded) + ) + { + //printf("Found member `%s' in file `%s' at line `%d' def=%s\n", + // md->name().data(),fd->name().data(),md->getStartBodyLine(),md->getOuterScope()->name().data()); + fd->addSourceRef(md->getStartBodyLine(),md->getOuterScope(),md); + } + } + } + MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict); + for (fnli.toFirst();(mn=fnli.current());++fnli) + { + MemberNameIterator mni(*mn); + MemberDef *md=0; + for (mni.toFirst();(md=mni.current());++mni) + { + FileDef *fd=md->getBodyDef(); + //printf("member %s body=[%d,%d] fd=%p link=%d parseSources=%d\n", + // md->name().data(), + // md->getStartBodyLine(),md->getEndBodyLine(),fd, + // md->isLinkableInProject(), + // Doxygen::parseSourcesNeeded); + if (fd && + md->getStartBodyLine()!=-1 && + md->isLinkableInProject() && + (fd->generateSourceFile() || Doxygen::parseSourcesNeeded) + ) + { + //printf("Found member `%s' in file `%s' at line `%d' def=%s\n", + // md->name().data(),fd->name().data(),md->getStartBodyLine(),md->getOuterScope()->name().data()); + fd->addSourceRef(md->getStartBodyLine(),md->getOuterScope(),md); + } + } + } +} + +//---------------------------------------------------------------------------- + +static void sortMemberLists() +{ + // sort class member lists + ClassSDict::Iterator cli(*Doxygen::classSDict); + ClassDef *cd=0; + for (cli.toFirst();(cd=cli.current());++cli) + { + cd->sortMemberLists(); + } + + // sort namespace member lists + NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict); + NamespaceDef *nd=0; + for (nli.toFirst();(nd=nli.current());++nli) + { + nd->sortMemberLists(); + } + + // sort file member lists + FileNameListIterator fnli(*Doxygen::inputNameList); + FileName *fn; + for (;(fn=fnli.current());++fnli) + { + FileNameIterator fni(*fn); + FileDef *fd; + for (;(fd=fni.current());++fni) + { + fd->sortMemberLists(); + } + } + + // sort group member lists + GroupSDict::Iterator gli(*Doxygen::groupSDict); + GroupDef *gd; + for (gli.toFirst();(gd=gli.current());++gli) + { + gd->sortMemberLists(); + } +} + +//---------------------------------------------------------------------------- +// generate the documentation of all classes + +static void generateClassList(ClassSDict &classSDict) +{ + ClassSDict::Iterator cli(classSDict); + for ( ; cli.current() ; ++cli ) + { + ClassDef *cd=cli.current(); + + //printf("cd=%s getOuterScope=%p global=%p\n",cd->name().data(),cd->getOuterScope(),Doxygen::globalScope); + if ((cd->getOuterScope()==0 || // <-- should not happen, but can if we read an old tag file + cd->getOuterScope()==Doxygen::globalScope // only look at global classes + ) && !cd->isHidden() && !cd->isEmbeddedInOuterScope() + ) + { + // skip external references, anonymous compounds and + // template instances + if ( cd->isLinkableInProject() && cd->templateMaster()==0) + { + msg("Generating docs for compound %s...\n",cd->name().data()); + + cd->writeDocumentation(*g_outputList); + cd->writeMemberList(*g_outputList); + } + // even for undocumented classes, the inner classes can be documented. + cd->writeDocumentationForInnerClasses(*g_outputList); + } + } +} + +static void generateClassDocs() +{ + generateClassList(*Doxygen::classSDict); + generateClassList(*Doxygen::hiddenClasses); +} + +//---------------------------------------------------------------------------- + +static void inheritDocumentation() +{ + MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict); + MemberName *mn; + //int count=0; + for (;(mn=mnli.current());++mnli) + { + MemberNameIterator mni(*mn); + MemberDef *md; + for (;(md=mni.current());++mni) + { + //printf("%04d Member `%s'\n",count++,md->name().data()); + if (md->documentation().isEmpty() && md->briefDescription().isEmpty()) + { // no documentation yet + MemberDef *bmd = md->reimplements(); + while (bmd && bmd->documentation().isEmpty() && + bmd->briefDescription().isEmpty() + ) + { // search up the inheritance tree for a documentation member + //printf("bmd=%s class=%s\n",bmd->name().data(),bmd->getClassDef()->name().data()); + bmd = bmd->reimplements(); + } + if (bmd) // copy the documentation from the reimplemented member + { + md->setInheritsDocsFrom(bmd); + md->setDocumentation(bmd->documentation(),bmd->docFile(),bmd->docLine()); + md->setDocsForDefinition(bmd->isDocsForDefinition()); + md->setBriefDescription(bmd->briefDescription(),bmd->briefFile(),bmd->briefLine()); + md->copyArgumentNames(bmd); + md->setInbodyDocumentation(bmd->inbodyDocumentation(),bmd->inbodyFile(),bmd->inbodyLine()); + } + } + } + } +} + +//---------------------------------------------------------------------------- + +static void combineUsingRelations() +{ + // for each file + FileNameListIterator fnli(*Doxygen::inputNameList); + FileName *fn; + for (fnli.toFirst();(fn=fnli.current());++fnli) + { + FileNameIterator fni(*fn); + FileDef *fd; + for (fni.toFirst();(fd=fni.current());++fni) + { + fd->visited=FALSE; + } + } + for (fnli.toFirst();(fn=fnli.current());++fnli) + { + FileNameIterator fni(*fn); + FileDef *fd; + for (fni.toFirst();(fd=fni.current());++fni) + { + fd->combineUsingRelations(); + } + } + + // for each namespace + NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict); + NamespaceDef *nd; + for (nli.toFirst() ; (nd=nli.current()) ; ++nli ) + { + nd->visited=FALSE; + } + for (nli.toFirst() ; (nd=nli.current()) ; ++nli ) + { + nd->combineUsingRelations(); + } +} + +//---------------------------------------------------------------------------- + +static void addMembersToMemberGroup() +{ + // for each class + ClassSDict::Iterator cli(*Doxygen::classSDict); + ClassDef *cd; + for ( ; (cd=cli.current()) ; ++cli ) + { + cd->addMembersToMemberGroup(); + } + // for each file + FileName *fn=Doxygen::inputNameList->first(); + while (fn) + { + FileDef *fd=fn->first(); + while (fd) + { + fd->addMembersToMemberGroup(); + fd=fn->next(); + } + fn=Doxygen::inputNameList->next(); + } + // for each namespace + NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict); + NamespaceDef *nd; + for ( ; (nd=nli.current()) ; ++nli ) + { + nd->addMembersToMemberGroup(); + } + // for each group + GroupSDict::Iterator gli(*Doxygen::groupSDict); + GroupDef *gd; + for (gli.toFirst();(gd=gli.current());++gli) + { + gd->addMembersToMemberGroup(); + } +} + +//---------------------------------------------------------------------------- + +static void distributeMemberGroupDocumentation() +{ + // for each class + ClassSDict::Iterator cli(*Doxygen::classSDict); + ClassDef *cd; + for ( ; (cd=cli.current()) ; ++cli ) + { + cd->distributeMemberGroupDocumentation(); + } + // for each file + FileName *fn=Doxygen::inputNameList->first(); + while (fn) + { + FileDef *fd=fn->first(); + while (fd) + { + fd->distributeMemberGroupDocumentation(); + fd=fn->next(); + } + fn=Doxygen::inputNameList->next(); + } + // for each namespace + NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict); + NamespaceDef *nd; + for ( ; (nd=nli.current()) ; ++nli ) + { + nd->distributeMemberGroupDocumentation(); + } + // for each group + GroupSDict::Iterator gli(*Doxygen::groupSDict); + GroupDef *gd; + for (gli.toFirst();(gd=gli.current());++gli) + { + gd->distributeMemberGroupDocumentation(); + } +} + +//---------------------------------------------------------------------------- + +static void findSectionsInDocumentation() +{ + // for each class + ClassSDict::Iterator cli(*Doxygen::classSDict); + ClassDef *cd; + for ( ; (cd=cli.current()) ; ++cli ) + { + cd->findSectionsInDocumentation(); + } + // for each file + FileName *fn=Doxygen::inputNameList->first(); + while (fn) + { + FileDef *fd=fn->first(); + while (fd) + { + fd->findSectionsInDocumentation(); + fd=fn->next(); + } + fn=Doxygen::inputNameList->next(); + } + // for each namespace + NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict); + NamespaceDef *nd; + for ( ; (nd=nli.current()) ; ++nli ) + { + nd->findSectionsInDocumentation(); + } + // for each group + GroupSDict::Iterator gli(*Doxygen::groupSDict); + GroupDef *gd; + for (gli.toFirst();(gd=gli.current());++gli) + { + gd->findSectionsInDocumentation(); + } + // for each page + PageSDict::Iterator pdi(*Doxygen::pageSDict); + PageDef *pd=0; + for (pdi.toFirst();(pd=pdi.current());++pdi) + { + pd->findSectionsInDocumentation(); + } + if (Doxygen::mainPage) Doxygen::mainPage->findSectionsInDocumentation(); +} + +static void flushCachedTemplateRelations() +{ + // remove all references to classes from the cache + // as there can be new template instances in the inheritance path + // to this class. Optimization: only remove those classes that + // have inheritance instances as direct or indirect sub classes. + QCacheIterator<LookupInfo> ci(*Doxygen::lookupCache); + LookupInfo *li=0; + for (ci.toFirst();(li=ci.current());++ci) + { + if (li->classDef) + { + Doxygen::lookupCache->remove(ci.currentKey()); + } + } + // remove all cached typedef resolutions whose target is a + // template class as this may now be a template instance + MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict); + MemberName *fn; + for (;(fn=fnli.current());++fnli) // for each global function name + { + MemberNameIterator fni(*fn); + MemberDef *fmd; + for (;(fmd=fni.current());++fni) // for each function with that name + { + if (fmd->isTypedefValCached()) + { + ClassDef *cd = fmd->getCachedTypedefVal(); + if (cd->isTemplate()) fmd->invalidateTypedefValCache(); + } + } + } + MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict); + for (;(fn=mnli.current());++mnli) // for each class method name + { + MemberNameIterator mni(*fn); + MemberDef *fmd; + for (;(fmd=mni.current());++mni) // for each function with that name + { + if (fmd->isTypedefValCached()) + { + ClassDef *cd = fmd->getCachedTypedefVal(); + if (cd->isTemplate()) fmd->invalidateTypedefValCache(); + } + } + } +} + +//---------------------------------------------------------------------------- + +static void flushUnresolvedRelations() +{ + // Remove all unresolved references to classes from the cache. + // This is needed before resolving the inheritance relations, since + // it would otherwise not find the inheritance relation + // for C in the example below, as B::I was already found to be unresolvable + // (which is correct if you igore the inheritance relation between A and B). + // + // class A { class I {} }; + // class B : public A {}; + // class C : public B::I {}; + // + QCacheIterator<LookupInfo> ci(*Doxygen::lookupCache); + LookupInfo *li=0; + for (ci.toFirst();(li=ci.current());++ci) + { + if (li->classDef==0 && li->typeDef==0) + { + Doxygen::lookupCache->remove(ci.currentKey()); + } + } + + MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict); + MemberName *fn; + for (;(fn=fnli.current());++fnli) // for each global function name + { + MemberNameIterator fni(*fn); + MemberDef *fmd; + for (;(fmd=fni.current());++fni) // for each function with that name + { + fmd->invalidateCachedArgumentTypes(); + } + } + MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict); + for (;(fn=mnli.current());++mnli) // for each class method name + { + MemberNameIterator mni(*fn); + MemberDef *fmd; + for (;(fmd=mni.current());++mni) // for each function with that name + { + fmd->invalidateCachedArgumentTypes(); + } + } + +} + +//---------------------------------------------------------------------------- + +static void findDefineDocumentation(EntryNav *rootNav) +{ + if ((rootNav->section()==Entry::DEFINEDOC_SEC || + rootNav->section()==Entry::DEFINE_SEC) && !rootNav->name().isEmpty() + ) + { + rootNav->loadEntry(g_storage); + Entry *root = rootNav->entry(); + + //printf("found define `%s' `%s' brief=`%s' doc=`%s'\n", + // root->name.data(),root->args.data(),root->brief.data(),root->doc.data()); + + if (rootNav->tagInfo() && !root->name.isEmpty()) // define read from a tag file + { + MemberDef *md=new MemberDef("<tagfile>",1, + "#define",root->name,root->args,0, + Public,Normal,FALSE,Member,MemberDef::Define,0,0); + md->setTagInfo(rootNav->tagInfo()); + md->setLanguage(root->lang); + //printf("Searching for `%s' fd=%p\n",filePathName.data(),fd); + md->setFileDef(rootNav->parent()->fileDef()); + //printf("Adding member=%s\n",md->name().data()); + MemberName *mn; + if ((mn=Doxygen::functionNameSDict->find(root->name))) + { + mn->append(md); + } + else + { + mn = new MemberName(root->name); + mn->append(md); + Doxygen::functionNameSDict->append(root->name,mn); + } + } + MemberName *mn=Doxygen::functionNameSDict->find(root->name); + if (mn) + { + int count=0; + MemberDef *md=mn->first(); + while (md) + { + if (md->memberType()==MemberDef::Define) count++; + md=mn->next(); + } + if (count==1) + { + md=mn->first(); + while (md) + { + if (md->memberType()==MemberDef::Define) + { + md->setDocumentation(root->doc,root->docFile,root->docLine); + md->setDocsForDefinition(!root->proto); + md->setBriefDescription(root->brief,root->briefFile,root->briefLine); + if (md->inbodyDocumentation().isEmpty()) + { + md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine); + } + md->setBodySegment(root->bodyLine,root->endBodyLine); + md->setBodyDef(rootNav->fileDef()); + md->addSectionsToDefinition(root->anchors); + md->setMaxInitLines(root->initLines); + md->setRefItems(root->sli); + if (root->mGrpId!=-1) md->setMemberGroupId(root->mGrpId); + addMemberToGroups(root,md); + } + md=mn->next(); + } + } + else if (count>1 && + (!root->doc.isEmpty() || + !root->brief.isEmpty() || + root->bodyLine!=-1 + ) + ) + // multiple defines don't know where to add docs + // but maybe they are in different files together with their documentation + { + md=mn->first(); + while (md) + { + if (md->memberType()==MemberDef::Define) + { + FileDef *fd=md->getFileDef(); + if (fd && fd->absFilePath()==root->fileName) + // doc and define in the same file assume they belong together. + { +#if 0 + if (md->documentation().isEmpty()) +#endif + { + md->setDocumentation(root->doc,root->docFile,root->docLine); + md->setDocsForDefinition(!root->proto); + } +#if 0 + if (md->briefDescription().isEmpty()) +#endif + { + md->setBriefDescription(root->brief,root->briefFile,root->briefLine); + } + if (md->inbodyDocumentation().isEmpty()) + { + md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine); + } + md->setBodySegment(root->bodyLine,root->endBodyLine); + md->setBodyDef(rootNav->fileDef()); + md->addSectionsToDefinition(root->anchors); + md->setRefItems(root->sli); + md->setLanguage(root->lang); + if (root->mGrpId!=-1) md->setMemberGroupId(root->mGrpId); + addMemberToGroups(root,md); + } + } + md=mn->next(); + } + //warn("warning: define %s found in the following files:\n",root->name.data()); + //warn("Cannot determine where to add the documentation found " + // "at line %d of file %s. \n", + // root->startLine,root->fileName.data()); + } + } + else if (!root->doc.isEmpty() || !root->brief.isEmpty()) // define not found + { + static bool preEnabled = Config_getBool("ENABLE_PREPROCESSING"); + if (preEnabled) + { + warn(root->fileName,root->startLine, + "warning: documentation for unknown define %s found.\n", + root->name.data() + ); + } + else + { + warn(root->fileName,root->startLine, + "warning: found documented #define but ignoring it because " + "ENABLE_PREPROCESSING is NO.\n", + root->name.data() + ); + } + } + + rootNav->releaseEntry(); + } + RECURSE_ENTRYTREE(findDefineDocumentation,rootNav); +} + +//---------------------------------------------------------------------------- + +static void findDirDocumentation(EntryNav *rootNav) +{ + if (rootNav->section() == Entry::DIRDOC_SEC) + { + rootNav->loadEntry(g_storage); + Entry *root = rootNav->entry(); + + QCString normalizedName = root->name; + normalizedName = substitute(normalizedName,"\\","/"); + //printf("root->docFile=%s normalizedName=%s\n", + // root->docFile.data(),normalizedName.data()); + if (root->docFile==normalizedName) // current dir? + { + int lastSlashPos=normalizedName.findRev('/'); + if (lastSlashPos!=-1) // strip file name + { + normalizedName=normalizedName.left(lastSlashPos); + } + } + if (normalizedName.at(normalizedName.length()-1)!='/') + { + normalizedName+='/'; + } + DirDef *dir,*matchingDir=0; + SDict<DirDef>::Iterator sdi(*Doxygen::directories); + for (sdi.toFirst();(dir=sdi.current());++sdi) + { + //printf("Dir: %s<->%s\n",dir->name().data(),normalizedName.data()); + if (dir->name().right(normalizedName.length())==normalizedName) + { + if (matchingDir) + { + warn(root->fileName,root->startLine, + "warning: \\dir command matches multiple directories.\n" + " Applying the command for directory %s\n" + " Ignoring the command for directory %s\n", + matchingDir->name().data(),dir->name().data() + ); + } + else + { + matchingDir=dir; + } + } + } + if (matchingDir) + { + //printf("Match for with dir %s\n",matchingDir->name().data()); + matchingDir->setBriefDescription(root->brief,root->briefFile,root->briefLine); + matchingDir->setDocumentation(root->doc,root->docFile,root->docLine); + matchingDir->setRefItems(root->sli); + addDirToGroups(root,matchingDir); + } + else + { + warn(root->fileName,root->startLine,"warning: No matching " + "directory found for command \\dir %s\n",normalizedName.data()); + } + rootNav->releaseEntry(); + } + RECURSE_ENTRYTREE(findDirDocumentation,rootNav); +} + + +//---------------------------------------------------------------------------- +// create a (sorted) list of separate documentation pages + +static void buildPageList(EntryNav *rootNav) +{ + if (rootNav->section() == Entry::PAGEDOC_SEC) + { + rootNav->loadEntry(g_storage); + Entry *root = rootNav->entry(); + + if (!root->name.isEmpty()) + { + addRelatedPage(rootNav); + } + + rootNav->releaseEntry(); + } + else if (rootNav->section() == Entry::MAINPAGEDOC_SEC) + { + rootNav->loadEntry(g_storage); + Entry *root = rootNav->entry(); + + QCString title=root->args.stripWhiteSpace(); + if (title.isEmpty()) title=theTranslator->trMainPage(); + //QCString name = Config_getBool("GENERATE_TREEVIEW")?"main":"index"; + QCString name = "index"; + addRefItem(root->sli, + name, + "page", + name, + title, + 0 + ); + + rootNav->releaseEntry(); + } + RECURSE_ENTRYTREE(buildPageList,rootNav); +} + +static void findMainPage(EntryNav *rootNav) +{ + if (rootNav->section() == Entry::MAINPAGEDOC_SEC) + { + rootNav->loadEntry(g_storage); + Entry *root = rootNav->entry(); + + if (Doxygen::mainPage==0) + { + //printf("Found main page! \n======\n%s\n=======\n",root->doc.data()); + QCString title=root->args.stripWhiteSpace(); + //QCString indexName=Config_getBool("GENERATE_TREEVIEW")?"main":"index"; + QCString indexName="index"; + Doxygen::mainPage = new PageDef(root->docFile,root->docLine, + indexName, root->brief+root->doc+root->inbodyDocs,title); + //setFileNameForSections(root->anchors,"index",Doxygen::mainPage); + Doxygen::mainPage->setFileName(indexName); + Doxygen::mainPage->setShowToc(root->stat); + addPageToContext(Doxygen::mainPage,rootNav); + + // a page name is a label as well! + SectionInfo *si=new SectionInfo( + indexName, + Doxygen::mainPage->name(), + Doxygen::mainPage->title(), + SectionInfo::Page, + 0); // level 0 + Doxygen::sectionDict.append(indexName,si); + Doxygen::mainPage->addSectionsToDefinition(root->anchors); + } + else + { + warn(root->fileName,root->startLine, + "warning: found more than one \\mainpage comment block! Skipping this " + "block." + ); + } + + rootNav->releaseEntry(); + } + RECURSE_ENTRYTREE(findMainPage,rootNav); +} + +static void computePageRelations(EntryNav *rootNav) +{ + if ((rootNav->section()==Entry::PAGEDOC_SEC || + rootNav->section()==Entry::MAINPAGEDOC_SEC + ) + && !rootNav->name().isEmpty() + ) + { + rootNav->loadEntry(g_storage); + Entry *root = rootNav->entry(); + + PageDef *pd = root->section==Entry::PAGEDOC_SEC ? + Doxygen::pageSDict->find(root->name) : + Doxygen::mainPage; + if (pd) + { + QListIterator<BaseInfo> bii(*root->extends); + BaseInfo *bi; + for (bii.toFirst();(bi=bii.current());++bii) + { + PageDef *subPd = Doxygen::pageSDict->find(bi->name); + if (subPd) + { + pd->addInnerCompound(subPd); + //printf("*** Added subpage relation: %s->%s\n", + // pd->name().data(),subPd->name().data()); + } + } + } + + rootNav->releaseEntry(); + } + RECURSE_ENTRYTREE(computePageRelations,rootNav); +} + +static void checkPageRelations() +{ + PageSDict::Iterator pdi(*Doxygen::pageSDict); + PageDef *pd=0; + for (pdi.toFirst();(pd=pdi.current());++pdi) + { + Definition *ppd = pd->getOuterScope(); + while (ppd) + { + if (ppd==pd) + { + err("warning: page defined at line %d of file %s with label %s is a subpage " + "of itself! Please remove this cyclic dependency.\n", + pd->docLine(),pd->docFile().data(),pd->name().data()); + exit(1); + } + ppd=ppd->getOuterScope(); + } + } +} + +//---------------------------------------------------------------------------- + +static void resolveUserReferences() +{ + SDict<SectionInfo>::Iterator sdi(Doxygen::sectionDict); + SectionInfo *si; + for (;(si=sdi.current());++sdi) + { + //printf("si->label=`%s' si->definition=%s si->fileName=`%s'\n", + // si->label.data(),si->definition?si->definition->name().data():"<none>", + // si->fileName.data()); + PageDef *pd=0; + + // hack: the items of a todo/test/bug/deprecated list are all fragments from + // different files, so the resulting section's all have the wrong file + // name (not from the todo/test/bug/deprecated list, but from the file in + // which they are defined). We correct this here by looking at the + // generated section labels! + QDictIterator<RefList> rli(*Doxygen::xrefLists); + RefList *rl; + for (rli.toFirst();(rl=rli.current());++rli) + { + QCString label="_"+rl->listName(); // "_todo", "_test", ... + if (si->label.left(label.length())==label) + { + si->fileName=rl->listName(); + si->generated=TRUE; + break; + } + } + + //printf("start: si->label=%s si->fileName=%s\n",si->label.data(),si->fileName.data()); + if (!si->generated) + { + // if this section is in a page and the page is in a group, then we + // have to adjust the link file name to point to the group. + if (!si->fileName.isEmpty() && + (pd=Doxygen::pageSDict->find(si->fileName)) && + pd->getGroupDef()) + { + si->fileName=pd->getGroupDef()->getOutputFileBase().copy(); + } + + if (si->definition) + { + // TODO: there should be one function in Definition that returns + // the file to link to, so we can avoid the following tests. + GroupDef *gd=0; + if (si->definition->definitionType()==Definition::TypeMember) + { + gd = ((MemberDef *)si->definition)->getGroupDef(); + } + + if (gd) + { + si->fileName=gd->getOutputFileBase().copy(); + } + else + { + //si->fileName=si->definition->getOutputFileBase().copy(); + //printf("Setting si->fileName to %s\n",si->fileName.data()); + } + } + } + //printf("end: si->label=%s si->fileName=%s\n",si->label.data(),si->fileName.data()); + } +} + + + +//---------------------------------------------------------------------------- +// generate all separate documentation pages + + +static void generatePageDocs() +{ + //printf("documentedPages=%d real=%d\n",documentedPages,Doxygen::pageSDict->count()); + if (documentedPages==0) return; + PageSDict::Iterator pdi(*Doxygen::pageSDict); + PageDef *pd=0; + for (pdi.toFirst();(pd=pdi.current());++pdi) + { + if (!pd->getGroupDef() && !pd->isReference()) + { + msg("Generating docs for page %s...\n",pd->name().data()); + Doxygen::insideMainPage=TRUE; + pd->writeDocumentation(*g_outputList); + Doxygen::insideMainPage=FALSE; + } + } +} + +//---------------------------------------------------------------------------- +// create a (sorted) list & dictionary of example pages + +static void buildExampleList(EntryNav *rootNav) +{ + if (rootNav->section()==Entry::EXAMPLE_SEC && !rootNav->name().isEmpty()) + { + rootNav->loadEntry(g_storage); + Entry *root = rootNav->entry(); + + if (Doxygen::exampleSDict->find(root->name)) + { + warn(root->fileName,root->startLine, + "warning: Example %s was already documented. Ignoring " + "documentation found here.", + root->name.data() + ); + } + else + { + PageDef *pd=new PageDef(root->fileName,root->startLine, + root->name,root->brief+root->doc+root->inbodyDocs,root->args); + pd->setFileName(convertNameToFile(pd->name()+"-example",FALSE,TRUE)); + pd->addSectionsToDefinition(root->anchors); + pd->setLanguage(root->lang); + //pi->addSections(root->anchors); + + Doxygen::exampleSDict->inSort(root->name,pd); + //we don't add example to groups + //addExampleToGroups(root,pd); + } + + rootNav->releaseEntry(); + } + RECURSE_ENTRYTREE(buildExampleList,rootNav); +} + +//---------------------------------------------------------------------------- +// prints the Entry tree (for debugging) + +void printNavTree(EntryNav *rootNav,int indent) +{ + QCString indentStr; + indentStr.fill(' ',indent); + msg("%s%s (sec=0x%x)\n", + indentStr.isEmpty()?"":indentStr.data(), + rootNav->name().isEmpty()?"<empty>":rootNav->name().data(), + rootNav->section()); + if (rootNav->children()) + { + EntryNavListIterator eli(*rootNav->children()); + for (;eli.current();++eli) printNavTree(eli.current(),indent+2); + } +} + + +//---------------------------------------------------------------------------- +// generate the example documentation + +static void generateExampleDocs() +{ + g_outputList->disable(OutputGenerator::Man); + PageSDict::Iterator pdi(*Doxygen::exampleSDict); + PageDef *pd=0; + for (pdi.toFirst();(pd=pdi.current());++pdi) + { + msg("Generating docs for example %s...\n",pd->name().data()); + resetCCodeParserState(); + QCString n=pd->getOutputFileBase(); + startFile(*g_outputList,n,n,pd->name()); + startTitle(*g_outputList,n); + g_outputList->docify(pd->name()); + endTitle(*g_outputList,n,0); + g_outputList->startContents(); + g_outputList->parseDoc(pd->docFile(), // file + pd->docLine(), // startLine + pd, // context + 0, // memberDef + pd->documentation()+"\n\n\\include "+pd->name(), // docs + TRUE, // index words + TRUE, // is example + pd->name() + ); + endFile(*g_outputList); // contains g_outputList->endContents() + } + g_outputList->enable(OutputGenerator::Man); +} + +//---------------------------------------------------------------------------- +// generate module pages + +static void generateGroupDocs() +{ + GroupSDict::Iterator gli(*Doxygen::groupSDict); + GroupDef *gd; + for (gli.toFirst();(gd=gli.current());++gli) + { + if (!gd->isReference()) + { + gd->writeDocumentation(*g_outputList); + } + } +} + +//---------------------------------------------------------------------------- + +//static void generatePackageDocs() +//{ +// writePackageIndex(*g_outputList); +// +// if (Doxygen::packageDict.count()>0) +// { +// PackageSDict::Iterator pdi(Doxygen::packageDict); +// PackageDef *pd; +// for (pdi.toFirst();(pd=pdi.current());++pdi) +// { +// pd->writeDocumentation(*g_outputList); +// } +// } +//} + +//---------------------------------------------------------------------------- +// generate module pages + +static void generateNamespaceDocs() +{ + //writeNamespaceIndex(*g_outputList); + + NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict); + NamespaceDef *nd; + // for each namespace... + for (;(nd=nli.current());++nli) + { + + if (nd->isLinkableInProject()) + { + msg("Generating docs for namespace %s\n",nd->name().data()); + nd->writeDocumentation(*g_outputList); + } + + // for each class in the namespace... + ClassSDict::Iterator cli(*nd->getClassSDict()); + for ( ; cli.current() ; ++cli ) + { + ClassDef *cd=cli.current(); + if ( ( cd->isLinkableInProject() && + cd->templateMaster()==0 + ) // skip external references, anonymous compounds and + // template instances and nested classes + && !cd->isHidden() && !cd->isEmbeddedInOuterScope() + ) + { + msg("Generating docs for compound %s...\n",cd->name().data()); + + cd->writeDocumentation(*g_outputList); + cd->writeMemberList(*g_outputList); + } + cd->writeDocumentationForInnerClasses(*g_outputList); + } + } +} + +#if defined(_WIN32) +static QCString fixSlashes(QCString &s) +{ + QCString result; + uint i; + for (i=0;i<s.length();i++) + { + switch(s.at(i)) + { + case '/': + case '\\': + result+="\\\\"; + break; + default: + result+=s.at(i); + } + } + return result; +} +#endif + + +//---------------------------------------------------------------------------- + +static bool openOutputFile(const char *outFile,QFile &f) +{ + bool fileOpened=FALSE; + bool writeToStdout=(outFile[0]=='-' && outFile[1]=='\0'); + if (writeToStdout) // write to stdout + { + fileOpened = f.open(IO_WriteOnly,stdout); + } + else // write to file + { + QFileInfo fi(outFile); + if (fi.exists()) // create a backup + { + QDir dir=fi.dir(); + QFileInfo backup(fi.fileName()+".bak"); + if (backup.exists()) // remove existing backup + dir.remove(backup.fileName()); + dir.rename(fi.fileName(),fi.fileName()+".bak"); + } + f.setName(outFile); + fileOpened = f.open(IO_WriteOnly|IO_Translate); + } + return fileOpened; +} + +/*! Generate a template version of the configuration file. + * If the \a shortList parameter is TRUE a configuration file without + * comments will be generated. + */ +static void generateConfigFile(const char *configFile,bool shortList, + bool updateOnly=FALSE) +{ + QFile f; + bool fileOpened=openOutputFile(configFile,f); + bool writeToStdout=(configFile[0]=='-' && configFile[1]=='\0'); + if (fileOpened) + { + FTextStream t(&f); + Config::instance()->writeTemplate(t,shortList,updateOnly); + if (!writeToStdout) + { + if (!updateOnly) + { + msg("\n\nConfiguration file `%s' created.\n\n",configFile); + msg("Now edit the configuration file and enter\n\n"); + if (strcmp(configFile,"Doxyfile") || strcmp(configFile,"doxyfile")) + msg(" doxygen %s\n\n",configFile); + else + msg(" doxygen\n\n"); + msg("to generate the documentation for your project\n\n"); + } + else + { + msg("\n\nConfiguration file `%s' updated.\n\n",configFile); + } + } + } + else + { + err("error: Cannot open file %s for writing\n",configFile); + exit(1); + } +} + +//---------------------------------------------------------------------------- +// read and parse a tag file + +//static bool readLineFromFile(QFile &f,QCString &s) +//{ +// char c=0; +// s.resize(0); +// while (!f.atEnd() && (c=f.getch())!='\n') s+=c; +// return f.atEnd(); +//} + +//---------------------------------------------------------------------------- + +static void readTagFile(Entry *root,const char *tl) +{ + QCString tagLine = tl; + QCString fileName; + QCString destName; + int eqPos = tagLine.find('='); + if (eqPos!=-1) // tag command contains a destination + { + fileName = tagLine.left(eqPos).stripWhiteSpace(); + destName = tagLine.right(tagLine.length()-eqPos-1).stripWhiteSpace(); + QFileInfo fi(fileName); + Doxygen::tagDestinationDict.insert(fi.fileName(),new QCString(destName)); + //printf("insert tagDestination %s->%s\n",fi.fileName().data(),destName.data()); + } + else + { + fileName = tagLine; + } + + QFileInfo fi(fileName); + if (!fi.exists() || !fi.isFile()) + { + err("error: Tag file `%s' does not exist or is not a file. Skipping it...\n", + fileName.data()); + return; + } + + if (!destName.isEmpty()) + msg("Reading tag file `%s', location `%s'...\n",fileName.data(),destName.data()); + else + msg("Reading tag file `%s'...\n",fileName.data()); + + parseTagFile(root,fi.absFilePath(),fi.fileName()); +} + +//---------------------------------------------------------------------------- +static void copyStyleSheet() +{ + QCString &htmlStyleSheet = Config_getString("HTML_STYLESHEET"); + if (!htmlStyleSheet.isEmpty()) + { + QFileInfo fi(htmlStyleSheet); + if (!fi.exists()) + { + err("Style sheet '%s' specified by HTML_STYLESHEET does not exist!\n",htmlStyleSheet.data()); + htmlStyleSheet.resize(0); // revert to the default + } + else + { + QCString destFileName = Config_getString("HTML_OUTPUT")+"/"+fi.fileName().data(); + copyFile(htmlStyleSheet,destFileName); + } + } +} + +static void copyLogo() +{ + QCString &projectLogo = Config_getString("PROJECT_LOGO"); + if (!projectLogo.isEmpty()) + { + QFileInfo fi(projectLogo); + if (!fi.exists()) + { + err("Project logo '%s' specified by PROJECT_LOGO does not exist!\n",projectLogo.data()); + projectLogo.resize(0); // revert to the default + } + else + { + QCString destFileName = Config_getString("HTML_OUTPUT")+"/"+fi.fileName().data(); + copyFile(projectLogo,destFileName); + } + } +} + +static void copyExtraFiles() +{ + QStrList files = Config_getList("HTML_EXTRA_FILES"); + uint i; + for (i=0; i<files.count(); ++i) + { + QCString fileName(files.at(i)); + + if (!fileName.isEmpty()) + { + QFileInfo fi(fileName); + if (!fi.exists()) + { + err("Extra HTML file '%s' specified in HTML_EXTRA_FILES does not exist!\n", fileName.data()); + } + else + { + QCString destFileName = Config_getString("HTML_OUTPUT")+"/"+fi.fileName().data(); + Doxygen::indexList.addImageFile(fi.fileName().data()); + copyFile(fileName, destFileName); + } + } + } +} + +//! parse the list of input files +static void parseFiles(Entry *root,EntryNav *rootNav) +{ +#if 0 + void *cd = 0; + QCString inpEncoding = Config_getString("INPUT_ENCODING"); + bool needsTranscoding = !inpEncoding.isEmpty(); + if (needsTranscoding) + { + if (!(cd = portable_iconv_open("UTF-8", inpEncoding))) + { + err("error: unsupported character enconding: '%s'",inpEncoding.data()); + exit(1); + } + } +#endif + + QCString *s=g_inputFiles.first(); + while (s) + { + QCString fileName=*s; + QCString extension; + int ei = fileName.findRev('.'); + if (ei!=-1) extension=fileName.right(fileName.length()-ei); + ParserInterface *parser = Doxygen::parserManager->getParser(extension); + + QFileInfo fi(fileName); + BufStr preBuf(fi.size()+4096); + + if (Config_getBool("ENABLE_PREPROCESSING") && + parser->needsPreprocessing(extension)) + { + BufStr inBuf(fi.size()+4096); + msg("Preprocessing %s...\n",s->data()); + readInputFile(fileName,inBuf); + preprocessFile(fileName,inBuf,preBuf); + } + else // no preprocessing + { + msg("Reading %s...\n",s->data()); + readInputFile(fileName,preBuf); + } + + BufStr convBuf(preBuf.curPos()+1024); + + // convert multi-line C++ comments to C style comments + convertCppComments(&preBuf,&convBuf,fileName); + + convBuf.addChar('\0'); + + // use language parse to parse the file + parser->parseInput(fileName,convBuf.data(),root); + + // store the Entry tree in a file and create an index to + // navigate/load entries + bool ambig; + FileDef *fd=findFileDef(Doxygen::inputNameDict,fileName,ambig); + ASSERT(fd!=0); + //printf("root->createNavigationIndex for %s\n",fd->name().data()); + root->createNavigationIndex(rootNav,g_storage,fd); + + s=g_inputFiles.next(); + } +} + +// resolves a path that may include symlinks, if a recursive symlink is +// found an empty string is returned. +static QCString resolveSymlink(QCString path) +{ + int sepPos=0; + int oldPos=0; + QFileInfo fi; + QDict<void> nonSymlinks; + QDict<void> known; + QCString result = path; + QCString oldPrefix = "/"; + do + { +#ifdef WIN32 + // UNC path, skip server and share name + if (sepPos==0 && (result.left(2)=="//" || result.left(2)=="\\\\")) + sepPos = result.find('/',2); + if (sepPos!=-1) + sepPos = result.find('/',sepPos+1); +#else + sepPos = result.find('/',sepPos+1); +#endif + QCString prefix = sepPos==-1 ? result : result.left(sepPos); + if (nonSymlinks.find(prefix)==0) + { + fi.setFile(prefix); + if (fi.isSymLink()) + { + QString target = fi.readLink(); + bool isRelative = QFileInfo(target).isRelative(); + if (isRelative) + { + target = QDir::cleanDirPath(oldPrefix+"/"+target.data()); + } + if (sepPos!=-1) + { + if (fi.isDir() && target.length()>0 && target.at(target.length()-1)!='/') + { + target+='/'; + } + target+=result.mid(sepPos); + } + result = QDir::cleanDirPath(target).data(); + sepPos = 0; + if (known.find(result)) return QCString(); // recursive symlink! + known.insert(result,(void*)0x8); + if (isRelative) + { + sepPos = oldPos; + } + else // link to absolute path + { + sepPos = 0; + oldPrefix = "/"; + } + } + else + { + nonSymlinks.insert(prefix,(void*)0x8); + oldPrefix = prefix; + } + oldPos = sepPos; + } + } + while (sepPos!=-1); + return QDir::cleanDirPath(result).data(); +} + +static QDict<void> g_pathsVisited(1009); + +//---------------------------------------------------------------------------- +// Read all files matching at least one pattern in `patList' in the +// directory represented by `fi'. +// The directory is read iff the recusiveFlag is set. +// The contents of all files is append to the input string + +int readDir(QFileInfo *fi, + FileNameList *fnList, + FileNameDict *fnDict, + StringDict *exclDict, + QStrList *patList, + QStrList *exclPatList, + StringList *resultList, + StringDict *resultDict, + bool errorIfNotExist, + bool recursive, + QDict<void> *killDict + ) +{ + QString dirName = fi->absFilePath(); + if (fi->isSymLink()) + { + dirName = resolveSymlink(dirName.data()); + if (dirName.isEmpty()) return 0; // recusive symlink + if (g_pathsVisited.find(dirName)) return 0; // already visited path + g_pathsVisited.insert(dirName,(void*)0x8); + } + QDir dir(dirName); + dir.setFilter( QDir::Files | QDir::Dirs | QDir::Hidden ); + int totalSize=0; + msg("Searching for files in directory %s\n", fi->absFilePath().data()); + //printf("killDict=%p count=%d\n",killDict,killDict->count()); + + const QFileInfoList *list = dir.entryInfoList(); + if (list) + { + QFileInfoListIterator it( *list ); + QFileInfo *cfi; + + while ((cfi=it.current())) + { + if (exclDict==0 || exclDict->find(cfi->absFilePath())==0) + { // file should not be excluded + //printf("killDict->find(%s)\n",cfi->absFilePath().data()); + if (!cfi->exists() || !cfi->isReadable()) + { + if (errorIfNotExist) + { + err("warning: source %s is not a readable file or directory... skipping.\n",cfi->absFilePath().data()); + } + } + else if (cfi->isFile() && + (!Config_getBool("EXCLUDE_SYMLINKS") || !cfi->isSymLink()) && + (patList==0 || patternMatch(*cfi,patList)) && + !patternMatch(*cfi,exclPatList) && + (killDict==0 || killDict->find(cfi->absFilePath())==0) + ) + { + totalSize+=cfi->size()+cfi->absFilePath().length()+4; + QCString name=convertToQCString(cfi->fileName()); + //printf("New file %s\n",name.data()); + if (fnDict) + { + FileDef *fd=new FileDef(cfi->dirPath()+"/",name); + FileName *fn=0; + if (!name.isEmpty() && (fn=(*fnDict)[name])) + { + fn->append(fd); + } + else + { + fn = new FileName(cfi->absFilePath(),name); + fn->append(fd); + if (fnList) fnList->inSort(fn); + fnDict->insert(name,fn); + } + } + QCString *rs=0; + if (resultList || resultDict) + { + rs=new QCString(cfi->absFilePath()); + } + if (resultList) resultList->append(rs); + if (resultDict) resultDict->insert(cfi->absFilePath(),rs); + if (killDict) killDict->insert(cfi->absFilePath(),(void *)0x8); + } + else if (recursive && + (!Config_getBool("EXCLUDE_SYMLINKS") || !cfi->isSymLink()) && + cfi->isDir() && cfi->fileName()!="." && + !patternMatch(*cfi,exclPatList) && + cfi->fileName()!="..") + { + cfi->setFile(cfi->absFilePath()); + totalSize+=readDir(cfi,fnList,fnDict,exclDict, + patList,exclPatList,resultList,resultDict,errorIfNotExist, + recursive,killDict); + } + } + ++it; + } + } + return totalSize; +} + + +//---------------------------------------------------------------------------- +// read a file or all files in a directory and append their contents to the +// input string. The names of the files are appended to the `fiList' list. + +int readFileOrDirectory(const char *s, + FileNameList *fnList, + FileNameDict *fnDict, + StringDict *exclDict, + QStrList *patList, + QStrList *exclPatList, + StringList *resultList, + StringDict *resultDict, + bool recursive, + bool errorIfNotExist, + QDict<void> *killDict + ) +{ + //printf("killDict=%p count=%d\n",killDict,killDict->count()); + // strip trailing slashes + if (s==0) return 0; + QCString fs = s; + char lc = fs.at(fs.length()-1); + if (lc=='/' || lc=='\\') fs = fs.left(fs.length()-1); + + QFileInfo fi(fs); + //printf("readFileOrDirectory(%s)\n",s); + int totalSize=0; + { + if (exclDict==0 || exclDict->find(fi.absFilePath())==0) + { + if (!fi.exists() || !fi.isReadable()) + { + if (errorIfNotExist) + { + err("warning: source %s is not a readable file or directory... skipping.\n",s); + } + } + else if (!Config_getBool("EXCLUDE_SYMLINKS") || !fi.isSymLink()) + { + if (fi.isFile()) + { + //printf("killDict->find(%s)\n",fi.absFilePath().data()); + if (killDict==0 || killDict->find(fi.absFilePath())==0) + { + totalSize+=fi.size()+fi.absFilePath().length()+4; //readFile(&fi,fiList,input); + //fiList->inSort(new FileInfo(fi)); + QCString name=convertToQCString(fi.fileName()); + //printf("New file %s\n",name.data()); + if (fnDict) + { + FileDef *fd=new FileDef(fi.dirPath(TRUE)+"/",name); + FileName *fn=0; + if (!name.isEmpty() && (fn=(*fnDict)[name])) + { + fn->append(fd); + } + else + { + fn = new FileName(fi.absFilePath(),name); + fn->append(fd); + if (fnList) fnList->inSort(fn); + fnDict->insert(name,fn); + } + } + QCString *rs=0; + if (resultList || resultDict) + { + rs=new QCString(fi.absFilePath()); + if (resultList) resultList->append(rs); + if (resultDict) resultDict->insert(fi.absFilePath(),rs); + } + + if (killDict) killDict->insert(fi.absFilePath(),(void *)0x8); + } + } + else if (fi.isDir()) // readable dir + { + totalSize+=readDir(&fi,fnList,fnDict,exclDict,patList, + exclPatList,resultList,resultDict,errorIfNotExist, + recursive,killDict); + } + } + } + } + return totalSize; +} + +//---------------------------------------------------------------------------- + +void readFormulaRepository() +{ + QFile f(Config_getString("HTML_OUTPUT")+"/formula.repository"); + if (f.open(IO_ReadOnly)) // open repository + { + msg("Reading formula repository...\n"); + QTextStream t(&f); + QCString line; + while (!t.eof()) + { + line=t.readLine(); + int se=line.find(':'); // find name and text separator. + if (se==-1) + { + err("warning: formula.repository is corrupted!\n"); + break; + } + else + { + QCString formName = line.left(se); + QCString formText = line.right(line.length()-se-1); + Formula *f=new Formula(formText); + Doxygen::formulaList.append(f); + Doxygen::formulaDict.insert(formText,f); + Doxygen::formulaNameDict.insert(formName,f); + } + } + } +} + +//---------------------------------------------------------------------------- + +static void expandAliases() +{ + QDictIterator<QCString> adi(Doxygen::aliasDict); + QCString *s; + for (adi.toFirst();(s=adi.current());++adi) + { + *s = expandAlias(adi.currentKey(),*s); + } +} + +//---------------------------------------------------------------------------- + +static void escapeAliases() +{ + QDictIterator<QCString> adi(Doxygen::aliasDict); + QCString *s; + for (adi.toFirst();(s=adi.current());++adi) + { + QCString value=*s,newValue; + int in,p=0; + // for each \n in the alias command value + while ((in=value.find("\\n",p))!=-1) + { + newValue+=value.mid(p,in-p); + // expand \n's except if \n is part of a built-in command. + if (value.mid(in,5)!="\\note" && + value.mid(in,5)!="\\name" && + value.mid(in,10)!="\\namespace" && + value.mid(in,14)!="\\nosubgrouping" + ) + { + newValue+="\\_linebr "; + } + else + { + newValue+="\\n"; + } + p=in+2; + } + newValue+=value.mid(p,value.length()-p); + *s=newValue; + //printf("Alias %s has value %s\n",adi.currentKey().data(),s->data()); + } +} + +//---------------------------------------------------------------------------- + +void readAliases() +{ + // add aliases to a dictionary + Doxygen::aliasDict.setAutoDelete(TRUE); + QStrList &aliasList = Config_getList("ALIASES"); + const char *s=aliasList.first(); + while (s) + { + if (Doxygen::aliasDict[s]==0) + { + QCString alias=s; + int i=alias.find('='); + if (i>0) + { + QCString name=alias.left(i).stripWhiteSpace(); + QCString value=alias.right(alias.length()-i-1); + //printf("Alias: found name=`%s' value=`%s'\n",name.data(),value.data()); + if (!name.isEmpty()) + { + QCString *dn=Doxygen::aliasDict[name]; + if (dn==0) // insert new alias + { + Doxygen::aliasDict.insert(name,new QCString(value)); + } + else // overwrite previous alias + { + *dn=value; + } + } + } + } + s=aliasList.next(); + } + expandAliases(); + escapeAliases(); +} + +//---------------------------------------------------------------------------- + +static void dumpSymbol(FTextStream &t,Definition *d) +{ + QCString anchor; + if (d->definitionType()==Definition::TypeMember) + { + MemberDef *md = (MemberDef *)d; + anchor=":"+md->anchor(); + } + QCString scope; + if (d->getOuterScope() && d->getOuterScope()!=Doxygen::globalScope) + { + scope = d->getOuterScope()->getOutputFileBase()+Doxygen::htmlFileExtension; + } + t << "REPLACE INTO symbols (symbol_id,scope_id,name,file,line) VALUES('" + << d->getOutputFileBase()+Doxygen::htmlFileExtension+anchor << "','" + << scope << "','" + << d->name() << "','" + << d->getDefFileName() << "','" + << d->getDefLine() + << "');" << endl; +} + +static void dumpSymbolMap() +{ + QFile f("symbols.sql"); + if (f.open(IO_WriteOnly)) + { + FTextStream t(&f); + QDictIterator<DefinitionIntf> di(*Doxygen::symbolMap); + DefinitionIntf *intf; + for (;(intf=di.current());++di) + { + if (intf->definitionType()==DefinitionIntf::TypeSymbolList) // list of symbols + { + DefinitionListIterator dli(*(DefinitionList*)intf); + Definition *d; + // for each symbol + for (dli.toFirst();(d=dli.current());++dli) + { + dumpSymbol(t,d); + } + } + else // single symbol + { + Definition *d = (Definition *)intf; + if (d!=Doxygen::globalScope) dumpSymbol(t,d); + } + } + } +} + +//---------------------------------------------------------------------------- + +void dumpConfigAsXML() +{ + QFile f("config.xml"); + if (f.open(IO_WriteOnly)) + { + FTextStream t(&f); + Config::instance()->writeXML(t); + } +} + +//---------------------------------------------------------------------------- +// print the usage of doxygen + +static void usage(const char *name) +{ + msg("Doxygen version %s\nCopyright Dimitri van Heesch 1997-2012\n\n",versionString); + msg("You can use doxygen in a number of ways:\n\n"); + msg("1) Use doxygen to generate a template configuration file:\n"); + msg(" %s [-s] -g [configName]\n\n",name); + msg(" If - is used for configName doxygen will write to standard output.\n\n"); + msg("2) Use doxygen to update an old configuration file:\n"); + msg(" %s [-s] -u [configName]\n\n",name); + msg("3) Use doxygen to generate documentation using an existing "); + msg("configuration file:\n"); + msg(" %s [configName]\n\n",name); + msg(" If - is used for configName doxygen will read from standard input.\n\n"); + msg("4) Use doxygen to generate a template file controlling the layout of the\n"); + msg(" generated documentation:\n"); + msg(" %s -l layoutFileName.xml\n\n",name); + msg("5) Use doxygen to generate a template style sheet file for RTF, HTML or Latex.\n"); + msg(" RTF: %s -w rtf styleSheetFile\n",name); + msg(" HTML: %s -w html headerFile footerFile styleSheetFile [configFile]\n",name); + msg(" LaTeX: %s -w latex headerFile footerFile styleSheetFile [configFile]\n\n",name); + msg("6) Use doxygen to generate an rtf extensions file\n"); + msg(" RTF: %s -e rtf extensionsFile\n\n",name); + msg("If -s is specified the comments in the config file will be omitted.\n"); + msg("If configName is omitted `Doxyfile' will be used as a default.\n\n"); + exit(1); +} + +//---------------------------------------------------------------------------- +// read the argument of option `c' from the comment argument list and +// update the option index `optind'. + +static const char *getArg(int argc,char **argv,int &optind) +{ + char *s=0; + if (strlen(&argv[optind][2])>0) + s=&argv[optind][2]; + else if (optind+1<argc && argv[optind+1][0]!='-') + s=argv[++optind]; + return s; +} + +//---------------------------------------------------------------------------- + +void initDoxygen() +{ + const char *lang = portable_getenv("LC_ALL"); + if (lang) portable_setenv("LANG",lang); + setlocale(LC_ALL,""); + setlocale(LC_CTYPE,"C"); // to get isspace(0xA0)==0, needed for UTF-8 + setlocale(LC_NUMERIC,"C"); + + //Doxygen::symbolMap->setAutoDelete(TRUE); + + Doxygen::runningTime.start(); + initPreprocessor(); + + Doxygen::parserManager = new ParserManager; + Doxygen::parserManager->registerParser("c", new CLanguageScanner, TRUE); + Doxygen::parserManager->registerParser("python", new PythonLanguageScanner); + Doxygen::parserManager->registerParser("fortran", new FortranLanguageScanner); + Doxygen::parserManager->registerParser("vhdl", new VHDLLanguageScanner); + Doxygen::parserManager->registerParser("dbusxml", new DBusXMLScanner); + Doxygen::parserManager->registerParser("tcl", new TclLanguageScanner); + Doxygen::parserManager->registerParser("md", new MarkdownFileParser); + + // register any additional parsers here... + + initDefaultExtensionMapping(); + initClassMemberIndices(); + initNamespaceMemberIndices(); + initFileMemberIndices(); + + Doxygen::symbolMap = new QDict<DefinitionIntf>(1000); + Doxygen::inputNameList = new FileNameList; + Doxygen::inputNameList->setAutoDelete(TRUE); + Doxygen::memberNameSDict = new MemberNameSDict(10000); + Doxygen::memberNameSDict->setAutoDelete(TRUE); + Doxygen::functionNameSDict = new MemberNameSDict(10000); + Doxygen::functionNameSDict->setAutoDelete(TRUE); + Doxygen::groupSDict = new GroupSDict(17); + Doxygen::groupSDict->setAutoDelete(TRUE); + Doxygen::globalScope = new NamespaceDef("<globalScope>",1,"<globalScope>"); + Doxygen::namespaceSDict = new NamespaceSDict(20); + Doxygen::namespaceSDict->setAutoDelete(TRUE); + Doxygen::classSDict = new ClassSDict(1009); + Doxygen::classSDict->setAutoDelete(TRUE); + Doxygen::hiddenClasses = new ClassSDict(257); + Doxygen::hiddenClasses->setAutoDelete(TRUE); + Doxygen::directories = new DirSDict(17); + Doxygen::directories->setAutoDelete(TRUE); + Doxygen::pageSDict = new PageSDict(1009); // all doc pages + Doxygen::pageSDict->setAutoDelete(TRUE); + Doxygen::exampleSDict = new PageSDict(1009); // all examples + Doxygen::exampleSDict->setAutoDelete(TRUE); + Doxygen::inputNameDict = new FileNameDict(10007); + Doxygen::includeNameDict = new FileNameDict(10007); + Doxygen::exampleNameDict = new FileNameDict(1009); + Doxygen::exampleNameDict->setAutoDelete(TRUE); + Doxygen::imageNameDict = new FileNameDict(257); + Doxygen::dotFileNameDict = new FileNameDict(257); + Doxygen::mscFileNameDict = new FileNameDict(257); + Doxygen::sectionDict.setAutoDelete(TRUE); + Doxygen::memGrpInfoDict.setAutoDelete(TRUE); + Doxygen::tagDestinationDict.setAutoDelete(TRUE); + Doxygen::dirRelations.setAutoDelete(TRUE); + Doxygen::citeDict = new CiteDict(257); +} + +void cleanUpDoxygen() +{ + delete Doxygen::inputNameDict; + delete Doxygen::includeNameDict; + delete Doxygen::exampleNameDict; + delete Doxygen::imageNameDict; + delete Doxygen::dotFileNameDict; + delete Doxygen::mscFileNameDict; + delete Doxygen::mainPage; + delete Doxygen::pageSDict; + delete Doxygen::exampleSDict; + delete Doxygen::globalScope; + delete Doxygen::xrefLists; + delete Doxygen::parserManager; + cleanUpPreprocessor(); + delete theTranslator; + delete g_outputList; + Mappers::freeMappers(); + codeFreeScanner(); + + if (Doxygen::symbolMap) + { + // iterate through Doxygen::symbolMap and delete all + // DefinitionList objects, since they have no owner + QDictIterator<DefinitionIntf> dli(*Doxygen::symbolMap); + DefinitionIntf *di; + for (dli.toFirst();(di=dli.current());) + { + if (di->definitionType()==DefinitionIntf::TypeSymbolList) + { + DefinitionIntf *tmp = Doxygen::symbolMap->take(dli.currentKey()); + delete (DefinitionList *)tmp; + } + else + { + ++dli; + } + } + } + + delete Doxygen::inputNameList; + delete Doxygen::memberNameSDict; + delete Doxygen::functionNameSDict; + delete Doxygen::groupSDict; + delete Doxygen::classSDict; + delete Doxygen::hiddenClasses; + delete Doxygen::namespaceSDict; + delete Doxygen::directories; + + //delete Doxygen::symbolMap; <- we cannot do this unless all static lists + // (such as Doxygen::namespaceSDict) + // with objects based on Definition are made + // dynamic first +} + +static int computeIdealCacheParam(uint v) +{ + //printf("computeIdealCacheParam(v=%u)\n",v); + + int r=0; + while (v!=0) v>>=1,r++; + // r = log2(v) + + // convert to a valid cache size value + return QMAX(0,QMIN(r-16,9)); +} + +void readConfiguration(int argc, char **argv) +{ + /************************************************************************** + * Handle arguments * + **************************************************************************/ + + int optind=1; + const char *configName=0; + const char *layoutName=0; + const char *debugLabel; + const char *formatName; + bool genConfig=FALSE; + bool shortList=FALSE; + bool updateConfig=FALSE; + bool genLayout=FALSE; + while (optind<argc && argv[optind][0]=='-' && + (isalpha(argv[optind][1]) || argv[optind][1]=='?' || + argv[optind][1]=='-') + ) + { + switch(argv[optind][1]) + { + case 'g': + genConfig=TRUE; + configName=getArg(argc,argv,optind); + if (strcmp(argv[optind+1],"-")==0) + { configName="-"; optind++; } + if (!configName) + { configName="Doxyfile"; } + break; + case 'l': + genLayout=TRUE; + layoutName=getArg(argc,argv,optind); + if (!layoutName) + { layoutName="DoxygenLayout.xml"; } + break; + case 'd': + debugLabel=getArg(argc,argv,optind); + Debug::setFlag(debugLabel); + break; + case 's': + shortList=TRUE; + break; + case 'u': + updateConfig=TRUE; + break; + case 'e': + formatName=getArg(argc,argv,optind); + if (!formatName) + { + err("error: option -e is missing format specifier rtf.\n"); + cleanUpDoxygen(); + exit(1); + } + if (stricmp(formatName,"rtf")==0) + { + if (optind+1>=argc) + { + err("error: option \"-e rtf\" is missing an extensions file name\n"); + cleanUpDoxygen(); + exit(1); + } + QFile f; + if (openOutputFile(argv[optind+1],f)) + { + RTFGenerator::writeExtensionsFile(f); + } + cleanUpDoxygen(); + exit(1); + } + err("error: option \"-e\" has invalid format specifier.\n"); + cleanUpDoxygen(); + exit(1); + break; + case 'w': + formatName=getArg(argc,argv,optind); + if (!formatName) + { + err("error: option -w is missing format specifier rtf, html or latex\n"); + cleanUpDoxygen(); + exit(1); + } + if (stricmp(formatName,"rtf")==0) + { + if (optind+1>=argc) + { + err("error: option \"-w rtf\" is missing a style sheet file name\n"); + cleanUpDoxygen(); + exit(1); + } + QFile f; + if (openOutputFile(argv[optind+1],f)) + { + RTFGenerator::writeStyleSheetFile(f); + } + cleanUpDoxygen(); + exit(1); + } + else if (stricmp(formatName,"html")==0) + { + if (optind+4<argc || QFileInfo("Doxyfile").exists()) + { + QCString df = optind+4<argc ? argv[optind+4] : QCString("Doxyfile"); + if (!Config::instance()->parse(df)) + { + err("error opening or reading configuration file %s!\n",argv[optind+4]); + cleanUpDoxygen(); + exit(1); + } + Config::instance()->substituteEnvironmentVars(); + Config::instance()->convertStrToVal(); + // avoid bootstrapping issues when the config file already + // refers to the files that we are supposed to parse. + Config_getString("HTML_HEADER")=""; + Config_getString("HTML_FOOTER")=""; + Config::instance()->check(); + } + else + { + Config::instance()->init(); + } + if (optind+3>=argc) + { + err("error: option \"-w html\" does not have enough arguments\n"); + cleanUpDoxygen(); + exit(1); + } + + QCString outputLanguage=Config_getEnum("OUTPUT_LANGUAGE"); + if (!setTranslator(outputLanguage)) + { + err("warning: Output language %s not supported! Using English instead.\n", outputLanguage.data()); + } + + QFile f; + if (openOutputFile(argv[optind+1],f)) + { + HtmlGenerator::writeHeaderFile(f, argv[optind+3]); + } + f.close(); + if (openOutputFile(argv[optind+2],f)) + { + HtmlGenerator::writeFooterFile(f); + } + f.close(); + if (openOutputFile(argv[optind+3],f)) + { + HtmlGenerator::writeStyleSheetFile(f); + } + cleanUpDoxygen(); + exit(0); + } + else if (stricmp(formatName,"latex")==0) + { + if (optind+4<argc) // use config file to get settings + { + if (!Config::instance()->parse(argv[optind+4])) + { + err("error opening or reading configuration file %s!\n",argv[optind+4]); + exit(1); + } + Config::instance()->substituteEnvironmentVars(); + Config::instance()->convertStrToVal(); + Config_getString("LATEX_HEADER")=""; + Config::instance()->check(); + } + else // use default config + { + Config::instance()->init(); + } + if (optind+3>=argc) + { + err("error: option \"-w latex\" does not have enough arguments\n"); + cleanUpDoxygen(); + exit(1); + } + + QCString outputLanguage=Config_getEnum("OUTPUT_LANGUAGE"); + if (!setTranslator(outputLanguage)) + { + err("warning: Output language %s not supported! Using English instead.\n", outputLanguage.data()); + } + + QFile f; + if (openOutputFile(argv[optind+1],f)) + { + LatexGenerator::writeHeaderFile(f); + } + f.close(); + if (openOutputFile(argv[optind+2],f)) + { + LatexGenerator::writeFooterFile(f); + } + f.close(); + if (openOutputFile(argv[optind+3],f)) + { + LatexGenerator::writeStyleSheetFile(f); + } + cleanUpDoxygen(); + exit(0); + } + else + { + err("error: Illegal format specifier %s: should be one of rtf, html, latex, or bst\n",formatName); + cleanUpDoxygen(); + exit(1); + } + break; + case 'm': + g_dumpSymbolMap = TRUE; + break; + case 'x': + g_dumpConfigAsXML = TRUE; + break; + case '-': + if (strcmp(&argv[optind][2],"help")==0) + { + usage(argv[0]); + } + else if (strcmp(&argv[optind][2],"version")==0) + { + msg("%s\n",versionString); + cleanUpDoxygen(); + exit(0); + } + break; + case 'b': + setvbuf(stdout,NULL,_IONBF,0); + Doxygen::outputToWizard=TRUE; + break; + case 'h': + case '?': + usage(argv[0]); + break; + default: + err("Unknown option -%c\n",argv[optind][1]); + usage(argv[0]); + } + optind++; + } + + /************************************************************************** + * Parse or generate the config file * + **************************************************************************/ + + Config::instance()->init(); + + if (genConfig) + { + if (g_dumpConfigAsXML) + { + checkConfiguration(); + generateConfigFile(configName,shortList); + dumpConfigAsXML(); + exit(0); + } + else + { + generateConfigFile(configName,shortList); + } + cleanUpDoxygen(); + exit(0); + } + if (genLayout) + { + writeDefaultLayoutFile(layoutName); + cleanUpDoxygen(); + exit(0); + } + + QFileInfo configFileInfo1("Doxyfile"),configFileInfo2("doxyfile"); + if (optind>=argc) + { + if (configFileInfo1.exists()) + { + configName="Doxyfile"; + } + else if (configFileInfo2.exists()) + { + configName="doxyfile"; + } + else + { + err("Doxyfile not found and no input file specified!\n"); + usage(argv[0]); + } + } + else + { + QFileInfo fi(argv[optind]); + if (fi.exists() || strcmp(argv[optind],"-")==0) + { + configName=argv[optind]; + } + else + { + err("error: configuration file %s not found!\n",argv[optind]); + usage(argv[0]); + } + } + + + if (!Config::instance()->parse(configName)) + { + err("error: could not open or read configuration file %s!\n",configName); + cleanUpDoxygen(); + exit(1); + } + + if (updateConfig) + { + generateConfigFile(configName,shortList,TRUE); + cleanUpDoxygen(); + exit(0); + } + + /* Perlmod wants to know the path to the config file.*/ + QFileInfo configFileInfo(configName); + setPerlModDoxyfile(configFileInfo.absFilePath().data()); + +} + +/** check and resolve config options */ +void checkConfiguration() +{ + + Config::instance()->substituteEnvironmentVars(); + Config::instance()->convertStrToVal(); + Config::instance()->check(); + + initWarningFormat(); +} + +/** adjust globals that depend on configuration settings. */ +void adjustConfiguration() +{ + QCString outputLanguage=Config_getEnum("OUTPUT_LANGUAGE"); + if (!setTranslator(outputLanguage)) + { + err("warning: Output language %s not supported! Using English instead.\n", + outputLanguage.data()); + } + QStrList &includePath = Config_getList("INCLUDE_PATH"); + char *s=includePath.first(); + while (s) + { + QFileInfo fi(s); + addSearchDir(fi.absFilePath()); + s=includePath.next(); + } + + /* Set the global html file extension. */ + Doxygen::htmlFileExtension = Config_getString("HTML_FILE_EXTENSION"); + + + Doxygen::xrefLists->setAutoDelete(TRUE); + + Doxygen::parseSourcesNeeded = Config_getBool("CALL_GRAPH") || + Config_getBool("CALLER_GRAPH") || + Config_getBool("REFERENCES_RELATION") || + Config_getBool("REFERENCED_BY_RELATION"); + + Doxygen::markdownSupport = Config_getBool("MARKDOWN_SUPPORT"); + + /************************************************************************** + * Add custom extension mappings + **************************************************************************/ + + QStrList &extMaps = Config_getList("EXTENSION_MAPPING"); + char *mapping = extMaps.first(); + while (mapping) + { + QCString mapStr = mapping; + int i; + if ((i=mapStr.find('='))!=-1) + { + QCString ext=mapStr.left(i).stripWhiteSpace().lower(); + QCString language=mapStr.mid(i+1).stripWhiteSpace().lower(); + if (!updateLanguageMapping(ext,language)) + { + err("Failed to map file extension '%s' to unsupported language '%s'.\n" + "Check the EXTENSION_MAPPING setting in the config file.\n", + ext.data(),language.data()); + } + else + { + msg("Adding custom extension mapping: .%s will be treated as language %s\n", + ext.data(),language.data()); + } + } + mapping = extMaps.next(); + } + + + // add predefined macro name to a dictionary + QStrList &expandAsDefinedList =Config_getList("EXPAND_AS_DEFINED"); + s=expandAsDefinedList.first(); + while (s) + { + if (Doxygen::expandAsDefinedDict[s]==0) + { + Doxygen::expandAsDefinedDict.insert(s,(void *)666); + } + s=expandAsDefinedList.next(); + } + + // read aliases and store them in a dictionary + readAliases(); + + // store number of spaces in a tab into Doxygen::spaces + int &tabSize = Config_getInt("TAB_SIZE"); + Doxygen::spaces.resize(tabSize+1); + int sp;for (sp=0;sp<tabSize;sp++) Doxygen::spaces.at(sp)=' '; + Doxygen::spaces.at(tabSize)='\0'; +} + +#ifdef HAS_SIGNALS +static void stopDoxygen(int) +{ + QDir thisDir; + msg("Cleaning up...\n"); + if (!Doxygen::entryDBFileName.isEmpty()) + { + thisDir.remove(Doxygen::entryDBFileName); + } + if (!Doxygen::objDBFileName.isEmpty()) + { + thisDir.remove(Doxygen::objDBFileName); + } + exit(1); +} +#endif + +static void exitDoxygen() +{ + if (!g_successfulRun) // premature exit + { + QDir thisDir; + msg("Exiting...\n"); + if (!Doxygen::entryDBFileName.isEmpty()) + { + thisDir.remove(Doxygen::entryDBFileName); + } + if (!Doxygen::objDBFileName.isEmpty()) + { + thisDir.remove(Doxygen::objDBFileName); + } + } +} + +static QCString createOutputDirectory(const QCString &baseDirName, + const char *formatDirOption, + const char *defaultDirName) +{ + // Note the & on the next line, we modify the formatDirOption! + QCString &formatDirName = Config_getString(formatDirOption); + if (formatDirName.isEmpty()) + { + formatDirName = baseDirName + defaultDirName; + } + else if (formatDirName[0]!='/' && (formatDirName.length()==1 || formatDirName[1]!=':')) + { + formatDirName.prepend(baseDirName+'/'); + } + QDir formatDir(formatDirName); + if (!formatDir.exists() && !formatDir.mkdir(formatDirName)) + { + err("Could not create output directory %s\n", formatDirName.data()); + cleanUpDoxygen(); + exit(1); + } + return formatDirName; +} + +static QCString getQchFileName() +{ + QCString const & qchFile = Config_getString("QCH_FILE"); + if (!qchFile.isEmpty()) + { + return qchFile; + } + + QCString const & projectName = Config_getString("PROJECT_NAME"); + QCString const & versionText = Config_getString("PROJECT_NUMBER"); + + return QCString("../qch/") + + (projectName.isEmpty() ? QCString("index") : projectName) + + (versionText.isEmpty() ? QCString("") : QCString("-") + versionText) + + QCString(".qch"); +} + +void searchInputFiles(StringList &inputFiles) +{ + QStrList &exclPatterns = Config_getList("EXCLUDE_PATTERNS"); + bool alwaysRecursive = Config_getBool("RECURSIVE"); + StringDict excludeNameDict(1009); + excludeNameDict.setAutoDelete(TRUE); + + // gather names of all files in the include path + msg("Searching for include files...\n"); + QStrList &includePathList = Config_getList("INCLUDE_PATH"); + char *s=includePathList.first(); + while (s) + { + QStrList &pl = Config_getList("INCLUDE_FILE_PATTERNS"); + if (pl.count()==0) + { + pl = Config_getList("FILE_PATTERNS"); + } + readFileOrDirectory(s,0,Doxygen::includeNameDict,0,&pl, + &exclPatterns,0,0, + alwaysRecursive); + s=includePathList.next(); + } + + msg("Searching for example files...\n"); + QStrList &examplePathList = Config_getList("EXAMPLE_PATH"); + s=examplePathList.first(); + while (s) + { + readFileOrDirectory(s,0,Doxygen::exampleNameDict,0, + &Config_getList("EXAMPLE_PATTERNS"), + 0,0,0, + (alwaysRecursive || Config_getBool("EXAMPLE_RECURSIVE"))); + s=examplePathList.next(); + } + + msg("Searching for images...\n"); + QStrList &imagePathList=Config_getList("IMAGE_PATH"); + s=imagePathList.first(); + while (s) + { + readFileOrDirectory(s,0,Doxygen::imageNameDict,0,0, + 0,0,0, + alwaysRecursive); + s=imagePathList.next(); + } + + msg("Searching for dot files...\n"); + QStrList &dotFileList=Config_getList("DOTFILE_DIRS"); + s=dotFileList.first(); + while (s) + { + readFileOrDirectory(s,0,Doxygen::dotFileNameDict,0,0, + 0,0,0, + alwaysRecursive); + s=dotFileList.next(); + } + + msg("Searching for msc files...\n"); + QStrList &mscFileList=Config_getList("MSCFILE_DIRS"); + s=mscFileList.first(); + while (s) + { + readFileOrDirectory(s,0,Doxygen::mscFileNameDict,0,0, + 0,0,0, + alwaysRecursive); + s=mscFileList.next(); + } + + + msg("Searching for files to exclude\n"); + QStrList &excludeList = Config_getList("EXCLUDE"); + s=excludeList.first(); + while (s) + { + readFileOrDirectory(s,0,0,0,&Config_getList("FILE_PATTERNS"), + 0,0,&excludeNameDict, + alwaysRecursive, + FALSE); + s=excludeList.next(); + } + + /************************************************************************** + * Determine Input Files * + **************************************************************************/ + + msg("Searching for files to process...\n"); + QDict<void> *killDict = new QDict<void>(10007); + int inputSize=0; + QStrList &inputList=Config_getList("INPUT"); + inputFiles.setAutoDelete(TRUE); + s=inputList.first(); + while (s) + { + QCString path=s; + uint l = path.length(); + // strip trailing slashes + if (path.at(l-1)=='\\' || path.at(l-1)=='/') path=path.left(l-1); + + inputSize+=readFileOrDirectory( + path, + Doxygen::inputNameList, + Doxygen::inputNameDict, + &excludeNameDict, + &Config_getList("FILE_PATTERNS"), + &exclPatterns, + &inputFiles,0, + alwaysRecursive, + TRUE, + killDict); + s=inputList.next(); + } + delete killDict; +} + + +void parseInput() +{ + atexit(exitDoxygen); + + + /************************************************************************** + * Make sure the output directory exists + **************************************************************************/ + QCString &outputDirectory = Config_getString("OUTPUT_DIRECTORY"); + if (outputDirectory.isEmpty()) + { + outputDirectory=QDir::currentDirPath(); + } + else + { + QDir dir(outputDirectory); + if (!dir.exists()) + { + dir.setPath(QDir::currentDirPath()); + if (!dir.mkdir(outputDirectory)) + { + err("error: tag OUTPUT_DIRECTORY: Output directory `%s' does not " + "exist and cannot be created\n",outputDirectory.data()); + cleanUpDoxygen(); + exit(1); + } + else if (!Config_getBool("QUIET")) + { + err("Notice: Output directory `%s' does not exist. " + "I have created it for you.\n", outputDirectory.data()); + } + dir.cd(outputDirectory); + } + outputDirectory=dir.absPath(); + } + + /************************************************************************** + * Initialize global lists and dictionaries + **************************************************************************/ + + int cacheSize = Config_getInt("SYMBOL_CACHE_SIZE"); + if (cacheSize<0) cacheSize=0; + if (cacheSize>9) cacheSize=9; + Doxygen::symbolCache = new ObjCache(16+cacheSize); // 16 -> room for 65536 elements, + // ~2.0 MByte "overhead" + //Doxygen::symbolCache = new ObjCache(1); // only to stress test cache behaviour + Doxygen::symbolStorage = new Store; + + // also scale lookup cache with SYMBOL_CACHE_SIZE + cacheSize = Config_getInt("LOOKUP_CACHE_SIZE"); + if (cacheSize<0) cacheSize=0; + if (cacheSize>9) cacheSize=9; + uint lookupSize = 65536 << cacheSize; + Doxygen::lookupCache = new QCache<LookupInfo>(lookupSize,lookupSize); + Doxygen::lookupCache->setAutoDelete(TRUE); + +#ifdef HAS_SIGNALS + signal(SIGINT, stopDoxygen); +#endif + + uint pid = portable_pid(); + Doxygen::objDBFileName.sprintf("doxygen_objdb_%d.tmp",pid); + Doxygen::objDBFileName.prepend(outputDirectory+"/"); + Doxygen::entryDBFileName.sprintf("doxygen_entrydb_%d.tmp",pid); + Doxygen::entryDBFileName.prepend(outputDirectory+"/"); + + if (Doxygen::symbolStorage->open(Doxygen::objDBFileName)==-1) + { + err("Failed to open temporary file %s\n",Doxygen::objDBFileName.data()); + exit(1); + } + + + /************************************************************************** + * Initialize some global constants + **************************************************************************/ + + g_compoundKeywordDict.insert("template class",(void *)8); + g_compoundKeywordDict.insert("template struct",(void *)8); + g_compoundKeywordDict.insert("class",(void *)8); + g_compoundKeywordDict.insert("struct",(void *)8); + g_compoundKeywordDict.insert("union",(void *)8); + g_compoundKeywordDict.insert("interface",(void *)8); + g_compoundKeywordDict.insert("exception",(void *)8); + + + /************************************************************************** + * Check/create output directorties * + **************************************************************************/ + + QCString htmlOutput; + bool &generateHtml = Config_getBool("GENERATE_HTML"); + if (generateHtml) + htmlOutput = createOutputDirectory(outputDirectory,"HTML_OUTPUT","/html"); + + QCString xmlOutput; + bool &generateXml = Config_getBool("GENERATE_XML"); + if (generateXml) + xmlOutput = createOutputDirectory(outputDirectory,"XML_OUTPUT","/xml"); + + QCString latexOutput; + bool &generateLatex = Config_getBool("GENERATE_LATEX"); + if (generateLatex) + latexOutput = createOutputDirectory(outputDirectory,"LATEX_OUTPUT","/latex"); + + QCString rtfOutput; + bool &generateRtf = Config_getBool("GENERATE_RTF"); + if (generateRtf) + rtfOutput = createOutputDirectory(outputDirectory,"RTF_OUTPUT","/rtf"); + + QCString manOutput; + bool &generateMan = Config_getBool("GENERATE_MAN"); + if (generateMan) + manOutput = createOutputDirectory(outputDirectory,"MAN_OUTPUT","/man"); + + + if (Config_getBool("HAVE_DOT")) + { + QCString curFontPath = Config_getString("DOT_FONTPATH"); + if (curFontPath.isEmpty()) + { + portable_getenv("DOTFONTPATH"); + QCString newFontPath = "."; + if (!curFontPath.isEmpty()) + { + newFontPath+=portable_pathListSeparator(); + newFontPath+=curFontPath; + } + portable_setenv("DOTFONTPATH",newFontPath); + } + else + { + portable_setenv("DOTFONTPATH",curFontPath); + } + } + + + + /************************************************************************** + * Handle layout file * + **************************************************************************/ + + LayoutDocManager::instance().init(); + QCString &layoutFileName = Config_getString("LAYOUT_FILE"); + bool defaultLayoutUsed = FALSE; + if (layoutFileName.isEmpty()) + { + layoutFileName = "DoxygenLayout.xml"; + defaultLayoutUsed = TRUE; + } + + QFile layoutFile(layoutFileName); + if (layoutFile.open(IO_ReadOnly)) + { + msg("Parsing layout file %s...\n",layoutFileName.data()); + QTextStream t(&layoutFile); + t.setEncoding(QTextStream::Latin1); + LayoutDocManager::instance().parse(t,layoutFileName); + } + else if (!defaultLayoutUsed) + { + err("warning: failed to open layout file '%s' for reading!\n",layoutFileName.data()); + } + + /************************************************************************** + * Read and preprocess input * + **************************************************************************/ + + // prevent search in the output directories + QStrList &exclPatterns = Config_getList("EXCLUDE_PATTERNS"); + if (generateHtml) exclPatterns.append(htmlOutput); + if (generateXml) exclPatterns.append(xmlOutput); + if (generateLatex) exclPatterns.append(latexOutput); + if (generateRtf) exclPatterns.append(rtfOutput); + if (generateMan) exclPatterns.append(manOutput); + + + searchInputFiles(g_inputFiles); + + // Notice: the order of the function calls below is very important! + + if (Config_getBool("GENERATE_HTML")) + { + readFormulaRepository(); + } + + /************************************************************************** + * Handle Tag Files * + **************************************************************************/ + + g_storage = new FileStorage; + g_storage->setName(Doxygen::entryDBFileName); + if (!g_storage->open(IO_WriteOnly)) + { + err("Failed to create temporary storage file %s\n", + Doxygen::entryDBFileName.data()); + exit(1); + } + Entry *root=new Entry; + EntryNav *rootNav = new EntryNav(0,root); + rootNav->setEntry(root); + msg("Reading and parsing tag files\n"); + + QStrList &tagFileList = Config_getList("TAGFILES"); + char *s=tagFileList.first(); + while (s) + { + readTagFile(root,s); + root->createNavigationIndex(rootNav,g_storage,0); + s=tagFileList.next(); + } + + /************************************************************************** + * Parse source files * + **************************************************************************/ + + //printNavTree(rootNav,0); + + // we are done with input scanning now, so free up the buffers used by flex + // (can be around 4MB) + preFreeScanner(); + scanFreeScanner(); + pyscanFreeScanner(); + + //delete rootNav; + //g_storage.close(); + //exit(1); + + if (Config_getBool("BUILTIN_STL_SUPPORT")) + { + addSTLClasses(rootNav); + } + + parseFiles(root,rootNav); + g_storage->close(); + if (!g_storage->open(IO_ReadOnly)) + { + err("Failed to open temporary storage file %s for reading", + Doxygen::entryDBFileName.data()); + exit(1); + } + + /************************************************************************** + * Gather information * + **************************************************************************/ + + msg("Building group list...\n"); + buildGroupList(rootNav); + organizeSubGroups(rootNav); + + msg("Building directory list...\n"); + buildDirectories(); + findDirDocumentation(rootNav); + + msg("Building namespace list...\n"); + buildNamespaceList(rootNav); + findUsingDirectives(rootNav); + + msg("Building file list...\n"); + buildFileList(rootNav); + //generateFileTree(); + + msg("Building class list...\n"); + buildClassList(rootNav); + + msg("Associating documentation with classes...\n"); + buildClassDocList(rootNav); + + // build list of using declarations here (global list) + buildListOfUsingDecls(rootNav); + + msg("Computing nesting relations for classes...\n"); + resolveClassNestingRelations(); + distributeClassGroupRelations(); + + // calling buildClassList may result in cached relations that + // become invalid after resolveClassNestingRelations(), that's why + // we need to clear the cache here + Doxygen::lookupCache->clear(); + // we don't need the list of using declaration anymore + g_usingDeclarations.clear(); + + msg("Building example list...\n"); + buildExampleList(rootNav); + + msg("Searching for enumerations...\n"); + findEnums(rootNav); + + // Since buildVarList calls isVarWithConstructor + // and this calls getResolvedClass we need to process + // typedefs first so the relations between classes via typedefs + // are properly resolved. See bug 536385 for an example. + msg("Searching for documented typedefs...\n"); + buildTypedefList(rootNav); + + msg("Searching for members imported via using declarations...\n"); + findUsingDeclImports(rootNav); + // this should be after buildTypedefList in order to properly import + // used typedefs + findUsingDeclarations(rootNav); + + msg("Searching for included using directives...\n"); + findIncludedUsingDirectives(); + + msg("Searching for documented variables...\n"); + buildVarList(rootNav); + + msg("Building member list...\n"); // using class info only ! + buildFunctionList(rootNav); + + msg("Searching for friends...\n"); + findFriends(); + + msg("Searching for documented defines...\n"); + findDefineDocumentation(rootNav); + + findClassEntries(rootNav); + msg("Computing class inheritance relations...\n"); + findInheritedTemplateInstances(); + msg("Computing class usage relations...\n"); + findUsedTemplateInstances(); + if (Config_getBool("INLINE_SIMPLE_STRUCTS")) + { + msg("Searching for tag less structs...\n"); + findTagLessClasses(); + } + + msg("Flushing cached template relations that have become invalid...\n"); + flushCachedTemplateRelations(); + + msg("Creating members for template instances...\n"); + createTemplateInstanceMembers(); + + msg("Computing class relations...\n"); + computeTemplateClassRelations(); + flushUnresolvedRelations(); + computeClassRelations(); + if (Config_getBool("OPTIMIZE_OUTPUT_VHDL")) + { + VhdlDocGen::computeVhdlComponentRelations(); + } + g_classEntries.clear(); + + msg("Add enum values to enums...\n"); + addEnumValuesToEnums(rootNav); + findEnumDocumentation(rootNav); + + msg("Searching for member function documentation...\n"); + findObjCMethodDefinitions(rootNav); + findMemberDocumentation(rootNav); // may introduce new members ! + + transferRelatedFunctionDocumentation(); + transferFunctionDocumentation(); + + msg("Building page list...\n"); + buildPageList(rootNav); + + msg("Search for main page...\n"); + findMainPage(rootNav); + + msg("Computing page relations...\n"); + computePageRelations(rootNav); + checkPageRelations(); + + msg("Determining the scope of groups...\n"); + findGroupScope(rootNav); + + msg("Sorting lists...\n"); + Doxygen::memberNameSDict->sort(); + Doxygen::functionNameSDict->sort(); + Doxygen::hiddenClasses->sort(); + Doxygen::classSDict->sort(); + + msg("Freeing entry tree\n"); + delete rootNav; + g_storage->close(); + delete g_storage; + g_storage=0; + + QDir thisDir; + thisDir.remove(Doxygen::entryDBFileName); + + msg("Determining which enums are documented\n"); + findDocumentedEnumValues(); + + msg("Computing member relations...\n"); + computeMemberRelations(); + + msg("Building full member lists recursively...\n"); + mergeCategories(); + buildCompleteMemberLists(); + + msg("Adding members to member groups.\n"); + addMembersToMemberGroup(); + + if (Config_getBool("DISTRIBUTE_GROUP_DOC")) + { + msg("Distributing member group documentation.\n"); + distributeMemberGroupDocumentation(); + } + + msg("Computing member references...\n"); + computeMemberReferences(); + + if (Config_getBool("INHERIT_DOCS")) + { + msg("Inheriting documentation...\n"); + inheritDocumentation(); + } + + // compute the shortest possible names of all files + // without loosing the uniqueness of the file names. + msg("Generating disk names...\n"); + Doxygen::inputNameList->generateDiskNames(); + + msg("Adding source references...\n"); + addSourceReferences(); + + msg("Adding xrefitems...\n"); + addListReferences(); + generateXRefPages(); + + msg("Sorting member lists...\n"); + sortMemberLists(); + + if (Config_getBool("SHOW_DIRECTORIES") && Config_getBool("DIRECTORY_GRAPH")) + { + msg("Computing dependencies between directories...\n"); + computeDirDependencies(); + } + + //msg("Resolving citations...\n"); + //Doxygen::citeDict->resolve(); + + msg("Generating citations page...\n"); + Doxygen::citeDict->generatePage(); + + msg("Counting data structures...\n"); + countDataStructures(); + + msg("Resolving user defined references...\n"); + resolveUserReferences(); + + msg("Finding anchors and sections in the documentation...\n"); + findSectionsInDocumentation(); + + transferFunctionReferences(); + + msg("Combining using relations...\n"); + combineUsingRelations(); + + msg("Adding members to index pages...\n"); + addMembersToIndex(); +} + +void generateOutput() +{ + /************************************************************************** + * Initialize output generators * + **************************************************************************/ + + //// dump all symbols + if (g_dumpSymbolMap) + { + dumpSymbolMap(); + exit(0); + } + + initDocParser(); + + g_outputList = new OutputList(TRUE); + if (Config_getBool("GENERATE_HTML")) + { + g_outputList->add(new HtmlGenerator); + HtmlGenerator::init(); + + // add HTML indexers that are enabled + bool generateHtmlHelp = Config_getBool("GENERATE_HTMLHELP"); + bool generateEclipseHelp = Config_getBool("GENERATE_ECLIPSEHELP"); + bool generateQhp = Config_getBool("GENERATE_QHP"); + bool generateTreeView = Config_getBool("GENERATE_TREEVIEW"); + bool generateDocSet = Config_getBool("GENERATE_DOCSET"); + if (generateEclipseHelp) Doxygen::indexList.addIndex(new EclipseHelp); + if (generateHtmlHelp) Doxygen::indexList.addIndex(new HtmlHelp); + if (generateQhp) Doxygen::indexList.addIndex(new Qhp); + if (generateTreeView) Doxygen::indexList.addIndex(new FTVHelp(TRUE)); + if (generateDocSet) Doxygen::indexList.addIndex(new DocSets); + Doxygen::indexList.initialize(); + HtmlGenerator::writeTabData(); + + // copy static stuff + copyStyleSheet(); + copyLogo(); + copyExtraFiles(); + if (!generateTreeView && Config_getBool("USE_INLINE_TREES")) + { + FTVHelp::generateTreeViewImages(); + } + } + if (Config_getBool("GENERATE_LATEX")) + { + g_outputList->add(new LatexGenerator); + LatexGenerator::init(); + } + if (Config_getBool("GENERATE_MAN")) + { + g_outputList->add(new ManGenerator); + ManGenerator::init(); + } + if (Config_getBool("GENERATE_RTF")) + { + g_outputList->add(new RTFGenerator); + RTFGenerator::init(); + } + + if (Config_getBool("USE_HTAGS")) + { + Htags::useHtags = TRUE; + QCString htmldir = Config_getString("HTML_OUTPUT"); + if (!Htags::execute(htmldir)) + err("error: USE_HTAGS is YES but htags(1) failed. \n"); + if (!Htags::loadFilemap(htmldir)) + err("error: htags(1) ended normally but failed to load the filemap. \n"); + } + + /************************************************************************** + * Generate documentation * + **************************************************************************/ + + QFile *tag=0; + QCString &generateTagFile = Config_getString("GENERATE_TAGFILE"); + if (!generateTagFile.isEmpty()) + { + tag=new QFile(generateTagFile); + if (!tag->open(IO_WriteOnly)) + { + err("error: cannot open tag file %s for writing\n", + generateTagFile.data() + ); + cleanUpDoxygen(); + exit(1); + } + Doxygen::tagFile.setDevice(tag); + Doxygen::tagFile << "<?xml version='1.0' encoding='ISO-8859-1' standalone='yes' ?>" << endl; + Doxygen::tagFile << "<tagfile>" << endl; + } + + if (Config_getBool("GENERATE_HTML")) writeDoxFont(Config_getString("HTML_OUTPUT")); + if (Config_getBool("GENERATE_LATEX")) writeDoxFont(Config_getString("LATEX_OUTPUT")); + if (Config_getBool("GENERATE_RTF")) writeDoxFont(Config_getString("RTF_OUTPUT")); + + msg("Generating style sheet...\n"); + //printf("writing style info\n"); + QCString genString = + theTranslator->trGeneratedAt(dateToString(TRUE),Config_getString("PROJECT_NAME")); + g_outputList->writeStyleInfo(0); // write first part + g_outputList->disableAllBut(OutputGenerator::Latex); + g_outputList->parseText(genString); + g_outputList->writeStyleInfo(1); // write second part + //parseText(*g_outputList,theTranslator->trWrittenBy()); + g_outputList->writeStyleInfo(2); // write third part + g_outputList->parseText(genString); + g_outputList->writeStyleInfo(3); // write fourth part + //parseText(*g_outputList,theTranslator->trWrittenBy()); + g_outputList->writeStyleInfo(4); // write last part + g_outputList->enableAll(); + + static bool searchEngine = Config_getBool("SEARCHENGINE"); + static bool serverBasedSearch = Config_getBool("SERVER_BASED_SEARCH"); + + // generate search indices (need to do this before writing other HTML + // pages as these contain a drop down menu with options depending on + // what categories we find in this function. + if (Config_getBool("GENERATE_HTML") && searchEngine) + { + msg("Generating search indices...\n"); + QCString searchDirName = Config_getString("HTML_OUTPUT")+"/search"; + QDir searchDir(searchDirName); + if (!searchDir.exists() && !searchDir.mkdir(searchDirName)) + { + err("error: Could not create search results directory '%s' $PWD='%s'\n", + searchDirName.data(),QDir::currentDirPath().data()); + exit(1); + } + HtmlGenerator::writeSearchData(searchDirName); + if (!serverBasedSearch) // client side search index + { + writeJavascriptSearchIndex(); + } + } + + msg("Generating example documentation...\n"); + generateExampleDocs(); + + msg("Generating file sources...\n"); + if (!Htags::useHtags) + { + generateFileSources(); + } + + msg("Generating file documentation...\n"); + generateFileDocs(); + + msg("Generating page documentation...\n"); + generatePageDocs(); + + msg("Generating group documentation...\n"); + generateGroupDocs(); + + msg("Generating class documentation...\n"); + generateClassDocs(); + + msg("Generating namespace index...\n"); + generateNamespaceDocs(); + + if (Config_getBool("GENERATE_LEGEND")) + { + msg("Generating graph info page...\n"); + writeGraphInfo(*g_outputList); + } + + if (Config_getBool("SHOW_DIRECTORIES")) + { + msg("Generating directory documentation...\n"); + generateDirDocs(*g_outputList); + } + + if (Doxygen::formulaList.count()>0 && Config_getBool("GENERATE_HTML") + && !Config_getBool("USE_MATHJAX")) + { + msg("Generating bitmaps for formulas in HTML...\n"); + Doxygen::formulaList.generateBitmaps(Config_getString("HTML_OUTPUT")); + } + + writeIndexHierarchy(*g_outputList); + + msg("finalizing index lists...\n"); + Doxygen::indexList.finalize(); + + if (!Config_getString("GENERATE_TAGFILE").isEmpty()) + { + Doxygen::tagFile << "</tagfile>" << endl; + delete tag; + } + + if (Config_getBool("DOT_CLEANUP")) + { + if (Config_getBool("GENERATE_HTML")) + removeDoxFont(Config_getString("HTML_OUTPUT")); + if (Config_getBool("GENERATE_RTF")) + removeDoxFont(Config_getString("RTF_OUTPUT")); + if (Config_getBool("GENERATE_LATEX")) + removeDoxFont(Config_getString("LATEX_OUTPUT")); + } + + if (Config_getBool("GENERATE_XML")) + { + msg("Generating XML output...\n"); + Doxygen::generatingXmlOutput=TRUE; + generateXML(); + Doxygen::generatingXmlOutput=FALSE; + } + if (Config_getBool("GENERATE_AUTOGEN_DEF")) + { + msg("Generating AutoGen DEF output...\n"); + generateDEF(); + } + if (Config_getBool("GENERATE_PERLMOD")) + { + msg("Generating Perl module output...\n"); + generatePerlMod(); + } + if (Config_getBool("GENERATE_HTML") && searchEngine && serverBasedSearch) + { + msg("Generating search index\n"); + HtmlGenerator::writeSearchPage(); + Doxygen::searchIndex->write(Config_getString("HTML_OUTPUT")+"/search/search.idx"); + } + + if (Config_getBool("GENERATE_RTF")) + { + msg("Combining RTF output...\n"); + if (!RTFGenerator::preProcessFileInplace(Config_getString("RTF_OUTPUT"),"refman.rtf")) + { + err("An error occurred during post-processing the RTF files!\n"); + } + } + + if (Config_getBool("HAVE_DOT")) + { + DotManager::instance()->run(); + } + + if (Config_getBool("GENERATE_HTML") && + Config_getBool("GENERATE_HTMLHELP") && + !Config_getString("HHC_LOCATION").isEmpty()) + { + msg("Running html help compiler...\n"); + QString oldDir = QDir::currentDirPath(); + QDir::setCurrent(Config_getString("HTML_OUTPUT")); + portable_sysTimerStart(); + if (portable_system(Config_getString("HHC_LOCATION"), "index.hhp", FALSE)) + { + err("error: failed to run html help compiler on index.hhp\n"); + } + portable_sysTimerStop(); + QDir::setCurrent(oldDir); + } + if ( Config_getBool("GENERATE_HTML") && + Config_getBool("GENERATE_QHP") && + !Config_getString("QHG_LOCATION").isEmpty()) + { + msg("Running qhelpgenerator...\n"); + QCString const qhpFileName = Qhp::getQhpFileName(); + QCString const qchFileName = getQchFileName(); + + QCString const args = QCString().sprintf("%s -o \"%s\"", qhpFileName.data(), qchFileName.data()); + QString const oldDir = QDir::currentDirPath(); + QDir::setCurrent(Config_getString("HTML_OUTPUT")); + portable_sysTimerStart(); + if (portable_system(Config_getString("QHG_LOCATION"), args.data(), FALSE)) + { + err("error: failed to run qhelpgenerator on index.qhp\n"); + } + portable_sysTimerStop(); + QDir::setCurrent(oldDir); + } + + int cacheParam; + msg("symbol cache used %d/%d hits=%d misses=%d\n", + Doxygen::symbolCache->count(), + Doxygen::symbolCache->size(), + Doxygen::symbolCache->hits(), + Doxygen::symbolCache->misses()); + cacheParam = computeIdealCacheParam(Doxygen::symbolCache->misses()); + if (cacheParam>Config_getInt("SYMBOL_CACHE_SIZE")) + { + msg("Note: based on cache misses the ideal setting for SYMBOL_CACHE_SIZE is %d at the cost of higher memory usage.\n",cacheParam); + } + msg("lookup cache used %d/%d hits=%d misses=%d\n", + Doxygen::lookupCache->count(), + Doxygen::lookupCache->size(), + Doxygen::lookupCache->hits(), + Doxygen::lookupCache->misses()); + cacheParam = computeIdealCacheParam(Doxygen::lookupCache->misses()*2/3); // part of the cache is flushed, hence the 2/3 correction factor + if (cacheParam>Config_getInt("LOOKUP_CACHE_SIZE")) + { + msg("Note: based on cache misses the ideal setting for LOOKUP_CACHE_SIZE is %d at the cost of higher memory usage.\n",cacheParam); + } + + if (Debug::isFlagSet(Debug::Time)) + { + msg("Total elapsed time: %.3f seconds\n(of which %.3f seconds waiting for external tools to finish)\n", + ((double)Doxygen::runningTime.elapsed())/1000.0, + portable_getSysElapsedTime() + ); + } + else + { + msg("finished...\n"); + } + + /************************************************************************** + * Start cleaning up * + **************************************************************************/ + + cleanUpDoxygen(); + + finializeDocParser(); + Doxygen::symbolStorage->close(); + QDir thisDir; + thisDir.remove(Doxygen::objDBFileName); + Config::deleteInstance(); + QTextCodec::deleteAllCodecs(); + delete Doxygen::symbolCache; + delete Doxygen::symbolMap; + delete Doxygen::symbolStorage; + g_successfulRun=TRUE; +} + diff --git a/trunk/src/doxygen.css b/trunk/src/doxygen.css new file mode 100644 index 0000000..831831a --- /dev/null +++ b/trunk/src/doxygen.css @@ -0,0 +1,1015 @@ +/* The standard CSS for doxygen */ + +body, table, div, p, dl { + font-family: Lucida Grande, Verdana, Geneva, Arial, sans-serif; + font-size: 13px; + line-height: 1.3; +} + +/* @group Heading Levels */ + +h1 { + font-size: 150%; +} + +.title { + font-size: 150%; + font-weight: bold; + margin: 10px 2px; +} + +h2 { + font-size: 120%; +} + +h3 { + font-size: 100%; +} + +dt { + font-weight: bold; +} + +div.multicol { + -moz-column-gap: 1em; + -webkit-column-gap: 1em; + -moz-column-count: 3; + -webkit-column-count: 3; +} + +p.startli, p.startdd, p.starttd { + margin-top: 2px; +} + +p.endli { + margin-bottom: 0px; +} + +p.enddd { + margin-bottom: 4px; +} + +p.endtd { + margin-bottom: 2px; +} + +/* @end */ + +caption { + font-weight: bold; +} + +span.legend { + font-size: 70%; + text-align: center; +} + +h3.version { + font-size: 90%; + text-align: center; +} + +div.qindex, div.navtab{ + background-color: ##ee; + border: 1px solid ##b0; + text-align: center; +} + +div.qindex, div.navpath { + width: 100%; + line-height: 140%; +} + +div.navtab { + margin-right: 15px; +} + +/* @group Link Styling */ + +a { + color: ##50; + font-weight: normal; + text-decoration: none; +} + +.contents a:visited { + color: ##60; +} + +a:hover { + text-decoration: underline; +} + +a.qindex { + font-weight: bold; +} + +a.qindexHL { + font-weight: bold; + background-color: ##AA; + color: #ffffff; + border: 1px double ##98; +} + +.contents a.qindexHL:visited { + color: #ffffff; +} + +a.el { + font-weight: bold; +} + +a.elRef { +} + +a.code, a.code:visited { + color: #4665A2; +} + +a.codeRef, a.codeRef:visited { + color: #4665A2; +} + +/* @end */ + +dl.el { + margin-left: -1cm; +} + +.fragment { + font-family: monospace, fixed; + font-size: 105%; +} + +pre.fragment { + border: 1px solid ##CC; + background-color: ##FC; + padding: 4px 6px; + margin: 4px 8px 4px 2px; + overflow: auto; + word-wrap: break-word; + font-size: 9pt; + line-height: 125%; +} + +div.ah { + background-color: black; + font-weight: bold; + color: #ffffff; + margin-bottom: 3px; + margin-top: 3px; + padding: 0.2em; + border: solid thin #333; + border-radius: 0.5em; + -webkit-border-radius: .5em; + -moz-border-radius: .5em; + box-shadow: 2px 2px 3px #999; + -webkit-box-shadow: 2px 2px 3px #999; + -moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px; + background-image: -webkit-gradient(linear, left top, left bottom, from(#eee), to(#000),color-stop(0.3, #444)); + background-image: -moz-linear-gradient(center top, #eee 0%, #444 40%, #000); +} + +div.groupHeader { + margin-left: 16px; + margin-top: 12px; + font-weight: bold; +} + +div.groupText { + margin-left: 16px; + font-style: italic; +} + +body { + background-color: white; + color: black; + margin: 0; +} + +div.contents { + margin-top: 10px; + margin-left: 8px; + margin-right: 8px; +} + +td.indexkey { + background-color: ##ee; + font-weight: bold; + border: 1px solid ##cc; + margin: 2px 0px 2px 0; + padding: 2px 10px; + white-space: nowrap; + vertical-align: top; +} + +td.indexvalue { + background-color: ##ee; + border: 1px solid ##cc; + padding: 2px 10px; + margin: 2px 0px; +} + +tr.memlist { + background-color: ##f0; +} + +p.formulaDsp { + text-align: center; +} + +img.formulaDsp { + +} + +img.formulaInl { + vertical-align: middle; +} + +div.center { + text-align: center; + margin-top: 0px; + margin-bottom: 0px; + padding: 0px; +} + +div.center img { + border: 0px; +} + +address.footer { + text-align: right; + padding-right: 12px; +} + +img.footer { + border: 0px; + vertical-align: middle; +} + +/* @group Code Colorization */ + +span.keyword { + color: #008000 +} + +span.keywordtype { + color: #604020 +} + +span.keywordflow { + color: #e08000 +} + +span.comment { + color: #800000 +} + +span.preprocessor { + color: #806020 +} + +span.stringliteral { + color: #002080 +} + +span.charliteral { + color: #008080 +} + +span.vhdldigit { + color: #ff00ff +} + +span.vhdlchar { + color: #000000 +} + +span.vhdlkeyword { + color: #700070 +} + +span.vhdllogic { + color: #ff0000 +} + +blockquote { + background-color: ##F8; + border-left: 2px solid ##AA; + margin: 0 24px 0 4px; + padding: 0 12px 0 16px; +} + +/* @end */ + +/* +.search { + color: #003399; + font-weight: bold; +} + +form.search { + margin-bottom: 0px; + margin-top: 0px; +} + +input.search { + font-size: 75%; + color: #000080; + font-weight: normal; + background-color: #e8eef2; +} +*/ + +td.tiny { + font-size: 75%; +} + +.dirtab { + padding: 4px; + border-collapse: collapse; + border: 1px solid ##b0; +} + +th.dirtab { + background: ##ee; + font-weight: bold; +} + +hr { + height: 0px; + border: none; + border-top: 1px solid ##66; +} + +hr.footer { + height: 1px; +} + +/* @group Member Descriptions */ + +table.memberdecls { + border-spacing: 0px; + padding: 0px; +} + +.mdescLeft, .mdescRight, +.memItemLeft, .memItemRight, +.memTemplItemLeft, .memTemplItemRight, .memTemplParams { + background-color: ##FA; + border: none; + margin: 4px; + padding: 1px 0 0 8px; +} + +.mdescLeft, .mdescRight { + padding: 0px 8px 4px 8px; + color: #555; +} + +.memItemLeft, .memItemRight, .memTemplParams { + border-top: 1px solid ##cc; +} + +.memItemLeft, .memTemplItemLeft { + white-space: nowrap; +} + +.memItemRight { + width: 100%; +} + +.memTemplParams { + color: ##60; + white-space: nowrap; +} + +/* @end */ + +/* @group Member Details */ + +/* Styles for detailed member documentation */ + +.memtemplate { + font-size: 80%; + color: ##60; + font-weight: normal; + margin-left: 9px; +} + +.memnav { + background-color: ##ee; + border: 1px solid ##b0; + text-align: center; + margin: 2px; + margin-right: 15px; + padding: 2px; +} + +.mempage { + width: 100%; +} + +.memitem { + padding: 0; + margin-bottom: 10px; + margin-right: 5px; +} + +.memname { + font-weight: bold; + margin-left: 6px; +} + +.memname td { + vertical-align: bottom; +} + +.memproto, dl.reflist dt { + border-top: 1px solid ##B4; + border-left: 1px solid ##B4; + border-right: 1px solid ##B4; + padding: 6px 0px 6px 0px; + color: ##2b; + font-weight: bold; + text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.9); + /* opera specific markup */ + box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); + border-top-right-radius: 8px; + border-top-left-radius: 8px; + /* firefox specific markup */ + -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px; + -moz-border-radius-topright: 8px; + -moz-border-radius-topleft: 8px; + /* webkit specific markup */ + -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); + -webkit-border-top-right-radius: 8px; + -webkit-border-top-left-radius: 8px; + background-image:url('nav_f.png'); + background-repeat:repeat-x; + background-color: ##E6; + +} + +.memdoc, dl.reflist dd { + border-bottom: 1px solid ##B4; + border-left: 1px solid ##B4; + border-right: 1px solid ##B4; + padding: 2px 5px; + background-color: ##FC; + border-top-width: 0; + /* opera specific markup */ + border-bottom-left-radius: 8px; + border-bottom-right-radius: 8px; + box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); + /* firefox specific markup */ + -moz-border-radius-bottomleft: 8px; + -moz-border-radius-bottomright: 8px; + -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px; + background-image: -moz-linear-gradient(center top, ##FF 0%, ##FF 60%, ##F8 95%, ##F0); + /* webkit specific markup */ + -webkit-border-bottom-left-radius: 8px; + -webkit-border-bottom-right-radius: 8px; + -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); + background-image: -webkit-gradient(linear,center top,center bottom,from(##FF), color-stop(0.6,##FF), color-stop(0.60,##FF), color-stop(0.95,##F8), to(##F0)); +} + +dl.reflist dt { + padding: 5px; +} + +dl.reflist dd { + margin: 0px 0px 10px 0px; + padding: 5px; +} + +.paramkey { + text-align: right; +} + +.paramtype { + white-space: nowrap; +} + +.paramname { + color: #602020; + white-space: nowrap; +} +.paramname em { + font-style: normal; +} + +.params, .retval, .exception, .tparams { + border-spacing: 6px 2px; +} + +.params .paramname, .retval .paramname { + font-weight: bold; + vertical-align: top; +} + +.params .paramtype { + font-style: italic; + vertical-align: top; +} + +.params .paramdir { + font-family: "courier new",courier,monospace; + vertical-align: top; +} + + + + +/* @end */ + +/* @group Directory (tree) */ + +/* for the tree view */ + +.ftvtree { + font-family: sans-serif; + margin: 0px; +} + +/* these are for tree view when used as main index */ + +.directory { + font-size: 9pt; + font-weight: bold; + margin: 5px; +} + +.directory h3 { + margin: 0px; + margin-top: 1em; + font-size: 11pt; +} + +/* +The following two styles can be used to replace the root node title +with an image of your choice. Simply uncomment the next two styles, +specify the name of your image and be sure to set 'height' to the +proper pixel height of your image. +*/ + +/* +.directory h3.swap { + height: 61px; + background-repeat: no-repeat; + background-image: url("yourimage.gif"); +} +.directory h3.swap span { + display: none; +} +*/ + +.directory > h3 { + margin-top: 0; +} + +.directory p { + margin: 0px; + white-space: nowrap; +} + +.directory div { + display: none; + margin: 0px; +} + +.directory img { + vertical-align: -30%; +} + +/* these are for tree view when not used as main index */ + +.directory-alt { + font-size: 100%; + font-weight: bold; +} + +.directory-alt h3 { + margin: 0px; + margin-top: 1em; + font-size: 11pt; +} + +.directory-alt > h3 { + margin-top: 0; +} + +.directory-alt p { + margin: 0px; + white-space: nowrap; +} + +.directory-alt div { + display: none; + margin: 0px; +} + +.directory-alt img { + vertical-align: -30%; +} + +/* @end */ + +div.dynheader { + margin-top: 8px; +} + +address { + font-style: normal; + color: ##33; +} + +table.doxtable { + border-collapse:collapse; + margin-top: 4px; + margin-bottom: 4px; +} + +table.doxtable td, table.doxtable th { + border: 1px solid ##37; + padding: 3px 7px 2px; +} + +table.doxtable th { + background-color: ##47; + color: #FFFFFF; + font-size: 110%; + padding-bottom: 4px; + padding-top: 5px; +} + +table.fieldtable { + width: 100%; + margin-bottom: 10px; + border: 1px solid ##B4; + border-spacing: 0px; + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + border-radius: 4px; + -moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px; + -webkit-box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.15); + box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.15); +} + +.fieldtable td, .fieldtable th { + padding: 3px 7px 2px; +} + +.fieldtable td.fieldtype, .fieldtable td.fieldname { + white-space: nowrap; + border-right: 1px solid ##B4; + border-bottom: 1px solid ##B4; + vertical-align: top; +} + +.fieldtable td.fielddoc { + border-bottom: 1px solid ##B4; + width: 100%; +} + +.fieldtable tr:last-child td { + border-bottom: none; +} + +.fieldtable th { + background-image:url('nav_f.png'); + background-repeat:repeat-x; + background-color: ##E6; + font-size: 90%; + color: ##2B; + padding-bottom: 4px; + padding-top: 5px; + text-align:left; + -moz-border-radius-topleft: 4px; + -moz-border-radius-topright: 4px; + -webkit-border-top-left-radius: 4px; + -webkit-border-top-right-radius: 4px; + border-top-left-radius: 4px; + border-top-right-radius: 4px; + border-bottom: 1px solid ##B4; +} + + +.tabsearch { + top: 0px; + left: 10px; + height: 36px; + background-image: url('tab_b.png'); + z-index: 101; + overflow: hidden; + font-size: 13px; +} + +.navpath ul +{ + font-size: 11px; + background-image:url('tab_b.png'); + background-repeat:repeat-x; + height:30px; + line-height:30px; + color:##9b; + border:solid 1px ##ca; + overflow:hidden; + margin:0px; + padding:0px; +} + +.navpath li +{ + list-style-type:none; + float:left; + padding-left:10px; + padding-right:15px; + background-image:url('bc_s.png'); + background-repeat:no-repeat; + background-position:right; + color:##45; +} + +.navpath li.navelem a +{ + height:32px; + display:block; + text-decoration: none; + outline: none; +} + +.navpath li.navelem a:hover +{ + color:##80; +} + +.navpath li.footer +{ + list-style-type:none; + float:right; + padding-left:10px; + padding-right:15px; + background-image:none; + background-repeat:no-repeat; + background-position:right; + color:##45; + font-size: 8pt; +} + + +div.summary +{ + float: right; + font-size: 8pt; + padding-right: 5px; + width: 50%; + text-align: right; +} + +div.summary a +{ + white-space: nowrap; +} + +div.ingroups +{ + margin-left: 5px; + font-size: 8pt; + padding-left: 5px; + width: 50%; + text-align: left; +} + +div.ingroups a +{ + white-space: nowrap; +} + +div.header +{ + background-image:url('nav_h.png'); + background-repeat:repeat-x; + background-color: ##FA; + margin: 0px; + border-bottom: 1px solid ##CC; +} + +div.headertitle +{ + padding: 5px 5px 5px 7px; +} + +dl +{ + padding: 0 0 0 10px; +} + +/* dl.note, dl.warning, dl.attention, dl.pre, dl.post, dl.invariant, dl.deprecated, dl.todo, dl.test, dl.bug */ +dl.section +{ + border-left:4px solid; + padding: 0 0 0 6px; +} + +dl.note +{ + border-color: #D0C000; +} + +dl.warning, dl.attention +{ + border-color: #FF0000; +} + +dl.pre, dl.post, dl.invariant +{ + border-color: #00D000; +} + +dl.deprecated +{ + border-color: #505050; +} + +dl.todo +{ + border-color: #00C0E0; +} + +dl.test +{ + border-color: #3030E0; +} + +dl.bug +{ + border-color: #C08050; +} + +dl.section dd { + margin-bottom: 6px; +} + + +#projectlogo +{ + text-align: center; + vertical-align: bottom; + border-collapse: separate; +} + +#projectlogo img +{ + border: 0px none; +} + +#projectname +{ + font: 300% Tahoma, Arial,sans-serif; + margin: 0px; + padding: 2px 0px; +} + +#projectbrief +{ + font: 120% Tahoma, Arial,sans-serif; + margin: 0px; + padding: 0px; +} + +#projectnumber +{ + font: 50% Tahoma, Arial,sans-serif; + margin: 0px; + padding: 0px; +} + +#titlearea +{ + padding: 0px; + margin: 0px; + width: 100%; + border-bottom: 1px solid ##70; +} + +.image +{ + text-align: center; +} + +.dotgraph +{ + text-align: center; +} + +.mscgraph +{ + text-align: center; +} + +.caption +{ + font-weight: bold; +} + +div.zoom +{ + border: 1px solid ##A0; +} + +dl.citelist { + margin-bottom:50px; +} + +dl.citelist dt { + color:##40; + float:left; + font-weight:bold; + margin-right:10px; + padding:5px; +} + +dl.citelist dd { + margin:2px 0; + padding:5px 0; +} + +div.toc { + padding: 14px 25px; + background-color: ##F6; + border: 1px solid ##DD; + border-radius: 7px 7px 7px 7px; + float: right; + height: auto; + margin: 0 20px 10px 10px; + width: 200px; +} + +div.toc li { + background: url("bdwn.png") no-repeat scroll 0 5px transparent; + font: 10px/1.2 Verdana,DejaVu Sans,Geneva,sans-serif; + margin-top: 5px; + padding-left: 10px; + padding-top: 2px; +} + +div.toc h3 { + font: bold 12px/1.2 Arial,FreeSans,sans-serif; + color: ##60; + border-bottom: 0 none; + margin: 0; +} + +div.toc ul { + list-style: none outside none; + border: medium none; + padding: 0px; +} + +div.toc li.level1 { + margin-left: 0px; +} + +div.toc li.level2 { + margin-left: 15px; +} + +div.toc li.level3 { + margin-left: 30px; +} + +div.toc li.level4 { + margin-left: 45px; +} + + +@media print +{ + #top { display: none; } + #side-nav { display: none; } + #nav-path { display: none; } + body { overflow:visible; } + h1, h2, h3, h4, h5, h6 { page-break-after: avoid; } + .summary { display: none; } + .memitem { page-break-inside: avoid; } + #doc-content + { + margin-left:0 !important; + height:auto !important; + width:auto !important; + overflow:inherit; + display:inline; + } + pre.fragment + { + overflow: visible; + text-wrap: unrestricted; + white-space: -moz-pre-wrap; /* Moz */ + white-space: -pre-wrap; /* Opera 4-6 */ + white-space: -o-pre-wrap; /* Opera 7 */ + white-space: pre-wrap; /* CSS3 */ + word-wrap: break-word; /* IE 5.5+ */ + } +} + diff --git a/trunk/src/doxygen.h b/trunk/src/doxygen.h new file mode 100644 index 0000000..0e436ec --- /dev/null +++ b/trunk/src/doxygen.h @@ -0,0 +1,177 @@ +/****************************************************************************** + * + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#ifndef DOXYGEN_H +#define DOXYGEN_H + +#include "qtbc.h" +#include <qdatetime.h> +#include <qcache.h> +#include "ftextstream.h" +#include "groupdef.h" +#include "filedef.h" +#include "classdef.h" +#include "memberdef.h" +#include "classlist.h" +#include "membername.h" +#include "filename.h" +#include "namespacedef.h" +#include "formula.h" +#include "section.h" +#include "membergroup.h" +#include "reflist.h" +#include "dirdef.h" +#include "index.h" +#include "docsets.h" + +class PageSList; +class PageSDict; +class PageDef; +class SearchIndex; +class ParserManager; +class ObjCache; +class Store; +class QFileInfo; +class BufStr; +class CiteDict; + +typedef QList<QCString> StringList; +typedef QDict<FileDef> FileDict; +typedef QDict<GroupDef> GroupDict; + +class StringDict : public QDict<QCString> +{ + public: + StringDict(uint size=17) : QDict<QCString>(size) {} + virtual ~StringDict() {} +}; + +struct LookupInfo +{ + LookupInfo() : classDef(0), typeDef(0) {} + LookupInfo(ClassDef *cd,MemberDef *td,QCString ts,QCString rt) + : classDef(cd), typeDef(td), templSpec(ts),resolvedType(rt) {} + ClassDef *classDef; + MemberDef *typeDef; + QCString templSpec; + QCString resolvedType; +}; + +extern QCString g_spaces; + +/*! \brief This class serves as a namespace for global variables used by doxygen. + * + * All fields in this class are public and static, so they can be used directly. + */ +class Doxygen +{ + public: + static ClassSDict *classSDict; + static ClassSDict *hiddenClasses; + static PageSDict *exampleSDict; + static PageSDict *pageSDict; + static PageDef *mainPage; + static bool insideMainPage; + static FileNameDict *includeNameDict; + static FileNameDict *exampleNameDict; + static FileNameDict *inputNameDict; + static FileNameList *inputNameList; + static FileNameDict *imageNameDict; + static FileNameDict *dotFileNameDict; + static FileNameDict *mscFileNameDict; + static QStrList tagfileList; + static MemberNameSDict *memberNameSDict; + static MemberNameSDict *functionNameSDict; + static FTextStream tagFile; + static SectionDict sectionDict; + static StringDict namespaceAliasDict; + static GroupSDict *groupSDict; + static NamespaceSDict *namespaceSDict; + static FormulaList formulaList; + static FormulaDict formulaDict; + static FormulaDict formulaNameDict; + static StringDict tagDestinationDict; + static StringDict aliasDict; + static QIntDict<MemberGroupInfo> memGrpInfoDict; + static QDict<void> expandAsDefinedDict; + static NamespaceDef *globalScope; + static QDict<RefList> *xrefLists; // array of xref lists: todo, test, bug, deprecated ... + static QCString htmlFileExtension; + static bool parseSourcesNeeded; + static QTime runningTime; + static SearchIndex *searchIndex; + static QDict<DefinitionIntf> *symbolMap; + static bool outputToWizard; + static QDict<int> *htmlDirMap; + static QCache<LookupInfo> *lookupCache; + static DirSDict *directories; + static SDict<DirRelation> dirRelations; + static ParserManager *parserManager; + static bool suppressDocWarnings; + static ObjCache *symbolCache; + static Store *symbolStorage; + static QCString objDBFileName; + static QCString entryDBFileName; + static CiteDict *citeDict; + static bool gatherDefines; + static bool userComments; + static IndexList indexList; + static int subpageNestingLevel; + static QCString spaces; + static bool generatingXmlOutput; + static bool markdownSupport; +}; + +void initDoxygen(); +void readConfiguration(int argc, char **argv); +void checkConfiguration(); +void adjustConfiguration(); +void searchInputFiles(StringList &inputFiles); +void parseInput(); +void generateOutput(); +void readAliases(); +void readFormulaRepository(); +int readFileOrDirectory(const char *s, + FileNameList *fnList, + FileNameDict *fnDict, + StringDict *exclDict, + QStrList *patList, + QStrList *exclPatList, + StringList *resultList, + StringDict *resultDict, + bool recursive, + bool errorIfNotExist=TRUE, + QDict<void> *killDict = 0 + ); +int readDir(QFileInfo *fi, + FileNameList *fnList, + FileNameDict *fnDict, + StringDict *exclDict, + QStrList *patList, + QStrList *exclPatList, + StringList *resultList, + StringDict *resultDict, + bool errorIfNotExist, + bool recursive, + QDict<void> *killDict + ); +void copyAndFilterFile(const char *fileName,BufStr &dest); + +#define NEWMATCH + +#endif diff --git a/trunk/src/doxygen.pro.in b/trunk/src/doxygen.pro.in new file mode 100644 index 0000000..42ffaa0 --- /dev/null +++ b/trunk/src/doxygen.pro.in @@ -0,0 +1,39 @@ +# +# +# +# Copyright (C) 1997-2012 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. +# +# TMake project file for doxygen + +TEMPLATE = app.t +CONFIG = console warn_on $extraopts +HEADERS = doxygen.h +SOURCES = main.cpp +unix:LIBS += -L../lib -ldoxygen -ldoxycfg -lqtools -lmd5 -lpthread +win32:INCLUDEPATH += . +win32-mingw:LIBS += -L../lib -ldoxygen -ldoxycfg -lqtools -lmd5 -lpthread +win32-msvc:LIBS += qtools.lib md5.lib doxygen.lib doxycfg.lib shell32.lib iconv.lib +win32-msvc:TMAKE_LFLAGS += /LIBPATH:..\lib +win32-borland:LIBS += qtools.lib md5.lib doxygen.lib doxycfg.lib shell32.lib iconv.lib +win32-borland:TMAKE_LFLAGS += -L..\lib -L$(BCB)\lib\psdk +win32:TMAKE_CXXFLAGS += -DQT_NODLL +win32-g++:LIBS = -L../lib -ldoxygen -ldoxycfg -lqtools -lmd5 -liconv -lpthread +win32-g++:TMAKE_CXXFLAGS += -fno-exceptions -fno-rtti +INCLUDEPATH += ../qtools ../libmd5 . +DESTDIR = ../bin +TARGET = doxygen +unix:TARGETDEPS = ../lib/libdoxygen.a ../lib/libdoxycfg.a +win32:TARGETDEPS = ..\lib\doxygen.lib ..\lib\doxycfg.lib +win32-g++:TARGETDEPS = ../lib/libdoxygen.a ../lib/libdoxycfg.a +win32-mingw:TARGETDEPS = ../lib/libdoxygen.a ../lib/libdoxycfg.a +OBJECTS_DIR = ../objects + diff --git a/trunk/src/doxygen_bst.h b/trunk/src/doxygen_bst.h new file mode 100644 index 0000000..c51f2df --- /dev/null +++ b/trunk/src/doxygen_bst.h @@ -0,0 +1,1388 @@ +" % \n" +" % \n" +" % This file is either \"html-btxbst.doc\" or was derived from\n" +" % \"html-btxbst.doc\" using cpp. \"html-btxbst.doc\" itself was edited\n" +" % from \"btxbst.doc\" and \"named.bst\".\n" +" % The following copyright information is from btxbst.doc:\n" +" % version 0.99b for BibTeX versions 0.99a or later, LaTeX version 2.09.\n" +" % Copyright (C) 1985, all rights reserved.\n" +" % Copying of this file is authorized only if either\n" +" % (1) you make absolutely no changes to your copy, including name, or\n" +" % (2) if you do make changes, you name it something other than\n" +" % btxbst.doc, plain.bst, unsrt.bst, alpha.bst, and abbrv.bst.\n" +" % This restriction helps ensure that all standard styles are identical.\n" +" % The file btxbst.doc has the documentation for this style.\n" +" % \"named\" style (sorted keys of the form [name, year])\n" +" % Some code for this was taken from \"named.bst\".\n" +"\n" +"ENTRY\n" +" { address\n" +" author\n" +" booktitle\n" +" chapter\n" +" edition\n" +" editor\n" +" howpublished\n" +" institution\n" +" journal\n" +" key\n" +" month\n" +" note\n" +" number\n" +" organization\n" +" pages\n" +" publisher\n" +" school\n" +" series\n" +" title\n" +" type\n" +" volume\n" +" year\n" +" dvi\n" +" html\n" +" keywords\n" +" pdf\n" +" postscript\n" +" url\n" +" doi\n" +" mailto\n" +" }\n" +" {}\n" +" { label extra.label sort.label }\n" +"\n" +"INTEGERS { output.state before.all mid.sentence after.sentence after.block }\n" +"\n" +"FUNCTION {init.state.consts}\n" +"{ #0 'before.all :=\n" +" #1 'mid.sentence :=\n" +" #2 'after.sentence :=\n" +" #3 'after.block :=\n" +"}\n" +"\n" +"STRINGS { s t }\n" +"\n" +"FUNCTION {output.nonnull}\n" +"{ 's :=\n" +" output.state mid.sentence =\n" +" { \", \" * write$ }\n" +" { output.state after.block =\n" +" { add.period$ write$\n" +" newline$\n" +" }\n" +" { output.state before.all =\n" +" 'write$\n" +" { add.period$ \" \" * write$ }\n" +" if$\n" +" }\n" +" if$\n" +" mid.sentence 'output.state :=\n" +" }\n" +" if$\n" +" s\n" +"}\n" +"\n" +"FUNCTION {output}\n" +"{ duplicate$ empty$\n" +" 'pop$\n" +" 'output.nonnull\n" +" if$\n" +"}\n" +"\n" +"FUNCTION {output.check}\n" +"{ 't :=\n" +" duplicate$ empty$\n" +" { pop$ \"empty \" t * \" in \" * cite$ * warning$ }\n" +" 'output.nonnull\n" +" if$\n" +"}\n" +"\n" +"FUNCTION {output.bibitem}\n" +"{ newline$\n" +" author empty$\n" +" { editor empty$\n" +" { organization empty$\n" +" 'skip$\n" +" { \"<!-- Authors: \" organization purify$ * \" -->\" * write$ newline$ }\n" +" if$\n" +" } \n" +" { \"<!-- Authors: \" editor purify$ * \" -->\" * write$ newline$ }\n" +" if$\n" +" }\n" +" { \"<!-- Authors: \" author purify$ * \" -->\" * write$ newline$ }\n" +" if$\n" +" keywords empty$\n" +" 'skip$\n" +" { \"<!-- Keywords: \" keywords * \" -->\" * write$ newline$ }\n" +" if$\n" +" \"<dt><a name=\" quote$ * \"CITEREF_\" * cite$ * quote$ * \">[\" * label * \"]</a></dt><dd>\" * write$\n" +" \"\"\n" +" before.all 'output.state :=\n" +"}\n" +"\n" +"FUNCTION {fin.entry}\n" +"{ add.period$\n" +" write$\n" +" postscript empty$\n" +" 'skip$\n" +" { newline$ \"<!-- PostScript: \" postscript * \" -->\" * write$ }\n" +" if$\n" +" pdf empty$\n" +" 'skip$\n" +" { newline$ \"<!-- PDF: \" pdf * \" -->\" * write$ }\n" +" if$\n" +" dvi empty$\n" +" 'skip$\n" +" { newline$ \"<!-- DVI: \" dvi * \" -->\" * write$ }\n" +" if$\n" +" doi empty$\n" +" 'skip$\n" +" { newline$ \"<!-- DOI: \" doi * \" -->\" * write$ }\n" +" if$\n" +" \"</dd>\" write$\n" +" newline$\n" +" newline$\n" +"}\n" +"\n" +"FUNCTION {new.block}\n" +"{ output.state before.all =\n" +" 'skip$\n" +" { after.block 'output.state := }\n" +" if$\n" +"}\n" +"\n" +"FUNCTION {new.sentence}\n" +"{ output.state after.block =\n" +" 'skip$\n" +" { output.state before.all =\n" +" 'skip$\n" +" { after.sentence 'output.state := }\n" +" if$\n" +" }\n" +" if$\n" +"}\n" +"\n" +"FUNCTION {not}\n" +"{ { #0 }\n" +" { #1 }\n" +" if$\n" +"}\n" +"\n" +"FUNCTION {and}\n" +"{ 'skip$\n" +" { pop$ #0 }\n" +" if$\n" +"}\n" +"\n" +"FUNCTION {or}\n" +"{ { pop$ #1 }\n" +" 'skip$\n" +" if$\n" +"}\n" +"\n" +"FUNCTION {str.to.int}\n" +"{\n" +" 's :=\n" +" #0\n" +" { s empty$ not }\n" +" { % Multiply the number on the top of the stack by 10 = 1010 binary\n" +" duplicate$ + % x2\n" +" duplicate$ % x2 x2\n" +" duplicate$ + duplicate$ + % x2 x8\n" +" +\n" +" s #1 #1 substring$ chr.to.int$ #48 - + % #48 is ascii for '0'\n" +" s #2 global.max$ substring$ 's :=\n" +" }\n" +" while$\n" +"}\n" +"\n" +"FUNCTION {new.block.checka}\n" +"{ empty$\n" +" 'skip$\n" +" 'new.block\n" +" if$\n" +"}\n" +"\n" +"FUNCTION {new.block.checkb}\n" +"{ empty$\n" +" swap$ empty$\n" +" and\n" +" 'skip$\n" +" 'new.block\n" +" if$\n" +"}\n" +"\n" +"FUNCTION {new.sentence.checka}\n" +"{ empty$\n" +" 'skip$\n" +" 'new.sentence\n" +" if$\n" +"}\n" +"\n" +"FUNCTION {new.sentence.checkb}\n" +"{ empty$\n" +" swap$ empty$\n" +" and\n" +" 'skip$\n" +" 'new.sentence\n" +" if$\n" +"}\n" +"\n" +"FUNCTION {field.or.null}\n" +"{ duplicate$ empty$\n" +" { pop$ \"\" }\n" +" 'skip$\n" +" if$\n" +"}\n" +"\n" +"FUNCTION {emphasize}\n" +"{ duplicate$ empty$\n" +" { pop$ \"\" }\n" +" { \"<em>\" swap$ * \"</em>\" * }\n" +" if$\n" +"}\n" +"\n" +"FUNCTION {add.link} % title\n" +"{\n" +" 't :=\n" +" t empty$\n" +" { \"\" }\n" +" { url empty$\n" +" { html empty$\n" +" { t }\n" +" { \"<a href=\" quote$ * html * quote$ * \">\" * t * \"</a>\" * }\n" +" if$ }\n" +" { \"<a href=\" quote$ * url * quote$ * \">\" * t * \"</a>\" * }\n" +" if$\n" +" }\n" +" if$\n" +"}\n" +"\n" +"FUNCTION {add.mailto} % authors\n" +"{\n" +" 't :=\n" +" t empty$\n" +" { \"\" }\n" +" { mailto empty$\n" +" { t }\n" +" { \"<a href=\" quote$ * \"mailto:\" * mailto * quote$ * \">\" * t * \"</a>\" * }\n" +" if$\n" +" }\n" +" if$\n" +"}\n" +"\n" +"INTEGERS { nameptr namesleft numnames }\n" +"\n" +"FUNCTION {format.names}\n" +"{ 's :=\n" +" #1 'nameptr :=\n" +" s num.names$ 'numnames :=\n" +" numnames 'namesleft :=\n" +" { namesleft #0 > }\n" +" { s nameptr \"{ff~}{vv~}{ll}{, jj}\" format.name$ 't :=\n" +" \"\\bibxhtmlname{\" t * \"}\" * 't :=\n" +" nameptr #1 >\n" +" { namesleft #1 >\n" +" { \", \" * t * }\n" +" { numnames #2 >\n" +" { \",\" * }\n" +" 'skip$\n" +" if$\n" +" t \"others\" =\n" +" { \" et~al.\" * }\n" +" { \" and \" * t * }\n" +" if$\n" +" }\n" +" if$\n" +" }\n" +" 't\n" +" if$\n" +" nameptr #1 + 'nameptr :=\n" +" namesleft #1 - 'namesleft :=\n" +" }\n" +" while$\n" +"}\n" +"\n" +"FUNCTION {format.authors}\n" +"{ author empty$\n" +" { \"\" }\n" +" { author format.names }\n" +" if$\n" +" add.mailto\n" +"}\n" +"\n" +"FUNCTION {format.editors}\n" +"{ editor empty$\n" +" { \"\" }\n" +" { editor format.names\n" +" editor num.names$ #1 >\n" +" { \", editors\" * }\n" +" { \", editor\" * }\n" +" if$\n" +" }\n" +" if$\n" +"}\n" +"\n" +"FUNCTION {format.title}\n" +"{ title empty$\n" +" { \"\" }\n" +" { title \"t\" change.case$ }\n" +" if$\n" +" add.link\n" +"}\n" +"\n" +"FUNCTION {n.dashify}\n" +"{ 't :=\n" +" \"\"\n" +" { t empty$ not }\n" +" { t #1 #1 substring$ \"-\" =\n" +" { t #1 #2 substring$ \"--\" = not\n" +" { \"--\" *\n" +" t #2 global.max$ substring$ 't :=\n" +" }\n" +" { { t #1 #1 substring$ \"-\" = }\n" +" { \"-\" *\n" +" t #2 global.max$ substring$ 't :=\n" +" }\n" +" while$\n" +" }\n" +" if$\n" +" }\n" +" { t #1 #1 substring$ *\n" +" t #2 global.max$ substring$ 't :=\n" +" }\n" +" if$\n" +" }\n" +" while$\n" +"}\n" +"\n" +"FUNCTION {format.date}\n" +"{ year empty$\n" +" { month empty$\n" +" { \"\" }\n" +" { \"there's a month but no year in \" cite$ * warning$\n" +" month\n" +" }\n" +" if$\n" +" }\n" +" { month empty$\n" +" 'year\n" +" { month \" \" * year * }\n" +" if$\n" +" }\n" +" if$\n" +"}\n" +"\n" +"FUNCTION {format.btitle}\n" +"{ title emphasize\n" +" add.link\n" +"}\n" +"\n" +"FUNCTION {tie.or.space.connect}\n" +"{ duplicate$ text.length$ #3 <\n" +" { \"~\" }\n" +" { \" \" }\n" +" if$\n" +" swap$ * *\n" +"}\n" +"\n" +"FUNCTION {either.or.check}\n" +"{ empty$\n" +" 'pop$\n" +" { \"can't use both \" swap$ * \" fields in \" * cite$ * warning$ }\n" +" if$\n" +"}\n" +"\n" +"FUNCTION {format.bvolume}\n" +"{ volume empty$\n" +" { \"\" }\n" +" { \"volume\" volume tie.or.space.connect\n" +" series empty$\n" +" 'skip$\n" +" { \" of \" * series emphasize * }\n" +" if$\n" +" \"volume and number\" number either.or.check\n" +" }\n" +" if$\n" +"}\n" +"\n" +"FUNCTION {format.number.series}\n" +"{ volume empty$\n" +" { number empty$\n" +" { series field.or.null }\n" +" { output.state mid.sentence =\n" +" { \"number\" }\n" +" { \"Number\" }\n" +" if$\n" +" number tie.or.space.connect\n" +" series empty$\n" +" { \"there's a number but no series in \" cite$ * warning$ }\n" +" { \" in \" * series * }\n" +" if$\n" +" }\n" +" if$\n" +" }\n" +" { \"\" }\n" +" if$\n" +"}\n" +"\n" +"FUNCTION {format.edition}\n" +"{ edition empty$\n" +" { \"\" }\n" +" { output.state mid.sentence =\n" +" { edition \"l\" change.case$ \" edition\" * }\n" +" { edition \"t\" change.case$ \" edition\" * }\n" +" if$\n" +" }\n" +" if$\n" +"}\n" +"\n" +"INTEGERS { multiresult }\n" +"\n" +"FUNCTION {multi.page.check}\n" +"{ 't :=\n" +" #0 'multiresult :=\n" +" { multiresult not\n" +" t empty$ not\n" +" and\n" +" }\n" +" { t #1 #1 substring$\n" +" duplicate$ \"-\" =\n" +" swap$ duplicate$ \",\" =\n" +" swap$ \"+\" =\n" +" or or\n" +" { #1 'multiresult := }\n" +" { t #2 global.max$ substring$ 't := }\n" +" if$\n" +" }\n" +" while$\n" +" multiresult\n" +"}\n" +"\n" +"FUNCTION {format.pages}\n" +"{ pages empty$\n" +" { \"\" }\n" +" { pages multi.page.check\n" +" { \"pages\" pages n.dashify tie.or.space.connect }\n" +" { \"page\" pages tie.or.space.connect }\n" +" if$\n" +" }\n" +" if$\n" +"}\n" +"\n" +"FUNCTION {format.vol.num.pages}\n" +"{ volume field.or.null\n" +" number empty$\n" +" 'skip$\n" +" { \"(\" number * \")\" * *\n" +" volume empty$\n" +" { \"there's a number but no volume in \" cite$ * warning$ }\n" +" 'skip$\n" +" if$\n" +" }\n" +" if$\n" +" pages empty$\n" +" 'skip$\n" +" { duplicate$ empty$\n" +" { pop$ format.pages }\n" +" { \":\" * pages n.dashify * }\n" +" if$\n" +" }\n" +" if$\n" +"}\n" +"\n" +"FUNCTION {format.chapter.pages}\n" +"{ chapter empty$\n" +" 'format.pages\n" +" { type empty$\n" +" { \"chapter\" }\n" +" { type \"l\" change.case$ }\n" +" if$\n" +" chapter tie.or.space.connect\n" +" pages empty$\n" +" 'skip$\n" +" { \", \" * format.pages * }\n" +" if$\n" +" }\n" +" if$\n" +"}\n" +"\n" +"FUNCTION {format.in.ed.booktitle}\n" +"{ booktitle empty$\n" +" { \"\" }\n" +" { editor empty$\n" +" { \"In \" booktitle emphasize * }\n" +" { \"In \" format.editors * \", \" * booktitle emphasize * }\n" +" if$\n" +" }\n" +" if$\n" +"}\n" +"\n" +"FUNCTION {empty.misc.check}\n" +"{ author empty$ title empty$ howpublished empty$\n" +" month empty$ year empty$ note empty$\n" +" and and and and and\n" +" key empty$ not and\n" +" { \"all relevant fields are empty in \" cite$ * warning$ }\n" +" 'skip$\n" +" if$\n" +"}\n" +"\n" +"FUNCTION {format.thesis.type}\n" +"{ type empty$\n" +" 'skip$\n" +" { pop$\n" +" type \"t\" change.case$\n" +" }\n" +" if$\n" +"}\n" +"\n" +"FUNCTION {format.tr.number}\n" +"{ type empty$\n" +" { \"Technical Report\" }\n" +" 'type\n" +" if$\n" +" number empty$\n" +" { \"t\" change.case$ }\n" +" { number tie.or.space.connect }\n" +" if$\n" +"}\n" +"\n" +"FUNCTION {format.article.crossref}\n" +"{\n" +" \"In <a href=\" quote$ * \"#\" * crossref * quote$ * \">\" *\n" +" key empty$\n" +" { journal empty$\n" +" { \"need key or journal for \" cite$ * \" to crossref \" * crossref *\n" +" warning$\n" +" \"\"\n" +" }\n" +" { \"<cite>\" * journal * \"</cite>\" * }\n" +" if$\n" +" }\n" +" { key * }\n" +" if$\n" +" \"</a> \\citelabel{\" * crossref * \"}\" *\n" +"}\n" +"\n" +"FUNCTION {format.crossref.editor}\n" +"{ editor #1 \"{vv~}{ll}\" format.name$\n" +" editor num.names$ duplicate$\n" +" #2 >\n" +" { pop$ \" et~al.\" * }\n" +" { #2 <\n" +" 'skip$\n" +" { editor #2 \"{ff }{vv }{ll}{ jj}\" format.name$ \"others\" =\n" +" { \" et~al.\" * }\n" +" { \" and \" * editor #2 \"{vv~}{ll}\" format.name$ * }\n" +" if$\n" +" }\n" +" if$\n" +" }\n" +" if$\n" +"}\n" +"\n" +"FUNCTION {format.book.crossref}\n" +"{ volume empty$\n" +" { \"empty volume in \" cite$ * \"'s crossref of \" * crossref * warning$\n" +" \"In \"\n" +" }\n" +" { \"Volume\" volume tie.or.space.connect\n" +" \" of \" *\n" +" }\n" +" if$\n" +" \"<a href=\" * quote$ * \"#\" * crossref * quote$ * \">\" *\n" +" editor empty$\n" +" editor field.or.null author field.or.null =\n" +" or\n" +" { key empty$\n" +" { series empty$\n" +" { \"need editor, key, or series for \" cite$ * \" to crossref \" *\n" +" crossref * warning$\n" +" \"\" *\n" +" }\n" +" { \"<cite>\" * series * \"</cite>\" * }\n" +" if$\n" +" }\n" +" { key * }\n" +" if$\n" +" }\n" +" { format.crossref.editor * }\n" +" if$\n" +" \"</a> \\citelabel{\" * crossref * \"}\" *\n" +"}\n" +"\n" +"FUNCTION {format.incoll.inproc.crossref}\n" +"{\n" +" \"In <a href=\" quote$ * \"#\" * crossref * quote$ * \">\" *\n" +" editor empty$\n" +" editor field.or.null author field.or.null =\n" +" or\n" +" { key empty$\n" +" { booktitle empty$\n" +" { \"need editor, key, or booktitle for \" cite$ * \" to crossref \" *\n" +" crossref * warning$\n" +" \"\"\n" +" }\n" +" { \"<cite>\" * booktitle * \"</cite>\" * }\n" +" if$\n" +" }\n" +" { key * }\n" +" if$\n" +" }\n" +" { format.crossref.editor * }\n" +" if$\n" +" \"</a> \\citelabel{\" * crossref * \"}\" *\n" +"}\n" +"\n" +"FUNCTION {article}\n" +"{ output.bibitem\n" +" format.authors \"author\" output.check\n" +" new.block\n" +" format.title \"title\" output.check\n" +" new.block\n" +" crossref missing$\n" +" { journal emphasize \"journal\" output.check\n" +" format.vol.num.pages output\n" +" format.date \"year\" output.check\n" +" }\n" +" { format.article.crossref output.nonnull\n" +" format.pages output\n" +" }\n" +" if$\n" +" new.block\n" +" note output\n" +" fin.entry\n" +"}\n" +"\n" +"FUNCTION {book}\n" +"{ output.bibitem\n" +" author empty$\n" +" { format.editors \"author and editor\" output.check }\n" +" { format.authors output.nonnull\n" +" crossref missing$\n" +" { \"author and editor\" editor either.or.check }\n" +" 'skip$\n" +" if$\n" +" }\n" +" if$\n" +" new.block\n" +" format.btitle \"title\" output.check\n" +" crossref missing$\n" +" { format.bvolume output\n" +" new.block\n" +" format.number.series output\n" +" new.sentence\n" +" publisher \"publisher\" output.check\n" +" address output\n" +" }\n" +" { new.block\n" +" format.book.crossref output.nonnull\n" +" }\n" +" if$\n" +" format.edition output\n" +" format.date \"year\" output.check\n" +" new.block\n" +" note output\n" +" fin.entry\n" +"}\n" +"\n" +"FUNCTION {booklet}\n" +"{ output.bibitem\n" +" format.authors output\n" +" new.block\n" +" format.title \"title\" output.check\n" +" howpublished address new.block.checkb\n" +" howpublished output\n" +" address output\n" +" format.date output\n" +" new.block\n" +" note output\n" +" fin.entry\n" +"}\n" +"\n" +"FUNCTION {inbook}\n" +"{ output.bibitem\n" +" author empty$\n" +" { format.editors \"author and editor\" output.check }\n" +" { format.authors output.nonnull\n" +" crossref missing$\n" +" { \"author and editor\" editor either.or.check }\n" +" 'skip$\n" +" if$\n" +" }\n" +" if$\n" +" new.block\n" +" format.btitle \"title\" output.check\n" +" crossref missing$\n" +" { format.bvolume output\n" +" format.chapter.pages \"chapter and pages\" output.check\n" +" new.block\n" +" format.number.series output\n" +" new.sentence\n" +" publisher \"publisher\" output.check\n" +" address output\n" +" }\n" +" { format.chapter.pages \"chapter and pages\" output.check\n" +" new.block\n" +" format.book.crossref output.nonnull\n" +" }\n" +" if$\n" +" format.edition output\n" +" format.date \"year\" output.check\n" +" new.block\n" +" note output\n" +" fin.entry\n" +"}\n" +"\n" +"FUNCTION {incollection}\n" +"{ output.bibitem\n" +" format.authors \"author\" output.check\n" +" new.block\n" +" format.title \"title\" output.check\n" +" new.block\n" +" crossref missing$\n" +" { format.in.ed.booktitle \"booktitle\" output.check\n" +" format.bvolume output\n" +" format.number.series output\n" +" format.chapter.pages output\n" +" new.sentence\n" +" publisher \"publisher\" output.check\n" +" address output\n" +" format.edition output\n" +" format.date \"year\" output.check\n" +" }\n" +" { format.incoll.inproc.crossref output.nonnull\n" +" format.chapter.pages output\n" +" }\n" +" if$\n" +" new.block\n" +" note output\n" +" fin.entry\n" +"}\n" +"\n" +"FUNCTION {inproceedings}\n" +"{ output.bibitem\n" +" format.authors \"author\" output.check\n" +" new.block\n" +" format.title \"title\" output.check\n" +" new.block\n" +" crossref missing$\n" +" { format.in.ed.booktitle \"booktitle\" output.check\n" +" format.bvolume output\n" +" format.number.series output\n" +" format.pages output\n" +" address empty$\n" +" { organization publisher new.sentence.checkb\n" +" organization output\n" +" publisher output\n" +" format.date \"year\" output.check\n" +" }\n" +" { address output.nonnull\n" +" format.date \"year\" output.check\n" +" new.sentence\n" +" organization output\n" +" publisher output\n" +" }\n" +" if$\n" +" }\n" +" { format.incoll.inproc.crossref output.nonnull\n" +" format.pages output\n" +" }\n" +" if$\n" +" new.block\n" +" note output\n" +" fin.entry\n" +"}\n" +"\n" +"FUNCTION {conference} { inproceedings }\n" +"\n" +"FUNCTION {manual}\n" +"{ output.bibitem\n" +" author empty$\n" +" { organization empty$\n" +" 'skip$\n" +" { organization output.nonnull\n" +" address output\n" +" }\n" +" if$\n" +" }\n" +" { format.authors output.nonnull }\n" +" if$\n" +" new.block\n" +" format.btitle \"title\" output.check\n" +" author empty$\n" +" { organization empty$\n" +" { address new.block.checka\n" +" address output\n" +" }\n" +" 'skip$\n" +" if$\n" +" }\n" +" { organization address new.block.checkb\n" +" organization output\n" +" address output\n" +" }\n" +" if$\n" +" format.edition output\n" +" format.date output\n" +" new.block\n" +" note output\n" +" fin.entry\n" +"}\n" +"\n" +"FUNCTION {mastersthesis}\n" +"{ output.bibitem\n" +" format.authors \"author\" output.check\n" +" new.block\n" +" format.title \"title\" output.check\n" +" new.block\n" +" \"Master's thesis\" format.thesis.type output.nonnull\n" +" school \"school\" output.check\n" +" address output\n" +" format.date \"year\" output.check\n" +" new.block\n" +" note output\n" +" fin.entry\n" +"}\n" +"\n" +"FUNCTION {misc}\n" +"{ output.bibitem\n" +" format.authors output\n" +" title howpublished new.block.checkb\n" +" format.title output\n" +" howpublished new.block.checka\n" +" howpublished output\n" +" format.date output\n" +" new.block\n" +" note output\n" +" fin.entry\n" +" empty.misc.check\n" +"}\n" +"\n" +"FUNCTION {phdthesis}\n" +"{ output.bibitem\n" +" format.authors \"author\" output.check\n" +" new.block\n" +" format.btitle \"title\" output.check\n" +" new.block\n" +" \"PhD thesis\" format.thesis.type output.nonnull\n" +" school \"school\" output.check\n" +" address output\n" +" format.date \"year\" output.check\n" +" new.block\n" +" note output\n" +" fin.entry\n" +"}\n" +"\n" +"FUNCTION {proceedings}\n" +"{ output.bibitem\n" +" editor empty$\n" +" { organization output }\n" +" { format.editors output.nonnull }\n" +" if$\n" +" new.block\n" +" format.btitle \"title\" output.check\n" +" format.bvolume output\n" +" format.number.series output\n" +" address empty$\n" +" { editor empty$\n" +" { publisher new.sentence.checka }\n" +" { organization publisher new.sentence.checkb\n" +" organization output\n" +" }\n" +" if$\n" +" publisher output\n" +" format.date \"year\" output.check\n" +" }\n" +" { address output.nonnull\n" +" format.date \"year\" output.check\n" +" new.sentence\n" +" editor empty$\n" +" 'skip$\n" +" { organization output }\n" +" if$\n" +" publisher output\n" +" }\n" +" if$\n" +" new.block\n" +" note output\n" +" fin.entry\n" +"}\n" +"\n" +"FUNCTION {techreport}\n" +"{ output.bibitem\n" +" format.authors \"author\" output.check\n" +" new.block\n" +" format.title \"title\" output.check\n" +" new.block\n" +" format.tr.number output.nonnull\n" +" institution \"institution\" output.check\n" +" address output\n" +" format.date \"year\" output.check\n" +" new.block\n" +" note output\n" +" fin.entry\n" +"}\n" +"\n" +"FUNCTION {unpublished}\n" +"{ output.bibitem\n" +" format.authors \"author\" output.check\n" +" new.block\n" +" format.title \"title\" output.check\n" +" new.block\n" +" note \"note\" output.check\n" +" format.date output\n" +" fin.entry\n" +"}\n" +"\n" +"FUNCTION {default.type} { misc }\n" +"\n" +"MACRO {jan} {\"January\"}\n" +"\n" +"MACRO {feb} {\"February\"}\n" +"\n" +"MACRO {mar} {\"March\"}\n" +"\n" +"MACRO {apr} {\"April\"}\n" +"\n" +"MACRO {may} {\"May\"}\n" +"\n" +"MACRO {jun} {\"June\"}\n" +"\n" +"MACRO {jul} {\"July\"}\n" +"\n" +"MACRO {aug} {\"August\"}\n" +"\n" +"MACRO {sep} {\"September\"}\n" +"\n" +"MACRO {oct} {\"October\"}\n" +"\n" +"MACRO {nov} {\"November\"}\n" +"\n" +"MACRO {dec} {\"December\"}\n" +"\n" +"MACRO {acmcs} {\"ACM Computing Surveys\"}\n" +"\n" +"MACRO {acta} {\"Acta Informatica\"}\n" +"\n" +"MACRO {cacm} {\"Communications of the ACM\"}\n" +"\n" +"MACRO {ibmjrd} {\"IBM Journal of Research and Development\"}\n" +"\n" +"MACRO {ibmsj} {\"IBM Systems Journal\"}\n" +"\n" +"MACRO {ieeese} {\"IEEE Transactions on Software Engineering\"}\n" +"\n" +"MACRO {ieeetc} {\"IEEE Transactions on Computers\"}\n" +"\n" +"MACRO {ieeetcad}\n" +" {\"IEEE Transactions on Computer-Aided Design of Integrated Circuits\"}\n" +"\n" +"MACRO {ipl} {\"Information Processing Letters\"}\n" +"\n" +"MACRO {jacm} {\"Journal of the ACM\"}\n" +"\n" +"MACRO {jcss} {\"Journal of Computer and System Sciences\"}\n" +"\n" +"MACRO {scp} {\"Science of Computer Programming\"}\n" +"\n" +"MACRO {sicomp} {\"SIAM Journal on Computing\"}\n" +"\n" +"MACRO {tocs} {\"ACM Transactions on Computer Systems\"}\n" +"\n" +"MACRO {tods} {\"ACM Transactions on Database Systems\"}\n" +"\n" +"MACRO {tog} {\"ACM Transactions on Graphics\"}\n" +"\n" +"MACRO {toms} {\"ACM Transactions on Mathematical Software\"}\n" +"\n" +"MACRO {toois} {\"ACM Transactions on Office Information Systems\"}\n" +"\n" +"MACRO {toplas} {\"ACM Transactions on Programming Languages and Systems\"}\n" +"\n" +"MACRO {tcs} {\"Theoretical Computer Science\"}\n" +"\n" +"READ\n" +"\n" +"FUNCTION {sortify}\n" +"{ purify$\n" +" \"l\" change.case$\n" +"}\n" +"\n" +"INTEGERS { len }\n" +"\n" +"FUNCTION {chop.word}\n" +"{ 's :=\n" +" 'len :=\n" +" s #1 len substring$ =\n" +" { s len #1 + global.max$ substring$ }\n" +" 's\n" +" if$\n" +"}\n" +"\n" +"\n" +"FUNCTION {format.lab.names}\n" +"{ 's :=\n" +" s num.names$ 'numnames :=\n" +" numnames #1 =\n" +" { s #1 \"{vv }{ll}\" format.name$ }\n" +" { numnames #2 =\n" +" { s #1 \"{vv }{ll }and \" format.name$ s #2 \"{vv }{ll}\" format.name$ * }\n" +" { s #1 \"{vv }{ll }\" format.name$ \"et~al.\" * }\n" +" if$\n" +" }\n" +" if$\n" +"}\n" +"\n" +"FUNCTION {author.key.label}\n" +"{ author empty$\n" +" { key empty$\n" +" { cite$ #1 #3 substring$ }\n" +" { key }\n" +" if$\n" +" }\n" +" { author format.lab.names }\n" +" if$\n" +"}\n" +"\n" +"FUNCTION {author.editor.key.label}\n" +"{ author empty$\n" +" { editor empty$\n" +" { key empty$\n" +" { cite$ #1 #3 substring$ }\n" +" { key }\n" +" if$\n" +" }\n" +" { editor format.lab.names }\n" +" if$\n" +" }\n" +" { author format.lab.names }\n" +" if$\n" +"}\n" +"\n" +"FUNCTION {author.key.organization.label}\n" +"{ author empty$\n" +" { key empty$\n" +" { organization empty$\n" +" { cite$ #1 #3 substring$ }\n" +" { \"The \" #4 organization chop.word #3 text.prefix$ }\n" +" if$\n" +" }\n" +" { key }\n" +" if$\n" +" }\n" +" { author format.lab.names }\n" +" if$\n" +"}\n" +"\n" +"FUNCTION {editor.key.organization.label}\n" +"{ editor empty$\n" +" { key empty$\n" +" { organization empty$\n" +" { cite$ #1 #3 substring$ }\n" +" { \"The \" #4 organization chop.word #3 text.prefix$ }\n" +" if$\n" +" }\n" +" { key }\n" +" if$\n" +" }\n" +" { editor format.lab.names }\n" +" if$\n" +"}\n" +"\n" +"FUNCTION {month.to.int}\n" +"{\n" +" \"l\" change.case$ #3 text.prefix$\n" +" 's :=\n" +" s \"jan\" = { #1 } {\n" +" s \"feb\" = { #2 } {\n" +" s \"mar\" = { #3 } {\n" +" s \"apr\" = { #4 } {\n" +" s \"may\" = { #5 } {\n" +" s \"jun\" = { #6 } {\n" +" s \"jul\" = { #7 } {\n" +" s \"aug\" = { #8 } {\n" +" s \"sep\" = { #9 } {\n" +" s \"oct\" = { #10 } {\n" +" s \"nov\" = { #11 } {\n" +" s \"dec\" = { #12 } { #13 } % 13 if nothing matches\n" +" if$}if$}if$}if$}if$}if$}if$}if$}if$}if$}if$}if$\n" +"}\n" +"\n" +"INTEGERS { done c } \n" +"FUNCTION { get.day }\n" +"{ month field.or.null 's :=\n" +" \n" +" % Strip out month name\n" +" #0 'done := \n" +" { s \"\" = not done not and }\n" +" { s #1 #1 substring$ \" \" = 'done :=\n" +" s #2 global.max$ substring$ 's :=\n" +" }\n" +" while$\n" +"\n" +" % Build up first number in t\n" +" \"0\" 't :=\n" +" #0 'done :=\n" +" { s \"\" = not done not and }\n" +" { s #1 #1 substring$ chr.to.int$ 'c :=\n" +" c #47 > c #58 < and\n" +" { t c int.to.chr$ * 't := }\n" +" { #1 'done := }\n" +" if$\n" +" s #2 global.max$ substring$ 's :=\n" +" }\n" +" while$\n" +"\n" +" t str.to.int\n" +"}\n" +"\n" +"FUNCTION { sortify.fourdigit }\n" +"{ 's :=\n" +" s empty$\n" +" { \"0000\" }\n" +" { s\n" +" }\n" +" if$\n" +"}\n" +"\n" +"FUNCTION { sortify.twodigit }\n" +"{ 's :=\n" +" s empty$\n" +" { \"00\" }\n" +" { s\n" +" str.to.int #10 + int.to.str$\n" +" }\n" +" if$\n" +"}\n" +"\n" +"FUNCTION {calc.label}\n" +"{ type$ \"book\" =\n" +" type$ \"inbook\" =\n" +" or\n" +" 'author.editor.key.label\n" +" { type$ \"proceedings\" =\n" +" 'editor.key.organization.label\n" +" { type$ \"manual\" =\n" +" 'author.key.organization.label\n" +" 'author.key.label\n" +" if$\n" +" }\n" +" if$\n" +" }\n" +" if$\n" +" duplicate$\n" +"\n" +" year empty$\n" +" 'skip$\n" +" { \", \" * }\n" +" if$\n" +" year field.or.null purify$ * % CHANGED - pfps - 15 Feb 1989\n" +" 'label :=\n" +"\n" +" year field.or.null purify$\n" +" #-1 #4 substring$ \n" +" sortify.fourdigit \n" +" \" \" *\n" +" month field.or.null month.to.int int.to.str$ sortify.twodigit *\n" +" \" \" * \n" +" get.day int.to.str$ sortify.twodigit *\n" +" \" \" *\n" +" * sortify 'sort.label :=\n" +"}\n" +"\n" +"FUNCTION {sort.format.names}\n" +"{ 's :=\n" +" #1 'nameptr :=\n" +" \"\"\n" +" s num.names$ 'numnames :=\n" +" numnames 'namesleft :=\n" +" { namesleft #0 > }\n" +" { nameptr #1 >\n" +" { \" \" * }\n" +" 'skip$\n" +" if$\n" +" s nameptr \"{vv{ } }{ll{ }}{ ff{ }}{ jj{ }}\" format.name$ 't :=\n" +" nameptr numnames = t \"others\" = and\n" +" { \"et al.\" * }\n" +" { t sortify * }\n" +" if$\n" +" nameptr #1 + 'nameptr :=\n" +" namesleft #1 - 'namesleft :=\n" +" }\n" +" while$\n" +"}\n" +"\n" +"FUNCTION {sort.format.title}\n" +"{ 't :=\n" +" \"A \" #2\n" +" \"An \" #3\n" +" \"The \" #4 t chop.word\n" +" chop.word\n" +" chop.word\n" +" sortify\n" +" #1 global.max$ substring$\n" +"}\n" +"\n" +"FUNCTION {author.sort}\n" +"{ author empty$\n" +" { key empty$\n" +" { \"to sort, need author or key in \" cite$ * warning$\n" +" \"\"\n" +" }\n" +" { key sortify }\n" +" if$\n" +" }\n" +" { author sort.format.names }\n" +" if$\n" +"}\n" +"\n" +"FUNCTION {author.editor.sort}\n" +"{ author empty$\n" +" { editor empty$\n" +" { key empty$\n" +" { \"to sort, need author, editor, or key in \" cite$ * warning$\n" +" \"\"\n" +" }\n" +" { key sortify }\n" +" if$\n" +" }\n" +" { editor sort.format.names }\n" +" if$\n" +" }\n" +" { author sort.format.names }\n" +" if$\n" +"}\n" +"\n" +"FUNCTION {author.organization.sort}\n" +"{ author empty$\n" +" { organization empty$\n" +" { key empty$\n" +" { \"to sort, need author, organization, or key in \" cite$ * warning$\n" +" \"\"\n" +" }\n" +" { key sortify }\n" +" if$\n" +" }\n" +" { \"The \" #4 organization chop.word sortify }\n" +" if$\n" +" }\n" +" { author sort.format.names }\n" +" if$\n" +"}\n" +"\n" +"FUNCTION {editor.organization.sort}\n" +"{ editor empty$\n" +" { organization empty$\n" +" { key empty$\n" +" { \"to sort, need editor, organization, or key in \" cite$ * warning$\n" +" \"\"\n" +" }\n" +" { key sortify }\n" +" if$\n" +" }\n" +" { \"The \" #4 organization chop.word sortify }\n" +" if$\n" +" }\n" +" { editor sort.format.names }\n" +" if$\n" +"}\n" +"\n" +"FUNCTION {presort}\n" +"{ calc.label\n" +" sort.label\n" +" \" \"\n" +" *\n" +" type$ \"book\" =\n" +" type$ \"inbook\" =\n" +" or\n" +" 'author.editor.sort\n" +" { type$ \"proceedings\" =\n" +" 'editor.organization.sort\n" +" { type$ \"manual\" =\n" +" 'author.organization.sort\n" +" 'author.sort\n" +" if$\n" +" }\n" +" if$\n" +" }\n" +" if$\n" +" *\n" +" \" \"\n" +" *\n" +" year field.or.null sortify\n" +" *\n" +" \" \"\n" +" *\n" +" title field.or.null\n" +" sort.format.title\n" +" *\n" +" #1 entry.max$ substring$\n" +" 'sort.key$ :=\n" +"}\n" +"\n" +"ITERATE {presort}\n" +"\n" +"SORT\n" +"\n" +"STRINGS { longest.label last.sort.label next.extra }\n" +"\n" +"INTEGERS { longest.label.width last.extra.num }\n" +"\n" +"FUNCTION {initialize.longest.label}\n" +"{ \"\" 'longest.label :=\n" +" #0 int.to.chr$ 'last.sort.label :=\n" +" \"\" 'next.extra :=\n" +" #0 'longest.label.width :=\n" +" #0 'last.extra.num :=\n" +"}\n" +"\n" +"FUNCTION {forward.pass}\n" +"{ last.sort.label sort.label =\n" +" { last.extra.num #1 + 'last.extra.num :=\n" +" last.extra.num int.to.chr$ 'extra.label :=\n" +" }\n" +" { \"a\" chr.to.int$ 'last.extra.num :=\n" +" \"\" 'extra.label :=\n" +" sort.label 'last.sort.label :=\n" +" }\n" +" if$\n" +"}\n" +"\n" +"FUNCTION {reverse.pass}\n" +"{ next.extra \"b\" =\n" +" { \"a\" 'extra.label := }\n" +" 'skip$\n" +" if$\n" +" label extra.label * 'label :=\n" +" label width$ longest.label.width >\n" +" { label 'longest.label :=\n" +" label width$ 'longest.label.width :=\n" +" }\n" +" 'skip$\n" +" if$\n" +" extra.label 'next.extra :=\n" +"}\n" +"\n" +"EXECUTE {initialize.longest.label}\n" +"\n" +"ITERATE {forward.pass}\n" +"\n" +"REVERSE {reverse.pass}\n" +"\n" +"FUNCTION {begin.bib}\n" +"{\n" +" \"# label-style: default\" write$ newline$\n" +"}\n" +"\n" +"EXECUTE {begin.bib}\n" +"\n" +"EXECUTE {init.state.consts}\n" +"\n" +"ITERATE {call.type$}\n" +"\n" +"FUNCTION {end.bib}\n" +"{ newline$\n" +"}\n" +"\n" +"EXECUTE {end.bib}\n" diff --git a/trunk/src/doxygen_css.h b/trunk/src/doxygen_css.h new file mode 100644 index 0000000..4b8f7d7 --- /dev/null +++ b/trunk/src/doxygen_css.h @@ -0,0 +1,1015 @@ +"/* The standard CSS for doxygen */\n" +"\n" +"body, table, div, p, dl {\n" +" font-family: Lucida Grande, Verdana, Geneva, Arial, sans-serif;\n" +" font-size: 13px;\n" +" line-height: 1.3;\n" +"}\n" +"\n" +"/* @group Heading Levels */\n" +"\n" +"h1 {\n" +" font-size: 150%;\n" +"}\n" +"\n" +".title {\n" +" font-size: 150%;\n" +" font-weight: bold;\n" +" margin: 10px 2px;\n" +"}\n" +"\n" +"h2 {\n" +" font-size: 120%;\n" +"}\n" +"\n" +"h3 {\n" +" font-size: 100%;\n" +"}\n" +"\n" +"dt {\n" +" font-weight: bold;\n" +"}\n" +"\n" +"div.multicol {\n" +" -moz-column-gap: 1em;\n" +" -webkit-column-gap: 1em;\n" +" -moz-column-count: 3;\n" +" -webkit-column-count: 3;\n" +"}\n" +"\n" +"p.startli, p.startdd, p.starttd {\n" +" margin-top: 2px;\n" +"}\n" +"\n" +"p.endli {\n" +" margin-bottom: 0px;\n" +"}\n" +"\n" +"p.enddd {\n" +" margin-bottom: 4px;\n" +"}\n" +"\n" +"p.endtd {\n" +" margin-bottom: 2px;\n" +"}\n" +"\n" +"/* @end */\n" +"\n" +"caption {\n" +" font-weight: bold;\n" +"}\n" +"\n" +"span.legend {\n" +" font-size: 70%;\n" +" text-align: center;\n" +"}\n" +"\n" +"h3.version {\n" +" font-size: 90%;\n" +" text-align: center;\n" +"}\n" +"\n" +"div.qindex, div.navtab{\n" +" background-color: ##ee;\n" +" border: 1px solid ##b0;\n" +" text-align: center;\n" +"}\n" +"\n" +"div.qindex, div.navpath {\n" +" width: 100%;\n" +" line-height: 140%;\n" +"}\n" +"\n" +"div.navtab {\n" +" margin-right: 15px;\n" +"}\n" +"\n" +"/* @group Link Styling */\n" +"\n" +"a {\n" +" color: ##50;\n" +" font-weight: normal;\n" +" text-decoration: none;\n" +"}\n" +"\n" +".contents a:visited {\n" +" color: ##60;\n" +"}\n" +"\n" +"a:hover {\n" +" text-decoration: underline;\n" +"}\n" +"\n" +"a.qindex {\n" +" font-weight: bold;\n" +"}\n" +"\n" +"a.qindexHL {\n" +" font-weight: bold;\n" +" background-color: ##AA;\n" +" color: #ffffff;\n" +" border: 1px double ##98;\n" +"}\n" +"\n" +".contents a.qindexHL:visited {\n" +" color: #ffffff;\n" +"}\n" +"\n" +"a.el {\n" +" font-weight: bold;\n" +"}\n" +"\n" +"a.elRef {\n" +"}\n" +"\n" +"a.code, a.code:visited {\n" +" color: #4665A2; \n" +"}\n" +"\n" +"a.codeRef, a.codeRef:visited {\n" +" color: #4665A2; \n" +"}\n" +"\n" +"/* @end */\n" +"\n" +"dl.el {\n" +" margin-left: -1cm;\n" +"}\n" +"\n" +".fragment {\n" +" font-family: monospace, fixed;\n" +" font-size: 105%;\n" +"}\n" +"\n" +"pre.fragment {\n" +" border: 1px solid ##CC;\n" +" background-color: ##FC;\n" +" padding: 4px 6px;\n" +" margin: 4px 8px 4px 2px;\n" +" overflow: auto;\n" +" word-wrap: break-word;\n" +" font-size: 9pt;\n" +" line-height: 125%;\n" +"}\n" +"\n" +"div.ah {\n" +" background-color: black;\n" +" font-weight: bold;\n" +" color: #ffffff;\n" +" margin-bottom: 3px;\n" +" margin-top: 3px;\n" +" padding: 0.2em;\n" +" border: solid thin #333;\n" +" border-radius: 0.5em;\n" +" -webkit-border-radius: .5em;\n" +" -moz-border-radius: .5em;\n" +" box-shadow: 2px 2px 3px #999;\n" +" -webkit-box-shadow: 2px 2px 3px #999;\n" +" -moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px;\n" +" background-image: -webkit-gradient(linear, left top, left bottom, from(#eee), to(#000),color-stop(0.3, #444));\n" +" background-image: -moz-linear-gradient(center top, #eee 0%, #444 40%, #000);\n" +"}\n" +"\n" +"div.groupHeader {\n" +" margin-left: 16px;\n" +" margin-top: 12px;\n" +" font-weight: bold;\n" +"}\n" +"\n" +"div.groupText {\n" +" margin-left: 16px;\n" +" font-style: italic;\n" +"}\n" +"\n" +"body {\n" +" background-color: white;\n" +" color: black;\n" +" margin: 0;\n" +"}\n" +"\n" +"div.contents {\n" +" margin-top: 10px;\n" +" margin-left: 8px;\n" +" margin-right: 8px;\n" +"}\n" +"\n" +"td.indexkey {\n" +" background-color: ##ee;\n" +" font-weight: bold;\n" +" border: 1px solid ##cc;\n" +" margin: 2px 0px 2px 0;\n" +" padding: 2px 10px;\n" +" white-space: nowrap;\n" +" vertical-align: top;\n" +"}\n" +"\n" +"td.indexvalue {\n" +" background-color: ##ee;\n" +" border: 1px solid ##cc;\n" +" padding: 2px 10px;\n" +" margin: 2px 0px;\n" +"}\n" +"\n" +"tr.memlist {\n" +" background-color: ##f0;\n" +"}\n" +"\n" +"p.formulaDsp {\n" +" text-align: center;\n" +"}\n" +"\n" +"img.formulaDsp {\n" +" \n" +"}\n" +"\n" +"img.formulaInl {\n" +" vertical-align: middle;\n" +"}\n" +"\n" +"div.center {\n" +" text-align: center;\n" +" margin-top: 0px;\n" +" margin-bottom: 0px;\n" +" padding: 0px;\n" +"}\n" +"\n" +"div.center img {\n" +" border: 0px;\n" +"}\n" +"\n" +"address.footer {\n" +" text-align: right;\n" +" padding-right: 12px;\n" +"}\n" +"\n" +"img.footer {\n" +" border: 0px;\n" +" vertical-align: middle;\n" +"}\n" +"\n" +"/* @group Code Colorization */\n" +"\n" +"span.keyword {\n" +" color: #008000\n" +"}\n" +"\n" +"span.keywordtype {\n" +" color: #604020\n" +"}\n" +"\n" +"span.keywordflow {\n" +" color: #e08000\n" +"}\n" +"\n" +"span.comment {\n" +" color: #800000\n" +"}\n" +"\n" +"span.preprocessor {\n" +" color: #806020\n" +"}\n" +"\n" +"span.stringliteral {\n" +" color: #002080\n" +"}\n" +"\n" +"span.charliteral {\n" +" color: #008080\n" +"}\n" +"\n" +"span.vhdldigit { \n" +" color: #ff00ff \n" +"}\n" +"\n" +"span.vhdlchar { \n" +" color: #000000 \n" +"}\n" +"\n" +"span.vhdlkeyword { \n" +" color: #700070 \n" +"}\n" +"\n" +"span.vhdllogic { \n" +" color: #ff0000 \n" +"}\n" +"\n" +"blockquote {\n" +" background-color: ##F8;\n" +" border-left: 2px solid ##AA;\n" +" margin: 0 24px 0 4px;\n" +" padding: 0 12px 0 16px;\n" +"}\n" +"\n" +"/* @end */\n" +"\n" +"/*\n" +".search {\n" +" color: #003399;\n" +" font-weight: bold;\n" +"}\n" +"\n" +"form.search {\n" +" margin-bottom: 0px;\n" +" margin-top: 0px;\n" +"}\n" +"\n" +"input.search {\n" +" font-size: 75%;\n" +" color: #000080;\n" +" font-weight: normal;\n" +" background-color: #e8eef2;\n" +"}\n" +"*/\n" +"\n" +"td.tiny {\n" +" font-size: 75%;\n" +"}\n" +"\n" +".dirtab {\n" +" padding: 4px;\n" +" border-collapse: collapse;\n" +" border: 1px solid ##b0;\n" +"}\n" +"\n" +"th.dirtab {\n" +" background: ##ee;\n" +" font-weight: bold;\n" +"}\n" +"\n" +"hr {\n" +" height: 0px;\n" +" border: none;\n" +" border-top: 1px solid ##66;\n" +"}\n" +"\n" +"hr.footer {\n" +" height: 1px;\n" +"}\n" +"\n" +"/* @group Member Descriptions */\n" +"\n" +"table.memberdecls {\n" +" border-spacing: 0px;\n" +" padding: 0px;\n" +"}\n" +"\n" +".mdescLeft, .mdescRight,\n" +".memItemLeft, .memItemRight,\n" +".memTemplItemLeft, .memTemplItemRight, .memTemplParams {\n" +" background-color: ##FA;\n" +" border: none;\n" +" margin: 4px;\n" +" padding: 1px 0 0 8px;\n" +"}\n" +"\n" +".mdescLeft, .mdescRight {\n" +" padding: 0px 8px 4px 8px;\n" +" color: #555;\n" +"}\n" +"\n" +".memItemLeft, .memItemRight, .memTemplParams {\n" +" border-top: 1px solid ##cc;\n" +"}\n" +"\n" +".memItemLeft, .memTemplItemLeft {\n" +" white-space: nowrap;\n" +"}\n" +"\n" +".memItemRight {\n" +" width: 100%;\n" +"}\n" +"\n" +".memTemplParams {\n" +" color: ##60;\n" +" white-space: nowrap;\n" +"}\n" +"\n" +"/* @end */\n" +"\n" +"/* @group Member Details */\n" +"\n" +"/* Styles for detailed member documentation */\n" +"\n" +".memtemplate {\n" +" font-size: 80%;\n" +" color: ##60;\n" +" font-weight: normal;\n" +" margin-left: 9px;\n" +"}\n" +"\n" +".memnav {\n" +" background-color: ##ee;\n" +" border: 1px solid ##b0;\n" +" text-align: center;\n" +" margin: 2px;\n" +" margin-right: 15px;\n" +" padding: 2px;\n" +"}\n" +"\n" +".mempage {\n" +" width: 100%;\n" +"}\n" +"\n" +".memitem {\n" +" padding: 0;\n" +" margin-bottom: 10px;\n" +" margin-right: 5px;\n" +"}\n" +"\n" +".memname {\n" +" font-weight: bold;\n" +" margin-left: 6px;\n" +"}\n" +"\n" +".memname td {\n" +" vertical-align: bottom;\n" +"}\n" +"\n" +".memproto, dl.reflist dt {\n" +" border-top: 1px solid ##B4;\n" +" border-left: 1px solid ##B4;\n" +" border-right: 1px solid ##B4;\n" +" padding: 6px 0px 6px 0px;\n" +" color: ##2b;\n" +" font-weight: bold;\n" +" text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.9);\n" +" /* opera specific markup */\n" +" box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15);\n" +" border-top-right-radius: 8px;\n" +" border-top-left-radius: 8px;\n" +" /* firefox specific markup */\n" +" -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px;\n" +" -moz-border-radius-topright: 8px;\n" +" -moz-border-radius-topleft: 8px;\n" +" /* webkit specific markup */\n" +" -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15);\n" +" -webkit-border-top-right-radius: 8px;\n" +" -webkit-border-top-left-radius: 8px;\n" +" background-image:url('nav_f.png');\n" +" background-repeat:repeat-x;\n" +" background-color: ##E6;\n" +"\n" +"}\n" +"\n" +".memdoc, dl.reflist dd {\n" +" border-bottom: 1px solid ##B4; \n" +" border-left: 1px solid ##B4; \n" +" border-right: 1px solid ##B4; \n" +" padding: 2px 5px;\n" +" background-color: ##FC;\n" +" border-top-width: 0;\n" +" /* opera specific markup */\n" +" border-bottom-left-radius: 8px;\n" +" border-bottom-right-radius: 8px;\n" +" box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15);\n" +" /* firefox specific markup */\n" +" -moz-border-radius-bottomleft: 8px;\n" +" -moz-border-radius-bottomright: 8px;\n" +" -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px;\n" +" background-image: -moz-linear-gradient(center top, ##FF 0%, ##FF 60%, ##F8 95%, ##F0);\n" +" /* webkit specific markup */\n" +" -webkit-border-bottom-left-radius: 8px;\n" +" -webkit-border-bottom-right-radius: 8px;\n" +" -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15);\n" +" background-image: -webkit-gradient(linear,center top,center bottom,from(##FF), color-stop(0.6,##FF), color-stop(0.60,##FF), color-stop(0.95,##F8), to(##F0));\n" +"}\n" +"\n" +"dl.reflist dt {\n" +" padding: 5px;\n" +"}\n" +"\n" +"dl.reflist dd {\n" +" margin: 0px 0px 10px 0px;\n" +" padding: 5px;\n" +"}\n" +"\n" +".paramkey {\n" +" text-align: right;\n" +"}\n" +"\n" +".paramtype {\n" +" white-space: nowrap;\n" +"}\n" +"\n" +".paramname {\n" +" color: #602020;\n" +" white-space: nowrap;\n" +"}\n" +".paramname em {\n" +" font-style: normal;\n" +"}\n" +"\n" +".params, .retval, .exception, .tparams {\n" +" border-spacing: 6px 2px;\n" +"} \n" +"\n" +".params .paramname, .retval .paramname {\n" +" font-weight: bold;\n" +" vertical-align: top;\n" +"}\n" +" \n" +".params .paramtype {\n" +" font-style: italic;\n" +" vertical-align: top;\n" +"} \n" +" \n" +".params .paramdir {\n" +" font-family: \"courier new\",courier,monospace;\n" +" vertical-align: top;\n" +"}\n" +"\n" +"\n" +"\n" +"\n" +"/* @end */\n" +"\n" +"/* @group Directory (tree) */\n" +"\n" +"/* for the tree view */\n" +"\n" +".ftvtree {\n" +" font-family: sans-serif;\n" +" margin: 0px;\n" +"}\n" +"\n" +"/* these are for tree view when used as main index */\n" +"\n" +".directory {\n" +" font-size: 9pt;\n" +" font-weight: bold;\n" +" margin: 5px;\n" +"}\n" +"\n" +".directory h3 {\n" +" margin: 0px;\n" +" margin-top: 1em;\n" +" font-size: 11pt;\n" +"}\n" +"\n" +"/*\n" +"The following two styles can be used to replace the root node title\n" +"with an image of your choice. Simply uncomment the next two styles,\n" +"specify the name of your image and be sure to set 'height' to the\n" +"proper pixel height of your image.\n" +"*/\n" +"\n" +"/*\n" +".directory h3.swap {\n" +" height: 61px;\n" +" background-repeat: no-repeat;\n" +" background-image: url(\"yourimage.gif\");\n" +"}\n" +".directory h3.swap span {\n" +" display: none;\n" +"}\n" +"*/\n" +"\n" +".directory > h3 {\n" +" margin-top: 0;\n" +"}\n" +"\n" +".directory p {\n" +" margin: 0px;\n" +" white-space: nowrap;\n" +"}\n" +"\n" +".directory div {\n" +" display: none;\n" +" margin: 0px;\n" +"}\n" +"\n" +".directory img {\n" +" vertical-align: -30%;\n" +"}\n" +"\n" +"/* these are for tree view when not used as main index */\n" +"\n" +".directory-alt {\n" +" font-size: 100%;\n" +" font-weight: bold;\n" +"}\n" +"\n" +".directory-alt h3 {\n" +" margin: 0px;\n" +" margin-top: 1em;\n" +" font-size: 11pt;\n" +"}\n" +"\n" +".directory-alt > h3 {\n" +" margin-top: 0;\n" +"}\n" +"\n" +".directory-alt p {\n" +" margin: 0px;\n" +" white-space: nowrap;\n" +"}\n" +"\n" +".directory-alt div {\n" +" display: none;\n" +" margin: 0px;\n" +"}\n" +"\n" +".directory-alt img {\n" +" vertical-align: -30%;\n" +"}\n" +"\n" +"/* @end */\n" +"\n" +"div.dynheader {\n" +" margin-top: 8px;\n" +"}\n" +"\n" +"address {\n" +" font-style: normal;\n" +" color: ##33;\n" +"}\n" +"\n" +"table.doxtable {\n" +" border-collapse:collapse;\n" +" margin-top: 4px;\n" +" margin-bottom: 4px;\n" +"}\n" +"\n" +"table.doxtable td, table.doxtable th {\n" +" border: 1px solid ##37;\n" +" padding: 3px 7px 2px;\n" +"}\n" +"\n" +"table.doxtable th {\n" +" background-color: ##47;\n" +" color: #FFFFFF;\n" +" font-size: 110%;\n" +" padding-bottom: 4px;\n" +" padding-top: 5px;\n" +"}\n" +"\n" +"table.fieldtable {\n" +" width: 100%;\n" +" margin-bottom: 10px;\n" +" border: 1px solid ##B4;\n" +" border-spacing: 0px;\n" +" -moz-border-radius: 4px;\n" +" -webkit-border-radius: 4px;\n" +" border-radius: 4px;\n" +" -moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px;\n" +" -webkit-box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.15);\n" +" box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.15);\n" +"}\n" +"\n" +".fieldtable td, .fieldtable th {\n" +" padding: 3px 7px 2px;\n" +"}\n" +"\n" +".fieldtable td.fieldtype, .fieldtable td.fieldname {\n" +" white-space: nowrap;\n" +" border-right: 1px solid ##B4;\n" +" border-bottom: 1px solid ##B4;\n" +" vertical-align: top;\n" +"}\n" +"\n" +".fieldtable td.fielddoc {\n" +" border-bottom: 1px solid ##B4;\n" +" width: 100%;\n" +"}\n" +"\n" +".fieldtable tr:last-child td {\n" +" border-bottom: none;\n" +"}\n" +"\n" +".fieldtable th {\n" +" background-image:url('nav_f.png');\n" +" background-repeat:repeat-x;\n" +" background-color: ##E6;\n" +" font-size: 90%;\n" +" color: ##2B;\n" +" padding-bottom: 4px;\n" +" padding-top: 5px;\n" +" text-align:left;\n" +" -moz-border-radius-topleft: 4px;\n" +" -moz-border-radius-topright: 4px;\n" +" -webkit-border-top-left-radius: 4px;\n" +" -webkit-border-top-right-radius: 4px;\n" +" border-top-left-radius: 4px;\n" +" border-top-right-radius: 4px;\n" +" border-bottom: 1px solid ##B4;\n" +"}\n" +"\n" +"\n" +".tabsearch {\n" +" top: 0px;\n" +" left: 10px;\n" +" height: 36px;\n" +" background-image: url('tab_b.png');\n" +" z-index: 101;\n" +" overflow: hidden;\n" +" font-size: 13px;\n" +"}\n" +"\n" +".navpath ul\n" +"{\n" +" font-size: 11px;\n" +" background-image:url('tab_b.png');\n" +" background-repeat:repeat-x;\n" +" height:30px;\n" +" line-height:30px;\n" +" color:##9b;\n" +" border:solid 1px ##ca;\n" +" overflow:hidden;\n" +" margin:0px;\n" +" padding:0px;\n" +"}\n" +"\n" +".navpath li\n" +"{\n" +" list-style-type:none;\n" +" float:left;\n" +" padding-left:10px;\n" +" padding-right:15px;\n" +" background-image:url('bc_s.png');\n" +" background-repeat:no-repeat;\n" +" background-position:right;\n" +" color:##45;\n" +"}\n" +"\n" +".navpath li.navelem a\n" +"{\n" +" height:32px;\n" +" display:block;\n" +" text-decoration: none;\n" +" outline: none;\n" +"}\n" +"\n" +".navpath li.navelem a:hover\n" +"{\n" +" color:##80;\n" +"}\n" +"\n" +".navpath li.footer\n" +"{\n" +" list-style-type:none;\n" +" float:right;\n" +" padding-left:10px;\n" +" padding-right:15px;\n" +" background-image:none;\n" +" background-repeat:no-repeat;\n" +" background-position:right;\n" +" color:##45;\n" +" font-size: 8pt;\n" +"}\n" +"\n" +"\n" +"div.summary\n" +"{\n" +" float: right;\n" +" font-size: 8pt;\n" +" padding-right: 5px;\n" +" width: 50%;\n" +" text-align: right;\n" +"} \n" +"\n" +"div.summary a\n" +"{\n" +" white-space: nowrap;\n" +"}\n" +"\n" +"div.ingroups\n" +"{\n" +" margin-left: 5px;\n" +" font-size: 8pt;\n" +" padding-left: 5px;\n" +" width: 50%;\n" +" text-align: left;\n" +"}\n" +"\n" +"div.ingroups a\n" +"{\n" +" white-space: nowrap;\n" +"}\n" +"\n" +"div.header\n" +"{\n" +" background-image:url('nav_h.png');\n" +" background-repeat:repeat-x;\n" +" background-color: ##FA;\n" +" margin: 0px;\n" +" border-bottom: 1px solid ##CC;\n" +"}\n" +"\n" +"div.headertitle\n" +"{\n" +" padding: 5px 5px 5px 7px;\n" +"}\n" +"\n" +"dl\n" +"{\n" +" padding: 0 0 0 10px;\n" +"}\n" +"\n" +"/* dl.note, dl.warning, dl.attention, dl.pre, dl.post, dl.invariant, dl.deprecated, dl.todo, dl.test, dl.bug */\n" +"dl.section\n" +"{\n" +" border-left:4px solid;\n" +" padding: 0 0 0 6px;\n" +"}\n" +"\n" +"dl.note\n" +"{\n" +" border-color: #D0C000;\n" +"}\n" +"\n" +"dl.warning, dl.attention\n" +"{\n" +" border-color: #FF0000;\n" +"}\n" +"\n" +"dl.pre, dl.post, dl.invariant\n" +"{\n" +" border-color: #00D000;\n" +"}\n" +"\n" +"dl.deprecated\n" +"{\n" +" border-color: #505050;\n" +"}\n" +"\n" +"dl.todo\n" +"{\n" +" border-color: #00C0E0;\n" +"}\n" +"\n" +"dl.test\n" +"{\n" +" border-color: #3030E0;\n" +"}\n" +"\n" +"dl.bug\n" +"{\n" +" border-color: #C08050;\n" +"}\n" +"\n" +"dl.section dd {\n" +" margin-bottom: 6px;\n" +"}\n" +"\n" +"\n" +"#projectlogo\n" +"{\n" +" text-align: center;\n" +" vertical-align: bottom;\n" +" border-collapse: separate;\n" +"}\n" +" \n" +"#projectlogo img\n" +"{ \n" +" border: 0px none;\n" +"}\n" +" \n" +"#projectname\n" +"{\n" +" font: 300% Tahoma, Arial,sans-serif;\n" +" margin: 0px;\n" +" padding: 2px 0px;\n" +"}\n" +" \n" +"#projectbrief\n" +"{\n" +" font: 120% Tahoma, Arial,sans-serif;\n" +" margin: 0px;\n" +" padding: 0px;\n" +"}\n" +"\n" +"#projectnumber\n" +"{\n" +" font: 50% Tahoma, Arial,sans-serif;\n" +" margin: 0px;\n" +" padding: 0px;\n" +"}\n" +"\n" +"#titlearea\n" +"{\n" +" padding: 0px;\n" +" margin: 0px;\n" +" width: 100%;\n" +" border-bottom: 1px solid ##70;\n" +"}\n" +"\n" +".image\n" +"{\n" +" text-align: center;\n" +"}\n" +"\n" +".dotgraph\n" +"{\n" +" text-align: center;\n" +"}\n" +"\n" +".mscgraph\n" +"{\n" +" text-align: center;\n" +"}\n" +"\n" +".caption\n" +"{\n" +" font-weight: bold;\n" +"}\n" +"\n" +"div.zoom\n" +"{\n" +" border: 1px solid ##A0;\n" +"}\n" +"\n" +"dl.citelist {\n" +" margin-bottom:50px;\n" +"}\n" +"\n" +"dl.citelist dt {\n" +" color:##40;\n" +" float:left;\n" +" font-weight:bold;\n" +" margin-right:10px;\n" +" padding:5px;\n" +"}\n" +"\n" +"dl.citelist dd {\n" +" margin:2px 0;\n" +" padding:5px 0;\n" +"}\n" +"\n" +"div.toc {\n" +" padding: 14px 25px;\n" +" background-color: ##F6;\n" +" border: 1px solid ##DD;\n" +" border-radius: 7px 7px 7px 7px;\n" +" float: right;\n" +" height: auto;\n" +" margin: 0 20px 10px 10px;\n" +" width: 200px;\n" +"}\n" +"\n" +"div.toc li {\n" +" background: url(\"bdwn.png\") no-repeat scroll 0 5px transparent;\n" +" font: 10px/1.2 Verdana,DejaVu Sans,Geneva,sans-serif;\n" +" margin-top: 5px;\n" +" padding-left: 10px;\n" +" padding-top: 2px;\n" +"}\n" +"\n" +"div.toc h3 {\n" +" font: bold 12px/1.2 Arial,FreeSans,sans-serif;\n" +" color: ##60;\n" +" border-bottom: 0 none;\n" +" margin: 0;\n" +"}\n" +"\n" +"div.toc ul {\n" +" list-style: none outside none;\n" +" border: medium none;\n" +" padding: 0px;\n" +"} \n" +"\n" +"div.toc li.level1 {\n" +" margin-left: 0px;\n" +"}\n" +"\n" +"div.toc li.level2 {\n" +" margin-left: 15px;\n" +"}\n" +"\n" +"div.toc li.level3 {\n" +" margin-left: 30px;\n" +"}\n" +"\n" +"div.toc li.level4 {\n" +" margin-left: 45px;\n" +"}\n" +"\n" +"\n" +"@media print\n" +"{\n" +" #top { display: none; }\n" +" #side-nav { display: none; }\n" +" #nav-path { display: none; }\n" +" body { overflow:visible; }\n" +" h1, h2, h3, h4, h5, h6 { page-break-after: avoid; }\n" +" .summary { display: none; }\n" +" .memitem { page-break-inside: avoid; }\n" +" #doc-content\n" +" {\n" +" margin-left:0 !important;\n" +" height:auto !important;\n" +" width:auto !important;\n" +" overflow:inherit;\n" +" display:inline;\n" +" }\n" +" pre.fragment\n" +" {\n" +" overflow: visible;\n" +" text-wrap: unrestricted;\n" +" white-space: -moz-pre-wrap; /* Moz */\n" +" white-space: -pre-wrap; /* Opera 4-6 */\n" +" white-space: -o-pre-wrap; /* Opera 7 */\n" +" white-space: pre-wrap; /* CSS3 */\n" +" word-wrap: break-word; /* IE 5.5+ */\n" +" }\n" +"}\n" +"\n" diff --git a/trunk/src/eclipsehelp.cpp b/trunk/src/eclipsehelp.cpp new file mode 100644 index 0000000..ea05885 --- /dev/null +++ b/trunk/src/eclipsehelp.cpp @@ -0,0 +1,205 @@ +/****************************************************************************** + * + * Copyright (C) 1997-2012 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. + * + */ +#include "eclipsehelp.h" +#include "util.h" +#include "config.h" +#include "message.h" +#include "doxygen.h" + +EclipseHelp::EclipseHelp() : m_depth(0), m_endtag(FALSE), m_tocfile(0) +{ +} + +EclipseHelp::~EclipseHelp() +{ +} + +void EclipseHelp::indent() +{ + int i; + for (i=0; i<m_depth; i++) + { + m_tocstream << " "; + } +} + +void EclipseHelp::closedTag() +{ + if (m_endtag) + { + m_tocstream << "/>" << endl; + m_endtag = FALSE; + } +} + +void EclipseHelp::openedTag() +{ + if (m_endtag) + { + m_tocstream << ">" << endl; + m_endtag = FALSE; + } +} + +/*! + * \brief Initialize the Eclipse generator + * + * This method opens the XML TOC file and writes headers of the files. + * \sa finalize() + */ +void EclipseHelp::initialize() +{ + // -- read path prefix from the configuration + //m_pathprefix = Config_getString("ECLIPSE_PATHPREFIX"); + //if (m_pathprefix.isEmpty()) m_pathprefix = "html/"; + + // -- open the contents file + QCString name = Config_getString("HTML_OUTPUT") + "/toc.xml"; + m_tocfile = new QFile(name); + if (!m_tocfile->open(IO_WriteOnly)) + { + err("Could not open file %s for writing\n", name.data()); + exit(1); + } + + // -- initialize its text stream + m_tocstream.setDevice(m_tocfile); + //m_tocstream.setEncoding(FTextStream::UnicodeUTF8); + + // -- write the opening tag + QCString title = Config_getString("PROJECT_NAME"); + if (title.isEmpty()) + { + title = "Doxygen generated documentation"; + } + m_tocstream << "<toc label=\"" << convertToXML(title) + << "\" topic=\"" << convertToXML(m_pathprefix) + << "index" << Doxygen::htmlFileExtension << "\">" << endl; + ++ m_depth; +} + +/*! + * \brief Finish generation of the Eclipse specific help files + * + * This method writes footers of the files and closes them. + * \sa initialize() + */ +void EclipseHelp::finalize() +{ + closedTag(); // -- close previous tag + + // -- write ending tag + --m_depth; + m_tocstream << "</toc>" << endl; + + // -- close the content file + m_tocstream.unsetDevice(); + m_tocfile->close(); + delete m_tocfile; m_tocfile = 0; + + QCString name = Config_getString("HTML_OUTPUT") + "/plugin.xml"; + QFile pluginFile(name); + if (pluginFile.open(IO_WriteOnly)) + { + QString docId = Config_getString("ECLIPSE_DOC_ID"); + FTextStream t(&pluginFile); + t << "<plugin name=\"" << docId << "\" id=\"" << docId << "\"" << endl; + t << " version=\"1.0.0\" provider-name=\"Doxygen\">" << endl; + t << " <extension point=\"org.eclipse.help.toc\">" << endl; + t << " <toc file=\"toc.xml\" primary=\"true\" />" << endl; + t << " </extension>" << endl; + t << "</plugin>" << endl; + } +} + +/*! + * \brief Increase the level of content hierarchy + */ +void EclipseHelp::incContentsDepth() +{ + openedTag(); + ++m_depth; +} + +/*! + * \brief Decrease the level of content hierarchy + * + * It closes currently opened topic tag. + */ +void EclipseHelp::decContentsDepth() +{ + // -- end of the opened topic + closedTag(); + --m_depth; + indent(); + m_tocstream << "</topic>" << endl; +} + +/*! + * \brief Add an item to the content + * + * @param isDir Flag whether the argument \a file is a directory or a file entry + * @param name Name of the item + * @param ref URL of the item + * @param file Name of a file which the item is defined in (without extension) + * @param anchor Name of an anchor of the item. + * @param separateIndex not used. + * @param addToNavIndex not used. + */ +void EclipseHelp::addContentsItem( + bool /* isDir */, + const char *name, + const char * /* ref */, + const char *file, + const char *anchor, + bool /* separateIndex */, + bool /* addToNavIndex */) +{ + // -- write the topic tag + closedTag(); + indent(); + m_tocstream << "<topic label=\"" << convertToXML(name) << "\""; + if (file) + { + m_tocstream << " href=\"" << convertToXML(m_pathprefix) + << file << Doxygen::htmlFileExtension; + if (anchor) + { + m_tocstream << "#" << anchor; + } + m_tocstream << "\""; + } + m_endtag = TRUE; +} + +void EclipseHelp::addIndexItem( + Definition * /* context */, + MemberDef * /* md */, + const char * /* title */) +{ +} + +void EclipseHelp::addIndexFile(const char * /* name */) +{ +} + +void EclipseHelp::addImageFile(const char * /* name */) +{ +} + +void EclipseHelp::addStyleSheetFile(const char * /* name */) +{ +} + diff --git a/trunk/src/eclipsehelp.h b/trunk/src/eclipsehelp.h new file mode 100644 index 0000000..0629810 --- /dev/null +++ b/trunk/src/eclipsehelp.h @@ -0,0 +1,77 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ +/* + * eclipsehelp.h + * + * Created on: 7.11.2009 + * Author: ondrej + */ + +#ifndef ECLIPSEHELP_H +#define ECLIPSEHELP_H + +#include "qtbc.h" +#include "index.h" +#include "ftextstream.h" + +/* -- forward declarations */ +class QFile; + +/*! + * \brief Generator of Eclipse help files + * + * This class generates the Eclipse specific help files. + * These files can be used to generate a help plugin readable + * by the Eclipse IDE. + */ +class EclipseHelp : public IndexIntf +{ + public: + EclipseHelp(); + virtual ~EclipseHelp(); + + /* -- index interface */ + virtual void initialize(); + virtual void finalize(); + virtual void incContentsDepth(); + virtual void decContentsDepth(); + virtual void addContentsItem(bool isDir, const char *name, const char *ref, + const char *file, const char *anchor,bool separateIndex,bool addToNavIndex); + virtual void addIndexItem(Definition *context,MemberDef *md,const char *title); + virtual void addIndexFile(const char *name); + virtual void addImageFile(const char *name); + virtual void addStyleSheetFile(const char *name); + + private: + int m_depth; + bool m_endtag; + + QFile * m_tocfile; + FTextStream m_tocstream; + QCString m_pathprefix; + + /* -- avoid copying */ + EclipseHelp(const EclipseHelp &); + EclipseHelp & operator = (const EclipseHelp &); + + /* -- formatting helpers */ + void indent(); + void closedTag(); + void openedTag(); +}; + +#endif /* ECLIPSEHELP_H */ diff --git a/trunk/src/entry.cpp b/trunk/src/entry.cpp new file mode 100644 index 0000000..01c9742 --- /dev/null +++ b/trunk/src/entry.cpp @@ -0,0 +1,458 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#include <stdlib.h> +#include <qfile.h> +#include "entry.h" +#include "marshal.h" +#include "util.h" +#include "section.h" +#include "doxygen.h" +#include "filestorage.h" +#include "arguments.h" + +//------------------------------------------------------------------ + +#define HEADER ('D'<<24)+('O'<<16)+('X'<<8)+'!' + +//------------------------------------------------------------------ + +int Entry::num=0; + +Entry::Entry() +{ + //printf("Entry::Entry(%p)\n",this); + num++; + m_parent=0; + section = EMPTY_SEC; + m_sublist = new QList<Entry>; + m_sublist->setAutoDelete(TRUE); + extends = new QList<BaseInfo>; + extends->setAutoDelete(TRUE); + groups = new QList<Grouping>; + groups->setAutoDelete(TRUE); + anchors = new QList<SectionInfo>; // Doxygen::sectionDict takes ownership of the items! + argList = new ArgumentList; + argList->setAutoDelete(TRUE); + //printf("Entry::Entry() tArgList=0\n"); + tArgLists = 0; + typeConstr = 0; + mGrpId = -1; + tagInfo = 0; + sli = 0; + relatesType = Simple; + hidden = FALSE; + groupDocType = GROUPDOC_NORMAL; + reset(); +} + +Entry::Entry(const Entry &e) +{ + //printf("Entry::Entry(%p):copy\n",this); + num++; + section = e.section; + type = e.type; + name = e.name; + tagInfo = e.tagInfo; + protection = e.protection; + mtype = e.mtype; + spec = e.spec; + initLines = e.initLines; + stat = e.stat; + explicitExternal = e.explicitExternal; + proto = e.proto; + subGrouping = e.subGrouping; + callGraph = e.callGraph; + callerGraph = e.callerGraph; + virt = e.virt; + args = e.args; + bitfields = e.bitfields; + argList = new ArgumentList; + argList->setAutoDelete(TRUE); + tArgLists = 0; + program = e.program; + initializer = e.initializer; + includeFile = e.includeFile; + includeName = e.includeName; + doc = e.doc; + docLine = e.docLine; + docFile = e.docFile; + brief = e.brief; + briefLine = e.briefLine; + briefFile = e.briefFile; + inbodyDocs = e.inbodyDocs; + inbodyLine = e.inbodyLine; + inbodyFile = e.inbodyFile; + relates = e.relates; + relatesType = e.relatesType; + read = e.read; + write = e.write; + inside = e.inside; + exception = e.exception; + typeConstr = 0; + bodyLine = e.bodyLine; + endBodyLine = e.endBodyLine; + mGrpId = e.mGrpId; + extends = new QList<BaseInfo>; + extends->setAutoDelete(TRUE); + groups = new QList<Grouping>; + groups->setAutoDelete(TRUE); + anchors = new QList<SectionInfo>; + fileName = e.fileName; + startLine = e.startLine; + if (e.sli) + { + sli = new QList<ListItemInfo>; + sli->setAutoDelete(TRUE); + QListIterator<ListItemInfo> slii(*e.sli); + ListItemInfo *ili; + for (slii.toFirst();(ili=slii.current());++slii) + { + sli->append(new ListItemInfo(*ili)); + } + } + else + { + sli=0; + } + lang = e.lang; + hidden = e.hidden; + artificial = e.artificial; + groupDocType = e.groupDocType; + + m_parent = e.m_parent; + m_sublist = new QList<Entry>; + m_sublist->setAutoDelete(TRUE); + + // deep copy of the child entry list + QListIterator<Entry> eli(*e.m_sublist); + Entry *cur; + for (;(cur=eli.current());++eli) + { + m_sublist->append(new Entry(*cur)); + } + + // deep copy base class list + QListIterator<BaseInfo> bli(*e.extends); + BaseInfo *bi; + for (;(bi=bli.current());++bli) + { + extends->append(new BaseInfo(*bi)); + } + + // deep copy group list + QListIterator<Grouping> gli(*e.groups); + Grouping *g; + for (;(g=gli.current());++gli) + { + groups->append(new Grouping(*g)); + } + + QListIterator<SectionInfo> sli2(*e.anchors); + SectionInfo *s; + for (;(s=sli2.current());++sli2) + { + anchors->append(new SectionInfo(*s)); + } + + // deep copy argument list + QListIterator<Argument> ali(*e.argList); + Argument *a; + for (;(a=ali.current());++ali) + { + argList->append(new Argument(*a)); + } + argList->constSpecifier = e.argList->constSpecifier; + argList->volatileSpecifier = e.argList->volatileSpecifier; + argList->pureSpecifier = e.argList->pureSpecifier; + + // deep copy type contraint list + if (e.typeConstr) + { + typeConstr = new ArgumentList; + typeConstr->setAutoDelete(TRUE); + QListIterator<Argument> tcli(*e.typeConstr); + for (;(a=tcli.current());++tcli) + { + typeConstr->append(new Argument(*a)); + } + } + + // deep copy template argument lists + if (e.tArgLists) + { + tArgLists = copyArgumentLists(e.tArgLists); + } + +} + +Entry::~Entry() +{ + //printf("Entry::~Entry(%p) num=%d\n",this,num); + //printf("Deleting entry %d name %s type %x children %d\n", + // num,name.data(),section,sublist->count()); + + delete m_sublist; // each element is now own by a EntryNav so we do no longer own + // our children. + delete extends; + delete groups; + delete anchors; + delete argList; + delete tArgLists; + delete tagInfo; + delete typeConstr; + delete sli; + num--; +} + +void Entry::addSubEntry(Entry *current) +{ + //printf("Entry %d with name %s type 0x%x added to %s type 0x%x\n", + // current->num,current->name.data(),current->section, + // name.data(),section); + //printf("Entry::addSubEntry(%s:%p) to %s\n",current->name.data(), + // current,name.data()); + current->m_parent=this; + m_sublist->append(current); +} + +void Entry::reset() +{ + //printf("Entry::reset()\n"); + name.resize(0); + type.resize(0); + args.resize(0); + bitfields.resize(0); + exception.resize(0); + program.resize(0); + includeFile.resize(0); + includeName.resize(0); + doc.resize(0); + docFile.resize(0); + docLine=-1; + relates.resize(0); + relatesType=Simple; + brief.resize(0); + briefFile.resize(0); + briefLine=-1; + inbodyDocs.resize(0); + inbodyFile.resize(0); + inbodyLine=-1; + inside.resize(0); + fileName.resize(0); + initializer.resize(0); + initLines = -1; + startLine = 1; + bodyLine = -1; + endBodyLine = -1; + mGrpId = -1; + callGraph = FALSE; + callerGraph = FALSE; + section = EMPTY_SEC; + mtype = Method; + virt = Normal; + stat = FALSE; + proto = FALSE; + explicitExternal = FALSE; + spec = 0; + lang = SrcLangExt_Unknown; + hidden = FALSE; + artificial = FALSE; + subGrouping = TRUE; + protection = Public; + groupDocType = GROUPDOC_NORMAL; + m_sublist->clear(); + extends->clear(); + groups->clear(); + anchors->clear(); + argList->clear(); + if (tagInfo) { delete tagInfo; tagInfo=0; } + if (tArgLists) { delete tArgLists; tArgLists=0; } + if (sli) { delete sli; sli=0; } + if (typeConstr) { delete typeConstr; typeConstr=0; } + //if (mtArgList) { delete mtArgList; mtArgList=0; } +} + + +int Entry::getSize() +{ + return sizeof(Entry); +} + +void Entry::createSubtreeIndex(EntryNav *nav,FileStorage *storage,FileDef *fd) +{ + EntryNav *childNav = new EntryNav(nav,this); + nav->addChild(childNav); + childNav->setFileDef(fd); + childNav->saveEntry(this,storage); + if (m_sublist) + { + //printf("saveEntry: %d children\n",node->sublist->count()); + QListIterator<Entry> eli(*m_sublist); + Entry *childNode; + for (eli.toFirst();(childNode=eli.current());++eli) + { + childNode->createSubtreeIndex(childNav,storage,fd); + } + //m_sublist->setAutoDelete(FALSE); + m_sublist->clear(); + } +} + +void Entry::createNavigationIndex(EntryNav *rootNav,FileStorage *storage,FileDef *fd) +{ + //printf("createNavigationIndex(%p) sublist=%p\n",this,m_sublist); + if (m_sublist) + { + //printf("saveEntries: %d children\n",root->sublist->count()); + // store all child entries of root, but keep the navigation info (=index) + QListIterator<Entry> eli(*m_sublist); + Entry *e; + for (eli.toFirst();(e=eli.current());++eli) + { + createSubtreeIndex(rootNav,storage,fd); + } + // remove all entries from root + //m_sublist->setAutoDelete(FALSE); + m_sublist->clear(); + } +} + +void Entry::addSpecialListItem(const char *listName,int itemId) +{ + if (sli==0) + { + sli = new QList<ListItemInfo>; + sli->setAutoDelete(TRUE); + } + ListItemInfo *ili=new ListItemInfo; + ili->type = listName; + ili->itemId = itemId; + sli->append(ili); +} + +Entry *Entry::removeSubEntry(Entry *e) +{ + int i = m_sublist->find(e); + return i!=-1 ? m_sublist->take(i) : 0; +} + +//------------------------------------------------------------------ + + +EntryNav::EntryNav(EntryNav *parent, Entry *e) + : m_parent(parent), m_subList(0), m_section(e->section), m_type(e->type), + m_name(e->name), m_fileDef(0), m_lang(e->lang), + m_info(0), m_offset(-1), m_noLoad(FALSE) +{ + if (e->tagInfo) + { + m_tagInfo = new TagInfo; + m_tagInfo->tagName = e->tagInfo->tagName; + m_tagInfo->fileName = e->tagInfo->fileName; + m_tagInfo->anchor = e->tagInfo->anchor; + if (e->tagInfo) + { + //printf("tagInfo %p: tagName=%s fileName=%s anchor=%s\n", + // e->tagInfo, + // e->tagInfo->tagName.data(), + // e->tagInfo->fileName.data(), + // e->tagInfo->anchor.data()); + } + } + else + { + m_tagInfo = 0; + } +} + +EntryNav::~EntryNav() +{ + delete m_subList; + delete m_info; + delete m_tagInfo; +} + +void EntryNav::addChild(EntryNav *e) +{ + if (m_subList==0) + { + m_subList = new QList<EntryNav>; + m_subList->setAutoDelete(TRUE); + } + m_subList->append(e); +} + +bool EntryNav::loadEntry(FileStorage *storage) +{ + if (m_noLoad) + { + return TRUE; + } + if (m_offset==-1) + { + //printf("offset not set!\n"); + return FALSE; + } + //delete m_info; + //printf("EntryNav::loadEntry: new entry %p: %s\n",m_info,m_name.data()); + //m_info->tagInfo = m_tagInfo; + //if (m_parent) + //{ + // m_info->parent = m_parent->m_info; + //} + //m_info->parent = 0; + //printf("load entry: seek to %llx\n",m_offset); + if (!storage->seek(m_offset)) + { + //printf("seek failed!\n"); + return FALSE; + } + if (m_info) delete m_info; + m_info = unmarshalEntry(storage); + m_info->name = m_name; + m_info->type = m_type; + m_info->section = m_section; + return TRUE; +} + +bool EntryNav::saveEntry(Entry *e,FileStorage *storage) +{ + m_offset = storage->pos(); + //printf("EntryNav::saveEntry offset=%llx\n",m_offset); + marshalEntry(storage,e); + return TRUE; +} + +void EntryNav::releaseEntry() +{ + if (!m_noLoad) + { + //printf("EntryNav::releaseEntry %p\n",m_info); + delete m_info; + m_info=0; + } +} + +void EntryNav::setEntry(Entry *e) +{ + delete m_info; + m_info = e; + //printf("EntryNav::setEntry %p\n",e); + m_noLoad=TRUE; +} + diff --git a/trunk/src/entry.h b/trunk/src/entry.h new file mode 100644 index 0000000..d312cec --- /dev/null +++ b/trunk/src/entry.h @@ -0,0 +1,351 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#ifndef ENTRY_H +#define ENTRY_H + +#include "qtbc.h" +#include <qlist.h> +#include "types.h" + +#include <qgstring.h> + +struct SectionInfo; +class QFile; +class EntryNav; +class FileDef; +class FileStorage; +class StorageIntf; +class ArgumentList; +struct ListItemInfo; + +/*! \brief This class stores information about an inheritance relation + */ +struct BaseInfo +{ + /*! Creates an object representing an inheritance relation */ + BaseInfo(const char *n,Protection p,Specifier v) : + name(n),prot(p),virt(v) {} + QCString name; //!< the name of the base class + Protection prot; //!< inheritance type + Specifier virt; //!< virtualness +}; + +/*! \brief This struct is used to capture the tag file information + * for an Entry. + */ +struct TagInfo +{ + QCString tagName; + QCString fileName; + QCString anchor; +}; + +/*! \brief Represents an unstructured piece of information, about an + * entity found in the sources. + * + * parseMain() in scanner.l will generate a tree of these + * entries. + */ +class Entry +{ + public: + + /*! Kind of entries that are supported */ + enum Sections { + CLASS_SEC = 0x00000001, + NAMESPACE_SEC = 0x00000010, + COMPOUND_MASK = CLASS_SEC, + SCOPE_MASK = COMPOUND_MASK | NAMESPACE_SEC, + + CLASSDOC_SEC = 0x00000800, + STRUCTDOC_SEC = 0x00001000, + UNIONDOC_SEC = 0x00002000, + EXCEPTIONDOC_SEC = 0x00004000, + NAMESPACEDOC_SEC = 0x00008000, + INTERFACEDOC_SEC = 0x00010000, + PROTOCOLDOC_SEC = 0x00020000, + CATEGORYDOC_SEC = 0x00040000, + COMPOUNDDOC_MASK = CLASSDOC_SEC | STRUCTDOC_SEC | UNIONDOC_SEC | + INTERFACEDOC_SEC | EXCEPTIONDOC_SEC | PROTOCOLDOC_SEC | + CATEGORYDOC_SEC, + + SOURCE_SEC = 0x00400000, + HEADER_SEC = 0x00800000, + FILE_MASK = SOURCE_SEC | HEADER_SEC, + + ENUMDOC_SEC = 0x01000000, + ENUM_SEC = 0x02000000, + EMPTY_SEC = 0x03000000, + PAGEDOC_SEC = 0x04000000, + VARIABLE_SEC = 0x05000000, + FUNCTION_SEC = 0x06000000, + TYPEDEF_SEC = 0x07000000, + MEMBERDOC_SEC = 0x08000000, + OVERLOADDOC_SEC = 0x09000000, + EXAMPLE_SEC = 0x0a000000, + VARIABLEDOC_SEC = 0x0b000000, + FILEDOC_SEC = 0x0c000000, + DEFINEDOC_SEC = 0x0d000000, + INCLUDE_SEC = 0x0e000000, + DEFINE_SEC = 0x0f000000, + GROUPDOC_SEC = 0x10000000, + USINGDIR_SEC = 0x11000000, + MAINPAGEDOC_SEC = 0x12000000, + MEMBERGRP_SEC = 0x13000000, + USINGDECL_SEC = 0x14000000, + PACKAGE_SEC = 0x15000000, + PACKAGEDOC_SEC = 0x16000000, + OBJCIMPL_SEC = 0x17000000, + DIRDOC_SEC = 0x18000000 + }; + enum MemberSpecifier + { + Inline = 0x00000001, + Explicit = 0x00000002, + Mutable = 0x00000004, + Settable = 0x00000008, + Gettable = 0x00000010, + Readable = 0x00000020, + Writable = 0x00000040, + Final = 0x00000080, + Abstract = 0x00000100, + Addable = 0x00000200, + Removable = 0x00000400, + Raisable = 0x00000800, + Override = 0x00001000, + New = 0x00002000, + Sealed = 0x00004000, + Initonly = 0x00008000, + Optional = 0x00010000, + Required = 0x00020000, + NonAtomic = 0x00040000, + Copy = 0x00080000, + Retain = 0x00100000, + Assign = 0x00200000, + Composition = 0x00400000, + Aggregation = 0x00800000, + Association = 0x01000000 + }; + enum ClassSpecifier + { + Template = 0x0001, + Generic = 0x0002, + Ref = 0x0004, + Value = 0x0008, + Interface = 0x0010, + Struct = 0x0020, + Union = 0x0040, + Exception = 0x0080, + Protocol = 0x0100, + Category = 0x0200, + SealedClass = 0x0400, + AbstractClass = 0x0800, + Enum = 0x1000 // for Java-style enums + }; + enum GroupDocType + { + GROUPDOC_NORMAL, //!< defgroup + GROUPDOC_ADD, //!< addgroup + GROUPDOC_WEAK //!< weakgroup + }; //!< kind of group + + Entry(); + Entry(const Entry &); + ~Entry(); + + /*! Returns the static size of the Entry (so excluding any dynamic memory) */ + int getSize(); + + void addSpecialListItem(const char *listName,int index); + void createNavigationIndex(EntryNav *rootNav,FileStorage *storage,FileDef *fd); + + // while parsing a file these function can be used to navigate/build the tree + void setParent(Entry *parent) { m_parent = parent; } + + /*! Returns the parent for this Entry or 0 if this entry has no parent. */ + Entry *parent() const { return m_parent; } + + /*! Returns the list of children for this Entry + * @see addSubEntry() and removeSubEntry() + */ + const QList<Entry> *children() const { return m_sublist; } + + /*! Adds entry \a e as a child to this entry */ + void addSubEntry (Entry* e) ; + + /*! Removes entry \a e from the list of children. + * Returns a pointer to the entry or 0 if the entry was not a child. + * Note the entry will not be deleted. + */ + Entry *removeSubEntry(Entry *e); + + /*! Restore the state of this Entry to the default value it has + * at construction time. + */ + void reset(); + + /*! Serialize this entry to a persistent storage stream. */ + void marshall(StorageIntf *); + + /*! Reinitialize this entry from a persistent storage stream. */ + void unmarshall(StorageIntf *); + + public: + + // identification + int section; //!< entry type (see Sections); + QCString type; //!< member type + QCString name; //!< member name + TagInfo *tagInfo; //!< tag file info + + // content + Protection protection; //!< class protection + MethodTypes mtype; //!< signal, slot, (dcop) method, or property? + int spec; //!< class/member specifiers + int initLines; //!< define/variable initializer lines to show + bool stat; //!< static ? + bool explicitExternal; //!< explicitly defined as external? + bool proto; //!< prototype ? + bool subGrouping; //!< automatically group class members? + bool callGraph; //!< do we need to draw the call graph? + bool callerGraph; //!< do we need to draw the caller graph? + Specifier virt; //!< virtualness of the entry + QCString args; //!< member argument string + QCString bitfields; //!< member's bit fields + ArgumentList *argList; //!< member arguments as a list + QList<ArgumentList> *tArgLists; //!< template argument declarations + QGString program; //!< the program text + QGString initializer; //!< initial value (for variables) + QCString includeFile; //!< include file (2 arg of \\class, must be unique) + QCString includeName; //!< include name (3 arg of \\class) + QCString doc; //!< documentation block (partly parsed) + int docLine; //!< line number at which the documentation was found + QCString docFile; //!< file in which the documentation was found + QCString brief; //!< brief description (doc block) + int briefLine; //!< line number at which the brief desc. was found + QCString briefFile; //!< file in which the brief desc. was found + QCString inbodyDocs; //!< documentation inside the body of a function + int inbodyLine; //!< line number at which the body doc was found + QCString inbodyFile; //!< file in which the body doc was found + QCString relates; //!< related class (doc block) + RelatesType relatesType; //!< how relates is handled + QCString read; //!< property read accessor + QCString write; //!< property write accessor + QCString inside; //!< name of the class in which documents are found + QCString exception; //!< throw specification + ArgumentList *typeConstr; //!< where clause (C#) for type constraints + int bodyLine; //!< line number of the definition in the source + int endBodyLine; //!< line number where the definition ends + int mGrpId; //!< member group id + QList<BaseInfo> *extends; //!< list of base classes + QList<Grouping> *groups; //!< list of groups this entry belongs to + QList<SectionInfo> *anchors; //!< list of anchors defined in this entry + QCString fileName; //!< file this entry was extracted from + int startLine; //!< start line of entry in the source + QList<ListItemInfo> *sli; //!< special lists (test/todo/bug/deprecated/..) this entry is in + SrcLangExt lang; //!< programming language in which this entry was found + bool hidden; //!< does this represent an entity that is hidden from the output + bool artificial; //!< Artificially introduced item + GroupDocType groupDocType; + + + static int num; //!< counts the total number of entries + + /// return the command name used to define GROUPDOC_SEC + const char *groupDocCmd() const + { + switch( groupDocType ) + { + case GROUPDOC_NORMAL: return "\\defgroup"; + case GROUPDOC_ADD: return "\\addgroup"; + case GROUPDOC_WEAK: return "\\weakgroup"; + default: return "unknown group command"; + } + } + Grouping::GroupPri_t groupingPri() const + { + if( section != GROUPDOC_SEC ) + { + return Grouping::GROUPING_LOWEST; + } + switch( groupDocType ) + { + case GROUPDOC_NORMAL: return Grouping::GROUPING_AUTO_DEF; + case GROUPDOC_ADD: return Grouping::GROUPING_AUTO_ADD; + case GROUPDOC_WEAK: return Grouping::GROUPING_AUTO_WEAK; + default: return Grouping::GROUPING_LOWEST; + } + } + + private: + void createSubtreeIndex(EntryNav *nav,FileStorage *storage,FileDef *fd); + Entry *m_parent; //!< parent node in the tree + QList<Entry> *m_sublist; //!< entries that are children of this one + Entry &operator=(const Entry &); +}; + +class EntryNav +{ + public: + EntryNav(EntryNav *parent,Entry *e); + ~EntryNav(); + void addChild(EntryNav *); + bool loadEntry(FileStorage *storage); + bool saveEntry(Entry *e,FileStorage *storage); + void setEntry(Entry *e); + void releaseEntry(); + void changeSection(int section) { m_section = section; } + void setFileDef(FileDef *fd) { m_fileDef = fd; } + + Entry *entry() const { return m_info; } + int section() const { return m_section; } + SrcLangExt lang() const { return m_lang; } + const QCString &type() const { return m_type; } + const QCString &name() const { return m_name; } + TagInfo *tagInfo() const { return m_tagInfo; } + const QList<EntryNav> *children() const { return m_subList; } + EntryNav *parent() const { return m_parent; } + FileDef *fileDef() const { return m_fileDef; } + + private: + + // navigation + EntryNav *m_parent; //!< parent node in the tree + QList<EntryNav> *m_subList; //!< entries that are children of this one + + // identification + int m_section; //!< entry type (see Sections); + QCString m_type; //!< member type + QCString m_name; //!< member name + TagInfo *m_tagInfo; //!< tag file info + FileDef *m_fileDef; + SrcLangExt m_lang; //!< programming language in which this entry was found + + Entry *m_info; + int64 m_offset; + bool m_noLoad; +}; + + +typedef QList<Entry> EntryList; +typedef QListIterator<Entry> EntryListIterator; + +typedef QList<EntryNav> EntryNavList; +typedef QListIterator<EntryNav> EntryNavListIterator; + +#endif diff --git a/trunk/src/example.h b/trunk/src/example.h new file mode 100644 index 0000000..a780326 --- /dev/null +++ b/trunk/src/example.h @@ -0,0 +1,45 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#ifndef EXAMPLE_H +#define EXAMPLE_H + +#include "qtbc.h" +#include <qdict.h> + +class ClassDef; +class MemberName; + +struct Example +{ + QCString anchor; + QCString name; + QCString file; +}; + +class ExampleSDict : public SDict<Example> +{ + public: + ExampleSDict(int size=17) : SDict<Example>(size) {} + ~ExampleSDict() {} + int compareItems(GCI item1,GCI item2) + { + return stricmp(((Example *)item1)->name,((Example *)item2)->name); + } +}; + +#endif diff --git a/trunk/src/filedef.cpp b/trunk/src/filedef.cpp new file mode 100644 index 0000000..e25e04f --- /dev/null +++ b/trunk/src/filedef.cpp @@ -0,0 +1,1679 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#include "qtbc.h" +#include "memberlist.h" +#include "classlist.h" +#include "filedef.h" +#include "doxygen.h" +#include "memberdef.h" +#include "classdef.h" +#include "namespacedef.h" +#include "util.h" +#include "language.h" +#include "outputlist.h" +#include "dot.h" +#include "message.h" +#include "docparser.h" +#include "searchindex.h" +#include "htags.h" +#include "parserintf.h" +#include "portable.h" +#include "vhdldocgen.h" +#include "debug.h" +#include "layout.h" +#include "entry.h" + +//--------------------------------------------------------------------------- + +class DevNullCodeDocInterface : public CodeOutputInterface +{ + public: + virtual void codify(const char *) {} + virtual void writeCodeLink(const char *,const char *, + const char *,const char *, + const char *) {} + virtual void writeLineNumber(const char *,const char *, + const char *,int) {} + virtual void startCodeLine() {} + virtual void endCodeLine() {} + virtual void startCodeAnchor(const char *) {} + virtual void endCodeAnchor() {} + virtual void startFontClass(const char *) {} + virtual void endFontClass() {} + virtual void writeCodeAnchor(const char *) {} + virtual void linkableSymbol(int, const char *,Definition *,Definition *) {} +}; + +//--------------------------------------------------------------------------- + +/*! create a new file definition, where \a p is the file path, + \a nm the file name, and \a lref is an HTML anchor name if the + file was read from a tag file or 0 otherwise +*/ +FileDef::FileDef(const char *p,const char *nm, + const char *lref,const char *dn) + : Definition((QCString)p+nm,1,nm) +{ + path=p; + filepath=path+nm; + filename=nm; + diskname=dn; + if (diskname.isEmpty()) diskname=nm; + setReference(lref); + classSDict = 0; + includeList = 0; + includeDict = 0; + includedByList = 0; + includedByDict = 0; + namespaceSDict = 0; + srcDefDict = 0; + srcMemberDict = 0; + usingDirList = 0; + usingDeclList = 0; + package = 0; + isSource = FALSE; + docname = nm; + dir = 0; + if (Config_getBool("FULL_PATH_NAMES")) + { + docname.prepend(stripFromPath(path.copy())); + } + SrcLangExt lang = getLanguageFromFileName(name()); + setLanguage(lang); + //m_isJava = lang==SrcLangExt_Java; + //m_isCSharp = lang==SrcLangExt_CSharp; + memberGroupSDict = 0; + acquireFileVersion(); + m_subGrouping=Config_getBool("SUBGROUPING"); +} + +/*! destroy the file definition */ +FileDef::~FileDef() +{ + delete classSDict; + delete includeDict; + delete includeList; + delete includedByDict; + delete includedByList; + delete namespaceSDict; + delete srcDefDict; + delete srcMemberDict; + delete usingDirList; + delete usingDeclList; + delete memberGroupSDict; +} + +/*! Compute the HTML anchor names for all members in the class */ +void FileDef::computeAnchors() +{ + MemberList *ml = getMemberList(MemberList::allMembersList); + if (ml) setAnchors(0,'a',ml); +} + +void FileDef::distributeMemberGroupDocumentation() +{ + //printf("FileDef::distributeMemberGroupDocumentation()\n"); + if (memberGroupSDict) + { + MemberGroupSDict::Iterator mgli(*memberGroupSDict); + MemberGroup *mg; + for (;(mg=mgli.current());++mgli) + { + mg->distributeMemberGroupDocumentation(); + } + } +} + +void FileDef::findSectionsInDocumentation() +{ + docFindSections(documentation(),this,0,docFile()); + if (memberGroupSDict) + { + MemberGroupSDict::Iterator mgli(*memberGroupSDict); + MemberGroup *mg; + for (;(mg=mgli.current());++mgli) + { + mg->findSectionsInDocumentation(); + } + } + + QListIterator<MemberList> mli(m_memberLists); + MemberList *ml; + for (mli.toFirst();(ml=mli.current());++mli) + { + if (ml->listType()&MemberList::declarationLists) + { + ml->findSectionsInDocumentation(); + } + } +} + +void FileDef::writeDetailedDescription(OutputList &ol,const QCString &title) +{ + if ((!briefDescription().isEmpty() && Config_getBool("REPEAT_BRIEF")) || + !documentation().isEmpty() || + (Config_getBool("SOURCE_BROWSER") && getStartBodyLine()!=-1 && getBodyDef()) + ) + { + ol.writeRuler(); + ol.pushGeneratorState(); + ol.disableAllBut(OutputGenerator::Html); + ol.writeAnchor(0,"details"); + ol.popGeneratorState(); + ol.startGroupHeader(); + ol.parseText(title); + ol.endGroupHeader(); + + ol.startTextBlock(); + if (!briefDescription().isEmpty() && Config_getBool("REPEAT_BRIEF")) + { + ol.parseDoc(briefFile(),briefLine(),this,0,briefDescription(),FALSE,FALSE); + } + if (!briefDescription().isEmpty() && Config_getBool("REPEAT_BRIEF") && + !documentation().isEmpty()) + { + ol.pushGeneratorState(); + ol.disable(OutputGenerator::Man); + ol.disable(OutputGenerator::RTF); + // ol.newParagraph(); // FIXME:PARA + ol.enableAll(); + ol.disableAllBut(OutputGenerator::Man); + ol.writeString("\n\n"); + ol.popGeneratorState(); + } + if (!documentation().isEmpty()) + { + ol.parseDoc(docFile(),docLine(),this,0,documentation()+"\n",TRUE,FALSE); + } + //printf("Writing source ref for file %s\n",name().data()); + if (Config_getBool("SOURCE_BROWSER")) + { + ol.startParagraph(); + QCString refText = theTranslator->trDefinedInSourceFile(); + int fileMarkerPos = refText.find("@0"); + if (fileMarkerPos!=-1) // should always pass this. + { + ol.parseText(refText.left(fileMarkerPos)); //text left from marker 1 + ol.writeObjectLink(0,getSourceFileBase(), + 0,name()); + ol.parseText(refText.right( + refText.length()-fileMarkerPos-2)); // text right from marker 2 + } + ol.endParagraph(); + } + ol.endTextBlock(); + } +} + +void FileDef::writeBriefDescription(OutputList &ol) +{ + if (!briefDescription().isEmpty() && Config_getBool("BRIEF_MEMBER_DESC")) + { + ol.startParagraph(); + ol.parseDoc(briefFile(),briefLine(),this,0, + briefDescription(),TRUE,FALSE,0,TRUE,FALSE); + ol.pushGeneratorState(); + ol.disable(OutputGenerator::RTF); + ol.writeString(" \n"); + ol.enable(OutputGenerator::RTF); + + if (Config_getBool("REPEAT_BRIEF") || + !documentation().isEmpty() + ) + { + ol.disableAllBut(OutputGenerator::Html); + ol.startTextLink(0,"details"); + ol.parseText(theTranslator->trMore()); + ol.endTextLink(); + } + ol.popGeneratorState(); + ol.endParagraph(); + + //ol.pushGeneratorState(); + //ol.disable(OutputGenerator::RTF); + //ol.newParagraph(); + //ol.popGeneratorState(); + } + ol.writeSynopsis(); +} + +void FileDef::writeIncludeFiles(OutputList &ol) +{ + if (/*Config_getBool("SHOW_INCLUDE_FILES") &&*/ includeList && + includeList->count()>0) + { + ol.startTextBlock(TRUE); + QListIterator<IncludeInfo> ili(*includeList); + IncludeInfo *ii; + for (;(ii=ili.current());++ili) + { + if (!ii->indirect) + { + FileDef *fd=ii->fileDef; + bool isIDLorJava = FALSE; + if (fd) + { + SrcLangExt lang = fd->getLanguage(); + isIDLorJava = lang==SrcLangExt_IDL || lang==SrcLangExt_Java; + } + ol.startTypewriter(); + if (isIDLorJava) // IDL/Java include + { + ol.docify("import "); + } + else if (ii->imported) // Objective-C include + { + ol.docify("#import "); + } + else // C/C++ include + { + ol.docify("#include "); + } + if (ii->local || isIDLorJava) + ol.docify("\""); + else + ol.docify("<"); + ol.disable(OutputGenerator::Html); + ol.docify(ii->includeName); + ol.enableAll(); + ol.disableAllBut(OutputGenerator::Html); + + // Here we use the include file name as it appears in the file. + // we could also we the name as it is used within doxygen, + // then we should have used fd->docName() instead of ii->includeName + if (fd && fd->isLinkable()) + { + ol.writeObjectLink(fd->getReference(), + fd->generateSourceFile() ? fd->includeName() : fd->getOutputFileBase(), + 0,ii->includeName); + if (!Config_getString("GENERATE_TAGFILE").isEmpty() && !fd->isReference()) + { + const char *locStr = (ii->local || isIDLorJava) ? "yes" : "no"; + const char *impStr = (ii->imported || isIDLorJava) ? "yes" : "no"; + Doxygen::tagFile << " <includes id=\"" + << convertToXML(fd->getOutputFileBase()) << "\" " + << "name=\"" << convertToXML(fd->name()) << "\" " + << "local=\"" << locStr << "\" " + << "imported=\"" << impStr << "\">" + << convertToXML(ii->includeName) + << "</includes>" + << endl; + } + } + else + { + ol.docify(ii->includeName); + } + + ol.enableAll(); + if (ii->local || isIDLorJava) + ol.docify("\""); + else + ol.docify(">"); + if (isIDLorJava) + ol.docify(";"); + ol.endTypewriter(); + ol.lineBreak(); + } + } + ol.endTextBlock(); + } +} + +void FileDef::writeIncludeGraph(OutputList &ol) +{ + if (Config_getBool("HAVE_DOT") /*&& Config_getBool("INCLUDE_GRAPH")*/) + { + //printf("Graph for file %s\n",name().data()); + DotInclDepGraph incDepGraph(this,FALSE); + if (!incDepGraph.isTrivial() && !incDepGraph.isTooBig()) + { + ol.startTextBlock(); + ol.disable(OutputGenerator::Man); + ol.startInclDepGraph(); + ol.parseText(theTranslator->trInclDepGraph(name())); + ol.endInclDepGraph(incDepGraph); + ol.enableAll(); + ol.endTextBlock(TRUE); + } + //incDepGraph.writeGraph(Config_getString("HTML_OUTPUT"),fd->getOutputFileBase()); + } +} + +void FileDef::writeIncludedByGraph(OutputList &ol) +{ + if (Config_getBool("HAVE_DOT") /*&& Config_getBool("INCLUDED_BY_GRAPH")*/) + { + //printf("Graph for file %s\n",name().data()); + DotInclDepGraph incDepGraph(this,TRUE); + if (!incDepGraph.isTrivial() && !incDepGraph.isTooBig()) + { + ol.startTextBlock(); + ol.disable(OutputGenerator::Man); + ol.startInclDepGraph(); + ol.parseText(theTranslator->trInclByDepGraph()); + ol.endInclDepGraph(incDepGraph); + ol.enableAll(); + ol.endTextBlock(TRUE); + } + //incDepGraph.writeGraph(Config_getString("HTML_OUTPUT"),fd->getOutputFileBase()); + } +} + + +void FileDef::writeSourceLink(OutputList &ol) +{ + //printf("%s: generateSourceFile()=%d\n",name().data(),generateSourceFile()); + if (generateSourceFile()) + { + ol.disableAllBut(OutputGenerator::Html); + ol.startParagraph(); + ol.startTextLink(includeName(),0); + ol.parseText(theTranslator->trGotoSourceCode()); + ol.endTextLink(); + ol.endParagraph(); + ol.enableAll(); + } +} + +void FileDef::writeNamespaceDeclarations(OutputList &ol,const QCString &title) +{ + // write list of namespaces + if (namespaceSDict) namespaceSDict->writeDeclaration(ol,title); +} + +void FileDef::writeClassDeclarations(OutputList &ol,const QCString &title) +{ + // write list of classes + if (classSDict) classSDict->writeDeclaration(ol,0,title,FALSE); +} + +void FileDef::writeInlineClasses(OutputList &ol) +{ + if (classSDict) classSDict->writeDocumentation(ol,this); +} + +void FileDef::startMemberDeclarations(OutputList &ol) +{ + ol.startMemberSections(); +} + +void FileDef::endMemberDeclarations(OutputList &ol) +{ + ol.endMemberSections(); +} + +void FileDef::startMemberDocumentation(OutputList &ol) +{ + if (Config_getBool("SEPARATE_MEMBER_PAGES")) + { + ol.disable(OutputGenerator::Html); + Doxygen::suppressDocWarnings = TRUE; + } +} + +void FileDef::endMemberDocumentation(OutputList &ol) +{ + if (Config_getBool("SEPARATE_MEMBER_PAGES")) + { + ol.enable(OutputGenerator::Html); + Doxygen::suppressDocWarnings = FALSE; + } +} + +void FileDef::writeMemberGroups(OutputList &ol) +{ + /* write user defined member groups */ + if (memberGroupSDict) + { + memberGroupSDict->sort(); + MemberGroupSDict::Iterator mgli(*memberGroupSDict); + MemberGroup *mg; + for (;(mg=mgli.current());++mgli) + { + if ((!mg->allMembersInSameSection() || !m_subGrouping) + && mg->header()!="[NOHEADER]") + { + mg->writeDeclarations(ol,0,0,this,0); + } + } + } +} + +void FileDef::writeAuthorSection(OutputList &ol) +{ + // write Author section (Man only) + ol.pushGeneratorState(); + ol.disableAllBut(OutputGenerator::Man); + ol.startGroupHeader(); + ol.parseText(theTranslator->trAuthor(TRUE,TRUE)); + ol.endGroupHeader(); + ol.parseText(theTranslator->trGeneratedAutomatically(Config_getString("PROJECT_NAME"))); + ol.popGeneratorState(); +} + +void FileDef::writeSummaryLinks(OutputList &ol) +{ + ol.pushGeneratorState(); + ol.disableAllBut(OutputGenerator::Html); + QListIterator<LayoutDocEntry> eli( + LayoutDocManager::instance().docEntries(LayoutDocManager::File)); + LayoutDocEntry *lde; + bool first=TRUE; + for (eli.toFirst();(lde=eli.current());++eli) + { + if ((lde->kind()==LayoutDocEntry::FileClasses && classSDict && classSDict->declVisible()) || + (lde->kind()==LayoutDocEntry::FileNamespaces && namespaceSDict && namespaceSDict->declVisible()) + ) + { + LayoutDocEntrySection *ls = (LayoutDocEntrySection*)lde; + QCString label = lde->kind()==LayoutDocEntry::FileClasses ? "nested-classes" : "namespaces"; + writeSummaryLink(ol,label,ls->title,first); + } + else if (lde->kind()==LayoutDocEntry::MemberDecl) + { + LayoutDocEntryMemberDecl *lmd = (LayoutDocEntryMemberDecl*)lde; + MemberList * ml = getMemberList(lmd->type); + if (ml && ml->declVisible()) + { + writeSummaryLink(ol,ml->listTypeAsString(),lmd->title,first); + } + } + } + if (!first) + { + ol.writeString(" </div>\n"); + } + ol.popGeneratorState(); +} + +/*! Write the documentation page for this file to the file of output + generators \a ol. +*/ +void FileDef::writeDocumentation(OutputList &ol) +{ + static bool generateTreeView = Config_getBool("GENERATE_TREEVIEW"); + //funcList->countDecMembers(); + + //QCString fn = name(); + //if (Config_getBool("FULL_PATH_NAMES")) + //{ + // fn.prepend(stripFromPath(getPath().copy())); + //} + + //printf("WriteDocumentation diskname=%s\n",diskname.data()); + + QCString versionTitle; + if (!fileVersion.isEmpty()) + { + versionTitle=("("+fileVersion+")"); + } + QCString title = docname+versionTitle; + QCString pageTitle=theTranslator->trFileReference(docname); + + if (Config_getBool("SHOW_DIRECTORIES") && getDirDef()) + { + startFile(ol,getOutputFileBase(),name(),pageTitle,HLI_FileVisible,!generateTreeView); + if (!generateTreeView) + { + getDirDef()->writeNavigationPath(ol); + ol.endQuickIndices(); + } + QCString pageTitleShort=theTranslator->trFileReference(name()); + startTitle(ol,getOutputFileBase(),this); + ol.pushGeneratorState(); + ol.disableAllBut(OutputGenerator::Html); + ol.parseText(pageTitleShort); // Html only + ol.enableAll(); + ol.disable(OutputGenerator::Html); + ol.parseText(pageTitle); // other output formats + ol.popGeneratorState(); + addGroupListToTitle(ol,this); + endTitle(ol,getOutputFileBase(),title); + } + else + { + startFile(ol,getOutputFileBase(),name(),pageTitle,HLI_FileVisible,!generateTreeView); + if (!generateTreeView) + { + ol.endQuickIndices(); + } + startTitle(ol,getOutputFileBase(),this); + ol.parseText(pageTitle); + addGroupListToTitle(ol,this); + endTitle(ol,getOutputFileBase(),title); + } + + ol.startContents(); + + if (!fileVersion.isEmpty()) + { + ol.disableAllBut(OutputGenerator::Html); + ol.startProjectNumber(); + ol.docify(versionTitle); + ol.endProjectNumber(); + ol.enableAll(); + } + + if (Doxygen::searchIndex) + { + Doxygen::searchIndex->setCurrentDoc(pageTitle,getOutputFileBase()); + Doxygen::searchIndex->addWord(localName(),TRUE); + } + + if (!Config_getString("GENERATE_TAGFILE").isEmpty()) + { + Doxygen::tagFile << " <compound kind=\"file\">" << endl; + Doxygen::tagFile << " <name>" << convertToXML(name()) << "</name>" << endl; + Doxygen::tagFile << " <path>" << convertToXML(getPath()) << "</path>" << endl; + Doxygen::tagFile << " <filename>" + << convertToXML(getOutputFileBase()) + << "</filename>" << endl; + } + + //---------------------------------------- start flexible part ------------------------------- + + QListIterator<LayoutDocEntry> eli( + LayoutDocManager::instance().docEntries(LayoutDocManager::File)); + LayoutDocEntry *lde; + for (eli.toFirst();(lde=eli.current());++eli) + { + switch (lde->kind()) + { + case LayoutDocEntry::BriefDesc: + writeBriefDescription(ol); + break; + case LayoutDocEntry::MemberDeclStart: + startMemberDeclarations(ol); + break; + case LayoutDocEntry::FileIncludes: + writeIncludeFiles(ol); + break; + case LayoutDocEntry::FileIncludeGraph: + writeIncludeGraph(ol); + break; + case LayoutDocEntry::FileIncludedByGraph: + writeIncludedByGraph(ol); + break; + case LayoutDocEntry::FileSourceLink: + writeSourceLink(ol); + break; + case LayoutDocEntry::FileClasses: + { + LayoutDocEntrySection *ls = (LayoutDocEntrySection*)lde; + writeClassDeclarations(ol,ls->title); + } + break; + case LayoutDocEntry::FileNamespaces: + { + LayoutDocEntrySection *ls = (LayoutDocEntrySection*)lde; + writeNamespaceDeclarations(ol,ls->title); + } + break; + case LayoutDocEntry::MemberGroups: + writeMemberGroups(ol); + break; + case LayoutDocEntry::MemberDecl: + { + LayoutDocEntryMemberDecl *lmd = (LayoutDocEntryMemberDecl*)lde; + writeMemberDeclarations(ol,lmd->type,lmd->title); + } + break; + case LayoutDocEntry::MemberDeclEnd: + endMemberDeclarations(ol); + break; + case LayoutDocEntry::DetailedDesc: + { + LayoutDocEntrySection *ls = (LayoutDocEntrySection*)lde; + writeDetailedDescription(ol,ls->title); + } + break; + case LayoutDocEntry::MemberDefStart: + startMemberDocumentation(ol); + break; + case LayoutDocEntry::FileInlineClasses: + writeInlineClasses(ol); + break; + case LayoutDocEntry::MemberDef: + { + LayoutDocEntryMemberDef *lmd = (LayoutDocEntryMemberDef*)lde; + writeMemberDocumentation(ol,lmd->type,lmd->title); + } + break; + case LayoutDocEntry::MemberDefEnd: + endMemberDocumentation(ol); + break; + case LayoutDocEntry::AuthorSection: + writeAuthorSection(ol); + break; + case LayoutDocEntry::ClassIncludes: + case LayoutDocEntry::ClassInheritanceGraph: + case LayoutDocEntry::ClassNestedClasses: + case LayoutDocEntry::ClassCollaborationGraph: + case LayoutDocEntry::ClassAllMembersLink: + case LayoutDocEntry::ClassUsedFiles: + case LayoutDocEntry::ClassInlineClasses: + case LayoutDocEntry::NamespaceNestedNamespaces: + case LayoutDocEntry::NamespaceClasses: + case LayoutDocEntry::NamespaceInlineClasses: + case LayoutDocEntry::GroupClasses: + case LayoutDocEntry::GroupInlineClasses: + case LayoutDocEntry::GroupNamespaces: + case LayoutDocEntry::GroupDirs: + case LayoutDocEntry::GroupNestedGroups: + case LayoutDocEntry::GroupFiles: + case LayoutDocEntry::GroupGraph: + case LayoutDocEntry::GroupPageDocs: + case LayoutDocEntry::DirSubDirs: + case LayoutDocEntry::DirFiles: + case LayoutDocEntry::DirGraph: + err("Internal inconsistency: member %d should not be part of " + "LayoutDocManager::File entry list\n",lde->kind()); + break; + } + } + + //---------------------------------------- end flexible part ------------------------------- + + if (!Config_getString("GENERATE_TAGFILE").isEmpty()) + { + writeDocAnchorsToTagFile(); + Doxygen::tagFile << " </compound>" << endl; + } + + ol.endContents(); + + endFileWithNavPath(this,ol); + + if (Config_getBool("SEPARATE_MEMBER_PAGES")) + { + MemberList *ml = getMemberList(MemberList::allMembersList); + if (ml) ml->sort(); + writeMemberPages(ol); + } +} + +void FileDef::writeMemberPages(OutputList &ol) +{ + ol.pushGeneratorState(); + ol.disableAllBut(OutputGenerator::Html); + + QListIterator<MemberList> mli(m_memberLists); + MemberList *ml; + for (mli.toFirst();(ml=mli.current());++mli) + { + if (ml->listType()&MemberList::documentationLists) + { + ml->writeDocumentationPage(ol,name(),this); + } + } + + ol.popGeneratorState(); +} + +void FileDef::writeQuickMemberLinks(OutputList &ol,MemberDef *currentMd) const +{ + static bool createSubDirs=Config_getBool("CREATE_SUBDIRS"); + + ol.writeString(" <div class=\"navtab\">\n"); + ol.writeString(" <table>\n"); + + MemberList *allMemberList = getMemberList(MemberList::allMembersList); + if (allMemberList) + { + MemberListIterator mli(*allMemberList); + MemberDef *md; + for (mli.toFirst();(md=mli.current());++mli) + { + if (md->getFileDef()==this && md->getNamespaceDef()==0 && md->isLinkable()) + { + ol.writeString(" <tr><td class=\"navtab\">"); + if (md->isLinkableInProject()) + { + if (md==currentMd) // selected item => highlight + { + ol.writeString("<a class=\"qindexHL\" "); + } + else + { + ol.writeString("<a class=\"qindex\" "); + } + ol.writeString("href=\""); + if (createSubDirs) ol.writeString("../../"); + ol.writeString(md->getOutputFileBase()+Doxygen::htmlFileExtension+"#"+md->anchor()); + ol.writeString("\">"); + ol.writeString(convertToHtml(md->localName())); + ol.writeString("</a>"); + } + ol.writeString("</td></tr>\n"); + } + } + } + + ol.writeString(" </table>\n"); + ol.writeString(" </div>\n"); +} + +/*! Write a source listing of this file to the output */ +void FileDef::writeSource(OutputList &ol) +{ + static bool generateTreeView = Config_getBool("GENERATE_TREEVIEW"); + static bool filterSourceFiles = Config_getBool("FILTER_SOURCE_FILES"); + static bool latexSourceCode = Config_getBool("LATEX_SOURCE_CODE"); + QCString title = docname; + if (!fileVersion.isEmpty()) + { + title+=(" ("+fileVersion+")"); + } + QCString pageTitle = theTranslator->trSourceFile(title); + ol.disable(OutputGenerator::Man); + ol.disable(OutputGenerator::RTF); + if (!latexSourceCode) ol.disable(OutputGenerator::Latex); + + if (Config_getBool("SHOW_DIRECTORIES") && getDirDef()) + { + startFile(ol,getSourceFileBase(),0,pageTitle,HLI_FileVisible, + !generateTreeView,getOutputFileBase()); + if (!generateTreeView) + { + getDirDef()->writeNavigationPath(ol); + ol.endQuickIndices(); + } + startTitle(ol,getOutputFileBase()); + ol.parseText(name()); + endTitle(ol,getOutputFileBase(),title); + } + else + { + startFile(ol,getSourceFileBase(),0,pageTitle,HLI_FileVisible, + FALSE,getOutputFileBase()); + startTitle(ol,getSourceFileBase()); + ol.parseText(title); + endTitle(ol,getSourceFileBase(),0); + } + + ol.startContents(); + + if (isLinkable()) + { + if (latexSourceCode) ol.disable(OutputGenerator::Latex); + ol.startTextLink(getOutputFileBase(),0); + ol.parseText(theTranslator->trGotoDocumentation()); + ol.endTextLink(); + if (latexSourceCode) ol.enable(OutputGenerator::Latex); + } + + ParserInterface *pIntf = Doxygen::parserManager->getParser(getDefFileExtension()); + pIntf->resetCodeParserState(); + ol.startCodeFragment(); + pIntf->parseCode(ol,0, + fileToString(absFilePath(),filterSourceFiles,TRUE), + FALSE,0,this + ); + ol.endCodeFragment(); + ol.endContents(); + endFileWithNavPath(this,ol); + ol.enableAll(); +} + +void FileDef::parseSource() +{ + static bool filterSourceFiles = Config_getBool("FILTER_SOURCE_FILES"); + DevNullCodeDocInterface devNullIntf; + ParserInterface *pIntf = Doxygen::parserManager->getParser(getDefFileExtension()); + pIntf->resetCodeParserState(); + pIntf->parseCode( + devNullIntf,0, + fileToString(absFilePath(),filterSourceFiles,TRUE), + FALSE,0,this + ); +} + +void FileDef::addMembersToMemberGroup() +{ + QListIterator<MemberList> mli(m_memberLists); + MemberList *ml; + for (mli.toFirst();(ml=mli.current());++mli) + { + if (ml->listType()&MemberList::declarationLists) + { + ::addMembersToMemberGroup(ml,&memberGroupSDict,this); + } + } + + // add members inside sections to their groups + if (memberGroupSDict) + { + MemberGroupSDict::Iterator mgli(*memberGroupSDict); + MemberGroup *mg; + for (;(mg=mgli.current());++mgli) + { + if (mg->allMembersInSameSection() && m_subGrouping) + { + //printf("----> addToDeclarationSection(%s)\n",mg->header().data()); + mg->addToDeclarationSection(); + } + } + } +} + +/*! Adds member definition \a md to the list of all members of this file */ +void FileDef::insertMember(MemberDef *md) +{ + if (md->isHidden()) return; + //printf("%s:FileDef::insertMember(%s (=%p) list has %d elements)\n", + // name().data(),md->name().data(),md,allMemberList.count()); + MemberList *allMemberList = getMemberList(MemberList::allMembersList); + if (allMemberList && allMemberList->findRef(md)!=-1) // TODO optimize the findRef! + { + return; + } + + if (allMemberList==0) + { + allMemberList = new MemberList(MemberList::allMembersList);; + m_memberLists.append(allMemberList); + } + allMemberList->append(md); + //::addFileMemberNameToIndex(md); + switch (md->memberType()) + { + case MemberDef::Variable: + case MemberDef::Property: + addMemberToList(MemberList::decVarMembers,md); + addMemberToList(MemberList::docVarMembers,md); + break; + case MemberDef::Function: + addMemberToList(MemberList::decFuncMembers,md); + addMemberToList(MemberList::docFuncMembers,md); + break; + case MemberDef::Typedef: + addMemberToList(MemberList::decTypedefMembers,md); + addMemberToList(MemberList::docTypedefMembers,md); + break; + case MemberDef::Enumeration: + addMemberToList(MemberList::decEnumMembers,md); + addMemberToList(MemberList::docEnumMembers,md); + break; + case MemberDef::EnumValue: // enum values are shown inside their enums + break; + case MemberDef::Define: + addMemberToList(MemberList::decDefineMembers,md); + addMemberToList(MemberList::docDefineMembers,md); + break; + default: + err("FileDef::insertMembers(): " + "member `%s' with class scope `%s' inserted in file scope `%s'!\n", + md->name().data(), + md->getClassDef() ? md->getClassDef()->name().data() : "<global>", + name().data()); + } + //addMemberToGroup(md,groupId); +} + +/*! Adds compound definition \a cd to the list of all compounds of this file */ +void FileDef::insertClass(ClassDef *cd) +{ + if (cd->isHidden()) return; + if (classSDict==0) + { + classSDict = new ClassSDict(17); + } + if (Config_getBool("SORT_BRIEF_DOCS")) + classSDict->inSort(cd->name(),cd); + else + classSDict->append(cd->name(),cd); +} + +/*! Adds namespace definition \a nd to the list of all compounds of this file */ +void FileDef::insertNamespace(NamespaceDef *nd) +{ + if (nd->isHidden()) return; + if (!nd->name().isEmpty() && + (namespaceSDict==0 || namespaceSDict->find(nd->name())==0)) + { + if (namespaceSDict==0) + { + namespaceSDict = new NamespaceSDict; + } + if (Config_getBool("SORT_BRIEF_DOCS")) + namespaceSDict->inSort(nd->name(),nd); + else + namespaceSDict->append(nd->name(),nd); + } +} + +void FileDef::addSourceRef(int line,Definition *d,MemberDef *md) +{ + //printf("FileDef::addSourceDef(%d,%p,%p)\n",line,d,md); + if (d) + { + if (srcDefDict==0) srcDefDict = new QIntDict<Definition>(257); + if (srcMemberDict==0) srcMemberDict = new QIntDict<MemberDef>(257); + srcDefDict->insert(line,d); + if (md) srcMemberDict->insert(line,md); + //printf("Adding member %s with anchor %s at line %d to file %s\n", + // md->name().data(),md->anchor().data(),line,name().data()); + } +} + +Definition *FileDef::getSourceDefinition(int lineNr) +{ + Definition *result=0; + if (srcDefDict) + { + result = srcDefDict->find(lineNr); + } + return result; +} + +MemberDef *FileDef::getSourceMember(int lineNr) +{ + MemberDef *result=0; + if (srcMemberDict) + { + result = srcMemberDict->find(lineNr); + } + return result; +} + + +void FileDef::addUsingDirective(NamespaceDef *nd) +{ + if (usingDirList==0) + { + usingDirList = new NamespaceSDict; + } + if (usingDirList->find(nd->qualifiedName())==0) + { + usingDirList->append(nd->qualifiedName(),nd); + } + //printf("%p: FileDef::addUsingDirective: %s:%d\n",this,name().data(),usingDirList->count()); +} + +NamespaceSDict *FileDef::getUsedNamespaces() const +{ + //printf("%p: FileDef::getUsedNamespace: %s:%d\n",this,name().data(),usingDirList?usingDirList->count():0); + return usingDirList; +} + +void FileDef::addUsingDeclaration(Definition *d) +{ + if (usingDeclList==0) + { + usingDeclList = new SDict<Definition>(17); + } + if (usingDeclList->find(d->qualifiedName())==0) + { + usingDeclList->append(d->qualifiedName(),d); + } +} + +void FileDef::addIncludeDependency(FileDef *fd,const char *incName,bool local, + bool imported,bool indirect) +{ + //printf("FileDef::addIncludeDependency(%p,%s,%d)\n",fd,incName,local); + QCString iName = fd ? fd->absFilePath().data() : incName; + if (!iName.isEmpty() && (!includeDict || includeDict->find(iName)==0)) + { + if (includeDict==0) + { + includeDict = new QDict<IncludeInfo>(61); + includeList = new QList<IncludeInfo>; + includeList->setAutoDelete(TRUE); + } + IncludeInfo *ii = new IncludeInfo; + ii->fileDef = fd; + ii->includeName = incName; + ii->local = local; + ii->imported = imported; + ii->indirect = indirect; + includeList->append(ii); + includeDict->insert(iName,ii); + } +} + +void FileDef::addIncludedUsingDirectives() +{ + if (visited) return; + visited=TRUE; + //printf("( FileDef::addIncludedUsingDirectives for file %s\n",name().data()); + + NamespaceList nl; + if (includeList) // file contains #includes + { + { + QListIterator<IncludeInfo> iii(*includeList); + IncludeInfo *ii; + for (iii.toFirst();(ii=iii.current());++iii) // foreach #include... + { + if (ii->fileDef && !ii->fileDef->visited) // ...that is a known file + { + // recurse into this file + ii->fileDef->addIncludedUsingDirectives(); + } + } + } + { + QListIterator<IncludeInfo> iii(*includeList); + IncludeInfo *ii; + // iterate through list from last to first + for (iii.toLast();(ii=iii.current());--iii) + { + if (ii->fileDef && ii->fileDef!=this) + { + // add using directives + NamespaceSDict *unl = ii->fileDef->usingDirList; + if (unl) + { + NamespaceSDict::Iterator nli(*unl); + NamespaceDef *nd; + for (nli.toLast();(nd=nli.current());--nli) + { + // append each using directive found in a #include file + if (usingDirList==0) usingDirList = new NamespaceSDict; + //printf("Prepending used namespace %s to the list of file %s\n", + // nd->name().data(),name().data()); + if (usingDirList->find(nd->qualifiedName())==0) // not yet added + { + usingDirList->prepend(nd->qualifiedName(),nd); + } + } + } + // add using declarations + SDict<Definition> *udl = ii->fileDef->usingDeclList; + if (udl) + { + SDict<Definition>::Iterator udi(*udl); + Definition *d; + for (udi.toLast();(d=udi.current());--udi) + { + //printf("Adding using declaration %s\n",d->name().data()); + if (usingDeclList==0) + { + usingDeclList = new SDict<Definition>(17); + } + if (usingDeclList->find(d->qualifiedName())==0) + { + usingDeclList->prepend(d->qualifiedName(),d); + } + } + } + } + } + } + } + //printf(") end FileDef::addIncludedUsingDirectives for file %s\n",name().data()); +} + + +void FileDef::addIncludedByDependency(FileDef *fd,const char *incName, + bool local,bool imported) +{ + //printf("FileDef::addIncludedByDependency(%p,%s,%d)\n",fd,incName,local); + QCString iName = fd ? fd->absFilePath().data() : incName; + if (!iName.isEmpty() && (includedByDict==0 || includedByDict->find(iName)==0)) + { + if (includedByDict==0) + { + includedByDict = new QDict<IncludeInfo>(61); + includedByList = new QList<IncludeInfo>; + includedByList->setAutoDelete(TRUE); + } + IncludeInfo *ii = new IncludeInfo; + ii->fileDef = fd; + ii->includeName = incName; + ii->local = local; + ii->imported = imported; + ii->indirect = FALSE; + includedByList->append(ii); + includedByDict->insert(iName,ii); + } +} + +bool FileDef::isIncluded(const QCString &name) const +{ + if (name.isEmpty()) return FALSE; + return includeDict!=0 && includeDict->find(name)!=0; +} + +bool FileDef::generateSourceFile() const +{ + QCString extension = name().right(4); + return !isReference() && + (Config_getBool("SOURCE_BROWSER") || + (Config_getBool("VERBATIM_HEADERS") && guessSection(name())==Entry::HEADER_SEC) + ) && + extension!=".doc" && extension!=".txt" && extension!=".dox"; +} + + +void FileDef::addListReferences() +{ + { + LockingPtr< QList<ListItemInfo> > xrefItems = xrefListItems(); + addRefItem(xrefItems.pointer(), + getOutputFileBase(), + theTranslator->trFile(TRUE,TRUE), + getOutputFileBase(),name(), + 0 + ); + } + if (memberGroupSDict) + { + MemberGroupSDict::Iterator mgli(*memberGroupSDict); + MemberGroup *mg; + for (;(mg=mgli.current());++mgli) + { + mg->addListReferences(this); + } + } + QListIterator<MemberList> mli(m_memberLists); + MemberList *ml; + for (mli.toFirst();(ml=mli.current());++mli) + { + if (ml->listType()&MemberList::documentationLists) + { + ml->addListReferences(this); + } + } +} + +//------------------------------------------------------------------- + +static int findMatchingPart(const QCString &path,const QCString dir) +{ + int si1; + int pos1=0,pos2=0; + while ((si1=path.find('/',pos1))!=-1) + { + int si2=dir.find('/',pos2); + //printf(" found slash at pos %d in path %d: %s<->%s\n",si1,si2, + // path.mid(pos1,si1-pos2).data(),dir.mid(pos2).data()); + if (si2==-1 && path.mid(pos1,si1-pos2)==dir.mid(pos2)) // match at end + { + return dir.length(); + } + if (si1!=si2 || path.mid(pos1,si1-pos2)!=dir.mid(pos2,si2-pos2)) // no match in middle + { + return QMAX(pos1-1,0); + } + pos1=si1+1; + pos2=si2+1; + } + return 0; +} + +static Directory *findDirNode(Directory *root,const QCString &name) +{ + QListIterator<DirEntry> dli(root->children()); + DirEntry *de; + for (dli.toFirst();(de=dli.current());++dli) + { + if (de->kind()==DirEntry::Dir) + { + Directory *dir = (Directory *)de; + QCString dirName=dir->name(); + int sp=findMatchingPart(name,dirName); + //printf("findMatchingPart(%s,%s)=%d\n",name.data(),dirName.data(),sp); + if (sp>0) // match found + { + if ((uint)sp==dirName.length()) // whole directory matches + { + // recurse into the directory + return findDirNode(dir,name.mid(dirName.length()+1)); + } + else // partial match => we need to split the path into three parts + { + QCString baseName =dirName.left(sp); + QCString oldBranchName=dirName.mid(sp+1); + QCString newBranchName=name.mid(sp+1); + // strip file name from path + int newIndex=newBranchName.findRev('/'); + if (newIndex>0) newBranchName=newBranchName.left(newIndex); + + //printf("Splitting off part in new branch \n" + // "base=%s old=%s new=%s\n", + // baseName.data(), + // oldBranchName.data(), + // newBranchName.data() + // ); + Directory *base = new Directory(root,baseName); + Directory *newBranch = new Directory(base,newBranchName); + dir->reParent(base); + dir->rename(oldBranchName); + base->addChild(dir); + base->addChild(newBranch); + dir->setLast(FALSE); + // remove DirEntry container from list (without deleting it) + root->children().setAutoDelete(FALSE); + root->children().removeRef(dir); + root->children().setAutoDelete(TRUE); + // add new branch to the root + if (!root->children().isEmpty()) + { + root->children().last()->setLast(FALSE); + } + root->addChild(base); + return newBranch; + } + } + } + } + int si=name.findRev('/'); + if (si==-1) // no subdir + { + return root; // put the file under the root node. + } + else // need to create a subdir + { + QCString baseName = name.left(si); + //printf("new subdir %s\n",baseName.data()); + Directory *newBranch = new Directory(root,baseName); + if (!root->children().isEmpty()) + { + root->children().last()->setLast(FALSE); + } + root->addChild(newBranch); + return newBranch; + } +} + +static void mergeFileDef(Directory *root,FileDef *fd) +{ + QCString rootPath = root->name(); + QCString filePath = fd->absFilePath(); + //printf("merging %s\n",filePath.data()); + Directory *dirNode = findDirNode(root,filePath); + if (!dirNode->children().isEmpty()) + { + dirNode->children().last()->setLast(FALSE); + } + DirEntry *e=new DirEntry(dirNode,fd); + dirNode->addChild(e); +} + +#if 0 +static void generateIndent(QTextStream &t,DirEntry *de,int level) +{ + if (de->parent()) + { + generateIndent(t,de->parent(),level+1); + } + // from the root up to node n do... + if (level==0) // item before a dir or document + { + if (de->isLast()) + { + if (de->kind()==DirEntry::Dir) + { + t << "<img " << FTV_IMGATTRIBS(plastnode) << "/>"; + } + else + { + t << "<img " << FTV_IMGATTRIBS(lastnode) << "/>"; + } + } + else + { + if (de->kind()==DirEntry::Dir) + { + t << "<img " << FTV_IMGATTRIBS(pnode) << "/>"; + } + else + { + t << "<img " << FTV_IMGATTRIBS(node) << "/>"; + } + } + } + else // item at another level + { + if (de->isLast()) + { + t << "<img " << FTV_IMGATTRIBS(blank) << "/>"; + } + else + { + t << "<img " << FTV_IMGATTRIBS(vertline) << "/>"; + } + } +} + +static void writeDirTreeNode(QTextStream &t,Directory *root,int level) +{ + QCString indent; + indent.fill(' ',level*2); + QListIterator<DirEntry> dli(root->children()); + DirEntry *de; + for (dli.toFirst();(de=dli.current());++dli) + { + t << indent << "<p>"; + generateIndent(t,de,0); + if (de->kind()==DirEntry::Dir) + { + Directory *dir=(Directory *)de; + //printf("%s [dir]: %s (last=%d,dir=%d)\n",indent.data(),dir->name().data(),dir->isLast(),dir->kind()==DirEntry::Dir); + t << "<img " << FTV_IMGATTRIBS(folderclosed) << "/>"; + t << dir->name(); + t << "</p>\n"; + t << indent << "<div>\n"; + writeDirTreeNode(t,dir,level+1); + t << indent << "</div>\n"; + } + else + { + //printf("%s [file]: %s (last=%d,dir=%d)\n",indent.data(),de->file()->name().data(),de->isLast(),de->kind()==DirEntry::Dir); + t << "<img " << FTV_IMGATTRIBS(doc) << "/>"; + t << de->file()->name(); + t << "</p>\n"; + } + } +} +#endif + +static void addDirsAsGroups(Directory *root,GroupDef *parent,int level) +{ + GroupDef *gd=0; + if (root->kind()==DirEntry::Dir) + { + gd = new GroupDef("[generated]", + 1, + root->path(), // name + root->name() // title + ); + if (parent) + { + parent->addGroup(gd); + gd->makePartOfGroup(parent); + } + else + { + Doxygen::groupSDict->append(root->path(),gd); + } + } + QListIterator<DirEntry> dli(root->children()); + DirEntry *de; + for (dli.toFirst();(de=dli.current());++dli) + { + if (de->kind()==DirEntry::Dir) + { + addDirsAsGroups((Directory *)de,gd,level+1); + } + } +} + +void generateFileTree() +{ + Directory *root=new Directory(0,"root"); + root->setLast(TRUE); + FileNameListIterator fnli(*Doxygen::inputNameList); + FileName *fn; + for (fnli.toFirst();(fn=fnli.current());++fnli) + { + FileNameIterator fni(*fn); + FileDef *fd; + for (;(fd=fni.current());++fni) + { + mergeFileDef(root,fd); + } + } + //t << "<div class=\"directory\">\n"; + //writeDirTreeNode(t,root,0); + //t << "</div>\n"; + addDirsAsGroups(root,0,0); + delete root; +} + +//------------------------------------------------------------------- + +void FileDef::combineUsingRelations() +{ + if (visited) return; // already done + visited=TRUE; + if (usingDirList) + { + NamespaceSDict::Iterator nli(*usingDirList); + NamespaceDef *nd; + for (nli.toFirst();(nd=nli.current());++nli) + { + nd->combineUsingRelations(); + } + for (nli.toFirst();(nd=nli.current());++nli) + { + // add used namespaces of namespace nd to this namespace + if (nd->getUsedNamespaces()) + { + NamespaceSDict::Iterator unli(*nd->getUsedNamespaces()); + NamespaceDef *und; + for (unli.toFirst();(und=unli.current());++unli) + { + //printf("Adding namespace %s to the using list of %s\n",und->qualifiedName().data(),qualifiedName().data()); + addUsingDirective(und); + } + } + // add used classes of namespace nd to this namespace + if (nd->getUsedClasses()) + { + SDict<Definition>::Iterator cli(*nd->getUsedClasses()); + Definition *ucd; + for (cli.toFirst();(ucd=cli.current());++cli) + { + //printf("Adding class %s to the using list of %s\n",cd->qualifiedName().data(),qualifiedName().data()); + addUsingDeclaration(ucd); + } + } + } + } +} + +bool FileDef::isDocumentationFile() const +{ + return name().right(4)==".doc" || + name().right(4)==".txt" || + name().right(4)==".dox"; +} + +void FileDef::acquireFileVersion() +{ + QCString vercmd = Config_getString("FILE_VERSION_FILTER"); + if (!vercmd.isEmpty() && !filepath.isEmpty() && filepath!="generated") + { + msg("Version of %s : ",filepath.data()); + QCString cmd = vercmd+" \""+filepath+"\""; + Debug::print(Debug::ExtCmd,0,"Executing popen(`%s`)\n",cmd.data()); + FILE *f=portable_popen(cmd,"r"); + if (!f) + { + err("error: could not execute %s\n",vercmd.data()); + return; + } + const int bufSize=1024; + char buf[bufSize]; + int numRead = fread(buf,1,bufSize,f); + portable_pclose(f); + if (numRead>0 && !(fileVersion=QCString(buf,numRead).stripWhiteSpace()).isEmpty()) + { + msg("%s\n",fileVersion.data()); + } + else + { + msg("no version available\n"); + } + } +} + + +QCString FileDef::getSourceFileBase() const +{ + if (Htags::useHtags) + { + return Htags::path2URL(filepath); + } + else + { + return convertNameToFile(diskname)+"_source"; + } +} + +/*! Returns the name of the verbatim copy of this file (if any). */ +QCString FileDef::includeName() const +{ + if (Htags::useHtags) + { + return Htags::path2URL(filepath); + } + else + { + return convertNameToFile(diskname)+"_source"; + } +} + +MemberList *FileDef::createMemberList(MemberList::ListType lt) +{ + m_memberLists.setAutoDelete(TRUE); + QListIterator<MemberList> mli(m_memberLists); + MemberList *ml; + for (mli.toFirst();(ml=mli.current());++mli) + { + if (ml->listType()==lt) + { + return ml; + } + } + // not found, create a new member list + ml = new MemberList(lt); + m_memberLists.append(ml); + return ml; +} + +void FileDef::addMemberToList(MemberList::ListType lt,MemberDef *md) +{ + static bool sortBriefDocs = Config_getBool("SORT_BRIEF_DOCS"); + static bool sortMemberDocs = Config_getBool("SORT_MEMBER_DOCS"); + MemberList *ml = createMemberList(lt); + ml->setNeedsSorting( + ((ml->listType()&MemberList::declarationLists) && sortBriefDocs) || + ((ml->listType()&MemberList::documentationLists) && sortMemberDocs)); + ml->append(md); +#if 0 + if (ml->needsSorting()) + ml->inSort(md); + else + ml->append(md); +#endif + if (lt&MemberList::documentationLists) + { + ml->setInFile(TRUE); + } + if (ml->listType()&MemberList::declarationLists) md->setSectionList(this,ml); +} + +void FileDef::sortMemberLists() +{ + MemberList *ml = m_memberLists.first(); + while (ml) + { + if (ml->needsSorting()) { ml->sort(); ml->setNeedsSorting(FALSE); } + ml = m_memberLists.next(); + } +} + +MemberList *FileDef::getMemberList(MemberList::ListType lt) const +{ + FileDef *that = (FileDef*)this; + MemberList *ml = that->m_memberLists.first(); + while (ml) + { + if (ml->listType()==lt) + { + return ml; + } + ml = that->m_memberLists.next(); + } + return 0; +} + +void FileDef::writeMemberDeclarations(OutputList &ol,MemberList::ListType lt,const QCString &title) +{ + static bool optVhdl = Config_getBool("OPTIMIZE_OUTPUT_VHDL"); + MemberList * ml = getMemberList(lt); + if (ml) + { + if (optVhdl) // use specific declarations function + { + + VhdlDocGen::writeVhdlDeclarations(ml,ol,0,0,this,0); + } + else + { + ml->writeDeclarations(ol,0,0,this,0,title,0); + } + } +} + +void FileDef::writeMemberDocumentation(OutputList &ol,MemberList::ListType lt,const QCString &title) +{ + MemberList * ml = getMemberList(lt); + if (ml) ml->writeDocumentation(ol,name(),this,title); +} + +bool FileDef::isLinkableInProject() const +{ + static bool showFiles = Config_getBool("SHOW_FILES"); + return hasDocumentation() && !isReference() && showFiles; +} + +#if 0 +bool FileDef::includes(FileDef *incFile,QDict<FileDef> *includedFiles) const +{ + //printf("%s::includes(%s)\n",name().data(),incFile->name().data()); + if (incFile==this) return TRUE; + includedFiles->insert(absFilePath(),this); + if (includeList) + { + QListIterator<IncludeInfo> ili(*includeList); + IncludeInfo *ii; + for (;(ii=ili.current());++ili) + { + //printf("ii=%s\n",ii->includeName.data()); + if ((ii->fileDef && + includedFiles->find(ii->fileDef->absFilePath())==0 && + ii->fileDef->includes(incFile,includedFiles) + ) || + incFile->absFilePath()==ii->includeName + ) return TRUE; + } + } + return FALSE; +} + +bool FileDef::includesByName(const QCString &fileName) const +{ + if (includeList) + { + QListIterator<IncludeInfo> ili(*includeList); + IncludeInfo *ii; + for (;(ii=ili.current());++ili) + { + //printf("ii=%s\n",ii->includeName.data()); + if (fileName==ii->includeName) return TRUE; + } + } + return FALSE; +} +#endif diff --git a/trunk/src/filedef.h b/trunk/src/filedef.h new file mode 100644 index 0000000..08b8480 --- /dev/null +++ b/trunk/src/filedef.h @@ -0,0 +1,326 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#ifndef FILEDEF_H +#define FILEDEF_H + +#include "index.h" +#include <qlist.h> +#include <qintdict.h> +#include <qdict.h> +#include "config.h" +#include "definition.h" +#include "memberlist.h" +#include "util.h" + +class FileDef; +class FileList; +class ClassSDict; +class ClassDef; +class ClassList; +class MemberDef; +class OutputList; +class NamespaceDef; +class NamespaceSDict; +class MemberGroupSDict; +class PackageDef; +class DirDef; + +struct IncludeInfo +{ + IncludeInfo() { fileDef=0; local=FALSE; indirect=FALSE; } + ~IncludeInfo() {} + FileDef *fileDef; + QCString includeName; + bool local; + bool imported; + bool indirect; +}; + +/*! \class FileDef filedef.h + \brief A File definition. + + An object of this class contains all file information that is gathered. + This includes the members and compounds defined in the file. + + The member writeDocumentation() can be used to generate the page of + documentation to HTML and LaTeX. +*/ + +class FileDef : public Definition +{ + friend class FileName; + + public: + //enum FileType { Source, Header, Unknown }; + + FileDef(const char *p,const char *n,const char *ref=0,const char *dn=0); + ~FileDef(); + DefType definitionType() const { return TypeFile; } + + /*! Returns the unique file name (this may include part of the path). */ + QCString name() const + { + if (Config_getBool("FULL_PATH_NAMES")) + return filename; + else + return Definition::name(); + } + QCString displayName() const { return name(); } + QCString fileName() const { return filename; } + + QCString getOutputFileBase() const + { return convertNameToFile(diskname); } + QCString anchor() const + { return QCString(); } + + QCString getFileBase() const + { return diskname; } + + QCString getSourceFileBase() const; + + /*! Returns the name of the verbatim copy of this file (if any). */ + QCString includeName() const; + + /*! Returns the absolute path including the file name. */ + QCString absFilePath() const { return filepath; } + + + /*! Returns the name as it is used in the documentation */ + QCString docName() const { return docname; } + + void addSourceRef(int line,Definition *d,MemberDef *md); + Definition *getSourceDefinition(int lineNr); + MemberDef *getSourceMember(int lineNr); + + /* Sets the name of the include file to \a n. */ + //void setIncludeName(const char *n_) { incName=n_; } + + /*! Returns the absolute path of this file. */ + QCString getPath() const { return path; } + + /*! Returns version of this file. */ + QCString getVersion() const { return fileVersion; } + + bool isLinkableInProject() const; + + bool isLinkable() const + { + return isLinkableInProject() || isReference(); + } + bool isIncluded(const QCString &name) const; + + //bool isJava() const { return m_isJava; } + //bool isCSharp() const { return m_isCSharp; } + + void writeDocumentation(OutputList &ol); + void writeMemberPages(OutputList &ol); + void writeQuickMemberLinks(OutputList &ol,MemberDef *currentMd) const; + void writeSummaryLinks(OutputList &ol); + + void writeSource(OutputList &ol); + void parseSource(); + friend void generatedFileNames(); + void insertMember(MemberDef *md); + void insertClass(ClassDef *cd); + void insertNamespace(NamespaceDef *nd); + void computeAnchors(); + + void setPackageDef(PackageDef *pd) { package=pd; } + PackageDef *packageDef() const { return package; } + + void setDirDef(DirDef *dd) { dir=dd; } + DirDef *getDirDef() const { return dir; } + + void addUsingDirective(NamespaceDef *nd); + NamespaceSDict *getUsedNamespaces() const; + void addUsingDeclaration(Definition *def); + SDict<Definition> *getUsedClasses() const { return usingDeclList; } + void combineUsingRelations(); + + bool generateSourceFile() const; + void sortMemberLists(); + + void addIncludeDependency(FileDef *fd,const char *incName,bool local,bool imported,bool indirect); + void addIncludedByDependency(FileDef *fd,const char *incName,bool local,bool imported); + QList<IncludeInfo> *includeFileList() const { return includeList; } + QList<IncludeInfo> *includedByFileList() const { return includedByList; } + + void addMembersToMemberGroup(); + void distributeMemberGroupDocumentation(); + void findSectionsInDocumentation(); + void addIncludedUsingDirectives(); + + void addListReferences(); + bool isDocumentationFile() const; + //bool includes(FileDef *incFile,QDict<FileDef> *includedFiles) const; + //bool includesByName(const QCString &name) const; + + MemberList *getMemberList(MemberList::ListType lt) const; + const QList<MemberList> &getMemberLists() const { return m_memberLists; } + + /* user defined member groups */ + MemberGroupSDict *getMemberGroupSDict() const { return memberGroupSDict; } + NamespaceSDict *getNamespaceSDict() const { return namespaceSDict; } + ClassSDict *getClassSDict() const { return classSDict; } + + bool visited; + + protected: + /** + * Retrieves the file version from version control system. + */ + void acquireFileVersion(); + + private: + MemberList *createMemberList(MemberList::ListType lt); + void addMemberToList(MemberList::ListType lt,MemberDef *md); + void writeMemberDeclarations(OutputList &ol,MemberList::ListType lt,const QCString &title); + void writeMemberDocumentation(OutputList &ol,MemberList::ListType lt,const QCString &title); + void writeIncludeFiles(OutputList &ol); + void writeIncludeGraph(OutputList &ol); + void writeIncludedByGraph(OutputList &ol); + void writeMemberGroups(OutputList &ol); + void writeAuthorSection(OutputList &ol); + void writeSourceLink(OutputList &ol); + void writeNamespaceDeclarations(OutputList &ol,const QCString &title); + void writeClassDeclarations(OutputList &ol,const QCString &title); + void writeInlineClasses(OutputList &ol); + void startMemberDeclarations(OutputList &ol); + void endMemberDeclarations(OutputList &ol); + void startMemberDocumentation(OutputList &ol); + void endMemberDocumentation(OutputList &ol); + void writeDetailedDescription(OutputList &ol,const QCString &title); + void writeBriefDescription(OutputList &ol); + + QDict<IncludeInfo> *includeDict; + QList<IncludeInfo> *includeList; + QDict<IncludeInfo> *includedByDict; + QList<IncludeInfo> *includedByList; + NamespaceSDict *usingDirList; + SDict<Definition> *usingDeclList; + QCString path; + QCString filepath; + QCString diskname; + QCString filename; + QCString docname; + QIntDict<Definition> *srcDefDict; + QIntDict<MemberDef> *srcMemberDict; + bool isSource; + //bool m_isJava; + //bool m_isCSharp; + QCString fileVersion; + PackageDef *package; + DirDef *dir; + QList<MemberList> m_memberLists; + MemberGroupSDict *memberGroupSDict; + NamespaceSDict *namespaceSDict; + ClassSDict *classSDict; + bool m_subGrouping; +}; + + +class FileList : public QList<FileDef> +{ + public: + FileList() : m_pathName("tmp") {} + FileList(const char *path) : QList<FileDef>(), m_pathName(path) {} + ~FileList() {} + QCString path() const { return m_pathName; } + int compareItems(GCI item1,GCI item2) + { + FileDef *md1 = (FileDef *)item1; + FileDef *md2 = (FileDef *)item2; + return stricmp(md1->name(),md2->name()); + } + private: + QCString m_pathName; +}; + +class OutputNameList : public QList<FileList> +{ + public: + OutputNameList() : QList<FileList>() {} + ~OutputNameList() {} + int compareItems(GCI item1,GCI item2) + { + FileList *fl1 = (FileList *)item1; + FileList *fl2 = (FileList *)item2; + return stricmp(fl1->path(),fl2->path()); + } +}; + +class OutputNameDict : public QDict<FileList> +{ + public: + OutputNameDict(int size) : QDict<FileList>(size) {} + ~OutputNameDict() {} +}; + +class Directory; + +class DirEntry +{ + public: + enum EntryKind { Dir, File }; + DirEntry(DirEntry *parent,FileDef *fd) + : m_parent(parent), m_name(fd->name()), m_kind(File), m_fd(fd), + m_isLast(FALSE) { } + DirEntry(DirEntry *parent,QCString name) + : m_parent(parent), m_name(name), m_kind(Dir), + m_fd(0), m_isLast(FALSE) { } + virtual ~DirEntry() { } + EntryKind kind() const { return m_kind; } + FileDef *file() const { return m_fd; } + bool isLast() const { return m_isLast; } + void setLast(bool b) { m_isLast=b; } + DirEntry *parent() const { return m_parent; } + QCString name() const { return m_name; } + QCString path() const { return parent() ? parent()->path()+"/"+name() : name(); } + + protected: + DirEntry *m_parent; + QCString m_name; + + private: + EntryKind m_kind; + FileDef *m_fd; + int num; + bool m_isLast; +}; + +class Directory : public DirEntry +{ + public: + Directory(Directory *parent,const QCString &name) + : DirEntry(parent,name) + { m_children.setAutoDelete(TRUE); } + virtual ~Directory() {} + void addChild(DirEntry *d) { m_children.append(d); d->setLast(TRUE); } + QList<DirEntry> &children() { return m_children; } + void rename(const QCString &name) { m_name=name; } + void reParent(Directory *parent) { m_parent=parent; } + + private: + QList<DirEntry> m_children; +}; + +//void generateFileTree(QTextStream &t); +void generateFileTree(); + +#endif + diff --git a/trunk/src/filename.cpp b/trunk/src/filename.cpp new file mode 100644 index 0000000..dddeeca --- /dev/null +++ b/trunk/src/filename.cpp @@ -0,0 +1,144 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#include "filename.h" +#include "util.h" + +FileName::FileName(const char *fn,const char *n) : FileList() +{ + setAutoDelete(TRUE); + fName=fn; + name=n; +} + +FileName::~FileName() +{ +} + + +void FileName::generateDiskNames() +{ + //QCString commonPrefix; + FileDef *fd=first(); + int count=0; + while (fd) + { + if (!fd->isReference()) count++; + fd=next(); + } + if (count==1) + { + fd=first(); + // skip references + while (fd && fd->isReference()) fd=next(); + // name if unique, so diskname is simply the name + //printf("!!!!!!!! Unique disk name=%s for fd=%s\n",name.data(),fd->diskname.data()); + fd->diskname=name.copy(); + } + else if (count>1) // multiple occurrences of the same file name + { + //printf("Multiple occurrences of %s\n",name.data()); + int i=0,j=0; + bool found=FALSE; + while (!found) // search for the common prefix of all paths + { + fd=first(); + while (fd && fd->isReference()) fd=next(); + char c=fd->path.at(i); + if (c=='/') j=i; // remember last position of dirname + fd=next(); + while (fd && !found) + { + if (!fd->isReference()) + { + //printf("i=%d j=%d fd->path=`%s' fd->name=`%s'\n",i,j,fd->path.left(i).data(),fd->name().data()); + if (i==(int)fd->path.length()) + { + //warning("Warning: Input file %s found multiple times!\n" + // " The generated documentation for this file may not be correct!\n",fd->absFilePath().data()); + found=TRUE; + } + else if (fd->path[i]!=c) + { + found=TRUE; + } + } + fd=next(); + } + i++; + } + fd=first(); + while (fd) + { + //printf("fd->setName(%s)\n",(fd->path.right(fd->path.length()-j-1)+name).data()); + if (!fd->isReference()) + { + QCString prefix = fd->path.right(fd->path.length()-j-1); + fd->setName(prefix+name); + //printf("!!!!!!!! non unique disk name=%s for fd=%s\n",(prefix+name).data(),fd->diskname.data()); + fd->diskname=prefix+name; + } + fd=next(); + } + } +} + +int FileName::compareItems(GCI item1, GCI item2) +{ + FileName *f1=(FileName *)item1; + FileName *f2=(FileName *)item2; + return stricmp(f1->fileName(),f2->fileName()); +} + +FileNameIterator::FileNameIterator(const FileName &fname) : + QListIterator<FileDef>(fname) +{ +} + +FileNameList::FileNameList() : QList<FileName>() +{ +} + +FileNameList::~FileNameList() +{ +} + +void FileNameList::generateDiskNames() +{ + FileName *fn=first(); + while (fn) + { + fn->generateDiskNames(); + fn=next(); + } +} + +int FileNameList::compareItems(GCI item1, GCI item2) +{ + FileName *f1=(FileName *)item1; + FileName *f2=(FileName *)item2; + //printf("FileNameList::compareItems `%s'<->`%s'\n", + // f1->fileName(),f2->fileName()); + return Config_getBool("FULL_PATH_NAMES") ? + stricmp(f1->fullName(),f2->fullName()) : + stricmp(f1->fileName(),f2->fileName()); +} + +FileNameListIterator::FileNameListIterator(const FileNameList &fnlist) : + QListIterator<FileName>(fnlist) +{ +} diff --git a/trunk/src/filename.h b/trunk/src/filename.h new file mode 100644 index 0000000..29e90c0 --- /dev/null +++ b/trunk/src/filename.h @@ -0,0 +1,69 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#ifndef FILENAME_H +#define FILENAME_H + +#include "qtbc.h" +#include <qdict.h> +#include "filedef.h" + +class FileName : public FileList +{ + public: + FileName(const char *fn,const char *name); + ~FileName(); + const char *fileName() const { return name; } + const char *fullName() const { return fName; } + void generateDiskNames(); + int compareItems(GCI item1,GCI item2); + + private: + QCString name; + QCString fName; +}; + +class FileNameIterator : public QListIterator<FileDef> +{ + public: + FileNameIterator(const FileName &list); +}; + +class FileNameList : public QList<FileName> +{ + public: + FileNameList(); + ~FileNameList(); + void generateDiskNames(); + int compareItems(GCI item1,GCI item2); +}; + +class FileNameListIterator : public QListIterator<FileName> +{ + public: + FileNameListIterator( const FileNameList &list ); +}; + +class FileNameDict : public QDict<FileName> +{ + public: + FileNameDict(uint size) : + QDict<FileName>(size,Config_getBool("CASE_SENSE_NAMES")) {} + ~FileNameDict() {} +}; + +#endif diff --git a/trunk/src/filestorage.h b/trunk/src/filestorage.h new file mode 100644 index 0000000..ddffeda --- /dev/null +++ b/trunk/src/filestorage.h @@ -0,0 +1,135 @@ +/****************************************************************************** + * + * Copyright (C) 1997-2012 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. + * + */ + +#include <qfile.h> +#include <assert.h> +#include "store.h" + + +#ifndef FILESTORAGE_H +#define FILESTORAGE_H + +/** @brief Store implementation based on a file. + Writing is linear, after that the file is re-opened for reading. + Reading is random (seek+read). + */ +class FileStorage : public StorageIntf +{ + public: + FileStorage() : m_readOnly(FALSE) {} + FileStorage( const QString &name) : + m_readOnly(FALSE) { m_file.setName(name); } + int read(char *buf,uint size) { return m_file.readBlock(buf,size); } + int write(const char *buf,uint size) { assert(m_readOnly==FALSE); return m_file.writeBlock(buf,size); } + bool open( int m ) { m_readOnly = m==IO_ReadOnly; return m_file.open(m); } + bool seek(int64 pos) { return m_file.seek(pos); } + int64 pos() const { return m_file.pos(); } + void close() { m_file.close(); } + void setName( const char *name ) { m_file.setName(name); } + private: + bool m_readOnly; + QFile m_file; +}; + +#if 0 // experimental version using mmap after opening the file as read only. +#include <sys/mman.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <string.h> +#include <unistd.h> +#include <stdio.h> + +class FileStorage : public StorageIntf +{ + public: + FileStorage() : m_readOnly(FALSE), m_map(0), m_off(0), m_size(0) {} + FileStorage( const QString &name) : + m_readOnly(FALSE) { m_file.setName(name); } + void setName( const char *name ) { m_file.setName(name); } + bool open( int m ) + { + if (m==IO_ReadOnly) + { + m_readOnly=TRUE; + QString name = m_file.name(); + m_file.close(); + m_fd = ::open(name.data(),O_RDONLY); + struct stat stat; + fstat(m_fd,&stat); + m_size = stat.st_size; + m_map = mmap(NULL,m_size,PROT_READ,MAP_SHARED,m_fd,0); + if (m_map==MAP_FAILED) perror("mmap failed"); + assert(m_map!=MAP_FAILED); + m_off = 0; + return TRUE; + } + else + { + m_readOnly = FALSE; + return m_file.open(m); + } + } + int write(const char *buf,uint size) + { + assert(m_map==0); + return m_file.writeBlock(buf,size); + } + int read(char *buf,uint size) + { + assert(m_map!=0); + memcpy(buf,((char *)m_map)+m_off,size); + m_off+=size; + return size; + } + bool seek(int64 pos) + { + m_off=pos; + return TRUE; + } + int64 pos() const + { + if (m_readOnly) + { + return m_off; + } + else + { + return m_file.pos(); + } + } + void close() + { + if (m_readOnly) + { + munmap(m_map,m_size); + ::close(m_fd); + exit(1); + } + else + { + m_file.close(); + } + } + private: + bool m_readOnly; + QFile m_file; + int m_fd; + void *m_map; + off_t m_off; + off_t m_size; +}; +#endif + +#endif diff --git a/trunk/src/footer.html b/trunk/src/footer.html new file mode 100644 index 0000000..c93cb56 --- /dev/null +++ b/trunk/src/footer.html @@ -0,0 +1,16 @@ +<!--BEGIN GENERATE_TREEVIEW--> + <li class="footer">$generatedby + <a href="http://www.doxygen.org/index.html"> + <img class="footer" src="doxygen.png" alt="doxygen"/></a> $doxygenversion </li> + </ul> + </div> +<!--END GENERATE_TREEVIEW--> +<!--BEGIN !GENERATE_TREEVIEW--> +<hr class="footer"/><address class="footer"><small> +$generatedby  <a href="http://www.doxygen.org/index.html"> +<img class="footer" src="$relpath$doxygen.png" alt="doxygen"/> +</a> $doxygenversion +</small></address> +<!--END !GENERATE_TREEVIEW--> +</body> +</html> diff --git a/trunk/src/footer_html.h b/trunk/src/footer_html.h new file mode 100644 index 0000000..86a2e91 --- /dev/null +++ b/trunk/src/footer_html.h @@ -0,0 +1,16 @@ +"<!--BEGIN GENERATE_TREEVIEW-->\n" +" <li class=\"footer\">$generatedby\n" +" <a href=\"http://www.doxygen.org/index.html\">\n" +" <img class=\"footer\" src=\"doxygen.png\" alt=\"doxygen\"/></a> $doxygenversion </li>\n" +" </ul>\n" +" </div>\n" +"<!--END GENERATE_TREEVIEW-->\n" +"<!--BEGIN !GENERATE_TREEVIEW-->\n" +"<hr class=\"footer\"/><address class=\"footer\"><small>\n" +"$generatedby  <a href=\"http://www.doxygen.org/index.html\">\n" +"<img class=\"footer\" src=\"$relpath$doxygen.png\" alt=\"doxygen\"/>\n" +"</a> $doxygenversion\n" +"</small></address>\n" +"<!--END !GENERATE_TREEVIEW-->\n" +"</body>\n" +"</html>\n" diff --git a/trunk/src/formula.cpp b/trunk/src/formula.cpp new file mode 100644 index 0000000..adc1d42 --- /dev/null +++ b/trunk/src/formula.cpp @@ -0,0 +1,329 @@ +/****************************************************************************** + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#include <stdlib.h> +#include <unistd.h> + +#include "qtbc.h" +#include <qfile.h> +#include <qfileinfo.h> +#include <qtextstream.h> +#include <qdir.h> + +#include "formula.h" +#include "image.h" +#include "util.h" +#include "message.h" +#include "config.h" +#include "portable.h" +#include "index.h" +#include "doxygen.h" +#include "ftextstream.h" + +Formula::Formula(const char *text) +{ + static int count=0; + number = count++; + form=text; +} + +Formula::~Formula() +{ +} + +int Formula::getId() +{ + return number; +} + +void FormulaList::generateBitmaps(const char *path) +{ + int x1,y1,x2,y2; + QDir d(path); + // store the original directory + if (!d.exists()) { err("error: Output dir %s does not exist!\n",path); exit(1); } + QCString oldDir = convertToQCString(QDir::currentDirPath()); + // go to the html output directory (i.e. path) + QDir::setCurrent(d.absPath()); + QDir thisDir; + // generate a latex file containing one formula per page. + QCString texName="_formulas.tex"; + QList<int> pagesToGenerate; + pagesToGenerate.setAutoDelete(TRUE); + FormulaListIterator fli(*this); + Formula *formula; + QFile f(texName); + bool formulaError=FALSE; + if (f.open(IO_WriteOnly)) + { + FTextStream t(&f); + if (Config_getBool("LATEX_BATCHMODE")) t << "\\batchmode" << endl; + t << "\\documentclass{article}" << endl; + t << "\\usepackage{epsfig}" << endl; // for those who want to include images + const char *s=Config_getList("EXTRA_PACKAGES").first(); + while (s) + { + t << "\\usepackage{" << s << "}\n"; + s=Config_getList("EXTRA_PACKAGES").next(); + } + t << "\\pagestyle{empty}" << endl; + t << "\\begin{document}" << endl; + int page=0; + for (fli.toFirst();(formula=fli.current());++fli) + { + QCString resultName; + resultName.sprintf("form_%d.png",formula->getId()); + // only formulas for which no image exists are generated + QFileInfo fi(resultName); + if (!fi.exists()) + { + // we force a pagebreak after each formula + t << formula->getFormulaText() << endl << "\\pagebreak\n\n"; + pagesToGenerate.append(new int(page)); + } + Doxygen::indexList.addImageFile(resultName); + page++; + } + t << "\\end{document}" << endl; + f.close(); + } + if (pagesToGenerate.count()>0) // there are new formulas + { + //printf("Running latex...\n"); + //system("latex _formulas.tex </dev/null >/dev/null"); + QCString latexCmd = Config_getString("LATEX_CMD_NAME"); + if (latexCmd.isEmpty()) latexCmd="latex"; + portable_sysTimerStart(); + if (portable_system(latexCmd,"_formulas.tex")!=0) + { + err("Problems running latex. Check your installation or look " + "for typos in _formulas.tex and check _formulas.log!\n"); + formulaError=TRUE; + //return; + } + portable_sysTimerStop(); + //printf("Running dvips...\n"); + QListIterator<int> pli(pagesToGenerate); + int *pagePtr; + int pageIndex=1; + for (;(pagePtr=pli.current());++pli,++pageIndex) + { + int pageNum=*pagePtr; + msg("Generating image form_%d.png for formula\n",pageNum); + char dviArgs[4096]; + QCString formBase; + formBase.sprintf("_form%d",pageNum); + // run dvips to convert the page with number pageIndex to an + // encapsulated postscript. + sprintf(dviArgs,"-q -D 600 -E -n 1 -p %d -o %s.eps _formulas.dvi", + pageIndex,formBase.data()); + portable_sysTimerStart(); + if (portable_system("dvips",dviArgs)!=0) + { + err("Problems running dvips. Check your installation!\n"); + portable_sysTimerStop(); + return; + } + portable_sysTimerStop(); + // now we read the generated postscript file to extract the bounding box + QFileInfo fi(formBase+".eps"); + if (fi.exists()) + { + QCString eps = fileToString(formBase+".eps"); + int i=eps.find("%%BoundingBox:"); + if (i!=-1) + { + sscanf(eps.data()+i,"%%%%BoundingBox:%d %d %d %d",&x1,&y1,&x2,&y2); + } + else + { + err("error: Couldn't extract bounding box!\n"); + } + } + // next we generate a postscript file which contains the eps + // and displays it in the right colors and the right bounding box + f.setName(formBase+".ps"); + if (f.open(IO_WriteOnly)) + { + FTextStream t(&f); + t << "1 1 1 setrgbcolor" << endl; // anti-alias to white background + t << "newpath" << endl; + t << "-1 -1 moveto" << endl; + t << (x2-x1+2) << " -1 lineto" << endl; + t << (x2-x1+2) << " " << (y2-y1+2) << " lineto" << endl; + t << "-1 " << (y2-y1+2) << " lineto" <<endl; + t << "closepath" << endl; + t << "fill" << endl; + t << -x1 << " " << -y1 << " translate" << endl; + t << "0 0 0 setrgbcolor" << endl; + t << "(" << formBase << ".eps) run" << endl; + f.close(); + } + // scale the image so that it is four times larger than needed. + // and the sizes are a multiple of four. + double scaleFactor = 16.0/3.0; + int zoomFactor = Config_getInt("FORMULA_FONTSIZE"); + if (zoomFactor<8 || zoomFactor>50) zoomFactor=10; + scaleFactor *= zoomFactor/10.0; + int gx = (((int)((x2-x1)*scaleFactor))+3)&~1; + int gy = (((int)((y2-y1)*scaleFactor))+3)&~1; + // Then we run ghostscript to convert the postscript to a pixmap + // The pixmap is a truecolor image, where only black and white are + // used. + + char gsArgs[4096]; + sprintf(gsArgs,"-q -g%dx%d -r%dx%dx -sDEVICE=ppmraw " + "-sOutputFile=%s.pnm -dNOPAUSE -dBATCH -- %s.ps", + gx,gy,(int)(scaleFactor*72),(int)(scaleFactor*72), + formBase.data(),formBase.data() + ); + portable_sysTimerStart(); + if (portable_system(portable_ghostScriptCommand(),gsArgs)!=0) + { + err("Problem running ghostscript %s %s. Check your installation!\n",portable_ghostScriptCommand(),gsArgs); + portable_sysTimerStop(); + return; + } + portable_sysTimerStop(); + f.setName(formBase+".pnm"); + uint imageX=0,imageY=0; + // we read the generated image again, to obtain the pixel data. + if (f.open(IO_ReadOnly)) + { + QTextStream t(&f); + QCString s; + if (!t.eof()) + s=t.readLine(); + if (s.length()<2 || s.left(2)!="P6") + err("error: ghostscript produced an illegal image format!"); + else + { + // assume the size if after the first line that does not start with + // # excluding the first line of the file. + while (!t.eof() && (s=t.readLine()) && !s.isEmpty() && s.at(0)=='#') { } + sscanf(s,"%d %d",&imageX,&imageY); + } + if (imageX>0 && imageY>0) + { + //printf("Converting image...\n"); + char *data = new char[imageX*imageY*3]; // rgb 8:8:8 format + uint i,x,y,ix,iy; + f.readBlock(data,imageX*imageY*3); + Image srcImage(imageX,imageY), + filteredImage(imageX,imageY), + dstImage(imageX/4,imageY/4); + uchar *ps=srcImage.getData(); + // convert image to black (1) and white (0) index. + for (i=0;i<imageX*imageY;i++) *ps++= (data[i*3]==0 ? 1 : 0); + // apply a simple box filter to the image + static int filterMask[]={1,2,1,2,8,2,1,2,1}; + for (y=0;y<srcImage.getHeight();y++) + { + for (x=0;x<srcImage.getWidth();x++) + { + int s=0; + for (iy=0;iy<2;iy++) + { + for (ix=0;ix<2;ix++) + { + s+=srcImage.getPixel(x+ix-1,y+iy-1)*filterMask[iy*3+ix]; + } + } + filteredImage.setPixel(x,y,s); + } + } + // down-sample the image to 1/16th of the area using 16 gray scale + // colors. + // TODO: optimize this code. + for (y=0;y<dstImage.getHeight();y++) + { + for (x=0;x<dstImage.getWidth();x++) + { + int xp=x<<2; + int yp=y<<2; + int c=filteredImage.getPixel(xp+0,yp+0)+ + filteredImage.getPixel(xp+1,yp+0)+ + filteredImage.getPixel(xp+2,yp+0)+ + filteredImage.getPixel(xp+3,yp+0)+ + filteredImage.getPixel(xp+0,yp+1)+ + filteredImage.getPixel(xp+1,yp+1)+ + filteredImage.getPixel(xp+2,yp+1)+ + filteredImage.getPixel(xp+3,yp+1)+ + filteredImage.getPixel(xp+0,yp+2)+ + filteredImage.getPixel(xp+1,yp+2)+ + filteredImage.getPixel(xp+2,yp+2)+ + filteredImage.getPixel(xp+3,yp+2)+ + filteredImage.getPixel(xp+0,yp+3)+ + filteredImage.getPixel(xp+1,yp+3)+ + filteredImage.getPixel(xp+2,yp+3)+ + filteredImage.getPixel(xp+3,yp+3); + // here we scale and clip the color value so the + // resulting image has a reasonable contrast + dstImage.setPixel(x,y,QMIN(15,(c*15)/(16*10))); + } + } + // save the result as a bitmap + QCString resultName; + resultName.sprintf("form_%d.png",pageNum); + // the option parameter 1 is used here as a temporary hack + // to select the right color palette! + dstImage.save(resultName,1); + delete[] data; + } + f.close(); + } + // remove intermediate image files + thisDir.remove(formBase+".eps"); + thisDir.remove(formBase+".pnm"); + thisDir.remove(formBase+".ps"); + } + // remove intermediate files produced by latex + thisDir.remove("_formulas.dvi"); + if (!formulaError) thisDir.remove("_formulas.log"); // keep file in case of errors + thisDir.remove("_formulas.aux"); + } + // remove the latex file itself + if (!formulaError) thisDir.remove("_formulas.tex"); + // write/update the formula repository so we know what text the + // generated images represent (we use this next time to avoid regeneration + // of the images, and to avoid forcing the user to delete all images in order + // to let a browser refresh the images). + f.setName("formula.repository"); + if (f.open(IO_WriteOnly)) + { + FTextStream t(&f); + for (fli.toFirst();(formula=fli.current());++fli) + { + t << "\\form#" << formula->getId() << ":" << formula->getFormulaText() << endl; + } + f.close(); + } + // reset the directory to the original location. + QDir::setCurrent(oldDir); +} + + +#ifdef FORMULA_TEST +int main() +{ + FormulaList fl; + fl.append(new Formula("$x^2$")); + fl.append(new Formula("$y^2$")); + fl.append(new Formula("$\\sqrt{x_0^2+x_1^2+x_2^2}$")); + fl.generateBitmaps("dest"); + return 0; +} +#endif diff --git a/trunk/src/formula.h b/trunk/src/formula.h new file mode 100644 index 0000000..ca68e6e --- /dev/null +++ b/trunk/src/formula.h @@ -0,0 +1,59 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#ifndef FORMULA_H +#define FORMULA_H + +#include "qtbc.h" +#include <qlist.h> +#include <qdict.h> + +class Formula +{ + public: + Formula(const char *text); + ~Formula(); + int getId(); + QCString getFormulaText() const { return form; } + + private: + int number; + QCString form; +}; + +class FormulaList : public QList<Formula> +{ + public: + void generateBitmaps(const char *path); +}; + +class FormulaListIterator : public QListIterator<Formula> +{ + public: + FormulaListIterator(const FormulaList &l) : + QListIterator<Formula>(l) {} +}; + +class FormulaDict : public QDict<Formula> +{ + public: + FormulaDict(uint size) : + QDict<Formula>(size) {} + ~FormulaDict() {} +}; + +#endif diff --git a/trunk/src/fortrancode.h b/trunk/src/fortrancode.h new file mode 100644 index 0000000..887fe65 --- /dev/null +++ b/trunk/src/fortrancode.h @@ -0,0 +1,35 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#ifndef CODE_H +#define CODE_H + +#include "qtbc.h" +#include <stdio.h> + +class CodeOutputInterface; +class FileDef; +class MemberDef; + +void parseFortranCode(CodeOutputInterface &,const char *,const QCString &, + bool ,const char *,FileDef *fd=0, + int startLine=-1,int endLine=-1,bool inlineFragment=FALSE, + MemberDef *memberDef=0,bool showLineNumbers=TRUE); +void resetFortranCodeParserState(); +void codeFreeScanner(); + +#endif diff --git a/trunk/src/fortrancode.l b/trunk/src/fortrancode.l new file mode 100644 index 0000000..f4ee358 --- /dev/null +++ b/trunk/src/fortrancode.l @@ -0,0 +1,1073 @@ +/****************************************************************************** + * + * Parser for syntax hightlighting and references for Fortran90 F subset + * + * Copyright (C) by Anke Visser + * based on the work of 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. + * + */ + +/** + @todo - continutation lines not always recognized + - merging of use-statements with same module name and different only-names + - rename part of use-statement + - links to interface functions + - references to variables +**/ + +%{ + +/* + * includes + */ +#include "qtbc.h" +#include <stdio.h> +#include <assert.h> +#include <ctype.h> +#include <qregexp.h> +#include <qdir.h> +#include <qstringlist.h> +#include "entry.h" +#include "doxygen.h" +#include "message.h" +#include "outputlist.h" +#include "util.h" +#include "membername.h" +#include "searchindex.h" +#include "defargs.h" + +#define YY_NEVER_INTERACTIVE 1 +#define YY_NO_TOP_STATE 1 + +//-------------------------------------------------------------------------------- + +/** + data of an use-statement +*/ +class UseEntry +{ + public: + QCString module; // just for debug + QStringList onlyNames; /* entries of the ONLY-part */ +}; + +/** + module name -> list of ONLY/remote entries + (module name = name of the module, which can be accessed via use-directive) +*/ +class UseSDict : public SDict<UseEntry> +{ + public: + UseSDict() : SDict<UseEntry>(17) {} +}; + +/** + Contains names of used modules and names of local variables. +*/ +class Scope +{ + public: + QStringList useNames; //!< contains names of used modules + QDict<void> localVars; //!< contains names of local variables + + Scope() : localVars(7, FALSE /*caseSensitive*/) {} +}; + +/*===================================================================*/ +/* + * statics + */ + +static QCString docBlock; //!< contents of all lines of a documentation block +static QCString currentModule=0; //!< name of the current enclosing module +static UseSDict *useMembers= new UseSDict; //!< info about used modules +static UseEntry *useEntry = 0; //!< current use statement info +static QList<Scope> scopeStack; +// static QStringList *currentUseNames= new QStringList; //! contains names of used modules of current program unit +static QCString str=""; //!> contents of fortran string + +static CodeOutputInterface * g_code; + +// TODO: is this still needed? if so, make it work +static QCString g_parmType; +static QCString g_parmName; + +static const char * g_inputString; //!< the code fragment as text +static int g_inputPosition; //!< read offset during parsing +static int g_inputLines; //!< number of line in the code fragment +static int g_yyLineNr; //!< current line number +static bool g_needsTermination; +static bool g_isFixedForm; + +static bool g_insideBody; //!< inside subprog/program body? => create links +static const char * g_currentFontClass; + +static bool g_exampleBlock; +static QCString g_exampleName; +static QCString g_exampleFile; + +static FileDef * g_sourceFileDef; +static Definition * g_currentDefinition; +static MemberDef * g_currentMemberDef; +static bool g_includeCodeFragment; + +static char stringStartSymbol; // single or double quote +// count in variable declaration to filter out +// declared from referenced names +static int bracketCount = 0; + +// simplified way to know if this is fixed form +// duplicate in fortranscanner.l +static bool recognizeFixedForm(const char* contents) +{ + int column=0; + bool skipLine=FALSE; + + for (int i=0;;i++) + { + column++; + + switch(contents[i]) + { + case '\n': + column=0; + skipLine=FALSE; + break; + case ' ': + break; + case '\000': + return FALSE; + case 'C': + case 'c': + case '*': + if(column==1) return TRUE; + if(skipLine) break; + return FALSE; + case '!': + if(column>1 && column<7) return FALSE; + skipLine=TRUE; + break; + default: + if(skipLine) break; + if(column==7) return TRUE; + return FALSE; + } + } + return FALSE; +} + +static void endFontClass() +{ + if (g_currentFontClass) + { + g_code->endFontClass(); + g_currentFontClass=0; + } +} + +static void startFontClass(const char *s) +{ + endFontClass(); + g_code->startFontClass(s); + g_currentFontClass=s; +} + +static void setCurrentDoc(const QCString &name,const QCString &base,const QCString &anchor="") +{ + if (Doxygen::searchIndex) + { + Doxygen::searchIndex->setCurrentDoc(name,base,anchor); + } +} + +static void addToSearchIndex(const char *text) +{ + if (Doxygen::searchIndex) + { + Doxygen::searchIndex->addWord(text,FALSE); + } +} + +/*! start a new line of code, inserting a line number if g_sourceFileDef + * is TRUE. If a definition starts at the current line, then the line + * number is linked to the documentation of that definition. + */ +static void startCodeLine() +{ + if (g_sourceFileDef) + { + //QCString lineNumber,lineAnchor; + //lineNumber.sprintf("%05d",g_yyLineNr); + //lineAnchor.sprintf("l%05d",g_yyLineNr); + + Definition *d = g_sourceFileDef->getSourceDefinition(g_yyLineNr); + //printf("startCodeLine %d d=%s\n", g_yyLineNr,d ? d->name().data() : "<null>"); + if (!g_includeCodeFragment && d) + { + g_currentDefinition = d; + g_currentMemberDef = g_sourceFileDef->getSourceMember(g_yyLineNr); + g_insideBody = FALSE; + g_parmType.resize(0); + g_parmName.resize(0); + QCString lineAnchor; + lineAnchor.sprintf("l%05d",g_yyLineNr); + if (g_currentMemberDef) + { + g_code->writeLineNumber(g_currentMemberDef->getReference(), + g_currentMemberDef->getOutputFileBase(), + g_currentMemberDef->anchor(),g_yyLineNr); + setCurrentDoc( + g_currentMemberDef->qualifiedName(), + g_sourceFileDef->getSourceFileBase(), + lineAnchor); + } + else if (d->isLinkableInProject()) + { + g_code->writeLineNumber(d->getReference(), + d->getOutputFileBase(), + 0,g_yyLineNr); + setCurrentDoc( + d->qualifiedName(), + g_sourceFileDef->getSourceFileBase(), + lineAnchor); + } + } + else + { + g_code->writeLineNumber(0,0,0,g_yyLineNr); + } + } + g_code->startCodeLine(); + if (g_currentFontClass) + { + g_code->startFontClass(g_currentFontClass); + } +} + + +static void endFontClass(); +static void endCodeLine() +{ + endFontClass(); + g_code->endCodeLine(); +} + +/*! write a code fragment `text' that may span multiple lines, inserting + * line numbers for each line. + */ +static void codifyLines(char *text) +{ + //printf("codifyLines(%d,\"%s\")\n",g_yyLineNr,text); + char *p=text,*sp=p; + char c; + bool done=FALSE; + while (!done) + { + sp=p; + while ((c=*p++) && c!='\n') { } + if (c=='\n') + { + g_yyLineNr++; + *(p-1)='\0'; + g_code->codify(sp); + endCodeLine(); + if (g_yyLineNr<g_inputLines) + { + startCodeLine(); + } + } + else + { + g_code->codify(sp); + done=TRUE; + } + } +} + +static void codifyLines(QCString str) +{ + char *tmp= (char *) malloc(str.length()+1); + strcpy(tmp, str); + codifyLines(tmp); + free(tmp); +} + +/*! writes a link to a fragment \a text that may span multiple lines, inserting + * line numbers for each line. If \a text contains newlines, the link will be + * split into multiple links with the same destination, one for each line. + */ +static void writeMultiLineCodeLink(CodeOutputInterface &ol, + const char *ref,const char *file, + const char *anchor,const char *text) +{ + bool done=FALSE; + char *p=(char *)text; + while (!done) + { + char *sp=p; + char c; + while ((c=*p++) && c!='\n') { } + if (c=='\n') + { + g_yyLineNr++; + *(p-1)='\0'; + //printf("writeCodeLink(%s,%s,%s,%s)\n",ref,file,anchor,sp); + ol.writeCodeLink(ref,file,anchor,sp,0); + endCodeLine(); + if (g_yyLineNr<g_inputLines) + { + startCodeLine(); + } + } + else + { + //printf("writeCodeLink(%s,%s,%s,%s)\n",ref,file,anchor,sp); + ol.writeCodeLink(ref,file,anchor,sp,0); + done=TRUE; + } + } +} + +/** + generates dictionay entries that are used if REFERENCED_BY_RELATION ... options are set + (e.g. the "referenced by ..." list after the function documentation) +*/ + +static void addDocCrossReference(MemberDef *src, MemberDef *dst) +{ + if (dst->isTypedef() || dst->isEnumerate()) return; // don't add types + //printf("======= addDocCrossReference src=%s,dst=%s\n",src->name().data(),dst->name().data()); + if ((Config_getBool("REFERENCED_BY_RELATION") || Config_getBool("CALLER_GRAPH")) && + (src->isFunction())) + { + dst->addSourceReferencedBy(src); + } + if ((Config_getBool("REFERENCES_RELATION") || Config_getBool("CALL_GRAPH")) && (src->isFunction())) + { + src->addSourceReferences(dst); + } +} + +//------------------------------------------------------------------------------- +/** + searches for definition of a type + @param tname the name of the type + @param moduleName name of enclosing module or null, if global entry + @param cd the entry, if found or null + @param useDict dictionary of data of USE-statement + @returns true, if type is found +*/ +static bool getFortranTypeDefs(const QCString &tname, const QCString &moduleName, + ClassDef *&cd, UseSDict *usedict=0) +{ + if (tname.isEmpty()) return FALSE; /* empty name => nothing to link */ + + //cout << "=== search for type: " << tname << endl; + + // search for type + if ((cd=Doxygen::classSDict->find(tname))) + { + //cout << "=== type found in global module" << endl; + return TRUE; + } + else if (moduleName && (cd= Doxygen::classSDict->find(moduleName+"::"+tname))) + { + //cout << "=== type found in local module" << endl; + return TRUE; + } + else + { + UseEntry *use; + for (UseSDict::Iterator di(*usedict); (use=di.current()); ++di) + if ((cd= Doxygen::classSDict->find(use->module+"::"+tname))) + { + //cout << "=== type found in used module" << endl; + return TRUE; + } + } + + return FALSE; +} + +/** + searches for definition of function memberName + @param memberName the name of the function/variable + @param moduleName name of enclosing module or null, if global entry + @param md the entry, if found or null + @param usedict array of data of USE-statement + @returns true, if found +*/ +static bool getFortranDefs(const QCString &memberName, const QCString &moduleName, + MemberDef *&md, UseSDict *usedict=0) +{ + if (memberName.isEmpty()) return FALSE; /* empty name => nothing to link */ + + // look in local variables + for (Scope *scope=scopeStack.last(); scope!=NULL; scope=scopeStack.prev()) + { + if(scope->localVars.find(memberName)) + return FALSE; + } + + // search for function + MemberName *mn = Doxygen::functionNameSDict->find(memberName); + + if (mn) // name is known + { + MemberListIterator mli(*mn); + for (mli.toFirst();(md=mli.current());++mli) // all found functions with given name + { + FileDef *fd=md->getFileDef(); + GroupDef *gd=md->getGroupDef(); + + //cout << "found link with same name: " << fd->fileName() << " " << memberName; + //if (md->getNamespaceDef() != 0) cout << " in namespace " << md->getNamespaceDef()->name();cout << endl; + + if ((gd && gd->isLinkable()) || (fd && fd->isLinkable())) + { + NamespaceDef *nspace= md->getNamespaceDef(); + + if (nspace == 0) + { // found function in global scope + return TRUE; + } + else if (moduleName == nspace->name()) + { // found in local scope + return TRUE; + } + else + { // else search in used modules + QCString moduleName= nspace->name(); + UseEntry *ue= usedict->find(moduleName); + if (ue) + { + // check if only-list exists and if current entry exists is this list + QStringList &only= ue->onlyNames; + if (only.isEmpty()) + { + //cout << " found in module " << moduleName << " entry " << memberName << endl; + return TRUE; // whole module used + } + else + { + for ( QStringList::Iterator it = only.begin(); it != only.end(); ++it) + { + //cout << " search in only: " << moduleName << ":: " << memberName << "==" << (*it)<< endl; + if (memberName == (QCString)(*it)) + return TRUE; // found in ONLY-part of use list + } + } + } + } + } // if linkable + } // for + } + return FALSE; +} + +/** + gets the link to a generic procedure which depends not on the name, but on the parameter list + @todo implementation +*/ +static bool getGenericProcedureLink(const ClassDef *cd, + const char *memberText, + CodeOutputInterface &ol) +{ + (void)cd; + (void)memberText; + (void)ol; + return FALSE; +} + +static bool getLink(UseSDict *usedict, // dictonary with used modules + const char *memberText, // exact member text + CodeOutputInterface &ol, + const char *text) +{ + MemberDef *md; + QCString memberName= removeRedundantWhiteSpace(memberText); + + if (getFortranDefs(memberName, currentModule, md, usedict) && md->isLinkable()) + { + //if (md->isVariable()) return FALSE; // variables aren't handled yet + + Definition *d = md->getOuterScope()==Doxygen::globalScope ? + md->getBodyDef() : md->getOuterScope(); + if (md->getGroupDef()) d = md->getGroupDef(); + if (d && d->isLinkable()) + { + if (g_currentDefinition && g_currentMemberDef && md!=g_currentMemberDef && g_insideBody) + { + addDocCrossReference(g_currentMemberDef,md); + } + ol.linkableSymbol(g_yyLineNr,md->name(),md, + g_currentMemberDef ? g_currentMemberDef : g_currentDefinition); + writeMultiLineCodeLink(ol,md->getReference(), + md->getOutputFileBase(), + md->anchor(), + text ? text : memberText); + addToSearchIndex(text ? text : memberText); + return TRUE; + } + } + return FALSE; +} + + +static void generateLink(CodeOutputInterface &ol, char *lname) +{ + ClassDef *cd=0; + + // check if lname is a linkable type or interface + if ( (getFortranTypeDefs(lname, currentModule, cd, useMembers)) && cd->isLinkable() ) + { + if ( (cd->compoundType() == ClassDef::Class) && // was Entry::INTERFACE_SEC) && + (getGenericProcedureLink(cd, lname, ol)) ) + { + //cout << "=== generic procedure resolved" << endl; + } + else + { // write type or interface link + ol.linkableSymbol(g_yyLineNr, lname, cd, g_currentMemberDef?g_currentMemberDef:g_currentDefinition); + writeMultiLineCodeLink(ol,cd->getReference(),cd->getOutputFileBase(),cd->anchor(),lname); + addToSearchIndex(lname); + } + } + // check for function/variable + else if (getLink(useMembers, lname, ol, lname)) + { + //cout << "=== found link for " << lname << endl; + } + else + { + // nothing found, just write out the word + ol.linkableSymbol(g_yyLineNr, lname, 0, g_currentMemberDef?g_currentMemberDef:g_currentDefinition); + //startFontClass("charliteral"); //test + codifyLines(lname); + //endFontClass(); //test + addToSearchIndex(lname); + } +} + +/*! counts the number of lines in the input */ +static int countLines() +{ + const char *p=g_inputString; + char c; + int count=1; + while ((c=*p)) + { + p++ ; + if (c=='\n') count++; + } + if (p>g_inputString && *(p-1)!='\n') + { // last line does not end with a \n, so we add an extra + // line and explicitly terminate the line after parsing. + count++, + g_needsTermination=TRUE; + } + return count; +} + +//---------------------------------------------------------------------------- +/** start scope */ +void startScope() +{ + // fprintf(stderr, "===> startScope %s",yytext); + Scope *scope = new Scope; + scopeStack.append(scope); +} + +/** end scope */ +void endScope() +{ + // fprintf(stderr,"===> endScope %s",yytext); + if (scopeStack.isEmpty()) + { + //fprintf(stderr,"WARNING: fortrancode.l: stack empty!\n"); + return; + } + + Scope *scope = scopeStack.getLast(); + scopeStack.removeLast(); + for ( QStringList::Iterator it = scope->useNames.begin(); it != scope->useNames.end(); ++it) + { + useMembers->remove(*it); + } + delete scope; +} + +void addUse(QString moduleName) +{ + if (!scopeStack.isEmpty()) + scopeStack.last()->useNames.append(moduleName); +} + +void addLocalVar(QString varName) +{ + if (!scopeStack.isEmpty()) + scopeStack.last()->localVars.insert(varName, (void*)1); +} + +//---------------------------------------------------------------------------- + +/* -----------------------------------------------------------------*/ +#undef YY_INPUT +#define YY_INPUT(buf,result,max_size) result=yyread(buf,max_size); + +static int yyread(char *buf,int max_size) +{ + int c=0; + while( c < max_size && g_inputString[g_inputPosition] ) + { + *buf = g_inputString[g_inputPosition++] ; + c++; buf++; + } + return c; +} + +%} + +IDSYM [a-z_A-Z0-9] +ID [a-z_A-Z]+{IDSYM}* +SUBPROG (subroutine|function) +B [ \t] +BS [ \t]* +BS_ [ \t]+ +COMMA {BS},{BS} +ARGS_L0 ("("[^)]*")") +ARGS_L1a [^()]*"("[^)]*")"[^)]* +ARGS_L1 ("("{ARGS_L1a}*")") +ARGS_L2 "("({ARGS_L0}|[^()]|{ARGS_L1a}|{ARGS_L1})*")" +ARGS {BS}({ARGS_L0}|{ARGS_L1}|{ARGS_L2}) + +NUM_TYPE (complex|integer|logical|real) +LOG_OPER (\.and\.|\.eq\.|\.eqv\.|\.ge\.|\.gt\.|\.le\.|\.lt\.|\.ne\.|\.neqv\.|\.or\.|\.not\.) +KIND {ARGS} +CHAR (CHARACTER{ARGS}?|CHARACTER{BS}"*"({BS}[0-9]+|{ARGS})) +TYPE_SPEC (({NUM_TYPE}({BS}"*"{BS}[0-9]+)?)|({NUM_TYPE}{KIND})|DOUBLE{BS_}COMPLEX|DOUBLE{BS_}PRECISION|{CHAR}|TYPE{ARGS}) + +INTENT_SPEC intent{BS}"("{BS}(in|out|in{BS}out){BS}")" +ATTR_SPEC (ALLOCATABLE|DIMENSION{ARGS}|EXTERNAL|{INTENT_SPEC}|INTRINSIC|OPTIONAL|PARAMETER|POINTER|PRIVATE|PUBLIC|SAVE|TARGET|RECURSIVE|PURE|ELEMENTAL) +ACCESS_SPEC (PRIVATE|PUBLIC) +/* Assume that attribute statements are almost the same as attributes. */ +ATTR_STMT {ATTR_SPEC}|DIMENSION +COMMANDS (DO|SELECT|CASE|WHERE|IF|THEN|ELSE|MODULE{BS_}PROCEDURE|CONTAINS|IMPLICIT{BS}NONE|CONTAINS|WRITE|READ|ALLOCATE|ALLOCATED|ASSOCIATED|DEALLOCATE|SIZE|END{BS}IF|END{BS}DO|WHILE|INQUIRE|OPEN|CLOSE|DATA) +IGNORE (CALL) + +/* | */ + +%option noyywrap +%option stack +%option caseless +/*%option debug*/ + +%x Start +%x SubCall +%x FuncDef +%x ClassName +%x ClassVar +%x Subprog +%x DocBlock +%x Use +%x UseOnly +%x TypeDecl +%x Declaration +%x DeclContLine +%x Parameterlist +%x String + +%% + /*==================================================================*/ + + /*-------- ignore ------------------------------------------------------------*/ + +<Start>{IGNORE}/{BS}"("? { // do not search keywords, intrinsics... TODO: complete list + codifyLines(yytext); + } + /*-------- inner construct ---------------------------------------------------*/ + +<Start>{COMMANDS}/[,( \t\n].* { // hightlight rest of fortran statements + /* font class is defined e.g. in doxygen.css */ + startFontClass("keyword"); + codifyLines(yytext); + endFontClass(); + } +<Start>"end"({BS_}{COMMANDS})?/[ \t\n] { + startFontClass("keyword"); + codifyLines(yytext); + endFontClass(); + } + + /*-------- use statement -------------------------------------------*/ +<Start>"use"{BS_} { + codifyLines(yytext); + yy_push_state(YY_START); + BEGIN(Use); + } +<Use>{ID} { + startFontClass("keywordflow"); + codifyLines(yytext); + endFontClass(); + + /* append module name to use dict */ + useEntry = new UseEntry(); + useEntry->module = yytext; + useMembers->append(yytext, useEntry); + addUse(yytext); + } +<Use>,{BS}"ONLY" { // TODO: rename + codifyLines(yytext); + yy_push_state(YY_START); + BEGIN(UseOnly); + } +<UseOnly>{BS},{BS} { codifyLines(yytext); } +<UseOnly>{ID} { + codifyLines(yytext); + useEntry->onlyNames.append(yytext); + } +<Use,UseOnly>"\n" { + unput(*yytext); + yy_pop_state(); + } + + /*-------- fortran module -----------------------------------------*/ +<Start>("block"{BS}"data"|"program"|"module"|"type"|"interface")/{BS_}|({COMMA}{ACCESS_SPEC})|\n { // + startScope(); + startFontClass("keyword"); + codifyLines(yytext); + endFontClass(); + yy_push_state(YY_START); + BEGIN(ClassName); + if (!stricmp(yytext,"module")) currentModule="module"; + } +<ClassName>{ID} { + if (currentModule == "module") currentModule=yytext; + generateLink(*g_code,yytext); + yy_pop_state(); + } +<ClassName>\n { // interface may be without name + yy_pop_state(); + REJECT; + } +<Start>"end"({BS_}"module").* { // just reset currentModule, rest is done in following rule + currentModule=0; + REJECT; + } +<Start>^{BS}"end"({BS}("program"|"module"|"type"|"interface")({BS_}{ID})?)?{BS}/(\n|!) { // + endScope(); + startFontClass("keyword"); + codifyLines(yytext); + endFontClass(); + } + + /*-------- subprog definition -------------------------------------*/ +<Start>{TYPE_SPEC}{BS}/{SUBPROG}{BS_} { // TYPE_SPEC is for old function style function result + startFontClass("keyword"); + codifyLines(yytext); + endFontClass(); + } +<Start>{SUBPROG}{BS_} { // Fortran subroutine or function found + startFontClass("keyword"); + codifyLines(yytext); + endFontClass(); + yy_push_state(YY_START); + BEGIN(Subprog); + } +<Subprog>{ID} { // subroutine/function name + // fprintf(stderr, "===> start subprogram %s\n", yytext); + startScope(); + generateLink(*g_code,yytext); + } +<Subprog>"(".* { // ignore rest of line + codifyLines(yytext); + } +<Subprog>"\n" { codifyLines(yytext); + yy_pop_state(); + } +<Start>^{BS}"end"({BS}{SUBPROG}({BS_}{ID})?)?{BS}/(\n|!) { // Fortran subroutine or function ends + //cout << "===> end function " << yytext << endl; + endScope(); + startFontClass("keyword"); + codifyLines(yytext); + endFontClass(); + } + /*-------- variable declaration ----------------------------------*/ +<Start>"TYPE"{BS}"(" { + yy_push_state(YY_START); + BEGIN(TypeDecl); + startFontClass("keywordtype"); + g_code->codify(yytext); + endFontClass(); + } +<TypeDecl>{ID} { // link type + g_insideBody=TRUE; + generateLink(*g_code,yytext); + g_insideBody=FALSE; + } +<TypeDecl>")" { + BEGIN(Declaration); + startFontClass("keywordtype"); + g_code->codify(yytext); + endFontClass(); + } +<Start>{TYPE_SPEC}/[,:( ] { + yy_push_state(YY_START); + BEGIN(Declaration); + startFontClass("keywordtype"); + g_code->codify(yytext); + endFontClass(); + } +<Start>{ATTR_SPEC} { + startFontClass("keywordtype"); + g_code->codify(yytext); + endFontClass(); + } +<Declaration>({TYPE_SPEC}|{ATTR_SPEC})/[,:( ] { //| variable deklaration + startFontClass("keywordtype"); + g_code->codify(yytext); + endFontClass(); + } +<Declaration>{ID} { // local var + g_code->codify(yytext); + if (g_currentMemberDef && g_currentMemberDef->isFunction()) + addLocalVar(yytext); + } +<Declaration>[(] { // start of array specification + bracketCount++; + g_code->codify(yytext); + } + +<Declaration>[)] { // end array specification + bracketCount--; + g_code->codify(yytext); + } + +<Declaration>"&" { // continuation line + yy_push_state(YY_START); + BEGIN(DeclContLine); + } +<DeclContLine>"\n" { // declaration not yet finished + codifyLines(yytext); + bracketCount = 0; + yy_pop_state(); + } +<Declaration>"\n" { // end declaration line + codifyLines(yytext); + bracketCount = 0; + yy_pop_state(); + } + + /*-------- subprog calls -----------------------------------------*/ + +<Start>"call"{BS_} { + codifyLines(yytext); + yy_push_state(YY_START); + BEGIN(SubCall); + } +<SubCall>{ID} { // subroutine call + g_insideBody=TRUE; + generateLink(*g_code, yytext); + g_insideBody=FALSE; + yy_pop_state(); + } +<Start>{ID}{BS}/"(" { // function call + g_insideBody=TRUE; + generateLink(*g_code, yytext); + g_insideBody=FALSE; + } + + /*-------- comments ---------------------------------------------------*/ +<Start>\n?{BS}"!>" { // start comment line or comment block + yy_push_state(YY_START); + BEGIN(DocBlock); + docBlock=yytext; + } + +<DocBlock>.* { // contents of current comment line + docBlock+=yytext; + } +<DocBlock>"\n"{BS}("!>"|"!"+) { //| comment block (next line is also comment line) + docBlock+=yytext; + } +<DocBlock>"\n" { // comment block ends at the end of this line + docBlock+=yytext; + // remove special comment (default config) + if (Config_getBool("STRIP_CODE_COMMENTS")) + { + g_yyLineNr+=((QCString)docBlock).contains('\n'); + endCodeLine(); + if (g_yyLineNr<g_inputLines) + { + startCodeLine(); + } + } + else // do not remove comment + { + startFontClass("comment"); + codifyLines(docBlock); + endFontClass(); + } + yy_pop_state(); + } + +<*>"!"[^>\n].*|"!"$ { // normal comment + if(YY_START == String) REJECT; // ignore in strings + startFontClass("comment"); + codifyLines(yytext); + endFontClass(); + } + +<*>^[Cc*].* { // normal comment + if(! g_isFixedForm) REJECT; + + startFontClass("comment"); + codifyLines(yytext); + endFontClass(); + } + + /*------ preprocessor --------------------------------------------*/ +<Start>"#".*\n { startFontClass("preprocessor"); + codifyLines(yytext); + endFontClass(); + } + /*------ variable references? -------------------------------------*/ + +<Start>"%"{BS}{ID} { // ignore references to elements + g_code->codify(yytext); + } +<Start>{ID} { + g_insideBody=TRUE; + generateLink(*g_code, yytext); + g_insideBody=FALSE; + } + /*------ strings --------------------------------------------------*/ +<*>"\\\\" { str+=yytext; /* ignore \\ */} +<*>"\\\""|\\\' { str+=yytext; /* ignore \" */} + +<String>\"|\' { // string ends with next quote without previous backspace + if(yytext[0]!=stringStartSymbol) REJECT; // single vs double quote + str+=yytext; + startFontClass("stringliteral"); + codifyLines(str); + endFontClass(); + yy_pop_state(); + } +<String>. {str+=yytext;} + +<*>\"|\' { /* string starts */ + /* if(YY_START == StrIgnore) REJECT; // ignore in simple comments */ + yy_push_state(YY_START); + stringStartSymbol=yytext[0]; // single or double quote + BEGIN(String); + str=yytext; + } + /*-----------------------------------------------------------------------------*/ + +<*>\n { + codifyLines(yytext); + } +<*>. { + g_code->codify(yytext); + } +<*>{LOG_OPER} { // Fortran logical comparison keywords + g_code->codify(yytext); + } +%% + +/*@ ---------------------------------------------------------------------------- + */ + +/*===================================================================*/ + + +void resetFortranCodeParserState() {} + +void parseFortranCode(CodeOutputInterface &od,const char *className,const QCString &s, + bool exBlock, const char *exName,FileDef *fd, + int startLine,int endLine,bool inlineFragment, + MemberDef *memberDef,bool) +{ + //printf("***parseCode() exBlock=%d exName=%s fd=%p\n",exBlock,exName,fd); + + // used parameters + (void)memberDef; + (void)className; + + if (s.isEmpty()) return; + g_code = &od; + g_inputString = s; + g_inputPosition = 0; + g_isFixedForm = recognizeFixedForm((const char*)s); + g_currentFontClass = 0; + g_needsTermination = FALSE; + if (endLine!=-1) + g_inputLines = endLine+1; + else + g_inputLines = countLines(); + + if (startLine!=-1) + g_yyLineNr = startLine; + else + g_yyLineNr = 1; + + g_exampleBlock = exBlock; + g_exampleName = exName; + g_sourceFileDef = fd; + if (exBlock && fd==0) + { + // create a dummy filedef for the example + g_sourceFileDef = new FileDef("",exName); + } + if (g_sourceFileDef) + { + setCurrentDoc(g_sourceFileDef->name(),g_sourceFileDef->getSourceFileBase()); + } + g_currentDefinition = 0; + g_currentMemberDef = 0; + if (!g_exampleName.isEmpty()) + { + g_exampleFile = convertNameToFile(g_exampleName+"-example"); + } + g_includeCodeFragment = inlineFragment; + startCodeLine(); + g_parmName.resize(0); + g_parmType.resize(0); + fcodeYYrestart( fcodeYYin ); + BEGIN( Start ); + fcodeYYlex(); + if (g_needsTermination) + { + endFontClass(); + g_code->endCodeLine(); + } + if (exBlock && g_sourceFileDef) + { + // delete the temporary file definition used for this example + delete g_sourceFileDef; + g_sourceFileDef=0; + } + return; +} + +#if !defined(YY_FLEX_SUBMINOR_VERSION) +extern "C" { // some bogus code to keep the compiler happy + void fcodeYYdummy() { yy_flex_realloc(0,0); } +} +#elif YY_FLEX_SUBMINOR_VERSION<33 +#error "You seem to be using a version of flex newer than 2.5.4 but older than 2.5.33. These versions do NOT work with doxygen! Please use version <=2.5.4 or >=2.5.33 or expect things to be parsed wrongly!" +#else +extern "C" { // some bogus code to keep the compiler happy + void fcodeYYdummy() { yy_top_state(); } +} +#endif + diff --git a/trunk/src/fortranscanner.h b/trunk/src/fortranscanner.h new file mode 100644 index 0000000..392a75d --- /dev/null +++ b/trunk/src/fortranscanner.h @@ -0,0 +1,51 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#ifndef SCANNER_FORTRAN_H +#define SCANNER_FORTRAN_H + +#include "parserintf.h" + +/** \brief Fortran language parser using state-based lexical scanning. + * + * This is the Fortran language parser for doxygen. + */ +class FortranLanguageScanner : public ParserInterface +{ + public: + virtual ~FortranLanguageScanner() {} + void parseInput(const char *fileName, + const char *fileBuf, + Entry *root); + bool needsPreprocessing(const QCString &extension); + void parseCode(CodeOutputInterface &codeOutIntf, + const char *scopeName, + const QCString &input, + bool isExampleBlock, + const char *exampleName=0, + FileDef *fileDef=0, + int startLine=-1, + int endLine=-1, + bool inlineFragment=FALSE, + MemberDef *memberDef=0, + bool showLineNumbers=TRUE + ); + void resetCodeParserState(); + void parsePrototype(const char *text); +}; + +#endif diff --git a/trunk/src/fortranscanner.l b/trunk/src/fortranscanner.l new file mode 100644 index 0000000..0a11483 --- /dev/null +++ b/trunk/src/fortranscanner.l @@ -0,0 +1,2252 @@ +/* -*- mode: fundamental; indent-tabs-mode: 1; -*- */ +/***************************************************************************** + * Parser for Fortran90 F subset + * + * Copyright (C) by Anke Visser + * based on the work of 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. + * + */ + +/* Developer notes. + * + * - Consider using startScope(), endScope() functions with module, program, + * subroutine or any other scope in fortran program. + * + * - Symbol modifiers (attributes) are collected using SymbolModifiers |= operator during + * substructure parsing. When substructure ends all modifiers are applied to actual + * entries in applyModifiers() functions. + * + * - How case insensitiveness should be handled in code? + * On one side we have arg->name and entry->name, on another side modifierMap[name]. + * In entries and arguments case is the same as in code, in modifier map case is lowered and + * then it is compared to lowered entry/argument names. + * + * - Do not like constructs like aa{BS} or {BS}bb. Should try to handle blank space + * with separate rule?: It seems it is often necessary, because we may parse something like + * "functionA" or "MyInterface". So constructs like `(^|[ \t])interface({BS_}{ID})?/[ \t\n]' + * are desired. + * + * - Must track yyLineNr when using REJECT, unput() or similar commands. + */ + +%{ + +#include <stdio.h> +#include <stdlib.h> +#include <assert.h> +#include <ctype.h> + +#include "qtbc.h" +#include <qarray.h> +#include <qstack.h> +#include <qregexp.h> +#include <unistd.h> +#include <qfile.h> +#include <qmap.h> + +#include "fortranscanner.h" +#include "entry.h" +#include "message.h" +#include "config.h" +#include "doxygen.h" +#include "util.h" +#include "defargs.h" +#include "language.h" +#include "commentscan.h" +#include "fortrancode.h" +#include "pre.h" +#include "arguments.h" + +#define YY_NEVER_INTERACTIVE 1 + +class Arguments; + +enum ScanVar { V_IGNORE, V_VARIABLE, V_PARAMETER}; +enum InterfaceType { IF_NONE, IF_SPECIFIC, IF_GENERIC, IF_ABSTRACT }; + +// {{{ ----- Helper structs ----- +//! Holds modifiers (ie attributes) for one symbol (variable, function, etc) +struct SymbolModifiers { + enum Protection {NONE_P, PUBLIC, PRIVATE}; + enum Direction {NONE_D, IN, OUT, INOUT}; + + //!< This is only used with function return value. + QCString type, returnName; + Protection protection; + Direction direction; + bool optional; + QCString dimension; + bool allocatable; + bool external; + bool intrinsic; + bool parameter; + bool pointer; + bool target; + bool save; + bool deferred; + bool nonoverridable; + bool nopass; + bool pass; + QCString passVar; + + SymbolModifiers() : type(), returnName(), protection(NONE_P), direction(NONE_D), + optional(FALSE), dimension(), allocatable(FALSE), + external(FALSE), intrinsic(FALSE), parameter(FALSE), + pointer(FALSE), target(FALSE), save(FALSE), deferred(FALSE), nonoverridable(FALSE), + nopass(FALSE), pass(FALSE), passVar() {} + + SymbolModifiers& operator|=(const SymbolModifiers &mdfs); + SymbolModifiers& operator|=(QCString mdfrString); +}; + +//ostream& operator<<(ostream& out, const SymbolModifiers& mdfs); + +static const char *directionStrs[] = +{ + "", "intent(in)", "intent(out)", "intent(inout)" +}; +static const char *directionParam[] = +{ + "", "[in]", "[out]", "[in,out]" +}; + +// }}} + +/* ----------------------------------------------------------------- + * + * statics + */ +static ParserInterface *g_thisParser; +static const char * inputString; +static int inputPosition; +static bool isFixedForm; +static QCString inputStringPrepass; ///< Input string for prepass of line cont. '&' +static QCString inputStringSemi; ///< Input string after command separetor ';' +static unsigned int inputPositionPrepass; +static int lineCountPrepass = 0; + +static QList<Entry> subrCurrent; + +struct CommentInPrepass { + int column; + QCString str; + CommentInPrepass(int column, QCString str) : column(column), str(str) {} +}; +static QList<CommentInPrepass> comments; + +#define MAX_INCLUDE_DEPTH 10 +YY_BUFFER_STATE include_stack[MAX_INCLUDE_DEPTH]; +int include_stack_ptr = 0; + +static QFile inputFile; +static QCString yyFileName; +static int yyLineNr = 1 ; +static int yyColNr = 0 ; +static Entry* current_root = 0 ; +static Entry* global_root = 0 ; +static Entry* file_root = 0 ; +static Entry* current = 0 ; +static Entry* last_entry = 0 ; +static ScanVar v_type = V_IGNORE; // type of parsed variable +static QList<Entry> moduleProcedures; // list of all interfaces which contain unresolved + // module procedures +static QCString docBlock; +static QCString docBlockName; +static bool docBlockInBody; +static bool docBlockJavaStyle; + +static MethodTypes mtype; +static bool gstat; +static Specifier virt; + +static QCString debugStr; +static QCString result; // function result +static Argument *parameter; // element of parameter list +static QCString argType; // fortran type of an argument of a parameter list +static QCString argName; // last identifier name in variable list +static QCString initializer; // initial value of a variable +static int initializerArrayScope; // number if nested array scopes in initializer +static int initializerScope; // number if nested function calls in initializer +static QCString useModuleName; // name of module in the use statement +static Protection defaultProtection; +static Protection typeProtection; +static int typeMode = false; +static InterfaceType ifType = IF_NONE; +static bool functionLine = FALSE; + +static char stringStartSymbol; // single or double quote + +//! Accumulated modifiers of current statement, eg variable declaration. +static SymbolModifiers currentModifiers; +//! Holds program scope->symbol name->symbol modifiers. +static QMap<Entry*,QMap<QCString,SymbolModifiers> > modifiers; + +//----------------------------------------------------------------------------- + +static int yyread(char *buf,int max_size); +static void startCommentBlock(bool); +static void handleCommentBlock(const QCString &doc,bool brief); +static void subrHandleCommentBlock(const QCString &doc,bool brief); +static void addCurrentEntry(); +static void addModule(const char *name, bool isModule=FALSE); +static void addSubprogram(const char *text); +static void addInterface(QCString name, InterfaceType type); +static Argument *getParameter(const QCString &name); +static void scanner_abort(); + +static void startScope(Entry *scope); +static bool endScope(Entry *scope, bool isGlobalRoot=FALSE); +static QCString getFullName(Entry *e); +//static bool isTypeName(QCString name); +static void resolveModuleProcedures(QList<Entry> &moduleProcedures, Entry *current_root); +static int getAmpersandAtTheStart(const char *buf, int length); +static int getAmpOrExclAtTheEnd(const char *buf, int length); +static void truncatePrepass(int index); +static void pushBuffer(QCString &buffer); +static void popBuffer(); +//static void extractPrefix(QCString& text); +static QCString extractFromParens(const QCString name); +static CommentInPrepass* locatePrepassComment(int from, int to); +static void updateVariablePrepassComment(int from, int to); +static void newLine(); + +//----------------------------------------------------------------------------- +#undef YY_INPUT +#define YY_INPUT(buf,result,max_size) result=yyread(buf,max_size); +#define YY_USER_ACTION yyColNr+=yyleng; +//----------------------------------------------------------------------------- + +%} + + //----------------------------------------------------------------------------- + //----------------------------------------------------------------------------- +IDSYM [a-z_A-Z0-9] +NOTIDSYM [^a-z_A-Z0-9] +SEPARATE [:, \t] +ID [a-z_A-Z%]+{IDSYM}* +ID_ [a-z_A-Z%]*{IDSYM}* +PP_ID {ID} +LABELID [a-z_A-Z]+[a-z_A-Z0-9\-]* +SUBPROG (subroutine|function) +B [ \t] +BS [ \t]* +BS_ [ \t]+ +COMMA {BS},{BS} +ARGS_L0 ("("[^)]*")") +ARGS_L1a [^()]*"("[^)]*")"[^)]* +ARGS_L1 ("("{ARGS_L1a}*")") +ARGS_L2 "("({ARGS_L0}|[^()]|{ARGS_L1a}|{ARGS_L1})*")" +ARGS {BS}({ARGS_L0}|{ARGS_L1}|{ARGS_L2}) +NOARGS {BS}"\n" + +NUM_TYPE (complex|integer|logical|real) +LOG_OPER (\.and\.|\.eq\.|\.eqv\.|\.ge\.|\.gt\.|\.le\.|\.lt\.|\.ne\.|\.neqv\.|\.or\.|\.not\.) +KIND {ARGS} +CHAR (CHARACTER{ARGS}?|CHARACTER{BS}"*"({BS}[0-9]+|{ARGS})) +TYPE_SPEC (({NUM_TYPE}({BS}"*"{BS}[0-9]+)?)|({NUM_TYPE}{KIND})|DOUBLE{BS_}COMPLEX|DOUBLE{BS_}PRECISION|{CHAR}|TYPE{ARGS}|CLASS{ARGS}|PROCEDURE{ARGS}?) + +INTENT_SPEC intent{BS}"("{BS}(in|out|in{BS}out){BS}")" +ATTR_SPEC (ALLOCATABLE|DIMENSION{ARGS}|EXTERNAL|{INTENT_SPEC}|INTRINSIC|OPTIONAL|PARAMETER|POINTER|PRIVATE|PUBLIC|SAVE|TARGET|NOPASS|PASS{ARGS}?|DEFERRED|NON_OVERRIDABLE) +ACCESS_SPEC (PRIVATE|PUBLIC) +LANGUAGE_BIND_SPEC BIND{BS}"("{BS}C{BS}(,{BS}NAME{BS}"="{BS}"\""(.*)"\""{BS})?")" +/* Assume that attribute statements are almost the same as attributes. */ +ATTR_STMT {ATTR_SPEC}|DIMENSION|{ACCESS_SPEC} + +CONTAINS CONTAINS +PREFIX (RECURSIVE{BS_}|PURE{BS_}|ELEMENTAL{BS_}){0,2}(RECURSIVE|PURE|ELEMENTAL)? + +%option noyywrap +%option stack +%option caseless +/*%option debug */ + + //--------------------------------------------------------------------------------- + + /** fortran parsing states */ +%x Subprog +%x SubprogPrefix +%x Parameterlist +%x SubprogBody +%x SubprogBodyContains +%x Start +%x Comment +%x Module +%x Program +%x ModuleBody +%x ModuleBodyContains +%x AttributeList +%x Variable +%x Initialization +%x ArrayInitializer +%x Typedef +%x TypedefBody +%x TypedefBodyContains +%x InterfaceBody +%x StrIgnore +%x String +%x Use +%x UseOnly +%x ModuleProcedure + +%x Prepass + + /** comment parsing states */ +%x DocBlock +%x DocBackLine +%x EndDoc + +%x BlockData +%% + + /*-----------------------------------------------------------------------------------*/ + +<*>^.*\n { // prepass: look for line continuations + functionLine = FALSE; + + //fprintf(stderr, "---%s", yytext); + + int indexStart = getAmpersandAtTheStart(yytext, yyleng); + int indexEnd = getAmpOrExclAtTheEnd(yytext, yyleng); + if (indexEnd>=0 && yytext[indexEnd]!='&') //we are only interested in amp + indexEnd=-1; + + if(indexEnd<0){ // ----- no ampersand as line continuation + if(YY_START == Prepass) { // last line in "continuation" + + // Only take input after initial ampersand + inputStringPrepass+=(const char*)(yytext+(indexStart+1)); + + //printf("BUFFER:%s\n", (const char*)inputStringPrepass); + pushBuffer(inputStringPrepass); + yyColNr = 0; + yy_pop_state(); + } else { // simple line + yyColNr = 0; + REJECT; + } + + } else { // ----- line with continuation + if(YY_START != Prepass) { + comments.setAutoDelete(TRUE); + comments.clear(); + yy_push_state(Prepass); + } + + int length = inputStringPrepass.length(); + + // Only take input after initial ampersand + inputStringPrepass+=(const char*)(yytext+(indexStart+1)); + lineCountPrepass ++; + + // cut off & and remove following comment if present + truncatePrepass(length+indexEnd-(indexStart+1)); + } + + } + + + /*------ ignore strings that are not initialization strings */ +<*>"\\\\" { if (yy_top_state() == Initialization + || yy_top_state() == ArrayInitializer) + initializer+=yytext; + } +<*>"\\\""|\\\' { if (yy_top_state() == Initialization + || yy_top_state() == ArrayInitializer) + initializer+=yytext; + } +<String>\"|\' { // string ends with next quote without previous backspace + if (yytext[0]!=stringStartSymbol) { yyColNr -= yyleng; REJECT; } // single vs double quote + if (yy_top_state() == Initialization + || yy_top_state() == ArrayInitializer) + initializer+=yytext; + yy_pop_state(); + } +<String>. { if (yy_top_state() == Initialization + || yy_top_state() == ArrayInitializer) + initializer+=yytext; + } +<*>\"|\' { /* string starts */ + if (YY_START == StrIgnore) { yyColNr -= yyleng; REJECT; }; // ignore in simple comments + yy_push_state(YY_START); + if (yy_top_state() == Initialization + || yy_top_state() == ArrayInitializer) + initializer+=yytext; + stringStartSymbol=yytext[0]; // single or double quote + BEGIN(String); + } + + /*------ ignore simple comment (not documentation comments) */ + +<*>"!"/[^<>\n] { if (YY_START == String) { yyColNr -= yyleng; REJECT; } // "!" is ignored in strings + // skip comment line (without docu comments "!>" "!<" ) + /* ignore further "!" and ignore comments in Strings */ + if ((YY_START != StrIgnore) && (YY_START != String)) + { + yy_push_state(YY_START); + BEGIN(StrIgnore); + debugStr="*!"; + //fprintf(stderr,"start comment %d\n",yyLineNr); + } + } +<StrIgnore>.?/\n { yy_pop_state(); // comment ends with endline character + //fprintf(stderr,"end comment %d %s\n",yyLineNr,debugStr.data()); + } // comment line ends +<StrIgnore>. { debugStr+=yytext; } + + + /*------ use handling ------------------------------------------------------------*/ + +<Start,ModuleBody,SubprogBody>"use"{BS_} { + if(YY_START == Start) + { + addModule(NULL); + yy_push_state(ModuleBody); //anon program + } + yy_push_state(Use); + } +<Use>{ID} { + //fprintf(stderr,"using dir %s\n",yytext); + current->name=yytext; + current->fileName = yyFileName; + current->section=Entry::USINGDIR_SEC; + current_root->addSubEntry(current); + current = new Entry; + current->lang = SrcLangExt_Fortran; + yy_pop_state(); + } +<Use>{ID}/, { + useModuleName=yytext; + } +<Use>,{BS}"ONLY" { BEGIN(UseOnly); + } +<UseOnly>{BS},{BS} {} +<UseOnly>{ID} { + current->name= useModuleName+"::"+yytext; + current->fileName = yyFileName; + current->section=Entry::USINGDECL_SEC; + current_root->addSubEntry(current); + current = new Entry ; + current->lang = SrcLangExt_Fortran; + } +<Use,UseOnly>"\n" { + yyColNr -= 1; + unput(*yytext); + yy_pop_state(); + } + + /* INTERFACE definitions */ +<Start,ModuleBody,SubprogBody>{ +^{BS}interface{IDSYM}+ { /* variable with interface prefix */ } +^{BS}interface { ifType = IF_SPECIFIC; + yy_push_state(InterfaceBody); + // do not start a scope here, every + // interface body is a scope of its own + } + +^{BS}abstract{BS_}interface { ifType = IF_ABSTRACT; + yy_push_state(InterfaceBody); + // do not start a scope here, every + // interface body is a scope of its own + } + +^{BS}interface{BS_}{ID}{ARGS}? { ifType = IF_GENERIC; + yy_push_state(InterfaceBody); + + // extract generic name + QCString name = QCString(yytext).stripWhiteSpace(); + name = name.right(name.length() - 9).stripWhiteSpace(); + addInterface(name, ifType); + + startScope(last_entry); + } +} + +<InterfaceBody>^{BS}end{BS}interface({BS_}{ID})? { + // end scope only if GENERIC interface + if (ifType == IF_GENERIC && !endScope(current_root)) + yyterminate(); + + ifType = IF_NONE; + yy_pop_state(); + } +<InterfaceBody>module{BS}procedure { yy_push_state(YY_START); + BEGIN(ModuleProcedure); + } +<ModuleProcedure>{ID} { if (ifType == IF_ABSTRACT || ifType == IF_SPECIFIC) + { + addInterface(yytext, ifType); + startScope(last_entry); + } + + current->section = Entry::FUNCTION_SEC ; + current->name = yytext; + moduleProcedures.append(current); + addCurrentEntry(); + } +<ModuleProcedure>"\n" { yyColNr -= 1; + unput(*yytext); + yy_pop_state(); + } +<InterfaceBody>. {} + + /*-- Contains handling --*/ +<Start>^{BS}{CONTAINS}/({BS}|\n|!) { + if(YY_START == Start) + { + addModule(NULL); + yy_push_state(ModuleBodyContains); //anon program + } + } +<ModuleBody>^{BS}{CONTAINS}/({BS}|\n|!) { BEGIN(ModuleBodyContains); } +<SubprogBody>^{BS}{CONTAINS}/({BS}|\n|!) { BEGIN(SubprogBodyContains); } +<TypedefBody>^{BS}{CONTAINS}/({BS}|\n|!) { BEGIN(TypedefBodyContains); } + + /*------ module handling ------------------------------------------------------------*/ +<Start>block{BS}data{BS}{ID_} { // + v_type = V_IGNORE; + yy_push_state(BlockData); + defaultProtection = Public; + } +<Start>module|program{BS_} { // + v_type = V_IGNORE; + if(yytext[0]=='m' || yytext[0]=='M') + yy_push_state(Module); + else + yy_push_state(Program); + defaultProtection = Public; + } +<BlockData>^{BS}"end"({BS}(block{BS}data)({BS_}{ID})?)?{BS}/(\n|!) { // end block data + //if (!endScope(current_root)) + // yyterminate(); + defaultProtection = Public; + yy_pop_state(); + } +<Start,ModuleBody,ModuleBodyContains>^{BS}"end"({BS}(module|program)({BS_}{ID})?)?{BS}/(\n|!) { // end module + resolveModuleProcedures(moduleProcedures, current_root); + if (!endScope(current_root)) + yyterminate(); + defaultProtection = Public; + yy_pop_state(); + } +<Module>{ID} { + addModule(yytext, TRUE); + BEGIN(ModuleBody); + } + +<Program>{ID} { + addModule(yytext, FALSE); + BEGIN(ModuleBody); + } + + /*------- access specification --------------------------------------------------------------------------*/ + +<ModuleBody>private/{BS}(\n|"!") { defaultProtection = Private; + current->protection = defaultProtection ; + } +<ModuleBody>public/{BS}(\n|"!") { defaultProtection = Public; + current->protection = defaultProtection ; + } + + /*------- type definition -------------------------------------------------------------------------------*/ + +<Start,ModuleBody>^{BS}type { + if(YY_START == Start) + { + addModule(NULL); + yy_push_state(ModuleBody); //anon program + } + + yy_push_state(Typedef); + current->protection = defaultProtection; + typeProtection = defaultProtection; + typeMode = true; + } +<Typedef>{ +{COMMA} {} + +{BS}"::"{BS} {} + +abstract { + current->spec |= Entry::AbstractClass; + } +extends{ARGS} { + QCString basename = extractFromParens(yytext); + current->extends->append(new BaseInfo(basename, Public, Normal)); + } +public { + current->protection = Public; + typeProtection = Public; + } +private { + current->protection = Private; + typeProtection = Private; + } +{LANGUAGE_BIND_SPEC} { + /* ignored for now */ + } +{ID} { /* type name found */ + current->section = Entry::CLASS_SEC; + current->spec |= Entry::Struct; + current->name = yytext; + current->fileName = yyFileName; + current->bodyLine = yyLineNr; + + /* if type is part of a module, mod name is necessary for output */ + if ((current_root) && + (current_root->section == Entry::CLASS_SEC + || current_root->section == Entry::NAMESPACE_SEC)) + { + current->name = current_root->name + "::" + current->name; + } + + addCurrentEntry(); + startScope(last_entry); + BEGIN(TypedefBody); + } +} + +<TypedefBodyContains>{ /* Type Bound Procedures */ +^{BS}PROCEDURE{ARGS}? { + current->type = QCString(yytext).simplifyWhiteSpace(); + } +^{BS}final { + current->spec |= Entry::Final; + current->type = QCString(yytext).simplifyWhiteSpace(); + } +^{BS}generic { + current->type = QCString(yytext).simplifyWhiteSpace(); + } +{COMMA} { + } +{ATTR_SPEC} { + currentModifiers |= QCString(yytext); + } +{BS}"::"{BS} { + } +{ID} { + QCString name = yytext; + modifiers[current_root][name.lower()] |= currentModifiers; + current->section = Entry::FUNCTION_SEC; + current->name = name; + current->fileName = yyFileName; + current->bodyLine = yyLineNr; + addCurrentEntry(); + } +{BS}"=>"[^(\n|\!)]* { /* Specific bindings come after the ID. */ + last_entry->args = yytext; + } +"\n" { + currentModifiers = SymbolModifiers(); + newLine(); + docBlock.resize(0); + } +} + + +<TypedefBody,TypedefBodyContains>{ +^{BS}"end"{BS}"type"({BS_}{ID})?{BS}/(\n|!) { /* end type definition */ + if (!endScope(current_root)) + yyterminate(); + typeMode = false; + yy_pop_state(); + } +} + + /*------- module/global/typedef variable ---------------------------------------------------*/ + +<SubprogBody,SubprogBodyContains>^{BS}[0-9]*{BS}"end"({BS}{SUBPROG}({BS_}{ID})?)?{BS}/(\n|!) { + // + // ABSTRACT and specific interfaces are stored + // in a scope of their own, even if multiple + // are group in one INTERFACE/END INTERFACE block. + // + if (ifType == IF_ABSTRACT || ifType == IF_SPECIFIC) + endScope(current_root); + + if (!endScope(current_root)) + yyterminate(); + subrCurrent.remove(0u); + yy_pop_state() ; + } +<BlockData>{ +{ID} { + } +} +<Start,ModuleBody,TypedefBody,SubprogBody>{ +^{BS}{TYPE_SPEC}/{SEPARATE} { + /* variable declaration starts */ + if(YY_START == Start) + { + addModule(NULL); + yy_push_state(ModuleBody); //anon program + } + argType = QCString(yytext).simplifyWhiteSpace(); + yy_push_state(AttributeList); + } + /* Dimitri: macro expansion should already be done during preprocessing not here! +^{BS}{PP_ID}{KIND}? { // check for preprocessor symbol expand to type + QCString str = yytext; + str = str.stripWhiteSpace(); + //DefineDict* defines = getGlobalDefineDict(); + QCString name; + int index = str.find("("); + if (index != -1) + name = str.left(index).stripWhiteSpace(); + else + name = str; + + Define *define = 0; //(*defines)[name]; + if (define != 0 && isTypeName(define->definition)) + { + argType = str; + yy_push_state(AttributeList); + } + else + { + yyColNr -= yyleng; + REJECT; + } + } + */ +{ATTR_STMT}/{BS_}{ID} | +{ATTR_STMT}/{BS}"::" { + /* attribute statement starts */ + //fprintf(stderr,"5=========> Attribute statement: %s\n", yytext); + QCString tmp = yytext; + currentModifiers |= tmp.stripWhiteSpace(); + argType=""; + yy_push_state(YY_START); + BEGIN( AttributeList ) ; + } +{ID} { + } +^{BS}"type"{BS_}"is" { } +} +<AttributeList>{ +{COMMA} {} +{BS} {} +{ATTR_SPEC}. { /* update current modifierswhen it is an ATTR_SPEC and not a variable name */ + /* bug_625519 */ + QChar chr = yytext[yyleng-1]; + if (chr.isLetter() || chr.isDigit() || (chr == '_')) + { + yyColNr -= yyleng; + REJECT; + } + else + { + QCString tmp = yytext; + tmp = tmp.left(tmp.length() - 1); + yyColNr -= 1; + unput(yytext[yyleng-1]); + currentModifiers |= (tmp); + } + } +"::" { /* end attribute list */ + BEGIN( Variable ); + } +. { /* unknown attribute, consider variable name */ + //cout<<"start variables, unput "<<*yytext<<endl; + yyColNr -= 1; + unput(*yytext); + BEGIN( Variable ); + } +} + +<Variable>{BS} { } +<Variable>{ID} { /* parse variable declaration */ + //cout << "5=========> got variable: " << argType << "::" << yytext << endl; + /* work around for bug in QCString.replace (QCString works) */ + QCString name=yytext; + /* remember attributes for the symbol */ + modifiers[current_root][name.lower()] |= currentModifiers; + argName= name; + + v_type= V_IGNORE; + if (!argType.isEmpty() && current_root->section!=Entry::FUNCTION_SEC) + { // new variable entry + v_type = V_VARIABLE; + current->section = Entry::VARIABLE_SEC; + current->name = argName; + current->type = argType; + current->fileName = yyFileName; + current->bodyLine = yyLineNr; // used for source reference + addCurrentEntry(); + } + else if (!argType.isEmpty()) + { // declaration of parameter list: add type for corr. parameter + parameter = getParameter(argName); + if (parameter) + { + v_type= V_PARAMETER; + if (!argType.isNull()) parameter->type=argType.stripWhiteSpace(); + if (!docBlock.isNull()) + { + subrHandleCommentBlock(docBlock,TRUE); + } + } + // save, it may be function return type + if (parameter) + { + modifiers[current_root][name.lower()].type = argType; + } + else + { + if ((current_root->name.lower() == argName.lower()) || + (modifiers[current_root->parent()][current_root->name.lower()].returnName.lower() == argName.lower())) + { + int strt = current_root->type.find("function"); + QString lft; + QString rght; + if (strt != -1) + { + lft = ""; + rght = ""; + if (strt != 0) lft = current_root->type.left(strt).stripWhiteSpace(); + if ((current_root->type.length() - strt - strlen("function"))!= 0) + { + rght = current_root->type.right(current_root->type.length() - strt - strlen("function")).stripWhiteSpace(); + } + current_root->type = lft; + if (rght.length() > 0) + { + if (current_root->type.length() > 0) current_root->type += " "; + current_root->type += rght; + } + if (argType.stripWhiteSpace().length() > 0) + { + if (current_root->type.length() > 0) current_root->type += " "; + current_root->type += argType.stripWhiteSpace(); + } + if (current_root->type.length() > 0) current_root->type += " "; + current_root->type += "function"; + } + else + { + current_root->type += " " + argType.stripWhiteSpace(); + } + current_root->type = current_root->type.stripWhiteSpace(); + modifiers[current_root][name.lower()].type = current_root->type; + } + else + { + modifiers[current_root][name.lower()].type = argType; + } + } + // any accumulated doc for argument should be emptied, + // because it is handled other way and this doc can be + // unexpectedly passed to the next member. + current->doc.resize(0); + current->brief.resize(0); + } + } +<Variable>{ARGS} { /* dimension of the previous entry. */ + QCString name(argName); + QCString attr("dimension"); + attr += yytext; + modifiers[current_root][name] |= attr; + } +<Variable>{COMMA} { //printf("COMMA: %d<=..<=%d\n", yyColNr-yyleng, yyColNr); + // locate !< comment + updateVariablePrepassComment(yyColNr-yyleng, yyColNr); + } +<Variable>{BS}"=" { yy_push_state(YY_START); + initializer=""; + initializerScope = initializerArrayScope = 0; + BEGIN(Initialization); + } +<Variable>"\n" { currentModifiers = SymbolModifiers(); + yy_pop_state(); // end variable declaration list + newLine(); + docBlock.resize(0); + } +<Variable>";".*"\n" { currentModifiers = SymbolModifiers(); + yy_pop_state(); // end variable declaration list + docBlock.resize(0); + inputStringSemi =(const char*)(QCString(" \n") + QCString(yytext+1)).data(); + yyLineNr--; + pushBuffer(inputStringSemi); + } +<*>";".*"\n" { + if (YY_START == Variable) REJECT; // Just be on the safe side + if (YY_START == String) REJECT; // ";" ignored in strings + if (YY_START == StrIgnore) REJECT; // ";" ignored in regular comments + inputStringSemi =(const char*)(QCString(" \n") + QCString(yytext+1)).data(); + yyLineNr--; + pushBuffer(inputStringSemi); + } + +<Initialization,ArrayInitializer>"(/" { initializer+=yytext; + initializerArrayScope++; + BEGIN(ArrayInitializer); // initializer may contain comma + } +<ArrayInitializer>"/)" { initializer+=yytext; + initializerArrayScope--; + if(initializerArrayScope<=0) + { + initializerArrayScope = 0; // just in case + BEGIN(Initialization); + } + } +<ArrayInitializer>. { initializer+=yytext; } +<Initialization>"(" { initializerScope++; + initializer+=yytext; + } +<Initialization>")" { initializerScope--; + initializer+=yytext; + } +<Initialization>{COMMA} { if (initializerScope == 0) + { + updateVariablePrepassComment(yyColNr-yyleng, yyColNr); + yy_pop_state(); // end initialization + if (v_type == V_VARIABLE) last_entry->initializer= initializer; + } + else + initializer+=", "; + } +<Initialization>"\n"|"!" { //| + yy_pop_state(); // end initialization + if (v_type == V_VARIABLE) last_entry->initializer= initializer; + yyColNr -= 1; + unput(*yytext); + } +<Initialization>. { initializer+=yytext; } + + /*------ fortran subroutine/function handling ------------------------------------------------------------*/ + /* Start is initial condition */ + +<Start,ModuleBody,SubprogBody,InterfaceBody,ModuleBodyContains,SubprogBodyContains>^{BS}({PREFIX}{BS_})?{TYPE_SPEC}{BS}/{SUBPROG}{BS_} { + if (ifType == IF_ABSTRACT || ifType == IF_SPECIFIC) + { + addInterface("$interface$", ifType); + startScope(last_entry); + } + + // TYPE_SPEC is for old function style function result + result = QCString(yytext).stripWhiteSpace(); + current->type = result; + yy_push_state(SubprogPrefix); + } + +<SubprogPrefix>{BS}{SUBPROG}{BS_} { + // Fortran subroutine or function found + v_type = V_IGNORE; + result=yytext; + result=result.stripWhiteSpace(); + addSubprogram(result); + BEGIN(Subprog); + } + +<Start,ModuleBody,SubprogBody,InterfaceBody,ModuleBodyContains,SubprogBodyContains>^{BS}({PREFIX}{BS_})?{SUBPROG}{BS_} { + // Fortran subroutine or function found + v_type = V_IGNORE; + if (ifType == IF_ABSTRACT || ifType == IF_SPECIFIC) + { + addInterface("$interface$", ifType); + startScope(last_entry); + } + + result = QCString(yytext).stripWhiteSpace(); + addSubprogram(result); + yy_push_state(Subprog); + } + +<Subprog>{BS} { /* ignore white space */ } +<Subprog>{ID} { current->name = yytext; + //cout << "1a==========> got " << current->type << " " << yytext << " " << yyLineNr << endl; + modifiers[current_root][current->name.lower()].returnName = current->name; + + if (ifType == IF_ABSTRACT || ifType == IF_SPECIFIC) + { + current_root->name.replace(QRegExp("\\$interface\\$"), yytext); + } + + BEGIN(Parameterlist); + } +<Parameterlist>"(" { current->args = "("; } +<Parameterlist>")" { + current->args += ")"; + current->args = removeRedundantWhiteSpace(current->args); + addCurrentEntry(); + startScope(last_entry); + BEGIN(SubprogBody); + } +<Parameterlist>{COMMA}|{BS} { current->args += yytext; + CommentInPrepass *c = locatePrepassComment(yyColNr-yyleng, yyColNr); + if (c!=NULL) { + if(current->argList->count()>0) { + current->argList->at(current->argList->count()-1)->docs = c->str; + } + } + } +<Parameterlist>{ID} { + //current->type not yet available + QCString param = yytext; + // std::cout << "3=========> got parameter " << param << std::endl; + current->args += param; + Argument *arg = new Argument; + arg->name = param; + arg->type = ""; + current->argList->append(arg); + } +<Parameterlist>{NOARGS} { + newLine(); + //printf("3=========> without parameterlist \n"); + //current->argList = ; + addCurrentEntry(); + startScope(last_entry); + BEGIN(SubprogBody); +} +<SubprogBody>result{BS}\({BS}{ID} { + if (functionLine) + { + result= yytext; + result= result.right(result.length()-result.find("(")-1); + result= result.stripWhiteSpace(); + modifiers[current_root->parent()][current_root->name.lower()].returnName = result; + } + //cout << "=====> got result " << result << endl; + } + + /*---- documentation comments --------------------------------------------------------------------*/ + +<Variable,SubprogBody,ModuleBody,TypedefBody>"!<" { /* backward docu comment */ + if (v_type != V_IGNORE) { + current->docLine = yyLineNr; + docBlockJavaStyle = FALSE; + docBlock.resize(0); + docBlockJavaStyle = Config_getBool("JAVADOC_AUTOBRIEF"); + startCommentBlock(TRUE); + yy_push_state(DocBackLine); + } + } +<DocBackLine>.* { // contents of current comment line + docBlock+=yytext; + } +<DocBackLine>"\n"{BS}"!"("<"|"!"+) { // comment block (next line is also comment line) + docBlock+="\n"; // \n is necessary for lists + newLine(); + } +<DocBackLine>"\n" { // comment block ends at the end of this line + //cout <<"3=========> comment block : "<< docBlock << endl; + yyColNr -= 1; + unput(*yytext); + if (v_type == V_VARIABLE) + { + Entry *tmp_entry = current; + current = last_entry; // temporarily switch to the previous entry + handleCommentBlock(docBlock,TRUE); + current=tmp_entry; + } + else if (v_type == V_PARAMETER) + { + subrHandleCommentBlock(docBlock,TRUE); + } + yy_pop_state(); + docBlock.resize(0); + } + +<Start,SubprogBody,ModuleBody,TypedefBody,InterfaceBody,ModuleBodyContains,SubprogBodyContains,TypedefBodyContains>"!>" { + yy_push_state(YY_START); + current->docLine = yyLineNr; + docBlockJavaStyle = FALSE; + docBlock.resize(0); + docBlockJavaStyle = Config_getBool("JAVADOC_AUTOBRIEF"); + startCommentBlock(TRUE); + BEGIN(DocBlock); + //cout << "start DocBlock " << endl; + } + +<DocBlock>.* { // contents of current comment line + docBlock+=yytext; + } +<DocBlock>"\n"{BS}"!"(">"|"!"+) { // comment block (next line is also comment line) + docBlock+="\n"; // \n is necessary for lists + newLine(); + } +<DocBlock>"\n" { // comment block ends at the end of this line + //cout <<"3=========> comment block : "<< docBlock << endl; + yyColNr -= 1; + unput(*yytext); + handleCommentBlock(docBlock,TRUE); + yy_pop_state(); + } + + /*------------------------------------------------------------------------------------------------*/ + +<*>"\n" { + newLine(); + //if (debugStr.stripWhiteSpace().length() > 0) cout << "ignored text: " << debugStr << " state: " <<YY_START << endl; + debugStr=""; + } + + + /*---- error: EOF in wrong state --------------------------------------------------------------------*/ + +<*><<EOF>> { + if ( include_stack_ptr <= 0 ) { + if (YY_START!=INITIAL && YY_START!=Start) { + //fprintf(stderr,"==== Error: EOF reached in wrong state (end missing)"); + scanner_abort(); + } + yyterminate(); + } else { + popBuffer(); + } + } +<*>{LOG_OPER} { // Fortran logical comparison keywords + } +<*>. { + //debugStr+=yytext; + //printf("I:%c\n", *yytext); + } // ignore remaining text + + /**********************************************************************************/ + /**********************************************************************************/ + /**********************************************************************************/ +%% +//---------------------------------------------------------------------------- + +#if 0 +static void extractPrefix(QCString &text) +{ + int prefixIndex = 0; + int curIndex = 0; + bool cont = TRUE; + const char* pre[] = {"RECURSIVE","PURE","ELEMENTAL"}; + while(cont) + { + cont = FALSE; + for(unsigned int i=0; i<3; i++) + { + if((prefixIndex=text.find(pre[i], curIndex, FALSE))==0) + { + text.remove(0,strlen(pre[i])); + text.stripWhiteSpace(); + cont = TRUE; + } + } + } +} +#endif + +static void newLine() { + yyLineNr++; + yyLineNr+=lineCountPrepass; + lineCountPrepass=0; + comments.clear(); +} + +static CommentInPrepass* locatePrepassComment(int from, int to) { + //printf("Locate %d-%d\n", from, to); + for(uint i=0; i<comments.count(); i++) { // todo: optimize + int c = comments.at(i)->column; + //printf("Candidate %d\n", c); + if (c>=from && c<=to) { + // comment for previous variable or parameter + return comments.at(i); + } + } + return NULL; +} + +static void updateVariablePrepassComment(int from, int to) { + CommentInPrepass *c = locatePrepassComment(from, to); + if (c!=NULL && v_type == V_VARIABLE) { + last_entry->brief = c->str; + } else if (c!=NULL && v_type == V_PARAMETER) { + Argument *parameter = getParameter(argName); + if (parameter) parameter->docs = c->str; + } +} + +static int getAmpersandAtTheStart(const char *buf, int length) +{ + for(int i=0; i<length; i++) { + switch(buf[i]) { + case ' ': + case '\t': + break; + case '&': + return i; + default: + return -1; + } + } + return -1; +} + +/* Returns ampersand index, comment start index or -1 if neither exist.*/ +static int getAmpOrExclAtTheEnd(const char *buf, int length) +{ + // Avoid ampersands in string and comments + int parseState = Start; + char quoteSymbol = 0; + int ampIndex = -1; + int commentIndex = -1; + + for(int i=0; i<length && parseState!=Comment; i++) + { + // When in string, skip backslashes + // Legacy code, not sure whether this is correct? + if(parseState==String) + { + if(buf[i]=='\\') i++; + } + + switch(buf[i]) + { + case '\'': + case '"': + // Close string, if quote symbol matches. + // Quote symbol is set iff parseState==String + if(buf[i]==quoteSymbol) + { + parseState = Start; + quoteSymbol = 0; + } + // Start new string, if not already in string or comment + else if(parseState==Start) + { + parseState = String; + quoteSymbol = buf[i]; + } + ampIndex = -1; // invalidate prev ampersand + break; + case '!': + // When in string or comment, ignore exclamation mark + if(parseState==Start) + { + parseState = Comment; + commentIndex = i; + } + break; + case ' ': // ignore whitespace + case '\t': + case '\n': // this may be at the end of line + break; + case '&': + ampIndex = i; + break; + default: + ampIndex = -1; // invalidate prev ampersand + } + } + + if (ampIndex>=0) + return ampIndex; + else + return commentIndex; +} + +/* Although comments at the end of continuation line are grabbed by this function, +* we still do not know how to use them later in parsing. +*/ +void truncatePrepass(int index) +{ + int length = inputStringPrepass.length(); + for (int i=index+1; i<length; i++) { + if (inputStringPrepass[i]=='!' && i<length-1 && inputStringPrepass[i+1]=='<') { // save comment + struct CommentInPrepass *c=new CommentInPrepass(index, inputStringPrepass.right(length-i-2)); + comments.append(c); + } + } + inputStringPrepass.truncate(index); +} + +// simplified way to know if this is fixed form +// duplicate in fortrancode.l +static bool recognizeFixedForm(const char* contents) +{ + int column=0; + bool skipLine=FALSE; + + for(int i=0;;i++) { + column++; + + switch(contents[i]) { + case '\n': + column=0; + skipLine=FALSE; + break; + case ' ': + break; + case '\000': + return FALSE; + case 'C': + case 'c': + case '*': + if(column==1) return TRUE; + if(skipLine) break; + return FALSE; + case '!': + if(column>1 && column<7) return FALSE; + skipLine=TRUE; + break; + default: + if(skipLine) break; + if(column==7) return TRUE; + return FALSE; + } + } + return FALSE; +} + +/* This function assumes that contents has at least size=length+1 */ +static void insertCharacter(char *contents, int length, int pos, char c) +{ + // shift tail by one character + for(int i=length; i>pos; i--) + contents[i]=contents[i-1]; + // set the character + contents[pos] = c; +} + +/* change comments and bring line continuation character to previous line */ +static const char* prepassFixedForm(const char* contents) +{ + int column=0; + int prevLineLength=0; + int prevLineAmpOrExclIndex=-1; + bool emptyLabel=TRUE; + int newContentsSize = strlen(contents)+2; // \000 and one spare character (to avoid reallocation) + char* newContents = (char*)malloc(newContentsSize); + + for(int i=0, j=0;;i++,j++) { + if(j>=newContentsSize-1) { // check for one spare character, which may be eventually used below (by &) + newContents = (char*)realloc(newContents, newContentsSize+1000); + newContentsSize = newContentsSize+1000; + } + + column++; + char c = contents[i]; + switch(c) { + case '\n': + prevLineLength=column; + prevLineAmpOrExclIndex=getAmpOrExclAtTheEnd(&contents[i-prevLineLength+1], prevLineLength); + column=0; + emptyLabel=TRUE; + newContents[j]=c; + break; + case ' ': + newContents[j]=c; + break; + case '\000': + newContents[j]='\000'; + return newContents; + case 'C': + case 'c': + case '*': + if (column!=6) + { + emptyLabel=FALSE; + if(column==1) + newContents[j]='!'; + else + newContents[j]=c; + break; + } + default: + if(column==6 && emptyLabel) { // continuation + if (c != '0') { // 0 not allowed as continuatioin character, see f95 standard paragraph 3.3.2.3 + newContents[j]=' '; + + if(prevLineAmpOrExclIndex==-1) { // add & just before end of previous line + insertCharacter(newContents, j+1, (j+1)-6-1, '&'); + j++; + } else { // add & just before end of previous line comment + insertCharacter(newContents, j+1, (j+1)-6-prevLineLength+prevLineAmpOrExclIndex, '&'); + j++; + } + } else { + newContents[j]=c; // , just handle like space + } + } else { + newContents[j]=c; + emptyLabel=FALSE; + } + break; + } + } + return newContents; +} + +static void pushBuffer(QCString& buffer) +{ + if ( include_stack_ptr >= MAX_INCLUDE_DEPTH ) + { + fprintf( stderr, "Stack buffers nested too deeply" ); + exit( 1 ); + } + include_stack[include_stack_ptr++] = YY_CURRENT_BUFFER; + yy_switch_to_buffer(yy_scan_string(buffer)); + + //fprintf(stderr, "--PUSH--%s", (const char *)buffer); + buffer = NULL; +} + +static void popBuffer() { + //fprintf(stderr, "--POP--"); + include_stack_ptr --; + yy_delete_buffer( YY_CURRENT_BUFFER ); + yy_switch_to_buffer( include_stack[include_stack_ptr] ); +} + +/** used to copy entry to an interface module procedure */ +static void copyEntry(Entry *dest, Entry *src) +{ + dest->type = src->type; + dest->fileName = src->fileName; + dest->bodyLine = src->bodyLine; + dest->args = src->args; + dest->argList = new ArgumentList(*src->argList); + dest->doc = src->doc; + dest->brief = src->brief; +} + +/** fill empty interface module procedures with info from + corresponding module subprogs + @TODO: handle procedures in used modules +*/ +void resolveModuleProcedures(QList<Entry> &moduleProcedures, Entry *current_root) +{ + if (moduleProcedures.isEmpty()) return; + + EntryListIterator eli1(moduleProcedures); + // for all module procedures + for (Entry *ce1; (ce1=eli1.current()); ++eli1) + { + // check all entries in this module + EntryListIterator eli2(*current_root->children()); + for (Entry *ce2; (ce2=eli2.current()); ++eli2) + { + if (ce1->name == ce2->name) + { + copyEntry(ce1, ce2); + } + } // for procedures in current module + } // for all interface module procedures + moduleProcedures.clear(); +} + +#if 0 +static bool isTypeName(QCString name) +{ + name = name.lower(); + return name=="integer" || name == "real" || + name=="complex" || name == "logical"; +} +#endif + +/*! Extracts string which resides within parentheses of provided string. */ +static QCString extractFromParens(const QCString name) +{ + QCString extracted = name; + int start = extracted.find("("); + if (start != -1) + { + extracted.remove(0, start+1); + } + int end = extracted.findRev(")"); + if (end != -1) + { + int length = extracted.length(); + extracted.remove(end, length); + } + extracted = extracted.stripWhiteSpace(); + + return extracted; +} + +/*! Adds passed modifiers to these modifiers.*/ +SymbolModifiers& SymbolModifiers::operator|=(const SymbolModifiers &mdfs) +{ + if (mdfs.protection!=NONE_P) protection = mdfs.protection; + if (mdfs.direction!=NONE_D) direction = mdfs.direction; + optional |= mdfs.optional; + if (!mdfs.dimension.isNull()) dimension = mdfs.dimension; + allocatable |= mdfs.allocatable; + external |= mdfs.external; + intrinsic |= mdfs.intrinsic; + parameter |= mdfs.parameter; + pointer |= mdfs.pointer; + target |= mdfs.target; + save |= mdfs.save; + deferred |= mdfs.deferred; + nonoverridable |= mdfs.nonoverridable; + nopass |= mdfs.nopass; + pass |= mdfs.pass; + passVar = mdfs.passVar; + return *this; +} + +/*! Extracts and adds passed modifier to these modifiers.*/ +SymbolModifiers& SymbolModifiers::operator|=(QCString mdfString) +{ + mdfString = mdfString.lower(); + SymbolModifiers newMdf; + + if (mdfString.find("dimension")==0) + { + newMdf.dimension=mdfString; + } + else if (mdfString.contains("intent")) + { + QCString tmp = extractFromParens(mdfString); + bool isin = tmp.contains("in"); + bool isout = tmp.contains("out"); + if (isin && isout) newMdf.direction = SymbolModifiers::INOUT; + else if (isin) newMdf.direction = SymbolModifiers::IN; + else if (isout) newMdf.direction = SymbolModifiers::OUT; + } + else if (mdfString=="public") + { + newMdf.protection = SymbolModifiers::PUBLIC; + } + else if (mdfString=="private") + { + newMdf.protection = SymbolModifiers::PRIVATE; + } + else if (mdfString=="optional") + { + newMdf.optional = TRUE; + } + else if (mdfString=="allocatable") + { + newMdf.allocatable = TRUE; + } + else if (mdfString=="external") + { + newMdf.external = TRUE; + } + else if (mdfString=="intrinsic") + { + newMdf.intrinsic = TRUE; + } + else if (mdfString=="parameter") + { + newMdf.parameter = TRUE; + } + else if (mdfString=="pointer") + { + newMdf.pointer = TRUE; + } + else if (mdfString=="target") + { + newMdf.target = TRUE; + } + else if (mdfString=="save") + { + newMdf.save = TRUE; + } + else if (mdfString=="nopass") + { + newMdf.nopass = TRUE; + } + else if (mdfString=="deferred") + { + newMdf.deferred = TRUE; + } + else if (mdfString=="non_overridable") + { + newMdf.nonoverridable = TRUE; + } + else if (mdfString.contains("pass")) + { + newMdf.pass = TRUE; + if (mdfString.contains("(")) + newMdf.passVar = extractFromParens(mdfString); + else + newMdf.passVar = ""; + } + + (*this) |= newMdf; + return *this; +} + +/*! For debugging purposes. */ +//ostream& operator<<(ostream& out, const SymbolModifiers& mdfs) +//{ +// out<<mdfs.protection<<", "<<mdfs.direction<<", "<<mdfs.optional<< +// ", "<<(mdfs.dimension.isNull() ? "" : mdfs.dimension.latin1())<< +// ", "<<mdfs.allocatable<<", "<<mdfs.external<<", "<<mdfs.intrinsic; +// +// return out; +//} + +/*! Find argument with given name in \a subprog entry. */ +static Argument *findArgument(Entry* subprog, QCString name, bool byTypeName = FALSE) +{ + QCString cname(name.lower()); + for (unsigned int i=0; i<subprog->argList->count(); i++) + { + Argument *arg = subprog->argList->at(i); + if ((!byTypeName && arg->name.lower() == cname) || + (byTypeName && arg->type.lower() == cname) + ) + { + return arg; + } + } + return 0; +} + +/*! Find function with given name in \a entry. */ +#if 0 +static Entry *findFunction(Entry* entry, QCString name) +{ + QCString cname(name.lower()); + + EntryListIterator eli(*entry->children()); + Entry *ce; + for (;(ce=eli.current());++eli) + { + if (ce->section != Entry::FUNCTION_SEC) + continue; + + if (ce->name.lower() == cname) + return ce; + } + + return 0; +} +#endif + +/*! Apply modifiers stored in \a mdfs to the \a typeName string. */ +static QCString applyModifiers(QCString typeName, SymbolModifiers& mdfs) +{ + if (!mdfs.dimension.isNull()) + { + typeName += ", "; + typeName += mdfs.dimension; + } + if (mdfs.direction!=SymbolModifiers::NONE_D) + { + typeName += ", "; + typeName += directionStrs[mdfs.direction]; + } + if (mdfs.optional) + { + typeName += ", "; + typeName += "optional"; + } + if (mdfs.allocatable) + { + typeName += ", "; + typeName += "allocatable"; + } + if (mdfs.external) + { + typeName += ", "; + typeName += "external"; + } + if (mdfs.intrinsic) + { + typeName += ", "; + typeName += "intrinsic"; + } + if (mdfs.parameter) + { + typeName += ", "; + typeName += "parameter"; + } + if (mdfs.pointer) + { + typeName += ", "; + typeName += "pointer"; + } + if (mdfs.target) + { + typeName += ", "; + typeName += "target"; + } + if (mdfs.save) + { + typeName += ", "; + typeName += "save"; + } + if (mdfs.deferred) + { + typeName += ", "; + typeName += "deferred"; + } + if (mdfs.nonoverridable) + { + typeName += ", "; + typeName += "non_overridable"; + } + if (mdfs.nopass) + { + typeName += ", "; + typeName += "nopass"; + } + if (mdfs.pass) + { + typeName += ", "; + typeName += "pass"; + if (!mdfs.passVar.isEmpty()) + typeName += "(" + mdfs.passVar + ")"; + } + if (mdfs.protection == SymbolModifiers::PUBLIC) + { + typeName += ", "; + typeName += "public"; + } + else if (mdfs.protection == SymbolModifiers::PRIVATE) + { + typeName += ", "; + typeName += "private"; + } + + return typeName; +} + +/*! Apply modifiers stored in \a mdfs to the \a arg argument. */ +static void applyModifiers(Argument *arg, SymbolModifiers& mdfs) +{ + QCString tmp = arg->type; + arg->type = applyModifiers(tmp, mdfs); +} + +/*! Apply modifiers stored in \a mdfs to the \a ent entry. */ +static void applyModifiers(Entry *ent, SymbolModifiers& mdfs) +{ + QCString tmp = ent->type; + ent->type = applyModifiers(tmp, mdfs); + + if (mdfs.protection == SymbolModifiers::PUBLIC) + ent->protection = Public; + else if (mdfs.protection == SymbolModifiers::PRIVATE) + ent->protection = Private; +} + +/*! Starts the new scope in fortran program. Consider using this function when + * starting module, interface, function or other program block. + * \see endScope() + */ +static void startScope(Entry *scope) +{ + //cout<<"start scope: "<<scope->name<<endl; + current_root= scope; /* start substructure */ + + QMap<QCString,SymbolModifiers> mdfMap; + modifiers.insert(scope, mdfMap); +} + +/*! Ends scope in fortran program: may update subprogram arguments or module variable attributes. + * \see startScope() + */ +static bool endScope(Entry *scope, bool isGlobalRoot) +{ + //cout<<"end scope: "<<scope->name<<endl; + if (current_root->parent() || isGlobalRoot) + { + current_root= current_root->parent(); /* end substructure */ + } + else + { + fprintf(stderr,"parse error in end <scopename>"); + scanner_abort(); + return FALSE; + } + + // update variables or subprogram arguments with modifiers + QMap<QCString,SymbolModifiers>& mdfsMap = modifiers[scope]; + + if (scope->section == Entry::FUNCTION_SEC) + { + // iterate all symbol modifiers of the scope + for (QMap<QCString,SymbolModifiers>::Iterator it=mdfsMap.begin(); it!=mdfsMap.end(); it++) + { + //cout<<it.key()<<": "<<it.data()<<endl; + Argument *arg = findArgument(scope, it.key()); + + if (arg) + applyModifiers(arg, it.data()); + } + + // find return type for function + //cout<<"RETURN NAME "<<modifiers[current_root][scope->name.lower()].returnName<<endl; + QCString returnName = modifiers[current_root][scope->name.lower()].returnName.lower(); + if (modifiers[scope].contains(returnName)) + { + scope->type = modifiers[scope][returnName].type; // returning type works + applyModifiers(scope, modifiers[scope][returnName]); // returning array works + } + + } + if (scope->section == Entry::CLASS_SEC) + { // was INTERFACE_SEC + if (scope->parent()->section == Entry::FUNCTION_SEC) + { // interface within function + // iterate functions of interface and + // try to find types for dummy(ie. argument) procedures. + //cout<<"Search in "<<scope->name<<endl; + EntryListIterator eli(*scope->children()); + Entry *ce; + int count = 0; + int found = FALSE; + for (;(ce=eli.current());++eli) + { + count++; + if (ce->section != Entry::FUNCTION_SEC) + continue; + + Argument *arg = findArgument(scope->parent(), ce->name, TRUE); + if (arg != 0) + { + // set type of dummy procedure argument to interface + arg->name = arg->type; + arg->type = scope->name; + } + if (ce->name.lower() == scope->name.lower()) found = TRUE; + } + if ((count == 1) && found) + { + // clear all modifiers of the scope + modifiers.remove(scope); + delete scope->parent()->removeSubEntry(scope); + scope = 0; + return TRUE; + } + } + } + if (scope->section!=Entry::FUNCTION_SEC) + { // not function section + // iterate variables: get and apply modifiers + EntryListIterator eli(*scope->children()); + Entry *ce; + for (;(ce=eli.current());++eli) + { + if (ce->section != Entry::VARIABLE_SEC && ce->section != Entry::FUNCTION_SEC) + continue; + + //cout<<ce->name<<", "<<mdfsMap.contains(ce->name.lower())<<mdfsMap.count()<<endl; + if (mdfsMap.contains(ce->name.lower())) + applyModifiers(ce, mdfsMap[ce->name.lower()]); + } + } + + // clear all modifiers of the scope + modifiers.remove(scope); + + return TRUE; +} + +//! Return full name of the entry. Sometimes we must combine several names recursively. +static QCString getFullName(Entry *e) +{ + QCString name = e->name; + if (e->section == Entry::CLASS_SEC // || e->section == Entry::INTERFACE_SEC + || !e->parent() || e->parent()->name.isEmpty()) + return name; + + return getFullName(e->parent())+"::"+name; +} + +static int yyread(char *buf,int max_size) +{ + int c=0; + + while ( c < max_size && inputString[inputPosition] ) + { + *buf = inputString[inputPosition++] ; + c++; buf++; + } + return c; +} + +static void initParser() +{ + last_entry = 0; +} + +static void initEntry() +{ + if (typeMode) + { + current->protection = typeProtection; + } + else + { + current->protection = defaultProtection; + } + current->mtype = mtype; + current->virt = virt; + current->stat = gstat; + current->lang = SrcLangExt_Fortran; + initGroupInfo(current); +} + +/** + adds current entry to current_root and creates new current +*/ +static void addCurrentEntry() +{ + //printf("===Adding entry %s to %s\n", current->name.data(), current_root->name.data()); + current_root->addSubEntry(current); + last_entry = current; + current = new Entry ; + initEntry(); +} + +static int max(int a, int b) {return a>b?a:b;} + +static void addModule(const char *name, bool isModule) +{ + //fprintf(stderr, "0=========> got module %s\n", name); + + if (isModule) + current->section = Entry::CLASS_SEC; + else + current->section = Entry::FUNCTION_SEC; + + if (name!=NULL) + { + current->name = name; + } + else + { + QCString fname = yyFileName; + int index = max(fname.findRev('/'), fname.findRev('\\')); + fname = fname.right(fname.length()-index-1); + fname = fname.prepend("__").append("__"); + current->name = fname; + } + current->type = "program"; + current->fileName = yyFileName; + current->bodyLine = yyLineNr; // used for source reference + current->protection = Public ; + addCurrentEntry(); + startScope(last_entry); +} + + +static void addSubprogram(const char *text) +{ + //fprintf(stderr,"1=========> got subprog, type: %s\n",text); + subrCurrent.prepend(current); + current->section = Entry::FUNCTION_SEC ; + QCString subtype = text; subtype=subtype.lower().stripWhiteSpace(); + functionLine = subtype=="function"; + current->type += " " + subtype; + current->type = current->type.stripWhiteSpace(); + current->fileName = yyFileName; + current->bodyLine = yyLineNr; // used for source reference + current->startLine = -1; // ??? what is startLine for? + current->args.resize(0); + current->argList->clear(); + docBlock.resize(0); +} + +/*! Adds interface to the root entry. + * \note Code was brought to this procedure from the parser, + * because there was/is idea to use it in several parts of the parser. + */ +static void addInterface(QCString name, InterfaceType type) +{ + if (YY_START == Start) + { + addModule(NULL); + yy_push_state(ModuleBody); //anon program + } + + current->section = Entry::CLASS_SEC; // was Entry::INTERFACE_SEC; + current->spec = Entry::Interface; + current->name = name; + + switch (type) + { + case IF_ABSTRACT: + current->type = "abstract"; + break; + + case IF_GENERIC: + current->type = "generic"; + break; + + case IF_SPECIFIC: + case IF_NONE: + default: + current->type = ""; + } + + /* if type is part of a module, mod name is necessary for output */ + if ((current_root) && + (current_root->section == Entry::CLASS_SEC || + current_root->section == Entry::NAMESPACE_SEC)) + { + current->name= current_root->name + "::" + current->name; + } + + current->fileName = yyFileName; + current->bodyLine = yyLineNr; + addCurrentEntry(); +} + + +//----------------------------------------------------------------------------- + +/*! Get the argument \a name. + */ +static Argument* getParameter(const QCString &name) +{ + // std::cout<<"addFortranParameter(): "<<name<<" DOCS:"<<(docs.isNull()?QCString("null"):docs)<<std::endl; + Argument *ret = 0; + if (current_root->argList==0) return 0; + ArgumentListIterator ali(*current_root->argList); + Argument *a; + for (ali.toFirst();(a=ali.current());++ali) + { + if (a->name.lower()==name.lower()) + { + ret=a; + //printf("parameter found: %s\n",(const char*)name); + break; + } + } // for + return ret; +} + + //---------------------------------------------------------------------------- +static void startCommentBlock(bool brief) +{ + if (brief) + { + current->briefFile = yyFileName; + current->briefLine = yyLineNr; + } + else + { + current->docFile = yyFileName; + current->docLine = yyLineNr; + } +} + +//---------------------------------------------------------------------------- + +static void handleCommentBlock(const QCString &doc,bool brief) +{ + docBlockInBody = FALSE; + bool needsEntry = FALSE; + static bool hideInBodyDocs = Config_getBool("HIDE_IN_BODY_DOCS"); + int position=0; + if (docBlockInBody && hideInBodyDocs) return; + //fprintf(stderr,"call parseCommentBlock [%s]\n",doc.data()); + int lineNr = brief ? current->briefLine : current->docLine; + while (parseCommentBlock( + g_thisParser, + docBlockInBody ? last_entry : current, + doc, // text + yyFileName, // file + lineNr, + docBlockInBody ? FALSE : brief, + docBlockInBody ? FALSE : docBlockJavaStyle, + docBlockInBody, + defaultProtection, + position, + needsEntry + )) + { + //fprintf(stderr,"parseCommentBlock position=%d [%s] needsEntry=%d\n",position,doc.data()+position,needsEntry); + if (needsEntry) addCurrentEntry(); + } + //fprintf(stderr,"parseCommentBlock position=%d [%s] needsEntry=%d\n",position,doc.data()+position,needsEntry); + + if (needsEntry) addCurrentEntry(); +} + +//---------------------------------------------------------------------------- + +static void subrHandleCommentBlock(const QCString &doc,bool brief) +{ + Entry *tmp_entry = current; + current = subrCurrent.first(); // temporarily switch to the entry of the subroutine / function + if (docBlock.stripWhiteSpace().find("\\param") == 0) + { + handleCommentBlock("\n\n"+doc,brief); + } + else if (docBlock.stripWhiteSpace().find("@param") == 0) + { + handleCommentBlock("\n\n"+doc,brief); + } + else + { + int dir1 = modifiers[current_root][argName.lower()].direction; + handleCommentBlock(QCString("\n\n@param ") + directionParam[dir1] + " " + + argName + " " + doc,brief); + } + current=tmp_entry; +} + +//---------------------------------------------------------------------------- +static int level=0; +static void debugCompounds(Entry *rt) // print Entry structure (for debugging) +{ + level++; + printf("%d) debugCompounds(%s) line %d\n",level, rt->name.data(), rt->bodyLine); + EntryListIterator eli(*rt->children()); + Entry *ce; + for (;(ce=eli.current());++eli) + { + debugCompounds(ce); + } +level--; +} + + +static void parseMain(const char *fileName,const char *fileBuf,Entry *rt) +{ + initParser(); + + defaultProtection = Public; + inputString = fileBuf; + inputPosition = 0; + inputStringPrepass = NULL; + inputPositionPrepass = 0; + + //anonCount = 0; // don't reset per file + mtype = Method; + gstat = FALSE; + virt = Normal; + current_root = rt; + global_root = rt; + inputFile.setName(fileName); + if (inputFile.open(IO_ReadOnly)) + { + isFixedForm = recognizeFixedForm(fileBuf); + + if (isFixedForm) + { + msg("Prepassing fixed form of %s\n", fileName); + //printf("---strlen=%d\n", strlen(fileBuf)); + //clock_t start=clock(); + + inputString = prepassFixedForm(fileBuf); + + //clock_t end=clock(); + //printf("CPU time used=%f\n", ((double) (end-start))/CLOCKS_PER_SEC); + } + + yyLineNr= 1 ; + yyFileName = fileName; + msg("Parsing file %s...\n",yyFileName.data()); + + startScope(rt); // implies current_root = rt + initParser(); + groupEnterFile(yyFileName,yyLineNr); + + current = new Entry; + current->lang = SrcLangExt_Fortran; + current->name = yyFileName; + current->section = Entry::SOURCE_SEC; + current_root->addSubEntry(current); + file_root = current; + current = new Entry; + current->lang = SrcLangExt_Fortran; + + fscanYYrestart( fscanYYin ); + { + BEGIN( Start ); + } + + fscanYYlex(); + groupLeaveFile(yyFileName,yyLineNr); + + endScope(current_root, TRUE); // TRUE - global root + + //debugCompounds(rt); //debug + + rt->program.resize(0); + delete current; current=0; + moduleProcedures.clear(); + if (isFixedForm) { + free((char*)inputString); + inputString=NULL; + } + + inputFile.close(); + } +} + +//---------------------------------------------------------------------------- + +void FortranLanguageScanner::parseInput(const char *fileName,const char *fileBuf,Entry *root) +{ + g_thisParser = this; + ::parseMain(fileName,fileBuf,root); +} + +void FortranLanguageScanner::parseCode(CodeOutputInterface & codeOutIntf, + const char * scopeName, + const QCString & input, + bool isExampleBlock, + const char * exampleName, + FileDef * fileDef, + int startLine, + int endLine, + bool inlineFragment, + MemberDef *memberDef, + bool showLineNumbers + ) +{ + ::parseFortranCode(codeOutIntf,scopeName,input,isExampleBlock,exampleName, + fileDef,startLine,endLine,inlineFragment,memberDef, + showLineNumbers); +} + +bool FortranLanguageScanner::needsPreprocessing(const QCString &extension) +{ + return extension!=extension.lower(); // use preprocessor only for upper case extensions +} +void FortranLanguageScanner::resetCodeParserState() +{ + ::resetFortranCodeParserState(); +} + +void FortranLanguageScanner::parsePrototype(const char *text) +{ + (void)text; +} + +static void scanner_abort() +{ + fprintf(stderr,"********************************************************************\n"); + fprintf(stderr,"Error in file %s line: %d, state: %d\n",yyFileName.data(),yyLineNr,YY_START); + fprintf(stderr,"********************************************************************\n"); + + EntryListIterator eli(*global_root->children()); + Entry *ce; + bool start=FALSE; + + for (;(ce=eli.current());++eli) + { + if (ce == file_root) start=TRUE; + if (start) ce->reset(); + } + + // dummy call to avoid compiler warning + (void)yy_top_state(); + + return; + //exit(-1); +} + +//---------------------------------------------------------------------------- + +#if !defined(YY_FLEX_SUBMINOR_VERSION) +//---------------------------------------------------------------------------- +extern "C" { // some bogus code to keep the compiler happy + void fscannerYYdummy() { yy_flex_realloc(0,0); } +} +#endif + diff --git a/trunk/src/ftextstream.cpp b/trunk/src/ftextstream.cpp new file mode 100644 index 0000000..f72185f --- /dev/null +++ b/trunk/src/ftextstream.cpp @@ -0,0 +1,259 @@ +#include "ftextstream.h" +#include <qfile.h> + +//---------------------------------------------------------------------------- + +class QGStringBuffer : public QIODevice +{ + public: + QGStringBuffer( QGString* str ); + ~QGStringBuffer(); + bool open( int m ); + void close(); + void flush(); + uint size() const; + int at() const; + bool at( int pos ); + int readBlock( char *, uint) { return -1; } + int writeBlock( const char *p, uint len ); + int getch() { return -1; } + int putch( int ch ); + int ungetch( int ) { return -1; } + + protected: + QGString* m_str; + + private: // Disabled copy constructor and operator= + QGStringBuffer( const QGStringBuffer & ); + QGStringBuffer &operator=( const QGStringBuffer & ); +}; + +QGStringBuffer::QGStringBuffer( QGString* str ) : m_str(str) +{ + //printf("QGStringBuffer::QGStringBuffer(%p)\n",str); +} + +QGStringBuffer::~QGStringBuffer() +{ +} + +bool QGStringBuffer::open( int m ) +{ + if ( !m_str ) + { +#if defined(CHECK_STATE) + qWarning( "QGStringBuffer::open: No string" ); +#endif + return FALSE; + } + if ( isOpen() ) + { // buffer already open +#if defined(CHECK_STATE) + qWarning( "QGStringBuffer::open: Buffer already open" ); +#endif + return FALSE; + } + setMode( m ); + if ( m & IO_Truncate ) + { // truncate buffer + m_str->truncate( 0 ); + } + if ( m & IO_Append ) + { // append to end of buffer + ioIndex = m_str->length(); + } + else + { + ioIndex = 0; + } + setState( IO_Open ); + setStatus( 0 ); + return TRUE; +} + +void QGStringBuffer::close() +{ + if ( isOpen() ) + { + setFlags( IO_Direct ); + ioIndex = 0; + } +} + +void QGStringBuffer::flush() +{ +} + +uint QGStringBuffer::size() const +{ + return m_str ? m_str->length() : 0; +} + +int QGStringBuffer::at() const +{ + return ioIndex; +} + +bool QGStringBuffer::at( int pos ) +{ +#if defined(CHECK_STATE) + if ( !isOpen() ) + { + qWarning( "QGStringBuffer::at: Buffer is not open" ); + return FALSE; + } +#endif + if ( (uint)pos >= m_str->length() ) + { +#if defined(CHECK_RANGE) + qWarning( "QGStringBuffer::at: Index %d out of range", pos ); +#endif + return FALSE; + } + + ioIndex = pos; + return TRUE; +} + +int QGStringBuffer::writeBlock( const char *p, uint len ) +{ + //printf("QGStringBuffer::writeBlock(%p,%d) m_str=%p ioIndex=%d\n",p,len, + // m_str,ioIndex); + m_str->enlarge(ioIndex+len+1); + memcpy(m_str->data()+ioIndex,p,len); + ioIndex+=len; + m_str->data()[ioIndex]='\0'; + m_str->setLen(ioIndex); + return len; +} + +int QGStringBuffer::putch( int ch ) +{ + //printf("QGStringBuffer::putch(%d) m_str=%p ioIndex=%d\n", + // ch,m_str,ioIndex); + m_str->enlarge(ioIndex+2); + m_str->data()[ioIndex] = (char)ch; + ioIndex++; + m_str->data()[ioIndex] = '\0'; + m_str->setLen(ioIndex); + return ch; +} + + +//---------------------------------------------------------------------------- + +FTextStream::FTextStream() +{ + m_dev = 0; + m_owndev = FALSE; +} + +FTextStream::FTextStream( QIODevice *dev ) +{ + m_dev = dev; + m_owndev = FALSE; +} + +FTextStream::FTextStream( QGString *s ) +{ + m_dev = new QGStringBuffer(s); + ((QGStringBuffer*)m_dev)->open( IO_WriteOnly ); + m_owndev = TRUE; +} + +FTextStream::FTextStream( FILE *fh ) +{ + m_dev = new QFile; + ((QFile *)m_dev)->open( IO_WriteOnly, fh); +} + +FTextStream::~FTextStream() +{ + if (m_owndev) delete m_dev; + m_dev = 0; +} + +QIODevice *FTextStream::device() const +{ + return m_dev; +} + +void FTextStream::setDevice( QIODevice *dev ) +{ + if (m_owndev) + { + delete m_dev; + m_owndev = FALSE; + } + m_dev = dev; +} + +void FTextStream::unsetDevice() +{ + setDevice(0); +} + +FTextStream &FTextStream::output_int( ulong n, bool neg ) +{ + char buf[20]; + char *p = &buf[19]; + *p = '\0'; + if ( neg ) + { + n = (ulong)(-(long)n); + } + do + { + *--p = ((int)(n%10)) + '0'; + n /= 10; + } while ( n ); + if ( neg ) *--p = '-'; + return operator<<(p); +} + +FTextStream &FTextStream::operator<<( signed short i ) +{ + return output_int( i, i < 0 ); +} + +FTextStream &FTextStream::operator<<( unsigned short i ) +{ + return output_int( i, FALSE ); +} + +FTextStream &FTextStream::operator<<( signed int i ) +{ + return output_int( i, i < 0 ); +} + +FTextStream &FTextStream::operator<<( unsigned int i ) +{ + return output_int( i, FALSE ); +} + +FTextStream &FTextStream::operator<<( signed long i ) +{ + return output_int( i, i < 0 ); +} + +FTextStream &FTextStream::operator<<( unsigned long i ) +{ + return output_int( i, FALSE ); +} + +FTextStream &FTextStream::operator<<( float f ) +{ + return *this << (double)f; +} + +FTextStream &FTextStream::operator<<( double d ) +{ + char buf[64]; + sprintf(buf,"%f",d); + return *this << buf; +} + + + + + diff --git a/trunk/src/ftextstream.h b/trunk/src/ftextstream.h new file mode 100644 index 0000000..63ef244 --- /dev/null +++ b/trunk/src/ftextstream.h @@ -0,0 +1,82 @@ +#ifndef FTEXTSTREAM_H +#define FTEXTSTREAM_H + +#include "qtbc.h" +#include "qiodevice.h" +#include "qstring.h" +#include "qgstring.h" +#include <stdio.h> + +/** @brief Simplified and optimized version of QTextStream */ +class FTextStream +{ + public: + FTextStream(); + FTextStream( QIODevice * ); + FTextStream( QGString * ); + FTextStream( FILE * ); + virtual ~FTextStream(); + + QIODevice *device() const; + void setDevice( QIODevice * ); + void unsetDevice(); + + FTextStream &operator<<( char ); + FTextStream &operator<<( const char *); + FTextStream &operator<<( const QString & ); + FTextStream &operator<<( const QCString & ); + FTextStream &operator<<( signed short ); + FTextStream &operator<<( unsigned short ); + FTextStream &operator<<( signed int ); + FTextStream &operator<<( unsigned int ); + FTextStream &operator<<( signed long ); + FTextStream &operator<<( unsigned long ); + FTextStream &operator<<( float ); + FTextStream &operator<<( double ); + + private: + QIODevice *m_dev; + bool m_owndev; + FTextStream &output_int( ulong n, bool neg ); + + private: // Disabled copy constructor and operator= +#if defined(Q_DISABLE_COPY) + FTextStream( const FTextStream & ); + FTextStream &operator=( const FTextStream & ); +#endif +}; + +inline FTextStream &FTextStream::operator<<( char c) +{ + m_dev->putch(c); + return *this; +} + +inline FTextStream &FTextStream::operator<<( const char* s) +{ + uint len = qstrlen( s ); + m_dev->writeBlock( s, len ); + return *this; +} + +inline FTextStream &FTextStream::operator<<( const QString & s) +{ + return operator<<(s.data()); +} + +inline FTextStream &FTextStream::operator<<( const QCString &s) +{ + return operator<<(s.data()); +} + +typedef FTextStream & (*FTSFUNC)(FTextStream &);// manipulator function + +inline FTextStream &operator<<( FTextStream &s, FTSFUNC f ) +{ return (*f)( s ); } + +inline FTextStream &endl( FTextStream & s) +{ + return s << '\n'; +} + +#endif // FTEXTSTREAM_H diff --git a/trunk/src/ftvhelp.cpp b/trunk/src/ftvhelp.cpp new file mode 100644 index 0000000..4816b50 --- /dev/null +++ b/trunk/src/ftvhelp.cpp @@ -0,0 +1,992 @@ +/****************************************************************************** + * ftvhelp.cpp,v 1.0 2000/09/06 16:09:00 + * + * Copyright (C) 1997-2012 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. + * + * Original version contributed by Kenney Wong <kwong@ea.com> + * Modified by Dimitri van Heesch + * + * Folder Tree View for offline help on browsers that do not support HTML Help. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <qlist.h> +#include <qdict.h> +#include <qfileinfo.h> + +#include "ftvhelp.h" +#include "config.h" +#include "message.h" +#include "doxygen.h" +#include "language.h" +#include "htmlgen.h" +#include "layout.h" +#include "pagedef.h" + +#define MAX_INDENT 1024 + + +static const char navtree_script[]= +#include "navtree_js.h" +; + +static const char resize_script[]= +#include "resize_js.h" +; + +static const char navtree_css[]= +#include "navtree_css.h" +; + +static unsigned char blank_png[352] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +static unsigned char folderopen_png[528] = +{ + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,228,195,193,190,187,218,255,255,255,255,255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,195,215,221,225,225,178,176,176,175,176,178,180,255,255,255,255,255,255, + 255,255,255,255,255,255,189,206,215,219,226,220,214,212,207,204,200,176,255,255,255,255,255,255, + 255,255,255,255,168,154,153,153,152,152,151,149,150,150,149,147,146,145,145,167,255,255,255,255, + 255,255,255,255,146,187,187,188,187,187,185,183,183,182,179,178,175,173,174,145,255,255,255,255, + 255,255,255,255,146,180,182,182,181,181,179,178,176,174,173,171,169,170,168,144,255,255,255,255, + 255,255,255,255,144,173,176,176,177,175,175,174,171,170,168,168,166,166,164,143,255,255,255,255, + 255,255,255,255,142,168,170,171,170,170,169,168,166,166,165,163,163,164,162,142,255,255,255,255, + 255,255,255,255,141,162,166,164,164,165,163,163,161,161,161,161,161,160,159,141,255,255,255,255, + 255,255,255,255,138,157,159,159,158,158,158,157,157,157,157,156,157,157,155,138,255,255,255,255, + 255,255,255,255,137,154,153,154,154,153,154,154,154,153,154,154,154,154,154,137,255,255,255,255, + 255,255,255,255,137,154,154,154,154,154,154,154,153,154,154,153,153,153,154,137,255,255,255,255, + 255,255,255,255,137,125,125,125,125,124,125,124,124,125,124,124,125,124,125,138,255,255,255,255, + 255,255,255,255,212,209,204,199,193,190,186,183,180,181,185,188,192,197,202,203,255,255,255,255, + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255 +}; + +static unsigned char folderopen_a_png[528] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0,255,255,255,255,255,255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 0, 0, 0, 0, + 0, 0, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 0, 0, 0, 0, + 0, 0, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 0, 0, 0, 0, + 0, 0, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 0, 0, 0, 0, + 0, 0, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 0, 0, 0, 0, + 0, 0, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 0, 0, 0, 0, + 0, 0, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 0, 0, 0, 0, + 0, 0, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 0, 0, 0, 0, + 0, 0, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 0, 0, 0, 0, + 0, 0, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 0, 0, 0, 0, + 0, 0, 0, 0,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +static unsigned char folderclosed_png[528] = +{ + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, + 255,255,255,255,255,197,155,155,155,155,196,255,255,255,255,255,255,255,255,255,255,255,255,255, + 255,255,255,255,255,155,191,191,191,192,155,255,255,255,255,255,255,255,255,255,255,255,255,255, + 255,255,255,255,168,144,180,180,181,180,145,145,146,145,146,146,146,146,145,167,255,255,255,255, + 255,255,255,255,147,225,226,226,225,226,225,221,221,219,215,214,212,211,213,145,255,255,255,255, + 255,255,255,255,147,212,211,211,210,211,210,205,206,205,201,201,199,196,201,145,255,255,255,255, + 255,255,255,255,146,204,203,204,203,203,202,200,200,197,197,196,195,194,196,145,255,255,255,255, + 255,255,255,255,146,202,200,201,201,200,199,198,198,195,194,194,193,192,194,145,255,255,255,255, + 255,255,255,255,145,200,196,196,196,195,195,193,192,192,190,189,189,189,191,143,255,255,255,255, + 255,255,255,255,143,192,191,190,190,189,189,188,186,187,186,185,185,185,187,142,255,255,255,255, + 255,255,255,255,142,186,184,183,182,183,182,183,180,181,181,181,181,181,182,141,255,255,255,255, + 255,255,255,255,138,177,175,176,176,177,177,176,175,174,175,175,175,174,176,138,255,255,255,255, + 255,255,255,255,138,173,169,170,168,170,169,170,170,169,171,171,171,171,174,137,255,255,255,255, + 255,255,255,255,138,166,163,163,162,162,162,162,162,162,164,163,163,163,166,137,255,255,255,255, + 255,255,255,255,137,124,124,124,125,124,124,124,125,125,124,124,125,124,125,138,255,255,255,255, + 255,255,255,255,231,231,228,225,222,220,218,216,214,215,217,219,221,224,227,226,255,255,255,255, + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255 +}; + +static unsigned char folderclosed_a_png[528] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0,255,255,255,255,255,255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0,255,255,255,255,255,255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 0, 0, 0, 0, + 0, 0, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 0, 0, 0, 0, + 0, 0, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 0, 0, 0, 0, + 0, 0, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 0, 0, 0, 0, + 0, 0, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 0, 0, 0, 0, + 0, 0, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 0, 0, 0, 0, + 0, 0, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 0, 0, 0, 0, + 0, 0, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 0, 0, 0, 0, + 0, 0, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 0, 0, 0, 0, + 0, 0, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 0, 0, 0, 0, + 0, 0, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 0, 0, 0, 0, + 0, 0, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 0, 0, 0, 0, + 0, 0, 0, 0,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +static unsigned char doc_png[528] = +{ + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, + 255,255,255,255,255,218,214,208,208,204,191,179,190,197,209,231,255,255,255,255,255,255,255,255, + 255,255,255,255,255,195,224,226,226,222,214,204,181,203,229,188,225,255,255,255,255,255,255,255, + 255,255,255,255,255,198,226,228,227,227,224,215,203,180,252,229,184,224,255,255,255,255,255,255, + 255,255,255,255,255,198,229,230,229,229,228,224,214,154,252,252,229,187,235,255,255,255,255,255, + 255,255,255,255,255,198,232,233,233,232,231,230,223,176,154,144,165,177,216,255,255,255,255,255, + 255,255,255,255,255,198,236,236,216,226,238,219,232,225,209,190,189,166,193,255,255,255,255,255, + 255,255,255,255,255,198,239,240,178,177,230,175,169,184,188,219,208,189,187,255,255,255,255,255, + 255,255,255,255,255,198,241,242,240,218,237,236,240,235,241,244,221,208,182,255,255,255,255,255, + 255,255,255,255,255,198,243,243,188,154,183,158,166,140,185,198,231,219,177,255,255,255,255,255, + 255,255,255,255,255,198,243,245,248,228,241,241,226,249,237,227,239,232,177,255,255,255,255,255, + 255,255,255,255,255,198,244,246,213,172,163,149,171,200,167,149,242,239,177,255,255,255,255,255, + 255,255,255,255,255,198,249,248,240,218,237,236,240,235,241,244,244,242,177,255,255,255,255,255, + 255,255,255,255,255,198,249,251,188,155,184,158,166,140,185,198,246,244,177,255,255,255,255,255, + 255,255,255,255,255,198,251,253,248,228,241,241,226,249,237,227,249,246,177,255,255,255,255,255, + 255,255,255,255,255,196,253,252,252,252,252,251,251,250,250,249,249,248,175,255,255,255,255,255, + 255,255,255,255,255,194, 64, 30, 37, 37, 37, 37, 37, 37, 37, 37, 30, 64,188,255,255,255,255,255, + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255 +}; + +static unsigned char doc_a_png[528] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0,255,255,255,255,255,255,255,255,255,255,255, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +static unsigned char arrow_right_png[352] = +{ + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, + 255,255,255,152,152,255,255,255,255,255,255,255,255,255,255,255, + 255,255,255,152,152,152,152,255,255,255,255,255,255,255,255,255, + 255,255,255,152,152,152,152,152,255,255,255,255,255,255,255,255, + 255,255,255,152,152,152,152,152,152,152,255,255,255,255,255,255, + 255,255,255,152,152,152,152,152,152,152,152,255,255,255,255,255, + 255,255,255,152,152,152,152,152,152,152,255,255,255,255,255,255, + 255,255,255,152,152,152,152,152,255,255,255,255,255,255,255,255, + 255,255,255,152,152,152,152,255,255,255,255,255,255,255,255,255, + 255,255,255,152,152,255,255,255,255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255 +}; + +static unsigned char arrow_right_a_png[352] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0,223, 75, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0,255,255,176, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0,255,255,255,248,117, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0,255,255,255,255,255,211, 60, 0, 0, 0, 0, 0, 0, + 0, 0, 0,255,255,255,255,255,255,255, 77, 0, 0, 0, 0, 0, + 0, 0, 0,255,255,255,255,255,211, 60, 0, 0, 0, 0, 0, 0, + 0, 0, 0,255,255,255,248,117, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0,255,255,176, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0,223, 75, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +static unsigned char arrow_down_png[352] = +{ + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, + 255,255,255,152,152,152,152,152,152,152,152,152,255,255,255,255, + 255,255,255,152,152,152,152,152,152,152,152,152,255,255,255,255, + 255,255,255,255,152,152,152,152,152,152,152,255,255,255,255,255, + 255,255,255,255,152,152,152,152,152,152,152,255,255,255,255,255, + 255,255,255,255,255,152,152,152,152,152,255,255,255,255,255,255, + 255,255,255,255,255,255,152,152,152,255,255,255,255,255,255,255, + 255,255,255,255,255,255,152,152,152,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,152,255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255 +}; + +static unsigned char arrow_down_a_png[352] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0,231,255,255,255,255,255,255,255,216, 0, 0, 0, 0, + 0, 0, 0, 87,255,255,255,255,255,255,255, 65, 0, 0, 0, 0, + 0, 0, 0, 0,186,255,255,255,255,255,164, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 38,251,255,255,255,241, 25, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0,127,255,255,255,107, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0,221,255,204, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 72,253, 52, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 77, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +#define SPLITBAR_LINE 170,242,224,202,183,170 +#define SPLITBAR_BLOCK2 SPLITBAR_LINE , SPLITBAR_LINE +#define SPLITBAR_BLOCK4 SPLITBAR_BLOCK2 , SPLITBAR_BLOCK2 +#define SPLITBAR_BLOCK8 SPLITBAR_BLOCK4 , SPLITBAR_BLOCK4 +#define SPLITBAR_BLOCK16 SPLITBAR_BLOCK8 , SPLITBAR_BLOCK8 +#define SPLITBAR_BLOCK32 SPLITBAR_BLOCK16 , SPLITBAR_BLOCK16 + +#define SPLITBAR_ALTLINE1 170,242,170,202,170,170 +#define SPLITBAR_ALTLINE2 170,243,224,255,183,255 +#define SPLITBAR_ALTBLOCK2 SPLITBAR_ALTLINE1 , SPLITBAR_ALTLINE2 +#define SPLITBAR_ALTBLOCK4 SPLITBAR_ALTBLOCK2 , SPLITBAR_ALTBLOCK2 +#define SPLITBAR_ALTBLOCK8 SPLITBAR_ALTBLOCK4 , SPLITBAR_ALTBLOCK4 + +static unsigned char splitbar_png[32*32*6] = +{ + SPLITBAR_BLOCK32, + SPLITBAR_BLOCK32, + SPLITBAR_BLOCK32, + SPLITBAR_BLOCK32, + SPLITBAR_BLOCK32, + SPLITBAR_BLOCK32, + SPLITBAR_BLOCK32, + SPLITBAR_BLOCK32, + SPLITBAR_BLOCK32, + SPLITBAR_BLOCK32, + SPLITBAR_BLOCK32, + SPLITBAR_BLOCK32, + SPLITBAR_BLOCK32, + SPLITBAR_BLOCK32, + SPLITBAR_BLOCK32, + SPLITBAR_BLOCK8, + SPLITBAR_BLOCK8, + SPLITBAR_ALTBLOCK8, + SPLITBAR_BLOCK8, + SPLITBAR_BLOCK32, + SPLITBAR_BLOCK32, + SPLITBAR_BLOCK32, + SPLITBAR_BLOCK32, + SPLITBAR_BLOCK32, + SPLITBAR_BLOCK32, + SPLITBAR_BLOCK32, + SPLITBAR_BLOCK32, + SPLITBAR_BLOCK32, + SPLITBAR_BLOCK32, + SPLITBAR_BLOCK32, + SPLITBAR_BLOCK32, + SPLITBAR_BLOCK32, + SPLITBAR_BLOCK32, + SPLITBAR_BLOCK32, + SPLITBAR_BLOCK32 +}; + +struct FTVImageInfo +{ + const char *alt; + const char *name; + const unsigned char *data; + unsigned int len; + unsigned short width, height; +}; + +//extern FTVImageInfo image_info[]; + +#define FTVIMG_blank 0 +#define FTVIMG_doc 1 +#define FTVIMG_folderclosed 2 +#define FTVIMG_folderopen 3 +#define FTVIMG_lastnode 4 +#define FTVIMG_link 5 +#define FTVIMG_mlastnode 6 +#define FTVIMG_mnode 7 +#define FTVIMG_node 8 +#define FTVIMG_plastnode 9 +#define FTVIMG_pnode 10 +#define FTVIMG_vertline 11 + +#define FTV_S(name) #name +#define FTV_ICON_FILE(name) "ftv2" FTV_S(name) ".png" +#define FTVIMG_INDEX(name) FTVIMG_ ## name +#define FTV_INFO(name) ( image_info[FTVIMG_INDEX(name)] ) +#define FTV_IMGATTRIBS(name) \ + "src=\"" FTV_ICON_FILE(name) "\" " \ + "alt=\"" << FTV_INFO(name).alt << "\" " \ + "width=\"" << FTV_INFO(name).width << "\" " \ + "height=\"" << FTV_INFO(name).height << "\" " + + +static FTVImageInfo image_info[] = +{ + { " ", "ftv2blank.png", 0 /*ftv2blank_png*/ ,174,16,22 }, + { "*", "ftv2doc.png", 0 /*ftv2doc_png*/ ,255,24,22 }, + { "+", "ftv2folderclosed.png", 0 /*ftv2folderclosed_png*/ ,259,24,22 }, + { "-", "ftv2folderopen.png", 0 /*ftv2folderopen_png*/ ,261,24,22 }, + { "\\", "ftv2lastnode.png", 0 /*ftv2lastnode_png*/ ,233,16,22 }, + { "-", "ftv2link.png", 0 /*ftv2link_png*/ ,358,24,22 }, + { "\\", "ftv2mlastnode.png", 0 /*ftv2mlastnode_png*/ ,160,16,22 }, + { "o", "ftv2mnode.png", 0 /*ftv2mnode_png*/ ,194,16,22 }, + { "o", "ftv2node.png", 0 /*ftv2node_png*/ ,235,16,22 }, + { "\\", "ftv2plastnode.png", 0 /*ftv2plastnode_png*/ ,165,16,22 }, + { "o", "ftv2pnode.png", 0 /*ftv2pnode_png*/ ,200,16,22 }, + { "|", "ftv2vertline.png", 0 /*ftv2vertline_png*/ ,229,16,22 }, + { 0, 0, 0, 0, 0, 0 } +}; + +static ColoredImgDataItem ftv_image_data[] = +{ + { "ftv2blank.png", 16, 22, blank_png, blank_png }, + { "ftv2doc.png", 24, 22, doc_png, doc_a_png }, + { "ftv2folderclosed.png", 24, 22, folderclosed_png, folderclosed_a_png }, + { "ftv2folderopen.png", 24, 22, folderopen_png, folderopen_a_png }, + { "ftv2lastnode.png", 16, 22, blank_png, blank_png }, + { "ftv2link.png", 24, 22, doc_png, doc_a_png }, + { "ftv2mlastnode.png", 16, 22, arrow_down_png, arrow_down_a_png }, + { "ftv2mnode.png", 16, 22, arrow_down_png, arrow_down_a_png }, + { "ftv2node.png", 16, 22, blank_png, blank_png }, + { "ftv2plastnode.png", 16, 22, arrow_right_png, arrow_right_a_png }, + { "ftv2pnode.png", 16, 22, arrow_right_png, arrow_right_a_png }, + { "ftv2vertline.png", 16, 22, blank_png, blank_png }, + { "ftv2splitbar.png", 6,1024, splitbar_png, 0 }, + { 0, 0, 0, 0, 0 } +}; + +static int folderId=1; + +struct FTVNode +{ + FTVNode(bool dir,const char *r,const char *f,const char *a,const char *n,bool sepIndex,bool navIndex) + : isLast(TRUE), isDir(dir),ref(r),file(f),anchor(a),name(n), index(0), + parent(0), separateIndex(sepIndex), addToNavIndex(navIndex) { children.setAutoDelete(TRUE); } + bool isLast; + bool isDir; + QCString ref; + QCString file; + QCString anchor; + QCString name; + int index; + QList<FTVNode> children; + FTVNode *parent; + bool separateIndex; + bool addToNavIndex; +}; + + +//---------------------------------------------------------------------------- + +/*! Constructs an ftv help object. + * The object has to be \link initialize() initialized\endlink before it can + * be used. + */ +FTVHelp::FTVHelp(bool TLI) +{ + /* initial depth */ + m_indentNodes = new QList<FTVNode>[MAX_INDENT]; + m_indentNodes[0].setAutoDelete(TRUE); + m_indent=0; + m_topLevelIndex = TLI; +} + +/*! Destroys the ftv help object. */ +FTVHelp::~FTVHelp() +{ + delete[] m_indentNodes; +} + +/*! This will create a folder tree view table of contents file (tree.js). + * \sa finalize() + */ +void FTVHelp::initialize() +{ +} + +/*! Finalizes the FTV help. This will finish and close the + * contents file (index.js). + * \sa initialize() + */ +void FTVHelp::finalize() +{ + generateTreeView(); +} + +/*! Increase the level of the contents hierarchy. + * This will start a new sublist in contents file. + * \sa decContentsDepth() + */ +void FTVHelp::incContentsDepth() +{ + //printf("incContentsDepth() indent=%d\n",m_indent); + m_indent++; + ASSERT(m_indent<MAX_INDENT); +} + +/*! Decrease the level of the contents hierarchy. + * This will end the current sublist. + * \sa incContentsDepth() + */ +void FTVHelp::decContentsDepth() +{ + //printf("decContentsDepth() indent=%d\n",m_indent); + ASSERT(m_indent>0); + if (m_indent>0) + { + m_indent--; + QList<FTVNode> *nl = &m_indentNodes[m_indent]; + FTVNode *parent = nl->getLast(); + if (parent) + { + QList<FTVNode> *children = &m_indentNodes[m_indent+1]; + while (!children->isEmpty()) + { + parent->children.append(children->take(0)); + } + } + } +} + +/*! Add a list item to the contents file. + * \param isDir TRUE if the item is a directory, FALSE if it is a text + * \param ref the URL of to the item. + * \param file the file containing the definition of the item + * \param anchor the anchor within the file. + * \param name the name of the item. + * \param separateIndex put the entries in a separate index file + * \param addToNavIndex add this entry to the quick navigation index + */ +void FTVHelp::addContentsItem(bool isDir, + const char *name, + const char *ref, + const char *file, + const char *anchor, + bool separateIndex, + bool addToNavIndex + ) +{ + //printf("addContentsItem(%s,%s,%s,%s)\n",name,ref,file,anchor); + QList<FTVNode> *nl = &m_indentNodes[m_indent]; + FTVNode *newNode = new FTVNode(isDir,ref,file,anchor,name,separateIndex,addToNavIndex); + if (!nl->isEmpty()) + { + nl->getLast()->isLast=FALSE; + } + nl->append(newNode); + newNode->index = nl->count()-1; + if (m_indent>0) + { + QList<FTVNode> *pnl = &m_indentNodes[m_indent-1]; + newNode->parent = pnl->getLast(); + } + +} + +static QCString node2URL(FTVNode *n) +{ + QCString url = n->file; + if (!url.isEmpty() && url.at(0)=='!') // relative URL + { + // remove leading ! + url = url.mid(1); + } + else if (!url.isEmpty() && url.at(0)=='^') // absolute URL + { + // skip, keep ^ in the output + } + else // local file (with optional anchor) + { + url+=Doxygen::htmlFileExtension; + if (!n->anchor.isEmpty()) url+="#"+n->anchor; + } + return url; +} + + +void FTVHelp::generateIndent(FTextStream &t, FTVNode *n,int level) +{ + if (n->parent) + { + generateIndent(t,n->parent,level+1); + } + // from the root up to node n do... + if (level==0) // item before a dir or document + { + if (n->isLast) + { + if (n->isDir) + { + t << "<img " << FTV_IMGATTRIBS(plastnode) << "onclick=\"toggleFolder('folder" << folderId << "', this)\"/>"; + } + else + { + t << "<img " << FTV_IMGATTRIBS(lastnode) << "/>"; + } + } + else + { + if (n->isDir) + { + t << "<img " << FTV_IMGATTRIBS(pnode) << "onclick=\"toggleFolder('folder" << folderId << "', this)\"/>"; + } + else + { + t << "<img " << FTV_IMGATTRIBS(node) << "/>"; + } + } + } + else // item at another level + { + if (n->isLast) + { + t << "<img " << FTV_IMGATTRIBS(blank) << "/>"; + } + else + { + t << "<img " << FTV_IMGATTRIBS(vertline) << "/>"; + } + } +} + +void FTVHelp::generateLink(FTextStream &t,FTVNode *n) +{ + //printf("FTVHelp::generateLink(ref=%s,file=%s,anchor=%s\n", + // n->ref.data(),n->file.data(),n->anchor.data()); + if (n->file.isEmpty()) // no link + { + t << "<b>" << convertToHtml(n->name) << "</b>"; + } + else // link into other frame + { + if (!n->ref.isEmpty()) // link to entity imported via tag file + { + t << "<a class=\"elRef\" "; + t << externalLinkTarget() << externalRef("",n->ref,FALSE); + } + else // local link + { + t << "<a class=\"el\" "; + } + t << "href=\""; + t << externalRef("",n->ref,TRUE); + t << node2URL(n); + if (m_topLevelIndex) + t << "\" target=\"basefrm\">"; + else + t << "\" target=\"_self\">"; + t << convertToHtml(n->name); + t << "</a>"; + if (!n->ref.isEmpty()) + { + t << " [external]"; + } + } +} + +void FTVHelp::generateJSLink(FTextStream &t,FTVNode *n) +{ + if (n->file.isEmpty()) // no link + { + t << "\"" << convertToJSString(n->name) << "\", null, "; + } + else // link into other page + { + // TODO: use m_topLevelIndex + t << "\"" << convertToJSString(n->name) << "\", \""; + t << externalRef("",n->ref,TRUE); + t << node2URL(n); + t << "\", "; + } +} + +void FTVHelp::generateTree(FTextStream &t, const QList<FTVNode> &nl,int level) +{ + QCString spaces; + spaces.fill(' ',level*2+8); + QListIterator<FTVNode> nli(nl); + FTVNode *n; + for (nli.toFirst();(n=nli.current());++nli) + { + t << spaces << "<p>"; + generateIndent(t,n,0); + if (n->isDir) + { + t << "<img " << FTV_IMGATTRIBS(folderclosed) << "onclick=\"toggleFolder('folder" << folderId << "', this)\"/>"; + generateLink(t,n); + t << "</p>\n"; + t << spaces << "<div id=\"folder" << folderId << "\">\n"; + folderId++; + generateTree(t,n->children,level+1); + t << spaces << "</div>\n"; + } + else + { + t << "<img " << FTV_IMGATTRIBS(doc) << "/>"; + generateLink(t,n); + t << "</p>\n"; + } + } +} + +static void writePathToNode(FTextStream &tidx,FTVNode *leaf,FTVNode *n) +{ + if (n->parent) + { + writePathToNode(tidx,leaf,n->parent); + } + tidx << n->index; + if (leaf!=n) tidx << ","; +} + +bool childOfHierarchy(const FTVNode *n) +{ + if (n==0) return FALSE; + if (n->file=="hierarchy") + return TRUE; + else + return childOfHierarchy(n->parent); +} + +bool dupOfParent(const FTVNode *n) +{ + if (n->parent==0) return FALSE; + if (n->file==n->parent->file) return TRUE; + return FALSE; +} + +bool FTVHelp::generateJSTree(FTextStream &tidx,FTextStream &t, const QList<FTVNode> &nl,int level,bool &first) +{ + QCString indentStr; + indentStr.fill(' ',level*2); + bool found=FALSE; + QListIterator<FTVNode> nli(nl); + FTVNode *n; + for (nli.toFirst();(n=nli.current());++nli) + { + // terminate previous entry + if (!first) t << "," << endl; + first=FALSE; + + // start entry + if (!found) + { + t << "[" << endl; + } + found=TRUE; + + //if (!n->file.isEmpty() && !childOfHierarchy(n->parent)) + if (n->addToNavIndex) + { + tidx << "," << endl << "\"" << node2URL(n) << "\":["; + writePathToNode(tidx,n,n); + tidx << "]"; + } + + if (n->separateIndex) // store items in a separate file for dynamic loading + { + bool firstChild=TRUE; + t << indentStr << " [ "; + generateJSLink(t,n); + if (n->children.count()>0) // write children to separate file for dynamic loading + { + QCString fileId = n->file; + if (dupOfParent(n)) fileId+="_dup"; + QFile f(Config_getString("HTML_OUTPUT")+"/"+fileId+".js"); + if (f.open(IO_WriteOnly)) + { + FTextStream tt(&f); + QCString varId = fileId; + int i=fileId.findRev('/'); + if (i>=0) varId = varId.mid(i+1); + tt << "var " << varId << " =" << endl; + generateJSTree(tidx,tt,n->children,1,firstChild); + tt << endl << "];"; + } + // write file name without extension as marker + t << "\"" << fileId << "\" ]"; + //if (n->file!="hierarchy") addFilesToIndex(tidx,n); + } + else // no children + { + t << "null ]"; + } + } + else // show items in this file + { + bool firstChild=TRUE; + t << indentStr << " [ "; + generateJSLink(t,n); + bool emptySection = !generateJSTree(tidx,t,n->children,level+1,firstChild); + if (emptySection) + t << "null ]"; + else + t << endl << indentStr << " ] ]"; + } + } + return found; +} + +// new style images +void FTVHelp::generateTreeViewImages() +{ + QCString dname=Config_getString("HTML_OUTPUT"); + writeColoredImgData(dname,ftv_image_data); +} + +// new style scripts +void FTVHelp::generateTreeViewScripts() +{ + // generate navtree.js + { + QCString htmlOutput = Config_getString("HTML_OUTPUT"); + QFile f(htmlOutput+"/navtree.js"); + QFile fidx(htmlOutput+"/navtreeindex.js"); + if (f.open(IO_WriteOnly) && fidx.open(IO_WriteOnly)) + { + FTextStream tidx(&fidx); + tidx << "var NAVTREEINDEX =" << endl; + tidx << "{" << endl; + FTextStream t(&f); + t << "var NAVTREE =" << endl; + t << "[" << endl; + t << " [ "; + QCString &projName = Config_getString("PROJECT_NAME"); + if (projName.isEmpty()) + { + if (Doxygen::mainPage && !Doxygen::mainPage->title().isEmpty()) // Use title of main page as root + { + t << "\"" << convertToJSString(Doxygen::mainPage->title()) << "\", "; + } + else // Use default section title as root + { + LayoutNavEntry *lne = LayoutDocManager::instance().rootNavEntry()->find(LayoutNavEntry::MainPage); + t << "\"" << convertToJSString(lne->title()) << "\", "; + } + } + else // use PROJECT_NAME as root tree element + { + t << "\"" << convertToJSString(projName) << "\", "; + } + t << "\"index" << Doxygen::htmlFileExtension << "\", "; + + tidx << "\"index" << Doxygen::htmlFileExtension << "\":[]"; + + bool first=TRUE; + generateJSTree(tidx,t,m_indentNodes[0],1,first); + + if (first) + t << "]" << endl; + else + t << endl << " ] ]" << endl; + t << "];" << endl; + t << endl << navtree_script; + + tidx << endl << "};" << endl; + } + } + // generate resize.js + { + QFile f(Config_getString("HTML_OUTPUT")+"/resize.js"); + if (f.open(IO_WriteOnly)) + { + FTextStream t(&f); + t << resize_script; + } + } + // generate navtree.css + { + QFile f(Config_getString("HTML_OUTPUT")+"/navtree.css"); + if (f.open(IO_WriteOnly)) + { + FTextStream t(&f); + t << replaceColorMarkers(navtree_css); + } + } +} + +// old style script (used for inline trees) +void FTVHelp::generateScript(FTextStream &t) +{ + t << " <script type=\"text/javascript\">\n"; + t << " <!-- // Hide script from old browsers\n"; + t << " \n"; + + /* User has clicked on a node (folder or +/-) in the tree */ + t << " function toggleFolder(id, imageNode) \n"; + t << " {\n"; + t << " var folder = document.getElementById(id);\n"; + t << " var l = imageNode.src.length;\n"; + /* If the user clicks on the book icon, we move left one image so + * the code (below) will also adjust the '+' icon. + */ + t << " if (imageNode.src.substring(l-20,l)==\"" FTV_ICON_FILE(folderclosed) "\" || \n"; + t << " imageNode.src.substring(l-18,l)==\"" FTV_ICON_FILE(folderopen) "\")\n"; + t << " {\n"; + t << " imageNode = imageNode.previousSibling;\n"; + t << " l = imageNode.src.length;\n"; + t << " }\n"; + t << " if (folder == null) \n"; + t << " {\n"; + t << " } \n"; + /* Node controls a open section, we need to close it */ + t << " else if (folder.style.display == \"block\") \n"; + t << " {\n"; + t << " if (imageNode != null) \n"; + t << " {\n"; + t << " imageNode.nextSibling.src = \"" FTV_ICON_FILE(folderclosed) "\";\n"; + t << " if (imageNode.src.substring(l-13,l) == \"" FTV_ICON_FILE(mnode) "\")\n"; + t << " {\n"; + t << " imageNode.src = \"" FTV_ICON_FILE(pnode) "\";\n"; + t << " }\n"; + t << " else if (imageNode.src.substring(l-17,l) == \"" FTV_ICON_FILE(mlastnode) "\")\n"; + t << " {\n"; + t << " imageNode.src = \"" FTV_ICON_FILE(plastnode) "\";\n"; + t << " }\n"; + t << " }\n"; + t << " folder.style.display = \"none\";\n"; + t << " } \n"; + t << " else \n"; /* section is closed, we need to open it */ + t << " {\n"; + t << " if (imageNode != null) \n"; + t << " {\n"; + t << " imageNode.nextSibling.src = \"" FTV_ICON_FILE(folderopen) "\";\n"; + t << " if (imageNode.src.substring(l-13,l) == \"" FTV_ICON_FILE(pnode) "\")\n"; + t << " {\n"; + t << " imageNode.src = \"" FTV_ICON_FILE(mnode) "\";\n"; + t << " }\n"; + t << " else if (imageNode.src.substring(l-17,l) == \"" FTV_ICON_FILE(plastnode) "\")\n"; + t << " {\n"; + t << " imageNode.src = \"" FTV_ICON_FILE(mlastnode) "\";\n"; + t << " }\n"; + t << " }\n"; + t << " folder.style.display = \"block\";\n"; + t << " }\n"; + t << " }\n"; + t << "\n"; + t << " // End script hiding --> \n"; + t << " </script>\n"; +} + +// write tree inside page +void FTVHelp::generateTreeViewInline(FTextStream &t) +{ + generateScript(t); + t << " <div class=\"directory-alt\">\n"; + t << " <br/>\n"; + t << " <div style=\"display: block;\">\n"; + + generateTree(t,m_indentNodes[0],0); + + t << " </div>\n"; + t << " </div>\n"; +} + +// write old style index.html and tree.html +void FTVHelp::generateTreeView() +{ + generateTreeViewImages(); + generateTreeViewScripts(); +} + diff --git a/trunk/src/ftvhelp.h b/trunk/src/ftvhelp.h new file mode 100644 index 0000000..89e9e62 --- /dev/null +++ b/trunk/src/ftvhelp.h @@ -0,0 +1,80 @@ +/****************************************************************************** + * + * Copyright (C) 1997-2012 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. + * + */ + +/****************************************************************************** + * ftvhelp.h,v 1.0 2000/09/06 16:09:00 + * + * Kenney Wong <kwong@ea.com> + * + * Folder Tree View for offline help on browsers that do not support HTML Help. + */ + +#ifndef FTVHELP_H +#define FTVHELP_H + +#include "qtbc.h" +#include <qtextstream.h> +#include <qlist.h> +#include "index.h" + +class QFile; +struct FTVNode; +class FTextStream; + +/*! A class that generates a dynamic tree view side panel. + */ +class FTVHelp : public IndexIntf +{ + public: + FTVHelp(bool LTI); + ~FTVHelp(); + void initialize(); + void finalize(); + void incContentsDepth(); + void decContentsDepth(); + void addContentsItem(bool isDir, + const char *name, + const char *ref, + const char *file, + const char *anchor, + bool separateIndex=FALSE, + bool addToNavIndex=FALSE); + //void addIndexItem(const char *, const char *, + // const char *, const char *, + // const char *, const MemberDef *) {} + void addIndexItem(Definition *,MemberDef *,const char *) {} + void addIndexFile(const char *) {} + void addImageFile(const char *) {} + void addStyleSheetFile(const char *) {} + void generateTreeView(); + void generateTreeViewInline(FTextStream &t); + static void generateTreeViewImages(); + void generateTreeViewScripts(); + private: + void generateScript(FTextStream &t); + void generateTree(FTextStream &t,const QList<FTVNode> &nl,int level); + bool generateJSTree(FTextStream &tidx,FTextStream &t,const QList<FTVNode> &nl,int level,bool &first); + //bool generateJSTreeTopLevel(FTextStream &tidx,FTextStream &t,const QList<FTVNode> &nl,int level,bool &first); + void generateIndent(FTextStream &t,FTVNode *n,int level); + void generateLink(FTextStream &t,FTVNode *n); + void generateJSLink(FTextStream &t,FTVNode *n); + QList<FTVNode> *m_indentNodes; + int m_indent; + bool m_topLevelIndex; +}; + + +#endif /* FTVHELP_H */ + diff --git a/trunk/src/groupdef.cpp b/trunk/src/groupdef.cpp new file mode 100644 index 0000000..57d04f7 --- /dev/null +++ b/trunk/src/groupdef.cpp @@ -0,0 +1,1475 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#include <ctype.h> +#include <qregexp.h> +#include "qtbc.h" +#include "groupdef.h" +#include "classdef.h" +#include "filedef.h" +#include "classlist.h" +#include "outputlist.h" +#include "namespacedef.h" +#include "language.h" +#include "util.h" +#include "memberlist.h" +#include "message.h" +#include "membergroup.h" +#include "doxygen.h" +#include "pagedef.h" +#include "docparser.h" +#include "searchindex.h" +#include "dot.h" +#include "vhdldocgen.h" +#include "layout.h" +#include "arguments.h" +#include "entry.h" + +//--------------------------------------------------------------------------- + +GroupDef::GroupDef(const char *df,int dl,const char *na,const char *t, + const char *refFileName) : Definition(df,dl,na) +{ + fileList = new FileList; + classSDict = new ClassSDict(17); + groupList = new GroupList; + namespaceSDict = new NamespaceSDict(17); + pageDict = new PageSDict(17); + exampleDict = new PageSDict(17); + dirList = new DirList; + allMemberNameInfoSDict = new MemberNameInfoSDict(17); + if (refFileName) + { + fileName=stripExtension(refFileName); + } + else + { + fileName = (QCString)"group_"+na; + } + setGroupTitle( t ); + memberGroupSDict = new MemberGroupSDict; + memberGroupSDict->setAutoDelete(TRUE); + + allMemberList = new MemberList(MemberList::allMembersList); + + visited = 0; + groupScope = 0; +} + +GroupDef::~GroupDef() +{ + delete fileList; + delete classSDict; + delete groupList; + delete namespaceSDict; + delete pageDict; + delete exampleDict; + delete allMemberList; + delete allMemberNameInfoSDict; + delete memberGroupSDict; + delete dirList; +} + +void GroupDef::setGroupTitle( const char *t ) +{ + if ( t && strlen(t) ) + { + title = t; + titleSet = TRUE; + } + else + { + title = name(); + title.at(0)=toupper(title.at(0)); + titleSet = FALSE; + } +} + + +void GroupDef::distributeMemberGroupDocumentation() +{ + MemberGroupSDict::Iterator mgli(*memberGroupSDict); + MemberGroup *mg; + for (;(mg=mgli.current());++mgli) + { + mg->distributeMemberGroupDocumentation(); + } +} + +void GroupDef::findSectionsInDocumentation() +{ + docFindSections(documentation(),this,0,docFile()); + MemberGroupSDict::Iterator mgli(*memberGroupSDict); + MemberGroup *mg; + for (;(mg=mgli.current());++mgli) + { + mg->findSectionsInDocumentation(); + } + + QListIterator<MemberList> mli(m_memberLists); + MemberList *ml; + for (mli.toFirst();(ml=mli.current());++mli) + { + if (ml->listType()&MemberList::declarationLists) + { + ml->findSectionsInDocumentation(); + } + } +} + +void GroupDef::addFile(const FileDef *def) +{ + static bool sortBriefDocs = Config_getBool("SORT_BRIEF_DOCS"); + if (def->isHidden()) return; + if (sortBriefDocs) + fileList->inSort(def); + else + fileList->append(def); +} + +bool GroupDef::addClass(const ClassDef *cd) +{ + static bool sortBriefDocs = Config_getBool("SORT_BRIEF_DOCS"); + if (cd->isHidden()) return FALSE; + if (classSDict->find(cd->qualifiedName())==0) + { + QCString qn = cd->qualifiedName(); + //printf("--- addClass %s sort=%d\n",qn.data(),sortBriefDocs); + if (sortBriefDocs) + { + classSDict->inSort(cd->qualifiedName(),cd); + } + else + { + int i=qn.findRev("::"); + if (i==-1) i=qn.find('.'); + bool found=FALSE; + //printf("i=%d\n",i); + if (i!=-1) + { + // add nested classes (e.g. A::B, A::C) after their parent (A) in + // order of insertion + QCString scope = qn.left(i); + int j=classSDict->findAt(scope); + if (j!=-1) + { + while (j<(int)classSDict->count() && + classSDict->at(j)->qualifiedName().left(i)==scope) + { + //printf("skipping over %s\n",classSDict->at(j)->qualifiedName().data()); + j++; + } + //printf("Found scope at index %d\n",j); + classSDict->insertAt(j,cd->qualifiedName(),cd); + found=TRUE; + } + } + if (!found) // no insertion point found -> just append + { + classSDict->append(cd->qualifiedName(),cd); + } + } + return TRUE; + } + return FALSE; +} + +bool GroupDef::addNamespace(const NamespaceDef *def) +{ + static bool sortBriefDocs = Config_getBool("SORT_BRIEF_DOCS"); + if (def->isHidden()) return FALSE; + if (namespaceSDict->find(def->name())==0) + { + if (sortBriefDocs) + namespaceSDict->inSort(def->name(),def); + else + namespaceSDict->append(def->name(),def); + return TRUE; + } + return FALSE; +} + +void GroupDef::addDir(const DirDef *def) +{ + if (def->isHidden()) return; + if (Config_getBool("SORT_BRIEF_DOCS")) + dirList->inSort(def); + else + dirList->append(def); +} + +void GroupDef::addPage(PageDef *def) +{ + if (def->isHidden()) return; + //printf("Making page %s part of a group\n",def->name.data()); + pageDict->append(def->name(),def); + def->makePartOfGroup(this); +} + +void GroupDef::addExample(const PageDef *def) +{ + if (def->isHidden()) return; + exampleDict->append(def->name(),def); +} + + +void GroupDef::addMembersToMemberGroup() +{ + QListIterator<MemberList> mli(m_memberLists); + MemberList *ml; + for (mli.toFirst();(ml=mli.current());++mli) + { + if (ml->listType()&MemberList::declarationLists) + { + ::addMembersToMemberGroup(ml,&memberGroupSDict,this); + } + } + + //printf("GroupDef::addMembersToMemberGroup() memberGroupList=%d\n",memberGroupList->count()); + MemberGroupSDict::Iterator mgli(*memberGroupSDict); + MemberGroup *mg; + for (;(mg=mgli.current());++mgli) + { + mg->setInGroup(TRUE); + } +} + + +bool GroupDef::insertMember(MemberDef *md,bool docOnly) +{ + if (md->isHidden()) return FALSE; + //printf("GroupDef(%s)::insertMember(%s)\n", title.data(), md->name().data()); + MemberNameInfo *mni=0; + if ((mni=(*allMemberNameInfoSDict)[md->name()])) + { // member with this name already found + MemberNameInfoIterator srcMnii(*mni); + MemberInfo *srcMi; + for ( ; (srcMi=srcMnii.current()) ; ++srcMnii ) + { + MemberDef *srcMd = srcMi->memberDef; + if (srcMd==md) return FALSE; // already added before! + + bool sameScope = srcMd->getOuterScope()==md->getOuterScope() || // same class or namespace + // both inside a file => definition and declaration do not have to be in the same file + (srcMd->getOuterScope()->definitionType()==Definition::TypeFile && + md->getOuterScope()->definitionType()==Definition::TypeFile); + + LockingPtr<ArgumentList> srcMdAl = srcMd->argumentList(); + LockingPtr<ArgumentList> mdAl = md->argumentList(); + LockingPtr<ArgumentList> tSrcMdAl = srcMd->templateArguments(); + LockingPtr<ArgumentList> tMdAl = md->templateArguments(); + + if (srcMd->isFunction() && md->isFunction() && // both are a function + ((tSrcMdAl.pointer()==0 && tMdAl.pointer()==0) || + (tSrcMdAl.pointer()!=0 && tMdAl.pointer()!=0 && tSrcMdAl->count()==tMdAl->count()) + ) && // same number of template arguments + matchArguments2(srcMd->getOuterScope(),srcMd->getFileDef(),srcMdAl.pointer(), + md->getOuterScope(),md->getFileDef(),mdAl.pointer(), + TRUE + ) && // matching parameters + sameScope // both are found in the same scope + ) + { + if (srcMd->getGroupAlias()==0) + { + md->setGroupAlias(srcMd); + } + else + { + md->setGroupAlias(srcMd->getGroupAlias()); + } + return FALSE; // member is the same as one that is already added + } + } + mni->append(new MemberInfo(md,md->protection(),md->virtualness(),FALSE)); + } + else + { + mni = new MemberNameInfo(md->name()); + mni->append(new MemberInfo(md,md->protection(),md->virtualness(),FALSE)); + allMemberNameInfoSDict->append(mni->memberName(),mni); + } + //printf("Added member!\n"); + allMemberList->append(md); + switch(md->memberType()) + { + case MemberDef::Variable: + if (!docOnly) + { + addMemberToList(MemberList::decVarMembers,md); + } + addMemberToList(MemberList::docVarMembers,md); + break; + case MemberDef::Function: + if (!docOnly) + { + addMemberToList(MemberList::decFuncMembers,md); + } + addMemberToList(MemberList::docFuncMembers,md); + break; + case MemberDef::Typedef: + if (!docOnly) + { + addMemberToList(MemberList::decTypedefMembers,md); + } + addMemberToList(MemberList::docTypedefMembers,md); + break; + case MemberDef::Enumeration: + if (!docOnly) + { + addMemberToList(MemberList::decEnumMembers,md); + } + addMemberToList(MemberList::docEnumMembers,md); + break; + case MemberDef::EnumValue: + if (!docOnly) + { + addMemberToList(MemberList::decEnumValMembers,md); + } + addMemberToList(MemberList::docEnumValMembers,md); + break; + case MemberDef::Define: + if (!docOnly) + { + addMemberToList(MemberList::decDefineMembers,md); + } + addMemberToList(MemberList::docDefineMembers,md); + break; + case MemberDef::Signal: + if (!docOnly) + { + addMemberToList(MemberList::decSignalMembers,md); + } + addMemberToList(MemberList::docSignalMembers,md); + break; + case MemberDef::Slot: + if (md->protection()==Public) + { + if (!docOnly) + { + addMemberToList(MemberList::decPubSlotMembers,md); + } + addMemberToList(MemberList::docPubSlotMembers,md); + } + else if (md->protection()==Protected) + { + if (!docOnly) + { + addMemberToList(MemberList::decProSlotMembers,md); + } + addMemberToList(MemberList::docProSlotMembers,md); + } + else + { + if (!docOnly) + { + addMemberToList(MemberList::decPriSlotMembers,md); + } + addMemberToList(MemberList::docPriSlotMembers,md); + } + break; + case MemberDef::Event: + if (!docOnly) + { + addMemberToList(MemberList::decEventMembers,md); + } + addMemberToList(MemberList::docEventMembers,md); + break; + case MemberDef::Property: + if (!docOnly) + { + addMemberToList(MemberList::decPropMembers,md); + } + addMemberToList(MemberList::docPropMembers,md); + break; + case MemberDef::Friend: + if (!docOnly) + { + addMemberToList(MemberList::decFriendMembers,md); + } + addMemberToList(MemberList::docFriendMembers,md); + break; + default: + err("GroupDef::insertMembers(): " + "member `%s' (typeid=%d) with scope `%s' inserted in group scope `%s'!\n", + md->name().data(),md->memberType(), + md->getClassDef() ? md->getClassDef()->name().data() : "", + name().data()); + } + return TRUE; +} + +void GroupDef::removeMember(MemberDef *md) +{ + // fprintf(stderr, "GroupDef(%s)::removeMember( %s )\n", title.data(), md->name().data()); + MemberNameInfo *mni = allMemberNameInfoSDict->find(md->name()); + if (mni) + { + MemberNameInfoIterator mnii(*mni); + while( mnii.current() ) + { + if( mnii.current()->memberDef == md ) + { + mni->remove(mnii.current()); + break; + } + ++mnii; + } + if( mni->isEmpty() ) + { + allMemberNameInfoSDict->remove(md->name()); + delete mni; + } + + removeMemberFromList(MemberList::allMembersList,md); + switch(md->memberType()) + { + case MemberDef::Variable: + removeMemberFromList(MemberList::decVarMembers,md); + removeMemberFromList(MemberList::docVarMembers,md); + break; + case MemberDef::Function: + removeMemberFromList(MemberList::decFuncMembers,md); + removeMemberFromList(MemberList::docFuncMembers,md); + break; + case MemberDef::Typedef: + removeMemberFromList(MemberList::decTypedefMembers,md); + removeMemberFromList(MemberList::docTypedefMembers,md); + break; + case MemberDef::Enumeration: + removeMemberFromList(MemberList::decEnumMembers,md); + removeMemberFromList(MemberList::docEnumMembers,md); + break; + case MemberDef::EnumValue: + removeMemberFromList(MemberList::decEnumValMembers,md); + removeMemberFromList(MemberList::docEnumValMembers,md); + break; + case MemberDef::Define: + removeMemberFromList(MemberList::decDefineMembers,md); + removeMemberFromList(MemberList::docDefineMembers,md); + break; + case MemberDef::Signal: + removeMemberFromList(MemberList::decSignalMembers,md); + removeMemberFromList(MemberList::docSignalMembers,md); + break; + case MemberDef::Slot: + if (md->protection()==Public) + { + removeMemberFromList(MemberList::decPubSlotMembers,md); + removeMemberFromList(MemberList::docPubSlotMembers,md); + } + else if (md->protection()==Protected) + { + removeMemberFromList(MemberList::decProSlotMembers,md); + removeMemberFromList(MemberList::docProSlotMembers,md); + } + else + { + removeMemberFromList(MemberList::decPriSlotMembers,md); + removeMemberFromList(MemberList::docPriSlotMembers,md); + } + break; + case MemberDef::Event: + removeMemberFromList(MemberList::decEventMembers,md); + removeMemberFromList(MemberList::docEventMembers,md); + break; + case MemberDef::Property: + removeMemberFromList(MemberList::decPropMembers,md); + removeMemberFromList(MemberList::docPropMembers,md); + break; + case MemberDef::Friend: + removeMemberFromList(MemberList::decFriendMembers,md); + removeMemberFromList(MemberList::docFriendMembers,md); + break; + default: + err("GroupDef::removeMember(): unexpected member remove in file!\n"); + } + } +} + +bool GroupDef::containsGroup(const GroupDef *def) +{ + return this==def || groupList->find(def) >= 0; +} + +void GroupDef::addGroup(const GroupDef *def) +{ + //printf("adding group `%s' to group `%s'\n",def->name().data(),name().data()); + //if (Config_getBool("SORT_MEMBER_DOCS")) + // groupList->inSort(def); + //else + groupList->append(def); +} + +bool GroupDef::isASubGroup() const +{ + LockingPtr<GroupList> groups = partOfGroups(); + return groups!=0 && groups->count()!=0; +} + +int GroupDef::countMembers() const +{ + return fileList->count()+ + classSDict->count()+ + namespaceSDict->count()+ + groupList->count()+ + allMemberList->count()+ + pageDict->count()+ + exampleDict->count(); +} + +/*! Compute the HTML anchor names for all members in the group */ +void GroupDef::computeAnchors() +{ + //printf("GroupDef::computeAnchors()\n"); + setAnchors(0,'a',allMemberList); +} + +void GroupDef::writeDetailedDescription(OutputList &ol,const QCString &title) +{ + if ((!briefDescription().isEmpty() && Config_getBool("REPEAT_BRIEF")) + || !documentation().isEmpty() || !inbodyDocumentation().isEmpty() + ) + { + if (pageDict->count()!=countMembers()) // not only pages -> classical layout + { + ol.writeRuler(); + ol.pushGeneratorState(); + ol.disableAllBut(OutputGenerator::Html); + ol.writeAnchor(0,"details"); + ol.popGeneratorState(); + ol.startGroupHeader(); + ol.parseText(title); + ol.endGroupHeader(); + } + + // repeat brief description + if (!briefDescription().isEmpty() && Config_getBool("REPEAT_BRIEF")) + { + ol.parseDoc(briefFile(),briefLine(),this,0,briefDescription(),FALSE,FALSE); + } + // write separator between brief and details + if (!briefDescription().isEmpty() && Config_getBool("REPEAT_BRIEF") && + !documentation().isEmpty()) + { + ol.pushGeneratorState(); + ol.disable(OutputGenerator::Man); + ol.disable(OutputGenerator::RTF); + // ol.newParagraph(); // FIXME:PARA + ol.enableAll(); + ol.disableAllBut(OutputGenerator::Man); + ol.writeString("\n\n"); + ol.popGeneratorState(); + } + + // write detailed documentation + if (!documentation().isEmpty()) + { + ol.parseDoc(docFile(),docLine(),this,0,documentation()+"\n",TRUE,FALSE); + } + + // write inbody documentation + if (!inbodyDocumentation().isEmpty()) + { + ol.parseDoc(inbodyFile(),inbodyLine(),this,0,inbodyDocumentation()+"\n",TRUE,FALSE); + } + } +} + +void GroupDef::writeBriefDescription(OutputList &ol) +{ + if (!briefDescription().isEmpty() && Config_getBool("BRIEF_MEMBER_DESC")) + { + ol.startParagraph(); + ol.parseDoc(briefFile(),briefLine(),this,0, + briefDescription(),TRUE,FALSE,0,TRUE,FALSE); + ol.pushGeneratorState(); + ol.disable(OutputGenerator::RTF); + ol.writeString(" \n"); + ol.enable(OutputGenerator::RTF); + + if (Config_getBool("REPEAT_BRIEF") || + !documentation().isEmpty() + ) + { + ol.disableAllBut(OutputGenerator::Html); + ol.startTextLink(0,"details"); + ol.parseText(theTranslator->trMore()); + ol.endTextLink(); + } + ol.popGeneratorState(); + ol.endParagraph(); + } +} + +void GroupDef::writeGroupGraph(OutputList &ol) +{ + if (Config_getBool("HAVE_DOT") /*&& Config_getBool("GROUP_GRAPHS")*/ ) + { + DotGroupCollaboration graph(this); + if (!graph.isTrivial()) + { + msg("Generating dependency graph for group %s\n",qualifiedName().data()); + ol.pushGeneratorState(); + ol.disable(OutputGenerator::Man); + //ol.startParagraph(); + ol.startGroupCollaboration(); + ol.parseText(theTranslator->trCollaborationDiagram(title)); + ol.endGroupCollaboration(graph); + //ol.endParagraph(); + ol.popGeneratorState(); + } + } +} + +void GroupDef::writeFiles(OutputList &ol,const QCString &title) +{ + // write list of files + if (fileList->count()>0) + { + ol.startMemberHeader("files"); + ol.parseText(title); + ol.endMemberHeader(); + ol.startMemberList(); + FileDef *fd=fileList->first(); + while (fd) + { + ol.startMemberItem(fd->getOutputFileBase(),0); + ol.docify(theTranslator->trFile(FALSE,TRUE)+" "); + ol.insertMemberAlign(); + ol.writeObjectLink(fd->getReference(),fd->getOutputFileBase(),0,fd->name()); + if (!Config_getString("GENERATE_TAGFILE").isEmpty()) + { + Doxygen::tagFile << " <file>" << convertToXML(fd->name()) << "</file>" << endl; + } + ol.endMemberItem(); + if (!fd->briefDescription().isEmpty() && Config_getBool("BRIEF_MEMBER_DESC")) + { + ol.startMemberDescription(fd->getOutputFileBase()); + ol.parseDoc(briefFile(),briefLine(),fd,0,fd->briefDescription(),FALSE,FALSE,0,TRUE,FALSE); + ol.endMemberDescription(); + } + fd=fileList->next(); + } + ol.endMemberList(); + } +} + +void GroupDef::writeNamespaces(OutputList &ol,const QCString &title) +{ + // write list of namespaces + namespaceSDict->writeDeclaration(ol,title); +} + +void GroupDef::writeNestedGroups(OutputList &ol,const QCString &title) +{ + // write list of groups + int count=0; + if (groupList->count()>0) + { + GroupDef *gd=groupList->first(); + while (gd) + { + if (gd->isVisible()) count++; + gd=groupList->next(); + } + } + if (count>0) + { + ol.startMemberHeader("groups"); + ol.parseText(title); + ol.endMemberHeader(); + ol.startMemberList(); + GroupDef *gd=groupList->first(); + while (gd) + { + if (gd->isVisible()) + { + ol.startMemberItem(gd->getOutputFileBase(),0); + //ol.docify(theTranslator->trGroup(FALSE,TRUE)); + //ol.docify(" "); + ol.insertMemberAlign(); + ol.writeObjectLink(gd->getReference(),gd->getOutputFileBase(),0,gd->groupTitle()); + if (!Config_getString("GENERATE_TAGFILE").isEmpty()) + { + Doxygen::tagFile << " <subgroup>" << convertToXML(gd->name()) << "</subgroup>" << endl; + } + ol.endMemberItem(); + if (!gd->briefDescription().isEmpty() && Config_getBool("BRIEF_MEMBER_DESC")) + { + ol.startMemberDescription(gd->getOutputFileBase()); + ol.parseDoc(briefFile(),briefLine(),gd,0,gd->briefDescription(),FALSE,FALSE,0,TRUE,FALSE); + ol.endMemberDescription(); + } + } + gd=groupList->next(); + } + ol.endMemberList(); + } +} + +void GroupDef::writeDirs(OutputList &ol,const QCString &title) +{ + // write list of directories + if (dirList->count()>0) + { + ol.startMemberHeader("dirs"); + ol.parseText(title); + ol.endMemberHeader(); + ol.startMemberList(); + DirDef *dd=dirList->first(); + while (dd) + { + ol.startMemberItem(dd->getOutputFileBase(),0); + ol.parseText(theTranslator->trDir(FALSE,TRUE)); + ol.insertMemberAlign(); + ol.writeObjectLink(dd->getReference(),dd->getOutputFileBase(),0,dd->shortName()); + ol.endMemberItem(); + if (!Config_getString("GENERATE_TAGFILE").isEmpty()) + { + Doxygen::tagFile << " <dir>" << convertToXML(dd->displayName()) << "</dir>" << endl; + } + if (!dd->briefDescription().isEmpty() && Config_getBool("BRIEF_MEMBER_DESC")) + { + ol.startMemberDescription(dd->getOutputFileBase()); + ol.parseDoc(briefFile(),briefLine(),dd,0,dd->briefDescription(),FALSE,FALSE,0,TRUE,FALSE); + ol.endMemberDescription(); + } + dd=dirList->next(); + } + + ol.endMemberList(); + } +} + +void GroupDef::writeClasses(OutputList &ol,const QCString &title) +{ + // write list of classes + classSDict->writeDeclaration(ol,0,title,FALSE); +} + +void GroupDef::writeInlineClasses(OutputList &ol) +{ + classSDict->writeDocumentation(ol); +} + +void GroupDef::writePageDocumentation(OutputList &ol) +{ + PageDef *pd=0; + PageSDict::Iterator pdi(*pageDict); + for (pdi.toFirst();(pd=pdi.current());++pdi) + { + if (!pd->isReference()) + { + QCString pageName = pd->getOutputFileBase(); + + if (!Config_getString("GENERATE_TAGFILE").isEmpty()) + { + Doxygen::tagFile << " <page>" << convertToXML(pageName) << "</page>" << endl; + } + + SectionInfo *si=0; + if (!pd->title().isEmpty() && !pd->name().isEmpty() && + (si=Doxygen::sectionDict[pd->name()])!=0) + { + ol.startSection(si->label,si->title,SectionInfo::Subsection); + ol.docify(si->title); + ol.endSection(si->label,SectionInfo::Subsection); + } + ol.startTextBlock(); + ol.parseDoc(pd->docFile(),pd->docLine(),pd,0,pd->documentation()+pd->inbodyDocumentation(),TRUE,FALSE,0,TRUE,FALSE); + ol.endTextBlock(); + } + } +} + +void GroupDef::writeMemberGroups(OutputList &ol) +{ + /* write user defined member groups */ + if (memberGroupSDict) + { + memberGroupSDict->sort(); + /* write user defined member groups */ + MemberGroupSDict::Iterator mgli(*memberGroupSDict); + MemberGroup *mg; + for (;(mg=mgli.current());++mgli) + { + mg->writeDeclarations(ol,0,0,0,this); + } + } +} + +void GroupDef::startMemberDeclarations(OutputList &ol) +{ + ol.startMemberSections(); +} + +void GroupDef::endMemberDeclarations(OutputList &ol) +{ + ol.endMemberSections(); +} + +void GroupDef::startMemberDocumentation(OutputList &ol) +{ + //printf("** GroupDef::startMemberDocumentation()\n"); + if (Config_getBool("SEPARATE_MEMBER_PAGES")) + { + ol.pushGeneratorState(); + ol.disable(OutputGenerator::Html); + Doxygen::suppressDocWarnings = TRUE; + } +} + +void GroupDef::endMemberDocumentation(OutputList &ol) +{ + //printf("** GroupDef::endMemberDocumentation()\n"); + if (Config_getBool("SEPARATE_MEMBER_PAGES")) + { + ol.popGeneratorState(); + Doxygen::suppressDocWarnings = FALSE; + } +} + +void GroupDef::writeAuthorSection(OutputList &ol) +{ + // write Author section (Man only) + ol.pushGeneratorState(); + ol.disableAllBut(OutputGenerator::Man); + ol.startGroupHeader(); + ol.parseText(theTranslator->trAuthor(TRUE,TRUE)); + ol.endGroupHeader(); + ol.parseText(theTranslator->trGeneratedAutomatically(Config_getString("PROJECT_NAME"))); + ol.popGeneratorState(); +} + +void GroupDef::writeSummaryLinks(OutputList &ol) +{ + ol.pushGeneratorState(); + ol.disableAllBut(OutputGenerator::Html); + QListIterator<LayoutDocEntry> eli( + LayoutDocManager::instance().docEntries(LayoutDocManager::Group)); + LayoutDocEntry *lde; + bool first=TRUE; + for (eli.toFirst();(lde=eli.current());++eli) + { + if ((lde->kind()==LayoutDocEntry::GroupClasses && classSDict->declVisible()) || + (lde->kind()==LayoutDocEntry::GroupNamespaces && namespaceSDict->declVisible()) || + (lde->kind()==LayoutDocEntry::GroupFiles && fileList->count()>0) || + (lde->kind()==LayoutDocEntry::GroupNestedGroups && groupList->count()>0) || + (lde->kind()==LayoutDocEntry::GroupDirs && dirList->count()>0) + ) + { + LayoutDocEntrySection *ls = (LayoutDocEntrySection*)lde; + QCString label = lde->kind()==LayoutDocEntry::GroupClasses ? "nested-classes" : + lde->kind()==LayoutDocEntry::GroupNamespaces ? "namespaces" : + lde->kind()==LayoutDocEntry::GroupFiles ? "files" : + lde->kind()==LayoutDocEntry::GroupNestedGroups ? "groups" : + "dirs"; + writeSummaryLink(ol,label,ls->title,first); + } + else if (lde->kind()==LayoutDocEntry::MemberDecl) + { + LayoutDocEntryMemberDecl *lmd = (LayoutDocEntryMemberDecl*)lde; + MemberList * ml = getMemberList(lmd->type); + if (ml && ml->declVisible()) + { + writeSummaryLink(ol,ml->listTypeAsString(),lmd->title,first); + } + } + } + if (!first) + { + ol.writeString(" </div>\n"); + } + ol.popGeneratorState(); +} + +void GroupDef::writeDocumentation(OutputList &ol) +{ + //static bool generateTreeView = Config_getBool("GENERATE_TREEVIEW"); + ol.pushGeneratorState(); + startFile(ol,getOutputFileBase(),name(),title,HLI_None); + + ol.startHeaderSection(); + writeSummaryLinks(ol); + ol.startTitleHead(getOutputFileBase()); + ol.pushGeneratorState(); + ol.disable(OutputGenerator::Man); + ol.parseText(title); + ol.popGeneratorState(); + ol.endTitleHead(getOutputFileBase(),title); + addGroupListToTitle(ol,this); + ol.endHeaderSection(); + ol.startContents(); + + if (Doxygen::searchIndex) + { + Doxygen::searchIndex->setCurrentDoc(title,getOutputFileBase()); + static QRegExp we("[a-zA-Z_][-a-zA-Z_0-9]*"); + int i=0,p=0,l=0; + while ((i=we.match(title,p,&l))!=-1) // foreach word in the title + { + Doxygen::searchIndex->addWord(title.mid(i,l),TRUE); + p=i+l; + } + } + + Doxygen::indexList.addIndexItem(this,0,title); + + if (!Config_getString("GENERATE_TAGFILE").isEmpty()) + { + Doxygen::tagFile << " <compound kind=\"group\">" << endl; + Doxygen::tagFile << " <name>" << convertToXML(name()) << "</name>" << endl; + Doxygen::tagFile << " <title>" << convertToXML(title) << "" << endl; + Doxygen::tagFile << " " << convertToXML(getOutputFileBase()) << Doxygen::htmlFileExtension << "" << endl; + } + + + //---------------------------------------- start flexible part ------------------------------- + + QListIterator eli( + LayoutDocManager::instance().docEntries(LayoutDocManager::Group)); + LayoutDocEntry *lde; + for (eli.toFirst();(lde=eli.current());++eli) + { + switch (lde->kind()) + { + case LayoutDocEntry::BriefDesc: + writeBriefDescription(ol); + break; + case LayoutDocEntry::MemberDeclStart: + startMemberDeclarations(ol); + break; + case LayoutDocEntry::GroupClasses: + { + LayoutDocEntrySection *ls = (LayoutDocEntrySection*)lde; + writeClasses(ol,ls->title); + } + break; + case LayoutDocEntry::GroupInlineClasses: + { + writeInlineClasses(ol); + } + break; + case LayoutDocEntry::GroupNamespaces: + { + LayoutDocEntrySection *ls = (LayoutDocEntrySection*)lde; + writeNamespaces(ol,ls->title); + } + break; + case LayoutDocEntry::MemberGroups: + writeMemberGroups(ol); + break; + case LayoutDocEntry::MemberDecl: + { + LayoutDocEntryMemberDecl *lmd = (LayoutDocEntryMemberDecl*)lde; + writeMemberDeclarations(ol,lmd->type,lmd->title); + } + break; + case LayoutDocEntry::MemberDeclEnd: + endMemberDeclarations(ol); + break; + case LayoutDocEntry::DetailedDesc: + { + LayoutDocEntrySection *ls = (LayoutDocEntrySection*)lde; + writeDetailedDescription(ol,ls->title); + } + break; + case LayoutDocEntry::MemberDefStart: + startMemberDocumentation(ol); + break; + case LayoutDocEntry::MemberDef: + { + LayoutDocEntryMemberDef *lmd = (LayoutDocEntryMemberDef*)lde; + writeMemberDocumentation(ol,lmd->type,lmd->title); + } + break; + case LayoutDocEntry::MemberDefEnd: + endMemberDocumentation(ol); + break; + case LayoutDocEntry::GroupNestedGroups: + { + LayoutDocEntrySection *ls = (LayoutDocEntrySection*)lde; + writeNestedGroups(ol,ls->title); + } + break; + case LayoutDocEntry::GroupPageDocs: + writePageDocumentation(ol); + break; + case LayoutDocEntry::GroupDirs: + { + LayoutDocEntrySection *ls = (LayoutDocEntrySection*)lde; + writeDirs(ol,ls->title); + } + break; + case LayoutDocEntry::GroupFiles: + { + LayoutDocEntrySection *ls = (LayoutDocEntrySection*)lde; + writeFiles(ol,ls->title); + } + break; + case LayoutDocEntry::GroupGraph: + writeGroupGraph(ol); + break; + case LayoutDocEntry::AuthorSection: + writeAuthorSection(ol); + break; + case LayoutDocEntry::ClassIncludes: + case LayoutDocEntry::ClassInheritanceGraph: + case LayoutDocEntry::ClassNestedClasses: + case LayoutDocEntry::ClassCollaborationGraph: + case LayoutDocEntry::ClassAllMembersLink: + case LayoutDocEntry::ClassUsedFiles: + case LayoutDocEntry::ClassInlineClasses: + case LayoutDocEntry::NamespaceNestedNamespaces: + case LayoutDocEntry::NamespaceClasses: + case LayoutDocEntry::NamespaceInlineClasses: + case LayoutDocEntry::FileClasses: + case LayoutDocEntry::FileNamespaces: + case LayoutDocEntry::FileIncludes: + case LayoutDocEntry::FileIncludeGraph: + case LayoutDocEntry::FileIncludedByGraph: + case LayoutDocEntry::FileSourceLink: + case LayoutDocEntry::FileInlineClasses: + case LayoutDocEntry::DirSubDirs: + case LayoutDocEntry::DirFiles: + case LayoutDocEntry::DirGraph: + err("Internal inconsistency: member %d should not be part of " + "LayoutDocManager::Group entry list\n",lde->kind()); + break; + } + } + + //---------------------------------------- end flexible part ------------------------------- + + endFile(ol); + + ol.popGeneratorState(); + + if (!Config_getString("GENERATE_TAGFILE").isEmpty()) + { + writeDocAnchorsToTagFile(); + Doxygen::tagFile << " " << endl; + } + + if (Config_getBool("SEPARATE_MEMBER_PAGES")) + { + allMemberList->sort(); + writeMemberPages(ol); + } + +} + +void GroupDef::writeMemberPages(OutputList &ol) +{ + ol.pushGeneratorState(); + ol.disableAllBut(OutputGenerator::Html); + + QListIterator mli(m_memberLists); + MemberList *ml; + for (mli.toFirst();(ml=mli.current());++mli) + { + if (ml->listType()&MemberList::documentationLists) + { + ml->writeDocumentationPage(ol,name(),this); + } + } + + ol.popGeneratorState(); +} + +void GroupDef::writeQuickMemberLinks(OutputList &ol,MemberDef *currentMd) const +{ + static bool createSubDirs=Config_getBool("CREATE_SUBDIRS"); + + ol.writeString("
\n"); + ol.writeString(" \n"); + + MemberListIterator mli(*allMemberList); + MemberDef *md; + for (mli.toFirst();(md=mli.current());++mli) + { + if (md->getGroupDef()==this && md->isLinkable()) + { + ol.writeString(" \n"); + } + } + + ol.writeString("
"); + if (md->isLinkableInProject()) + { + if (md==currentMd) // selected item => highlight + { + ol.writeString("getOutputFileBase()+Doxygen::htmlFileExtension+"#"+md->anchor()); + ol.writeString("\">"); + ol.writeString(convertToHtml(md->localName())); + ol.writeString(""); + } + ol.writeString("
\n"); + ol.writeString("
\n"); +} + + + +//---- helper functions ------------------------------------------------------ + +void addClassToGroups(Entry *root,ClassDef *cd) +{ + QListIterator gli(*root->groups); + Grouping *g; + for (;(g=gli.current());++gli) + { + GroupDef *gd=0; + if (!g->groupname.isEmpty() && (gd=Doxygen::groupSDict->find(g->groupname))) + { + if (gd->addClass(cd)) + { + cd->makePartOfGroup(gd); + } + //printf("Compound %s: in group %s\n",cd->name().data(),gd->groupTitle()); + } + } +} + +void addNamespaceToGroups(Entry *root,NamespaceDef *nd) +{ + //printf("root->groups->count()=%d\n",root->groups->count()); + QListIterator gli(*root->groups); + Grouping *g; + for (;(g=gli.current());++gli) + { + GroupDef *gd=0; + //printf("group `%s'\n",s->data()); + if (!g->groupname.isEmpty() && (gd=Doxygen::groupSDict->find(g->groupname))) + { + if (gd->addNamespace(nd)) nd->makePartOfGroup(gd); + //printf("Namespace %s: in group %s\n",nd->name().data(),s->data()); + } + } +} + +void addDirToGroups(Entry *root,DirDef *dd) +{ + //printf("*** root->groups->count()=%d\n",root->groups->count()); + QListIterator gli(*root->groups); + Grouping *g; + for (;(g=gli.current());++gli) + { + GroupDef *gd=0; + //printf("group `%s'\n",g->groupname.data()); + if (!g->groupname.isEmpty() && (gd=Doxygen::groupSDict->find(g->groupname))) + { + gd->addDir(dd); + dd->makePartOfGroup(gd); + //printf("Dir %s: in group %s\n",dd->name().data(),g->groupname.data()); + } + } +} + +void addGroupToGroups(Entry *root,GroupDef *subGroup) +{ + //printf("addGroupToGroups for %s groups=%d\n",root->name.data(), + // root->groups?root->groups->count():-1); + QListIterator gli(*root->groups); + Grouping *g; + for (;(g=gli.current());++gli) + { + GroupDef *gd=0; + if (!g->groupname.isEmpty() && (gd=Doxygen::groupSDict->find(g->groupname)) && + !gd->containsGroup(subGroup) ) + { + gd->addGroup(subGroup); + subGroup->makePartOfGroup(gd); + } + else if (gd==subGroup) + { + warn(root->fileName,root->startLine,"Trying to add group %s to itself!", + gd->name().data()); + } + } +} + +/*! Add a member to the group with the highest priority */ +void addMemberToGroups(Entry *root,MemberDef *md) +{ + //printf("addMemberToGroups: Root %p = %s, md %p=%s groups=%d\n", + // root, root->name.data(), md, md->name().data(), root->groups->count() ); + QListIterator gli(*root->groups); + Grouping *g; + + // Search entry's group list for group with highest pri. + Grouping::GroupPri_t pri = Grouping::GROUPING_LOWEST; + GroupDef *fgd=0; + for (;(g=gli.current());++gli) + { + GroupDef *gd=0; + if (!g->groupname.isEmpty() && + (gd=Doxygen::groupSDict->find(g->groupname)) && + g->pri >= pri) + { + if (fgd && gd!=fgd && g->pri==pri) + { + warn(root->fileName.data(), root->startLine, + "warning: Member %s found in multiple %s groups! " + "The member will be put in group %s, and not in group %s", + md->name().data(), Grouping::getGroupPriName( pri ), + gd->name().data(), fgd->name().data() + ); + } + + fgd = gd; + pri = g->pri; + } + } + //printf("fgd=%p\n",fgd); + + // put member into group defined by this entry? + if (fgd) + { + GroupDef *mgd = md->getGroupDef(); + //printf("mgd=%p\n",mgd); + bool insertit = FALSE; + if (mgd==0) + { + insertit = TRUE; + } + else if (mgd!=fgd) + { + bool moveit = FALSE; + + // move member from one group to another if + // - the new one has a higher priority + // - the new entry has the same priority, but with docs where the old one had no docs + if (md->getGroupPri()getGroupPri()==pri) + { + if (!root->doc.isEmpty() && !md->getGroupHasDocs()) + { + moveit = TRUE; + } + else if (!root->doc.isEmpty() && md->getGroupHasDocs()) + { + warn(md->getGroupFileName(),md->getGroupStartLine(), + "warning: Member documentation for %s found several times in %s groups!\n" + "%s:%d: The member will remain in group %s, and won't be put into group %s", + md->name().data(), Grouping::getGroupPriName( pri ), + root->fileName.data(), root->startLine, + mgd->name().data(), + fgd->name().data() + ); + } + } + } + + if (moveit) + { + //printf("removeMember\n"); + mgd->removeMember(md); + insertit = TRUE; + } + } + + if (insertit) + { + //printf("insertMember found at %s line %d: %s: related %s\n", + // md->getDefFileName().data(),md->getDefLine(), + // md->name().data(),root->relates.data()); + bool success = fgd->insertMember(md); + if (success) + { + //printf("insertMember successful\n"); + md->setGroupDef(fgd,pri,root->fileName,root->startLine, + !root->doc.isEmpty()); + ClassDef *cd = md->getClassDefOfAnonymousType(); + if (cd) + { + cd->setGroupDefForAllMembers(fgd,pri,root->fileName,root->startLine,root->doc.length() != 0); + } + } + } + } +} + + +void addExampleToGroups(Entry *root,PageDef *eg) +{ + QListIterator gli(*root->groups); + Grouping *g; + for (;(g=gli.current());++gli) + { + GroupDef *gd=0; + if (!g->groupname.isEmpty() && (gd=Doxygen::groupSDict->find(g->groupname))) + { + gd->addExample(eg); + eg->makePartOfGroup(gd); + //printf("Example %s: in group %s\n",eg->name().data(),s->data()); + } + } +} + +QCString GroupDef::getOutputFileBase() const +{ + if (isReference()) + { + return fileName; + } + else + { + return convertNameToFile(fileName); + } +} + +void GroupDef::addListReferences() +{ + { + LockingPtr< QList > xrefItems = xrefListItems(); + addRefItem(xrefItems.pointer(), + getOutputFileBase(), + theTranslator->trGroup(TRUE,TRUE), + getOutputFileBase(),name(), + 0 + ); + } + MemberGroupSDict::Iterator mgli(*memberGroupSDict); + MemberGroup *mg; + for (;(mg=mgli.current());++mgli) + { + mg->addListReferences(this); + } + QListIterator mli(m_memberLists); + MemberList *ml; + for (mli.toFirst();(ml=mli.current());++mli) + { + if (ml->listType()&MemberList::documentationLists) + { + ml->addListReferences(this); + } + } +} + +MemberList *GroupDef::createMemberList(MemberList::ListType lt) +{ + m_memberLists.setAutoDelete(TRUE); + QListIterator mli(m_memberLists); + MemberList *ml; + for (mli.toFirst();(ml=mli.current());++mli) + { + if (ml->listType()==lt) + { + return ml; + } + } + // not found, create a new member list + ml = new MemberList(lt); + m_memberLists.append(ml); + ml->setInGroup(TRUE); + return ml; +} + +void GroupDef::addMemberToList(MemberList::ListType lt,MemberDef *md) +{ + static bool sortBriefDocs = Config_getBool("SORT_BRIEF_DOCS"); + static bool sortMemberDocs = Config_getBool("SORT_MEMBER_DOCS"); + MemberList *ml = createMemberList(lt); + ml->setNeedsSorting( + ((ml->listType()&MemberList::declarationLists) && sortBriefDocs) || + ((ml->listType()&MemberList::documentationLists) && sortMemberDocs)); + ml->append(md); +} + +void GroupDef::sortMemberLists() +{ + MemberList *ml = m_memberLists.first(); + while (ml) + { + if (ml->needsSorting()) { ml->sort(); ml->setNeedsSorting(FALSE); } + ml = m_memberLists.next(); + } +} + + +MemberList *GroupDef::getMemberList(MemberList::ListType lt) const +{ + GroupDef *that = (GroupDef*)this; + MemberList *ml = that->m_memberLists.first(); + while (ml) + { + if (ml->listType()==lt) + { + return ml; + } + ml = that->m_memberLists.next(); + } + return 0; +} + +void GroupDef::writeMemberDeclarations(OutputList &ol,MemberList::ListType lt,const QCString &title) +{ + static bool optimizeVhdl = Config_getBool("OPTIMIZE_OUTPUT_VHDL"); + + MemberList * ml = getMemberList(lt); + if (optimizeVhdl && ml) + { + VhdlDocGen::writeVhdlDeclarations(ml,ol,this,0,0,0); + return; + } + if (ml) + { + ml->writeDeclarations(ol,0,0,0,this,title,0); + } +} + +void GroupDef::writeMemberDocumentation(OutputList &ol,MemberList::ListType lt,const QCString &title) +{ + MemberList * ml = getMemberList(lt); + if (ml) ml->writeDocumentation(ol,name(),this,title); +} + +void GroupDef::removeMemberFromList(MemberList::ListType lt,MemberDef *md) +{ + MemberList *ml = getMemberList(lt); + if (ml) ml->remove(md); +} + +void GroupDef::sortSubGroups() +{ + groupList->sort(); +} + +bool GroupDef::isLinkableInProject() const +{ + return !isReference() && isLinkable(); +} + +bool GroupDef::isLinkable() const +{ + return hasUserDocumentation(); +} + diff --git a/trunk/src/groupdef.h b/trunk/src/groupdef.h new file mode 100644 index 0000000..5c83b81 --- /dev/null +++ b/trunk/src/groupdef.h @@ -0,0 +1,192 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#ifndef GROUPDEF_H +#define GROUPDEF_H + +#include "qtbc.h" +#include "sortdict.h" +#include "definition.h" +#include "memberlist.h" +#include "memberdef.h" +#include "htmlhelp.h" + +class FileList; +class ClassSDict; +class FileDef; +class ClassDef; +class NamespaceDef; +class GroupList; +class OutputList; +class NamespaceSDict; +class MemberGroupSDict; +class MemberNameInfoSDict; +class PageSDict; +class PageDef; +class DirDef; +class DirList; +class FTVHelp; +class Entry; + +class GroupDef : public Definition +{ + public: + GroupDef(const char *fileName,int line,const char *name,const char *title,const char *refFileName=0); + ~GroupDef(); + DefType definitionType() const { return TypeGroup; } + QCString getOutputFileBase() const; + QCString anchor() const { return QCString(); } + QCString displayName() const { return hasGroupTitle() ? title : Definition::name(); } + const char *groupTitle() const { return title; } + void setGroupTitle( const char *newtitle ); + bool hasGroupTitle( ) const { return titleSet; } + void addFile(const FileDef *def); + bool addClass(const ClassDef *def); + bool addNamespace(const NamespaceDef *def); + void addGroup(const GroupDef *def); + void addParentGroup(const GroupDef *def); + void addPage(PageDef *def); + void addExample(const PageDef *def); + void addDir(const DirDef *dd); + bool insertMember(MemberDef *def,bool docOnly=FALSE); + void removeMember(MemberDef *md); + bool containsGroup(const GroupDef *def); // true if def is already a subgroup + void writeDocumentation(OutputList &ol); + void writeMemberPages(OutputList &ol); + void writeQuickMemberLinks(OutputList &ol,MemberDef *currentMd) const; + int countMembers() const; + bool isLinkableInProject() const; + bool isLinkable() const; + bool isASubGroup() const; + void computeAnchors(); + + void addMembersToMemberGroup(); + void distributeMemberGroupDocumentation(); + void findSectionsInDocumentation(); + + void addListReferences(); + void sortMemberLists(); + + bool visited; // number of times accessed for output - KPW + + //friend void writeGroupTreeNode(OutputList&, GroupDef*, int, FTVHelp*); + // make accessible for writing tree view of group in index.cpp - KPW + + void setGroupScope(Definition *d) { groupScope = d; } + Definition *getGroupScope() const { return groupScope; } + + MemberList *getMemberList(MemberList::ListType lt) const; + const QList &getMemberLists() const { return m_memberLists; } + + /* user defined member groups */ + MemberGroupSDict *getMemberGroupSDict() const { return memberGroupSDict; } + + FileList * getFiles() const { return fileList; } + ClassSDict * getClasses() const { return classSDict; } + NamespaceSDict * getNamespaces() const { return namespaceSDict; } + GroupList * getSubGroups() const { return groupList; } + PageSDict * getPages() const { return pageDict; } + DirList * getDirs() const { return dirList; } + PageSDict * getExamples() const { return exampleDict; } + //MemberList* getMembers() const { return allMemberList; } + void sortSubGroups(); + + protected: + void addMemberListToGroup(MemberList *,bool (MemberDef::*)() const); + + private: + MemberList *createMemberList(MemberList::ListType lt); + void addMemberToList(MemberList::ListType lt,MemberDef *md); + void writeMemberDeclarations(OutputList &ol,MemberList::ListType lt,const QCString &title); + void writeMemberDocumentation(OutputList &ol,MemberList::ListType lt,const QCString &title); + void removeMemberFromList(MemberList::ListType lt,MemberDef *md); + void writeGroupGraph(OutputList &ol); + void writeFiles(OutputList &ol,const QCString &title); + void writeNamespaces(OutputList &ol,const QCString &title); + void writeNestedGroups(OutputList &ol,const QCString &title); + void writeDirs(OutputList &ol,const QCString &title); + void writeClasses(OutputList &ol,const QCString &title); + void writeInlineClasses(OutputList &ol); + void writePageDocumentation(OutputList &ol); + void writeDetailedDescription(OutputList &ol,const QCString &title); + void writeBriefDescription(OutputList &ol); + void writeMemberGroups(OutputList &ol); + void startMemberDeclarations(OutputList &ol); + void endMemberDeclarations(OutputList &ol); + void startMemberDocumentation(OutputList &ol); + void endMemberDocumentation(OutputList &ol); + void writeAuthorSection(OutputList &ol); + void writeSummaryLinks(OutputList &ol); + + QCString title; // title of the group + bool titleSet; // true if title is not the same as the name + QCString fileName; // base name of the generated file + FileList *fileList; // list of files in the group + ClassSDict *classSDict; // list of classes in the group + NamespaceSDict *namespaceSDict; // list of namespaces in the group + GroupList *groupList; // list of sub groups. + PageSDict *pageDict; // list of pages in the group + PageSDict *exampleDict; // list of examples in the group + DirList *dirList; // list of directories in the group + + MemberList *allMemberList; + MemberNameInfoSDict *allMemberNameInfoSDict; + + Definition *groupScope; + + QList m_memberLists; + MemberGroupSDict *memberGroupSDict; + +}; + +class GroupSDict : public SDict +{ + public: + GroupSDict(uint size) : SDict(size) {} + virtual ~GroupSDict() {} + int compareItems(GCI item1,GCI item2) + { + return strcmp(((GroupDef*)item1)->groupTitle(),((GroupDef*)item2)->groupTitle()); + } +}; + +class GroupList : public QList +{ + public: + int compareItems(GCI item1,GCI item2) + { + return strcmp(((GroupDef*)item1)->groupTitle(),((GroupDef*)item2)->groupTitle()); + } +}; + +class GroupListIterator : public QListIterator +{ + public: + GroupListIterator(const GroupList &l) : QListIterator(l) {} + virtual ~GroupListIterator() {} +}; + +void addClassToGroups(Entry *root,ClassDef *cd); +void addNamespaceToGroups(Entry *root,NamespaceDef *nd); +void addGroupToGroups(Entry *root,GroupDef *subGroup); +void addMemberToGroups(Entry *root,MemberDef *md); +void addPageToGroups(Entry *root,PageDef *pd); +void addExampleToGroups(Entry *root,PageDef *eg); +void addDirToGroups(Entry *root,DirDef *dd); + +#endif + diff --git a/trunk/src/growbuf.h b/trunk/src/growbuf.h new file mode 100644 index 0000000..6798692 --- /dev/null +++ b/trunk/src/growbuf.h @@ -0,0 +1,38 @@ +#ifndef GROWBUF_H +#define GROWBUF_H + +#include +#include + +class GrowBuf +{ + public: + GrowBuf() : str(0), pos(0), len(0) {} + ~GrowBuf() { free(str); str=0; pos=0; len=0; } + void clear() { pos=0; } + void addChar(char c) { if (pos>=len) { len+=1024; str = (char*)realloc(str,len); } + str[pos++]=c; + } + void addStr(const char *s) { + int l=strlen(s); + if (pos+l>=len) { len+=l+1024; str = (char*)realloc(str,len); } + strcpy(&str[pos],s); + pos+=l; + } + void addStr(const char *s,int n) { + int l=strlen(s); + if (n=len) { len+=l+1024; str = (char*)realloc(str,len); } + strncpy(&str[pos],s,n); + pos+=l; + } + const char *get() { return str; } + int getPos() const { return pos; } + char at(int i) const { return str[i]; } + private: + char *str; + int pos; + int len; +}; + +#endif diff --git a/trunk/src/header.html b/trunk/src/header.html new file mode 100644 index 0000000..76e9553 --- /dev/null +++ b/trunk/src/header.html @@ -0,0 +1,49 @@ + + + + + +$projectname: $title +$title + + +$treeview +$search +$mathjax + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + +
+
$projectname +  $projectnumber +
+
$projectbrief
+
+
$projectbrief
+
$searchbox
+
+ diff --git a/trunk/src/header_html.h b/trunk/src/header_html.h new file mode 100644 index 0000000..4ed2e02 --- /dev/null +++ b/trunk/src/header_html.h @@ -0,0 +1,49 @@ +"\n" +"\n" +"\n" +"\n" +"\n" +"$projectname: $title\n" +"$title\n" +"\n" +"\n" +"$treeview\n" +"$search\n" +"$mathjax\n" +"\n" +"\n" +"
\n" +"\n" +"\n" +"
\n" +"\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"
\"Logo\"\n" +"
$projectname\n" +"  $projectnumber\n" +"
\n" +"
$projectbrief
\n" +"
\n" +"
$projectbrief
\n" +"
$searchbox
\n" +"
\n" +"\n" diff --git a/trunk/src/htags.cpp b/trunk/src/htags.cpp new file mode 100644 index 0000000..caa4535 --- /dev/null +++ b/trunk/src/htags.cpp @@ -0,0 +1,179 @@ +/****************************************************************************** + * + * Copyright (C) 1997-2012 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. + * + */ + +#include + +#include +#include + +#include "qtbc.h" +#include "htags.h" +#include "util.h" +#include "message.h" +#include "config.h" +#include "portable.h" + + +bool Htags::useHtags = FALSE; + +static QDir g_inputDir; +static QDict g_symbolDict(10007); + +/*! constructs command line of htags(1) and executes it. + * \retval TRUE success + * \retval FALSE an error has occured. + */ +bool Htags::execute(const QCString &htmldir) +{ + static QStrList &inputSource = Config_getList("INPUT"); + static bool quiet = Config_getBool("QUIET"); + static bool warnings = Config_getBool("WARNINGS"); + static QCString htagsOptions = ""; //Config_getString("HTAGS_OPTIONS"); + static QCString projectName = Config_getString("PROJECT_NAME"); + static QCString projectNumber = Config_getString("PROJECT_NUMBER"); + + QCString cwd = convertToQCString(QDir::currentDirPath()); + if (inputSource.isEmpty()) + { + g_inputDir.setPath(cwd); + } + else if (inputSource.count()==1) + { + g_inputDir.setPath(inputSource.first()); + if (!g_inputDir.exists()) + err("error: Cannot find directory %s. " + "Check the value of the INPUT tag in the configuration file.\n", + inputSource.first() + ); + } + else + { + err("error: If you use USE_HTAGS then INPUT should specific a single directory. \n"); + return FALSE; + } + + /* + * Construct command line for htags(1). + */ + QCString commandLine = " -g -s -a -n "; + if (!quiet) commandLine += "-v "; + if (warnings) commandLine += "-w "; + if (!htagsOptions.isEmpty()) + { + commandLine += ' '; + commandLine += htagsOptions; + } + if (!projectName.isEmpty()) + { + commandLine += "-t \""; + commandLine += projectName; + if (!projectNumber.isEmpty()) + { + commandLine += '-'; + commandLine += projectNumber; + } + commandLine += "\" "; + } + commandLine += " \"" + htmldir + "\""; + QCString oldDir = convertToQCString(QDir::currentDirPath()); + QDir::setCurrent(g_inputDir.absPath()); + //printf("CommandLine=[%s]\n",commandLine.data()); + portable_sysTimerStart(); + bool result=portable_system("htags",commandLine,FALSE)==0; + portable_sysTimerStop(); + QDir::setCurrent(oldDir); + return result; +} + + +/*! load filemap and make index. + * \param htmlDir of HTML directory generated by htags(1). + * \retval TRUE success + * \retval FALSE error + */ +bool Htags::loadFilemap(const QCString &htmlDir) +{ + QCString fileMapName = htmlDir+"/HTML/FILEMAP"; + QCString fileMap; + QFileInfo fi(fileMapName); + /* + * Construct FILEMAP dictionary using QDict. + * + * In FILEMAP, URL includes 'html' suffix but we cut it off according + * to the method of FileDef class. + * + * FILEMAP format: + * \t.html\n + * QDICT: + * dict[] = + */ + if (fi.exists() && fi.isReadable()) + { + QFile f(fileMapName); + const int maxlen = 8192; + QCString line(maxlen+1); + line.at(maxlen)='\0'; + if (f.open(IO_ReadOnly)) + { + while (f.readLine(line.data(),maxlen)>0) + { + //printf("Read line: %s",line.data()); + int sep = line.find('\t'); + if (sep!=-1) + { + QCString key = line.left(sep).stripWhiteSpace(); + QCString value = line.mid(sep+1).stripWhiteSpace(); + int ext=value.findRev('.'); + if (ext!=-1) value=value.left(ext); // strip extension + g_symbolDict.setAutoDelete(TRUE); + g_symbolDict.insert(key,new QCString(value)); + //printf("Key/Value=(%s,%s)\n",key.data(),value.data()); + } + } + return TRUE; + } + else + { + err("error: file %s cannot be opened\n",fileMapName.data()); + } + } + return FALSE; +} + +/*! convert path name into the url in the hypertext generated by htags. + * \param path path name + * \returns URL NULL: not found. + */ +QCString Htags::path2URL(const QCString &path) +{ + QCString url,symName=path; + QCString dir = convertToQCString(g_inputDir.absPath()); + int dl=dir.length(); + if ((int)symName.length()>dl+1) + { + symName = symName.mid(dl+1); + } + if (!symName.isEmpty()) + { + QCString *result = g_symbolDict[symName]; + //printf("path2URL=%s symName=%s result=%p\n",path.data(),symName.data(),result); + if (result) + { + url = "HTML/" + *result; + } + } + return url; +} + diff --git a/trunk/src/htags.h b/trunk/src/htags.h new file mode 100644 index 0000000..458adec --- /dev/null +++ b/trunk/src/htags.h @@ -0,0 +1,28 @@ +/****************************************************************************** + * + * Copyright (C) 1997-2012 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. + * + */ +#ifndef HTAGS_H +#define HTAGS_H + +class QCString; + +struct Htags +{ + static bool useHtags; + static bool loadFilemap(const QCString &htmldir); + static QCString path2URL(const QCString &path); + static bool execute(const QCString &htmldir); +}; + +#endif /* HTAGS_H */ diff --git a/trunk/src/htmlattrib.h b/trunk/src/htmlattrib.h new file mode 100644 index 0000000..b391861 --- /dev/null +++ b/trunk/src/htmlattrib.h @@ -0,0 +1,77 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#ifndef _HTMLATTRIB_H +#define _HTMLATTRIB_H + +/*! A Html option. A name, value pair */ +struct HtmlAttrib +{ + QCString name; + QCString value; +}; + +/*! @brief A list of Html attributes. + * + * The Html attributes are deeply copied into the list. + */ +class HtmlAttribList : public QList +{ + public: + HtmlAttribList() : QList() { setAutoDelete(TRUE); } + ~HtmlAttribList() { clear(); } + HtmlAttribList(const HtmlAttribList &l) : QList() + { operator=(l); } + HtmlAttribList &operator=(const HtmlAttribList &l) + { clear(); QList::operator=(l); return *this; } + QCString find(const QCString name) const + { + HtmlAttribList *that = (HtmlAttribList *)this; + QCString result; + HtmlAttrib *attr=that->first(); + while (attr) + { + if (attr->name==name) return attr->value; + attr=that->next(); + } + return result; + } + QCString toString() const + { + HtmlAttribList *that = (HtmlAttribList *)this; + QCString result; + HtmlAttrib *attr=that->first(); + while (attr) + { + result+=" "+attr->name+"=\""+attr->value+"\""; + attr=that->next(); + } + return result; + } + private: + QCollection::Item newItem( QCollection::Item d ) + { return (QCollection::Item)new HtmlAttrib(*(HtmlAttrib *)d); } + void deleteItem(QCollection::Item d) + { delete (HtmlAttrib *)d; } +}; + +/*! @brief Html attribute list iterator */ +class HtmlAttribListIterator : public QListIterator +{ + public: + HtmlAttribListIterator(const HtmlAttribList &l) : QListIterator(l) {} +}; + +#endif + diff --git a/trunk/src/htmldocvisitor.cpp b/trunk/src/htmldocvisitor.cpp new file mode 100644 index 0000000..dc73510 --- /dev/null +++ b/trunk/src/htmldocvisitor.cpp @@ -0,0 +1,1855 @@ +/****************************************************************************** + * + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#include +#include "htmldocvisitor.h" +#include "docparser.h" +#include "language.h" +#include "doxygen.h" +#include "outputgen.h" +#include "dot.h" +#include "message.h" +#include "config.h" +#include "htmlgen.h" +#include "parserintf.h" +#include "msc.h" +#include "util.h" + + +static const int NUM_HTML_LIST_TYPES = 4; +static const char types[][NUM_HTML_LIST_TYPES] = {"1", "a", "i", "A"}; + +static QCString convertIndexWordToAnchor(const QString &word) +{ + static char hex[] = "0123456789abcdef"; + uint i; + QCString result; + for (i=0;i>4]; + cs[1]=hex[c&0xf]; + cs[2]=0; + result+=cs; + } + } + return result; +} + +static bool mustBeOutsideParagraph(DocNode *n) +{ + switch (n->kind()) + { + /*
    */ + case DocNode::Kind_HtmlList: + case DocNode::Kind_SimpleList: + case DocNode::Kind_AutoList: + /*
    */ + case DocNode::Kind_SimpleSect: + case DocNode::Kind_ParamSect: + case DocNode::Kind_HtmlDescList: + case DocNode::Kind_XRefItem: + /* */ + case DocNode::Kind_HtmlTable: + /* */ + case DocNode::Kind_Section: + case DocNode::Kind_HtmlHeader: + /* \internal */ + case DocNode::Kind_Internal: + /*
    */ + case DocNode::Kind_Include: + case DocNode::Kind_Verbatim: + case DocNode::Kind_Image: + case DocNode::Kind_SecRefList: + /*
    */ + case DocNode::Kind_HorRuler: + /* CopyDoc gets paragraph markers from the wrapping DocPara node, + * but needs to insert them for all documentation being copied to + * preserve formatting. + */ + case DocNode::Kind_Copy: + /*
    */ + case DocNode::Kind_HtmlBlockQuote: + return TRUE; + case DocNode::Kind_StyleChange: + return ((DocStyleChange*)n)->style()==DocStyleChange::Preformatted || + ((DocStyleChange*)n)->style()==DocStyleChange::Div || + ((DocStyleChange*)n)->style()==DocStyleChange::Center; + case DocNode::Kind_Formula: + return !((DocFormula*)n)->isInline(); + default: + break; + } + return FALSE; +} + +static QString htmlAttribsToString(const HtmlAttribList &attribs) +{ + QString result; + HtmlAttribListIterator li(attribs); + HtmlAttrib *att; + for (li.toFirst();(att=li.current());++li) + { + if (!att->value.isEmpty()) // ignore attribute without values as they + // are not XHTML compliant + { + result+=" "; + result+=att->name; + result+="=\""+convertToXML(att->value)+"\""; + } + } + return result; +} + +//------------------------------------------------------------------------- + +HtmlDocVisitor::HtmlDocVisitor(FTextStream &t,CodeOutputInterface &ci, + const char *langExt) + : DocVisitor(DocVisitor_Html), m_t(t), m_ci(ci), m_insidePre(FALSE), + m_hide(FALSE), m_langExt(langExt) +{ +} + + //-------------------------------------- + // visitor functions for leaf nodes + //-------------------------------------- + +void HtmlDocVisitor::visit(DocWord *w) +{ + //printf("word: %s\n",w->word().data()); + if (m_hide) return; + filter(w->word()); +} + +void HtmlDocVisitor::visit(DocLinkedWord *w) +{ + if (m_hide) return; + startLink(w->ref(),w->file(),w->relPath(),w->anchor(),w->tooltip()); + filter(w->word()); + endLink(); +} + +void HtmlDocVisitor::visit(DocWhiteSpace *w) +{ + if (m_hide) return; + if (m_insidePre) + { + m_t << w->chars(); + } + else + { + m_t << " "; + } +} + +void HtmlDocVisitor::visit(DocSymbol *s) +{ + if (m_hide) return; + switch(s->symbol()) + { + case DocSymbol::BSlash: m_t << "\\"; break; + case DocSymbol::At: m_t << "@"; break; + case DocSymbol::Less: m_t << "<"; break; + case DocSymbol::Greater: m_t << ">"; break; + case DocSymbol::Amp: m_t << "&"; break; + case DocSymbol::Dollar: m_t << "$"; break; + case DocSymbol::Hash: m_t << "#"; break; + case DocSymbol::DoubleColon: m_t << "::"; break; + case DocSymbol::Percent: m_t << "%"; break; + case DocSymbol::Copy: m_t << "©"; break; + case DocSymbol::Tm: m_t << "™"; break; + case DocSymbol::Reg: m_t << "®"; break; + case DocSymbol::Apos: m_t << "'"; break; + case DocSymbol::Quot: m_t << "\""; break; + case DocSymbol::Lsquo: m_t << "‘"; break; + case DocSymbol::Rsquo: m_t << "’"; break; + case DocSymbol::Ldquo: m_t << "“"; break; + case DocSymbol::Rdquo: m_t << "”"; break; + case DocSymbol::Ndash: m_t << "–"; break; + case DocSymbol::Mdash: m_t << "—"; break; + case DocSymbol::Uml: m_t << "&" << s->letter() << "uml;"; break; + case DocSymbol::Acute: m_t << "&" << s->letter() << "acute;"; break; + case DocSymbol::Grave: m_t << "&" << s->letter() << "grave;"; break; + case DocSymbol::Circ: m_t << "&" << s->letter() << "circ;"; break; + case DocSymbol::Slash: m_t << "&" << s->letter() << "slash;"; break; + case DocSymbol::Tilde: m_t << "&" << s->letter() << "tilde;"; break; + case DocSymbol::Szlig: m_t << "ß"; break; + case DocSymbol::Cedil: m_t << "&" << s->letter() << "cedil;"; break; + case DocSymbol::Ring: m_t << "&" << s->letter() << "ring;"; break; + case DocSymbol::Nbsp: m_t << " "; break; + case DocSymbol::AElig: m_t << "Æ"; break; + case DocSymbol::Aelig: m_t << "æ"; break; + default: + err("error: unknown symbol found\n"); + } +} + +void HtmlDocVisitor::visit(DocURL *u) +{ + if (m_hide) return; + if (u->isEmail()) // mail address + { + // do obfuscation via javascript + m_t << "url(); + uint i; + int size=3; + for (i=0;i"; + size=5; + for (i=0;i.nosp@m."; + i+=size; + if (size==5) size=4; else size=5; + } + m_t << ""; + } + else // web address + { + m_t << "url() << "\">"; + filter(u->url()); + m_t << ""; + } +} + +void HtmlDocVisitor::visit(DocLineBreak *) +{ + if (m_hide) return; + m_t << "
    \n"; +} + +void HtmlDocVisitor::visit(DocHorRuler *) +{ + if (m_hide) return; + m_t << "
    \n"; +} + +void HtmlDocVisitor::visit(DocStyleChange *s) +{ + if (m_hide) return; + switch (s->style()) + { + case DocStyleChange::Bold: + if (s->enable()) m_t << "attribs()) << ">"; else m_t << ""; + break; + case DocStyleChange::Italic: + if (s->enable()) m_t << "attribs()) << ">"; else m_t << ""; + break; + case DocStyleChange::Code: + if (s->enable()) m_t << "attribs()) << ">"; else m_t << ""; + break; + case DocStyleChange::Subscript: + if (s->enable()) m_t << "attribs()) << ">"; else m_t << ""; + break; + case DocStyleChange::Superscript: + if (s->enable()) m_t << "attribs()) << ">"; else m_t << ""; + break; + case DocStyleChange::Center: + if (s->enable()) + { + forceEndParagraph(s); + m_t << "attribs()) << ">"; + } + else + { + m_t << ""; + forceStartParagraph(s); + } + break; + case DocStyleChange::Small: + if (s->enable()) m_t << "attribs()) << ">"; else m_t << ""; + break; + case DocStyleChange::Preformatted: + if (s->enable()) + { + forceEndParagraph(s); + m_t << "attribs()) << ">"; + m_insidePre=TRUE; + } + else + { + m_insidePre=FALSE; + m_t << ""; + forceStartParagraph(s); + } + break; + case DocStyleChange::Div: + if (s->enable()) + { + forceEndParagraph(s); + m_t << "attribs()) << ">"; + } + else + { + m_t << "
    "; + forceStartParagraph(s); + } + break; + case DocStyleChange::Span: + if (s->enable()) m_t << "attribs()) << ">"; else m_t << ""; + break; + + } +} + + +void HtmlDocVisitor::visit(DocVerbatim *s) +{ + if (m_hide) return; + QCString lang = m_langExt; + if (!s->language().isEmpty()) // explicit language setting + { + lang = s->language(); + } + switch(s->type()) + { + case DocVerbatim::Code: + forceEndParagraph(s); + m_t << PREFRAG_START; + Doxygen::parserManager->getParser(lang) + ->parseCode(m_ci,s->context(),s->text(), + s->isExample(),s->exampleFile()); + m_t << PREFRAG_END; + forceStartParagraph(s); + break; + case DocVerbatim::Verbatim: + forceEndParagraph(s); + m_t << PREFRAG_START; + filter(s->text()); + m_t << PREFRAG_END; + forceStartParagraph(s); + break; + case DocVerbatim::HtmlOnly: + m_t << s->text(); + break; + case DocVerbatim::ManOnly: + case DocVerbatim::LatexOnly: + case DocVerbatim::XmlOnly: + /* nothing */ + break; + + case DocVerbatim::Dot: + { + static int dotindex = 1; + QCString fileName(4096); + + fileName.sprintf("%s%d%s", + (Config_getString("HTML_OUTPUT")+"/inline_dotgraph_").data(), + dotindex++, + ".dot" + ); + QFile file(fileName); + if (!file.open(IO_WriteOnly)) + { + err("Could not open file %s for writing\n",fileName.data()); + } + file.writeBlock( s->text(), s->text().length() ); + file.close(); + + forceEndParagraph(s); + m_t << "
    " << endl; + writeDotFile(fileName,s->relPath(),s->context()); + m_t << "
    " << endl; + forceStartParagraph(s); + + if (Config_getBool("DOT_CLEANUP")) file.remove(); + } + break; + case DocVerbatim::Msc: + { + static int mscindex = 1; + QCString baseName(4096); + + baseName.sprintf("%s%d", + (Config_getString("HTML_OUTPUT")+"/inline_mscgraph_").data(), + mscindex++ + ); + QFile file(baseName+".msc"); + if (!file.open(IO_WriteOnly)) + { + err("Could not open file %s.msc for writing\n",baseName.data()); + } + QCString text = "msc {"; + text+=s->text(); + text+="}"; + file.writeBlock( text, text.length() ); + file.close(); + + forceEndParagraph(s); + m_t << "
    " << endl; + writeMscFile(baseName+".msc",s->relPath(),s->context()); + m_t << "
    " << endl; + forceStartParagraph(s); + + if (Config_getBool("DOT_CLEANUP")) file.remove(); + } + break; + } +} + +void HtmlDocVisitor::visit(DocAnchor *anc) +{ + if (m_hide) return; + m_t << "anchor() << "\">"; +} + +void HtmlDocVisitor::visit(DocInclude *inc) +{ + if (m_hide) return; + switch(inc->type()) + { + case DocInclude::Include: + forceEndParagraph(inc); + m_t << PREFRAG_START; + Doxygen::parserManager->getParser(inc->extension()) + ->parseCode(m_ci, + inc->context(), + inc->text(), + inc->isExample(), + inc->exampleFile(), + 0, // fd + -1, // startLine + -1, // endLine + TRUE // inlineFragment + ); + m_t << PREFRAG_END; + forceStartParagraph(inc); + break; + case DocInclude::IncWithLines: + { + forceEndParagraph(inc); + m_t << PREFRAG_START; + QFileInfo cfi( inc->file() ); + FileDef fd( cfi.dirPath(), cfi.fileName() ); + Doxygen::parserManager->getParser(inc->extension()) + ->parseCode(m_ci, + inc->context(), + inc->text(), + inc->isExample(), + inc->exampleFile(), &fd); + m_t << PREFRAG_END; + forceStartParagraph(inc); + } + break; + case DocInclude::DontInclude: + break; + case DocInclude::HtmlInclude: + m_t << inc->text(); + break; + case DocInclude::VerbInclude: + forceEndParagraph(inc); + m_t << PREFRAG_START; + filter(inc->text()); + m_t << PREFRAG_END; + forceStartParagraph(inc); + break; + case DocInclude::Snippet: + { + forceEndParagraph(inc); + m_t << PREFRAG_START; + Doxygen::parserManager->getParser(inc->extension()) + ->parseCode(m_ci, + inc->context(), + extractBlock(inc->text(),inc->blockId()), + inc->isExample(), + inc->exampleFile(), + 0, + -1, // startLine + -1, // endLine + TRUE // inlineFragment + ); + m_t << PREFRAG_END; + forceStartParagraph(inc); + } + break; + } +} + +void HtmlDocVisitor::visit(DocIncOperator *op) +{ + //printf("DocIncOperator: type=%d first=%d, last=%d text=`%s'\n", + // op->type(),op->isFirst(),op->isLast(),op->text().data()); + if (op->isFirst()) + { + if (!m_hide) m_t << PREFRAG_START; + pushEnabled(); + m_hide=TRUE; + } + if (op->type()!=DocIncOperator::Skip) + { + popEnabled(); + if (!m_hide) + { + Doxygen::parserManager->getParser(m_langExt) + ->parseCode(m_ci,op->context(), + op->text(),op->isExample(), + op->exampleFile()); + } + pushEnabled(); + m_hide=TRUE; + } + if (op->isLast()) + { + popEnabled(); + if (!m_hide) m_t << PREFRAG_END; + } + else + { + if (!m_hide) m_t << endl; + } +} + +void HtmlDocVisitor::visit(DocFormula *f) +{ + if (m_hide) return; + bool bDisplay = !f->isInline(); + if (bDisplay) + { + forceEndParagraph(f); + m_t << "

    " << endl; + } + + if (Config_getBool("USE_MATHJAX")) + { + QCString text = f->text(); + bool closeInline = FALSE; + if (!bDisplay && !text.isEmpty() && text.at(0)=='$' && + text.at(text.length()-1)=='$') + { + closeInline=TRUE; + text = text.mid(1,text.length()-2); + m_t << "\\("; + } + m_t << convertToHtml(text); + if (closeInline) + { + m_t << "\\)"; + } + } + else + { + m_t << "\"";text()); + m_t << "\""; + /// @todo cache image dimensions on formula generation and give height/width + /// for faster preloading and better rendering of the page + m_t << " src=\"" << f->relPath() << f->name() << ".png\"/>"; + + } + if (bDisplay) + { + m_t << endl << "

    " << endl; + forceStartParagraph(f); + } +} + +void HtmlDocVisitor::visit(DocIndexEntry *e) +{ + QCString anchor = convertIndexWordToAnchor(e->entry()); + if (e->member()) + { + anchor.prepend(e->member()->anchor()+"_"); + } + m_t << ""; + //printf("*** DocIndexEntry: word='%s' scope='%s' member='%s'\n", + // e->entry().data(), + // e->scope() ? e->scope()->name().data() : "", + // e->member() ? e->member()->name().data() : "" + // ); + Doxygen::indexList.addIndexItem(e->scope(),e->member(),e->entry()); +} + +void HtmlDocVisitor::visit(DocSimpleSectSep *) +{ + m_t << "" << endl; + m_t << "
    " << endl; +} + +void HtmlDocVisitor::visit(DocCite *cite) +{ + if (m_hide) return; + if (!cite->file().isEmpty()) + { + startLink(cite->ref(),cite->file(),cite->relPath(),cite->anchor()); + } + else + { + m_t << "["; + } + filter(cite->text()); + if (!cite->file().isEmpty()) + { + endLink(); + } + else + { + m_t << "]"; + } +} + + +//-------------------------------------- +// visitor functions for compound nodes +//-------------------------------------- + + +void HtmlDocVisitor::visitPre(DocAutoList *l) +{ + //printf("DocAutoList::visitPre\n"); + if (m_hide) return; + forceEndParagraph(l); + if (l->isEnumList()) + { + // + // Do list type based on depth: + // 1. + // a. + // i. + // A. + // 1. (repeat)... + // + m_t << "
      depth() % NUM_HTML_LIST_TYPES] << "\">"; + } + else + { + m_t << "
        "; + } + if (!l->isPreformatted()) m_t << "\n"; +} + +void HtmlDocVisitor::visitPost(DocAutoList *l) +{ + //printf("DocAutoList::visitPost\n"); + if (m_hide) return; + if (l->isEnumList()) + { + m_t << "
    "; + } + else + { + m_t << ""; + } + if (!l->isPreformatted()) m_t << "\n"; + forceStartParagraph(l); +} + +void HtmlDocVisitor::visitPre(DocAutoListItem *) +{ + if (m_hide) return; + m_t << "
  • "; +} + +void HtmlDocVisitor::visitPost(DocAutoListItem *li) +{ + if (m_hide) return; + m_t << "
  • "; + if (!li->isPreformatted()) m_t << "\n"; +} + +template +bool isFirstChildNode(T *parent, DocNode *node) +{ + return parent->children().getFirst()==node; +} + +template +bool isLastChildNode(T *parent, DocNode *node) +{ + return parent->children().getLast()==node; +} + +bool isSeparatedParagraph(DocSimpleSect *parent,DocPara *par) +{ + QList nodes = parent->children(); + int i = nodes.findRef(par); + if (i==-1) return FALSE; + int count = parent->children().count(); + if (count>1 && i==0) + { + if (nodes.at(i+1)->kind()==DocNode::Kind_SimpleSectSep) + { + return TRUE; + } + } + else if (count>1 && i==count-1) + { + if (nodes.at(i-1)->kind()==DocNode::Kind_SimpleSectSep) + { + return TRUE; + } + } + else if (count>2 && i>0 && ikind()==DocNode::Kind_SimpleSectSep && + nodes.at(i+1)->kind()==DocNode::Kind_SimpleSectSep) + { + return TRUE; + } + } + return FALSE; +} + +static int getParagraphContext(DocPara *p,bool &isFirst,bool &isLast) +{ + int t=0; + isFirst=FALSE; + isLast=FALSE; + if (p && p->parent()) + { + switch (p->parent()->kind()) + { + case DocNode::Kind_AutoListItem: + //isFirst=TRUE; + //isLast =TRUE; + isFirst=isFirstChildNode((DocAutoListItem*)p->parent(),p); + isLast =isLastChildNode ((DocAutoListItem*)p->parent(),p); + t=1; // not used + break; + case DocNode::Kind_SimpleListItem: + isFirst=TRUE; + isLast =TRUE; + t=1; // not used + break; + case DocNode::Kind_ParamList: + isFirst=TRUE; + isLast =TRUE; + t=1; // not used + break; + case DocNode::Kind_HtmlListItem: + isFirst=isFirstChildNode((DocHtmlListItem*)p->parent(),p); + isLast =isLastChildNode ((DocHtmlListItem*)p->parent(),p); + if (isFirst) t=1; + if (isLast) t=3; + break; + case DocNode::Kind_SecRefItem: + isFirst=isFirstChildNode((DocSecRefItem*)p->parent(),p); + isLast =isLastChildNode ((DocSecRefItem*)p->parent(),p); + if (isFirst) t=1; + if (isLast) t=3; + break; + case DocNode::Kind_HtmlDescData: + isFirst=isFirstChildNode((DocHtmlDescData*)p->parent(),p); + isLast =isLastChildNode ((DocHtmlDescData*)p->parent(),p); + if (isFirst) t=2; + if (isLast) t=4; + break; + case DocNode::Kind_XRefItem: + isFirst=isFirstChildNode((DocXRefItem*)p->parent(),p); + isLast =isLastChildNode ((DocXRefItem*)p->parent(),p); + if (isFirst) t=2; + if (isLast) t=4; + break; + case DocNode::Kind_HtmlCell: + isFirst=isFirstChildNode((DocHtmlCell*)p->parent(),p); + isLast =isLastChildNode ((DocHtmlCell*)p->parent(),p); + if (isFirst) t=5; + if (isLast) t=6; + break; + case DocNode::Kind_SimpleSect: + isFirst=isFirstChildNode((DocSimpleSect*)p->parent(),p); + isLast =isLastChildNode ((DocSimpleSect*)p->parent(),p); + if (isFirst) t=2; + if (isLast) t=4; + if (isSeparatedParagraph((DocSimpleSect*)p->parent(),p)) + // if the paragraph is enclosed with separators it will + // be included in
    ..
    so avoid addition paragraph + // markers + { + isFirst=isLast=TRUE; + } + break; + default: + break; + } + //printf("para=%p parent()->kind=%d isFirst=%d isLast=%d t=%d\n", + // p,p->parent()->kind(),isFirst,isLast,t); + } + return t; +} + +void HtmlDocVisitor::visitPre(DocPara *p) +{ + if (m_hide) return; + + //printf("DocPara::visitPre: parent of kind %d ", + // p->parent() ? p->parent()->kind() : -1); + + bool needsTag = FALSE; + if (p && p->parent()) + { + switch (p->parent()->kind()) + { + case DocNode::Kind_Section: + case DocNode::Kind_Internal: + case DocNode::Kind_HtmlListItem: + case DocNode::Kind_HtmlDescData: + case DocNode::Kind_HtmlCell: + case DocNode::Kind_SimpleListItem: + case DocNode::Kind_AutoListItem: + case DocNode::Kind_SimpleSect: + case DocNode::Kind_XRefItem: + case DocNode::Kind_Copy: + case DocNode::Kind_HtmlBlockQuote: + needsTag = TRUE; + break; + case DocNode::Kind_Root: + needsTag = !((DocRoot*)p->parent())->singleLine(); + break; + default: + needsTag = FALSE; + } + } + + // if the first element of a paragraph is something that should be outside of + // the paragraph (
      ,
      ,
    ,..) then that will already started the + // paragraph and we don't need to do it here + uint nodeIndex = 0; + if (p && nodeIndexchildren().count()) + { + while (nodeIndexchildren().count() && + p->children().at(nodeIndex)->kind()==DocNode::Kind_WhiteSpace) + { + nodeIndex++; + } + if (nodeIndexchildren().count()) + { + DocNode *n = p->children().at(nodeIndex); + if (mustBeOutsideParagraph(n)) + { + needsTag = FALSE; + } + } + } + + // check if this paragraph is the first or last child of a
  • or
    . + // this allows us to mark the tag with a special class so we can + // fix the otherwise ugly spacing. + int t; + static const char *contexts[7] = + { "", // 0 + " class=\"startli\"", // 1 + " class=\"startdd\"", // 2 + " class=\"endli\"", // 3 + " class=\"enddd\"", // 4 + " class=\"starttd\"", // 5 + " class=\"endtd\"" // 6 + }; + bool isFirst; + bool isLast; + t = getParagraphContext(p,isFirst,isLast); + //printf("startPara first=%d last=%d\n",isFirst,isLast); + if (isFirst && isLast) needsTag=FALSE; + + //printf(" needsTag=%d\n",needsTag); + // write the paragraph tag (if needed) + if (needsTag) m_t << ""; +} + +void HtmlDocVisitor::visitPost(DocPara *p) +{ + bool needsTag = FALSE; + if (p && p->parent()) + { + switch (p->parent()->kind()) + { + case DocNode::Kind_Section: + case DocNode::Kind_Internal: + case DocNode::Kind_HtmlListItem: + case DocNode::Kind_HtmlDescData: + case DocNode::Kind_HtmlCell: + case DocNode::Kind_SimpleListItem: + case DocNode::Kind_AutoListItem: + case DocNode::Kind_SimpleSect: + case DocNode::Kind_XRefItem: + case DocNode::Kind_Copy: + case DocNode::Kind_HtmlBlockQuote: + needsTag = TRUE; + break; + case DocNode::Kind_Root: + needsTag = !((DocRoot*)p->parent())->singleLine(); + break; + default: + needsTag = FALSE; + } + } + + QCString context; + // if the last element of a paragraph is something that should be outside of + // the paragraph (
      ,
      ,
  • ) then that will already have ended the + // paragraph and we don't need to do it here + int nodeIndex = p->children().count()-1; + if (p && nodeIndex>=0) + { + while (nodeIndex>=0 && p->children().at(nodeIndex)->kind()==DocNode::Kind_WhiteSpace) + { + nodeIndex--; + } + if (nodeIndex>=0) + { + DocNode *n = p->children().at(nodeIndex); + if (mustBeOutsideParagraph(n)) + { + needsTag = FALSE; + } + } + } + + bool isFirst; + bool isLast; + getParagraphContext(p,isFirst,isLast); + //printf("endPara first=%d last=%d\n",isFirst,isLast); + if (isFirst && isLast) needsTag=FALSE; + + //printf("DocPara::visitPost needsTag=%d\n",needsTag); + + if (needsTag) m_t << "

    \n"; + +} + +void HtmlDocVisitor::visitPre(DocRoot *) +{ +} + +void HtmlDocVisitor::visitPost(DocRoot *) +{ +} + +void HtmlDocVisitor::visitPre(DocSimpleSect *s) +{ + if (m_hide) return; + forceEndParagraph(s); + m_t << "
    typeString() << "\">
    "; + switch(s->type()) + { + case DocSimpleSect::See: + m_t << theTranslator->trSeeAlso(); break; + case DocSimpleSect::Return: + m_t << theTranslator->trReturns(); break; + case DocSimpleSect::Author: + m_t << theTranslator->trAuthor(TRUE,TRUE); break; + case DocSimpleSect::Authors: + m_t << theTranslator->trAuthor(TRUE,FALSE); break; + case DocSimpleSect::Version: + m_t << theTranslator->trVersion(); break; + case DocSimpleSect::Since: + m_t << theTranslator->trSince(); break; + case DocSimpleSect::Date: + m_t << theTranslator->trDate(); break; + case DocSimpleSect::Note: + m_t << theTranslator->trNote(); break; + case DocSimpleSect::Warning: + m_t << theTranslator->trWarning(); break; + case DocSimpleSect::Pre: + m_t << theTranslator->trPrecondition(); break; + case DocSimpleSect::Post: + m_t << theTranslator->trPostcondition(); break; + case DocSimpleSect::Copyright: + m_t << theTranslator->trCopyright(); break; + case DocSimpleSect::Invar: + m_t << theTranslator->trInvariant(); break; + case DocSimpleSect::Remark: + m_t << theTranslator->trRemarks(); break; + case DocSimpleSect::Attention: + m_t << theTranslator->trAttention(); break; + case DocSimpleSect::User: break; + case DocSimpleSect::Rcs: break; + case DocSimpleSect::Unknown: break; + } + + // special case 1: user defined title + if (s->type()!=DocSimpleSect::User && s->type()!=DocSimpleSect::Rcs) + { + m_t << ":
    "; + } +} + +void HtmlDocVisitor::visitPost(DocSimpleSect *s) +{ + if (m_hide) return; + m_t << "
    \n"; + forceStartParagraph(s); +} + +void HtmlDocVisitor::visitPre(DocTitle *) +{ +} + +void HtmlDocVisitor::visitPost(DocTitle *) +{ + if (m_hide) return; + m_t << "
    "; +} + +void HtmlDocVisitor::visitPre(DocSimpleList *sl) +{ + if (m_hide) return; + forceEndParagraph(sl); + m_t << "
      "; + if (!sl->isPreformatted()) m_t << "\n"; + +} + +void HtmlDocVisitor::visitPost(DocSimpleList *sl) +{ + if (m_hide) return; + m_t << "
    "; + if (!sl->isPreformatted()) m_t << "\n"; + forceStartParagraph(sl); +} + +void HtmlDocVisitor::visitPre(DocSimpleListItem *) +{ + if (m_hide) return; + m_t << "
  • "; +} + +void HtmlDocVisitor::visitPost(DocSimpleListItem *li) +{ + if (m_hide) return; + m_t << "
  • "; + if (!li->isPreformatted()) m_t << "\n"; +} + +void HtmlDocVisitor::visitPre(DocSection *s) +{ + if (m_hide) return; + forceEndParagraph(s); + m_t << "level()+1 << ">"; + m_t << "anchor(); + m_t << "\">" << endl; + filter(convertCharEntitiesToUTF8(s->title().data())); + m_t << "level()+1 << ">\n"; +} + +void HtmlDocVisitor::visitPost(DocSection *s) +{ + forceStartParagraph(s); +} + +void HtmlDocVisitor::visitPre(DocHtmlList *s) +{ + if (m_hide) return; + forceEndParagraph(s); + if (s->type()==DocHtmlList::Ordered) + { + m_t << "attribs()) << ">\n"; + } + else + { + m_t << "attribs()) << ">\n"; + } +} + +void HtmlDocVisitor::visitPost(DocHtmlList *s) +{ + if (m_hide) return; + if (s->type()==DocHtmlList::Ordered) + { + m_t << ""; + } + else + { + m_t << ""; + } + if (!s->isPreformatted()) m_t << "\n"; + forceStartParagraph(s); +} + +void HtmlDocVisitor::visitPre(DocHtmlListItem *i) +{ + if (m_hide) return; + m_t << "attribs()) << ">"; + if (!i->isPreformatted()) m_t << "\n"; +} + +void HtmlDocVisitor::visitPost(DocHtmlListItem *) +{ + if (m_hide) return; + m_t << "\n"; +} + +void HtmlDocVisitor::visitPre(DocHtmlDescList *dl) +{ + if (m_hide) return; + forceEndParagraph(dl); + m_t << "attribs()) << ">\n"; +} + +void HtmlDocVisitor::visitPost(DocHtmlDescList *dl) +{ + if (m_hide) return; + m_t << "\n"; + forceStartParagraph(dl); +} + +void HtmlDocVisitor::visitPre(DocHtmlDescTitle *dt) +{ + if (m_hide) return; + m_t << "attribs()) << ">"; +} + +void HtmlDocVisitor::visitPost(DocHtmlDescTitle *) +{ + if (m_hide) return; + m_t << "\n"; +} + +void HtmlDocVisitor::visitPre(DocHtmlDescData *dd) +{ + if (m_hide) return; + m_t << "attribs()) << ">"; +} + +void HtmlDocVisitor::visitPost(DocHtmlDescData *) +{ + if (m_hide) return; + m_t << "
    \n"; +} + +void HtmlDocVisitor::visitPre(DocHtmlTable *t) +{ + if (m_hide) return; + + forceEndParagraph(t); + + QString attrs = htmlAttribsToString(t->attribs()); + if (attrs.isEmpty()) + { + m_t << "
    \n"; + } + else + { + m_t << "
    attribs()) << ">\n"; + } +} + +void HtmlDocVisitor::visitPost(DocHtmlTable *t) +{ + if (m_hide) return; + m_t << "
    \n"; + forceStartParagraph(t); +} + +void HtmlDocVisitor::visitPre(DocHtmlRow *tr) +{ + if (m_hide) return; + m_t << "attribs()) << ">\n"; +} + +void HtmlDocVisitor::visitPost(DocHtmlRow *) +{ + if (m_hide) return; + m_t << "\n"; +} + +void HtmlDocVisitor::visitPre(DocHtmlCell *c) +{ + if (m_hide) return; + if (c->isHeading()) + { + m_t << "attribs()) << ">"; + } + else + { + m_t << "attribs()) << ">"; + } +} + +void HtmlDocVisitor::visitPost(DocHtmlCell *c) +{ + if (m_hide) return; + if (c->isHeading()) m_t << ""; else m_t << ""; +} + +void HtmlDocVisitor::visitPre(DocHtmlCaption *c) +{ + if (m_hide) return; + bool hasAlign = FALSE; + HtmlAttribListIterator li(c->attribs()); + HtmlAttrib *att; + for (li.toFirst();(att=li.current());++li) + { + if (att->name=="align") hasAlign=TRUE; + } + m_t << "attribs()); + if (!hasAlign) m_t << " align=\"bottom\""; + m_t << ">"; +} + +void HtmlDocVisitor::visitPost(DocHtmlCaption *) +{ + if (m_hide) return; + m_t << "\n"; +} + +void HtmlDocVisitor::visitPre(DocInternal *) +{ + if (m_hide) return; + //forceEndParagraph(i); + //m_t << "

    " << theTranslator->trForInternalUseOnly() << "

    " << endl; +} + +void HtmlDocVisitor::visitPost(DocInternal *) +{ + if (m_hide) return; + //forceStartParagraph(i); +} + +void HtmlDocVisitor::visitPre(DocHRef *href) +{ + if (m_hide) return; + QCString url = correctURL(href->url(),href->relPath()); + m_t << "attribs()) << ">"; +} + +void HtmlDocVisitor::visitPost(DocHRef *) +{ + if (m_hide) return; + m_t << ""; +} + +void HtmlDocVisitor::visitPre(DocHtmlHeader *header) +{ + if (m_hide) return; + forceEndParagraph(header); + m_t << "level() + << htmlAttribsToString(header->attribs()) << ">"; +} + +void HtmlDocVisitor::visitPost(DocHtmlHeader *header) +{ + if (m_hide) return; + m_t << "level() << ">\n"; + forceStartParagraph(header); +} + +void HtmlDocVisitor::visitPre(DocImage *img) +{ + if (img->type()==DocImage::Html) + { + forceEndParagraph(img); + if (m_hide) return; + QString baseName=img->name(); + int i; + if ((i=baseName.findRev('/'))!=-1 || (i=baseName.findRev('\\'))!=-1) + { + baseName=baseName.right(baseName.length()-i-1); + } + m_t << "
    " << endl; + QCString url = img->url(); + if (url.isEmpty()) + { + m_t << "relPath() << img->name() << "\" alt=\"" + << baseName << "\"" << htmlAttribsToString(img->attribs()) + << "/>" << endl; + } + else + { + m_t << "relPath()) << "\" " + << htmlAttribsToString(img->attribs()) + << "/>" << endl; + } + if (img->hasCaption()) + { + m_t << "
    " << endl; + } + } + else // other format -> skip + { + pushEnabled(); + m_hide=TRUE; + } +} + +void HtmlDocVisitor::visitPost(DocImage *img) +{ + if (img->type()==DocImage::Html) + { + if (m_hide) return; + if (img->hasCaption()) + { + m_t << "
    "; + } + m_t << "
    " << endl; + forceStartParagraph(img); + } + else // other format + { + popEnabled(); + } +} + +void HtmlDocVisitor::visitPre(DocDotFile *df) +{ + if (m_hide) return; + m_t << "
    " << endl; + writeDotFile(df->file(),df->relPath(),df->context()); + if (df->hasCaption()) + { + m_t << "
    " << endl; + } +} + +void HtmlDocVisitor::visitPost(DocDotFile *df) +{ + if (m_hide) return; + if (df->hasCaption()) + { + m_t << "
    " << endl; + } + m_t << "
    " << endl; +} + +void HtmlDocVisitor::visitPre(DocMscFile *df) +{ + if (m_hide) return; + m_t << "
    " << endl; + writeMscFile(df->file(),df->relPath(),df->context()); + if (df->hasCaption()) + { + m_t << "
    " << endl; + } +} +void HtmlDocVisitor::visitPost(DocMscFile *df) +{ + if (m_hide) return; + if (df->hasCaption()) + { + m_t << "
    " << endl; + } + m_t << "
    " << endl; +} + +void HtmlDocVisitor::visitPre(DocLink *lnk) +{ + if (m_hide) return; + startLink(lnk->ref(),lnk->file(),lnk->relPath(),lnk->anchor()); +} + +void HtmlDocVisitor::visitPost(DocLink *) +{ + if (m_hide) return; + endLink(); +} + +void HtmlDocVisitor::visitPre(DocRef *ref) +{ + if (m_hide) return; + if (!ref->file().isEmpty()) + { + // when ref->isSubPage()==TRUE we use ref->file() for HTML and + // ref->anchor() for LaTeX/RTF + startLink(ref->ref(),ref->file(),ref->relPath(),ref->isSubPage() ? QCString() : ref->anchor()); + } + if (!ref->hasLinkText()) filter(ref->targetTitle()); +} + +void HtmlDocVisitor::visitPost(DocRef *ref) +{ + if (m_hide) return; + if (!ref->file().isEmpty()) endLink(); + //m_t << " "; +} + +void HtmlDocVisitor::visitPre(DocSecRefItem *ref) +{ + if (m_hide) return; + QString refName=ref->file(); + if (refName.right(Doxygen::htmlFileExtension.length())!= + QString(Doxygen::htmlFileExtension)) + { + refName+=Doxygen::htmlFileExtension; + } + m_t << "
  • anchor() << "\">"; + +} + +void HtmlDocVisitor::visitPost(DocSecRefItem *) +{ + if (m_hide) return; + m_t << "
  • \n"; +} + +void HtmlDocVisitor::visitPre(DocSecRefList *s) +{ + if (m_hide) return; + forceEndParagraph(s); + m_t << "
    " << endl; + m_t << "
      " << endl; +} + +void HtmlDocVisitor::visitPost(DocSecRefList *s) +{ + if (m_hide) return; + m_t << "
    " << endl; + m_t << "
    " << endl; + forceStartParagraph(s); +} + +//void HtmlDocVisitor::visitPre(DocLanguage *l) +//{ +// QString langId = Config_getEnum("OUTPUT_LANGUAGE"); +// if (l->id().lower()!=langId.lower()) +// { +// pushEnabled(); +// m_hide = TRUE; +// } +//} +// +//void HtmlDocVisitor::visitPost(DocLanguage *l) +//{ +// QString langId = Config_getEnum("OUTPUT_LANGUAGE"); +// if (l->id().lower()!=langId.lower()) +// { +// popEnabled(); +// } +//} + +void HtmlDocVisitor::visitPre(DocParamSect *s) +{ + if (m_hide) return; + forceEndParagraph(s); + QCString className; + QCString heading; + switch(s->type()) + { + case DocParamSect::Param: + heading=theTranslator->trParameters(); + className="params"; + break; + case DocParamSect::RetVal: + heading=theTranslator->trReturnValues(); + className="retval"; + break; + case DocParamSect::Exception: + heading=theTranslator->trExceptions(); + className="exception"; + break; + case DocParamSect::TemplateParam: + heading="Template Parameters"; break; // TODO: TRANSLATE ME + className="tparams"; + default: + ASSERT(0); + } + m_t << "
    "; + m_t << heading << ":"; + m_t << "
    " << endl; + m_t << " " << endl; +} + +void HtmlDocVisitor::visitPost(DocParamSect *s) +{ + if (m_hide) return; + m_t << "
    " << endl; + m_t << "
    " << endl; + m_t << "
    " << endl; + forceStartParagraph(s); +} + +void HtmlDocVisitor::visitPre(DocParamList *pl) +{ + //printf("DocParamList::visitPre\n"); + if (m_hide) return; + m_t << " "; + DocParamSect *sect = 0; + if (pl->parent()->kind()==DocNode::Kind_ParamSect) + { + sect=(DocParamSect*)pl->parent(); + } + if (sect && sect->hasInOutSpecifier()) + { + m_t << ""; + if (pl->direction()!=DocParamSect::Unspecified) + { + m_t << "["; + if (pl->direction()==DocParamSect::In) + { + m_t << "in"; + } + else if (pl->direction()==DocParamSect::Out) + { + m_t << "out"; + } + else if (pl->direction()==DocParamSect::InOut) + { + m_t << "in,out"; + } + m_t << "]"; + } + m_t << ""; + } + if (sect && sect->hasTypeSpecifier()) + { + m_t << ""; + QListIterator li(pl->paramTypes()); + DocNode *type; + bool first=TRUE; + for (li.toFirst();(type=li.current());++li) + { + if (!first) m_t << " | "; else first=FALSE; + if (type->kind()==DocNode::Kind_Word) + { + visit((DocWord*)type); + } + else if (type->kind()==DocNode::Kind_LinkedWord) + { + visit((DocLinkedWord*)type); + } + } + m_t << ""; + } + m_t << ""; + //QStrListIterator li(pl->parameters()); + //const char *s; + QListIterator li(pl->parameters()); + DocNode *param; + bool first=TRUE; + for (li.toFirst();(param=li.current());++li) + { + if (!first) m_t << ","; else first=FALSE; + if (param->kind()==DocNode::Kind_Word) + { + visit((DocWord*)param); + } + else if (param->kind()==DocNode::Kind_LinkedWord) + { + visit((DocLinkedWord*)param); + } + } + m_t << ""; +} + +void HtmlDocVisitor::visitPost(DocParamList *) +{ + //printf("DocParamList::visitPost\n"); + if (m_hide) return; + m_t << "" << endl; +} + +void HtmlDocVisitor::visitPre(DocXRefItem *x) +{ + if (m_hide) return; + forceEndParagraph(x); + bool anonymousEnum = x->file()=="@"; + if (!anonymousEnum) + { + m_t << "
    key() << "\">
    relPath() << x->file() << Doxygen::htmlFileExtension + << "#" << x->anchor() << "\">"; + } + else + { + m_t << "
    key() << "\">
    "; + } + filter(x->title()); + m_t << ":"; + if (!anonymousEnum) m_t << ""; + m_t << "
    "; +} + +void HtmlDocVisitor::visitPost(DocXRefItem *x) +{ + if (m_hide) return; + m_t << "
    " << endl; + forceStartParagraph(x); +} + +void HtmlDocVisitor::visitPre(DocInternalRef *ref) +{ + if (m_hide) return; + startLink(0,ref->file(),ref->relPath(),ref->anchor()); +} + +void HtmlDocVisitor::visitPost(DocInternalRef *) +{ + if (m_hide) return; + endLink(); + m_t << " "; +} + +void HtmlDocVisitor::visitPre(DocCopy *) +{ +} + +void HtmlDocVisitor::visitPost(DocCopy *) +{ +} + +void HtmlDocVisitor::visitPre(DocText *) +{ +} + +void HtmlDocVisitor::visitPost(DocText *) +{ +} + +void HtmlDocVisitor::visitPre(DocHtmlBlockQuote *b) +{ + if (m_hide) return; + forceEndParagraph(b); + + QString attrs = htmlAttribsToString(b->attribs()); + if (attrs.isEmpty()) + { + m_t << "
    \n"; + } + else + { + m_t << "
    attribs()) << ">\n"; + } +} + +void HtmlDocVisitor::visitPost(DocHtmlBlockQuote *b) +{ + if (m_hide) return; + m_t << "
    " << endl; + forceStartParagraph(b); +} + +void HtmlDocVisitor::filter(const char *str) +{ + if (str==0) return; + const char *p=str; + char c; + while (*p) + { + c=*p++; + switch(c) + { + case '<': m_t << "<"; break; + case '>': m_t << ">"; break; + case '&': m_t << "&"; break; + default: m_t << c; + } + } +} + +/// Escape basic entities to produce a valid CDATA attribute value, +/// assume that the outer quoting will be using the double quote " +void HtmlDocVisitor::filterQuotedCdataAttr(const char* str) +{ + if (str==0) return; + const char *p=str; + char c; + while (*p) + { + c=*p++; + switch(c) + { + case '&': m_t << "&"; break; + case '"': m_t << """; break; + // For SGML compliance, and given the SGML declaration for HTML syntax, + // it's enough to replace these two, provided that the declaration + // for the HTML version we generate (and as supported by the browser) + // specifies that all the other symbols used in rawVal are + // within the right charachter class (i.e., they're not + // some multinational weird charachters not in the BASESET). + // We assume that 1) the browser will support whatever is remaining + // in the formula and 2) the TeX formulae are generally governed + // by even stricter charachter restrictions so it should be enough. + // + // On some incompliant browsers, additional translation of + // '>' and '<' into ">" and "<", respectively, might be needed; + // but I'm unaware of particular modern (last 4 years) versions + // with such problems, so let's not do it for performance. + // Also, some brousers will (wrongly) not process the entity references + // inside the attribute value and show the &...; form instead, + // so we won't create entites unless necessary to minimize clutter there. + // --vassilii + default: m_t << c; + } + } +} + +void HtmlDocVisitor::startLink(const QCString &ref,const QCString &file, + const QCString &relPath,const QCString &anchor, + const QCString &tooltip) +{ + if (!ref.isEmpty()) // link to entity imported via tag file + { + m_t << ""; +} + +void HtmlDocVisitor::endLink() +{ + m_t << ""; +} + +void HtmlDocVisitor::pushEnabled() +{ + m_enabled.push(new bool(m_hide)); +} + +void HtmlDocVisitor::popEnabled() +{ + bool *v=m_enabled.pop(); + ASSERT(v!=0); + m_hide = *v; + delete v; +} + +void HtmlDocVisitor::writeDotFile(const QCString &fn,const QCString &relPath, + const QCString &context) +{ + QCString baseName=fn; + int i; + if ((i=baseName.findRev('/'))!=-1) + { + baseName=baseName.right(baseName.length()-i-1); + } + if ((i=baseName.find('.'))!=-1) // strip extension + { + baseName=baseName.left(i); + } + baseName.prepend("dot_"); + QCString outDir = Config_getString("HTML_OUTPUT"); + writeDotGraphFromFile(fn,outDir,baseName,BITMAP); + writeDotImageMapFromFile(m_t,fn,outDir,relPath,baseName,context); +} + +void HtmlDocVisitor::writeMscFile(const QCString &fileName, + const QCString &relPath, + const QCString &context) +{ + QCString baseName=fileName; + int i; + if ((i=baseName.findRev('/'))!=-1) // strip path + { + baseName=baseName.right(baseName.length()-i-1); + } + if ((i=baseName.find('.'))!=-1) // strip extension + { + baseName=baseName.left(i); + } + baseName.prepend("msc_"); + QCString outDir = Config_getString("HTML_OUTPUT"); + writeMscGraphFromFile(fileName,outDir,baseName,MSC_BITMAP); + writeMscImageMapFromFile(m_t,fileName,outDir,relPath,baseName,context); +} + +/** Used for items found inside a paragraph, which due to XHTML restrictions + * have to be outside of the paragraph. This method will forcefully end + * the current paragraph and forceStartParagraph() will restart it. + */ +void HtmlDocVisitor::forceEndParagraph(DocNode *n) +{ + //printf("forceEndParagraph(%p) %d\n",n,n->kind()); + if (n->parent() && n->parent()->kind()==DocNode::Kind_Para) + { + DocPara *para = (DocPara*)n->parent(); + int nodeIndex = para->children().findRef(n); + nodeIndex--; + if (nodeIndex<0) return; // first node + while (nodeIndex>=0 && + para->children().at(nodeIndex)->kind()==DocNode::Kind_WhiteSpace + ) + { + nodeIndex--; + } + if (nodeIndex>=0) + { + DocNode *n = para->children().at(nodeIndex); + //printf("n=%p kind=%d outside=%d\n",n,n->kind(),mustBeOutsideParagraph(n)); + if (mustBeOutsideParagraph(n)) return; + } + + bool isFirst; + bool isLast; + getParagraphContext(para,isFirst,isLast); + //printf("forceEnd first=%d last=%d\n",isFirst,isLast); + if (isFirst && isLast) return; + + m_t << "

    " << endl; + } +} + +/** Used for items found inside a paragraph, which due to XHTML restrictions + * have to be outside of the paragraph. This method will forcefully start + * the paragraph, that was previously ended by forceEndParagraph(). + */ +void HtmlDocVisitor::forceStartParagraph(DocNode *n) +{ + //printf("forceStartParagraph(%p) %d\n",n,n->kind()); + if (n->parent() && n->parent()->kind()==DocNode::Kind_Para) // if we are inside a paragraph + { + DocPara *para = (DocPara*)n->parent(); + int nodeIndex = para->children().findRef(n); + int numNodes = para->children().count(); + nodeIndex++; + if (nodeIndex==numNodes) return; // last node + while (nodeIndexchildren().at(nodeIndex)->kind()==DocNode::Kind_WhiteSpace + ) + { + nodeIndex++; + } + if (nodeIndexchildren().at(nodeIndex); + if (mustBeOutsideParagraph(n)) return; + } + else + { + return; // only whitespace at the end! + } + + bool isFirst; + bool isLast; + getParagraphContext(para,isFirst,isLast); + //printf("forceStart first=%d last=%d\n",isFirst,isLast); + if (isFirst && isLast) return; + + m_t << "

    "; + } +} + diff --git a/trunk/src/htmldocvisitor.h b/trunk/src/htmldocvisitor.h new file mode 100644 index 0000000..33d1177 --- /dev/null +++ b/trunk/src/htmldocvisitor.h @@ -0,0 +1,165 @@ +/****************************************************************************** + * + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#ifndef _HTMLDOCVISITOR_H +#define _HTMLDOCVISITOR_H + +#include "docvisitor.h" +#include +#include + +class DocNode; +class FTextStream; +class CodeOutputInterface; + +/*! @brief Concrete visitor implementation for HTML output. */ +class HtmlDocVisitor : public DocVisitor +{ + public: + HtmlDocVisitor(FTextStream &t,CodeOutputInterface &ci,const char *langExt); + + //-------------------------------------- + // visitor functions for leaf nodes + //-------------------------------------- + + void visit(DocWord *); + void visit(DocLinkedWord *); + void visit(DocWhiteSpace *); + void visit(DocSymbol *); + void visit(DocURL *); + void visit(DocLineBreak *); + void visit(DocHorRuler *); + void visit(DocStyleChange *); + void visit(DocVerbatim *); + void visit(DocAnchor *); + void visit(DocInclude *); + void visit(DocIncOperator *); + void visit(DocFormula *); + void visit(DocIndexEntry *); + void visit(DocSimpleSectSep *); + void visit(DocCite *); + + //-------------------------------------- + // visitor functions for compound nodes + //-------------------------------------- + + void visitPre(DocAutoList *); + void visitPost(DocAutoList *); + void visitPre(DocAutoListItem *); + void visitPost(DocAutoListItem *); + void visitPre(DocPara *) ; + void visitPost(DocPara *); + void visitPre(DocRoot *); + void visitPost(DocRoot *); + void visitPre(DocSimpleSect *); + void visitPost(DocSimpleSect *); + void visitPre(DocTitle *); + void visitPost(DocTitle *); + void visitPre(DocSimpleList *); + void visitPost(DocSimpleList *); + void visitPre(DocSimpleListItem *); + void visitPost(DocSimpleListItem *); + void visitPre(DocSection *); + void visitPost(DocSection *); + void visitPre(DocHtmlList *); + void visitPost(DocHtmlList *) ; + void visitPre(DocHtmlListItem *); + void visitPost(DocHtmlListItem *); + void visitPre(DocHtmlDescList *); + void visitPost(DocHtmlDescList *); + void visitPre(DocHtmlDescTitle *); + void visitPost(DocHtmlDescTitle *); + void visitPre(DocHtmlDescData *); + void visitPost(DocHtmlDescData *); + void visitPre(DocHtmlTable *); + void visitPost(DocHtmlTable *); + void visitPre(DocHtmlRow *); + void visitPost(DocHtmlRow *) ; + void visitPre(DocHtmlCell *); + void visitPost(DocHtmlCell *); + void visitPre(DocHtmlCaption *); + void visitPost(DocHtmlCaption *); + void visitPre(DocInternal *); + void visitPost(DocInternal *); + void visitPre(DocHRef *); + void visitPost(DocHRef *); + void visitPre(DocHtmlHeader *); + void visitPost(DocHtmlHeader *); + void visitPre(DocImage *); + void visitPost(DocImage *); + void visitPre(DocDotFile *); + void visitPost(DocDotFile *); + void visitPre(DocMscFile *); + void visitPost(DocMscFile *); + void visitPre(DocLink *); + void visitPost(DocLink *); + void visitPre(DocRef *); + void visitPost(DocRef *); + void visitPre(DocSecRefItem *); + void visitPost(DocSecRefItem *); + void visitPre(DocSecRefList *); + void visitPost(DocSecRefList *); + void visitPre(DocParamSect *); + void visitPost(DocParamSect *); + void visitPre(DocParamList *); + void visitPost(DocParamList *); + void visitPre(DocXRefItem *); + void visitPost(DocXRefItem *); + void visitPre(DocInternalRef *); + void visitPost(DocInternalRef *); + void visitPre(DocCopy *); + void visitPost(DocCopy *); + void visitPre(DocText *); + void visitPost(DocText *); + void visitPre(DocHtmlBlockQuote *); + void visitPost(DocHtmlBlockQuote *); + + private: + + //-------------------------------------- + // helper functions + //-------------------------------------- + + void filter(const char *str); + void filterQuotedCdataAttr(const char* str); + void startLink(const QCString &ref,const QCString &file, + const QCString &relPath,const QCString &anchor, + const QCString &tooltip = ""); + void endLink(); + void writeDotFile(const QCString &fileName,const QCString &relPath,const QCString &context); + void writeMscFile(const QCString &fileName,const QCString &relPath,const QCString &context); + + void pushEnabled(); + void popEnabled(); + + void forceEndParagraph(DocNode *n); + void forceStartParagraph(DocNode *n); + + //-------------------------------------- + // state variables + //-------------------------------------- + + FTextStream &m_t; + CodeOutputInterface &m_ci; + bool m_insidePre; + bool m_hide; + QStack m_enabled; + QCString m_langExt; +}; + +#endif diff --git a/trunk/src/htmlgen.cpp b/trunk/src/htmlgen.cpp new file mode 100644 index 0000000..eac4a20 --- /dev/null +++ b/trunk/src/htmlgen.cpp @@ -0,0 +1,3021 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#include + +#include "qtbc.h" +#include +#include +#include "message.h" +#include "htmlgen.h" +#include "config.h" +#include "util.h" +#include "doxygen.h" +#include "logos.h" +#include "diagram.h" +#include "version.h" +#include "dot.h" +#include "language.h" +#include "htmlhelp.h" +#include "docparser.h" +#include "htmldocvisitor.h" +#include "searchindex.h" +#include "pagedef.h" +#include "debug.h" +#include "dirdef.h" +#include "vhdldocgen.h" +#include "layout.h" +#include "image.h" + + +//#define DBG_HTML(x) x; +#define DBG_HTML(x) + +static const char defaultHtmlHeader[] = +#include "header_html.h" +; + +static const char defaultHtmlFooter[] = +#include "footer_html.h" +; + +static const char defaultStyleSheet[] = +#include "doxygen_css.h" +; + +static const char search_functions_script[]= +#include "search_functions_php.h" +; + +static const char search_opensearch_script[]= +#include "search_opensearch_php.h" +; + +static const char search_styleSheet[] = +#include "search_css.h" +; + +static const char search_jquery_script1[]= +#include "jquery_js.h" +; + +static const char search_jquery_script2[]= +#include "sizzle_js.h" +; + +static const char search_jquery_script3[]= +#include "jquery_ui_js.h" +; + +static const char search_jquery_script4[]= +#include "jquery_fx_js.h" +; + +static const char svgpan_script[]= +#include "svgpan_js.h" +; + + +static QCString g_header; +static QCString g_footer; + +//------------------------- Pictures for the Tabs ------------------------ + +// active +static unsigned char tab_a_png[36] = +{ + 31, 42, 59, 69, 73, 74, 75, 77, 77, + 77, 79, 80, 80, 82, 81, 83, 84, 86, + 87, 88, 89, 90, 91, 91, 93, 94, 94, + 96, 96, 97, 98, 98, 99, 99, 99, 100 +}; + +// normal background +static unsigned char tab_b_png[36] = +{ + 240, 239, 238, 237, 235, 234, 234, 232, 231, + 229, 228, 227, 224, 224, 221, 219, 218, 217, + 214, 212, 210, 209, 206, 203, 202, 200, 198, + 196, 195, 193, 192, 190, 189, 188, 188, 188 +}; + +// shadowed header +static unsigned char header_png[12] = +{ + 255, 240, 241, 242, 243, 244, + 245, 246, 247, 248, 249, 250 +}; + +// function header +static unsigned char func_header_png[56] = +{ + 248, 247, 246, 245, 244, 243, 242, 241, + 240, 239, 238, 237, 236, 235, 234, 233, + 232, 231, 230, 229, 228, 223, 223, 223, + 223, 223, 223, 223, 223, 223, 223, 223, + 224, 224, 224, 224, 225, 225, 225, 225, + 225, 226, 226, 226, 227, 227, 227, 227, + 228, 228, 228, 229, 229, 229, 229, 229 +}; + +// hovering +static unsigned char tab_h_png[36] = +{ + 199, 198, 196, 196, 195, 194, 193, 192, 189, + 188, 187, 184, 184, 181, 180, 178, 176, 173, + 171, 169, 166, 164, 163, 161, 159, 156, 155, + 153, 152, 149, 148, 147, 145, 145, 150, 161 +}; + +// separator +static unsigned char tab_s_png[36] = +{ + 187, 186, 185, 183, 182, 181, 180, 178, 176, + 174, 173, 171, 169, 167, 164, 163, 161, 158, + 156, 154, 152, 150, 148, 145, 143, 141, 140, + 138, 136, 134, 131, 131, 128, 126, 125, 124 +}; + + +static unsigned char bc_s_png[240] = +{ + 150,187,187,148,148,148,148,148, + 147,175,186,147,147,147,147,147, + 146,153,185,185,146,146,146,146, + 144,144,177,183,144,144,144,144, + 144,144,159,182,144,144,144,144, + 143,143,144,179,181,143,143,143, + 142,142,142,165,180,142,142,142, + 141,141,141,144,178,178,141,141, + 139,139,139,139,167,176,139,139, + 137,137,137,137,146,174,137,137, + 137,137,137,137,137,169,173,137, + 135,135,135,135,135,150,171,135, + 133,133,133,133,133,135,167,169, + 132,132,132,132,132,132,154,167, + 129,129,129,129,129,129,140,164, + 129,129,129,129,129,129,154,163, + 127,127,127,127,127,128,161,161, + 125,125,125,125,125,141,158,125, + 123,123,123,123,123,152,156,123, + 121,121,121,121,129,154,121,121, + 120,120,120,120,143,152,120,120, + 118,118,118,120,150,150,118,118, + 117,117,117,132,148,117,117,117, + 114,114,114,142,145,114,114,114, + 113,113,120,143,113,113,113,113, + 111,111,133,141,111,111,111,111, + 110,112,140,140,110,110,110,110, + 109,124,138,109,109,109,109,109, + 107,133,136,107,107,107,107,107, + 111,134,106,106,106,106,106,106 +}; + +static unsigned char bc_s_a_png[240] = +{ + 241,241, 21, 0, 0, 0, 0, 0, + 162,205,117, 0, 0, 0, 0, 0, + 54,231,225, 3, 0, 0, 0, 0, + 0,198,215, 78, 0, 0, 0, 0, + 0, 93,211,186, 0, 0, 0, 0, + 0, 6,232,235, 42, 0, 0, 0, + 0, 0,132,203,147, 0, 0, 0, + 0, 0, 27,242,241, 15, 0, 0, + 0, 0, 0,168,205,108, 0, 0, + 0, 0, 0, 63,228,219, 0, 0, + 0, 0, 0, 0,207,221, 72, 0, + 0, 0, 0, 0,102,208,177, 0, + 0, 0, 0, 0, 9,238,240, 36, + 0, 0, 0, 0, 0,138,201,138, + 0, 0, 0, 0, 0, 77,187,158, + 0, 0, 0, 0, 0,159,204,120, + 0, 0, 0, 0, 15,241,241, 21, + 0, 0, 0, 0,111,208,171, 0, + 0, 0, 0, 0,210,222, 66, 0, + 0, 0, 0, 60,227,219, 0, 0, + 0, 0, 0,162,204,114, 0, 0, + 0, 0, 18,238,238, 21, 0, 0, + 0, 0,114,205,165, 0, 0, 0, + 0, 0,216,225, 60, 0, 0, 0, + 0, 66,226,216, 0, 0, 0, 0, + 0,165,204,111, 0, 0, 0, 0, + 21,241,241, 18, 0, 0, 0, 0, + 117,203,159, 0, 0, 0, 0, 0, + 219,227, 57, 0, 0, 0, 0, 0, + 211,201, 0, 0, 0, 0, 0, 0 +}; + +static unsigned char doxygen_png[3224] = +{ + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,255,255,255,255,255,255,255,255, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 91, 91, 91, 91, 32, 32,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,255,255,255,255, 32, 32,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,253,253,253,253, 32, 32,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,255,255,255,255,255,255,255,255, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,251,251,251,251, 32, 32,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,255,255,255,255,255,255,255,255, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,249,249,249,249, 32, 32,249,249,249,249, 32, 32, 32, 32, 32, 32,249,249,249,249, 32, 32, 32, 32, 32, 32,249,249,249,249, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,249,249,249, 32, 32, 32, 32, 32,249,249,249,249, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,249,249,249,249,249,249, 32, 32, 32, 32, 32, 32, 32,249,249,249,249,249, 32, 32, 32, 32, 32,249, 32, 32, 32, 32, 32,255,255,255, + 32, 32, 32, 32, 46,132,190,190,147, 61,247,247,247,247, 32, 32,247,247, 32, 32,118,161,190,190,161,118, 32, 32,247, 32, 46, 89, 89, 89, 89, 46, 32,247,247, 32, 89, 89, 89, 89, 61, 89, 89, 89, 89, 46, 32,247, 32, 46, 89, 89, 89, 89, 32,247, 32, 32,118,175,190,161, 89, 61, 89, 89, 89, 61, 32,247,247,247, 32, 32,104,147,190,190,190,132, 89, 32, 32,247,247, 32, 46, 89, 89, 89, 75, 32, 89,161,190,161, 75, 32,255,255, + 32, 32, 32, 74,230,244,244,244,244,244,244,244,244,244, 32, 32,244, 32, 74,216,244,244,244,244,244,244,216, 74, 32,244, 32,187,244,244,244,159, 32,244, 32,117,244,244,244,230, 46,173,244,244,244,131, 32,244, 32,131,244,244,244,173, 32, 32, 46,173,244,244,244,244,244,230,244,244,244,131, 32,244,244, 32, 74,202,244,244,244,244,244,244,244,173, 46, 32,244, 32, 89,244,244,244,187,145,244,244,244,244,244, 89, 32,255, + 32, 32, 46,213,241,241,241,241,241,241,241,241,241,241, 32, 32, 32, 60,227,241,241,241,241,241,241,241,241,227, 60, 32, 32, 46,227,241,241,241,102, 32, 60,227,241,241,241, 88, 32,116,241,241,241,199, 32,241, 32,185,241,241,241,116, 32, 32,143,241,241,241,241,241,241,241,241,241,241,130, 32,241, 32, 74,227,241,241,241,199,185,241,241,241,241,171, 32,241, 32, 88,241,241,241,241,241,241,241,241,241,241,199, 32,255, + 32, 32,128,237,237,237,223,128, 87,128,237,237,237,237, 32, 32, 32,182,237,237,237,196,100,100,196,237,237,237,182, 32,237, 32,100,237,237,237,223, 59,196,237,237,237,141, 32, 32, 46,237,237,237,237, 59, 32, 46,237,237,237,237, 46, 32, 59,237,237,237,237,169, 87, 87,182,237,237,237,128, 32,237, 32,196,237,237,237, 87, 32, 32, 73,223,237,237,237, 73, 32, 32, 87,237,237,237,237,223,182,223,237,237,237,237, 46, 32, + 32, 32,207,234,234,234,113, 32, 32, 32,234,234,234,234, 32, 32, 59,234,234,234,221, 45, 32, 32, 45,221,234,234,234, 59, 32,234, 32,140,234,234,234,221,234,234,234,194, 32, 32,234, 32,167,234,234,234,126, 32, 99,234,234,234,167, 32, 32,126,234,234,234,180, 32, 32, 32,126,234,234,234,126, 32, 32, 99,234,234,234,167, 32, 32, 32, 32,153,234,234,234,126, 32, 32, 86,234,234,234,207, 45, 32, 45,234,234,234,234, 86, 32, + 32, 45,231,231,231,218, 32, 32, 32, 32,231,231,231,231, 32, 32, 98,231,231,231,165, 32,231,231, 32,165,231,231,231, 98, 32,231, 32, 45,191,231,231,231,231,231,218, 72, 32,231,231, 32, 98,231,231,231,165, 32,151,231,231,231,112, 32, 32,165,231,231,231,112, 32,231, 32,125,231,231,231,125, 32, 32,138,231,231,231,178,125,125,125,125,178,231,231,231,178, 32, 32, 85,231,231,231,178, 32,255, 32,191,231,231,231, 85, 32, + 32, 84,227,227,227,175, 32, 32, 32, 32,227,227,227,227, 32, 32,123,227,227,227,123, 32,227,227, 32,123,227,227,227,123, 32,227,227, 32, 71,227,227,227,227,227,123, 32,227,227,227,227, 32,214,227,227,227, 45,201,227,227,227, 45, 32, 32,175,227,227,227, 84, 32,227, 32,123,227,227,227,123, 32, 32,175,227,227,227,227,227,227,227,227,227,227,227,227,175, 32, 32, 84,227,227,227,175, 32,255, 32,175,227,227,227, 84, 32, + 32, 83,223,223,223,172, 32, 32, 32, 32,223,223,223,223, 32, 32,121,223,223,223,121, 32,223,223, 32,121,223,223,223,121, 32,223,223,223, 32,172,223,223,223,210, 45, 32,223,223,223,223, 32,147,223,223,223,134,223,223,223,147, 32,223, 32,172,223,223,223, 83, 32,223, 32,121,223,223,223,121, 32, 32,172,223,223,223,223,223,223,223,223,223,223,223,223,172, 32, 32, 83,223,223,223,172, 32,255, 32,172,223,223,223, 83, 32, + 32, 82,220,220,220,170, 32, 32, 32, 32,220,220,220,220, 32, 32,120,220,220,220,120, 32,220,220, 32,120,220,220,220,120, 32,220,220, 32, 95,220,220,220,220,220,132, 32,220,220,220,220, 32, 95,220,220,220,207,220,220,220, 95, 32,220, 32,170,220,220,220,107, 32,220, 32,120,220,220,220,120, 32, 32,170,220,220,220,132, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 82,220,220,220,170, 32,255, 32,170,220,220,220, 82, 32, + 32, 57,216,216,216,216, 32, 32, 32, 32,216,216,216,216, 32, 32, 81,216,216,216,167, 32,216,216, 32,155,216,216,216, 81, 32,216, 32, 57,204,216,216,216,216,216,216, 93, 32,216,216,216,216, 32,204,216,216,216,216,216,204, 32,216,216, 32,118,216,216,216,167, 32, 32, 32,130,216,216,216,118, 32, 32,118,216,216,216,191, 32, 32,216,216,216, 32, 32, 44, 57, 32, 32, 81,216,216,216,167, 32,255, 32,167,216,216,216, 81, 32, + 32, 32,189,213,213,213,116, 32, 32, 80,213,213,213,213, 32, 32, 44,201,213,213,213, 68, 32, 32, 68,213,213,213,213, 44, 32, 32, 32,165,213,213,213,165,213,213,213,201, 44, 32,213,213,213, 32,129,213,213,213,213,213,141, 32,213,213, 32, 80,213,213,213,213,165,116,153,213,213,213,213,116, 32, 32, 56,213,213,213,213,153, 56, 32, 32, 32, 44,104,189,116, 32, 32, 80,213,213,213,165, 32,255, 32,165,213,213,213, 80, 32, + 32, 32,139,210,210,210,210,174,174,210,210,210,210,210, 32, 32, 32,127,210,210,210,198,127,127,198,210,210,210,127, 32,210, 32,115,210,210,210,174, 44,139,210,210,210,163, 32, 32,210,210, 32, 68,210,210,210,210,210, 91, 32,210,210,210, 32,174,210,210,210,210,210,210,210,210,210,210,115, 32,210, 32,127,210,210,210,210,210,174,163,163,210,210,210,115, 32, 32, 79,210,210,210,163, 32,255, 32,163,210,210,210, 79, 32, + 32, 32, 55,194,206,206,206,206,206,194,206,206,206,206, 32, 32, 32, 44,171,206,206,206,206,206,206,206,206,171, 44, 32, 32, 67,206,206,206,206, 67, 32, 44,183,206,206,206,113, 32,206,206,206, 32,183,206,206,206,194, 32,206,206,206,206, 32, 67,194,206,206,206,206,206,171,206,206,206,113, 32,206, 32, 32,136,206,206,206,206,206,206,206,206,206,206,113, 32, 32, 78,206,206,206,160, 32,255, 32,160,206,206,206, 78, 32, + 32, 32, 32,100,192,203,203,203,157, 55,203,203,203,203, 32, 32,203, 32, 43,135,203,203,203,203,203,203,135, 43, 32, 32, 43,180,203,203,203,112, 32,203, 32, 66,203,203,203,203, 66, 32,203,203, 32,157,203,203,203,135, 32,203,203,203,203,203, 32, 43,112,157,157,123, 55,112,203,203,203,112, 32,203,203, 32, 32, 78,146,203,203,203,203,203,203,169,123, 55, 32, 32, 78,203,203,203,157, 32,255, 32,157,203,203,203, 78, 32, + 32, 32, 32, 32, 54,110,110, 88, 32, 32, 32, 32, 32, 32, 32, 32,200,200, 32, 32, 54, 99,110,110, 99, 54, 32, 32,200,200, 32, 32, 32, 32, 32, 32, 32,200,200, 32, 32, 32, 32, 32, 32,200,200, 32, 54,200,200,200,200, 77, 32,200,200,200,200,200, 32, 32, 32, 32, 32, 32, 32,166,200,200,200, 88, 32,200,200,200,200, 32, 32, 32, 66, 77, 77, 77, 32, 32, 32, 32,200,200, 32, 32, 32, 32, 32, 32,255, 32, 32, 32, 32, 32, 32,255, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,198,198,198,198, 32, 32, 32, 32, 32, 32,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198, 32,109,198,198,198,176, 32,198,198,198,198,198, 32, 98,121, 76, 32, 32, 54,109,198,198,198,198, 43, 32,198,198,198,198,198,198,198, 32, 32, 32, 32,198,198,198,198,198,198,198,198,198,198,198,198,255,255,255,255,255,255,255,255, + 32, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 33,159,191,191,191,117, 36, 41, 41, 41, 41, 41, 34,108,191,191,191,191,191,191,191,191,191,117, 36, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,255, + 32, 41, 97,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, 78, 38, 64,190,192,192,192, 66, 66, 41, 41, 85,128, 65, 34,107,190,192,192,192,192,192,192,192,139, 48, 39, 41, 41,105,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, 97, 41,255, + 32, 41, 97,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, 96, 36, 95,147,148,148,139, 55, 41, 41, 85,121,128, 91, 38, 75,137,158,190,190,190,170,139, 97, 49, 37, 41, 41,105,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, 97, 41,255, + 32, 41, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 41, 36, 45, 45, 45, 48, 38, 41, 41, 76, 76, 76, 76, 76, 37, 34, 42, 33, 33, 33, 39, 48, 59, 41, 41, 41, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 41,255, + 32, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,255, + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255 +}; + +static unsigned char doxygen_a_png[3224] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 66, 66, 66, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0,145,247,247,247,247,145, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0,247,247,247,247,247,247, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0,247,247,247,247,247,247, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0,247,247,247,247,247,247, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 16,115,181,181,132,247,247,247,247,247,247, 0, 0, 0, 0, 0, 99,148,181,181,148, 99, 0, 0, 0, 0, 16, 66, 66, 66, 66, 16, 0, 0, 0, 0, 66, 66, 66, 66, 33, 66, 66, 66, 66, 16, 0, 0, 0, 16, 66, 66, 66, 66, 0, 0, 0, 0, 99,165,181,148, 66, 33, 66, 66, 66, 33, 0, 0, 0, 0, 0, 0, 82,132,181,181,181,115, 66, 0, 0, 0, 0, 0, 16, 66, 66, 66, 49, 0, 66,148,181,148, 49, 0, 0, 0, + 0, 0, 0,129,247,247,247,247,247,247,247,247,247,247,247, 0, 0, 0,112,214,247,247,247,247,247,247,214,112, 0, 16,247,247,247,247,247,247, 46, 0, 0,145,247,247,247,247,247,247,247,247,247,247, 16, 0, 16,247,247,247,247,247, 66, 0, 63,165,247,247,247,247,247,247,247,247,247,247, 33, 0, 0, 0, 96,198,247,247,247,247,247,247,247,165, 63, 0, 0, 16,247,247,247,247,247,145,247,247,247,247,247,145, 0, 0, + 0, 0,112,247,247,247,247,247,247,247,247,247,247,247,247, 0, 0,129,247,247,247,247,247,247,247,247,247,247,129, 0,181,247,247,247,247,247,148, 0,129,247,247,247,247,247,247,247,247,247,247,247,115, 0,115,247,247,247,247,247,165, 30,247,247,247,247,247,247,247,247,247,247,247,247,115, 0, 0,129,247,247,247,247,247,247,247,247,247,247,247, 63, 0, 66,247,247,247,247,247,247,247,247,247,247,247,247, 96, 0, + 0, 16,247,247,247,247,247,247,247,247,247,247,247,247,247, 0, 79,247,247,247,247,247,247,247,247,247,247,247,247, 79, 79,247,247,247,247,247,247,129,247,247,247,247,247,247,129,247,247,247,247,247,198, 0,181,247,247,247,247,247, 99,145,247,247,247,247,247,247,247,247,247,247,247,247,115, 0, 96,247,247,247,247,247,247,247,247,247,247,247,247,165, 0, 66,247,247,247,247,247,247,247,247,247,247,247,247,198, 0, + 0,115,247,247,247,247,247,247,247,247,247,247,247,247,247, 0,181,247,247,247,247,247,247,247,247,247,247,247,247,181, 0,129,247,247,247,247,247,247,247,247,247,247,247,145, 16,247,247,247,247,247,247, 33,247,247,247,247,247,247, 33,247,247,247,247,247,247,247,247,247,247,247,247,247,115, 0,198,247,247,247,247,247,198,181,247,247,247,247,247,247, 49, 66,247,247,247,247,247,247,247,247,247,247,247,247,247, 16, + 0,214,247,247,247,247,247,129, 66,247,247,247,247,247,247, 33,247,247,247,247,247,247, 96, 96,247,247,247,247,247,247, 33, 0,145,247,247,247,247,247,247,247,247,247,198, 30, 0,165,247,247,247,247,247,115,247,247,247,247,247,165,115,247,247,247,247,247,181, 66,115,247,247,247,247,247,115, 82,247,247,247,247,247,165,115,115,148,247,247,247,247,247,115, 66,247,247,247,247,247,247,181,247,247,247,247,247,247, 66, + 16,247,247,247,247,247,231, 0, 0,247,247,247,247,247,247, 82,247,247,247,247,247,165, 0, 0,165,247,247,247,247,247, 82, 0, 30,247,247,247,247,247,247,247,247,247, 96, 0, 0, 82,247,247,247,247,247,165,247,247,247,247,247, 99,165,247,247,247,247,247, 99, 0,115,247,247,247,247,247,115,132,247,247,247,247,247,247,247,247,247,247,247,247,247,247,181, 66,247,247,247,247,247,181, 0,198,247,247,247,247,247, 66, + 66,247,247,247,247,247,181, 0, 0,247,247,247,247,247,247,115,247,247,247,247,247,115, 0, 0,115,247,247,247,247,247,115, 0, 0, 96,247,247,247,247,247,247,247,129, 0, 0, 0, 0,231,247,247,247,247,247,247,247,247,247,247, 16,181,247,247,247,247,247, 66, 0,115,247,247,247,247,247,115,181,247,247,247,247,247,247,247,247,247,247,247,247,247,247,181, 66,247,247,247,247,247,181, 0,181,247,247,247,247,247, 66, + 66,247,247,247,247,247,181, 0, 0,247,247,247,247,247,247,115,247,247,247,247,247,115, 0, 0,115,247,247,247,247,247,115, 0, 0, 0,181,247,247,247,247,247,247, 30, 0, 0, 0, 0,148,247,247,247,247,247,247,247,247,247,148, 0,181,247,247,247,247,247, 66, 0,115,247,247,247,247,247,115,181,247,247,247,247,247,247,247,247,247,247,247,247,247,247,181, 66,247,247,247,247,247,181, 0,181,247,247,247,247,247, 66, + 66,247,247,247,247,247,181, 0, 0,247,247,247,247,247,247,115,247,247,247,247,247,115, 0, 0,115,247,247,247,247,247,115, 0, 0,129,247,247,247,247,247,247,247,145, 0, 0, 0, 0, 82,247,247,247,247,247,247,247,247,247, 82, 0,181,247,247,247,247,247, 99, 0,115,247,247,247,247,247,115,181,247,247,247,247,247,247,247,247,247,247,247,247,247,181, 79, 66,247,247,247,247,247,181, 0,181,247,247,247,247,247, 66, + 33,247,247,247,247,247,247, 14, 0,247,247,247,247,247,247, 66,247,247,247,247,247,181, 0, 0,165,247,247,247,247,247, 66, 0, 79,247,247,247,247,247,247,247,247,247,129, 0, 0, 0, 0,231,247,247,247,247,247,247,247,231, 0, 0,115,247,247,247,247,247,181,115,165,247,247,247,247,247,115,115,247,247,247,247,247,214, 63, 0, 0, 0, 16,112,247,247, 33, 66,247,247,247,247,247,181, 0,181,247,247,247,247,247, 66, + 0,214,247,247,247,247,247,198,198,247,247,247,247,247,247, 16,247,247,247,247,247,247,132,132,247,247,247,247,247,247, 16, 14,181,247,247,247,247,247,247,247,247,247,247, 79, 0, 0, 0,132,247,247,247,247,247,247,247,148, 0, 0, 66,247,247,247,247,247,247,247,247,247,247,247,247,247,115, 33,247,247,247,247,247,247,247,198,181,181,247,247,247,247,115, 66,247,247,247,247,247,181, 0,181,247,247,247,247,247, 66, + 0,148,247,247,247,247,247,247,247,247,247,247,247,247,247, 0,132,247,247,247,247,247,247,247,247,247,247,247,247,145, 0,145,247,247,247,247,247,247,247,247,247,247,247,181, 14, 0, 0, 49,247,247,247,247,247,247,247, 82, 0, 0, 0,198,247,247,247,247,247,247,247,247,247,247,247,247,115, 0,145,247,247,247,247,247,247,247,247,247,247,247,247,247,115, 66,247,247,247,247,247,181, 0,181,247,247,247,247,247, 66, + 0, 46,247,247,247,247,247,247,247,247,247,247,247,247,247, 0, 30,247,247,247,247,247,247,247,247,247,247,247,247, 30,112,247,247,247,247,247,247, 96,247,247,247,247,247,247,145, 0, 0, 0,214,247,247,247,247,247,231, 0, 0, 0, 0, 96,247,247,247,247,247,247,247,247,247,247,247,247,115, 0, 30,148,247,247,247,247,247,247,247,247,247,247,247,247,115, 66,247,247,247,247,247,181, 0,181,247,247,247,247,247, 66, + 0, 0,129,247,247,247,247,247,247,247,247,247,247,247,247, 0, 0, 96,247,247,247,247,247,247,247,247,247,247, 96, 16,247,247,247,247,247,247,145, 0,112,247,247,247,247,247,247, 49, 0, 0,181,247,247,247,247,247,148, 0, 0, 0, 0, 0,129,247,247,247,247,247,247,247,247,247,247,247,115, 0, 0, 46,148,247,247,247,247,247,247,247,247,247,247,247, 33, 66,247,247,247,247,247,181, 0,181,247,247,247,247,247, 66, + 0, 0, 0,129,247,247,247,247,181,145,247,247,247,247,145, 0, 0, 0, 46,148,247,247,247,247,247,247,148, 46, 0, 0,112,214,247,247,247,145, 14, 0, 0,145,247,247,247,247,145, 0, 0, 33,247,247,247,247,247,247, 66, 0, 0, 0, 0, 0, 99,132,115,181,181,132,198,247,247,247,247,247, 82, 0, 0, 0, 0, 66,165,247,247,247,247,247,247,198,132, 33, 0, 0,145,247,247,247,181, 79, 0, 79,181,247,247,247,145, 0, + 0, 0, 0, 0, 33,115,115, 82, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 33, 99,115,115, 99, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,115,247,247,247,247,247,214, 0, 0, 0, 0, 0, 99,247,247,247,247,247,247,247,247,247,247,247,247, 16, 0, 0, 0, 0, 0, 0, 0, 49, 66, 66, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0,165,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,108,224,255,255,255,255,255,255,101,164,255,255,255,143,250,255,255,255,255,255,255,255,255,255,255,255, 98,170,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,165, 0, + 0,165,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,136,251,255,255,255,255,255,255,101,130,255,255,255,153,250,255,255,255,255,255,255,255,255,255,255,121, 98,189,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,165, 0, + 0,165,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,198,252,255,255,255,255,255,164,164,255,255,255,255,176,249,251,255,255,255,255,255,255,255,255,150, 86,192,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,165, 0, + 0,165,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,164,198,255,255,255,255,201,133,164,255,255,255,255,255,145,203,255,255,255,255,255,255,255,117, 79,194,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,165, 0, + 0, 66,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, 73, 73,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, 47, 70,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, 66, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +unsigned char mag_sel_png[] = { + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, + 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x13, + 0x08, 0x06, 0x00, 0x00, 0x00, 0x90, 0x8c, 0x2d, 0xb5, 0x00, 0x00, 0x00, + 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0b, 0x13, 0x00, 0x00, 0x0b, + 0x13, 0x01, 0x00, 0x9a, 0x9c, 0x18, 0x00, 0x00, 0x00, 0x20, 0x63, 0x48, + 0x52, 0x4d, 0x00, 0x00, 0x6d, 0x98, 0x00, 0x00, 0x73, 0x8e, 0x00, 0x00, + 0xe0, 0x38, 0x00, 0x00, 0x82, 0xd5, 0x00, 0x00, 0x7a, 0x07, 0x00, 0x00, + 0xca, 0xb4, 0x00, 0x00, 0x33, 0x44, 0x00, 0x00, 0x1c, 0x76, 0x84, 0x36, + 0x2a, 0xbd, 0x00, 0x00, 0x01, 0xb9, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, + 0xe4, 0x94, 0xbb, 0x8a, 0x22, 0x41, 0x14, 0x86, 0xbf, 0xda, 0x16, 0x3a, + 0x10, 0xba, 0x03, 0x2f, 0x78, 0x03, 0x51, 0x11, 0x4c, 0xd4, 0x40, 0xd4, + 0x37, 0x30, 0x31, 0x30, 0xe9, 0x07, 0xf0, 0x15, 0x14, 0x7c, 0x1e, 0x31, + 0x37, 0x33, 0x11, 0x73, 0xe9, 0x56, 0x44, 0x84, 0x36, 0xe9, 0x40, 0x50, + 0x54, 0x14, 0xc4, 0xc0, 0xa8, 0x6d, 0x50, 0x6a, 0x92, 0x1d, 0xd9, 0x9d, + 0x99, 0x75, 0x0d, 0x26, 0x58, 0xd8, 0x3f, 0xaa, 0xe2, 0xfc, 0xf5, 0xd5, + 0x39, 0x9c, 0x53, 0x25, 0xa4, 0x94, 0x7c, 0xa7, 0x7e, 0xf0, 0xcd, 0xfa, + 0xf7, 0x81, 0xbe, 0xf7, 0xc5, 0xf9, 0x7c, 0x96, 0x93, 0xc9, 0x84, 0xe5, + 0x72, 0xc9, 0x66, 0xb3, 0x21, 0x99, 0x4c, 0x92, 0xcf, 0xe7, 0xa9, 0x54, + 0x2a, 0x04, 0x02, 0x01, 0xf1, 0x2a, 0x50, 0x48, 0x29, 0x39, 0x9d, 0x4e, + 0x72, 0x30, 0x18, 0x60, 0x59, 0xd6, 0x27, 0x43, 0xb5, 0x5a, 0xa5, 0xd1, + 0x68, 0x10, 0x0c, 0x06, 0xc5, 0xcb, 0x19, 0x4e, 0xa7, 0x53, 0x2c, 0xcb, + 0x22, 0x95, 0x4a, 0x51, 0x2a, 0x95, 0xc8, 0x64, 0x32, 0xac, 0x56, 0x2b, + 0x66, 0xb3, 0x19, 0x93, 0xc9, 0x84, 0x48, 0x24, 0x42, 0xbd, 0x5e, 0x7f, + 0xbd, 0x64, 0xdb, 0xb6, 0x01, 0x28, 0x97, 0xcb, 0x54, 0x2a, 0x15, 0x34, + 0x4d, 0x13, 0xa1, 0x50, 0x48, 0x2a, 0x8a, 0xc2, 0x7a, 0xbd, 0xc6, 0xb6, + 0x6d, 0xea, 0xf5, 0x3a, 0xa3, 0xd1, 0x48, 0xf6, 0xfb, 0xfd, 0xc7, 0x61, + 0xc3, 0x30, 0xa8, 0xd5, 0x6a, 0xe2, 0x53, 0x53, 0xb6, 0xdb, 0x2d, 0x00, + 0xc5, 0x62, 0x11, 0x4d, 0xd3, 0x04, 0x80, 0xa6, 0x69, 0xa2, 0x50, 0x28, + 0xf0, 0x6b, 0x1c, 0x10, 0x86, 0x61, 0x3c, 0x60, 0x80, 0xf8, 0xb2, 0xcb, + 0x89, 0x44, 0x02, 0x00, 0xc7, 0x71, 0x00, 0xde, 0x27, 0x5d, 0xfe, 0xdc, + 0x3f, 0xe2, 0x1f, 0xa0, 0xe2, 0x8f, 0x63, 0x93, 0xcb, 0xe5, 0x00, 0x18, + 0x8f, 0xc7, 0x98, 0xa6, 0x89, 0xeb, 0xba, 0xd2, 0x34, 0x4d, 0xc6, 0xe3, + 0x31, 0x00, 0xe9, 0x74, 0x1a, 0x80, 0x5a, 0xad, 0xf6, 0x80, 0x3e, 0xed, + 0xf2, 0x7a, 0xbd, 0x96, 0xc3, 0xe1, 0x90, 0xf9, 0x7c, 0xfe, 0xa5, 0x29, + 0x1c, 0x0e, 0xd3, 0xe9, 0x74, 0xd0, 0x75, 0x5d, 0x00, 0x8c, 0x46, 0xa3, + 0x8f, 0x17, 0xfc, 0x0e, 0xf4, 0x3c, 0x4f, 0xee, 0x76, 0x3b, 0x16, 0x8b, + 0x05, 0x8e, 0xe3, 0xb0, 0xdf, 0xef, 0x89, 0xc7, 0xe3, 0xa4, 0xd3, 0x69, + 0x6c, 0xdb, 0xe6, 0x74, 0x3a, 0x11, 0x8d, 0x46, 0x69, 0xb7, 0xdb, 0x0f, + 0xe8, 0xd3, 0x0c, 0x01, 0x3c, 0xcf, 0x93, 0xae, 0xeb, 0xe2, 0x79, 0x1e, + 0xb7, 0xdb, 0x0d, 0x9f, 0xcf, 0x87, 0xa2, 0x28, 0x5c, 0x2e, 0x17, 0x7a, + 0xbd, 0x1e, 0xc7, 0xe3, 0x91, 0x58, 0x2c, 0x46, 0xab, 0xd5, 0x7a, 0x0a, + 0x7d, 0xbc, 0x14, 0x55, 0x55, 0x85, 0xaa, 0xaa, 0x9f, 0x0c, 0x7e, 0xbf, + 0x5f, 0x36, 0x9b, 0x4d, 0xba, 0xdd, 0x2e, 0xd7, 0xeb, 0x95, 0xeb, 0xf5, + 0x8a, 0xae, 0xeb, 0x7f, 0xcf, 0xf0, 0x99, 0x5c, 0xd7, 0x95, 0x87, 0xc3, + 0x81, 0xfb, 0xfd, 0x4e, 0x36, 0x9b, 0x7d, 0xad, 0xe4, 0xff, 0xe7, 0xfb, + 0x7a, 0x1b, 0x00, 0x59, 0xa8, 0xba, 0x68, 0xca, 0x4f, 0xc5, 0xa7, 0x00, + 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 +}; +unsigned int mag_sel_png_len = 563; + +unsigned char mag_png[] = { + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, + 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x13, + 0x08, 0x06, 0x00, 0x00, 0x00, 0x90, 0x8c, 0x2d, 0xb5, 0x00, 0x00, 0x00, + 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0b, 0x13, 0x00, 0x00, 0x0b, + 0x13, 0x01, 0x00, 0x9a, 0x9c, 0x18, 0x00, 0x00, 0x00, 0x20, 0x63, 0x48, + 0x52, 0x4d, 0x00, 0x00, 0x6d, 0x98, 0x00, 0x00, 0x73, 0x8e, 0x00, 0x00, + 0xe0, 0x38, 0x00, 0x00, 0x82, 0xd5, 0x00, 0x00, 0x7a, 0x07, 0x00, 0x00, + 0xca, 0xb4, 0x00, 0x00, 0x33, 0x44, 0x00, 0x00, 0x1c, 0x76, 0x84, 0x36, + 0x2a, 0xbd, 0x00, 0x00, 0x01, 0x92, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, + 0xe4, 0x94, 0xbb, 0xaa, 0xea, 0x50, 0x10, 0x86, 0xbf, 0xec, 0x08, 0x29, + 0x36, 0x24, 0x85, 0x17, 0xbc, 0x81, 0x18, 0x11, 0x6c, 0xd4, 0x42, 0x8c, + 0x0f, 0x61, 0xe1, 0x2b, 0xf8, 0x0a, 0x0a, 0x3e, 0x8f, 0xf8, 0x0c, 0x36, + 0x62, 0x1f, 0x92, 0x88, 0x88, 0x10, 0x9b, 0x14, 0x42, 0x44, 0x45, 0x41, + 0x2c, 0xac, 0x92, 0x80, 0xb2, 0x4e, 0x73, 0x94, 0x03, 0xfb, 0xb0, 0x4d, + 0xb1, 0x8b, 0x03, 0xe7, 0xaf, 0xd6, 0x62, 0xfe, 0xf5, 0x31, 0xc3, 0xcc, + 0x1a, 0x49, 0x08, 0xc1, 0x4f, 0xea, 0x83, 0x1f, 0xd6, 0xbf, 0x0f, 0x4c, + 0x3c, 0x0f, 0xd7, 0xeb, 0x55, 0x38, 0x8e, 0xc3, 0x66, 0xb3, 0x61, 0xb7, + 0xdb, 0x51, 0x2a, 0x95, 0xa8, 0xd7, 0xeb, 0x18, 0x86, 0x41, 0x32, 0x99, + 0x94, 0xe2, 0x02, 0x25, 0x21, 0x04, 0x97, 0xcb, 0x45, 0x4c, 0xa7, 0x53, + 0x6c, 0xdb, 0xfe, 0x62, 0xe8, 0x74, 0x3a, 0xf4, 0x7a, 0x3d, 0x52, 0xa9, + 0x94, 0x14, 0x3b, 0xc3, 0xc5, 0x62, 0x81, 0x6d, 0xdb, 0x94, 0xcb, 0x65, + 0x5a, 0xad, 0x16, 0x95, 0x4a, 0x85, 0xed, 0x76, 0xcb, 0x72, 0xb9, 0xc4, + 0x71, 0x1c, 0xb2, 0xd9, 0x2c, 0xdd, 0x6e, 0x37, 0x7e, 0xc9, 0xae, 0xeb, + 0x02, 0xd0, 0x6e, 0xb7, 0x31, 0x0c, 0x03, 0x55, 0x55, 0xa5, 0x74, 0x3a, + 0x2d, 0x64, 0x59, 0xc6, 0xf7, 0x7d, 0x5c, 0xd7, 0x8d, 0x0d, 0xfc, 0x00, + 0xd8, 0xef, 0xf7, 0x00, 0x34, 0x9b, 0x4d, 0x54, 0x55, 0x95, 0x00, 0x54, + 0x55, 0x95, 0x1a, 0x8d, 0x06, 0x7f, 0xc6, 0x63, 0x03, 0x8b, 0xc5, 0x22, + 0x00, 0x9e, 0xe7, 0x01, 0x3c, 0x27, 0x5d, 0xfc, 0xbe, 0xbf, 0xe2, 0xb1, + 0x81, 0xb5, 0x5a, 0x0d, 0x00, 0xd3, 0x34, 0xb1, 0x2c, 0x8b, 0x20, 0x08, + 0x84, 0x65, 0x59, 0x98, 0xa6, 0x09, 0x80, 0xae, 0xeb, 0xaf, 0x07, 0xf3, + 0xf9, 0xfc, 0x7d, 0x97, 0x7d, 0xdf, 0x17, 0xb3, 0xd9, 0x8c, 0xd5, 0x6a, + 0xf5, 0x57, 0x53, 0x26, 0x93, 0x61, 0x34, 0x1a, 0xa1, 0x69, 0x9a, 0x14, + 0x6b, 0x6c, 0xa2, 0x28, 0x12, 0x87, 0xc3, 0x81, 0xf5, 0x7a, 0x8d, 0xe7, + 0x79, 0x1c, 0x8f, 0x47, 0x0a, 0x85, 0x02, 0xba, 0xae, 0xe3, 0xba, 0x2e, + 0x97, 0xcb, 0x85, 0x5c, 0x2e, 0xc7, 0x70, 0x38, 0x7c, 0x0b, 0x95, 0x9e, + 0xcb, 0x21, 0x8a, 0x22, 0x11, 0x04, 0x01, 0x51, 0x14, 0x71, 0xbf, 0xdf, + 0x49, 0x24, 0x12, 0xc8, 0xb2, 0xcc, 0xed, 0x76, 0x63, 0x32, 0x99, 0x70, + 0x3e, 0x9f, 0xc9, 0xe7, 0xf3, 0x0c, 0x06, 0x83, 0x6f, 0xa1, 0xaf, 0x9f, + 0xa2, 0x28, 0x8a, 0xa4, 0x28, 0xca, 0x17, 0xc3, 0xe7, 0xe7, 0xa7, 0xe8, + 0xf7, 0xfb, 0x8c, 0xc7, 0x63, 0xc2, 0x30, 0x24, 0x0c, 0x43, 0x34, 0x4d, + 0x7b, 0x9f, 0xe1, 0x77, 0x0a, 0x82, 0x40, 0x9c, 0x4e, 0x27, 0x1e, 0x8f, + 0x07, 0xd5, 0x6a, 0x35, 0x5e, 0xc9, 0xff, 0xcf, 0xfa, 0xfa, 0x35, 0x00, + 0x70, 0xf3, 0xae, 0xcb, 0x89, 0xcd, 0xd2, 0x46, 0x00, 0x00, 0x00, 0x00, + 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 +}; +unsigned int mag_png_len = 524; + +unsigned char search_l_png[] = { + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, + 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x13, + 0x08, 0x06, 0x00, 0x00, 0x00, 0x90, 0x8c, 0x2d, 0xb5, 0x00, 0x00, 0x00, + 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0b, 0x13, 0x00, 0x00, 0x0b, + 0x13, 0x01, 0x00, 0x9a, 0x9c, 0x18, 0x00, 0x00, 0x00, 0x20, 0x63, 0x48, + 0x52, 0x4d, 0x00, 0x00, 0x6d, 0x98, 0x00, 0x00, 0x73, 0x8e, 0x00, 0x00, + 0xe0, 0x38, 0x00, 0x00, 0x82, 0xd5, 0x00, 0x00, 0x7a, 0x07, 0x00, 0x00, + 0xca, 0xb4, 0x00, 0x00, 0x33, 0x44, 0x00, 0x00, 0x1c, 0x76, 0x84, 0x36, + 0x2a, 0xbd, 0x00, 0x00, 0x01, 0xe2, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, + 0xac, 0x54, 0x3d, 0xab, 0xda, 0x50, 0x18, 0x7e, 0xce, 0xc9, 0x39, 0x31, + 0x4d, 0xfc, 0x40, 0x30, 0x46, 0x14, 0xec, 0x50, 0x44, 0x17, 0x2f, 0x9d, + 0xba, 0x15, 0xda, 0xd1, 0xa1, 0x2e, 0xdd, 0x3b, 0x14, 0x4a, 0xa1, 0x7f, + 0xa6, 0x74, 0xbd, 0x43, 0xff, 0x84, 0xfd, 0x05, 0x82, 0xda, 0xa5, 0x83, + 0x1d, 0xdc, 0x8a, 0x88, 0xa0, 0x44, 0x83, 0xc6, 0x28, 0xad, 0x1f, 0x49, + 0xde, 0x2e, 0x8d, 0x78, 0x6f, 0xaf, 0x34, 0x68, 0x9f, 0xed, 0xbc, 0x70, + 0x1e, 0x9e, 0x8f, 0xf7, 0x1c, 0x46, 0x44, 0x38, 0x45, 0xaf, 0xd7, 0x63, + 0xb6, 0x6d, 0xe7, 0x6d, 0xdb, 0x6e, 0xba, 0xae, 0xfb, 0x6e, 0xb3, 0xd9, + 0xdc, 0x6c, 0xb7, 0xdb, 0x04, 0xe7, 0x1c, 0x8c, 0x31, 0xfc, 0x0b, 0x2c, + 0x22, 0xec, 0x76, 0xbb, 0xcc, 0xf3, 0xbc, 0xcc, 0x68, 0x34, 0x7a, 0xed, + 0xba, 0xee, 0x87, 0x6c, 0x36, 0x7b, 0x93, 0xcb, 0xe5, 0x44, 0x3a, 0x9d, + 0x86, 0xa6, 0x69, 0x50, 0x14, 0x25, 0x3e, 0x61, 0xa7, 0xd3, 0x61, 0xf3, + 0xf9, 0xfc, 0xc9, 0x78, 0x3c, 0xbe, 0xd5, 0x75, 0xfd, 0x79, 0xa5, 0x52, + 0x11, 0xa6, 0x69, 0x22, 0x95, 0x4a, 0x41, 0xd3, 0x34, 0x08, 0x21, 0xc0, + 0x18, 0x8b, 0x45, 0x28, 0x00, 0x60, 0xb5, 0x5a, 0xa5, 0x27, 0x93, 0xc9, + 0xa7, 0x62, 0xb1, 0xf8, 0xb2, 0x5a, 0xad, 0x22, 0x9f, 0xcf, 0xc3, 0x30, + 0x0c, 0x48, 0x29, 0xc1, 0x39, 0x47, 0x5c, 0xbb, 0x00, 0x20, 0xda, 0xed, + 0x36, 0x9f, 0x4e, 0xa7, 0xaf, 0x4c, 0xd3, 0x7c, 0x51, 0xaf, 0xd7, 0x61, + 0x59, 0x16, 0x74, 0x5d, 0x87, 0x94, 0x12, 0x97, 0x40, 0x2c, 0x16, 0x0b, + 0x93, 0x88, 0xde, 0xd6, 0x6a, 0x35, 0xdd, 0xb2, 0x2c, 0x18, 0x86, 0x01, + 0x21, 0x04, 0x2e, 0x05, 0xf7, 0x3c, 0xaf, 0x59, 0x2e, 0x97, 0x9f, 0x45, + 0xca, 0x38, 0xe7, 0xb8, 0x06, 0x3c, 0x08, 0x82, 0x46, 0xa1, 0x50, 0x78, + 0x74, 0xad, 0xb2, 0x23, 0xa1, 0x94, 0xf2, 0x69, 0x26, 0x93, 0xe1, 0x51, + 0x66, 0xf7, 0xf7, 0xd2, 0xf7, 0xfd, 0x07, 0x2f, 0x9e, 0x9b, 0x73, 0x55, + 0x55, 0xb3, 0x91, 0x55, 0xc6, 0x18, 0xc2, 0x30, 0xbc, 0x1b, 0xf2, 0x19, + 0xd5, 0xe7, 0xe6, 0x5c, 0x4a, 0x39, 0x06, 0x70, 0x5c, 0x8b, 0xb8, 0xeb, + 0x71, 0xd6, 0x32, 0x11, 0x75, 0xf6, 0xfb, 0xfd, 0xd1, 0xea, 0xd5, 0xa5, + 0x10, 0xd1, 0xb7, 0xf5, 0x7a, 0x1d, 0x84, 0x61, 0x08, 0x22, 0xba, 0x9e, + 0x50, 0x51, 0x94, 0xaf, 0x8e, 0xe3, 0xfc, 0xdc, 0xed, 0x76, 0xf8, 0x1f, + 0xe0, 0x89, 0x44, 0xe2, 0xc7, 0x72, 0xb9, 0xfc, 0xee, 0x38, 0x0e, 0x7c, + 0xdf, 0x3f, 0x5a, 0xbf, 0xdf, 0x76, 0x6c, 0xc2, 0x46, 0xa3, 0xf1, 0x2b, + 0x08, 0x82, 0xdb, 0xe1, 0x70, 0xe8, 0x2c, 0x16, 0x0b, 0x04, 0x41, 0x00, + 0x22, 0xba, 0xb8, 0x1c, 0xfe, 0x67, 0x05, 0xbe, 0x78, 0x9e, 0xf7, 0x79, + 0x30, 0x18, 0x8c, 0x67, 0xb3, 0x19, 0x45, 0x25, 0x9d, 0x53, 0x49, 0x44, + 0x38, 0x1c, 0x0e, 0x38, 0x2d, 0xf3, 0xce, 0x6f, 0x03, 0x60, 0x29, 0x84, + 0xf8, 0xe8, 0x79, 0x9e, 0xdb, 0xef, 0xf7, 0xdf, 0x97, 0x4a, 0xa5, 0xc7, + 0xd1, 0x53, 0x54, 0x55, 0x15, 0x52, 0xca, 0xbf, 0x14, 0x0b, 0x21, 0x1e, + 0x8c, 0x87, 0x9d, 0x1e, 0x5a, 0xad, 0x96, 0x00, 0x50, 0x27, 0xa2, 0x37, + 0xaa, 0xaa, 0x36, 0x0d, 0xc3, 0x28, 0x26, 0x93, 0x49, 0xa1, 0x69, 0x9a, + 0xc2, 0x39, 0x8f, 0x95, 0xc1, 0xef, 0x01, 0x00, 0x35, 0xe5, 0xd5, 0x5e, + 0xd0, 0xed, 0x0c, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, + 0xae, 0x42, 0x60, 0x82 +}; +unsigned int search_l_png_len = 604; + +unsigned char search_m_png[] = { + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, + 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x13, + 0x08, 0x02, 0x00, 0x00, 0x00, 0x35, 0x5e, 0x4b, 0x4d, 0x00, 0x00, 0x00, + 0x04, 0x67, 0x41, 0x4d, 0x41, 0x00, 0x00, 0xd6, 0xd8, 0xd4, 0x4f, 0x58, + 0x32, 0x00, 0x00, 0x00, 0x19, 0x74, 0x45, 0x58, 0x74, 0x53, 0x6f, 0x66, + 0x74, 0x77, 0x61, 0x72, 0x65, 0x00, 0x41, 0x64, 0x6f, 0x62, 0x65, 0x20, + 0x49, 0x6d, 0x61, 0x67, 0x65, 0x52, 0x65, 0x61, 0x64, 0x79, 0x71, 0xc9, + 0x65, 0x3c, 0x00, 0x00, 0x00, 0x30, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, + 0x62, 0x2c, 0x2f, 0x2f, 0x67, 0x60, 0x60, 0x60, 0x3c, 0x7e, 0xfc, 0x38, + 0x88, 0xfa, 0xf8, 0xf1, 0x23, 0x88, 0xfa, 0xff, 0xff, 0x3f, 0x90, 0x62, + 0x62, 0x00, 0x03, 0x5a, 0x50, 0x2c, 0x10, 0x1b, 0x58, 0x6e, 0xdd, 0xba, + 0x05, 0xa4, 0x00, 0x02, 0x0c, 0x00, 0xa5, 0x07, 0x0f, 0x3c, 0x7e, 0xe1, + 0x45, 0xa7, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, + 0x60, 0x82 +}; +unsigned int search_m_png_len = 158; + +unsigned char search_r_png[] = { + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, + 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x13, + 0x08, 0x06, 0x00, 0x00, 0x00, 0x9d, 0x92, 0x5d, 0xf2, 0x00, 0x00, 0x00, + 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0b, 0x13, 0x00, 0x00, 0x0b, + 0x13, 0x01, 0x00, 0x9a, 0x9c, 0x18, 0x00, 0x00, 0x00, 0x20, 0x63, 0x48, + 0x52, 0x4d, 0x00, 0x00, 0x6d, 0x98, 0x00, 0x00, 0x73, 0x8e, 0x00, 0x00, + 0xe0, 0x38, 0x00, 0x00, 0x82, 0xd5, 0x00, 0x00, 0x7a, 0x07, 0x00, 0x00, + 0xca, 0xb4, 0x00, 0x00, 0x33, 0x44, 0x00, 0x00, 0x1c, 0x76, 0x84, 0x36, + 0x2a, 0xbd, 0x00, 0x00, 0x01, 0xea, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, + 0xa4, 0xd4, 0xbf, 0xaa, 0x1a, 0x41, 0x14, 0x06, 0xf0, 0x6f, 0xf6, 0x9f, + 0xb2, 0x0a, 0x6b, 0xa5, 0x56, 0x8b, 0xa4, 0x92, 0xd4, 0x69, 0x7c, 0x03, + 0xb1, 0x59, 0x49, 0x11, 0x52, 0xdf, 0xbc, 0x43, 0xcc, 0x2b, 0xa4, 0x4c, + 0x97, 0x67, 0x08, 0xa4, 0x11, 0x2c, 0x52, 0x5c, 0x42, 0x24, 0x60, 0x8a, + 0x34, 0x29, 0x42, 0x50, 0x41, 0x21, 0xa0, 0x97, 0xd5, 0x55, 0xb3, 0xbb, + 0xee, 0xb2, 0xce, 0xee, 0xcc, 0x49, 0x91, 0x28, 0xc2, 0x0d, 0xe6, 0xaa, + 0xa7, 0x9d, 0xc3, 0x8f, 0x73, 0x98, 0xf9, 0x86, 0x75, 0x3a, 0x1d, 0xc2, + 0x89, 0x12, 0x42, 0x24, 0xf9, 0x7c, 0x7e, 0x5a, 0x2c, 0x16, 0x3f, 0x96, + 0x4a, 0xa5, 0x5e, 0xb5, 0x5a, 0xfd, 0x52, 0x2e, 0x97, 0xfd, 0x46, 0xa3, + 0x21, 0x8e, 0xfb, 0xd8, 0x60, 0x30, 0x38, 0x09, 0x65, 0x59, 0x86, 0x24, + 0x49, 0x10, 0x04, 0x81, 0xf0, 0x3c, 0x6f, 0xb3, 0xd9, 0x6c, 0x7e, 0x58, + 0x96, 0x75, 0x5b, 0xab, 0xd5, 0xde, 0x34, 0x9b, 0xcd, 0x5f, 0x07, 0xc8, + 0xf7, 0xfd, 0x93, 0x90, 0x94, 0xf2, 0x80, 0x85, 0x61, 0x88, 0xe5, 0x72, + 0x49, 0xe3, 0xf1, 0x58, 0xc6, 0x71, 0xfc, 0xc1, 0xb6, 0xed, 0xe7, 0x8e, + 0xe3, 0x84, 0x00, 0xc0, 0xa4, 0x94, 0x27, 0x21, 0x22, 0x82, 0x94, 0x12, + 0x52, 0x4a, 0xa4, 0x69, 0x8a, 0x28, 0x8a, 0xb0, 0x58, 0x2c, 0x30, 0x1c, + 0x0e, 0x85, 0xeb, 0xba, 0xef, 0x6b, 0xb5, 0xda, 0x4d, 0xab, 0xd5, 0x8a, + 0x34, 0xc6, 0xd8, 0x29, 0x07, 0x8c, 0x31, 0x28, 0x8a, 0x02, 0x22, 0x82, + 0xae, 0xeb, 0x30, 0x0c, 0x03, 0xb9, 0x5c, 0x0e, 0x86, 0x61, 0xa8, 0x52, + 0xca, 0xa7, 0xf3, 0xf9, 0xfc, 0x67, 0xbf, 0xdf, 0x7f, 0xa5, 0xe0, 0x81, + 0xc5, 0x18, 0x03, 0x63, 0x0c, 0x9a, 0xa6, 0xa1, 0x50, 0x28, 0xa0, 0x52, + 0xa9, 0xa0, 0x5e, 0xaf, 0x6b, 0x00, 0x5e, 0xac, 0xd7, 0xeb, 0x47, 0x0f, + 0x86, 0x8e, 0x41, 0x55, 0x55, 0x61, 0x9a, 0x26, 0x2a, 0x95, 0x0a, 0x6c, + 0xdb, 0xb6, 0x82, 0x20, 0x78, 0x76, 0x36, 0xb4, 0xc7, 0xf6, 0x93, 0x55, + 0xab, 0x55, 0x26, 0x84, 0x78, 0xac, 0x1c, 0x5f, 0xf3, 0xb9, 0xa5, 0xeb, + 0x3a, 0x2c, 0xcb, 0x82, 0xae, 0xeb, 0xbb, 0x03, 0xa4, 0x69, 0xda, 0xd9, + 0x53, 0x29, 0x8a, 0x02, 0xd3, 0x34, 0x99, 0x61, 0x18, 0xcb, 0x8b, 0x56, + 0x3b, 0xc6, 0xfe, 0x4e, 0x76, 0x77, 0x15, 0x44, 0x44, 0xe0, 0x9c, 0x0b, + 0x22, 0xfa, 0xaa, 0x5c, 0x83, 0x48, 0x29, 0x11, 0x86, 0xe1, 0x86, 0x88, + 0xbe, 0x5f, 0x35, 0xd1, 0x6e, 0xb7, 0x83, 0xe7, 0x79, 0x3d, 0x55, 0x55, + 0x7d, 0xd0, 0x05, 0x25, 0xa5, 0x24, 0xce, 0x39, 0x4d, 0x26, 0x93, 0x45, + 0xb7, 0xdb, 0x7d, 0x42, 0x44, 0x50, 0x2e, 0x59, 0x49, 0x08, 0x81, 0xf5, + 0x7a, 0x9d, 0x4c, 0xa7, 0xd3, 0x77, 0x42, 0x88, 0x6f, 0x00, 0xa0, 0xed, + 0x0f, 0xb3, 0x2c, 0x3b, 0xe4, 0xe9, 0x5f, 0xf9, 0x23, 0xfa, 0x93, 0x6d, + 0xce, 0x39, 0x56, 0xab, 0x95, 0x18, 0x0e, 0x87, 0x9f, 0x82, 0x20, 0x78, + 0xdd, 0x6e, 0xb7, 0xd3, 0x7b, 0xe9, 0x27, 0xa2, 0x7b, 0x08, 0x11, 0x21, + 0x4d, 0x53, 0x70, 0xce, 0x11, 0xc7, 0xb1, 0x74, 0x5d, 0xd7, 0x9f, 0xcd, + 0x66, 0x3d, 0xce, 0xf9, 0x4b, 0xc7, 0x71, 0xee, 0x0e, 0xef, 0x70, 0x34, + 0x1a, 0xe1, 0x7f, 0xff, 0x51, 0x92, 0x24, 0xd8, 0x6e, 0xb7, 0x61, 0x14, + 0x45, 0x9f, 0x39, 0xe7, 0x6f, 0x19, 0x63, 0xb7, 0x8e, 0xe3, 0x44, 0xc7, + 0x7d, 0xbf, 0x07, 0x00, 0x5f, 0x77, 0x46, 0x8c, 0x30, 0x2c, 0xd8, 0x9d, + 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 +}; +unsigned int search_r_png_len = 612; + +static unsigned char close_png[] = { + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, + 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0b, + 0x08, 0x06, 0x00, 0x00, 0x00, 0xa9, 0xac, 0x77, 0x26, 0x00, 0x00, 0x00, + 0xd8, 0x49, 0x44, 0x41, 0x54, 0x18, 0x19, 0x75, 0x51, 0xbd, 0x12, 0x46, + 0x40, 0x0c, 0xdc, 0x18, 0x15, 0x0a, 0x14, 0x14, 0x1a, 0x43, 0xeb, 0x35, + 0xbc, 0x7f, 0xa7, 0x43, 0x67, 0x06, 0x33, 0x28, 0xd0, 0xde, 0x77, 0x7b, + 0x23, 0x2a, 0xdf, 0x16, 0x97, 0x9f, 0xdb, 0xcb, 0x26, 0x39, 0xc1, 0x83, + 0x7d, 0xdf, 0xcd, 0xb2, 0x2c, 0xd8, 0xb6, 0x0d, 0xe7, 0x79, 0x22, 0x8a, + 0x22, 0xc4, 0x71, 0x8c, 0x3c, 0xcf, 0x91, 0xa6, 0xa9, 0x90, 0xe6, 0x8e, + 0x69, 0x9a, 0xcc, 0x38, 0x8e, 0xb8, 0xae, 0x4b, 0xdf, 0xbe, 0x36, 0x0c, + 0x43, 0x94, 0x65, 0x89, 0xa2, 0x28, 0xc4, 0x3b, 0x8e, 0xe3, 0x2f, 0x91, + 0x2f, 0xa8, 0xc2, 0x42, 0x56, 0xd1, 0x78, 0xf3, 0x3c, 0xbb, 0x04, 0x2f, + 0xda, 0xb6, 0x45, 0x55, 0x55, 0x74, 0x9d, 0x65, 0x2c, 0x22, 0xb8, 0xef, + 0x1b, 0xeb, 0xba, 0xc2, 0x67, 0x8f, 0x4c, 0x10, 0x7d, 0xdf, 0xa3, 0xae, + 0x6b, 0xe7, 0xd3, 0x32, 0x56, 0x90, 0xe7, 0x53, 0x46, 0x31, 0x0c, 0x83, + 0x73, 0x95, 0xa8, 0x31, 0x93, 0x9c, 0xc7, 0xe3, 0xd4, 0x0a, 0xb6, 0xa0, + 0x44, 0x5a, 0xc6, 0xc6, 0x18, 0x77, 0xcd, 0x41, 0xbd, 0x24, 0x49, 0x94, + 0xfb, 0x12, 0x59, 0x51, 0x5b, 0xd2, 0x16, 0xed, 0xfa, 0x20, 0xdc, 0x6f, + 0xd7, 0x75, 0x9f, 0x6b, 0xd3, 0x2a, 0x41, 0x10, 0xa0, 0x69, 0x1a, 0x57, + 0x59, 0x28, 0x47, 0x99, 0x2f, 0x30, 0xcf, 0x7b, 0xfb, 0x41, 0xcf, 0x1a, + 0x2c, 0xeb, 0xeb, 0x07, 0x29, 0x9d, 0x65, 0x19, 0x6c, 0xab, 0x6e, 0x5d, + 0x3f, 0x07, 0x0a, 0x79, 0x90, 0x0e, 0x11, 0x45, 0xc2, 0x00, 0x00, 0x00, + 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 +}; +static unsigned int close_png_len = 273; + +#if 0 +unsigned char open_gif[] = { + 0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x09, 0x00, 0x09, 0x00, 0xf0, 0x00, + 0x00, 0x8e, 0xaf, 0xc4, 0x00, 0x00, 0x00, 0x21, 0xf9, 0x04, 0x01, 0x00, + 0x00, 0x01, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x09, 0x00, + 0x00, 0x02, 0x0d, 0x8c, 0x8f, 0xa9, 0xcb, 0xe0, 0xff, 0x02, 0x8c, 0x66, + 0x26, 0x7a, 0x51, 0x01, 0x00, 0x3b +}; +unsigned int open_gif_len = 54; + +unsigned char closed_gif[] = { + 0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x09, 0x00, 0x09, 0x00, 0xf0, 0x00, + 0x00, 0x8e, 0xaf, 0xc4, 0x00, 0x00, 0x00, 0x21, 0xf9, 0x04, 0x01, 0x00, + 0x00, 0x01, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x09, 0x00, + 0x00, 0x02, 0x10, 0x8c, 0x03, 0xa7, 0x98, 0xcb, 0xad, 0x80, 0x84, 0x66, + 0xca, 0x38, 0x57, 0xd6, 0xf4, 0xd0, 0x02, 0x00, 0x3b +}; +unsigned int closed_gif_len = 57; +#endif + +static unsigned char closed_png[81] = +{ + 0, 0, 0, 0,142, 0, 0, 0, 0, + 0, 0, 0, 0,142,142, 0, 0, 0, + 0, 0, 0, 0,142,142,142, 0, 0, + 0, 0, 0, 0,142,142,142,142, 0, + 0, 0, 0, 0,142,142,142,142,142, + 0, 0, 0, 0,142,142,142,142, 0, + 0, 0, 0, 0,142,142,142, 0, 0, + 0, 0, 0, 0,142,142, 0, 0, 0, + 0, 0, 0, 0,142, 0, 0, 0, 0 +}; + +static unsigned char closed_a_png[81] = +{ + 0, 0, 0, 0,255, 0, 0, 0, 0, + 0, 0, 0, 0,255,255, 0, 0, 0, + 0, 0, 0, 0,255,255,255, 0, 0, + 0, 0, 0, 0,255,255,255,255, 0, + 0, 0, 0, 0,255,255,255,255,255, + 0, 0, 0, 0,255,255,255,255, 0, + 0, 0, 0, 0,255,255,255, 0, 0, + 0, 0, 0, 0,255,255, 0, 0, 0, + 0, 0, 0, 0,255, 0, 0, 0, 0 +}; + +static unsigned char open_png[81] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 142,142,142,142,142,142,142,142,142, + 0,142,142,142,142,142,142,142, 0, + 0, 0,142,142,142,142,142, 0, 0, + 0, 0, 0,142,142,142, 0, 0, 0, + 0, 0, 0, 0,142, 0, 0, 0, 0 +}; + +static unsigned char open_a_png[81] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 255,255,255,255,255,255,255,255,255, + 0,255,255,255,255,255,255,255, 0, + 0, 0,255,255,255,255,255, 0, 0, + 0, 0, 0,255,255,255, 0, 0, 0, + 0, 0, 0, 0,255, 0, 0, 0, 0 +}; + +static unsigned char bdwn_png[7*8] = +{ + 0, 0, 0,142, 0, 0, 0, + 0, 0, 0,142, 0, 0, 0, + 0, 0, 0,142, 0, 0, 0, + 142, 0, 0,142, 0, 0,142, + 142,142, 0,142, 0,142,142, + 142,142,142,142,142,142,142, + 0,142,142,142,142,142, 0, + 0, 0,142,142,142, 0, 0, +}; + +static unsigned char bdwn_a_png[7*8] = +{ + 0, 0, 0,255, 0, 0, 0, + 0, 0, 0,255, 0, 0, 0, + 0, 0, 0,255, 0, 0, 0, + 128, 0, 0,255, 0, 0,128, + 255,128, 0,255, 0,128,255, + 128,255,128,255,128,255,128, + 0,128,255,255,255,128, 0, + 0, 0,128,255,128, 0, 0, +}; + + + +//------------------------------------------------------------------------ + +static const char tabs_css[] = +".tabs, .tabs2, .tabs3 {\n" +" background-image: url('tab_b.png');\n" +" width: 100%;\n" +" z-index: 101;\n" +" font-size: 13px;\n" +"}\n" +"\n" +".tabs2 {\n" +" font-size: 10px;\n" +"}\n" +".tabs3 {\n" +" font-size: 9px;\n" +"}\n" +"\n" +".tablist {\n" +" margin: 0;\n" +" padding: 0;\n" +" display: table;\n" +"}\n" +"\n" +".tablist li {\n" +" float: left;\n" +" display: table-cell;\n" +" background-image: url('tab_b.png');\n" +" line-height: 36px;\n" +" list-style: none;\n" +"}\n" +"\n" +".tablist a {\n" +" display: block;\n" +" padding: 0 20px;\n" +" font-weight: bold;\n" +" background-image:url('tab_s.png');\n" +" background-repeat:no-repeat;\n" +" background-position:right;\n" +" color: ##30;\n" +" text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.9);\n" +" text-decoration: none;\n" +" outline: none;\n" +"}\n" +"\n" +".tabs3 .tablist a {\n" +" padding: 0 10px;\n" +"}\n" +"\n" +".tablist a:hover {\n" +" background-image: url('tab_h.png');\n" +" background-repeat:repeat-x;\n" +" color: #fff;\n" +" text-shadow: 0px 1px 1px rgba(0, 0, 0, 1.0);\n" +" text-decoration: none;\n" +"}\n" +"\n" +".tablist li.current a {\n" +" background-image: url('tab_a.png');\n" +" background-repeat:repeat-x;\n" +" color: #fff;\n" +" text-shadow: 0px 1px 1px rgba(0, 0, 0, 1.0);\n" +"}\n" +; + +struct img_data_item +{ + const char *name; + unsigned char *content; + unsigned int len; +}; + + +static void writeImgData(const char *dir,img_data_item *data) +{ + while (data->name) + { + QCString fileName; + fileName=(QCString)dir+"/"+data->name; + QFile f(fileName); + if (f.open(IO_WriteOnly)) + { + f.writeBlock((char*)data->content, + data->len>0 ? data->len : strlen((char*)data->content)); + } + else + { + fprintf(stderr,"Warning: Cannot open file %s for writing\n",data->name); + } + Doxygen::indexList.addImageFile(QCString("/search/")+data->name); + data++; + } +} + +static ColoredImgDataItem colored_tab_data[] = +{ + { "tab_a.png", 1, 36, tab_a_png, 0 }, + { "tab_b.png", 1, 36, tab_b_png, 0 }, + { "tab_h.png", 1, 36, tab_h_png, 0 }, + { "tab_s.png", 1, 36, tab_s_png, 0 }, + { "nav_h.png", 1, 12, header_png, 0 }, + { "nav_f.png", 1, 56, func_header_png, 0 }, + { "bc_s.png", 8, 32, bc_s_png, bc_s_a_png }, + { "doxygen.png", 104,31, doxygen_png, doxygen_a_png }, + { "closed.png", 9, 9, closed_png, closed_a_png }, + { "open.png", 9, 9, open_png, open_a_png }, + { "bdwn.png", 7, 8, bdwn_png, bdwn_a_png }, + { 0, 0, 0, 0, 0 } +}; + +static img_data_item search_client_data[] = +{ + { "mag_sel.png", mag_sel_png, mag_sel_png_len }, + { "search_l.png", search_l_png, search_l_png_len }, + { "search_m.png", search_m_png, search_m_png_len }, + { "search_r.png", search_r_png, search_r_png_len }, + { "close.png", close_png, close_png_len }, + { 0, 0, 0 } +}; + +static img_data_item search_server_data[] = +{ + { "mag.png", mag_png, mag_png_len }, + { "search_l.png", search_l_png, search_l_png_len }, + { "search_m.png", search_m_png, search_m_png_len }, + { "search_r.png", search_r_png, search_r_png_len }, + { 0, 0, 0 } +}; + +//------------------------------------------------------------------------ + +static void writeClientSearchBox(FTextStream &t,const char *relPath) +{ + t << "

    \n"; + t << " \n"; + t << " \"\"/\n"; + t << " trSearch() << "\" accesskey=\"S\"\n"; + t << " onfocus=\"searchBox.OnSearchFieldFocus(true)\" \n"; + t << " onblur=\"searchBox.OnSearchFieldFocus(false)\" \n"; + t << " onkeyup=\"searchBox.OnSearchFieldChange(event)\"/>\n"; + t << " \n"; + t << " " + << "\"\"/\n"; + t << " \n"; + t << "
    \n"; +} + +static void writeServerSearchBox(FTextStream &t,const char *relPath,bool highlightSearch) +{ + t << "
    \n"; + t << "
    \n"; + t << "
    \n"; + t << " \"\"/\n"; + if (!highlightSearch) + { + t << " trSearch() << "\" size=\"20\" accesskey=\"S\" \n"; + t << " onfocus=\"searchBox.OnSearchFieldFocus(true)\" \n"; + t << " onblur=\"searchBox.OnSearchFieldFocus(false)\"/>\n"; + t << "
    \n"; + t << "
    \n"; + t << "
    \n"; + } +} + +//------------------------------------------------------------------------ + +/// substitute all occurrences of \a src in \a s by \a dst +QCString substitute(const char *s,const char *src,const char *dst) +{ + if (s==0 || src==0) return s; + const char *p, *q; + int srcLen = strlen(src); + int dstLen = dst ? strlen(dst) : 0; + int resLen; + if (srcLen!=dstLen) + { + int count; + for (count=0, p=s; (q=strstr(p,src))!=0; p=q+srcLen) count++; + resLen = p-s+strlen(p)+count*(dstLen-srcLen); + } + else // result has same size as s + { + resLen = strlen(s); + } + QCString result(resLen+1); + char *r; + for (r=result.data(), p=s; (q=strstr(p,src))!=0; p=q+srcLen) + { + int l = (int)(q-p); + memcpy(r,p,l); + r+=l; + if (dst) memcpy(r,dst,dstLen); + r+=dstLen; + } + strcpy(r,p); + //printf("substitute(%s,%s,%s)->%s\n",s,src,dst,result.data()); + return result; +} +//---------------------------------------------------------------------- + +/// Clear a text block \a s from \a begin to \a end markers +QCString clearBlock(const char *s,const char *begin,const char *end) +{ + if (s==0 || begin==0 || end==0) return s; + const char *p, *q; + int beginLen = strlen(begin); + int endLen = strlen(end); + int resLen = 0; + for (p=s; (q=strstr(p,begin))!=0; p=q+endLen) + { + resLen+=q-p; + p=q+beginLen; + if ((q=strstr(p,end))==0) + { + resLen+=beginLen; + break; + } + } + resLen+=strlen(p); + // resLen is the length of the string without the marked block + + QCString result(resLen+1); + char *r; + for (r=result.data(), p=s; (q=strstr(p,begin))!=0; p=q+endLen) + { + int l = (int)(q-p); + memcpy(r,p,l); + r+=l; + p=q+beginLen; + if ((q=strstr(p,end))==0) + { + memcpy(r,begin,beginLen); + r+=beginLen; + break; + } + } + strcpy(r,p); + return result; +} +//---------------------------------------------------------------------- + +QCString selectBlock(const QCString& s,const QCString &name,bool enable) +{ + const QCString begin = ""; + const QCString end = ""; + const QCString nobegin = ""; + const QCString noend = ""; + + QCString result = s; + if (enable) + { + result = substitute(result, begin, ""); + result = substitute(result, end, ""); + result = clearBlock(result, nobegin, noend); + } + else + { + result = substitute(result, nobegin, ""); + result = substitute(result, noend, ""); + result = clearBlock(result, begin, end); + } + + return result; +} + +static QCString getSearchBox(bool serverSide, QCString relPath, bool highlightSearch) +{ + QGString result; + FTextStream t(&result); + if (serverSide) { + writeServerSearchBox(t, relPath, highlightSearch); + } + else { + writeClientSearchBox(t, relPath); + } + return QCString(result); +} + + +static QCString substituteHtmlKeywords(const QCString &s,const char *title, + const QCString &relPath) +{ + // Build CSS/Javascript tags depending on treeview, search engine settings + QCString cssFile; + QCString generatedBy; + QCString treeViewCssJs; + QCString searchCssJs; + QCString searchBox; + QCString mathJaxJs; + + static QCString projectName = Config_getString("PROJECT_NAME"); + static bool timeStamp = Config_getBool("HTML_TIMESTAMP"); + static bool treeView = Config_getBool("GENERATE_TREEVIEW"); + static bool searchEngine = Config_getBool("SEARCHENGINE"); + static bool serverBasedSearch = Config_getBool("SERVER_BASED_SEARCH"); + static bool mathJax = Config_getBool("USE_MATHJAX"); + static bool disableIndex = Config_getBool("DISABLE_INDEX"); + static bool hasProjectName = !projectName.isEmpty(); + static bool hasProjectNumber = !Config_getString("PROJECT_NUMBER").isEmpty(); + static bool hasProjectBrief = !Config_getString("PROJECT_BRIEF").isEmpty(); + static bool hasProjectLogo = !Config_getString("PROJECT_LOGO").isEmpty(); + static bool titleArea = (hasProjectName || hasProjectBrief || hasProjectLogo || (disableIndex && searchEngine)); + + cssFile = Config_getString("HTML_STYLESHEET"); + if (cssFile.isEmpty()) + { + cssFile = "doxygen.css"; + } + else + { + QFileInfo cssfi(cssFile); + if (cssfi.exists()) + { + cssFile = cssfi.fileName(); + } + else + { + cssFile = "doxygen.css"; + } + } + + if (timeStamp) { + generatedBy = theTranslator->trGeneratedAt(dateToString(TRUE), Config_getString("PROJECT_NAME")); + } + else { + generatedBy = theTranslator->trGeneratedBy(); + } + + if (treeView) + { + treeViewCssJs = "\n" + "\n" + "\n" + "\n" + ""; + } + + if (searchEngine) + { + searchCssJs = "\n"; + if (!Config_getBool("GENERATE_TREEVIEW")) + { + searchCssJs += "\n"; + } + searchCssJs += "\n"; + + if (!serverBasedSearch) + { + searchCssJs += ""; + } + else + { + searchCssJs += "\n"; + + // OPENSEARCH_PROVIDER { + searchCssJs += ""; + // OPENSEARCH_PROVIDER } + } + searchBox = getSearchBox(serverBasedSearch, relPath, FALSE); + } + + if (mathJax) + { + QCString path = Config_getString("MATHJAX_RELPATH"); + if (!path.isEmpty() && path.at(path.length()-1)!='/') + { + path+="/"; + } + if (path.isEmpty() || path.left(2)=="..") // relative path + { + path.prepend(relPath); + } + mathJaxJs = ""; + mathJaxJs += "\n"; + } + + // first substitute generic keywords + QCString result = substituteKeywords(s,title, + convertToHtml(Config_getString("PROJECT_NAME")), + convertToHtml(Config_getString("PROJECT_NUMBER")), + convertToHtml(Config_getString("PROJECT_BRIEF"))); + + // additional HTML only keywords + result = substitute(result,"$stylesheet",cssFile); + result = substitute(result,"$treeview",treeViewCssJs); + result = substitute(result,"$searchbox",searchBox); + result = substitute(result,"$search",searchCssJs); + result = substitute(result,"$mathjax",mathJaxJs); + result = substitute(result,"$generatedby",generatedBy); + result = substitute(result,"$relpath$",relPath); //<-- must be last + + // additional HTML only conditional blocks + result = selectBlock(result,"DISABLE_INDEX",disableIndex); + result = selectBlock(result,"GENERATE_TREEVIEW",treeView); + result = selectBlock(result,"SEARCHENGINE",searchEngine); + result = selectBlock(result,"TITLEAREA",titleArea); + result = selectBlock(result,"PROJECT_NAME",hasProjectName); + result = selectBlock(result,"PROJECT_NUMBER",hasProjectNumber); + result = selectBlock(result,"PROJECT_BRIEF",hasProjectBrief); + result = selectBlock(result,"PROJECT_LOGO",hasProjectLogo); + + return result; +} + +//------------------------- Pictures for the Tabs ------------------------ + +HtmlGenerator::HtmlGenerator() : OutputGenerator() +{ + dir=Config_getString("HTML_OUTPUT"); + col=0; + m_emptySection=FALSE; +} + +HtmlGenerator::~HtmlGenerator() +{ + //printf("HtmlGenerator::~HtmlGenerator()\n"); +} + +void HtmlGenerator::init() +{ + QCString dname=Config_getString("HTML_OUTPUT"); + QDir d(dname); + if (!d.exists() && !d.mkdir(dname)) + { + err("Could not create output directory %s\n",dname.data()); + exit(1); + } + //writeLogo(dname); + if (!Config_getString("HTML_HEADER").isEmpty()) + { + g_header=fileToString(Config_getString("HTML_HEADER")); + //printf("g_header='%s'\n",g_header.data()); + } + else + { + g_header = defaultHtmlHeader; + } + + if (!Config_getString("HTML_FOOTER").isEmpty()) + { + g_footer=fileToString(Config_getString("HTML_FOOTER")); + //printf("g_footer='%s'\n",g_footer.data()); + } + else + { + g_footer = defaultHtmlFooter; + } + createSubDirs(d); + + QCString fileName=dname+"/tabs.css"; + QFile f(fileName); + if (f.open(IO_WriteOnly)) + { + FTextStream t(&f); + t << replaceColorMarkers(tabs_css); + } + else + { + fprintf(stderr,"Warning: Cannot open file %s for writing\n",fileName.data()); + } + + { + QFile f(dname+"/jquery.js"); + if (f.open(IO_WriteOnly)) + { + FTextStream t(&f); + t << search_jquery_script1 << search_jquery_script2 << search_jquery_script3; + if (Config_getBool("GENERATE_TREEVIEW")) + { + t << search_jquery_script4; + } + } + } + + if (Config_getBool("INTERACTIVE_SVG")) + { + QFile f(dname+"/svgpan.js"); + if (f.open(IO_WriteOnly)) + { + FTextStream t(&f); + t << svgpan_script; + } + } + + if (Config_getBool("HTML_DYNAMIC_SECTIONS")) + { + QFile f(dname+"/dynsections.js"); + if (f.open(IO_WriteOnly)) + { + FTextStream t(&f); + t << + "var showTriggers = new Array();\n" + "\n" + "function registerShow(sectId,showFunc) {\n" + " showTriggers[sectId] = showFunc;\n" + "}\n" + "\n" + "function hasClass(ele,cls) {\n" + " return ele.className.match(new RegExp('(\\\\s|^)'+cls+'(\\\\s|$)'));\n" + "}\n" + "\n" + "function addClass(ele,cls) {\n" + " if (!this.hasClass(ele,cls)) ele.className += \" \"+cls;\n" + "}\n" + "\n" + "function removeClass(ele,cls) {\n" + " if (hasClass(ele,cls)) {\n" + " var reg = new RegExp('(\\\\s|^)'+cls+'(\\\\s|$)');\n" + " ele.className=ele.className.replace(reg,' ');\n" + " }\n" + "}\n" + "\n" + "function toggleVisibility(linkObj) {\n" + " var base = linkObj.getAttribute('id');\n" + " var summary = document.getElementById(base + '-summary');\n" + " var content = document.getElementById(base + '-content');\n" + " var trigger = document.getElementById(base + '-trigger');\n" + " if ( hasClass(linkObj,'closed') ) {\n" + " summary.style.display = 'none';\n" + " content.style.display = 'block';\n" + " trigger.src = trigger.src.substring(0,trigger.src.length-10)+'open.png';\n" + " removeClass(linkObj,'closed');\n" + " addClass(linkObj,'opened');\n" + " if (showTriggers[base]) { showTriggers[base](); }\n" + " } else if ( hasClass(linkObj,'opened') ) {\n" + " summary.style.display = 'block';\n" + " content.style.display = 'none';\n" + " trigger.src = trigger.src.substring(0,trigger.src.length-8)+'closed.png';\n" + " removeClass(linkObj,'opened');\n" + " addClass(linkObj,'closed');\n" + " }\n" + " return false;\n" + "}\n"; + } + } +} + +/// Additional initialization after indices have been created +void HtmlGenerator::writeTabData() +{ + Doxygen::indexList.addStyleSheetFile("tabs.css"); + QCString dname=Config_getString("HTML_OUTPUT"); + writeColoredImgData(dname,colored_tab_data); +} + +void HtmlGenerator::writeSearchData(const char *dir) +{ + static bool serverBasedSearch = Config_getBool("SERVER_BASED_SEARCH"); + writeImgData(dir,serverBasedSearch ? search_server_data : search_client_data); + QCString searchDirName = Config_getString("HTML_OUTPUT")+"/search"; + QFile f(searchDirName+"/search.css"); + if (f.open(IO_WriteOnly)) + { + FTextStream t(&f); + QCString searchCss = replaceColorMarkers(search_styleSheet); + if (Config_getBool("DISABLE_INDEX")) + { + // move up the search box if there are no tabs + searchCss = substitute(searchCss,"margin-top: 8px;","margin-top: 0px;"); + } + t << searchCss; + } + Doxygen::indexList.addStyleSheetFile("search/search.css"); +} + + + +void HtmlGenerator::writeStyleSheetFile(QFile &file) +{ + FTextStream t(&file); + t << replaceColorMarkers(defaultStyleSheet); +} + +void HtmlGenerator::writeHeaderFile(QFile &file, const char *cssname) +{ + FTextStream t(&file); + + QString relPathStr = "$relpath$"; + + QCString id(file.name()); + if (id.right(Doxygen::htmlFileExtension.length())==Doxygen::htmlFileExtension) + { + id=id.left(id.length()-Doxygen::htmlFileExtension.length()); + } + + t << substitute(defaultHtmlHeader, "$stylesheet", cssname); +} + +void HtmlGenerator::writeFooterFile(QFile &file) +{ + FTextStream t(&file); + QCString contents(defaultHtmlFooter); + t << contents; +} + +static void generateDynamicSections(FTextStream &t,const QCString &relPath) +{ + if (Config_getBool("HTML_DYNAMIC_SECTIONS")) + { + t << "\n"; + } +} + + +void HtmlGenerator::startFile(const char *name,const char *, + const char *title) +{ + //printf("HtmlGenerator::startFile(%s)\n",name); + QCString fileName=name; + lastTitle=title; + relPath = relativePathToRoot(fileName); + + if (fileName.right(Doxygen::htmlFileExtension.length())!=Doxygen::htmlFileExtension) + { + fileName+=Doxygen::htmlFileExtension; + } + startPlainFile(fileName); + Doxygen::indexList.addIndexFile(fileName); + //if (Config_getBool("GENERATE_HTMLHELP")) + //{ + // HtmlHelp::getInstance()->addIndexFile(fileName); + //} + + lastFile = fileName; + t << substituteHtmlKeywords(g_header,convertToHtml(title),relPath); + + t << "" << endl; + //static bool generateTreeView = Config_getBool("GENERATE_TREEVIEW"); + static bool searchEngine = Config_getBool("SEARCHENGINE"); + if (searchEngine /*&& !generateTreeView*/) + { + t << "\n"; + } + generateDynamicSections(t,relPath); + m_sectionCount=0; +} + +void HtmlGenerator::writeSearchInfo(FTextStream &t,const QCString &relPath) +{ + static bool searchEngine = Config_getBool("SEARCHENGINE"); + static bool serverBasedSearch = Config_getBool("SERVER_BASED_SEARCH"); + if (searchEngine && !serverBasedSearch) + { + (void)relPath; + t << "\n"; + t << "
    \n"; + writeSearchCategories(t); + t << "
    \n"; + t << "\n"; + t << "\n"; + t << "
    \n"; + t << "\n"; + t << "
    \n"; + t << "\n"; + } +} + +void HtmlGenerator::writeSearchInfo() +{ + writeSearchInfo(t,relPath); +} + + +QCString HtmlGenerator::writeLogoAsString(const char *path) +{ + static bool timeStamp = Config_getBool("HTML_TIMESTAMP"); + QCString result; + if (timeStamp) + { + result += theTranslator->trGeneratedAt( + dateToString(TRUE), + Config_getString("PROJECT_NAME") + ); + } + else + { + result += theTranslator->trGeneratedBy(); + } + result += " \n\n" + "\"doxygen\"/ "; + result += versionString; + result += " "; + return result; +} + +void HtmlGenerator::writeLogo() +{ + t << writeLogoAsString(relPath); +} + +void HtmlGenerator::writePageFooter(FTextStream &t,const QCString &lastTitle,const QCString &relPath) +{ + t << substituteHtmlKeywords(g_footer,convertToHtml(lastTitle),relPath); +} + +void HtmlGenerator::writeFooter() +{ + writePageFooter(t,lastTitle,relPath); +} + +void HtmlGenerator::endFile() +{ + endPlainFile(); +} + +void HtmlGenerator::startProjectNumber() +{ + t << "

    "; +} + +void HtmlGenerator::endProjectNumber() +{ + t << "

    "; +} + +void HtmlGenerator::writeStyleInfo(int part) +{ + //printf("writeStyleInfo(%d)\n",part); + if (part==0) + { + if (Config_getString("HTML_STYLESHEET").isEmpty()) // write default style sheet + { + //printf("write doxygen.css\n"); + startPlainFile("doxygen.css"); + + // alternative, cooler looking titles + //t << "H1 { text-align: center; border-width: thin none thin none;" << endl; + //t << " border-style : double; border-color : blue; padding-left : 1em; padding-right : 1em }" << endl; + + t << replaceColorMarkers(defaultStyleSheet); + endPlainFile(); + Doxygen::indexList.addStyleSheetFile("doxygen.css"); + } + else // write user defined style sheet + { + 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()); + } + else + { + // convert style sheet to string + QCString fileStr = fileToString(cssname); + // write the string into the output dir + startPlainFile(cssfi.fileName()); + t << fileStr; + endPlainFile(); + } + Doxygen::indexList.addStyleSheetFile(cssfi.fileName()); + } + } +} + +void HtmlGenerator::startDoxyAnchor(const char *,const char *, + const char *anchor, const char *, + const char *) +{ + t << ""; +} + +void HtmlGenerator::endDoxyAnchor(const char *,const char *) +{ +} + +//void HtmlGenerator::newParagraph() +//{ +// t << endl << "

    " << endl; +//} + +void HtmlGenerator::startParagraph() +{ + t << endl << "

    "; +} + +void HtmlGenerator::endParagraph() +{ + t << "

    " << endl; +} + +void HtmlGenerator::writeString(const char *text) +{ + t << text; +} + +void HtmlGenerator::startIndexListItem() +{ + t << "
  • "; +} + +void HtmlGenerator::endIndexListItem() +{ + t << "
  • " << endl; +} + +void HtmlGenerator::startIndexItem(const char *ref,const char *f) +{ + //printf("HtmlGenerator::startIndexItem(%s,%s)\n",ref,f); + if (ref || f) + { + if (ref) + { + t << ""; + } + else + { + t << ""; + } +} + +void HtmlGenerator::endIndexItem(const char *ref,const char *f) +{ + //printf("HtmlGenerator::endIndexItem(%s,%s,%s)\n",ref,f,name); + if (ref || f) + { + t << ""; + } + else + { + t << ""; + } +} + +void HtmlGenerator::writeStartAnnoItem(const char *,const char *f, + const char *path,const char *name) +{ + t << "
  • "; + if (path) docify(path); + t << ""; + docify(name); + t << " "; +} + +void HtmlGenerator::writeObjectLink(const char *ref,const char *f, + const char *anchor, const char *name) +{ + if (ref) + { + t << ""; + docify(name); + t << ""; +} + +void HtmlGenerator::writeCodeLink(const char *ref,const char *f, + const char *anchor, const char *name, + const char *tooltip) +{ + //printf("writeCodeLink(ref=%s,f=%s,anchor=%s,name=%s,tooltip=%s)\n",ref,f,anchor,name,tooltip); + if (ref) + { + t << ""; + docify(name); + t << ""; + col+=strlen(name); +} + +void HtmlGenerator::startTextLink(const char *f,const char *anchor) +{ + t << ""; +} + +void HtmlGenerator::endTextLink() +{ + t << ""; +} + +void HtmlGenerator::startHtmlLink(const char *url) +{ + static bool generateTreeView = Config_getBool("GENERATE_TREEVIEW"); + t << ""; +} + +void HtmlGenerator::endHtmlLink() +{ + t << ""; +} + +void HtmlGenerator::startGroupHeader(int extraIndentLevel) +{ + if (extraIndentLevel==2) + { + t << "

    "; + } + else if (extraIndentLevel==1) + { + t << "

    "; + } + else // extraIndentLevel==0 + { + t << "

    "; + } +} + +void HtmlGenerator::endGroupHeader(int extraIndentLevel) +{ + if (extraIndentLevel==2) + { + t << "

    " << endl; + } + else if (extraIndentLevel==1) + { + t << "" << endl; + } + else + { + t << "" << endl; + } +} + +void HtmlGenerator::startSection(const char *lab,const char *,SectionInfo::SectionType type) +{ + switch(type) + { + case SectionInfo::Page: t << "\n\n

    "; break; + case SectionInfo::Section: t << "\n\n

    "; break; + case SectionInfo::Subsection: t << "\n\n

    "; break; + case SectionInfo::Subsubsection: t << "\n\n

    "; break; + case SectionInfo::Paragraph: t << "\n\n

    "; break; + default: ASSERT(0); break; + } + t << ""; +} + +void HtmlGenerator::endSection(const char *,SectionInfo::SectionType type) +{ + switch(type) + { + case SectionInfo::Page: t << "
    "; break; + case SectionInfo::Section: t << ""; break; + case SectionInfo::Subsection: t << ""; break; + case SectionInfo::Subsubsection: t << ""; break; + case SectionInfo::Paragraph: t << ""; break; + default: ASSERT(0); break; + } +} + +void HtmlGenerator::docify(const char *str) +{ + docify(str,FALSE); +} + +void HtmlGenerator::docify(const char *str,bool inHtmlComment) +{ + if (str) + { + const char *p=str; + char c; + while (*p) + { + c=*p++; + switch(c) + { + case '<': t << "<"; break; + case '>': t << ">"; break; + case '&': t << "&"; break; + case '"': t << """; break; + case '-': if (inHtmlComment) t << "-"; else t << "-"; break; + case '\\': + if (*p=='<') + { t << "<"; p++; } + else if (*p=='>') + { t << ">"; p++; } + else + t << "\\"; + break; + default: t << c; + } + } + } +} + +void HtmlGenerator::codify(const char *str) +{ + //docify(str); + //static char spaces[]=" "; + if (str) + { + const char *p=str; + char c; + int spacesToNextTabStop; + while (*p) + { + c=*p++; + switch(c) + { + case '\t': spacesToNextTabStop = + Config_getInt("TAB_SIZE") - (col%Config_getInt("TAB_SIZE")); + t << Doxygen::spaces.left(spacesToNextTabStop); + col+=spacesToNextTabStop; + break; + case '\n': t << "\n"; col=0; + break; + //case '\n': t << "
    "; col=0; + // break; + case '\r': break; + case '<': t << "<"; col++; + break; + case '>': t << ">"; col++; + break; + case '&': t << "&"; col++; + break; + case '\'': t << "'"; col++; // ' is not valid HTML + break; + case '"': t << """; col++; + break; + //case ' ': t << " "; col++; + // break; + case '\\': + if (*p=='<') + { t << "<"; p++; } + else if (*p=='>') + { t << ">"; p++; } + else + t << "\\"; + col++; + break; + default: t << c; + col++; + break; + } + } + } +} + +void HtmlGenerator::writeChar(char c) +{ + char cs[2]; + cs[0]=c; + cs[1]=0; + docify(cs); +} + +//--- helper function for dynamic sections ------------------------- + +static void startSectionHeader(FTextStream &t, + const QCString &relPath,int sectionCount) +{ + //t << ""; + static bool dynamicSections = Config_getBool("HTML_DYNAMIC_SECTIONS"); + if (dynamicSections) + { + t << "
    " << endl; + t << " \"+\"/ "; + } + else + { + t << "
    " << endl; + } +} + +static void endSectionHeader(FTextStream &t) +{ + //t << ""; + t << "
    " << endl; +} + +static void startSectionSummary(FTextStream &t,int sectionCount) +{ + //t << ""; + static bool dynamicSections = Config_getBool("HTML_DYNAMIC_SECTIONS"); + if (dynamicSections) + { + t << "
    " << endl; + } +} + +static void endSectionSummary(FTextStream &t) +{ + //t << ""; + static bool dynamicSections = Config_getBool("HTML_DYNAMIC_SECTIONS"); + if (dynamicSections) + { + t << "
    " << endl; + } +} + +static void startSectionContent(FTextStream &t,int sectionCount) +{ + //t << ""; + static bool dynamicSections = Config_getBool("HTML_DYNAMIC_SECTIONS"); + if (dynamicSections) + { + t << "
    " << endl; + } + else + { + t << "
    " << endl; + } +} + +static void endSectionContent(FTextStream &t) +{ + //t << ""; + t << "
    " << endl; +} + +//---------------------------- + +void HtmlGenerator::startClassDiagram() +{ + startSectionHeader(t,relPath,m_sectionCount); +} + +void HtmlGenerator::endClassDiagram(const ClassDiagram &d, + const char *fileName,const char *name) +{ + endSectionHeader(t); + startSectionSummary(t,m_sectionCount); + endSectionSummary(t); + startSectionContent(t,m_sectionCount); + t << "
    " << endl; + t << " \"\"/" << endl; + t << " " << endl; + + d.writeImage(t,dir,relPath,fileName); + t << "
    "; + endSectionContent(t); + m_sectionCount++; +} + + +void HtmlGenerator::startMemberList() +{ + DBG_HTML(t << "" << endl) + if (Config_getBool("HTML_ALIGN_MEMBERS")) + { + } + else + { + t << "
      " << endl; + } +} + +void HtmlGenerator::endMemberList() +{ + DBG_HTML(t << "" << endl) + if (Config_getBool("HTML_ALIGN_MEMBERS")) + { + } + else + { + t << "
    " << endl; + } +} + +// anonymous type: +// 0 = single column right aligned +// 1 = double column left aligned +// 2 = single column left aligned +void HtmlGenerator::startMemberItem(const char *anchor,int annoType) +{ + DBG_HTML(t << "" << endl) + if (Config_getBool("HTML_ALIGN_MEMBERS")) + { + if (m_emptySection) + { + t << "" << endl; + m_emptySection=FALSE; + } + t << ""; + switch(annoType) + { + case 0: t << ""; + } + t << endl; +} + +void HtmlGenerator::startMemberTemplateParams() +{ +} + +void HtmlGenerator::endMemberTemplateParams(const char *anchor) +{ + if (Config_getBool("HTML_ALIGN_MEMBERS")) + { + t << "" << endl; + t << ""; +} + +void HtmlGenerator::startIndexValue(bool) +{ + // inserted 'class = ...', 02 jan 2002, jh + t << "" << endl; +} + +void HtmlGenerator::startMemberDocList() +{ + DBG_HTML(t << "" << endl;) +} + +void HtmlGenerator::endMemberDocList() +{ + DBG_HTML(t << "" << endl;) +} + +void HtmlGenerator::startMemberDoc(const char *,const char *,const char *,const char *,bool) +{ + DBG_HTML(t << "" << endl;) + + t << "\n
    " << endl; + t << "
    " << endl; +} + +void HtmlGenerator::startMemberDocPrefixItem() +{ + DBG_HTML(t << "" << endl;) + t << "
    " << endl; +} + +void HtmlGenerator::endMemberDocPrefixItem() +{ + DBG_HTML(t << "" << endl;) + t << "
    " << endl; +} + +void HtmlGenerator::startMemberDocName(bool /*align*/) +{ + DBG_HTML(t << "" << endl;) + + t << "
    "; break; + case 1: t << ""; break; + case 2: t << ""; break; + default: t << ""; break; + } + } + else + { + t << "
  • "; + } +} + +void HtmlGenerator::endMemberItem() +{ + //DBG_HTML(t << "" << endl) + if (Config_getBool("HTML_ALIGN_MEMBERS")) + { + t << "
  • "; + } +} + + +void HtmlGenerator::insertMemberAlign(bool templ) +{ + DBG_HTML(t << "" << endl) + if (Config_getBool("HTML_ALIGN_MEMBERS")) + { + QCString className = templ ? "memTemplItemRight" : "memItemRight"; + t << " "; + } +} + +void HtmlGenerator::startMemberDescription(const char *anchor) +{ + DBG_HTML(t << "" << endl) + if (Config_getBool("HTML_ALIGN_MEMBERS")) + { + if (m_emptySection) + { + t << "" << endl; + m_emptySection=FALSE; + } + t << "" << endl; + } + else + { + t << "
    "; + } +} + +void HtmlGenerator::startMemberSections() +{ + DBG_HTML(t << "" << endl) + if (Config_getBool("HTML_ALIGN_MEMBERS")) + { + m_emptySection=TRUE; // we postpone writing
     "; + } + else + { + t << "
    "; + } +} + +void HtmlGenerator::endMemberDescription() +{ + DBG_HTML(t << "" << endl) + if (Config_getBool("HTML_ALIGN_MEMBERS")) + { + t << "
    until we actually + // write a row to prevent empty tables, which + // are not valid XHTML! + } +} + +void HtmlGenerator::endMemberSections() +{ + DBG_HTML(t << "" << endl) + if (Config_getBool("HTML_ALIGN_MEMBERS")) + { + if (!m_emptySection) + { + t << "
    " << endl; + } + } +} + +void HtmlGenerator::startMemberHeader(const char *anchor) +{ + DBG_HTML(t << "" << endl) + if (Config_getBool("HTML_ALIGN_MEMBERS")) + { + if (m_emptySection) + { + t << "" << endl; + m_emptySection=FALSE; + } + t << "" << endl; + } + else + { + endGroupHeader(FALSE); + } +} + +void HtmlGenerator::startMemberSubtitle() +{ + DBG_HTML(t << "" << endl) + if (Config_getBool("HTML_ALIGN_MEMBERS")) t << "" << endl; +} + +void HtmlGenerator::startIndexList() +{ + t << "

    "; + } + else + { + startGroupHeader(FALSE); + } + if (anchor) + { + t << "" << endl; + } +} + +void HtmlGenerator::endMemberHeader() +{ + DBG_HTML(t << "" << endl) + if (Config_getBool("HTML_ALIGN_MEMBERS")) + { + t << "

    "; +} + +void HtmlGenerator::endMemberSubtitle() +{ + DBG_HTML(t << "" << endl) + if (Config_getBool("HTML_ALIGN_MEMBERS")) t << "
    " << endl; +} + +void HtmlGenerator::endIndexList() +{ + t << "
    " << endl; +} + +void HtmlGenerator::startIndexKey() +{ + // inserted 'class = ...', 02 jan 2002, jh + t << "
    "; +} + +void HtmlGenerator::endIndexKey() +{ + t << ""; +} + +void HtmlGenerator::endIndexValue(const char *,bool) +{ + t << "
    " << endl; + + t << " " << endl; + t << " " << endl; +} + +void HtmlGenerator::startParameterList(bool openBracket) +{ + DBG_HTML(t << "" << endl;) + t << " " << endl; +} + +void HtmlGenerator::startParameterType(bool first,const char *key) +{ + if (first) + { + DBG_HTML(t << "" << endl;) + t << " " << endl; + t << " " << endl; + t << " " << endl; + t << " " << endl; +} + +void HtmlGenerator::startParameterName(bool /*oneArgOnly*/) +{ + DBG_HTML(t << "" << endl;) + t << " " << endl; + t << " " << endl; + t << " " << endl; + t << " " << endl; + t << " " << endl; + t << " " << endl; + t << " " << endl; + t << " " << endl; + } +} + +void HtmlGenerator::endParameterList() +{ + DBG_HTML(t << "" << endl;) + t << "" << endl; + t << " " << endl; +} + +void HtmlGenerator::endMemberDoc(bool hasArgs) +{ + DBG_HTML(t << "" << endl;) + if (!hasArgs) + { + t << " " << endl; + } + t << "
    "; +} + +void HtmlGenerator::endMemberDocName() +{ + DBG_HTML(t << "" << endl;) + t << ""; + if (openBracket) t << "("; + t << ""; + } + else + { + DBG_HTML(t << "" << endl;) + t << "
    "; + if (key) t << key; + t << ""; + } +} + +void HtmlGenerator::endParameterType() +{ + DBG_HTML(t << "" << endl;) + t << " "; +} + +void HtmlGenerator::endParameterName(bool last,bool emptyList,bool closeBracket) +{ + DBG_HTML(t << "" << endl;) + if (last) + { + if (emptyList) + { + if (closeBracket) t << ")"; + t << ""; + } + else + { + t << " 
    "; + if (closeBracket) t << ")"; + t << ""; + } + } + else + { + t << "
    " << endl; + t << "
    " << endl; +} + +void HtmlGenerator::startDotGraph() +{ + startSectionHeader(t,relPath,m_sectionCount); +} + +void HtmlGenerator::endDotGraph(const DotClassGraph &g) +{ + endSectionHeader(t); + startSectionSummary(t,m_sectionCount); + endSectionSummary(t); + startSectionContent(t,m_sectionCount); + + g.writeGraph(t,BITMAP,dir,fileName,relPath,TRUE,TRUE,m_sectionCount); + if (Config_getBool("GENERATE_LEGEND")) + { + t << "
    ["; + startHtmlLink(relPath+"graph_legend"+Doxygen::htmlFileExtension); + t << theTranslator->trLegend(); + endHtmlLink(); + t << "]
    "; + } + + endSectionContent(t); + m_sectionCount++; +} + +void HtmlGenerator::startInclDepGraph() +{ + startSectionHeader(t,relPath,m_sectionCount); +} + +void HtmlGenerator::endInclDepGraph(const DotInclDepGraph &g) +{ + endSectionHeader(t); + startSectionSummary(t,m_sectionCount); + endSectionSummary(t); + startSectionContent(t,m_sectionCount); + + g.writeGraph(t,BITMAP,dir,fileName,relPath,TRUE,m_sectionCount); + + endSectionContent(t); + m_sectionCount++; +} + +void HtmlGenerator::startGroupCollaboration() +{ + startSectionHeader(t,relPath,m_sectionCount); +} + +void HtmlGenerator::endGroupCollaboration(const DotGroupCollaboration &g) +{ + endSectionHeader(t); + startSectionSummary(t,m_sectionCount); + endSectionSummary(t); + startSectionContent(t,m_sectionCount); + + g.writeGraph(t,BITMAP,dir,fileName,relPath,TRUE,m_sectionCount); + + endSectionContent(t); + m_sectionCount++; +} + +void HtmlGenerator::startCallGraph() +{ + startSectionHeader(t,relPath,m_sectionCount); +} + +void HtmlGenerator::endCallGraph(const DotCallGraph &g) +{ + endSectionHeader(t); + startSectionSummary(t,m_sectionCount); + endSectionSummary(t); + startSectionContent(t,m_sectionCount); + + g.writeGraph(t,BITMAP,dir,fileName,relPath,TRUE,m_sectionCount); + + endSectionContent(t); + m_sectionCount++; +} + +void HtmlGenerator::startDirDepGraph() +{ + startSectionHeader(t,relPath,m_sectionCount); +} + +void HtmlGenerator::endDirDepGraph(const DotDirDeps &g) +{ + endSectionHeader(t); + startSectionSummary(t,m_sectionCount); + endSectionSummary(t); + startSectionContent(t,m_sectionCount); + + g.writeGraph(t,BITMAP,dir,fileName,relPath,TRUE,m_sectionCount); + + endSectionContent(t); + m_sectionCount++; +} + +void HtmlGenerator::writeGraphicalHierarchy(const DotGfxHierarchyTable &g) +{ + g.writeGraph(t,dir,fileName); +} + +void HtmlGenerator::startMemberGroupHeader(bool) +{ + t << "
    "; +} + +void HtmlGenerator::endMemberGroupHeader() +{ + t << "
    " << endl; +} + +void HtmlGenerator::startMemberGroupDocs() +{ + t << "
    "; +} + +void HtmlGenerator::endMemberGroupDocs() +{ + t << "
    " << endl; +} + +void HtmlGenerator::startMemberGroup() +{ +} + +void HtmlGenerator::endMemberGroup(bool) +{ +} + +void HtmlGenerator::startIndent() +{ + DBG_HTML(t << "" << endl;) + + t << "
    \n"; +} + +void HtmlGenerator::endIndent() +{ + DBG_HTML(t << "" << endl;) + t << endl << "
    " << endl << "
    " << endl; +} + +void HtmlGenerator::addIndexItem(const char *,const char *) +{ +} + +void HtmlGenerator::writeNonBreakableSpace(int n) +{ + int i; + for (i=0;i
    "; + if (filename) + { + writeObjectLink(0,filename,anchor,title); + } + else + { + docify(title); + } + t << "
    "; +} + +void HtmlGenerator::endSimpleSect() +{ + t << "
  • "; +} + +void HtmlGenerator::startParamList(ParamListTypes, + const char *title) +{ + t << "
    "; + docify(title); + t << "
    "; +} + +void HtmlGenerator::endParamList() +{ + t << "
    "; +} + +void HtmlGenerator::printDoc(DocNode *n,const char *langExt) +{ + HtmlDocVisitor *visitor = new HtmlDocVisitor(t,*this,langExt); + n->accept(visitor); + delete visitor; +} + +//---------------- helpers for index generation ----------------------------- + +static void startQuickIndexList(FTextStream &t,bool compact,bool topLevel=TRUE) +{ + if (compact) + { + if (topLevel) + { + t << "
    \n"; + } + else + { + t << "
    \n"; + } + t << "
      \n"; + } + else + { + t << "
        "; + } +} + +static void endQuickIndexList(FTextStream &t,bool compact) +{ + if (compact) + { + t << "
      \n"; + t << "
    \n"; + } + else + { + t << "
\n"; + } +} + +static void startQuickIndexItem(FTextStream &t,const char *l, + bool hl,bool /*compact*/, + const QCString &relPath) +{ + t << " "; + if (l) t << ""; + t << ""; +} + +static void endQuickIndexItem(FTextStream &t,const char *l) +{ + t << ""; + if (l) t << ""; + t << "\n"; +} + +static QCString fixSpaces(const QCString &s) +{ + return substitute(s," "," "); +} + +static bool quickLinkVisible(LayoutNavEntry::Kind kind) +{ + switch (kind) + { + case LayoutNavEntry::MainPage: return TRUE; + case LayoutNavEntry::User: return TRUE; + case LayoutNavEntry::UserGroup: return TRUE; + case LayoutNavEntry::Pages: return indexedPages>0; + case LayoutNavEntry::Modules: return documentedGroups>0; + case LayoutNavEntry::Namespaces: return documentedNamespaces>0; + case LayoutNavEntry::NamespaceList: return documentedNamespaces>0; + case LayoutNavEntry::NamespaceMembers: return documentedNamespaceMembers[NMHL_All]>0; + case LayoutNavEntry::Classes: return annotatedClasses>0; + case LayoutNavEntry::ClassList: return annotatedClasses>0; + case LayoutNavEntry::ClassIndex: return annotatedClasses>0; + case LayoutNavEntry::ClassHierarchy: return hierarchyClasses>0; + case LayoutNavEntry::ClassMembers: return documentedClassMembers[CMHL_All]>0; + case LayoutNavEntry::Files: return documentedHtmlFiles>0; + case LayoutNavEntry::FileList: return documentedHtmlFiles>0; + case LayoutNavEntry::FileGlobals: return documentedFileMembers[FMHL_All]>0; + case LayoutNavEntry::Dirs: return documentedDirs>0; + case LayoutNavEntry::Examples: return Doxygen::exampleSDict->count()>0; + } + return FALSE; +} + +static void renderQuickLinksAsTree(FTextStream &t,const QCString &relPath,LayoutNavEntry *root) + +{ + QListIterator li(root->children()); + LayoutNavEntry *entry; + int count=0; + for (li.toFirst();(entry=li.current());++li) + { + if (entry->visible() && quickLinkVisible(entry->kind())) count++; + } + if (count>0) // at least one item is visible + { + startQuickIndexList(t,FALSE); + for (li.toFirst();(entry=li.current());++li) + { + if (entry->visible() && quickLinkVisible(entry->kind())) + { + QCString url = entry->url(); + t << "
  • "; + t << fixSpaces(entry->title()); + t << "\n"; + // recursive into child list + renderQuickLinksAsTree(t,relPath,entry); + t << "
  • "; + } + } + endQuickIndexList(t,FALSE); + } +} + + +static void renderQuickLinksAsTabs(FTextStream &t,const QCString &relPath, + LayoutNavEntry *hlEntry,LayoutNavEntry::Kind kind, + bool highlightParent,bool highlightSearch) +{ + if (hlEntry->parent()) // first draw the tabs for the parent of hlEntry + { + renderQuickLinksAsTabs(t,relPath,hlEntry->parent(),kind,highlightParent,highlightSearch); + } + if (hlEntry->parent() && hlEntry->parent()->children().count()>0) // draw tabs for row containing hlEntry + { + bool topLevel = hlEntry->parent()->parent()==0; + QListIterator li(hlEntry->parent()->children()); + LayoutNavEntry *entry; + + int count=0; + for (li.toFirst();(entry=li.current());++li) + { + if (entry->visible() && quickLinkVisible(entry->kind())) count++; + } + if (count>0) // at least one item is visible + { + startQuickIndexList(t,TRUE,topLevel); + for (li.toFirst();(entry=li.current());++li) + { + if (entry->visible() && quickLinkVisible(entry->kind())) + { + QCString url = entry->url(); + startQuickIndexItem(t,url, + entry==hlEntry && + (entry->children().count()>0 || + (entry->kind()==kind && !highlightParent) + ), + TRUE,relPath); + t << fixSpaces(entry->title()); + endQuickIndexItem(t,url); + } + } + if (hlEntry->parent()==LayoutDocManager::instance().rootNavEntry()) // first row is special as it contains the search box + { + static bool searchEngine = Config_getBool("SEARCHENGINE"); + static bool serverBasedSearch = Config_getBool("SERVER_BASED_SEARCH"); + if (searchEngine) + { + t << "
  • \n"; + if (!serverBasedSearch) // pure client side search + { + writeClientSearchBox(t,relPath); + t << "
  • \n"; + } + else // server based search + { + writeServerSearchBox(t,relPath,highlightSearch); + if (!highlightSearch) + { + t << " \n"; + } + } + } + if (!highlightSearch) // on the search page the index will be ended by the + // page itself + { + endQuickIndexList(t,TRUE); + } + } + else // normal case for other rows than first one + { + endQuickIndexList(t,TRUE); + } + } + } +} + +static void writeDefaultQuickLinks(FTextStream &t,bool compact, + HighlightedItem hli, + const char *file, + const QCString &relPath) +{ + LayoutNavEntry *root = LayoutDocManager::instance().rootNavEntry(); + LayoutNavEntry::Kind kind = (LayoutNavEntry::Kind)-1; + LayoutNavEntry::Kind altKind = (LayoutNavEntry::Kind)-1; // fall back for the old layout file + bool highlightParent=FALSE; + switch (hli) // map HLI enums to LayoutNavEntry::Kind enums + { + case HLI_Main: kind = LayoutNavEntry::MainPage; break; + case HLI_Modules: kind = LayoutNavEntry::Modules; break; + case HLI_Directories: kind = LayoutNavEntry::Dirs; break; + case HLI_Namespaces: kind = LayoutNavEntry::NamespaceList; altKind = LayoutNavEntry::Namespaces; break; + case HLI_Hierarchy: kind = LayoutNavEntry::ClassHierarchy; break; + case HLI_Classes: kind = LayoutNavEntry::ClassIndex; altKind = LayoutNavEntry::Classes; break; + case HLI_Annotated: kind = LayoutNavEntry::ClassList; altKind = LayoutNavEntry::Classes; break; + case HLI_Files: kind = LayoutNavEntry::FileList; altKind = LayoutNavEntry::Files; break; + case HLI_NamespaceMembers: kind = LayoutNavEntry::NamespaceMembers; break; + case HLI_Functions: kind = LayoutNavEntry::ClassMembers; break; + case HLI_Globals: kind = LayoutNavEntry::FileGlobals; break; + case HLI_Pages: kind = LayoutNavEntry::Pages; break; + case HLI_Examples: kind = LayoutNavEntry::Examples; break; + case HLI_UserGroup: kind = LayoutNavEntry::UserGroup; break; + case HLI_ClassVisible: kind = LayoutNavEntry::ClassList; altKind = LayoutNavEntry::Classes; + highlightParent = TRUE; break; + case HLI_NamespaceVisible: kind = LayoutNavEntry::NamespaceList; altKind = LayoutNavEntry::Namespaces; + highlightParent = TRUE; break; + case HLI_FileVisible: kind = LayoutNavEntry::FileList; altKind = LayoutNavEntry::Files; + highlightParent = TRUE; break; + case HLI_None: break; + case HLI_Search: break; + } + + if (compact) + { + // find highlighted index item + LayoutNavEntry *hlEntry = root->find(kind,kind==LayoutNavEntry::UserGroup ? file : 0); + if (!hlEntry && altKind!=(LayoutNavEntry::Kind)-1) { hlEntry=root->find(altKind); kind=altKind; } + if (!hlEntry) // highlighted item not found in the index! -> just show the level 1 index... + { + highlightParent=TRUE; + hlEntry = root->children().getFirst(); + if (hlEntry==0) + { + return; // argl, empty index! + } + } + if (kind==LayoutNavEntry::UserGroup) + { + LayoutNavEntry *e = hlEntry->children().getFirst(); + if (e) + { + hlEntry = e; + } + } + renderQuickLinksAsTabs(t,relPath,hlEntry,kind,highlightParent,hli==HLI_Search); + } + else + { + renderQuickLinksAsTree(t,relPath,root); + } +} + +void HtmlGenerator::endQuickIndices() +{ + t << "
    " << endl; +} + +QCString HtmlGenerator::writeSplitBarAsString(const char *name,const char *relpath) +{ + static bool generateTreeView = Config_getBool("GENERATE_TREEVIEW"); + QCString result; + // write split bar + if (generateTreeView) + { + result = QCString( + "
    \n" + "
    \n" + "
    \n" + "
    \n" + "
    \n" + "
    \n" + "
    \n" + "
    \n" + "\n" + "
    \n"); + } + return result; +} + +void HtmlGenerator::writeSplitBar(const char *name) +{ + t << writeSplitBarAsString(name,relPath); +} + +void HtmlGenerator::startContents() +{ + t << "
    " << endl; +} + +void HtmlGenerator::endContents() +{ + t << "
    " << endl; +} + +void HtmlGenerator::writeQuickLinks(bool compact,HighlightedItem hli,const char *file) +{ + writeDefaultQuickLinks(t,compact,hli,file,relPath); +} + +// PHP based search script +void HtmlGenerator::writeSearchPage() +{ + static bool generateTreeView = Config_getBool("GENERATE_TREEVIEW"); + static bool disableIndex = Config_getBool("DISABLE_INDEX"); + static QCString projectName = Config_getString("PROJECT_NAME"); + + // OPENSEARCH_PROVIDER { + QCString configFileName = Config_getString("HTML_OUTPUT")+"/search-config.php"; + QFile cf(configFileName); + if (cf.open(IO_WriteOnly)) + { + FTextStream t(&cf); + t << "\n"; + } + + QCString functionsFileName = Config_getString("HTML_OUTPUT")+"/search-functions.php"; + QFile ff(functionsFileName); + if (ff.open(IO_WriteOnly)) + { + FTextStream t(&ff); + // Write stuff from search_functions.php source file... + t << search_functions_script; + } + + QCString opensearchFileName = Config_getString("HTML_OUTPUT")+"/search-opensearch.php"; + QFile of(opensearchFileName); + if (of.open(IO_WriteOnly)) + { + FTextStream t(&of); + // Write stuff from search_opensearch.php source file... + t << search_opensearch_script; + } + // OPENSEARCH_PROVIDER } + + QCString fileName = Config_getString("HTML_OUTPUT")+"/search.php"; + QFile f(fileName); + if (f.open(IO_WriteOnly)) + { + FTextStream t(&f); + t << substituteHtmlKeywords(g_header,"Search",""); + + t << "" << endl; + //static bool generateTreeView = Config_getBool("GENERATE_TREEVIEW"); + static bool searchEngine = Config_getBool("SEARCHENGINE"); + if (searchEngine /* && !generateTreeView*/) + { + t << "\n"; + } + if (!Config_getBool("DISABLE_INDEX")) + { + writeDefaultQuickLinks(t,TRUE,HLI_Search,0,""); + } + else + { + //t << " \n
    \n"; + //t << "
    \n"; + t << "
    " << endl; + } + + t << "\n"; + + writeSearchInfo(t,""); + + // Write empty navigation path, to make footer connect properly + if (generateTreeView) + { + t << "
    \n"; + t << "
      \n"; + } + + writePageFooter(t,"Search",""); + } + QCString scriptName = Config_getString("HTML_OUTPUT")+"/search/search.js"; + QFile sf(scriptName); + if (sf.open(IO_WriteOnly)) + { + FTextStream t(&sf); + t << "function SearchBox(name, resultsPath, inFrame, label)\n"; + t << "{\n"; + t << " this.searchLabel = label;\n"; + t << " this.DOMSearchField = function()\n"; + t << " { return document.getElementById(\"MSearchField\"); }\n"; + t << " this.DOMSearchBox = function()\n"; + t << " { return document.getElementById(\"MSearchBox\"); }\n"; + t << " this.OnSearchFieldFocus = function(isActive)\n"; + t << " {\n"; + t << " if (isActive)\n"; + t << " {\n"; + t << " this.DOMSearchBox().className = 'MSearchBoxActive';\n"; + t << " var searchField = this.DOMSearchField();\n"; + t << " if (searchField.value == this.searchLabel) \n"; + t << " {\n"; + t << " searchField.value = '';\n"; + t << " }\n"; + t << " }\n"; + t << " else\n"; + t << " {\n"; + t << " this.DOMSearchBox().className = 'MSearchBoxInactive';\n"; + t << " this.DOMSearchField().value = this.searchLabel;\n"; + t << " }\n"; + t << " }\n"; + t << "}\n"; + } + else + { + err("Failed to open file '%s' for writing...\n",scriptName.data()); + } + +} + +void HtmlGenerator::startConstraintList(const char *header) +{ + t << "
      " << endl; + t << "
      " << header << "
      " << endl; + t << "" << endl; +} + +void HtmlGenerator::startConstraintParam() +{ + t << ""; +} + +void HtmlGenerator::startConstraintType() +{ + t << ""; +} + +void HtmlGenerator::startConstraintDocs() +{ + t << "" << endl; +} + +void HtmlGenerator::endConstraintList() +{ + t << "
      "; +} + +void HtmlGenerator::endConstraintParam() +{ + t << " :"; +} + +void HtmlGenerator::endConstraintType() +{ + t << " "; +} + +void HtmlGenerator::endConstraintDocs() +{ + t << "
      " << endl; + t << "
      " << endl; + t << "
      " << endl; +} + +void HtmlGenerator::lineBreak(const char *style) +{ + if (style) + { + t << "
      " << endl; + } + else + { + t << "
      " << endl; + } +} + +void HtmlGenerator::startHeaderSection() +{ + t << "
      " << endl; +} + +void HtmlGenerator::startTitleHead(const char *) +{ + t << "
      " << endl; + startTitle(); +} + +void HtmlGenerator::endTitleHead(const char *,const char *) +{ + endTitle(); + t << "
      " << endl; +} + +void HtmlGenerator::endHeaderSection() +{ + t << "
      " << endl; +} + +void HtmlGenerator::startInlineHeader() +{ + if (m_emptySection) + { + t << "" << endl; + m_emptySection=FALSE; + } + t << "" << endl; +} + +void HtmlGenerator::startMemberDocSimple() +{ + DBG_HTML(t << "" << endl;) + t << "

      "; +} + +void HtmlGenerator::endInlineHeader() +{ + t << "

      " << endl; + t << "" << endl; +} + +void HtmlGenerator::endMemberDocSimple() +{ + DBG_HTML(t << "" << endl;) + t << "
      " << theTranslator->trCompoundMembers() << "
      " << endl; +} + +void HtmlGenerator::startInlineMemberType() +{ + DBG_HTML(t << "" << endl;) + t << "" << endl; +} + +void HtmlGenerator::endInlineMemberType() +{ + DBG_HTML(t << "" << endl;) + t << "" << endl; +} + +void HtmlGenerator::startInlineMemberName() +{ + DBG_HTML(t << "" << endl;) + t << "" << endl; +} + +void HtmlGenerator::endInlineMemberName() +{ + DBG_HTML(t << "" << endl;) + t << "" << endl; +} + +void HtmlGenerator::startInlineMemberDoc() +{ + DBG_HTML(t << "" << endl;) + t << "" << endl; +} + +void HtmlGenerator::endInlineMemberDoc() +{ + DBG_HTML(t << "" << endl;) + t << "" << endl; +} + diff --git a/trunk/src/htmlgen.h b/trunk/src/htmlgen.h new file mode 100644 index 0000000..dbbdc11 --- /dev/null +++ b/trunk/src/htmlgen.h @@ -0,0 +1,290 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#ifndef HTMLGEN_H +#define HTMLGEN_H + +#include "qtbc.h" +#include "outputgen.h" + +#define PREFRAG_START "
      "
      +#define PREFRAG_END   "
      " + +class QFile; +class FTextStream; + +class HtmlGenerator : public OutputGenerator +{ + public: + HtmlGenerator(); + virtual ~HtmlGenerator(); + static void init(); + static void writeStyleSheetFile(QFile &f); + static void writeHeaderFile(QFile &f, const char *cssname); + static void writeFooterFile(QFile &f); + static void writeTabData(); + static void writeSearchInfo(FTextStream &t,const QCString &relPath); + static void writeSearchData(const char *dir); + static void writeSearchPage(); + static QCString writeLogoAsString(const char *path); + static QCString writeSplitBarAsString(const char *name,const char *relpath); + + void enable() + { if (genStack->top()) active=*genStack->top(); else active=TRUE; } + void disable() { active=FALSE; } + void enableIf(OutputType o) { if (o==Html) enable(); } + void disableIf(OutputType o) { if (o==Html) disable(); } + void disableIfNot(OutputType o) { if (o!=Html) disable(); } + bool isEnabled(OutputType o) { return (o==Html && active); } + OutputGenerator *get(OutputType o) { return (o==Html) ? this : 0; } + + void printDoc(DocNode *,const char *); + + void startFile(const char *name,const char *manName,const char *title); + void writeFooter(); + void endFile(); + void clearBuffer(); + void writeSearchInfo(); + + void startIndexSection(IndexSections) {} + void endIndexSection(IndexSections) {} + void writePageLink(const char *,bool) {} + void startProjectNumber(); + void endProjectNumber(); + void writeStyleInfo(int part); + void startTitleHead(const char *); + void endTitleHead(const char *,const char *); + void startTitle() { t << "
      "; } + void endTitle() { t << "
      "; } + + void startParagraph(); + void endParagraph(); + void writeString(const char *text); + void startIndexListItem(); + void endIndexListItem(); + void startIndexList(); + void endIndexList(); + void startIndexKey(); + void endIndexKey(); + void startIndexValue(bool); + void endIndexValue(const char *,bool); + void startItemList() { t << "
        " << endl; } + void endItemList() { t << "
      " << endl; } + void startIndexItem(const char *ref,const char *file); + void endIndexItem(const char *ref,const char *file); + void docify(const char *text); + void codify(const char *text); + void writeObjectLink(const char *ref,const char *file, + const char *anchor,const char *name); + void writeCodeLink(const char *ref,const char *file, + const char *anchor,const char *name, + const char *tooltip); + void startTextLink(const char *file,const char *anchor); + void endTextLink(); + void startHtmlLink(const char *url); + void endHtmlLink(); + void startTypewriter() { t << ""; } + void endTypewriter() { t << ""; } + void startGroupHeader(int); + void endGroupHeader(int); + void startItemListItem() { t << "
    • "; } + void endItemListItem() { t << "
    • \n"; } + + void startMemberSections(); + void endMemberSections(); + void startHeaderSection(); + void endHeaderSection(); + void startMemberHeader(const char *); + void endMemberHeader(); + void startMemberSubtitle(); + void endMemberSubtitle(); + void startMemberDocList(); + void endMemberDocList(); + void startMemberList(); + void endMemberList(); + void startInlineHeader(); + void endInlineHeader(); + void startAnonTypeScope(int) {} + void endAnonTypeScope(int) {} + void startMemberItem(const char *anchor,int); + void endMemberItem(); + void startMemberTemplateParams(); + void endMemberTemplateParams(const char *anchor); + + void startMemberGroupHeader(bool); + void endMemberGroupHeader(); + void startMemberGroupDocs(); + void endMemberGroupDocs(); + void startMemberGroup(); + void endMemberGroup(bool); + + void insertMemberAlign(bool); + void startMemberDescription(const char *anchor); + void endMemberDescription(); + + void writeRuler() { t << "
      "; } + void writeAnchor(const char *,const char *name) + { t << ""; } + void startCodeFragment() { t << PREFRAG_START; } + void endCodeFragment() { t << PREFRAG_END; } + void writeLineNumber(const char *,const char *,const char *,int); + void startCodeLine() { col=0; } + void endCodeLine() { codify("\n"); } + void startEmphasis() { t << ""; } + void endEmphasis() { t << ""; } + void startBold() { t << ""; } + void endBold() { t << ""; } + void startDescription() { t << endl << "
      " << endl; } + void endDescription() { t << endl << "
      \n" << endl; } + void startDescItem() { t << "
      "; } + void endDescItem() { t << "
      "; } + void startDescForItem() { t << "
      "; } + void endDescForItem() { t << "
      \n"; } + void lineBreak(const char *style); + void writeChar(char c); + void startMemberDoc(const char *,const char *,const char *,const char *,bool); + void endMemberDoc(bool); + void startDoxyAnchor(const char *fName,const char *manName, + const char *anchor,const char *name, + const char *args); + void endDoxyAnchor(const char *fName,const char *anchor); + void startCodeAnchor(const char *label) { t << ""; } + void endCodeAnchor() { } + void writeLatexSpacing() {} + void writeStartAnnoItem(const char *type,const char *file, + const char *path,const char *name); + void writeEndAnnoItem(const char *) { t << endl; } + void startSubsection() { t << "

      "; } + void endSubsection() { t << "

      " << endl; } + void startSubsubsection() { t << "

      "; } + void endSubsubsection() { t << "

      " << endl; } + void startCenter() { t << "
      " << endl; } + void endCenter() { t << "
      " << endl; } + void startSmall() { t << "" << endl; } + void endSmall() { t << "" << endl; } + //void startDescList(SectionTypes) { t << "
      " << endl; } + //void endDescList() { t << "
      "; } + void startSimpleSect(SectionTypes,const char *,const char *,const char *); + void endSimpleSect(); + void startParamList(ParamListTypes,const char *); + void endParamList(); + //void writeDescItem() { t << "
      " << endl; } + void startSection(const char *,const char *,SectionInfo::SectionType); + void endSection(const char *,SectionInfo::SectionType); + void addIndexItem(const char *,const char *); + void startIndent(); + void endIndent(); + void writeSynopsis() {} + void startClassDiagram(); + void endClassDiagram(const ClassDiagram &,const char *,const char *); + void startPageRef() {} + void endPageRef(const char *,const char *) {} + void startQuickIndices() {} + void endQuickIndices(); + void writeSplitBar(const char *name); + void writeLogo(); + void writeQuickLinks(bool compact,HighlightedItem hli,const char *file); + void startContents(); + void endContents(); + void writeNonBreakableSpace(int); + + void startDescTable() + { t << "" << endl; } + void endDescTable() + { t << "
      " << endl; } + void startDescTableTitle() + { t << ""; } + void endDescTableTitle() + { t << " "; } + void startDescTableData() + { t << "" << endl; } + void endDescTableData() + { t << "" << endl; } + + void startDotGraph(); + void endDotGraph(const DotClassGraph &g); + void startInclDepGraph(); + void endInclDepGraph(const DotInclDepGraph &g); + void startGroupCollaboration(); + void endGroupCollaboration(const DotGroupCollaboration &g); + void startCallGraph(); + void endCallGraph(const DotCallGraph &g); + void startDirDepGraph(); + void endDirDepGraph(const DotDirDeps &g); + void writeGraphicalHierarchy(const DotGfxHierarchyTable &g); + + void startTextBlock(bool) + { t << "
      "; } + void endTextBlock(bool) + { t << "
      "; } + void lastIndexPage() {} + + void startMemberDocPrefixItem(); + void endMemberDocPrefixItem(); + void startMemberDocName(bool); + void endMemberDocName(); + void startParameterType(bool first,const char *key); + void endParameterType(); + void startParameterName(bool); + void endParameterName(bool last,bool emptyList,bool closeBracket); + void startParameterList(bool); + void endParameterList(); + + void startConstraintList(const char *); + void startConstraintParam(); + void endConstraintParam(); + void startConstraintType(); + void endConstraintType(); + void startConstraintDocs(); + void endConstraintDocs(); + void endConstraintList(); + + void startMemberDocSimple(); + void endMemberDocSimple(); + void startInlineMemberType(); + void endInlineMemberType(); + void startInlineMemberName(); + void endInlineMemberName(); + void startInlineMemberDoc(); + void endInlineMemberDoc(); + + void startFontClass(const char *s) { t << ""; } + void endFontClass() { t << ""; } + + + void writeCodeAnchor(const char *anchor) + { t << ""; } + void linkableSymbol(int,const char *,Definition *,Definition *) {} + + //static void generateSectionImages(); + + private: + static void writePageFooter(FTextStream &t,const QCString &,const QCString &); + QCString lastTitle; + QCString lastFile; + QCString relPath; + void docify(const char *text,bool inHtmlComment); + + HtmlGenerator &operator=(const HtmlGenerator &g); + HtmlGenerator(const HtmlGenerator &g); + + int col; + int m_sectionCount; + bool m_emptySection; +}; + +#endif diff --git a/trunk/src/htmlhelp.cpp b/trunk/src/htmlhelp.cpp new file mode 100644 index 0000000..af06445 --- /dev/null +++ b/trunk/src/htmlhelp.cpp @@ -0,0 +1,708 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + * The original version of this file is largely based on a contribution from + * Harm van der Heijden. + */ + +#include +#include +#include +#include +#include +#include "qtextcodec.h" +#include "sortdict.h" + +#include "htmlhelp.h" +#include "config.h" +#include "message.h" +#include "doxygen.h" +#include "language.h" +#include "portable.h" + +//---------------------------------------------------------------------------- + +struct IndexField +{ + QCString name; + QCString url; + QCString anchor; + bool link; + bool reversed; +}; + +class IndexFieldSDict : public SDict +{ + public: + IndexFieldSDict() : SDict(17) {} + ~IndexFieldSDict() {} + int compareItems(GCI item1, GCI item2) + { + return stricmp(((IndexField *)item1)->name,((IndexField *)item2)->name); + } +}; + +/*! A helper class for HtmlHelp that manages a two level index in + * alphabetical order + */ +class HtmlHelpIndex +{ + public: + HtmlHelpIndex(HtmlHelp *help); + ~HtmlHelpIndex(); + void addItem(const char *first,const char *second, + const char *url, const char *anchor, + bool hasLink,bool reversed); + void writeFields(FTextStream &t); + private: + IndexFieldSDict *dict; + HtmlHelp *m_help; +}; + +/*! Constructs a new HtmlHelp index */ +HtmlHelpIndex::HtmlHelpIndex(HtmlHelp *help) : m_help(help) +{ + dict = new IndexFieldSDict; + dict->setAutoDelete(TRUE); +} + +/*! Destroys the HtmlHelp index */ +HtmlHelpIndex::~HtmlHelpIndex() +{ + delete dict; +} + +/*! Stores an item in the index if it is not already present. + * Items are stored in alphetical order, by sorting on the + * concatenation of \a level1 and \a level2 (if present). + * + * \param level1 the string at level 1 in the index. + * \param level2 the string at level 2 in the index (or 0 if not applicable). + * \param url the url of the documentation (without .html extension). + * \param anchor the anchor of the documentation within the page. + * \param hasLink if true, the url (without anchor) can be used in the + * level1 item, when writing the header of a list of level2 items. + * \param reversed TRUE if level1 is the member name and level2 the compound + * name. + */ +void HtmlHelpIndex::addItem(const char *level1,const char *level2, + const char *url,const char *anchor,bool hasLink, + bool reversed) +{ + QCString key = level1; + if (level2) key+= (QCString)"?" + level2; + if (key.find(QRegExp("@[0-9]+"))!=-1) // skip anonymous stuff + { + return; + } + if (dict->find(key)==0) // new key + { + //printf(">>>>>>>>> HtmlHelpIndex::addItem(%s,%s,%s,%s)\n", + // level1,level2,url,anchor); + IndexField *f = new IndexField; + f->name = key; + f->url = url; + f->anchor = anchor; + f->link = hasLink; + f->reversed = reversed; + dict->append(key,f); + } +} + +/*! Writes the sorted list of index items into a html like list. + * + * An list of calls with name = level1,level2 as follows: + *
      + *    a1,b1
      + *    a1,b2
      + *    a2,b1
      + *    a2,b2
      + *    a3
      + *    a4,b1
      + *  
      + * + * Will result in the following list: + * + *
      + *    a1       -> link to url if hasLink==TRUE
      + *      b1     -> link to url#anchor
      + *      b2     -> link to url#anchor
      + *    a2       -> link to url if hasLink==TRUE
      + *      b1     -> link to url#anchor
      + *      b2     -> link to url#anchor
      + *    a3       -> link to url if hasLink==TRUE
      + *    a4       -> link to url if hasLink==TRUE
      + *      b1     -> link to url#anchor 
      + *  
      + */ +void HtmlHelpIndex::writeFields(FTextStream &t) +{ + dict->sort(); + IndexFieldSDict::Iterator ifli(*dict); + IndexField *f; + QCString lastLevel1; + bool level2Started=FALSE; + for (;(f=ifli.current());++ifli) + { + QCString level1,level2; + int i; + if ((i=f->name.find('?'))!=-1) + { + level1 = f->name.left(i); + level2 = f->name.right(f->name.length()-i-1); + } + else + { + level1 = f->name.copy(); + } + + if (level1!=lastLevel1) + { // finish old list at level 2 + if (level2Started) t << "
    " << endl; + level2Started=FALSE; + + // + // Added this code so that an item with only one subitem is written + // without any subitem. + // For example: + // a1, b1 -> will create only a1, not separate subitem for b1 + // a2, b2 + // a2, b3 + QCString nextLevel1; + IndexField* fnext = ++ifli; + if (fnext) + { + nextLevel1 = fnext->name.left(fnext->name.find('?')); + --ifli; + } + if (level1 != nextLevel1) + { + level2 = ""; + } + // + + if (level2.isEmpty()) + { + t << "
  • "; + t << "url << Doxygen::htmlFileExtension; + if (!f->anchor.isEmpty() && f->reversed) t << "#" << f->anchor; + t << "\">"; + t << "recode(level1) << "\">" + "\n"; + } + else + { + if (f->link) + { + t << "
  • "; + t << "url << Doxygen::htmlFileExtension; + if (!f->anchor.isEmpty() && f->reversed) t << "#" << f->anchor; + t << "\">"; + t << "recode(level1) << "\">" + "\n"; + } + else + { + t << "
  • "; + t << "recode(level1) << "\">"; + t << "recode(level1) << "\">" + "\n"; + } + } + } + if (!level2Started && !level2.isEmpty()) + { // start new list at level 2 + t << "
      " << endl; + level2Started=TRUE; + } + else if (level2Started && level2.isEmpty()) + { // end list at level 2 + t << "
    " << endl; + level2Started=FALSE; + } + if (level2Started) + { + t << "
  • "; + t << "url << Doxygen::htmlFileExtension; + if (!f->anchor.isEmpty()) t << "#" << f->anchor; + t << "\">"; + t << "recode(level2) << "\">" + "\n"; + } + lastLevel1 = level1.copy(); + } + if (level2Started) t << " " << endl; +} + +//---------------------------------------------------------------------------- + +HtmlHelp *HtmlHelp::theInstance = 0; + +/*! Constructs an html object. + * The object has to be \link initialize() initialized\endlink before it can + * be used. + */ +HtmlHelp::HtmlHelp() : indexFileDict(1009) +{ + /* initial depth */ + dc = 0; + cf = kf = 0; + index = new HtmlHelpIndex(this); + m_fromUtf8 = (void *)(-1); +} + +HtmlHelp::~HtmlHelp() +{ + if (m_fromUtf8!=(void *)(-1)) portable_iconv_close(m_fromUtf8); +} +#if 0 +/*! return a reference to the one and only instance of this class. + */ +HtmlHelp *HtmlHelp::getInstance() +{ + if (theInstance==0) theInstance = new HtmlHelp; + return theInstance; +} +#endif + +static QDict s_languageDict; + +/*! This will create a contents file (index.hhc) and a index file (index.hhk) + * and write the header of those files. + * It also creates a project file (index.hhp) + * \sa finalize() + */ +void HtmlHelp::initialize() +{ + const char *str = Config_getString("CHM_INDEX_ENCODING"); + if (!str) str = "CP1250"; // use safe and likely default + m_fromUtf8 = portable_iconv_open(str,"UTF-8"); + if (m_fromUtf8==(void *)(-1)) + { + err("Error: unsupported character conversion for CHM_INDEX_ENCODING: '%s'->'UTF-8'\n", str); + exit(1); + } + + /* open the contents file */ + QCString fName = Config_getString("HTML_OUTPUT") + "/index.hhc"; + cf = new QFile(fName); + if (!cf->open(IO_WriteOnly)) + { + err("Could not open file %s for writing\n",fName.data()); + exit(1); + } + /* Write the header of the contents file */ + cts.setDevice(cf); + cts << "\n" + "\n" + "\n" + "\n" + "\n" + "
      \n"; + + /* open the contents file */ + fName = Config_getString("HTML_OUTPUT") + "/index.hhk"; + kf = new QFile(fName); + if (!kf->open(IO_WriteOnly)) + { + err("Could not open file %s for writing\n",fName.data()); + exit(1); + } + /* Write the header of the contents file */ + kts.setDevice(kf); + kts << "\n" + "\n" + "\n" + "\n" + "\n" + "
        \n"; + + /* language codes for Html help + 0x405 Czech + 0x406 Danish + 0x413 Dutch + 0xC09 English (Australia) + 0x809 English (Britain) + 0x1009 English (Canada) + 0x1809 English (Ireland) + 0x1409 English (New Zealand) + 0x1C09 English (South Africa) + 0x409 English (United States) + 0x40B Finnish + 0x40C French + 0x407 German + 0x408 Greece + 0x40E Hungarian + 0x410 Italian + 0x814 Norwegian + 0x415 Polish + 0x816 Portuguese(Portugal) + 0x416 Portuguese(Brazil) + 0x419 Russian + 0x80A Spanish(Mexico) + 0xC0A Spanish(Modern Sort) + 0x40A Spanish(Traditional Sort) + 0x41D Swedish + 0x41F Turkey + 0x411 Japanese + 0x412 Korean + 0x804 Chinese (PRC) + 0x404 Chinese (Taiwan) + + New LCIDs: + 0x421 Indonesian + 0x41A Croatian + 0x418 Romanian + 0x424 Slovenian + 0x41B Slovak + 0x422 Ukrainian + 0x81A Serbian (Serbia, Latin) + 0x403 Catalan + 0x427 Lithuanian + 0x436 Afrikaans + 0x42A Vietnamese + 0x429 Persian (Iran) + 0xC01 Arabic (Egypt) - I don't know which version of arabic is used inside translator_ar.h , + so I have chosen Egypt at random + + */ + s_languageDict.setAutoDelete(TRUE); + s_languageDict.clear(); + s_languageDict.insert("czech", new QCString("0x405 Czech")); + s_languageDict.insert("danish", new QCString("0x406 Danish")); + s_languageDict.insert("dutch", new QCString("0x413 Dutch")); + s_languageDict.insert("finnish", new QCString("0x40B Finnish")); + s_languageDict.insert("french", new QCString("0x40C French")); + s_languageDict.insert("german", new QCString("0x407 German")); + s_languageDict.insert("greek", new QCString("0x408 Greece")); + s_languageDict.insert("hungarian", new QCString("0x40E Hungarian")); + s_languageDict.insert("italian", new QCString("0x410 Italian")); + s_languageDict.insert("norwegian", new QCString("0x814 Norwegian")); + s_languageDict.insert("polish", new QCString("0x415 Polish")); + s_languageDict.insert("portuguese", new QCString("0x816 Portuguese(Portugal)")); + s_languageDict.insert("brazil", new QCString("0x416 Portuguese(Brazil)")); + s_languageDict.insert("russian", new QCString("0x419 Russian")); + s_languageDict.insert("spanish", new QCString("0x40A Spanish(Traditional Sort)")); + s_languageDict.insert("swedish", new QCString("0x41D Swedish")); + s_languageDict.insert("turkish", new QCString("0x41F Turkey")); + s_languageDict.insert("japanese", new QCString("0x411 Japanese")); + s_languageDict.insert("japanese-en", new QCString("0x411 Japanese")); + s_languageDict.insert("korean", new QCString("0x412 Korean")); + s_languageDict.insert("korean-en", new QCString("0x412 Korean")); + s_languageDict.insert("chinese", new QCString("0x804 Chinese (PRC)")); + s_languageDict.insert("chinese-traditional", new QCString("0x404 Chinese (Taiwan)")); + + // new LCIDs + s_languageDict.insert("indonesian", new QCString("0x412 Indonesian")); + s_languageDict.insert("croatian", new QCString("0x41A Croatian")); + s_languageDict.insert("romanian", new QCString("0x418 Romanian")); + s_languageDict.insert("slovene", new QCString("0x424 Slovenian")); + s_languageDict.insert("slovak", new QCString("0x41B Slovak")); + s_languageDict.insert("ukrainian", new QCString("0x422 Ukrainian")); + s_languageDict.insert("serbian", new QCString("0x81A Serbian (Serbia, Latin)")); + s_languageDict.insert("catalan", new QCString("0x403 Catalan")); + s_languageDict.insert("lithuanian", new QCString("0x427 Lithuanian")); + s_languageDict.insert("afrikaans", new QCString("0x436 Afrikaans")); + s_languageDict.insert("vietnamese", new QCString("0x42A Vietnamese")); + s_languageDict.insert("persian", new QCString("0x429 Persian (Iran)")); + s_languageDict.insert("arabic", new QCString("0xC01 Arabic (Egypt)")); +} + + +static QCString getLanguageString() +{ + if (!theTranslator->idLanguage().isEmpty()) + { + QCString *s = s_languageDict[theTranslator->idLanguage()]; + if (s) + { + return *s; + } + } + // default language + return "0x409 English (United States)"; +} + + + +void HtmlHelp::createProjectFile() +{ + /* Write the project file */ + QCString fName = Config_getString("HTML_OUTPUT") + "/index.hhp"; + QFile f(fName); + if (f.open(IO_WriteOnly)) + { + FTextStream t(&f); + + QCString indexName="index"+Doxygen::htmlFileExtension; + //if (Config_getBool("GENERATE_TREEVIEW")) indexName="main"+Doxygen::htmlFileExtension; + t << "[OPTIONS]\n"; + if (!Config_getString("CHM_FILE").isEmpty()) + { + t << "Compiled file=" << Config_getString("CHM_FILE") << "\n"; + } + t << "Compatibility=1.1\n" + "Full-text search=Yes\n" + "Contents file=index.hhc\n" + "Default Window=main\n" + "Default topic=" << indexName << "\n" + "Index file=index.hhk\n" + "Language=" << getLanguageString() << endl; + if (Config_getBool("BINARY_TOC")) t << "Binary TOC=YES\n"; + if (Config_getBool("GENERATE_CHI")) t << "Create CHI file=YES\n"; + t << "Title=" << recode(Config_getString("PROJECT_NAME")) << endl << endl; + + t << "[WINDOWS]" << endl; + + // NOTE: the 0x10387e number is a set of bits specifying the buttons + // which should appear in the CHM viewer; that specific value + // means "show all buttons including the font-size one"; + // the font-size one is not normally settable by the HTML Help Workshop + // utility but the way to set it is described here: + // http://support.microsoft.com/?scid=kb%3Ben-us%3B240062&x=17&y=18 + t << "main=\"" << recode(Config_getString("PROJECT_NAME")) << "\",\"index.hhc\"," + "\"index.hhk\",\"" << indexName << "\",\"" << + indexName << "\",,,,,0x23520,,0x10387e,,,,,,,,0" << endl << endl; + + t << "[FILES]" << endl; + char *s = indexFiles.first(); + while (s) + { + t << s << endl; + s = indexFiles.next(); + } +#if 0 + // items not found by the html help compiler scan. + t << "tabs.css" << endl; + t << "tab_a.png" << endl; + t << "tab_b.png" << endl; + t << "tab_h.png" << endl; + t << "tab_s.png" << endl; + t << "nav_h.png" << endl; + t << "nav_f.png" << endl; + t << "bc_s.png" << endl; + if (Config_getBool("HTML_DYNAMIC_SECTIONS")) + { + t << "open.png" << endl; + t << "closed.png" << endl; + } + if (Config_getBool("GENERATE_HTMLHELP")) + { + t << "ftv2blank.png" << endl; + t << "ftv2doc.png" << endl; + t << "ftv2folderclosed.png" << endl; + t << "ftv2folderopen.png" << endl; + t << "ftv2lastnode.png" << endl; + t << "ftv2link.png" << endl; + t << "ftv2mlastnode.png" << endl; + t << "ftv2mnode.png" << endl; + t << "ftv2node.png" << endl; + t << "ftv2plastnode.png" << endl; + t << "ftv2pnode.png" << endl; + t << "ftv2vertline.png" << endl; + } + if (Config_getBool("SEARCHENGINE")) + { + t << "search_l.png" << endl; + t << "search_m.png" << endl; + t << "search_r.png" << endl; + if (Config_getBool("SERVER_BASED_SEARCH")) + { + t << "mag.png" << endl; + } + else + { + t << "mag_sel.png" << endl; + t << "close.png" << endl; + } + } +#endif + uint i; + for (i=0;i\n"; + cts << "\n"; + cts << "\n"; + cts.unsetDevice(); + cf->close(); + delete cf; + + index->writeFields(kts); + + // end the index file + kts << "
      \n"; + kts << "\n"; + kts << "\n"; + kts.unsetDevice(); + kf->close(); + delete kf; + + createProjectFile(); + s_languageDict.clear(); +} + +/*! Increase the level of the contents hierarchy. + * This will start a new unnumbered HTML list in contents file. + * \sa decContentsDepth() + */ +void HtmlHelp::incContentsDepth() +{ + int i; for (i=0;i\n"; + ++dc; +} + +/*! Decrease the level of the contents hierarchy. + * This will end the unnumber HTML list. + * \sa incContentsDepth() + */ +void HtmlHelp::decContentsDepth() +{ + int i; for (i=0;i\n"; + --dc; +} + +QCString HtmlHelp::recode(const QCString &s) +{ + int iSize = s.length(); + int oSize = iSize*4+1; + QCString output(oSize); + size_t iLeft = iSize; + size_t oLeft = oSize; + const char *iPtr = s.data(); + char *oPtr = output.data(); + if (!portable_iconv(m_fromUtf8,&iPtr,&iLeft,&oPtr,&oLeft)) + { + oSize -= oLeft; + output.resize(oSize+1); + output.at(oSize)='\0'; + return output; + } + else + { + return s; + } +} + +/*! Add an list item to the contents file. + * \param isDir boolean indicating if this is a dir or file entry + * \param name the name of the item. + * \param ref the URL of to the item. + * \param file the file in which the item is defined. + * \param anchor the anchor of the item. + * \param separateIndex not used. + * \param addToNavIndex not used. + */ +void HtmlHelp::addContentsItem(bool isDir, + const char *name, + const char * /*ref*/, + const char *file, + const char *anchor, + bool /* separateIndex */, + bool /* addToNavIndex */) +{ + // If we're using a binary toc then folders cannot have links. + if(Config_getBool("BINARY_TOC") && isDir) + { + file = 0; + anchor = 0; + } + int i; for (i=0;i"; + cts << ""; + if (file) // made file optional param - KPW + { + cts << ""; + } + cts << ""; + cts << "\n"; +} + + +void HtmlHelp::addIndexItem(Definition *context,MemberDef *md, + const char *word) +{ + if (md) + { + static bool separateMemberPages = Config_getBool("SEPARATE_MEMBER_PAGES"); + if (context==0) // global member + { + if (md->getGroupDef()) + context = md->getGroupDef(); + else if (md->getFileDef()) + context = md->getFileDef(); + } + if (context==0) return; // should not happen + + QCString cfname = md->getOutputFileBase(); + QCString cfiname = context->getOutputFileBase(); + QCString level1 = context->name(); + QCString level2 = md->name(); + QCString contRef = separateMemberPages ? cfname : cfiname; + QCString memRef = cfname; + QCString anchor = md->anchor(); + index->addItem(level1,level2,contRef,anchor,TRUE,FALSE); + index->addItem(level2,level1,memRef,anchor,TRUE,TRUE); + } + else if (context) + { + QCString level1 = word ? QCString(word) : context->name(); + index->addItem(level1,0,context->getOutputFileBase(),0,TRUE,FALSE); + } +} + +void HtmlHelp::addImageFile(const char *fileName) +{ + imageFiles.append(fileName); +} + diff --git a/trunk/src/htmlhelp.h b/trunk/src/htmlhelp.h new file mode 100644 index 0000000..ef5fb67 --- /dev/null +++ b/trunk/src/htmlhelp.h @@ -0,0 +1,104 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + * The code is this file is largely based on a contribution from + * Harm van der Heijden + * Please send thanks to him and bug reports to me :-) + */ + +#ifndef HTMLHELP_H +#define HTMLHELP_H + +#include "qtbc.h" +#include +#include "index.h" +#include "ftextstream.h" + +class QFile; +class HtmlHelpIndex; + +/*! A class that generated the HTML Help specific files. + * These files can be used with the Microsoft HTML Help workshop + * to generate compressed HTML files (.chm). + */ +class HtmlHelp : public IndexIntf +{ + /*! used in imageNumber param of HTMLHelp::addContentsItem() function + to specify document icon in tree view. + Writes \ in .HHC file. */ + enum ImageNumber { + BOOK_CLOSED=1, BOOK_OPEN, + BOOK_CLOSED_NEW, BOOK_OPEN_NEW, + FOLDER_CLOSED, FOLDER_OPEN, + FOLDER_CLOSED_NEW,FOLDER_OPEN_NEW, + QUERY, QUERY_NEW, + TEXT, TEXT_NEW, + WEB_DOC, WEB_DOC_NEW, + WEB_LINK, WEB_LINK_NEW, + INFO, INFO_NEW, + LINK, LINK_NEW, + BOOKLET, BOOKLET_NEW, + EMAIL, EMAIL_NEW, + EMAIL2, EMAIL2_NEW, + IMAGE, IMAGE_NEW, + AUDIO, AUDIO_NEW, + MUSIC, MUSIC_NEW, + VIDEO, VIDEO_NEW, + INDEX, INDEX_NEW, + IDEA, IDEA_NEW, + NOTE, NOTE_NEW, + TOOL, TOOL_NEW + }; + public: + //static HtmlHelp *getInstance(); + HtmlHelp(); + ~HtmlHelp(); + void initialize(); + void finalize(); + void incContentsDepth(); + void decContentsDepth(); + void addContentsItem(bool isDir, + const char *name, + const char *ref, + const char *file, + const char *anchor, + bool separateIndex, + bool addToNavIndex); + //void addIndexItem(const char *level1, const char *level2, + // const char *contRef, const char *memRef, + // const char *anchor,const MemberDef *md); + void addIndexItem(Definition *context,MemberDef *md,const char *title); + void addIndexFile(const char *name); + void addImageFile(const char *); + void addStyleSheetFile(const char *) {} + + private: + friend class HtmlHelpIndex; + void createProjectFile(); + + QFile *cf,*kf; + FTextStream cts,kts; + HtmlHelpIndex *index; + int dc; + QStrList indexFiles; + QStrList imageFiles; + QDict indexFileDict; + static HtmlHelp *theInstance; + QCString recode(const QCString &s); + void *m_fromUtf8; +}; + +#endif /* HTMLHELP_H */ + diff --git a/trunk/src/image.cpp b/trunk/src/image.cpp new file mode 100644 index 0000000..20fa868 --- /dev/null +++ b/trunk/src/image.cpp @@ -0,0 +1,540 @@ +/****************************************************************************** + * + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#include "qtbc.h" +#include "image.h" +#include +#include +#include "lodepng.h" +#include "config.h" + +typedef unsigned char Byte; + +struct Color +{ + Byte red; + Byte green; + Byte blue; + Byte alpha; +}; + +const int charSetWidth=80; +const int charHeight=12; +const int numChars=96; + +unsigned short charPos[numChars] = + { + 0, 5, 8, 13, 20, 27, 38, 47, + 50, 54, 58, 65, 72, 76, 83, 87, + 91, 98,105,112,119,126,133,140, + 147,154,161,164,167,174,181,188, + 195,207,216,224,233,242,250,258, + 267,276,279,286,294,301,312,321, + 331,339,349,357,365,372,380,389, + 400,409,418,427,430,434,437,443, + 450,453,460,467,474,481,488,492, + 499,506,509,512,518,521,530,537, + 544,551,557,562,568,571,578,585, + 594,600,607,613,617,620,624,631 + }; + +unsigned char charWidth[numChars] = + { + 5, 3, 5, 7, 7,11, 9, 3, + 4, 4, 7, 7, 4, 7, 4, 4, + + 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 3, 3, 7, 7, 7, 7, + 12, 9, 8, 9, 9, 8, 8, 9, + 9, 3, 7, 8, 7,11, 9,10, + 8,10, 8, 8, 7, 8, 9,11, + 9, 9, 9, 3, 4, 3, 6, 7, + 3, 7, 7, 7, 7, 7, 4, 7, + 7, 3, 3, 6, 3, 9, 7, 7, + 7, 6, 5, 6, 3, 7, 7, 9, + 6, 7, 6, 4, 3, 4, 7, 5 + }; + +unsigned char fontRaw[charSetWidth*charHeight] = { + 0x02, 0x50, 0x01, 0x06, 0x20, 0x60, 0xc6, 0x04, 0x00, 0x00, 0x00, 0x27, + 0x04, 0x1c, 0x38, 0x11, 0xf1, 0xc7, 0xc7, 0x0e, 0x00, 0x00, 0x00, 0x03, + 0x81, 0xf0, 0x10, 0x7c, 0x1e, 0x3e, 0x1f, 0x9f, 0x87, 0x88, 0x24, 0x09, + 0x09, 0x02, 0x02, 0x41, 0x0f, 0x0f, 0x83, 0xc3, 0xe1, 0xe7, 0xf4, 0x24, + 0x12, 0x22, 0x41, 0x20, 0x9f, 0xce, 0x30, 0x00, 0x10, 0x04, 0x00, 0x01, + 0x00, 0x30, 0x08, 0x12, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, + 0x00, 0x00, 0x00, 0x00, 0x01, 0xac, 0x00, 0x00, 0x02, 0x51, 0x43, 0x89, + 0x40, 0x90, 0x49, 0x15, 0x00, 0x00, 0x00, 0x28, 0x9c, 0x22, 0x44, 0x31, + 0x02, 0x20, 0x48, 0x91, 0x00, 0x00, 0x00, 0x04, 0x46, 0x08, 0x28, 0x42, + 0x21, 0x21, 0x10, 0x10, 0x08, 0x48, 0x24, 0x09, 0x11, 0x03, 0x06, 0x61, + 0x10, 0x88, 0x44, 0x22, 0x12, 0x10, 0x84, 0x24, 0x12, 0x22, 0x22, 0x20, + 0x80, 0x4a, 0x11, 0x00, 0x20, 0x04, 0x00, 0x01, 0x00, 0x40, 0x08, 0x00, + 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x22, 0x00, 0x00, 0x02, 0x51, 0x45, 0x49, 0x40, 0x90, 0x89, 0x0a, + 0x00, 0x00, 0x00, 0x48, 0x84, 0x02, 0x04, 0x51, 0x02, 0x00, 0x88, 0x91, + 0x00, 0x00, 0x00, 0x04, 0x44, 0xd4, 0x28, 0x42, 0x40, 0x20, 0x90, 0x10, + 0x10, 0x08, 0x24, 0x09, 0x21, 0x03, 0x06, 0x51, 0x20, 0x48, 0x48, 0x12, + 0x12, 0x00, 0x84, 0x22, 0x22, 0x22, 0x22, 0x11, 0x00, 0x89, 0x12, 0x80, + 0x31, 0xc5, 0x87, 0x0d, 0x1c, 0xe3, 0x4b, 0x12, 0x49, 0x29, 0x16, 0x1c, + 0x58, 0x69, 0x4c, 0xe8, 0x91, 0x44, 0x61, 0x44, 0xf2, 0x22, 0x00, 0x00, + 0x02, 0x07, 0xe5, 0x06, 0x80, 0x60, 0x10, 0x95, 0x08, 0x00, 0x00, 0x48, + 0x84, 0x04, 0x18, 0x51, 0xe2, 0xc0, 0x87, 0x11, 0x24, 0x18, 0x03, 0x00, + 0x89, 0x24, 0x44, 0x42, 0x40, 0x20, 0x90, 0x10, 0x10, 0x08, 0x24, 0x09, + 0x41, 0x02, 0x8a, 0x51, 0x20, 0x48, 0x48, 0x12, 0x11, 0x80, 0x84, 0x22, + 0x21, 0x24, 0x14, 0x11, 0x01, 0x09, 0x14, 0x40, 0x02, 0x26, 0x48, 0x93, + 0x22, 0x44, 0xcc, 0x92, 0x51, 0x36, 0x99, 0x22, 0x64, 0x99, 0x92, 0x48, + 0x91, 0x44, 0x52, 0x44, 0x12, 0x22, 0x00, 0x00, 0x02, 0x01, 0x43, 0x80, + 0x80, 0xa0, 0x10, 0x84, 0x08, 0x00, 0x00, 0x88, 0x84, 0x08, 0x04, 0x90, + 0x13, 0x21, 0x08, 0x8f, 0x00, 0x61, 0xf0, 0xc0, 0x8a, 0x24, 0x44, 0x7c, + 0x40, 0x20, 0x9f, 0x9f, 0x11, 0xcf, 0xe4, 0x09, 0xc1, 0x02, 0x8a, 0x49, + 0x20, 0x4f, 0x88, 0x13, 0xe0, 0x60, 0x84, 0x22, 0x21, 0x54, 0x08, 0x0a, + 0x02, 0x08, 0x90, 0x00, 0x00, 0x24, 0x48, 0x11, 0x22, 0x44, 0x48, 0x92, + 0x61, 0x24, 0x91, 0x22, 0x44, 0x89, 0x10, 0x48, 0x91, 0x24, 0x8c, 0x44, + 0x22, 0x22, 0x64, 0x00, 0x02, 0x07, 0xe1, 0x41, 0x31, 0x14, 0x10, 0x80, + 0x3e, 0x07, 0xc0, 0x88, 0x84, 0x10, 0x05, 0x10, 0x12, 0x21, 0x08, 0x81, + 0x01, 0x80, 0x00, 0x31, 0x0a, 0x24, 0x7c, 0x42, 0x40, 0x20, 0x90, 0x10, + 0x10, 0x48, 0x24, 0x09, 0x21, 0x02, 0x52, 0x45, 0x20, 0x48, 0x08, 0x92, + 0x20, 0x10, 0x84, 0x21, 0x41, 0x54, 0x14, 0x04, 0x04, 0x08, 0x90, 0x00, + 0x01, 0xe4, 0x48, 0x11, 0x3e, 0x44, 0x48, 0x92, 0x61, 0x24, 0x91, 0x22, + 0x44, 0x89, 0x0c, 0x48, 0x8a, 0x24, 0x8c, 0x48, 0x44, 0x21, 0x98, 0x00, + 0x02, 0x02, 0x85, 0x41, 0x49, 0x08, 0x10, 0x80, 0x08, 0x00, 0x00, 0x88, + 0x84, 0x20, 0x45, 0xf9, 0x12, 0x21, 0x08, 0x81, 0x00, 0x61, 0xf0, 0xc1, + 0x0a, 0x68, 0x82, 0x42, 0x40, 0x20, 0x90, 0x10, 0x10, 0x48, 0x24, 0x89, + 0x11, 0x02, 0x52, 0x45, 0x20, 0x48, 0x08, 0x52, 0x12, 0x10, 0x84, 0x21, + 0x40, 0x88, 0x22, 0x04, 0x08, 0x08, 0x90, 0x00, 0x02, 0x24, 0x48, 0x11, + 0x20, 0x44, 0x48, 0x92, 0x51, 0x24, 0x91, 0x22, 0x44, 0x89, 0x02, 0x48, + 0x8a, 0x2a, 0x92, 0x28, 0x42, 0x22, 0x00, 0x00, 0x00, 0x02, 0x85, 0x41, + 0x49, 0x18, 0x10, 0x80, 0x08, 0x00, 0x01, 0x08, 0x84, 0x20, 0x44, 0x11, + 0x12, 0x22, 0x08, 0x91, 0x00, 0x18, 0x03, 0x00, 0x09, 0xb0, 0x82, 0x42, + 0x21, 0x21, 0x10, 0x10, 0x08, 0xc8, 0x24, 0x89, 0x09, 0x02, 0x22, 0x43, + 0x10, 0x88, 0x04, 0x22, 0x12, 0x10, 0x84, 0x20, 0x80, 0x88, 0x22, 0x04, + 0x10, 0x08, 0x50, 0x00, 0x02, 0x26, 0x48, 0x93, 0x22, 0x44, 0xc8, 0x92, + 0x49, 0x24, 0x91, 0x22, 0x64, 0x99, 0x12, 0x49, 0x84, 0x11, 0x21, 0x28, + 0x82, 0x22, 0x00, 0x00, 0x02, 0x02, 0x83, 0x82, 0x30, 0xe4, 0x10, 0x80, + 0x00, 0x20, 0x05, 0x07, 0x04, 0x3e, 0x38, 0x10, 0xe1, 0xc2, 0x07, 0x0e, + 0x24, 0x00, 0x00, 0x01, 0x04, 0x00, 0x82, 0x7c, 0x1e, 0x3e, 0x1f, 0x90, + 0x07, 0x48, 0x24, 0x71, 0x05, 0xf2, 0x22, 0x41, 0x0f, 0x08, 0x03, 0xd2, + 0x11, 0xe0, 0x83, 0xc0, 0x80, 0x88, 0x41, 0x04, 0x1f, 0xc8, 0x50, 0x00, + 0x01, 0xd5, 0x87, 0x0d, 0x1c, 0x43, 0x48, 0x92, 0x45, 0x24, 0x91, 0x1c, + 0x58, 0x69, 0x0c, 0x66, 0x84, 0x11, 0x21, 0x10, 0xf2, 0x22, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x03, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x00, 0x00, 0x40, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x02, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x09, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x08, 0x10, 0x1f, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x04, 0x40, 0x02, + 0x00, 0x00, 0x00, 0x00, 0x40, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, + 0x02, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x30, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0xac, 0x00, 0x00 +}; + +static Color palette[] = +{ + { 0xff, 0xff, 0xff, 0x00 }, + { 0x00, 0x00, 0x00, 0xff }, + { 0xff, 0xff, 0xc0, 0xff }, + { 0x9f, 0x9f, 0x60, 0xff }, + { 0x90, 0x00, 0x00, 0xff }, + { 0x00, 0x90, 0x00, 0xff }, + { 0x00, 0x00, 0x90, 0xff }, + { 0xc0, 0xc0, 0xc0, 0xff } +}; + +// for alpha we use x^(1/1.3) +static Color palette2[] = +{ + { 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x2e }, + { 0x00, 0x00, 0x00, 0x48 }, + { 0x00, 0x00, 0x00, 0x5d }, + { 0x00, 0x00, 0x00, 0x6f }, + { 0x00, 0x00, 0x00, 0x80 }, + { 0x00, 0x00, 0x00, 0x8f }, + { 0x00, 0x00, 0x00, 0x9e }, + { 0x00, 0x00, 0x00, 0xac }, + { 0x00, 0x00, 0x00, 0xb9 }, + { 0x00, 0x00, 0x00, 0xc5 }, + { 0x00, 0x00, 0x00, 0xd2 }, + { 0x00, 0x00, 0x00, 0xdd }, + { 0x00, 0x00, 0x00, 0xe9 }, + { 0x00, 0x00, 0x00, 0xf4 }, + { 0x00, 0x00, 0x00, 0xff } +}; + +static Color palette3[] = +{ + { 0xff, 0xff, 0xff, 0xff }, + { 0xe0, 0xe0, 0xe0, 0xff }, + { 0xd0, 0xd0, 0xd0, 0xff }, + { 0xc0, 0xc0, 0xc0, 0xff }, + { 0xb0, 0xb0, 0xb0, 0xff }, + { 0xa0, 0xa0, 0xa0, 0xff }, + { 0x90, 0x90, 0x90, 0xff }, + { 0x80, 0x80, 0x80, 0xff }, + { 0x70, 0x70, 0x70, 0xff }, + { 0x60, 0x60, 0x60, 0xff }, + { 0x50, 0x50, 0x50, 0xff }, + { 0x40, 0x40, 0x40, 0xff }, + { 0x30, 0x30, 0x30, 0xff }, + { 0x20, 0x20, 0x20, 0xff }, + { 0x10, 0x10, 0x10, 0xff }, + { 0x00, 0x00, 0x00, 0xff } +}; + + +Image::Image(int w,int h) +{ + static int hue = Config_getInt("HTML_COLORSTYLE_HUE"); + static int sat = Config_getInt("HTML_COLORSTYLE_SAT"); + static int gamma = Config_getInt("HTML_COLORSTYLE_GAMMA"); + + double red1,green1,blue1; + double red2,green2,blue2; + + ColoredImage::hsl2rgb(hue/360.0, // hue + sat/255.0, // saturation + pow(235/255.0,gamma/100.0), // luma (gamma corrected) + &red1,&green1,&blue1 + ); + + ColoredImage::hsl2rgb(hue/360.0, // hue + sat/255.0, // saturation + pow(138/255.0,gamma/100.0), // luma (gamma corrected) + &red2,&green2,&blue2 + ); + + palette[2].red = (int)(red1 * 255.0); + palette[2].green = (int)(green1 * 255.0); + palette[2].blue = (int)(blue1 * 255.0); + + palette[3].red = (int)(red2 * 255.0); + palette[3].green = (int)(green2 * 255.0); + palette[3].blue = (int)(blue2 * 255.0); + + data = new uchar[w*h]; + memset(data,0,w*h); + width = w; + height = h; +} + +Image::~Image() +{ + delete[] data; +} + +void Image::setPixel(int x,int y,uchar val) +{ + if (x>=0 && x=0 && y=0 && x=0 && y=' ') + { + int xf,yf,ci=c-' '; + int rowOffset=0; + int cw = charWidth[ci]; + int cp = charPos[ci]; + for (yf=0;yf>3); + int bitOffset = cp&7; + // get the bit pattern for row yf of the character from the font data + while (bitsLeft>0) + { + int bits=8-bitOffset; + if (bits>bitsLeft) bits=bitsLeft; + bitPattern<<=bits; + bitPattern|=((fontRaw[byteOffset]<>(8-bits); + bitsLeft-=bits; + bitOffset=0; + byteOffset++; + } + int mask=1<<(cw-1); + // draw character row yf + for (xf=0;xf>=1; + } + rowOffset+=charSetWidth; + } + } +} + +void Image::writeString(int x,int y,const char *s,uchar fg) +{ + if (s) + { + char c; + while ((c=*s++)) + { + writeChar(x,y,c,fg); + x+=charWidth[c-' ']; + } + } +} + +uint Image::stringLength(const char *s) +{ + int w=0; + if (s) + { + char c; + while ((c=*s++)) w+=charWidth[c-' ']; + } + return w; +} + +void Image::drawHorzLine(int y,int xs,int xe,uchar colIndex,uint mask) +{ + int x,i=0,j=0; + for (x=xs;x<=xe;x++,j++) + { + if (j&1) i++; + if (mask&(1<<(i&0x1f))) setPixel(x,y,colIndex); + } +} + +void Image::drawHorzArrow(int y,int xs,int xe,uchar colIndex,uint mask) +{ + drawHorzLine(y,xs,xe,colIndex,mask); + int i; + for (i=0;i<6;i++) + { + int h=i>>1; + drawVertLine(xe-i,y-h,y+h,colIndex,0xffffffff); + } +} + +void Image::drawVertLine(int x,int ys,int ye,uchar colIndex,uint mask) +{ + int y,i=0; + for (y=ys;y<=ye;y++,i++) + { + if (mask&(1<<(i&0x1f))) setPixel(x,y,colIndex); + } +} + +void Image::drawVertArrow(int x,int ys,int ye,uchar colIndex,uint mask) +{ + drawVertLine(x,ys,ye,colIndex,mask); + int i; + for (i=0;i<6;i++) + { + int h=i>>1; + drawHorzLine(ys+i,x-h,x+h,colIndex,0xffffffff); + } +} + +void Image::drawRect(int x,int y,int w,int h,uchar colIndex,uint mask) +{ + drawHorzLine(y,x,x+w-1,colIndex,mask); + drawHorzLine(y+h-1,x,x+w-1,colIndex,mask); + drawVertLine(x,y,y+h-1,colIndex,mask); + drawVertLine(x+w-1,y,y+h-1,colIndex,mask); +} + +void Image::fillRect(int x,int y,int lwidth,int lheight,uchar colIndex,uint mask) +{ + int xp,yp,xi,yi; + for (yp=y,yi=0;ypred,pPal->green,pPal->blue,pPal->alpha); + } + encoder.infoPng.color.colorType = 3; + encoder.infoRaw.color.colorType = 3; + LodePNG_encode(&encoder, &buffer, &bufferSize, data, width, height); + LodePNG_saveFile(buffer, bufferSize, fileName); + free(buffer); + LodePNG_Encoder_cleanup(&encoder); + return TRUE; +} + +//---------------------------------------------------------------- + +void ColoredImage::hsl2rgb(double h,double s,double l, + double *pRed,double *pGreen,double *pBlue) +{ + double v; + double r,g,b; + + r = l; // default to gray + g = l; + b = l; + v = (l <= 0.5) ? (l * (1.0 + s)) : (l + s - l * s); + if (v > 0) + { + double m; + double sv; + int sextant; + double fract, vsf, mid1, mid2; + + m = l + l - v; + sv = (v - m ) / v; + h *= 6.0; + sextant = (int)h; + fract = h - sextant; + vsf = v * sv * fract; + mid1 = m + vsf; + mid2 = v - vsf; + switch (sextant) + { + case 0: + r = v; + g = mid1; + b = m; + break; + case 1: + r = mid2; + g = v; + b = m; + break; + case 2: + r = m; + g = v; + b = mid1; + break; + case 3: + r = m; + g = mid2; + b = v; + break; + case 4: + r = mid1; + g = m; + b = v; + break; + case 5: + r = v; + g = m; + b = mid2; + break; + } + } + *pRed = r; + *pGreen = g; + *pBlue = b; +} + +ColoredImage::ColoredImage(int width,int height, + const uchar *greyLevels,const uchar *alphaLevels, + int saturation,int hue,int gamma) +{ + m_hasAlpha = alphaLevels!=0; + m_width = width; + m_height = height; + m_data = (uchar*)malloc(width*height*4); + int i; + for (i=0;i + +class Image +{ + public: + Image(int w,int h); + ~Image(); + + void setPixel(int x,int y,uchar val); + uchar getPixel(int x,int y) const; + void writeChar(int x,int y,char c,uchar fg); + void writeString(int x,int y,const char *s,uchar fg); + void drawHorzLine(int y,int xs,int xe,uchar colIndex,uint mask); + void drawHorzArrow(int y,int xs,int xe,uchar colIndex,uint mask); + void drawVertLine(int x,int ys,int ye,uchar colIndex,uint mask); + void drawVertArrow(int x,int ys,int ye,uchar colIndex,uint mask); + void drawRect(int x,int y,int width,int height,uchar colIndex,uint mask); + void fillRect(int x,int y,int width,int height,uchar colIndex,uint mask); + bool save(const char *fileName,int mode=0); + friend uint stringLength(const char *s); + uint getWidth() const { return width; } + uint getHeight() const { return height; } + uchar *getData() const { return data; } + static uint stringLength(const char *s); + + private: + int width; + int height; + uchar *data; +}; + +class ColoredImage +{ + public: + ColoredImage(int width,int height, + const uchar *greyLevels,const uchar *alphaLevels, + int saturation,int hue,int gamma); + ~ColoredImage(); + bool save(const char *fileName); + static void hsl2rgb(double h,double s,double l, + double *pRed,double *pGreen,double *pBlue); + private: + int m_width; + int m_height; + uchar *m_data; + bool m_hasAlpha; +}; + +#endif diff --git a/trunk/src/increasebuffer.pl b/trunk/src/increasebuffer.pl new file mode 100755 index 0000000..109f9ad --- /dev/null +++ b/trunk/src/increasebuffer.pl @@ -0,0 +1,9 @@ +# Since the internal token buffer of a generated flex file is hardcoded +# to 16K, this script is used to increase the buffer size of a flex +# generated scanner to 256K. +while (<>) +{ + s/YY_BUF_SIZE 16384/YY_BUF_SIZE 262144/g; + s/YY_READ_BUF_SIZE 8192/YY_READ_BUF_SIZE 262144/g; + print $_; +} diff --git a/trunk/src/index.cpp b/trunk/src/index.cpp new file mode 100644 index 0000000..d92fbc5 --- /dev/null +++ b/trunk/src/index.cpp @@ -0,0 +1,3932 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +/** @file + * @brief This file contains functions for the various index pages. + */ + +#include + +#include +#include +#include +#include + +#include "message.h" +#include "index.h" +#include "doxygen.h" +#include "config.h" +#include "filedef.h" +#include "outputlist.h" +#include "util.h" +#include "groupdef.h" +#include "language.h" +#include "htmlgen.h" +#include "htmlhelp.h" +#include "ftvhelp.h" +#include "dot.h" +#include "pagedef.h" +#include "dirdef.h" +#include "vhdldocgen.h" +#include "layout.h" + +#define MAX_ITEMS_BEFORE_MULTIPAGE_INDEX 200 +#define MAX_ITEMS_BEFORE_QUICK_INDEX 30 + + +int annotatedClasses; +int annotatedClassesPrinted; +int hierarchyClasses; +int documentedFiles; +int documentedGroups; +int documentedNamespaces; +int indexedPages; +int documentedClassMembers[CMHL_Total]; +int documentedFileMembers[FMHL_Total]; +int documentedNamespaceMembers[NMHL_Total]; +int documentedHtmlFiles; +int documentedPages; +int documentedDirs; + +static int countClassHierarchy(); +static void countFiles(int &htmlFiles,int &files); +static int countGroups(); +static int countDirs(); +static int countNamespaces(); +static int countAnnotatedClasses(int *cp); +static void countRelatedPages(int &docPages,int &indexPages); + +void countDataStructures() +{ + annotatedClasses = countAnnotatedClasses(&annotatedClassesPrinted); // "classes" + "annotated" + hierarchyClasses = countClassHierarchy(); // "hierarchy" + countFiles(documentedHtmlFiles,documentedFiles); // "files" + countRelatedPages(documentedPages,indexedPages); // "pages" + documentedGroups = countGroups(); // "modules" + documentedNamespaces = countNamespaces(); // "namespaces" + documentedDirs = countDirs(); // "dirs" + // "globals" + // "namespacemembers" + // "functions" +} + +static void startIndexHierarchy(OutputList &ol,int level) +{ + ol.pushGeneratorState(); + ol.disable(OutputGenerator::Man); + ol.disable(OutputGenerator::Html); + if (level<6) ol.startIndexList(); + ol.enableAll(); + ol.disable(OutputGenerator::Latex); + ol.disable(OutputGenerator::RTF); + ol.startItemList(); + ol.popGeneratorState(); +} + +static void endIndexHierarchy(OutputList &ol,int level) +{ + ol.pushGeneratorState(); + ol.disable(OutputGenerator::Man); + ol.disable(OutputGenerator::Html); + if (level<6) ol.endIndexList(); + ol.enableAll(); + ol.disable(OutputGenerator::Latex); + ol.disable(OutputGenerator::RTF); + ol.endItemList(); + ol.popGeneratorState(); +} + +//---------------------------------------------------------------------------- + +class MemberIndexList : public QList +{ + public: + MemberIndexList() : QList() {} + ~MemberIndexList() {} + int compareItems(GCI item1, GCI item2) + { + MemberDef *md1=(MemberDef *)item1; + MemberDef *md2=(MemberDef *)item2; + return stricmp(md1->name(),md2->name()); + } +}; + +#define MEMBER_INDEX_ENTRIES 256 + +static MemberIndexList g_memberIndexLetterUsed[CMHL_Total][MEMBER_INDEX_ENTRIES]; +static MemberIndexList g_fileIndexLetterUsed[FMHL_Total][MEMBER_INDEX_ENTRIES]; +static MemberIndexList g_namespaceIndexLetterUsed[NMHL_Total][MEMBER_INDEX_ENTRIES]; + +//static bool g_classIndexLetterUsed[CHL_Total][256]; + +const int maxItemsBeforeQuickIndex = MAX_ITEMS_BEFORE_QUICK_INDEX; + +//---------------------------------------------------------------------------- + +// strips w from s iff s starts with w +static bool stripWord(QCString &s,QCString w) +{ + bool success=FALSE; + if (s.left(w.length())==w) + { + success=TRUE; + s=s.right(s.length()-w.length()); + } + return success; +} + +//---------------------------------------------------------------------------- +// some quasi intelligent brief description abbreviator :^) +static QCString abbreviate(const char *s,const char *name) +{ + QCString scopelessName=name; + int i=scopelessName.findRev("::"); + if (i!=-1) scopelessName=scopelessName.mid(i+2); + QCString result=s; + result=result.stripWhiteSpace(); + // strip trailing . + if (!result.isEmpty() && result.at(result.length()-1)=='.') + result=result.left(result.length()-1); + + // strip any predefined prefix + QStrList &briefDescAbbrev = Config_getList("ABBREVIATE_BRIEF"); + const char *p = briefDescAbbrev.first(); + while (p) + { + QCString s = p; + s.replace(QRegExp("\\$name"), scopelessName); // replace $name with entity name + s += " "; + stripWord(result,s); + p = briefDescAbbrev.next(); + } + + // capitalize first word + if (!result.isEmpty()) + { + int c=result[0]; + if (c>='a' && c<='z') c+='A'-'a'; + result[0]=c; + } + return result; +} + +//---------------------------------------------------------------------------- + +static void startQuickIndexList(OutputList &ol,bool letterTabs=FALSE) +{ + bool fancyTabs = TRUE; + if (fancyTabs) + { + if (letterTabs) + { + ol.writeString("
      \n"); + } + else + { + ol.writeString("
      \n"); + } + ol.writeString("
        \n"); + } + else + { + ol.writeString("
        "); + } +} + +static void endQuickIndexList(OutputList &ol) +{ + bool fancyTabs = TRUE; + if (fancyTabs) + { + ol.writeString("
      \n"); + } + ol.writeString("
      \n"); +} + +static void startQuickIndexItem(OutputList &ol,const char *l, + bool hl,bool compact,bool &first) +{ + bool fancyTabs = TRUE; + if (!first && compact && !fancyTabs) ol.writeString(" | "); + first=FALSE; + if (fancyTabs) + { + ol.writeString(" "); + if (hl && compact) + { + ol.writeString(""); + if (fancyTabs) + { + ol.writeString(""); + } +} + +static void endQuickIndexItem(OutputList &ol) +{ + bool fancyTabs=TRUE; + if (fancyTabs) ol.writeString(""); + ol.writeString(""); + if (fancyTabs) ol.writeString("\n"); +} + +// don't make this static as it is called from a template function and some +// old compilers don't support calls to static functions from a template. +QCString fixSpaces(const QCString &s) +{ + return substitute(s," "," "); +} + +void startTitle(OutputList &ol,const char *fileName,Definition *def) +{ + ol.startHeaderSection(); + if (def) def->writeSummaryLinks(ol); + ol.startTitleHead(fileName); + ol.pushGeneratorState(); + ol.disable(OutputGenerator::Man); +} + +void endTitle(OutputList &ol,const char *fileName,const char *name) +{ + ol.popGeneratorState(); + ol.endTitleHead(fileName,name); + ol.endHeaderSection(); +} + +void startFile(OutputList &ol,const char *name,const char *manName, + const char *title,HighlightedItem hli,bool additionalIndices, + const char *altSidebarName) +{ + static bool disableIndex = Config_getBool("DISABLE_INDEX"); + ol.startFile(name,manName,title); + ol.startQuickIndices(); + if (!disableIndex) + { + ol.writeQuickLinks(TRUE,hli,name); + } + if (!additionalIndices) + { + ol.endQuickIndices(); + } + ol.writeSplitBar(altSidebarName ? altSidebarName : name); + ol.writeSearchInfo(); +} + +void endFile(OutputList &ol,bool skipNavIndex,bool skipEndContents) +{ + static bool generateTreeView = Config_getBool("GENERATE_TREEVIEW"); + ol.pushGeneratorState(); + ol.disableAllBut(OutputGenerator::Html); + if (!skipNavIndex) + { + if (!skipEndContents) ol.endContents(); + if (generateTreeView) + { + ol.writeString("
      \n"); + ol.writeString("
      \n"); + ol.writeString("
        \n"); + } + } + ol.writeFooter(); // write the footer + ol.popGeneratorState(); + ol.endFile(); +} + +void endFileWithNavPath(Definition *d,OutputList &ol) +{ + static bool generateTreeView = Config_getBool("GENERATE_TREEVIEW"); + if (generateTreeView) + { + d->writeNavigationPath(ol); + } + endFile(ol,generateTreeView,TRUE); +} + +//---------------------------------------------------------------------- +template void addMembersToIndex(T *def,LayoutDocManager::LayoutPart part,const QCString &name,const QCString &anchor) +{ + bool hasMembers = def->getMemberLists().count()>0 || def->getMemberGroupSDict()!=0; + Doxygen::indexList.addContentsItem(hasMembers,name,def->getReference(),def->getOutputFileBase(),anchor,hasMembers,TRUE); + if (hasMembers) + { + Doxygen::indexList.incContentsDepth(); + QListIterator eli(LayoutDocManager::instance().docEntries(part)); + LayoutDocEntry *lde; + for (eli.toFirst();(lde=eli.current());++eli) + { + if (lde->kind()==LayoutDocEntry::MemberDef) + { + LayoutDocEntryMemberDef *lmd = (LayoutDocEntryMemberDef*)lde; + MemberList *ml = def->getMemberList(lmd->type); + if (ml) + { + MemberListIterator mi(*ml); + MemberDef *md; + for (mi.toFirst();(md=mi.current());++mi) + { + if (md->name().find('@')==-1) + { + Doxygen::indexList.addContentsItem(FALSE, + md->name(),md->getReference(),md->getOutputFileBase(),md->anchor(),FALSE); + } + } + } + } + else if (lde->kind()==LayoutDocEntry::NamespaceClasses || + lde->kind()==LayoutDocEntry::FileClasses) + { + ClassSDict *classes = def->getClassSDict(); + if (classes) + { + ClassDef *cd; + ClassSDict::Iterator it(*classes); + for (;(cd=it.current());++it) + { + if (cd->getOuterScope()==def) + { + Doxygen::indexList.addContentsItem(FALSE, + cd->localName(), + cd->getReference(),cd->getOutputFileBase(),cd->anchor(),FALSE,FALSE); + } + } + } + } + } + + Doxygen::indexList.decContentsDepth(); + } +} + +//---------------------------------------------------------------------------- + +static bool classHasVisibleChildren(ClassDef *cd) +{ + BaseClassList *bcl; + + if (cd->getLanguage()==SrcLangExt_VHDL) // reverse baseClass/subClass relation + { + if (cd->baseClasses()==0) return FALSE; + bcl=cd->baseClasses(); + } + else + { + if (cd->subClasses()==0) return FALSE; + bcl=cd->subClasses(); + } + + BaseClassListIterator bcli(*bcl); + for ( ; bcli.current() ; ++bcli) + { + if (bcli.current()->classDef->isVisibleInHierarchy()) + { + return TRUE; + } + } + return FALSE; +} + +//---------------------------------------------------------------------------- +/*! Generates HTML Help tree of classes */ + +static void writeClassTree(OutputList &ol,BaseClassList *bcl,bool hideSuper,int level,FTVHelp* ftv,bool addToIndex) +{ + if (bcl==0) return; + BaseClassListIterator bcli(*bcl); + bool started=FALSE; + for ( ; bcli.current() ; ++bcli) + { + ClassDef *cd=bcli.current()->classDef; + bool b; + if (cd->getLanguage()==SrcLangExt_VHDL) + { + b=hasVisibleRoot(cd->subClasses()); + } + else + { + b=hasVisibleRoot(cd->baseClasses()); + } + + if (cd->isVisibleInHierarchy() && b) // hasVisibleRoot(cd->baseClasses())) + { + if (!started) + { + startIndexHierarchy(ol,level); + if (addToIndex) + { + Doxygen::indexList.incContentsDepth(); + } + if (ftv) + { + ftv->incContentsDepth(); + } + started=TRUE; + } + ol.startIndexListItem(); + //printf("Passed...\n"); + bool hasChildren = !cd->visited && !hideSuper && classHasVisibleChildren(cd); + //printf("tree4: Has children %s: %d\n",cd->name().data(),hasChildren); + if (cd->isLinkable()) + { + //printf("Writing class %s\n",cd->displayName().data()); + ol.startIndexItem(cd->getReference(),cd->getOutputFileBase()); + ol.parseText(cd->displayName()); + ol.endIndexItem(cd->getReference(),cd->getOutputFileBase()); + if (cd->isReference()) + { + ol.startTypewriter(); + ol.docify(" [external]"); + ol.endTypewriter(); + } + if (addToIndex) + { + Doxygen::indexList.addContentsItem(hasChildren,cd->displayName(),cd->getReference(),cd->getOutputFileBase(),cd->anchor()); + } + if (ftv) + { + ftv->addContentsItem(hasChildren,cd->displayName(),cd->getReference(),cd->getOutputFileBase(),cd->anchor()); + } + } + else + { + ol.startIndexItem(0,0); + ol.parseText(cd->name()); + ol.endIndexItem(0,0); + if (addToIndex) + { + Doxygen::indexList.addContentsItem(hasChildren,cd->displayName(),0,0,0); + } + if (ftv) + { + ftv->addContentsItem(hasChildren,cd->displayName(),0,0,0); + } + } + if (hasChildren) + { + //printf("Class %s at %p visited=%d\n",cd->name().data(),cd,cd->visited); + bool wasVisited=cd->visited; + cd->visited=TRUE; + if (cd->getLanguage()==SrcLangExt_VHDL) + { + writeClassTree(ol,cd->baseClasses(),wasVisited,level+1,ftv,addToIndex); + } + else + { + writeClassTree(ol,cd->subClasses(),wasVisited,level+1,ftv,addToIndex); + } + } + ol.endIndexListItem(); + } + } + if (started) + { + endIndexHierarchy(ol,level); + if (addToIndex) + { + Doxygen::indexList.decContentsDepth(); + } + if (ftv) + { + ftv->decContentsDepth(); + } + } +} + +//---------------------------------------------------------------------------- + +static void writeClassTreeForList(OutputList &ol,ClassSDict *cl,bool &started,FTVHelp* ftv,bool addToIndex) +{ + ClassSDict::Iterator cli(*cl); + for (;cli.current(); ++cli) + { + ClassDef *cd=cli.current(); + //printf("class %s hasVisibleRoot=%d isVisibleInHierarchy=%d\n", + // cd->name().data(), + // hasVisibleRoot(cd->baseClasses()), + // cd->isVisibleInHierarchy() + // ); + bool b; + if (cd->getLanguage()==SrcLangExt_VHDL) + { + if (!(VhdlDocGen::VhdlClasses)cd->protection()==VhdlDocGen::ENTITYCLASS) + { + continue; + } + b=!hasVisibleRoot(cd->subClasses()); + } + else + { + b=!hasVisibleRoot(cd->baseClasses()); + } + + if (b) //filter on root classes + { + if (cd->isVisibleInHierarchy()) // should it be visible + { + if (!started) + { + startIndexHierarchy(ol,0); + if (addToIndex) + { + Doxygen::indexList.incContentsDepth(); + } + started=TRUE; + } + ol.startIndexListItem(); + bool hasChildren = !cd->visited && classHasVisibleChildren(cd); + //printf("list: Has children %s: %d\n",cd->name().data(),hasChildren); + if (cd->isLinkable()) + { + //printf("Writing class %s isLinkable()=%d isLinkableInProject()=%d cd->templateMaster()=%p\n", + // cd->displayName().data(),cd->isLinkable(),cd->isLinkableInProject(),cd->templateMaster()); + ol.startIndexItem(cd->getReference(),cd->getOutputFileBase()); + ol.parseText(cd->displayName()); + ol.endIndexItem(cd->getReference(),cd->getOutputFileBase()); + if (cd->isReference()) + { + ol.startTypewriter(); + ol.docify(" [external]"); + ol.endTypewriter(); + } + if (addToIndex) + { + Doxygen::indexList.addContentsItem(hasChildren,cd->displayName(),cd->getReference(),cd->getOutputFileBase(),cd->anchor(),FALSE,FALSE); + } + if (ftv) + { + ftv->addContentsItem(hasChildren,cd->displayName(),cd->getReference(),cd->getOutputFileBase(),cd->anchor()); + } + } + else + { + ol.startIndexItem(0,0); + ol.parseText(cd->displayName()); + ol.endIndexItem(0,0); + if (addToIndex) + { + Doxygen::indexList.addContentsItem(hasChildren,cd->displayName(),0,0,0,FALSE,FALSE); + } + if (ftv) + { + ftv->addContentsItem(hasChildren,cd->displayName(),0,0,0); + } + } + if (cd->getLanguage()==SrcLangExt_VHDL && hasChildren) + { + writeClassTree(ol,cd->baseClasses(),cd->visited,1,ftv,addToIndex); + cd->visited=TRUE; + } + else if (hasChildren) + { + writeClassTree(ol,cd->subClasses(),cd->visited,1,ftv,addToIndex); + cd->visited=TRUE; + } + ol.endIndexListItem(); + } + } + } +} + +static void writeClassHierarchy(OutputList &ol, FTVHelp* ftv,bool addToIndex) +{ + initClassHierarchy(Doxygen::classSDict); + initClassHierarchy(Doxygen::hiddenClasses); + if (ftv) + { + ol.pushGeneratorState(); + ol.disable(OutputGenerator::Html); + } + bool started=FALSE; + writeClassTreeForList(ol,Doxygen::classSDict,started,ftv,addToIndex); + writeClassTreeForList(ol,Doxygen::hiddenClasses,started,ftv,addToIndex); + if (started) + { + endIndexHierarchy(ol,0); + if (addToIndex) + { + Doxygen::indexList.decContentsDepth(); + } + } + if (ftv) + ol.popGeneratorState(); +} + +//---------------------------------------------------------------------------- + +static int countClassesInTreeList(const ClassSDict &cl) +{ + int count=0; + ClassSDict::Iterator cli(cl); + for (;cli.current(); ++cli) + { + ClassDef *cd=cli.current(); + if (!hasVisibleRoot(cd->baseClasses())) // filter on root classes + { + if (cd->isVisibleInHierarchy()) // should it be visible + { + if (cd->subClasses()) // should have sub classes + { + count++; + } + } + } + } + return count; +} + +static int countClassHierarchy() +{ + int count=0; + initClassHierarchy(Doxygen::classSDict); + initClassHierarchy(Doxygen::hiddenClasses); + count+=countClassesInTreeList(*Doxygen::classSDict); + count+=countClassesInTreeList(*Doxygen::hiddenClasses); + return count; +} + +//---------------------------------------------------------------------------- + +static void writeHierarchicalIndex(OutputList &ol) +{ + if (hierarchyClasses==0) return; + ol.pushGeneratorState(); + ol.disable(OutputGenerator::Man); + + LayoutNavEntry *lne = LayoutDocManager::instance().rootNavEntry()->find(LayoutNavEntry::ClassHierarchy); + QCString title = lne ? lne->title() : theTranslator->trClassHierarchy(); + bool addToIndex = lne==0 || lne->visible(); + + startFile(ol,"hierarchy",0, title, HLI_Hierarchy); + startTitle(ol,0); + ol.parseText(title); + endTitle(ol,0,0); + ol.startContents(); + ol.startTextBlock(); + + if (addToIndex) + { + Doxygen::indexList.addContentsItem(TRUE,title,0,"hierarchy",0,TRUE,TRUE); + } + + if (Config_getBool("HAVE_DOT") && Config_getBool("GRAPHICAL_HIERARCHY")) + { + ol.disable(OutputGenerator::Latex); + ol.disable(OutputGenerator::RTF); + ol.startParagraph(); + ol.startTextLink("inherits",0); + ol.parseText(theTranslator->trGotoGraphicalHierarchy()); + ol.endTextLink(); + ol.endParagraph(); + ol.enable(OutputGenerator::Latex); + ol.enable(OutputGenerator::RTF); + } + ol.parseText(lne ? lne->intro() : theTranslator->trClassHierarchyDescription()); + ol.endTextBlock(); + + FTVHelp* ftv = 0; + bool treeView=Config_getBool("USE_INLINE_TREES"); + if (treeView) + { + ftv = new FTVHelp(FALSE); + } + + writeClassHierarchy(ol,ftv,addToIndex); + + if (ftv) + { + QGString outStr; + FTextStream t(&outStr); + ftv->generateTreeViewInline(t); + ol.pushGeneratorState(); + ol.disableAllBut(OutputGenerator::Html); + ol.writeString(outStr); + ol.popGeneratorState(); + delete ftv; + } + endFile(ol); + ol.popGeneratorState(); +} + +//---------------------------------------------------------------------------- + +static void writeGraphicalClassHierarchy(OutputList &ol) +{ + if (hierarchyClasses==0) return; + ol.disableAllBut(OutputGenerator::Html); + LayoutNavEntry *lne = LayoutDocManager::instance().rootNavEntry()->find(LayoutNavEntry::ClassHierarchy); + QCString title = lne ? lne->title() : theTranslator->trClassHierarchy(); + startFile(ol,"inherits",0,title,HLI_Hierarchy,FALSE,"hierarchy"); + startTitle(ol,0); + ol.parseText(title); + endTitle(ol,0,0); + ol.startContents(); + ol.startTextBlock(); + ol.startParagraph(); + ol.startTextLink("hierarchy",0); + ol.parseText(theTranslator->trGotoTextualHierarchy()); + ol.endTextLink(); + ol.endParagraph(); + ol.endTextBlock(); + DotGfxHierarchyTable g; + ol.writeGraphicalHierarchy(g); + endFile(ol); + ol.enableAll(); +} + +//---------------------------------------------------------------------------- + +static void countFiles(int &htmlFiles,int &files) +{ + htmlFiles=0; + files=0; + FileNameListIterator fnli(*Doxygen::inputNameList); + FileName *fn; + for (;(fn=fnli.current());++fnli) + { + FileNameIterator fni(*fn); + FileDef *fd; + for (;(fd=fni.current());++fni) + { + bool doc = fd->isLinkableInProject(); + bool src = fd->generateSourceFile(); + bool nameOk = !fd->isDocumentationFile(); + if (nameOk) + { + if (doc || src) + { + htmlFiles++; + } + if (doc) + { + files++; + } + } + } + } +} + +//---------------------------------------------------------------------------- + +static void writeFileIndex(OutputList &ol) +{ + if (documentedHtmlFiles==0) return; + ol.pushGeneratorState(); + ol.disable(OutputGenerator::Man); + if (documentedFiles==0) ol.disableAllBut(OutputGenerator::Html); + LayoutNavEntry *lne = LayoutDocManager::instance().rootNavEntry()->find(LayoutNavEntry::FileList); + if (lne==0) lne = LayoutDocManager::instance().rootNavEntry()->find(LayoutNavEntry::Files); // fall back + QCString title = lne ? lne->title() : theTranslator->trFileList(); + bool addToIndex = lne==0 || lne->visible(); + + startFile(ol,"files",0,title,HLI_Files); + startTitle(ol,0); + //if (!Config_getString("PROJECT_NAME").isEmpty()) + //{ + // title.prepend(Config_getString("PROJECT_NAME")+" "); + //} + ol.parseText(title); + endTitle(ol,0,0); + ol.startContents(); + ol.startTextBlock(); + + if (addToIndex) + { + Doxygen::indexList.addContentsItem(TRUE,title,0,"files",0,TRUE,TRUE); + Doxygen::indexList.incContentsDepth(); + } + + ol.parseText(lne ? lne->intro() : theTranslator->trFileListDescription(Config_getBool("EXTRACT_ALL"))); + ol.endTextBlock(); + + OutputNameDict outputNameDict(1009); + OutputNameList outputNameList; + outputNameList.setAutoDelete(TRUE); + + if (Config_getBool("FULL_PATH_NAMES")) + { + // re-sort input files in (dir,file) output order instead of (file,dir) input order + FileName *fn=Doxygen::inputNameList->first(); + while (fn) + { + FileDef *fd=fn->first(); + while (fd) + { + QCString path=fd->getPath(); + if (path.isEmpty()) path="[external]"; + FileList *fl = outputNameDict.find(path); + if (fl) + { + fl->inSort(fd); + //printf("+ inserting %s---%s\n",fd->getPath().data(),fd->name().data()); + } + else + { + //printf("o inserting %s---%s\n",fd->getPath().data(),fd->name().data()); + fl = new FileList(path); + fl->inSort(fd); + outputNameList.inSort(fl); + outputNameDict.insert(path,fl); + } + fd=fn->next(); + } + fn=Doxygen::inputNameList->next(); + } + } + + ol.startIndexList(); + FileList *fl=0; + if (Config_getBool("FULL_PATH_NAMES")) + { + fl = outputNameList.first(); + } + else + { + fl = Doxygen::inputNameList->first(); + } + while (fl) + { + FileDef *fd=fl->first(); + while (fd) + { + //printf("Found filedef %s\n",fd->name().data()); + bool doc = fd->isLinkableInProject(); + bool src = fd->generateSourceFile(); + bool nameOk = !fd->isDocumentationFile(); + if (nameOk && (doc || src) && + !fd->isReference()) + { + QCString path; + if (Config_getBool("FULL_PATH_NAMES")) + { + path=stripFromPath(fd->getPath().copy()); + } + QCString fullName=fd->name(); + if (!path.isEmpty()) + { + if (path.at(path.length()-1)!='/') fullName.prepend("/"); + fullName.prepend(path); + } + + ol.startIndexKey(); + ol.docify(path); + if (doc) + { + ol.writeObjectLink(0,fd->getOutputFileBase(),0,fd->name()); + if (addToIndex) + { + addMembersToIndex(fd,LayoutDocManager::File,fullName,QCString()); + } + } + else + { + ol.startBold(); + ol.docify(fd->name()); + ol.endBold(); + if (addToIndex) + { + Doxygen::indexList.addContentsItem(FALSE,fullName,0,0,0); + } + } + if (src) + { + ol.pushGeneratorState(); + ol.disableAllBut(OutputGenerator::Html); + ol.docify(" "); + ol.startTextLink(fd->includeName(),0); + ol.docify("["); + ol.parseText(theTranslator->trCode()); + ol.docify("]"); + ol.endTextLink(); + ol.popGeneratorState(); + } + ol.endIndexKey(); + bool hasBrief = !fd->briefDescription().isEmpty(); + ol.startIndexValue(hasBrief); + if (hasBrief) + { + //ol.docify(" ("); + ol.parseDoc( + fd->briefFile(),fd->briefLine(), + fd,0, + abbreviate(fd->briefDescription(),fd->name()), + FALSE, // index words + FALSE, // isExample + 0, // example name + TRUE, // single line + TRUE // link from index + ); + //ol.docify(")"); + } + ol.endIndexValue(fd->getOutputFileBase(),hasBrief); + //ol.popGeneratorState(); + // -------------------------------------------------------- + } + fd=fl->next(); + } + if (Config_getBool("FULL_PATH_NAMES")) + { + fl=outputNameList.next(); + } + else + { + fl=Doxygen::inputNameList->next(); + } + } + ol.endIndexList(); + + if (addToIndex) + { + Doxygen::indexList.decContentsDepth(); + } + + endFile(ol); + ol.popGeneratorState(); +} + +//---------------------------------------------------------------------------- +static int countNamespaces() +{ + int count=0; + NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict); + NamespaceDef *nd; + for (;(nd=nli.current());++nli) + { + if (nd->isLinkableInProject()) count++; + } + return count; +} + +//---------------------------------------------------------------------------- + +static void writeNamespaceIndex(OutputList &ol) +{ + if (documentedNamespaces==0) return; + ol.pushGeneratorState(); + ol.disable(OutputGenerator::Man); + LayoutNavEntry *lne = LayoutDocManager::instance().rootNavEntry()->find(LayoutNavEntry::NamespaceList); + if (lne==0) lne = LayoutDocManager::instance().rootNavEntry()->find(LayoutNavEntry::Namespaces); // fall back + QCString title = lne ? lne->title() : theTranslator->trNamespaceList(); + bool addToIndex = lne==0 || lne->visible(); + startFile(ol,"namespaces",0,title,HLI_Namespaces); + startTitle(ol,0); + ol.parseText(title); + endTitle(ol,0,0); + ol.startContents(); + ol.startTextBlock(); + if (addToIndex) + { + Doxygen::indexList.addContentsItem(TRUE,title,0,"namespaces",0,TRUE,TRUE); + Doxygen::indexList.incContentsDepth(); + } + ol.parseText(lne ? lne->intro() : theTranslator->trNamespaceListDescription(Config_getBool("EXTRACT_ALL"))); + ol.endTextBlock(); + + bool first=TRUE; + + NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict); + NamespaceDef *nd; + for (nli.toFirst();(nd=nli.current());++nli) + { + if (nd->isLinkableInProject()) + { + if (first) + { + ol.startIndexList(); + first=FALSE; + } + //ol.writeStartAnnoItem("namespace",nd->getOutputFileBase(),0,nd->name()); + ol.startIndexKey(); + if (nd->getLanguage()==SrcLangExt_VHDL) + { + ClassDef* ccd=getClass(nd->displayName()); + if (ccd) ol.writeObjectLink(0,ccd->getOutputFileBase(),0,nd->displayName()); + } + else + { + ol.writeObjectLink(0,nd->getOutputFileBase(),0,nd->displayName()); + } + ol.endIndexKey(); + + bool hasBrief = !nd->briefDescription().isEmpty(); + ol.startIndexValue(hasBrief); + if (hasBrief) + { + //ol.docify(" ("); + ol.parseDoc( + nd->briefFile(),nd->briefLine(), + nd,0, + abbreviate(nd->briefDescription(),nd->displayName()), + FALSE, // index words + FALSE, // isExample + 0, // example name + TRUE, // single line + TRUE // link from index + ); + //ol.docify(")"); + } + ol.endIndexValue(nd->getOutputFileBase(),hasBrief); + + if (addToIndex) + { + if (nd->getLanguage()==SrcLangExt_VHDL) + { + ClassDef* ccd=getClass(nd->displayName().data()); + if (ccd) Doxygen::indexList.addContentsItem(FALSE,ccd->displayName(),ccd->getReference(),ccd->getOutputFileBase(),0); + } + else + { + addMembersToIndex(nd,LayoutDocManager::Namespace,nd->displayName(),QCString()); + } + } + } + } + if (!first) ol.endIndexList(); + if (addToIndex) + { + Doxygen::indexList.decContentsDepth(); + } + endFile(ol); + ol.popGeneratorState(); +} + +//---------------------------------------------------------------------------- + +static int countAnnotatedClasses(int *cp) +{ + int count=0; + int countPrinted=0; + ClassSDict::Iterator cli(*Doxygen::classSDict); + ClassDef *cd; + for (;(cd=cli.current());++cli) + { + if (cd->isLinkableInProject() && cd->templateMaster()==0) + { + if (!cd->isEmbeddedInOuterScope()) + { + countPrinted++; + } + count++; + } + } + *cp = countPrinted; + return count; +} + + +static void writeAnnotatedClassList(OutputList &ol) +{ + LayoutNavEntry *lne = LayoutDocManager::instance().rootNavEntry()->find(LayoutNavEntry::ClassList); + bool addToIndex = lne==0 || lne->visible(); + + ol.startIndexList(); + ClassSDict::Iterator cli(*Doxygen::classSDict); + ClassDef *cd; + + for (cli.toFirst();(cd=cli.current());++cli) + { + if (cd->getLanguage()==SrcLangExt_VHDL &&(!(VhdlDocGen::VhdlClasses)cd->protection()==VhdlDocGen::ENTITYCLASS )) + continue; + + ol.pushGeneratorState(); + if (cd->isEmbeddedInOuterScope()) + { + ol.disable(OutputGenerator::Latex); + ol.disable(OutputGenerator::RTF); + } + if (cd->isLinkableInProject() && cd->templateMaster()==0) + { + QCString type=cd->compoundTypeString(); + ol.startIndexKey(); + if (cd->getLanguage()==SrcLangExt_VHDL) + { + QCString prot= VhdlDocGen::getProtectionName((VhdlDocGen::VhdlClasses)cd->protection()); + ol.docify(prot.data()); + ol.writeString(" "); + } + ol.writeObjectLink(0,cd->getOutputFileBase(),cd->anchor(),cd->displayName()); + ol.endIndexKey(); + bool hasBrief = !cd->briefDescription().isEmpty(); + ol.startIndexValue(hasBrief); + if (hasBrief) + { + ol.parseDoc( + cd->briefFile(),cd->briefLine(), + cd,0, + abbreviate(cd->briefDescription(),cd->displayName()), + FALSE, // indexWords + FALSE, // isExample + 0, // example name + TRUE, // single line + TRUE // link from index + ); + } + ol.endIndexValue(cd->getOutputFileBase(),hasBrief); + + if (addToIndex) + { + addMembersToIndex(cd,LayoutDocManager::Class,cd->displayName(),cd->anchor()); + } + } + ol.popGeneratorState(); + } + ol.endIndexList(); +} + +static QCString letterToLabel(char startLetter) +{ + QCString s(5); + if (isId(startLetter)) + { + s[0]=startLetter; s[1]=0; + } + else + { + const char hex[]="0123456789abcdef"; + s[0]='0'; + s[1]='x'; + s[2]=hex[startLetter>>4]; + s[3]=hex[startLetter&0xF]; + s[4]=0; + } + return s; +} + +//---------------------------------------------------------------------------- + +class PrefixIgnoreClassList : public ClassList +{ +public: + virtual int compareItems(GCI item1, GCI item2) + { + ClassDef *c1=(ClassDef *)item1; + ClassDef *c2=(ClassDef *)item2; + + QCString n1 = c1->className(); + QCString n2 = c2->className(); + return stricmp (n1.data()+getPrefixIndex(n1), n2.data()+getPrefixIndex(n2)); + } +}; + +class AlphaIndexTableCell +{ + public: + AlphaIndexTableCell(int row,int col,uchar letter,ClassDef *cd) : + m_letter(letter), m_class(cd), m_row(row), m_col(col) + { //printf("AlphaIndexTableCell(%d,%d,%c,%s)\n",row,col,letter!=0 ? letter: '-', + // cd!=(ClassDef*)0x8 ? cd->name().data() : ""); + } + + ClassDef *classDef() const { return m_class; } + uchar letter() const { return m_letter; } + int row() const { return m_row; } + int column() const { return m_col; } + + private: + uchar m_letter; + ClassDef *m_class; + int m_row; + int m_col; +}; + +class AlphaIndexTableRows : public QList +{ + public: + AlphaIndexTableRows() { setAutoDelete(TRUE); } +}; + +class AlphaIndexTableRowsIterator : public QListIterator +{ + public: + AlphaIndexTableRowsIterator(const AlphaIndexTableRows &list) : + QListIterator(list) {} +}; + +class AlphaIndexTableColumns : public QList +{ + public: + AlphaIndexTableColumns() { setAutoDelete(TRUE); } +}; + +// write an alphabetical index of all class with a header for each letter +static void writeAlphabeticalClassList(OutputList &ol) +{ + // What starting letters are used + bool indexLetterUsed[256]; + memset (indexLetterUsed, 0, sizeof (indexLetterUsed)); + + // first count the number of headers + ClassSDict::Iterator cli(*Doxygen::classSDict); + ClassDef *cd; + uint startLetter=0; + int headerItems=0; + for (;(cd=cli.current());++cli) + { + if (cd->isLinkableInProject() && cd->templateMaster()==0) + { + if (cd->getLanguage()==SrcLangExt_VHDL && !((VhdlDocGen::VhdlClasses)cd->protection()==VhdlDocGen::ENTITYCLASS ))// no architecture + continue; + + int index = getPrefixIndex(cd->className()); + //printf("name=%s index=%d %d\n",cd->className().data(),index,cd->protection()); + startLetter=toupper(cd->className().at(index))&0xFF; + indexLetterUsed[startLetter] = true; + } + } + + // write quick link index (row of letters) + QCString alphaLinks = "
        "; + int l; + for (l=0; l<256; l++) + { + if (indexLetterUsed[l]) + { + if (headerItems) alphaLinks += " | "; + headerItems++; + alphaLinks += (QCString)"" + + (char)l + ""; + } + } + alphaLinks += "
        \n"; + ol.writeString(alphaLinks); + + + // the number of columns in the table + const int columns = Config_getInt("COLS_IN_ALPHA_INDEX"); + + int i,j; + int totalItems = headerItems*2 + annotatedClasses; // number of items in the table (headers span 2 items) + int rows = (totalItems + columns - 1)/columns; // number of rows in the table + + //printf("headerItems=%d totalItems=%d columns=%d rows=%d itemsInLastRow=%d\n", + // headerItems,totalItems,columns,rows,itemsInLastRow); + + // Keep a list of classes for each starting letter + PrefixIgnoreClassList classesByLetter[256]; + AlphaIndexTableColumns tableColumns; + + // fill the columns with the class list (row elements in each column, + // expect for the columns with number >= itemsInLastRow, which get one + // item less. + //int icount=0; + startLetter=0; + for (cli.toFirst();(cd=cli.current());++cli) + { + if (cd->getLanguage()==SrcLangExt_VHDL && !((VhdlDocGen::VhdlClasses)cd->protection()==VhdlDocGen::ENTITYCLASS ))// no architecture + continue; + + if (cd->isLinkableInProject() && cd->templateMaster()==0) + { + int index = getPrefixIndex(cd->className()); + startLetter=toupper(cd->className().at(index))&0xFF; + // Do some sorting again, since the classes are sorted by name with + // prefix, which should be ignored really. + if (cd->getLanguage()==SrcLangExt_VHDL) + { + if ((VhdlDocGen::VhdlClasses)cd->protection()==VhdlDocGen::ENTITYCLASS )// no architecture + classesByLetter[startLetter].inSort(cd); + } + else + classesByLetter[startLetter].inSort(cd); + } + } + + #define NEXT_ROW() \ + do \ + { \ + if (row>maxRows) maxRows=row; \ + if (row>=rows && col0) + { + // add special header cell + tableRows->append(new AlphaIndexTableCell(row,col,(uchar)l,(ClassDef*)0x8)); + row++; + tableRows->append(new AlphaIndexTableCell(row,col,0,(ClassDef*)0x8)); + row++; + tableRows->append(new AlphaIndexTableCell(row,col,0,classesByLetter[l].at(0))); + row++; + NEXT_ROW(); + for (i=1; i<(int)classesByLetter[l].count(); i++) + { + // add normal cell + tableRows->append(new AlphaIndexTableCell(row,col,0,classesByLetter[l].at(i))); + row++; + NEXT_ROW(); + } + } + } + + // create row iterators for each column + AlphaIndexTableRowsIterator **colIterators = new AlphaIndexTableRowsIterator*[columns]; + for (i=0;i\n"); + // generate table + for (i=0;i<=maxRows;i++) // foreach table row + { + //printf("writing row %d\n",i); + //ol.nextTableRow(); + ol.writeString(""); + // the last column may contain less items then the others + //int colsInRow = (icurrent(); + if (cell) + { + if (cell->row()==i) + { + if (cell->letter()!=0) + { + QCString s = letterToLabel(cell->letter()); + ol.writeString(""); + ol.writeString(""); + ol.writeString("" + "" + "" + "" + "
          "); + ol.writeString(s); + ol.writeString( "  
        " + "
        \n"); + } + else if (cell->classDef()!=(ClassDef*)0x8) + { + cd = cell->classDef(); + ol.writeString(""); + QCString namesp,cname; + //if (cd->getNamespaceDef()) namesp=cd->getNamespaceDef()->displayName(); + //QCString cname=cd->className(); + extractNamespaceName(cd->name(),cname,namesp); + QCString nsDispName; + SrcLangExt lang = cd->getLanguage(); + QCString sep = getLanguageSpecificSeparator(lang); + if (sep!="::") + { + nsDispName=substitute(namesp,"::",sep); + } + else + { + nsDispName=namesp; + } + if (cname.right(2)=="-g" || cname.right(2)=="-p") + { + cname = cname.left(cname.length()-2); + } + + ol.writeObjectLink(cd->getReference(), + cd->getOutputFileBase(),cd->anchor(),cname); + if (!namesp.isEmpty()) + { + ol.docify(" ("); + NamespaceDef *nd = getResolvedNamespace(namesp); + if (nd && nd->isLinkable()) + { + ol.writeObjectLink(nd->getReference(), + nd->getOutputFileBase(),0,nsDispName); + } + else + { + ol.docify(nsDispName); + } + ol.docify(")"); + } + ol.writeNonBreakableSpace(3); + } + ++(*colIterators[j]); + if (cell->letter()!=0 || cell->classDef()!=(ClassDef*)0x8) + { + ol.writeString(""); + } + } + } + else + { + ol.writeString(""); + } + } + } + ol.writeString("\n"); + } + ol.writeString("\n"); + + ol.writeString(alphaLinks); + + // release the temporary memory + for (i=0;ifind(LayoutNavEntry::ClassIndex); + QCString title = lne ? lne->title() : theTranslator->trCompoundIndex(); + bool addToIndex = lne==0 || lne->visible(); + + startFile(ol,"classes",0,title,HLI_Classes); + + startTitle(ol,0); + ol.parseText(title); + endTitle(ol,0,0); + + if (addToIndex) + { + Doxygen::indexList.addContentsItem(TRUE,title,0,"classes",0,TRUE,TRUE); + } + + ol.startContents(); + writeAlphabeticalClassList(ol); + endFile(ol); // contains ol.endContents() + + ol.popGeneratorState(); +} + +//---------------------------------------------------------------------------- + +static void writeAnnotatedIndex(OutputList &ol) +{ + //printf("writeAnnotatedIndex: count=%d printed=%d\n", + // annotatedClasses,annotatedClassesPrinted); + if (annotatedClasses==0) return; + + ol.pushGeneratorState(); + ol.disable(OutputGenerator::Man); + if (annotatedClassesPrinted==0) + { + ol.disable(OutputGenerator::Latex); + ol.disable(OutputGenerator::RTF); + } + LayoutNavEntry *lne = LayoutDocManager::instance().rootNavEntry()->find(LayoutNavEntry::ClassList); + if (lne==0) lne = LayoutDocManager::instance().rootNavEntry()->find(LayoutNavEntry::Classes); // fall back + QCString title = lne ? lne->title() : theTranslator->trCompoundList(); + bool addToIndex = lne==0 || lne->visible(); + + if (Config_getBool("OPTIMIZE_OUTPUT_VHDL")) + { + VhdlDocGen::findConstraintFile(lne); + } + + startFile(ol,"annotated",0,title,HLI_Annotated); + + startTitle(ol,0); + ol.parseText(title); + endTitle(ol,0,0); + + ol.startContents(); + + if (addToIndex) + { + Doxygen::indexList.addContentsItem(TRUE,title,0,"annotated",0,TRUE,TRUE); + Doxygen::indexList.incContentsDepth(); + } + + ol.startTextBlock(); + ol.parseText(lne ? lne->intro() : theTranslator->trCompoundListDescription()); + ol.endTextBlock(); + + writeAnnotatedClassList(ol); + + if (addToIndex) + { + Doxygen::indexList.decContentsDepth(); + } + + endFile(ol); // contains ol.endContents() + ol.popGeneratorState(); +} + +//---------------------------------------------------------------------------- +static void writeClassLinkForMember(OutputList &ol,MemberDef *md,const char *separator, + QCString &prevClassName) +{ + ClassDef *cd=md->getClassDef(); + if ( cd && prevClassName!=cd->displayName()) + { + ol.docify(separator); + ol.writeObjectLink(md->getReference(),md->getOutputFileBase(),md->anchor(), + cd->displayName()); + ol.writeString("\n"); + prevClassName = cd->displayName(); + } +} + +static void writeFileLinkForMember(OutputList &ol,MemberDef *md,const char *separator, + QCString &prevFileName) +{ + FileDef *fd=md->getFileDef(); + if (fd && prevFileName!=fd->name()) + { + ol.docify(separator); + ol.writeObjectLink(md->getReference(),md->getOutputFileBase(),md->anchor(), + fd->name()); + ol.writeString("\n"); + prevFileName = fd->name(); + } +} + +static void writeNamespaceLinkForMember(OutputList &ol,MemberDef *md,const char *separator, + QCString &prevNamespaceName) +{ + NamespaceDef *nd=md->getNamespaceDef(); + if (nd && prevNamespaceName!=nd->name()) + { + ol.docify(separator); + ol.writeObjectLink(md->getReference(),md->getOutputFileBase(),md->anchor(), + nd->name()); + ol.writeString("\n"); + prevNamespaceName = nd->name(); + } +} + +static void writeMemberList(OutputList &ol,bool useSections,int page, + MemberIndexList memberLists[MEMBER_INDEX_ENTRIES], + DefinitionIntf::DefType type) +{ + int pi; + // page==-1 => write all member indices to one page (used when total members is small) + // page!=-1 => write all member for this page only (used when total member is large) + int startIndex = page==-1 ? 0 : page; + int endIndex = page==-1 ? MEMBER_INDEX_ENTRIES-1 : page; + ASSERT((int)type<3); + + typedef void (*writeLinkForMember_t)(OutputList &ol,MemberDef *md,const char *separator, + QCString &prevNamespaceName); + + // each index tab has its own write function + static writeLinkForMember_t writeLinkForMemberMap[3] = + { + &writeClassLinkForMember, + &writeFileLinkForMember, + &writeNamespaceLinkForMember + }; + QCString prevName; + QCString prevDefName; + bool first=TRUE; + bool firstSection=TRUE; + bool firstItem=TRUE; + for (pi=startIndex; pi<=endIndex; pi++) // page==-1 => pi=[0..127], page!=-1 => pi=page + { + MemberIndexList *ml = &memberLists[pi]; + if (ml->count()==0) continue; + ml->sort(); + QListIterator mli(*ml); + MemberDef *md; + for (mli.toFirst();(md=mli.current());++mli) + { + const char *sep; + bool isFunc=!md->isObjCMethod() && + (md->isFunction() || md->isSlot() || md->isSignal()); + QCString name=md->name(); + int startIndex = getPrefixIndex(name); + if (QCString(name.data()+startIndex)!=prevName) // new entry + { + if ((prevName.isEmpty() || + tolower(name.at(startIndex))!=tolower(prevName.at(0))) && + useSections) // new section + { + if (!firstItem) ol.endItemListItem(); + if (!firstSection) ol.endItemList(); + char cl[2]; + cl[0] = tolower(name.at(startIndex)); + cl[1] = 0; + QCString cs = letterToLabel(cl[0]); + QCString anchor=(QCString)"index_"+cs; + QCString title=(QCString)"- "+cl+" -"; + ol.startSection(anchor,title,SectionInfo::Subsection); + ol.docify(title); + ol.endSection(anchor,SectionInfo::Subsection); + ol.startItemList(); + firstSection=FALSE; + firstItem=TRUE; + } + else if (!useSections && first) + { + ol.startItemList(); + first=FALSE; + } + + // member name + if (!firstItem) ol.endItemListItem(); + ol.startItemListItem(); + firstItem=FALSE; + ol.docify(name); + if (isFunc) ol.docify("()"); + ol.writeString("\n"); + + // link to class + prevDefName=""; + sep = ": "; + prevName = name.data()+startIndex; + } + else // same entry + { + sep = ", "; + // link to class for other members with the same name + } + // write the link for the specific list type + writeLinkForMemberMap[(int)type](ol,md,sep,prevDefName); + } + } + if (!firstItem) ol.endItemListItem(); + ol.endItemList(); +} + +//---------------------------------------------------------------------------- + +void initClassMemberIndices() +{ + int i=0; + int j=0; + for (j=0;jisLinkableInProject() && + (cd=md->getClassDef()) && + cd->isLinkableInProject() && + cd->templateMaster()==0) + { + QCString n = md->name(); + int index = getPrefixIndex(n); + uchar charCode = (uchar)n.at(index); + uint letter = charCode<128 ? tolower(charCode) : charCode; + if (!n.isEmpty()) + { + bool isFriendToHide = hideFriendCompounds && + (QCString(md->typeString())=="friend class" || + QCString(md->typeString())=="friend struct" || + QCString(md->typeString())=="friend union"); + if (!(md->isFriend() && isFriendToHide)) + { + g_memberIndexLetterUsed[CMHL_All][letter].append(md); + documentedClassMembers[CMHL_All]++; + } + if (md->isFunction() || md->isSlot() || md->isSignal()) + { + g_memberIndexLetterUsed[CMHL_Functions][letter].append(md); + documentedClassMembers[CMHL_Functions]++; + } + else if (md->isVariable()) + { + g_memberIndexLetterUsed[CMHL_Variables][letter].append(md); + documentedClassMembers[CMHL_Variables]++; + } + else if (md->isTypedef()) + { + g_memberIndexLetterUsed[CMHL_Typedefs][letter].append(md); + documentedClassMembers[CMHL_Typedefs]++; + } + else if (md->isEnumerate()) + { + g_memberIndexLetterUsed[CMHL_Enums][letter].append(md); + documentedClassMembers[CMHL_Enums]++; + } + else if (md->isEnumValue()) + { + g_memberIndexLetterUsed[CMHL_EnumValues][letter].append(md); + documentedClassMembers[CMHL_EnumValues]++; + } + else if (md->isProperty()) + { + g_memberIndexLetterUsed[CMHL_Properties][letter].append(md); + documentedClassMembers[CMHL_Properties]++; + } + else if (md->isEvent()) + { + g_memberIndexLetterUsed[CMHL_Events][letter].append(md); + documentedClassMembers[CMHL_Events]++; + } + else if (md->isRelated() || md->isForeign() || + (md->isFriend() && !isFriendToHide)) + { + g_memberIndexLetterUsed[CMHL_Related][letter].append(md); + documentedClassMembers[CMHL_Related]++; + } + } + } +} + +//---------------------------------------------------------------------------- + +void initNamespaceMemberIndices() +{ + int i=0; + int j=0; + for (j=0;jgetNamespaceDef(); + if (nd && nd->isLinkableInProject() && md->isLinkableInProject()) + { + QCString n = md->name(); + int index = getPrefixIndex(n); + uchar charCode = (uchar)n.at(index); + uint letter = charCode<128 ? tolower(charCode) : charCode; + if (!n.isEmpty()) + { + g_namespaceIndexLetterUsed[NMHL_All][letter].append(md); + documentedNamespaceMembers[NMHL_All]++; + + if (md->isFunction()) + { + g_namespaceIndexLetterUsed[NMHL_Functions][letter].append(md); + documentedNamespaceMembers[NMHL_Functions]++; + } + else if (md->isVariable()) + { + g_namespaceIndexLetterUsed[NMHL_Variables][letter].append(md); + documentedNamespaceMembers[NMHL_Variables]++; + } + else if (md->isTypedef()) + { + g_namespaceIndexLetterUsed[NMHL_Typedefs][letter].append(md); + documentedNamespaceMembers[NMHL_Typedefs]++; + } + else if (md->isEnumerate()) + { + g_namespaceIndexLetterUsed[NMHL_Enums][letter].append(md); + documentedNamespaceMembers[NMHL_Enums]++; + } + else if (md->isEnumValue()) + { + g_namespaceIndexLetterUsed[NMHL_EnumValues][letter].append(md); + documentedNamespaceMembers[NMHL_EnumValues]++; + } + } + } +} + +//---------------------------------------------------------------------------- + +void initFileMemberIndices() +{ + int i=0; + int j=0; + for (j=0;jgetFileDef(); + if (fd && fd->isLinkableInProject() && md->isLinkableInProject()) + { + QCString n = md->name(); + int index = getPrefixIndex(n); + uchar charCode = (uchar)n.at(index); + uint letter = charCode<128 ? tolower(charCode) : charCode; + if (!n.isEmpty()) + { + g_fileIndexLetterUsed[FMHL_All][letter].append(md); + documentedFileMembers[FMHL_All]++; + + if (md->isFunction()) + { + g_fileIndexLetterUsed[FMHL_Functions][letter].append(md); + documentedFileMembers[FMHL_Functions]++; + } + else if (md->isVariable()) + { + g_fileIndexLetterUsed[FMHL_Variables][letter].append(md); + documentedFileMembers[FMHL_Variables]++; + } + else if (md->isTypedef()) + { + g_fileIndexLetterUsed[FMHL_Typedefs][letter].append(md); + documentedFileMembers[FMHL_Typedefs]++; + } + else if (md->isEnumerate()) + { + g_fileIndexLetterUsed[FMHL_Enums][letter].append(md); + documentedFileMembers[FMHL_Enums]++; + } + else if (md->isEnumValue()) + { + g_fileIndexLetterUsed[FMHL_EnumValues][letter].append(md); + documentedFileMembers[FMHL_EnumValues]++; + } + else if (md->isDefine()) + { + g_fileIndexLetterUsed[FMHL_Defines][letter].append(md); + documentedFileMembers[FMHL_Defines]++; + } + } + } +} + +//---------------------------------------------------------------------------- + +static void writeQuickMemberIndex(OutputList &ol, + MemberIndexList charUsed[MEMBER_INDEX_ENTRIES],int page, + QCString fullName,bool multiPage) +{ + bool first=TRUE; + int i; + startQuickIndexList(ol,TRUE); + for (i=33;i<127;i++) + { + char is[2];is[0]=(char)i;is[1]='\0'; + QCString ci = letterToLabel((char)i); + if (charUsed[i].count()>0) + { + QCString anchor; + QCString extension=Doxygen::htmlFileExtension; + if (!multiPage) + anchor="#index_"; + else if (first) + anchor=fullName+extension+"#index_"; + else + anchor=fullName+QCString().sprintf("_0x%02x",i)+extension+"#index_"; + startQuickIndexItem(ol,anchor+ci,i==page,TRUE,first); + ol.writeString(is); + endQuickIndexItem(ol); + first=FALSE; + } + } + endQuickIndexList(ol); +} + +//---------------------------------------------------------------------------- + +struct CmhlInfo +{ + CmhlInfo(const char *fn,const char *t) : fname(fn), title(t) {} + const char *fname; + QCString title; +}; + +static const CmhlInfo *getCmhlInfo(int hl) +{ + static bool fortranOpt = Config_getBool("OPTIMIZE_FOR_FORTRAN"); + static bool vhdlOpt = Config_getBool("OPTIMIZE_OUTPUT_VHDL"); + static CmhlInfo cmhlInfo[] = + { + CmhlInfo("functions", theTranslator->trAll()), + CmhlInfo("functions_func", + fortranOpt ? theTranslator->trSubprograms() : + vhdlOpt ? VhdlDocGen::trFunctionAndProc() : + theTranslator->trFunctions()), + CmhlInfo("functions_vars",theTranslator->trVariables()), + CmhlInfo("functions_type",theTranslator->trTypedefs()), + CmhlInfo("functions_enum",theTranslator->trEnumerations()), + CmhlInfo("functions_eval",theTranslator->trEnumerationValues()), + CmhlInfo("functions_prop",theTranslator->trProperties()), + CmhlInfo("functions_evnt",theTranslator->trEvents()), + CmhlInfo("functions_rela",theTranslator->trRelatedFunctions()) + }; + return &cmhlInfo[hl]; +} + +static void writeClassMemberIndexFiltered(OutputList &ol, ClassMemberHighlight hl) +{ + if (documentedClassMembers[hl]==0) return; + + static bool disableIndex = Config_getBool("DISABLE_INDEX"); + + bool multiPageIndex=FALSE; + int numPages=1; + if (documentedClassMembers[hl]>MAX_ITEMS_BEFORE_MULTIPAGE_INDEX) + { + multiPageIndex=TRUE; + numPages=127; + } + + ol.pushGeneratorState(); + ol.disableAllBut(OutputGenerator::Html); + + QCString extension=Doxygen::htmlFileExtension; + LayoutNavEntry *lne = LayoutDocManager::instance().rootNavEntry()->find(LayoutNavEntry::ClassMembers); + QCString title = lne ? lne->title() : theTranslator->trCompoundMembers(); + if (hl!=CMHL_All) title+=(QCString)" - "+getCmhlInfo(hl)->title; + bool addToIndex = lne==0 || lne->visible(); + + if (addToIndex) + { + Doxygen::indexList.addContentsItem(multiPageIndex,getCmhlInfo(hl)->title,0, + getCmhlInfo(hl)->fname,0,multiPageIndex,TRUE); + if (multiPageIndex) Doxygen::indexList.incContentsDepth(); + } + + int page; + bool first=TRUE; + for (page=0;page0) + { + QCString fileName = getCmhlInfo(hl)->fname; + if (multiPageIndex) + { + if (!first) + { + fileName+=QCString().sprintf("_0x%02x",page); + } + char cs[2]; + cs[0]=page; + cs[1]=0; + if (addToIndex) + { + Doxygen::indexList.addContentsItem(FALSE,cs,0,fileName,0,FALSE,TRUE); + } + } + bool quickIndex = documentedClassMembers[hl]>maxItemsBeforeQuickIndex; + + ol.startFile(fileName+extension,0,title); + ol.startQuickIndices(); + if (!disableIndex) + { + ol.writeQuickLinks(TRUE,HLI_Functions,0); + startQuickIndexList(ol); + + // index item for global member list + startQuickIndexItem(ol, + getCmhlInfo(0)->fname+Doxygen::htmlFileExtension,hl==CMHL_All,TRUE,first); + ol.writeString(fixSpaces(getCmhlInfo(0)->title)); + endQuickIndexItem(ol); + + int i; + // index items per category member lists + for (i=1;i0) + { + startQuickIndexItem(ol,getCmhlInfo(i)->fname+Doxygen::htmlFileExtension,hl==i,TRUE,first); + ol.writeString(fixSpaces(getCmhlInfo(i)->title)); + //printf("multiPageIndex=%d first=%d fileName=%s file=%s title=%s\n", + // multiPageIndex,first,fileName.data(),getCmhlInfo(i)->fname,getCmhlInfo(i)->title.data()); + endQuickIndexItem(ol); + } + } + + endQuickIndexList(ol); + + // quick alphabetical index + if (quickIndex) + { + writeQuickMemberIndex(ol,g_memberIndexLetterUsed[hl],page, + getCmhlInfo(hl)->fname,multiPageIndex); + } + } + ol.endQuickIndices(); + ol.writeSplitBar(fileName); + ol.writeSearchInfo(); + + ol.startContents(); + + if (hl==CMHL_All) + { + ol.startTextBlock(); + ol.parseText(lne ? lne->intro() : theTranslator->trCompoundMembersDescription(Config_getBool("EXTRACT_ALL"))); + ol.endTextBlock(); + } + else + { + // hack to work around a mozilla bug, which refuses to switch to + // normal lists otherwise + ol.writeString(" "); + } + //ol.newParagraph(); // FIXME:PARA + writeMemberList(ol,quickIndex, + multiPageIndex?page:-1, + g_memberIndexLetterUsed[hl], + Definition::TypeClass); + endFile(ol); + first=FALSE; + } + } + + if (multiPageIndex && addToIndex) Doxygen::indexList.decContentsDepth(); + + ol.popGeneratorState(); +} + +static void writeClassMemberIndex(OutputList &ol) +{ + LayoutNavEntry *lne = LayoutDocManager::instance().rootNavEntry()->find(LayoutNavEntry::ClassMembers); + bool addToIndex = lne==0 || lne->visible(); + + if (documentedClassMembers[CMHL_All]>0 && addToIndex) + { + Doxygen::indexList.addContentsItem(TRUE,lne ? lne->title() : theTranslator->trCompoundMembers(),0,"functions",0); + Doxygen::indexList.incContentsDepth(); + } + writeClassMemberIndexFiltered(ol,CMHL_All); + writeClassMemberIndexFiltered(ol,CMHL_Functions); + writeClassMemberIndexFiltered(ol,CMHL_Variables); + writeClassMemberIndexFiltered(ol,CMHL_Typedefs); + writeClassMemberIndexFiltered(ol,CMHL_Enums); + writeClassMemberIndexFiltered(ol,CMHL_EnumValues); + writeClassMemberIndexFiltered(ol,CMHL_Properties); + writeClassMemberIndexFiltered(ol,CMHL_Events); + writeClassMemberIndexFiltered(ol,CMHL_Related); + if (documentedClassMembers[CMHL_All]>0 && addToIndex) + { + Doxygen::indexList.decContentsDepth(); + } + +} + +//---------------------------------------------------------------------------- + +struct FmhlInfo +{ + FmhlInfo(const char *fn,const char *t) : fname(fn), title(t) {} + const char *fname; + QCString title; +}; + +static const FmhlInfo *getFmhlInfo(int hl) +{ + static bool fortranOpt = Config_getBool("OPTIMIZE_FOR_FORTRAN"); + static bool vhdlOpt = Config_getBool("OPTIMIZE_OUTPUT_VHDL"); + static FmhlInfo fmhlInfo[] = + { + FmhlInfo("globals", theTranslator->trAll()), + FmhlInfo("globals_func", + fortranOpt ? theTranslator->trSubprograms() : + vhdlOpt ? VhdlDocGen::trFunctionAndProc() : + theTranslator->trFunctions()), + FmhlInfo("globals_vars",theTranslator->trVariables()), + FmhlInfo("globals_type",theTranslator->trTypedefs()), + FmhlInfo("globals_enum",theTranslator->trEnumerations()), + FmhlInfo("globals_eval",theTranslator->trEnumerationValues()), + FmhlInfo("globals_defs",theTranslator->trDefines()) + }; + return &fmhlInfo[hl]; +} + +static void writeFileMemberIndexFiltered(OutputList &ol, FileMemberHighlight hl) +{ + if (documentedFileMembers[hl]==0) return; + + static bool disableIndex = Config_getBool("DISABLE_INDEX"); + + bool multiPageIndex=FALSE; + int numPages=1; + if (documentedFileMembers[hl]>MAX_ITEMS_BEFORE_MULTIPAGE_INDEX) + { + multiPageIndex=TRUE; + numPages=127; + } + + ol.pushGeneratorState(); + ol.disableAllBut(OutputGenerator::Html); + + QCString extension=Doxygen::htmlFileExtension; + LayoutNavEntry *lne = LayoutDocManager::instance().rootNavEntry()->find(LayoutNavEntry::FileGlobals); + QCString title = lne ? lne->title() : theTranslator->trFileMembers(); + bool addToIndex = lne==0 || lne->visible(); + + if (addToIndex) + { + Doxygen::indexList.addContentsItem(multiPageIndex,getFmhlInfo(hl)->title,0, + getFmhlInfo(hl)->fname,0,multiPageIndex,TRUE); + if (multiPageIndex) Doxygen::indexList.incContentsDepth(); + } + + int page; + bool first=TRUE; + for (page=0;page0) + { + QCString fileName = getFmhlInfo(hl)->fname; + if (multiPageIndex) + { + if (!first) + { + fileName+=QCString().sprintf("_0x%02x",page); + } + char cs[2]; + cs[0]=page; + cs[1]=0; + if (addToIndex) + { + Doxygen::indexList.addContentsItem(FALSE,cs,0,fileName,0,FALSE,TRUE); + } + } + bool quickIndex = documentedFileMembers[hl]>maxItemsBeforeQuickIndex; + + ol.startFile(fileName+extension,0,title); + ol.startQuickIndices(); + if (!disableIndex) + { + ol.writeQuickLinks(TRUE,HLI_Globals,0); + startQuickIndexList(ol); + + // index item for all file member lists + startQuickIndexItem(ol, + getFmhlInfo(0)->fname+Doxygen::htmlFileExtension,hl==FMHL_All,TRUE,first); + ol.writeString(fixSpaces(getFmhlInfo(0)->title)); + endQuickIndexItem(ol); + + int i; + // index items for per category member lists + for (i=1;i0) + { + startQuickIndexItem(ol, + getFmhlInfo(i)->fname+Doxygen::htmlFileExtension,hl==i,TRUE,first); + ol.writeString(fixSpaces(getFmhlInfo(i)->title)); + endQuickIndexItem(ol); + } + } + + endQuickIndexList(ol); + + if (quickIndex) + { + writeQuickMemberIndex(ol,g_fileIndexLetterUsed[hl],page, + getFmhlInfo(hl)->fname,multiPageIndex); + } + } + ol.endQuickIndices(); + ol.writeSplitBar(fileName); + ol.writeSearchInfo(); + + ol.startContents(); + + if (hl==FMHL_All) + { + ol.startTextBlock(); + ol.parseText(lne ? lne->intro() : theTranslator->trFileMembersDescription(Config_getBool("EXTRACT_ALL"))); + ol.endTextBlock(); + } + else + { + // hack to work around a mozilla bug, which refuses to switch to + // normal lists otherwise + ol.writeString(" "); + } + //ol.newParagraph(); // FIXME:PARA + //writeFileMemberList(ol,quickIndex,hl,page); + writeMemberList(ol,quickIndex, + multiPageIndex?page:-1, + g_fileIndexLetterUsed[hl], + Definition::TypeFile); + endFile(ol); + first=FALSE; + } + } + if (multiPageIndex && addToIndex) Doxygen::indexList.decContentsDepth(); + ol.popGeneratorState(); +} + +static void writeFileMemberIndex(OutputList &ol) +{ + LayoutNavEntry *lne = LayoutDocManager::instance().rootNavEntry()->find(LayoutNavEntry::FileGlobals); + bool addToIndex = lne==0 || lne->visible(); + if (documentedFileMembers[FMHL_All]>0 && addToIndex) + { + Doxygen::indexList.addContentsItem(FALSE,lne ? lne->title() : theTranslator->trFileMembers(),0,"globals",0); + Doxygen::indexList.incContentsDepth(); + } + writeFileMemberIndexFiltered(ol,FMHL_All); + writeFileMemberIndexFiltered(ol,FMHL_Functions); + writeFileMemberIndexFiltered(ol,FMHL_Variables); + writeFileMemberIndexFiltered(ol,FMHL_Typedefs); + writeFileMemberIndexFiltered(ol,FMHL_Enums); + writeFileMemberIndexFiltered(ol,FMHL_EnumValues); + writeFileMemberIndexFiltered(ol,FMHL_Defines); + if (documentedFileMembers[FMHL_All]>0 && addToIndex) + { + Doxygen::indexList.decContentsDepth(); + } + +} + +//---------------------------------------------------------------------------- + +struct NmhlInfo +{ + NmhlInfo(const char *fn,const char *t) : fname(fn), title(t) {} + const char *fname; + QCString title; +}; + +static const NmhlInfo *getNmhlInfo(int hl) +{ + static bool fortranOpt = Config_getBool("OPTIMIZE_FOR_FORTRAN"); + static bool vhdlOpt = Config_getBool("OPTIMIZE_OUTPUT_VHDL"); + static NmhlInfo nmhlInfo[] = + { + NmhlInfo("namespacemembers", theTranslator->trAll()), + NmhlInfo("namespacemembers_func", + fortranOpt ? theTranslator->trSubprograms() : + vhdlOpt ? VhdlDocGen::trFunctionAndProc() : + theTranslator->trFunctions()), + NmhlInfo("namespacemembers_vars",theTranslator->trVariables()), + NmhlInfo("namespacemembers_type",theTranslator->trTypedefs()), + NmhlInfo("namespacemembers_enum",theTranslator->trEnumerations()), + NmhlInfo("namespacemembers_eval",theTranslator->trEnumerationValues()) + }; + return &nmhlInfo[hl]; +} + +//---------------------------------------------------------------------------- + +static void writeNamespaceMemberIndexFiltered(OutputList &ol, + NamespaceMemberHighlight hl) +{ + if (documentedNamespaceMembers[hl]==0) return; + + static bool disableIndex = Config_getBool("DISABLE_INDEX"); + + + bool multiPageIndex=FALSE; + int numPages=1; + if (documentedNamespaceMembers[hl]>MAX_ITEMS_BEFORE_MULTIPAGE_INDEX) + { + multiPageIndex=TRUE; + numPages=127; + } + + ol.pushGeneratorState(); + ol.disableAllBut(OutputGenerator::Html); + + QCString extension=Doxygen::htmlFileExtension; + LayoutNavEntry *lne = LayoutDocManager::instance().rootNavEntry()->find(LayoutNavEntry::NamespaceMembers); + QCString title = lne ? lne->title() : theTranslator->trNamespaceMembers(); + bool addToIndex = lne==0 || lne->visible(); + + if (addToIndex) + { + Doxygen::indexList.addContentsItem(multiPageIndex,getNmhlInfo(hl)->title,0, + getNmhlInfo(hl)->fname,0,multiPageIndex,TRUE); + if (multiPageIndex) Doxygen::indexList.incContentsDepth(); + } + + int page; + bool first=TRUE; + for (page=0;page0) + { + QCString fileName = getNmhlInfo(hl)->fname; + if (multiPageIndex) + { + if (!first) + { + fileName+=QCString().sprintf("_0x%02x",page); + } + char cs[2]; + cs[0]=page; + cs[1]=0; + if (addToIndex) + { + Doxygen::indexList.addContentsItem(FALSE,cs,0,fileName,0,FALSE,TRUE); + } + } + bool quickIndex = documentedNamespaceMembers[hl]>maxItemsBeforeQuickIndex; + + ol.startFile(fileName+extension,0,title); + ol.startQuickIndices(); + if (!disableIndex) + { + ol.writeQuickLinks(TRUE,HLI_NamespaceMembers,0); + startQuickIndexList(ol); + + // index item for all namespace member lists + startQuickIndexItem(ol, + getNmhlInfo(0)->fname+Doxygen::htmlFileExtension,hl==NMHL_All,TRUE,first); + ol.writeString(fixSpaces(getNmhlInfo(0)->title)); + endQuickIndexItem(ol); + + int i; + // index items per category member lists + for (i=1;i0) + { + startQuickIndexItem(ol, + getNmhlInfo(i)->fname+Doxygen::htmlFileExtension,hl==i,TRUE,first); + ol.writeString(fixSpaces(getNmhlInfo(i)->title)); + endQuickIndexItem(ol); + } + } + + endQuickIndexList(ol); + + if (quickIndex) + { + writeQuickMemberIndex(ol,g_namespaceIndexLetterUsed[hl],page, + getNmhlInfo(hl)->fname,multiPageIndex); + } + + } + ol.endQuickIndices(); + ol.writeSplitBar(fileName); + ol.writeSearchInfo(); + + ol.startContents(); + + if (hl==NMHL_All) + { + ol.startTextBlock(); + ol.parseText(lne ? lne->intro() : theTranslator->trNamespaceMemberDescription(Config_getBool("EXTRACT_ALL"))); + ol.endTextBlock(); + } + else + { + // hack to work around a mozilla bug, which refuses to switch to + // normal lists otherwise + ol.writeString(" "); + } + //ol.newParagraph(); // FIXME:PARA + + //writeNamespaceMemberList(ol,quickIndex,hl,page); + writeMemberList(ol,quickIndex, + multiPageIndex?page:-1, + g_namespaceIndexLetterUsed[hl], + Definition::TypeNamespace); + endFile(ol); + } + } + if (multiPageIndex && addToIndex) Doxygen::indexList.decContentsDepth(); + ol.popGeneratorState(); +} + +static void writeNamespaceMemberIndex(OutputList &ol) +{ + LayoutNavEntry *lne = LayoutDocManager::instance().rootNavEntry()->find(LayoutNavEntry::NamespaceMembers); + bool addToIndex = lne==0 || lne->visible(); + if (documentedNamespaceMembers[NMHL_All]>0 && addToIndex) + { + Doxygen::indexList.addContentsItem(FALSE,lne ? lne->title() : theTranslator->trNamespaceMembers(),0,"namespacemembers",0); + Doxygen::indexList.incContentsDepth(); + } + //bool fortranOpt = Config_getBool("OPTIMIZE_FOR_FORTRAN"); + writeNamespaceMemberIndexFiltered(ol,NMHL_All); + writeNamespaceMemberIndexFiltered(ol,NMHL_Functions); + writeNamespaceMemberIndexFiltered(ol,NMHL_Variables); + writeNamespaceMemberIndexFiltered(ol,NMHL_Typedefs); + writeNamespaceMemberIndexFiltered(ol,NMHL_Enums); + writeNamespaceMemberIndexFiltered(ol,NMHL_EnumValues); + if (documentedNamespaceMembers[NMHL_All]>0 && addToIndex) + { + Doxygen::indexList.decContentsDepth(); + } + +} + +//---------------------------------------------------------------------------- + +//---------------------------------------------------------------------------- + +static void writeExampleIndex(OutputList &ol) +{ + if (Doxygen::exampleSDict->count()==0) return; + ol.pushGeneratorState(); + ol.disable(OutputGenerator::Man); + LayoutNavEntry *lne = LayoutDocManager::instance().rootNavEntry()->find(LayoutNavEntry::Examples); + QCString title = lne ? lne->title() : theTranslator->trExamples(); + bool addToIndex = lne==0 || lne->visible(); + + startFile(ol,"examples",0,title,HLI_Examples); + + startTitle(ol,0); + ol.parseText(title); + endTitle(ol,0,0); + + ol.startContents(); + + if (addToIndex) + { + Doxygen::indexList.addContentsItem(TRUE,title,0,"examples",0,TRUE,TRUE); + Doxygen::indexList.incContentsDepth(); + } + + ol.startTextBlock(); + ol.parseText(lne ? lne->intro() : theTranslator->trExamplesDescription()); + ol.endTextBlock(); + + ol.startItemList(); + PageSDict::Iterator pdi(*Doxygen::exampleSDict); + PageDef *pd=0; + for (pdi.toFirst();(pd=pdi.current());++pdi) + { + ol.startItemListItem(); + QCString n=pd->getOutputFileBase(); + if (!pd->title().isEmpty()) + { + ol.writeObjectLink(0,n,0,pd->title()); + if (addToIndex) + { + Doxygen::indexList.addContentsItem(FALSE,filterTitle(pd->title()),pd->getReference(),n,0,FALSE,TRUE); + } + } + else + { + ol.writeObjectLink(0,n,0,pd->name()); + if (addToIndex) + { + Doxygen::indexList.addContentsItem(FALSE,pd->name(),pd->getReference(),n,0,FALSE,TRUE); + } + } + ol.endItemListItem(); + ol.writeString("\n"); + } + ol.endItemList(); + + if (addToIndex) + { + Doxygen::indexList.decContentsDepth(); + } + endFile(ol); + ol.popGeneratorState(); +} + + +//---------------------------------------------------------------------------- + +template +bool writeMemberNavIndex(FTextStream &t, + int indent, + int n, + int documentedMembers[], + MemberIndexList indexLetterUsed[][MEMBER_INDEX_ENTRIES], + const T *(*getInfo)(int), + bool &first + ) + +{ + bool found=FALSE; + QCString indentStr; + indentStr.fill(' ',indent*2); + // index items per category member lists + int i; + for (i=0;i0; + bool quickIndex = documentedMembers[i]>maxItemsBeforeQuickIndex; + bool multiIndexPage = documentedMembers[i]>MAX_ITEMS_BEFORE_MULTIPAGE_INDEX; + if (hasIndex) + { + // terminate previous entry + if (!first) t << "," << endl; + first = FALSE; + + // start entry + if (!found) + { + t << "[" << endl; + } + found = TRUE; + + t << indentStr << " [ "; + t << "\"" << fixSpaces(getInfo(i)->title) << "\", "; + t << "\"" << getInfo(i)->fname << Doxygen::htmlFileExtension << "\", "; + bool firstPage=TRUE; + if (quickIndex) + { + t << "[ " << endl; + int j; + for (j=33;j<127;j++) + { + if (indexLetterUsed[i][j].count()>0) + { + if (!firstPage) t << "," << endl; + QCString fullName = getInfo(i)->fname; + QCString extension = Doxygen::htmlFileExtension; + QCString anchor; + if (firstPage || !multiIndexPage) + anchor=fullName+extension+"#index_"; + else + anchor=fullName+QCString().sprintf("_0x%02x",j)+extension+"#index_"; + char is[2];is[0]=(char)j;is[1]='\0'; + QCString ci = letterToLabel((char)j); + t << indentStr << " [ "; + t << "\"" << is << "\", "; + t << "\"" << anchor << ci << "\", null ]"; + firstPage=FALSE; + } + } + t << endl << indentStr << " ] ]"; + } + else + { + t << "null" << " ]"; + } + } + } + return found; +} + +//---------------------------------------------------------------------------- + +static bool writeFullNavIndex(FTextStream &t, LayoutNavEntry *root,int indent,bool &first) +{ + static struct NavEntryCountMap + { + LayoutNavEntry::Kind kind; + bool hasItems; + } navEntryCountMap[] = + { + { LayoutNavEntry::MainPage, TRUE }, + { LayoutNavEntry::Pages, indexedPages>0 }, + { LayoutNavEntry::Modules, documentedGroups>0 }, + { LayoutNavEntry::Namespaces, documentedNamespaces>0 }, + { LayoutNavEntry::NamespaceList, documentedNamespaces>0 }, + { LayoutNavEntry::NamespaceMembers, documentedNamespaceMembers[NMHL_All]>0 }, + { LayoutNavEntry::Classes, annotatedClasses>0 }, + { LayoutNavEntry::ClassList, annotatedClasses>0 }, + { LayoutNavEntry::ClassIndex, annotatedClasses>0 }, + { LayoutNavEntry::ClassHierarchy, hierarchyClasses>0 }, + { LayoutNavEntry::ClassMembers, documentedClassMembers[CMHL_All]>0 }, + { LayoutNavEntry::Files, documentedFiles>0 }, + { LayoutNavEntry::FileList, documentedFiles>0 }, + { LayoutNavEntry::FileGlobals, documentedFileMembers[FMHL_All]>0 }, + { LayoutNavEntry::Dirs, documentedDirs>0 }, + { LayoutNavEntry::Examples, Doxygen::exampleSDict->count()>0 } + }; + + QCString indentStr; + indentStr.fill(' ',indent*2); + bool found=FALSE; + if (root->children().count()>0) + { + QListIterator li(root->children()); + LayoutNavEntry *entry; + for (li.toFirst();(entry=li.current());++li) + { + if (navEntryCountMap[entry->kind()].hasItems && entry->visible()) + { + // terminate previous entry + if (!first) t << "," << endl; + first = FALSE; + + // start entry + if (!found) + { + t << "[" << endl; + } + found = TRUE; + + bool emptySection=TRUE; + t << indentStr << " [ "; + t << "\"" << fixSpaces(entry->title()) << "\", "; + t << "\"" << entry->baseFile() << Doxygen::htmlFileExtension << "\", "; + + // write children (if any) + bool firstChild=TRUE; + if (entry->kind()==LayoutNavEntry::ClassMembers) + { + emptySection = !writeMemberNavIndex(t,indent+1,CMHL_Total,documentedClassMembers,g_memberIndexLetterUsed,&getCmhlInfo,firstChild); + } + else if (entry->kind()==LayoutNavEntry::NamespaceMembers) + { + emptySection = !writeMemberNavIndex(t,indent+1,NMHL_Total,documentedNamespaceMembers,g_namespaceIndexLetterUsed,&getNmhlInfo,firstChild); + } + else if (entry->kind()==LayoutNavEntry::FileGlobals) + { + emptySection = !writeMemberNavIndex(t,indent+1,FMHL_Total,documentedFileMembers,g_fileIndexLetterUsed,&getFmhlInfo,firstChild); + } + else + { + emptySection = !writeFullNavIndex(t,entry,indent+1,firstChild); + } + // end entry + if (emptySection) // entry without children + t << "null ]"; + else // entry with children + t << endl << indentStr << " ] ]"; + } + } + } + return found; +} + +//---------------------------------------------------------------------------- + +static void countRelatedPages(int &docPages,int &indexPages) +{ + docPages=indexPages=0; + PageSDict::Iterator pdi(*Doxygen::pageSDict); + PageDef *pd=0; + for (pdi.toFirst();(pd=pdi.current());++pdi) + { + if ( pd->visibleInIndex()) + { + indexPages++; + } + if ( pd->documentedPage()) + { + docPages++; + } + } +} + +//---------------------------------------------------------------------------- + +static void writeSubPages(PageDef *pd) +{ + LayoutNavEntry *lne = LayoutDocManager::instance().rootNavEntry()->find(LayoutNavEntry::Pages); + bool addToIndex = lne==0 || lne->visible(); + //printf("Write subpages(%s #=%d)\n",pd->name().data(),pd->getSubPages() ? pd->getSubPages()->count() : 0 ); + PageSDict *subPages = pd->getSubPages(); + if (subPages) + { + PageSDict::Iterator pi(*subPages); + PageDef *subPage; + for (pi.toFirst();(subPage=pi.current());++pi) + { + QCString pageTitle; + + if (subPage->title().isEmpty()) + pageTitle=subPage->name(); + else + pageTitle=subPage->title(); + + bool hasSubPages = subPage->hasSubPages(); + bool hasSections = subPage->hasSections(); + + //printf("subpage %s: addToIndex=%d hasSubPages=%d hasSections=%d\n", + // pd->name().data(),addToIndex,hasSubPages,hasSections); + if (addToIndex) + { + Doxygen::indexList.addContentsItem(hasSubPages,pageTitle, + subPage->getReference(),subPage->getOutputFileBase(), + 0,hasSubPages,TRUE); + if (hasSections || hasSubPages) + { + Doxygen::indexList.incContentsDepth(); + } + if (hasSections) + { + subPage->addSectionsToIndex(); + } + } + writeSubPages(subPage); + if (addToIndex && (hasSections || hasSubPages)) + { + Doxygen::indexList.decContentsDepth(); + } + } + } +} + +static void writePageIndex(OutputList &ol) +{ + if (indexedPages==0) return; + ol.pushGeneratorState(); + ol.disableAllBut(OutputGenerator::Html); + LayoutNavEntry *lne = LayoutDocManager::instance().rootNavEntry()->find(LayoutNavEntry::Pages); + QCString title = lne ? lne->title() : theTranslator->trRelatedPages(); + startFile(ol,"pages",0,title,HLI_Pages); + startTitle(ol,0); + ol.parseText(title); + endTitle(ol,0,0); + ol.startContents(); + ol.startTextBlock(); + bool addToIndex = lne==0 || lne->visible(); + if (0 /*addToIndex*/) // skip Related Pages section in navigation index + { + Doxygen::indexList.addContentsItem(TRUE,title,0,"pages",0,TRUE,TRUE); + Doxygen::indexList.incContentsDepth(); + } + ol.parseText(lne ? lne->intro() : theTranslator->trRelatedPagesDescription()); + ol.endTextBlock(); + startIndexHierarchy(ol,0); + PageSDict::Iterator pdi(*Doxygen::pageSDict); + PageDef *pd=0; + for (pdi.toFirst();(pd=pdi.current());++pdi) + { + if (pd->visibleInIndex()) + { + QCString pageTitle; + + if (pd->title().isEmpty()) + pageTitle=pd->name(); + else + pageTitle=pd->title(); + + bool hasSubPages = pd->hasSubPages(); + bool hasSections = pd->hasSections(); + + ol.startIndexListItem(); + ol.startIndexItem(pd->getReference(),pd->getOutputFileBase()); + ol.parseText(pageTitle); + ol.endIndexItem(pd->getReference(),pd->getOutputFileBase()); + if (pd->isReference()) + { + ol.startTypewriter(); + ol.docify(" [external]"); + ol.endTypewriter(); + } + ol.writeString("\n"); + if (addToIndex) + { + Doxygen::indexList.addContentsItem( + hasSubPages || hasSections, // isDir + filterTitle(pageTitle), // name + pd->getReference(), // ref + pd->getOutputFileBase(), // file + 0, // anchor + hasSubPages || hasSections, // separateIndex + TRUE); // addToNavIndex + if (hasSections || hasSubPages) + { + Doxygen::indexList.incContentsDepth(); + } + if (hasSections) + { + pd->addSectionsToIndex(); + } + } + writeSubPages(pd); + if (addToIndex && (hasSections || hasSubPages)) + { + Doxygen::indexList.decContentsDepth(); + } + ol.endIndexListItem(); + } + } + endIndexHierarchy(ol,0); + if (0 /*addToIndex*/) // skip Related Pages section in navigation index + { + Doxygen::indexList.decContentsDepth(); + } + endFile(ol); + ol.popGeneratorState(); +} + +//---------------------------------------------------------------------------- + +static int countGroups() +{ + int count=0; + GroupSDict::Iterator gli(*Doxygen::groupSDict); + GroupDef *gd; + for (gli.toFirst();(gd=gli.current());++gli) + { + if (!gd->isReference()) + { + gd->visited=FALSE; + count++; + } + } + return count; +} + +//---------------------------------------------------------------------------- + +static int countDirs() +{ + int count=0; + SDict::Iterator dli(*Doxygen::directories); + DirDef *dd; + for (dli.toFirst();(dd=dli.current());++dli) + { + if (dd->isLinkableInProject()) + { + dd->visited=FALSE; + count++; + } + } + return count; +} + + +//---------------------------------------------------------------------------- + +void writeGraphInfo(OutputList &ol) +{ + if (!Config_getBool("HAVE_DOT") || !Config_getBool("GENERATE_HTML")) return; + ol.pushGeneratorState(); + ol.disableAllBut(OutputGenerator::Html); + generateGraphLegend(Config_getString("HTML_OUTPUT")); + startFile(ol,"graph_legend",0,theTranslator->trLegendTitle().data()); + startTitle(ol,0); + ol.parseText(theTranslator->trLegendTitle()); + endTitle(ol,0,0); + ol.startContents(); + bool &stripCommentsStateRef = Config_getBool("STRIP_CODE_COMMENTS"); + bool oldStripCommentsState = stripCommentsStateRef; + // temporarily disable the stripping of comments for our own code example! + stripCommentsStateRef = FALSE; + QCString legendDocs = theTranslator->trLegendDocs(); + int s = legendDocs.find("
        "); + int e = legendDocs.find("
        "); + if (Config_getEnum("DOT_IMAGE_FORMAT")=="svg" && s!=-1 && e!=-1) + { + legendDocs = legendDocs.left(s+8) + "[!-- SVG 0 --]\n" + legendDocs.mid(e); + //printf("legendDocs=%s\n",legendDocs.data()); + } + ol.parseDoc("graph_legend",1,0,0,legendDocs,FALSE,FALSE); + stripCommentsStateRef = oldStripCommentsState; + endFile(ol); + ol.popGeneratorState(); +} + + + +//---------------------------------------------------------------------------- +/*! + * write groups as hierarchical trees + */ +static void writeGroupTreeNode(OutputList &ol, GroupDef *gd, int level, FTVHelp* ftv, bool addToIndex) +{ + //bool fortranOpt = Config_getBool("OPTIMIZE_FOR_FORTRAN"); + //bool vhdlOpt = Config_getBool("OPTIMIZE_OUTPUT_VHDL"); + if (level>20) + { + warn(gd->getDefFileName(),gd->getDefLine(), + "warning: maximum nesting level exceeded for group %s: check for possible recursive group relation!\n",gd->name().data() + ); + return; + } + + /* Some groups should appear twice under different parent-groups. + * That is why we should not check if it was visited + */ + if (/*!gd->visited &&*/ (!gd->isASubGroup() || level>0) && + gd->isVisible() && + (!gd->isReference() || Config_getBool("EXTERNAL_GROUPS")) // hide external groups by default + ) + { + //printf("gd->name()=%s #members=%d\n",gd->name().data(),gd->countMembers()); + // write group info + bool hasSubGroups = gd->getSubGroups()->count()>0; + bool hasSubPages = gd->getPages()->count()>0; + int numSubItems = 0; + if (1 /*Config_getBool("TOC_EXPAND")*/) + { + QListIterator mli(gd->getMemberLists()); + MemberList *ml; + for (mli.toFirst();(ml=mli.current());++mli) + { + if (ml->listType()&MemberList::documentationLists) + { + numSubItems += ml->count(); + } + } + numSubItems += gd->getNamespaces()->count(); + numSubItems += gd->getClasses()->count(); + numSubItems += gd->getFiles()->count(); + numSubItems += gd->getDirs()->count(); + numSubItems += gd->getPages()->count(); + } + + bool isDir = hasSubGroups || hasSubPages || numSubItems>0; + //printf("gd=`%s': pageDict=%d\n",gd->name().data(),gd->pageDict->count()); + if (addToIndex) + { + Doxygen::indexList.addContentsItem(isDir,gd->groupTitle(),gd->getReference(),gd->getOutputFileBase(),0,isDir,TRUE); + Doxygen::indexList.incContentsDepth(); + } + if (ftv) + { + ftv->addContentsItem(hasSubGroups,gd->groupTitle(),gd->getReference(),gd->getOutputFileBase(),0); + ftv->incContentsDepth(); + } + + //ol.writeListItem(); + //ol.startTextLink(gd->getOutputFileBase(),0); + //parseText(ol,gd->groupTitle()); + //ol.endTextLink(); + + ol.startIndexListItem(); + ol.startIndexItem(gd->getReference(),gd->getOutputFileBase()); + ol.parseText(gd->groupTitle()); + ol.endIndexItem(gd->getReference(),gd->getOutputFileBase()); + if (gd->isReference()) + { + ol.startTypewriter(); + ol.docify(" [external]"); + ol.endTypewriter(); + } + + QListIterator eli(LayoutDocManager::instance().docEntries(LayoutDocManager::Group)); + LayoutDocEntry *lde; + for (eli.toFirst();(lde=eli.current());++eli) + { + if (lde->kind()==LayoutDocEntry::MemberDef && addToIndex) + { + LayoutDocEntryMemberDef *lmd = (LayoutDocEntryMemberDef*)lde; + MemberList *ml = gd->getMemberList(lmd->type); + if (ml) + { + MemberListIterator mi(*ml); + MemberDef *md; + for (mi.toFirst();(md=mi.current());++mi) + { + if (md->isVisible() && md->name().find('@')==-1) + { + Doxygen::indexList.addContentsItem(FALSE, + md->name(),md->getReference(), + md->getOutputFileBase(),md->anchor(),FALSE); + } + } + } + } + else if (lde->kind()==LayoutDocEntry::GroupClasses && addToIndex) + { + ClassSDict::Iterator it(*gd->getClasses()); + ClassDef *cd; + for (;(cd=it.current());++it) + { + if (cd->isVisible()) + { + Doxygen::indexList.addContentsItem(FALSE, + cd->localName(),cd->getReference(), + cd->getOutputFileBase(),cd->anchor(),FALSE,FALSE); + } + } + } + else if (lde->kind()==LayoutDocEntry::GroupNamespaces && addToIndex) + { + NamespaceSDict::Iterator it(*gd->getNamespaces()); + NamespaceDef *nd; + for (;(nd=it.current());++it) + { + if (nd->isVisible()) + { + Doxygen::indexList.addContentsItem(FALSE, + nd->localName(),nd->getReference(), + nd->getOutputFileBase(),0,FALSE,FALSE); + } + } + } + else if (lde->kind()==LayoutDocEntry::GroupFiles && addToIndex) + { + QListIterator it(*gd->getFiles()); + FileDef *fd; + for (;(fd=it.current());++it) + { + if (fd->isVisible()) + { + Doxygen::indexList.addContentsItem(FALSE, + fd->displayName(),fd->getReference(), + fd->getOutputFileBase(),0,FALSE,FALSE); + } + } + } + else if (lde->kind()==LayoutDocEntry::GroupDirs && addToIndex) + { + static bool showDirs = Config_getBool("SHOW_DIRECTORIES"); + if (showDirs) + { + QListIterator it(*gd->getDirs()); + DirDef *dd; + for (;(dd=it.current());++it) + { + if (dd->isVisible()) + { + Doxygen::indexList.addContentsItem(FALSE, + dd->shortName(),dd->getReference(), + dd->getOutputFileBase(),0,FALSE,FALSE); + } + } + } + } + else if (lde->kind()==LayoutDocEntry::GroupPageDocs && addToIndex) + { + SDict::Iterator it(*gd->getPages()); + PageDef *pd; + for (;(pd=it.current());++it) + { + SectionInfo *si=0; + if (!pd->name().isEmpty()) si=Doxygen::sectionDict[pd->name()]; + bool hasSubPages = pd->hasSubPages(); + bool hasSections = pd->hasSections(); + Doxygen::indexList.addContentsItem( + hasSubPages || hasSections, + convertToHtml(pd->title(),TRUE), + gd->getReference(), + gd->getOutputFileBase(), + si ? si->label.data() : 0, + hasSubPages || hasSections, + TRUE); // addToNavIndex + if (hasSections || hasSubPages) + { + Doxygen::indexList.incContentsDepth(); + } + if (hasSections) + { + pd->addSectionsToIndex(); + } + writeSubPages(pd); + if (hasSections || hasSubPages) + { + Doxygen::indexList.decContentsDepth(); + } + } + } + else if (lde->kind()==LayoutDocEntry::GroupNestedGroups) + { + if (gd->getSubGroups()->count()>0) + { + startIndexHierarchy(ol,level+1); + if (Config_getBool("SORT_GROUP_NAMES")) gd->sortSubGroups(); + QListIterator gli(*gd->getSubGroups()); + GroupDef *subgd = 0; + for (gli.toFirst();(subgd=gli.current());++gli) + { + writeGroupTreeNode(ol,subgd,level+1,ftv,addToIndex); + } + endIndexHierarchy(ol,level+1); + } + } + } + + ol.endIndexListItem(); + + if (addToIndex) + { + Doxygen::indexList.decContentsDepth(); + } + if (ftv) + { + ftv->decContentsDepth(); + } + //gd->visited=TRUE; + } +} + +static void writeGroupHierarchy(OutputList &ol, FTVHelp* ftv,bool addToIndex) +{ + if (ftv) + { + ol.pushGeneratorState(); + ol.disable(OutputGenerator::Html); + } + startIndexHierarchy(ol,0); + if (Config_getBool("SORT_GROUP_NAMES")) + { + Doxygen::groupSDict->sort(); + } + GroupSDict::Iterator gli(*Doxygen::groupSDict); + GroupDef *gd; + for (gli.toFirst();(gd=gli.current());++gli) + { + writeGroupTreeNode(ol,gd,0,ftv,addToIndex); + } + endIndexHierarchy(ol,0); + if (ftv) + { + ol.popGeneratorState(); + } +} + +//---------------------------------------------------------------------------- +static void writeDirTreeNode(OutputList &ol, DirDef *dd, int level, FTVHelp* ftv,bool addToIndex) +{ + if (level>20) + { + warn(dd->getDefFileName(),dd->getDefLine(), + "warning: maximum nesting level exceeded for directory %s: " + "check for possible recursive directory relation!\n",dd->name().data() + ); + return; + } + + static bool tocExpand = TRUE; //Config_getBool("TOC_EXPAND"); + bool isDir = dd->subDirs().count()>0 || // there are subdirs + (tocExpand && // or toc expand and + dd->getFiles() && dd->getFiles()->count()>0 // there are files + ); + //printf("gd=`%s': pageDict=%d\n",gd->name().data(),gd->pageDict->count()); + if (addToIndex) + { + Doxygen::indexList.addContentsItem(isDir,dd->shortName(),dd->getReference(),dd->getOutputFileBase(),0,TRUE,TRUE); + Doxygen::indexList.incContentsDepth(); + } + if (ftv) + { + ftv->addContentsItem(isDir,dd->shortName(),dd->getReference(),dd->getOutputFileBase(),0); + ftv->incContentsDepth(); + } + + ol.startIndexListItem(); + ol.startIndexItem(dd->getReference(),dd->getOutputFileBase()); + ol.parseText(dd->shortName()); + ol.endIndexItem(dd->getReference(),dd->getOutputFileBase()); + if (dd->isReference()) + { + ol.startTypewriter(); + ol.docify(" [external]"); + ol.endTypewriter(); + } + + // write sub directories + if (dd->subDirs().count()>0) + { + startIndexHierarchy(ol,level+1); + QListIterator dli(dd->subDirs()); + DirDef *subdd = 0; + for (dli.toFirst();(subdd=dli.current());++dli) + { + writeDirTreeNode(ol,subdd,level+1,ftv,addToIndex); + } + endIndexHierarchy(ol,level+1); + } + + if (tocExpand && addToIndex) + { + // write files of this directory + FileList *fileList=dd->getFiles(); + if (fileList && fileList->count()>0) + { + FileDef *fd=fileList->first(); + while (fd) + { + if (fd->isLinkable()) + { + Doxygen::indexList.addContentsItem(FALSE, convertToHtml(fd->name(),TRUE),fd->getReference(), fd->getOutputFileBase(), 0); + } + fd=fileList->next(); + } + } + } + ol.endIndexListItem(); + + if (addToIndex) + { + Doxygen::indexList.decContentsDepth(); + } + if (ftv) + { + ftv->decContentsDepth(); + } +} + +static void writeDirHierarchy(OutputList &ol, FTVHelp* ftv,bool addToIndex) +{ + if (ftv) + { + ol.pushGeneratorState(); + ol.disable(OutputGenerator::Html); + } + startIndexHierarchy(ol,0); + SDict::Iterator dli(*Doxygen::directories); + DirDef *dd; + for (dli.toFirst();(dd=dli.current());++dli) + { + if (dd->getOuterScope()==Doxygen::globalScope) writeDirTreeNode(ol,dd,0,ftv,addToIndex); + } + endIndexHierarchy(ol,0); + if (ftv) + { + ol.popGeneratorState(); + } +} + +//---------------------------------------------------------------------------- + +static void writeGroupIndex(OutputList &ol) +{ + if (documentedGroups==0) return; + ol.pushGeneratorState(); + ol.disable(OutputGenerator::Man); + LayoutNavEntry *lne = LayoutDocManager::instance().rootNavEntry()->find(LayoutNavEntry::Modules); + QCString title = lne ? lne->title() : theTranslator->trModules(); + bool addToIndex = lne==0 || lne->visible(); + + startFile(ol,"modules",0,title,HLI_Modules); + startTitle(ol,0); + ol.parseText(title); + endTitle(ol,0,0); + ol.startContents(); + ol.startTextBlock(); + if (addToIndex) + { + Doxygen::indexList.addContentsItem(TRUE,title,0,"modules",0,TRUE,TRUE); + Doxygen::indexList.incContentsDepth(); + } + ol.parseText(lne ? lne->intro() : theTranslator->trModulesDescription()); + ol.endTextBlock(); + + FTVHelp* ftv = 0; + bool treeView=Config_getBool("USE_INLINE_TREES"); + if (treeView) + { + ftv = new FTVHelp(FALSE); + } + + writeGroupHierarchy(ol,ftv,addToIndex); + + if (addToIndex) + { + Doxygen::indexList.decContentsDepth(); + } + if (ftv) + { + QGString outStr; + FTextStream t(&outStr); + ftv->generateTreeViewInline(t); + ol.pushGeneratorState(); + ol.disableAllBut(OutputGenerator::Html); + ol.writeString(outStr); + ol.popGeneratorState(); + delete ftv; + } + endFile(ol); + ol.popGeneratorState(); +} + +//---------------------------------------------------------------------------- + +static void writeDirIndex(OutputList &ol) +{ + if (documentedDirs==0) return; + ol.pushGeneratorState(); + ol.disable(OutputGenerator::Man); + LayoutNavEntry *lne = LayoutDocManager::instance().rootNavEntry()->find(LayoutNavEntry::Dirs); + QCString title = lne ? lne->title() : theTranslator->trDirectories(); + bool addToIndex=lne==0 || lne->visible(); + + startFile(ol,"dirs",0,title,HLI_Directories); + startTitle(ol,0); + ol.parseText(title); + endTitle(ol,0,0); + ol.startContents(); + ol.startTextBlock(); + + if (addToIndex) + { + Doxygen::indexList.addContentsItem(TRUE,title,0,"dirs",0,TRUE,TRUE); + Doxygen::indexList.incContentsDepth(); + } + ol.parseText(lne ? lne->intro() : theTranslator->trDirDescription()); + ol.endTextBlock(); + + FTVHelp* ftv = 0; + bool treeView=Config_getBool("USE_INLINE_TREES"); + if (treeView) + { + ftv = new FTVHelp(FALSE); + } + + writeDirHierarchy(ol,ftv,addToIndex); + + if (ftv) + { + QGString outStr; + FTextStream t(&outStr); + ftv->generateTreeViewInline(t); + ol.pushGeneratorState(); + ol.disableAllBut(OutputGenerator::Html); + ol.writeString(outStr); + ol.popGeneratorState(); + delete ftv; + } + if (addToIndex) + { + Doxygen::indexList.decContentsDepth(); + } + endFile(ol); + ol.popGeneratorState(); +} + +//---------------------------------------------------------------------------- + +static void writeUserGroupStubPage(OutputList &ol,LayoutNavEntry *lne) +{ + ol.pushGeneratorState(); + ol.disableAllBut(OutputGenerator::Html); + startFile(ol,lne->baseFile(),0,lne->title(),HLI_UserGroup); + startTitle(ol,0); + ol.parseText(lne->title()); + endTitle(ol,0,0); + QListIterator li(lne->children()); + LayoutNavEntry *entry; + int count=0; + for (li.toFirst();(entry=li.current());++li) + { + if (entry->visible()) count++; + } + if (count>0) + { + ol.writeString("\n"); + } + endFile(ol); + ol.popGeneratorState(); +} + +//---------------------------------------------------------------------------- + +static bool mainPageHasTitle() +{ + if (Doxygen::mainPage==0) return FALSE; + if (Doxygen::mainPage->title().isEmpty()) return FALSE; + if (Doxygen::mainPage->title().lower()=="notitle") return FALSE; + return TRUE; +} + +//---------------------------------------------------------------------------- + +static void writeIndex(OutputList &ol) +{ + static bool fortranOpt = Config_getBool("OPTIMIZE_FOR_FORTRAN"); + static bool vhdlOpt = Config_getBool("OPTIMIZE_OUTPUT_VHDL"); + // save old generator state + ol.pushGeneratorState(); + + QCString projPrefix; + if (!Config_getString("PROJECT_NAME").isEmpty()) + { + projPrefix=Config_getString("PROJECT_NAME")+" "; + } + + //-------------------------------------------------------------------- + // write HTML index + //-------------------------------------------------------------------- + ol.disableAllBut(OutputGenerator::Html); + + QCString defFileName = + Doxygen::mainPage ? Doxygen::mainPage->docFile().data() : "[generated]"; + int defLine = + Doxygen::mainPage ? Doxygen::mainPage->docLine() : -1; + + QCString title; + if (!mainPageHasTitle()) + { + title = theTranslator->trMainPage(); + } + else + { + title = filterTitle(Doxygen::mainPage->title()); + } + + QCString indexName="index"; + ol.startFile(indexName,0,title); + + if (Doxygen::mainPage) + { + if (Doxygen::mainPage->hasSubPages() || + (!Config_getString("PROJECT_NAME").isEmpty() && mainPageHasTitle()) + ) // to avoid duplicate entries in the treeview + { + Doxygen::indexList.addContentsItem(Doxygen::mainPage->hasSubPages(),title,0,indexName,0,Doxygen::mainPage->hasSubPages(),TRUE); + } + if (Doxygen::mainPage->hasSubPages()) + { + writeSubPages(Doxygen::mainPage); + } + } + + ol.startQuickIndices(); + if (!Config_getBool("DISABLE_INDEX")) + { + ol.writeQuickLinks(TRUE,HLI_Main,0); + } + ol.endQuickIndices(); + ol.writeSplitBar(indexName); + ol.writeSearchInfo(); + bool headerWritten=FALSE; + if (Doxygen::mainPage && !Doxygen::mainPage->title().isEmpty()) + { + if (Doxygen::mainPage->title().lower()!="notitle") + { + ol.startHeaderSection(); + ol.startTitleHead(0); + ol.parseDoc(Doxygen::mainPage->docFile(),Doxygen::mainPage->docLine(), + Doxygen::mainPage,0,Doxygen::mainPage->title(), + TRUE,FALSE,0,TRUE,FALSE); + headerWritten = TRUE; + } + } + else + { + if (!Config_getString("PROJECT_NAME").isEmpty()) + { + ol.startHeaderSection(); + ol.startTitleHead(0); + ol.parseText(projPrefix+theTranslator->trDocumentation()); + headerWritten = TRUE; + } + } + if (headerWritten) + { + ol.endTitleHead(0,0); + ol.endHeaderSection(); + } + + ol.startContents(); + if (Config_getBool("DISABLE_INDEX") && Doxygen::mainPage==0) + { + ol.writeQuickLinks(FALSE,HLI_Main,0); + } + + if (Doxygen::mainPage) + { + Doxygen::insideMainPage=TRUE; + if (Doxygen::mainPage->showToc() && Doxygen::mainPage->hasSections()) + { + Doxygen::mainPage->writeToc(ol); + } + + ol.startTextBlock(); + ol.parseDoc(defFileName,defLine,Doxygen::mainPage,0, + Doxygen::mainPage->documentation(),TRUE,FALSE + /*,Doxygen::mainPage->sectionDict*/); + ol.endTextBlock(); + + if (!Config_getString("GENERATE_TAGFILE").isEmpty()) + { + Doxygen::tagFile << " " << endl + << " " + << convertToXML(Doxygen::mainPage->name()) + << "" << endl + << " " + << convertToXML(Doxygen::mainPage->title()) + << "" << endl + << " " + << convertToXML(Doxygen::mainPage->getOutputFileBase()) + << "" << endl; + + Doxygen::mainPage->writeDocAnchorsToTagFile(); + Doxygen::tagFile << " " << endl; + } + Doxygen::insideMainPage=FALSE; + } + + endFile(ol); + ol.disable(OutputGenerator::Html); + + //-------------------------------------------------------------------- + // write LaTeX/RTF index + //-------------------------------------------------------------------- + ol.enable(OutputGenerator::Latex); + ol.enable(OutputGenerator::RTF); + + ol.startFile("refman",0,0); + ol.startIndexSection(isTitlePageStart); + if (!Config_getString("LATEX_HEADER").isEmpty()) + { + ol.disable(OutputGenerator::Latex); + } + + if (projPrefix.isEmpty()) + { + ol.parseText(theTranslator->trReferenceManual()); + } + else + { + ol.parseText(projPrefix); + } + + if (!Config_getString("PROJECT_NUMBER").isEmpty()) + { + ol.startProjectNumber(); + ol.parseDoc(defFileName,defLine,Doxygen::mainPage,0,Config_getString("PROJECT_NUMBER"),FALSE,FALSE); + ol.endProjectNumber(); + } + ol.endIndexSection(isTitlePageStart); + ol.startIndexSection(isTitlePageAuthor); + ol.parseText(theTranslator->trGeneratedBy()); + ol.endIndexSection(isTitlePageAuthor); + ol.enable(OutputGenerator::Latex); + + ol.lastIndexPage(); + if (Doxygen::mainPage) + { + ol.startIndexSection(isMainPage); + if (mainPageHasTitle()) + { + ol.parseText(Doxygen::mainPage->title()); + } + else + { + ol.parseText(/*projPrefix+*/theTranslator->trMainPage()); + } + ol.endIndexSection(isMainPage); + } + if (documentedPages>0) + { + //ol.parseText(projPrefix+theTranslator->trPageDocumentation()); + //ol.endIndexSection(isPageDocumentation); + PageSDict::Iterator pdi(*Doxygen::pageSDict); + PageDef *pd=pdi.toFirst(); + bool first=Doxygen::mainPage==0; + for (pdi.toFirst();(pd=pdi.current());++pdi) + { + if (!pd->getGroupDef() && !pd->isReference() && + (!pd->hasParentPage() || // not inside other page + (Doxygen::mainPage==pd->getOuterScope())) // or inside main page + ) + { + bool isCitationPage = pd->name()=="citelist"; + if (isCitationPage) + { + // For LaTeX the bibliograph is already written by \bibliography + ol.pushGeneratorState(); + ol.disable(OutputGenerator::Latex); + } + QCString title = pd->title(); + if (title.isEmpty()) title=pd->name(); + ol.startIndexSection(isPageDocumentation); + ol.parseText(title); + ol.endIndexSection(isPageDocumentation); + ol.pushGeneratorState(); // write TOC title (RTF only) + ol.disableAllBut(OutputGenerator::RTF); + ol.startIndexSection(isPageDocumentation2); + ol.parseText(title); + ol.endIndexSection(isPageDocumentation2); + ol.popGeneratorState(); + ol.writeAnchor(0,pd->name()); + + ol.writePageLink(pd->getOutputFileBase(),first); + first=FALSE; + + if (isCitationPage) + { + ol.popGeneratorState(); + } + } + } + } + + if (!Config_getBool("LATEX_HIDE_INDICES")) + { + //if (indexedPages>0) + //{ + // ol.startIndexSection(isPageIndex); + // ol.parseText(/*projPrefix+*/ theTranslator->trPageIndex()); + // ol.endIndexSection(isPageIndex); + //} + if (documentedGroups>0) + { + ol.startIndexSection(isModuleIndex); + ol.parseText(/*projPrefix+*/ theTranslator->trModuleIndex()); + ol.endIndexSection(isModuleIndex); + } + if (Config_getBool("SHOW_DIRECTORIES") && documentedDirs>0) + { + ol.startIndexSection(isDirIndex); + ol.parseText(/*projPrefix+*/ theTranslator->trDirIndex()); + ol.endIndexSection(isDirIndex); + } + if (documentedNamespaces>0) + { + ol.startIndexSection(isNamespaceIndex); + ol.parseText(/*projPrefix+*/(fortranOpt?theTranslator->trModulesIndex():theTranslator->trNamespaceIndex())); + ol.endIndexSection(isNamespaceIndex); + } + if (hierarchyClasses>0) + { + ol.startIndexSection(isClassHierarchyIndex); + ol.parseText(/*projPrefix+*/ + (fortranOpt ? theTranslator->trCompoundIndexFortran() : + vhdlOpt ? VhdlDocGen::trDesignUnitIndex() : + theTranslator->trCompoundIndex() + )); + ol.endIndexSection(isClassHierarchyIndex); + } + if (annotatedClassesPrinted>0) + { + ol.startIndexSection(isCompoundIndex); + ol.parseText(/*projPrefix+*/ + (fortranOpt ? theTranslator->trCompoundIndexFortran() : + vhdlOpt ? VhdlDocGen::trDesignUnitIndex() : + theTranslator->trCompoundIndex() + )); + ol.endIndexSection(isCompoundIndex); + } + if (documentedFiles>0) + { + ol.startIndexSection(isFileIndex); + ol.parseText(/*projPrefix+*/theTranslator->trFileIndex()); + ol.endIndexSection(isFileIndex); + } + } + if (documentedGroups>0) + { + ol.startIndexSection(isModuleDocumentation); + ol.parseText(/*projPrefix+*/theTranslator->trModuleDocumentation()); + ol.endIndexSection(isModuleDocumentation); + } + if (Config_getBool("SHOW_DIRECTORIES") && documentedDirs>0) + { + ol.startIndexSection(isDirDocumentation); + ol.parseText(/*projPrefix+*/theTranslator->trDirDocumentation()); + ol.endIndexSection(isDirDocumentation); + } + if (documentedNamespaces>0) + { + ol.startIndexSection(isNamespaceDocumentation); + ol.parseText(/*projPrefix+*/(fortranOpt?theTranslator->trModuleDocumentation():theTranslator->trNamespaceDocumentation())); + ol.endIndexSection(isNamespaceDocumentation); + } + if (annotatedClassesPrinted>0) + { + ol.startIndexSection(isClassDocumentation); + ol.parseText(/*projPrefix+*/(fortranOpt?theTranslator->trTypeDocumentation():theTranslator->trClassDocumentation())); + ol.endIndexSection(isClassDocumentation); + } + if (documentedFiles>0) + { + ol.startIndexSection(isFileDocumentation); + ol.parseText(/*projPrefix+*/theTranslator->trFileDocumentation()); + ol.endIndexSection(isFileDocumentation); + } + if (Doxygen::exampleSDict->count()>0) + { + ol.startIndexSection(isExampleDocumentation); + ol.parseText(/*projPrefix+*/theTranslator->trExampleDocumentation()); + ol.endIndexSection(isExampleDocumentation); + } + ol.endIndexSection(isEndIndex); + endFile(ol); + + if (Doxygen::mainPage) + { + Doxygen::insideMainPage=TRUE; + ol.disable(OutputGenerator::Man); + startFile(ol,Doxygen::mainPage->name(),0,Doxygen::mainPage->title()); + ol.startContents(); + ol.startTextBlock(); + ol.parseDoc(defFileName,defLine,Doxygen::mainPage,0, + Doxygen::mainPage->documentation(),FALSE,FALSE + ); + ol.endTextBlock(); + endFile(ol); + ol.enable(OutputGenerator::Man); + Doxygen::insideMainPage=FALSE; + } + + ol.popGeneratorState(); +} + +static QArray indexWritten; + +static void writeIndexHierarchyEntries(OutputList &ol,const QList &entries) +{ + QListIterator li(entries); + LayoutNavEntry *lne; + for (li.toFirst();(lne=li.current());++li) + { + LayoutNavEntry::Kind kind = lne->kind(); + uint index = (uint)kind; + if (index>=indexWritten.size()) + { + uint i; + uint oldSize = indexWritten.size(); + uint newSize = index+1; + indexWritten.resize(newSize); + for (i=oldSize;ititle().data(),lne->kind()); + bool addToIndex=lne==0 || lne->visible(); + bool needsClosing=FALSE; + if (!indexWritten.at(index)) + { + switch(kind) + { + case LayoutNavEntry::MainPage: + msg("Generating index page...\n"); + writeIndex(ol); + break; + case LayoutNavEntry::Pages: + msg("Generating page index...\n"); + writePageIndex(ol); + break; + case LayoutNavEntry::Modules: + msg("Generating module index...\n"); + writeGroupIndex(ol); + break; + case LayoutNavEntry::Namespaces: + { + if (documentedNamespaces>0 && addToIndex) + { + Doxygen::indexList.addContentsItem(TRUE,lne->title(),0,0,0); + Doxygen::indexList.incContentsDepth(); + needsClosing=TRUE; + } + if (LayoutDocManager::instance().rootNavEntry()->find(LayoutNavEntry::Namespaces)!=lne) // for backward compatibility with old layout file + { + msg("Generating namespace index...\n"); + writeNamespaceIndex(ol); + } + } + break; + case LayoutNavEntry::NamespaceList: + msg("Generating namespace index...\n"); + writeNamespaceIndex(ol); + break; + case LayoutNavEntry::NamespaceMembers: + msg("Generating namespace member index...\n"); + writeNamespaceMemberIndex(ol); + break; + case LayoutNavEntry::Classes: + if (annotatedClasses>0 && addToIndex) + { + Doxygen::indexList.addContentsItem(TRUE,lne->title(),0,0,0); + Doxygen::indexList.incContentsDepth(); + needsClosing=TRUE; + } + if (LayoutDocManager::instance().rootNavEntry()->find(LayoutNavEntry::Classes)!=lne) // for backward compatibility with old layout file + { + msg("Generating annotated compound index...\n"); + writeAnnotatedIndex(ol); + } + break; + case LayoutNavEntry::ClassList: + msg("Generating annotated compound index...\n"); + writeAnnotatedIndex(ol); + break; + case LayoutNavEntry::ClassIndex: + msg("Generating alphabetical compound index...\n"); + writeAlphabeticalIndex(ol); + break; + case LayoutNavEntry::ClassHierarchy: + msg("Generating hierarchical class index...\n"); + writeHierarchicalIndex(ol); + if (Config_getBool("HAVE_DOT") && Config_getBool("GRAPHICAL_HIERARCHY")) + { + msg("Generating graphical class hierarchy...\n"); + writeGraphicalClassHierarchy(ol); + } + break; + case LayoutNavEntry::ClassMembers: + msg("Generating member index...\n"); + writeClassMemberIndex(ol); + break; + case LayoutNavEntry::Files: + if (documentedHtmlFiles>0 && addToIndex) + { + Doxygen::indexList.addContentsItem(TRUE,lne->title(),0,0,0); + Doxygen::indexList.incContentsDepth(); + needsClosing=TRUE; + } + if (LayoutDocManager::instance().rootNavEntry()->find(LayoutNavEntry::Files)!=lne) // for backward compatibility with old layout file + { + msg("Generating file index...\n"); + writeFileIndex(ol); + } + break; + case LayoutNavEntry::FileList: + msg("Generating file index...\n"); + writeFileIndex(ol); + break; + case LayoutNavEntry::FileGlobals: + msg("Generating file member index...\n"); + writeFileMemberIndex(ol); + break; + case LayoutNavEntry::Dirs: + if (Config_getBool("SHOW_DIRECTORIES")) + { + msg("Generating directory index...\n"); + writeDirIndex(ol); + } + break; + case LayoutNavEntry::Examples: + msg("Generating example index...\n"); + writeExampleIndex(ol); + break; + case LayoutNavEntry::User: + { + // prepend a ! or ^ marker to the URL to avoid tampering with it + QCString url = correctURL(lne->url(),"!"); // add ! to relative URL + if (!url.isEmpty() && url.at(0)!='!') // absolute URL + { + url.prepend("^"); // prepend ^ to absolute URL + } + bool isRef = lne->baseFile().left(4)=="@ref" || lne->baseFile().left(4)=="\\ref"; + Doxygen::indexList.addContentsItem(TRUE,lne->title(),0,url,0,FALSE,isRef); + } + break; + case LayoutNavEntry::UserGroup: + if (addToIndex) + { + Doxygen::indexList.addContentsItem(TRUE,lne->title(),0,lne->baseFile(),0,TRUE,TRUE); + Doxygen::indexList.incContentsDepth(); + needsClosing=TRUE; + } + writeUserGroupStubPage(ol,lne); + break; + } + if (kind!=LayoutNavEntry::User && kind!=LayoutNavEntry::UserGroup) // User entry may appear multiple times + { + indexWritten.at(index)=TRUE; + } + } + writeIndexHierarchyEntries(ol,lne->children()); + if (needsClosing) + { + switch(kind) + { + case LayoutNavEntry::Namespaces: + case LayoutNavEntry::Classes: + case LayoutNavEntry::Files: + case LayoutNavEntry::UserGroup: + Doxygen::indexList.decContentsDepth(); + break; + default: + break; + } + } + //printf("ending %s kind=%d\n",lne->title().data(),lne->kind()); + } +} + +void writeIndexHierarchy(OutputList &ol) +{ + LayoutNavEntry *lne = LayoutDocManager::instance().rootNavEntry(); + if (lne) + { + writeIndexHierarchyEntries(ol,lne->children()); + } +} + diff --git a/trunk/src/index.h b/trunk/src/index.h new file mode 100644 index 0000000..54f7f35 --- /dev/null +++ b/trunk/src/index.h @@ -0,0 +1,271 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#ifndef INDEX_H +#define INDEX_H + +#include "qtbc.h" +#include +#include + +class Definition; +class MemberDef; +class OutputList; +class FTextStream; + +/** \brief Abstract interface for index generators. */ +class IndexIntf +{ + public: + virtual ~IndexIntf() {} + virtual void initialize() = 0; + virtual void finalize() = 0; + virtual void incContentsDepth() = 0; + virtual void decContentsDepth() = 0; + virtual void addContentsItem(bool isDir, const char *name, const char *ref, + const char *file, const char *anchor, bool separateIndex, + bool addToNavIndex) = 0; + virtual void addIndexItem(Definition *context,MemberDef *md,const char *title) = 0; + virtual void addIndexFile(const char *name) = 0; + virtual void addImageFile(const char *name) = 0; + virtual void addStyleSheetFile(const char *name) = 0; +}; + +/** \brief A list of index interfaces. + * + * This class itself implements all methods of IndexIntf and + * just forwards the calls to all items in the list. + */ +class IndexList : public IndexIntf +{ + private: + QList m_intfs; + + // --- foreach implementations for various number of arguments + + void foreach(void (IndexIntf::*methodPtr)()) + { + QListIterator li(m_intfs); + for (li.toFirst();li.current();++li) (li.current()->*methodPtr)(); + } + + template + void foreach(void (IndexIntf::*methodPtr)(A1),A1 a1) + { + QListIterator li(m_intfs); + for (li.toFirst();li.current();++li) (li.current()->*methodPtr)(a1); + } + + template + void foreach(void (IndexIntf::*methodPtr)(A1,A2,A3),A1 a1,A2 a2,A3 a3) + { + QListIterator li(m_intfs); + for (li.toFirst();li.current();++li) (li.current()->*methodPtr)(a1,a2,a3); + } + + template + void foreach(void (IndexIntf::*methodPtr)(A1,A2,A3,A4),A1 a1,A2 a2,A3 a3,A4 a4) + { + QListIterator li(m_intfs); + for (li.toFirst();li.current();++li) (li.current()->*methodPtr)(a1,a2,a3,a4); + } + + template + void foreach(void (IndexIntf::*methodPtr)(A1,A2,A3,A4,A5),A1 a1,A2 a2,A3 a3,A4 a4,A5 a5) + { + QListIterator li(m_intfs); + for (li.toFirst();li.current();++li) (li.current()->*methodPtr)(a1,a2,a3,a4,a5); + } + + template + void foreach(void (IndexIntf::*methodPtr)(A1,A2,A3,A4,A5,A6),A1 a1,A2 a2,A3 a3,A4 a4,A5 a5,A6 a6) + { + QListIterator li(m_intfs); + for (li.toFirst();li.current();++li) (li.current()->*methodPtr)(a1,a2,a3,a4,a5,a6); + } + + template + void foreach(void (IndexIntf::*methodPtr)(A1,A2,A3,A4,A5,A6,A7),A1 a1,A2 a2,A3 a3,A4 a4,A5 a5,A6 a6,A7 a7) + { + QListIterator li(m_intfs); + for (li.toFirst();li.current();++li) (li.current()->*methodPtr)(a1,a2,a3,a4,a5,a6,a7); + } + + public: + /** Creates a list of indexes */ + IndexList() { m_intfs.setAutoDelete(TRUE); } + /** Add an index generator to the list */ + void addIndex(IndexIntf *intf) + { m_intfs.append(intf); } + + // IndexIntf implementation + void initialize() + { foreach(&IndexIntf::initialize); } + void finalize() + { foreach(&IndexIntf::finalize); } + void incContentsDepth() + { foreach(&IndexIntf::incContentsDepth); } + void decContentsDepth() + { foreach(&IndexIntf::decContentsDepth); } + void addContentsItem(bool isDir, const char *name, const char *ref, + const char *file, const char *anchor,bool separateIndex=FALSE,bool addToNavIndex=FALSE) + { foreach + (&IndexIntf::addContentsItem,isDir,name,ref,file,anchor,separateIndex,addToNavIndex); } + void addIndexItem(Definition *context,MemberDef *md,const char *title=0) + { foreach + (&IndexIntf::addIndexItem,context,md,title); } + void addIndexFile(const char *name) + { foreach(&IndexIntf::addIndexFile,name); } + void addImageFile(const char *name) + { foreach(&IndexIntf::addImageFile,name); } + void addStyleSheetFile(const char *name) + { foreach(&IndexIntf::addStyleSheetFile,name); } + +}; + + +enum IndexSections +{ + isTitlePageStart, + isTitlePageAuthor, + isMainPage, + isModuleIndex, + isDirIndex, + isNamespaceIndex, + isClassHierarchyIndex, + isCompoundIndex, + isFileIndex, + isPageIndex, + isModuleDocumentation, + isDirDocumentation, + isNamespaceDocumentation, + isClassDocumentation, + isFileDocumentation, + isExampleDocumentation, + isPageDocumentation, + isPageDocumentation2, + isEndIndex +}; + +enum HighlightedItem +{ + HLI_None=0, + HLI_Main, + HLI_Modules, + HLI_Directories, + HLI_Namespaces, + HLI_Hierarchy, + HLI_Classes, + HLI_Annotated, + HLI_Files, + HLI_NamespaceMembers, + HLI_Functions, + HLI_Globals, + HLI_Pages, + HLI_Examples, + HLI_Search, + HLI_UserGroup, + + HLI_ClassVisible, + HLI_NamespaceVisible, + HLI_FileVisible +}; + +enum ClassMemberHighlight +{ + CMHL_All = 0, + CMHL_Functions, + CMHL_Variables, + CMHL_Typedefs, + CMHL_Enums, + CMHL_EnumValues, + CMHL_Properties, + CMHL_Events, + CMHL_Related, + CMHL_Total = CMHL_Related+1 +}; + +enum FileMemberHighlight +{ + FMHL_All = 0, + FMHL_Functions, + FMHL_Variables, + FMHL_Typedefs, + FMHL_Enums, + FMHL_EnumValues, + FMHL_Defines, + FMHL_Total = FMHL_Defines+1 +}; + +enum NamespaceMemberHighlight +{ + NMHL_All = 0, + NMHL_Functions, + NMHL_Variables, + NMHL_Typedefs, + NMHL_Enums, + NMHL_EnumValues, + NMHL_Total = NMHL_EnumValues+1 +}; + +enum ClassHighlight +{ + CHL_All = 0, + CHL_Classes, + CHL_Structs, + CHL_Unions, + CHL_Interfaces, + CHL_Protocols, + CHL_Categories, + CHL_Exceptions, + CHL_Total = CHL_Exceptions+1 +}; + +void writeGraphInfo(OutputList &ol); +void writeIndexHierarchy(OutputList &ol); + +void countDataStructures(); + +extern int annotatedClasses; +extern int hierarchyClasses; +extern int documentedFiles; +extern int documentedGroups; +extern int documentedNamespaces; +extern int indexedPages; +extern int documentedClassMembers[CMHL_Total]; +extern int documentedFileMembers[FMHL_Total]; +extern int documentedNamespaceMembers[NMHL_Total]; +extern int documentedDirs; +extern int documentedHtmlFiles; +extern int documentedPages; + +void startTitle(OutputList &ol,const char *fileName,Definition *def=0); +void endTitle(OutputList &ol,const char *fileName,const char *name); +void startFile(OutputList &ol,const char *name,const char *manName, + const char *title,HighlightedItem hli=HLI_None, + bool additionalIndices=FALSE,const char *altSidebarName=0); +void endFile(OutputList &ol,bool skipNavIndex=FALSE,bool skipEndContents=FALSE); +void endFileWithNavPath(Definition *d,OutputList &ol); + +void initClassMemberIndices(); +void initFileMemberIndices(); +void initNamespaceMemberIndices(); +void addClassMemberNameToIndex(MemberDef *md); +void addFileMemberNameToIndex(MemberDef *md); +void addNamespaceMemberNameToIndex(MemberDef *md); + +#endif diff --git a/trunk/src/index.xsd b/trunk/src/index.xsd new file mode 100644 index 0000000..d7ab2a9 --- /dev/null +++ b/trunk/src/index.xsd @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/trunk/src/index_xsd.h b/trunk/src/index_xsd.h new file mode 100644 index 0000000..2f5d0c5 --- /dev/null +++ b/trunk/src/index_xsd.h @@ -0,0 +1,66 @@ +"\n" +"\n" +" \n" +"\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"\n" +"\n" +"\n" diff --git a/trunk/src/indexlog.cpp b/trunk/src/indexlog.cpp new file mode 100644 index 0000000..5fb67f5 --- /dev/null +++ b/trunk/src/indexlog.cpp @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2008 by Sebastian Pipping. + * Copyright (C) 2008 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. + * + * Sebastian Pipping + */ + +#include "indexlog.h" +#include "message.h" +#include "config.h" + +#include +#include + + +IndexLog::IndexLog() +{ +} + +IndexLog::~IndexLog() +{ +} + +void IndexLog::initialize() +{ + char const * const attributes[] = + { "xmlns", + "http://doxygen.org/xmlns/indexlog/1/0/", + NULL + }; + m_out.open("log", attributes); + + openMethodCall("initialize"); + closeMethodCall(); +} + +void IndexLog::finalize() +{ + openMethodCall("finalize"); + closeMethodCall(); + m_out.close("log"); + QCString fileName = Config_getString("HTML_OUTPUT")+"/index.log.xml"; + QFile file(fileName); + if (!file.open(IO_WriteOnly)) + { + err("Could not open file %s for writing\n", fileName.data()); + exit(1); + } + m_out.dumpTo(file); + file.flush(); + file.close(); +} + +void IndexLog::incContentsDepth() +{ + openMethodCall("incContentsDepth"); + closeMethodCall(); +} + +void IndexLog::decContentsDepth() +{ + openMethodCall("decContentsDepth"); + closeMethodCall(); +} + +void IndexLog::addContentsItem(bool isDir, char const * name, + char const * ref, char const * file, + char const * anchor) +{ + openMethodCall("addContentsItem"); + addBoolParameter("isDir", isDir); + addStringParameter("name", name); + addStringParameter("ref", ref); + addStringParameter("file", file); + addStringParameter("anchor", anchor); + closeMethodCall(); +} + +void IndexLog::addIndexItem(char const * level1, char const * level2, + char const * contRef, char const * memRef, + char const * anchor, const MemberDef * md) +{ + openMethodCall("addIndexItem"); + addStringParameter("level1", level1); + addStringParameter("level2", level2); + addStringParameter("contRef", contRef); + addStringParameter("memRef", memRef); + addStringParameter("anchor", anchor); + addMemberDefParameter("md", md); + closeMethodCall(); +} + +void IndexLog::addIndexFile(char const * name) +{ + openMethodCall("addIndexFile"); + addStringParameter("name", name); + closeMethodCall(); +} + +void IndexLog::openMethodCall(char const * methodName) +{ + m_out.setCompressionEnabled(true); + m_out.open("call"); + m_out.openCloseContent("method", methodName); +} + +void IndexLog::addPrimitiveParameter(char const * parameterName, + char const * value) +{ + m_out.open("param"); + m_out.openCloseContent("name", parameterName); + if (value != NULL) + { + m_out.openCloseContent("value", value); + } + m_out.close("param"); +} + +void IndexLog::addBoolParameter(char const * parameterName, bool value) +{ + addPrimitiveParameter(parameterName, value ? "true" : "false"); +} + +void IndexLog::addStringParameter(char const * parameterName, + char const * value) +{ + addPrimitiveParameter(parameterName, value); +} + +void IndexLog::addMemberDefParameter(char const * parameterName, + const MemberDef * /*value*/) +{ + m_out.open("param"); + m_out.openCloseContent("name", parameterName); + m_out.close("param"); +} + +void IndexLog::closeMethodCall() +{ + m_out.setCompressionEnabled(false); + m_out.close("call"); +} + diff --git a/trunk/src/indexlog.h b/trunk/src/indexlog.h new file mode 100644 index 0000000..6875971 --- /dev/null +++ b/trunk/src/indexlog.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2008 by Sebastian Pipping. + * Copyright (C) 2008 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. + * + * Sebastian Pipping + */ + +#ifndef INDEXLOG_H +#define INDEXLOG_H + +#include "index.h" +#include "qhpxmlwriter.h" + +class IndexLog : public IndexIntf +{ + public: + IndexLog(); + ~IndexLog(); + + // BEGIN IndexIntf + void initialize(); + void finalize(); + void incContentsDepth(); + void decContentsDepth(); + void addContentsItem(bool isDir, const char *name, const char *ref, + const char *file, const char *anchor); + void addIndexItem(const char *level1, const char *level2, + const char *contRef, const char *memRef, + const char *anchor, const MemberDef * md); + void addIndexFile(const char *name); + // END IndexIntf + + private: + void openMethodCall(char const * methodName); + void addPrimitiveParameter(char const * parameterName, + char const * value); + void addBoolParameter(char const * parameterName, bool value); + void addStringParameter(char const * parameterName, + char const * value); + void addMemberDefParameter(char const * parameterName, + const MemberDef * value); + void closeMethodCall(); + + QhpXmlWriter m_out; +}; + +#endif // INDEXLOG_H + diff --git a/trunk/src/jquery.js b/trunk/src/jquery.js new file mode 100644 index 0000000..60894d0 --- /dev/null +++ b/trunk/src/jquery.js @@ -0,0 +1,13 @@ +/* + * jQuery JavaScript Library v1.3.2 + * http://jquery.com/ + * + * Copyright (c) 2009 John Resig + * Dual licensed under the MIT and GPL licenses. + * http://docs.jquery.com/License + * + * Date: 2009-02-19 17:34:21 -0500 (Thu, 19 Feb 2009) + * Revision: 6246 + */ +(function(){var l=this,g,y=l.jQuery,p=l.$,o=l.jQuery=l.$=function(E,F){return new o.fn.init(E,F)},D=/^[^<]*(<(.|\s)+>)[^>]*$|^#([\w-]+)$/,f=/^.[^:#\[\.,]*$/;o.fn=o.prototype={init:function(E,H){E=E||document;if(E.nodeType){this[0]=E;this.length=1;this.context=E;return this}if(typeof E==="string"){var G=D.exec(E);if(G&&(G[1]||!H)){if(G[1]){E=o.clean([G[1]],H)}else{var I=document.getElementById(G[3]);if(I&&I.id!=G[3]){return o().find(E)}var F=o(I||[]);F.context=document;F.selector=E;return F}}else{return o(H).find(E)}}else{if(o.isFunction(E)){return o(document).ready(E)}}if(E.selector&&E.context){this.selector=E.selector;this.context=E.context}return this.setArray(o.isArray(E)?E:o.makeArray(E))},selector:"",jquery:"1.3.2",size:function(){return this.length},get:function(E){return E===g?Array.prototype.slice.call(this):this[E]},pushStack:function(F,H,E){var G=o(F);G.prevObject=this;G.context=this.context;if(H==="find"){G.selector=this.selector+(this.selector?" ":"")+E}else{if(H){G.selector=this.selector+"."+H+"("+E+")"}}return G},setArray:function(E){this.length=0;Array.prototype.push.apply(this,E);return this},each:function(F,E){return o.each(this,F,E)},index:function(E){return o.inArray(E&&E.jquery?E[0]:E,this)},attr:function(F,H,G){var E=F;if(typeof F==="string"){if(H===g){return this[0]&&o[G||"attr"](this[0],F)}else{E={};E[F]=H}}return this.each(function(I){for(F in E){o.attr(G?this.style:this,F,o.prop(this,E[F],G,I,F))}})},css:function(E,F){if((E=="width"||E=="height")&&parseFloat(F)<0){F=g}return this.attr(E,F,"curCSS")},text:function(F){if(typeof F!=="object"&&F!=null){return this.empty().append((this[0]&&this[0].ownerDocument||document).createTextNode(F))}var E="";o.each(F||this,function(){o.each(this.childNodes,function(){if(this.nodeType!=8){E+=this.nodeType!=1?this.nodeValue:o.fn.text([this])}})});return E},wrapAll:function(E){if(this[0]){var F=o(E,this[0].ownerDocument).clone();if(this[0].parentNode){F.insertBefore(this[0])}F.map(function(){var G=this;while(G.firstChild){G=G.firstChild}return G}).append(this)}return this},wrapInner:function(E){return this.each(function(){o(this).contents().wrapAll(E)})},wrap:function(E){return this.each(function(){o(this).wrapAll(E)})},append:function(){return this.domManip(arguments,true,function(E){if(this.nodeType==1){this.appendChild(E)}})},prepend:function(){return this.domManip(arguments,true,function(E){if(this.nodeType==1){this.insertBefore(E,this.firstChild)}})},before:function(){return this.domManip(arguments,false,function(E){this.parentNode.insertBefore(E,this)})},after:function(){return this.domManip(arguments,false,function(E){this.parentNode.insertBefore(E,this.nextSibling)})},end:function(){return this.prevObject||o([])},push:[].push,sort:[].sort,splice:[].splice,find:function(E){if(this.length===1){var F=this.pushStack([],"find",E);F.length=0;o.find(E,this[0],F);return F}else{return this.pushStack(o.unique(o.map(this,function(G){return o.find(E,G)})),"find",E)}},clone:function(G){var E=this.map(function(){if(!o.support.noCloneEvent&&!o.isXMLDoc(this)){var I=this.outerHTML;if(!I){var J=this.ownerDocument.createElement("div");J.appendChild(this.cloneNode(true));I=J.innerHTML}return o.clean([I.replace(/ jQuery\d+="(?:\d+|null)"/g,"").replace(/^\s*/,"")])[0]}else{return this.cloneNode(true)}});if(G===true){var H=this.find("*").andSelf(),F=0;E.find("*").andSelf().each(function(){if(this.nodeName!==H[F].nodeName){return}var I=o.data(H[F],"events");for(var K in I){for(var J in I[K]){o.event.add(this,K,I[K][J],I[K][J].data)}}F++})}return E},filter:function(E){return this.pushStack(o.isFunction(E)&&o.grep(this,function(G,F){return E.call(G,F)})||o.multiFilter(E,o.grep(this,function(F){return F.nodeType===1})),"filter",E)},closest:function(E){var G=o.expr.match.POS.test(E)?o(E):null,F=0;return this.map(function(){var H=this;while(H&&H.ownerDocument){if(G?G.index(H)>-1:o(H).is(E)){o.data(H,"closest",F);return H}H=H.parentNode;F++}})},not:function(E){if(typeof E==="string"){if(f.test(E)){return this.pushStack(o.multiFilter(E,this,true),"not",E)}else{E=o.multiFilter(E,this)}}var F=E.length&&E[E.length-1]!==g&&!E.nodeType;return this.filter(function(){return F?o.inArray(this,E)<0:this!=E})},add:function(E){return this.pushStack(o.unique(o.merge(this.get(),typeof E==="string"?o(E):o.makeArray(E))))},is:function(E){return !!E&&o.multiFilter(E,this).length>0},hasClass:function(E){return !!E&&this.is("."+E)},val:function(K){if(K===g){var E=this[0];if(E){if(o.nodeName(E,"option")){return(E.attributes.value||{}).specified?E.value:E.text}if(o.nodeName(E,"select")){var I=E.selectedIndex,L=[],M=E.options,H=E.type=="select-one";if(I<0){return null}for(var F=H?I:0,J=H?I+1:M.length;F=0||o.inArray(this.name,K)>=0)}else{if(o.nodeName(this,"select")){var N=o.makeArray(K);o("option",this).each(function(){this.selected=(o.inArray(this.value,N)>=0||o.inArray(this.text,N)>=0)});if(!N.length){this.selectedIndex=-1}}else{this.value=K}}})},html:function(E){return E===g?(this[0]?this[0].innerHTML.replace(/ jQuery\d+="(?:\d+|null)"/g,""):null):this.empty().append(E)},replaceWith:function(E){return this.after(E).remove()},eq:function(E){return this.slice(E,+E+1)},slice:function(){return this.pushStack(Array.prototype.slice.apply(this,arguments),"slice",Array.prototype.slice.call(arguments).join(","))},map:function(E){return this.pushStack(o.map(this,function(G,F){return E.call(G,F,G)}))},andSelf:function(){return this.add(this.prevObject)},domManip:function(J,M,L){if(this[0]){var I=(this[0].ownerDocument||this[0]).createDocumentFragment(),F=o.clean(J,(this[0].ownerDocument||this[0]),I),H=I.firstChild;if(H){for(var G=0,E=this.length;G1||G>0?I.cloneNode(true):I)}}if(F){o.each(F,z)}}return this;function K(N,O){return M&&o.nodeName(N,"table")&&o.nodeName(O,"tr")?(N.getElementsByTagName("tbody")[0]||N.appendChild(N.ownerDocument.createElement("tbody"))):N}}};o.fn.init.prototype=o.fn;function z(E,F){if(F.src){o.ajax({url:F.src,async:false,dataType:"script"})}else{o.globalEval(F.text||F.textContent||F.innerHTML||"")}if(F.parentNode){F.parentNode.removeChild(F)}}function e(){return +new Date}o.extend=o.fn.extend=function(){var J=arguments[0]||{},H=1,I=arguments.length,E=false,G;if(typeof J==="boolean"){E=J;J=arguments[1]||{};H=2}if(typeof J!=="object"&&!o.isFunction(J)){J={}}if(I==H){J=this;--H}for(;H-1}},swap:function(H,G,I){var E={};for(var F in G){E[F]=H.style[F];H.style[F]=G[F]}I.call(H);for(var F in G){H.style[F]=E[F]}},css:function(H,F,J,E){if(F=="width"||F=="height"){var L,G={position:"absolute",visibility:"hidden",display:"block"},K=F=="width"?["Left","Right"]:["Top","Bottom"];function I(){L=F=="width"?H.offsetWidth:H.offsetHeight;if(E==="border"){return}o.each(K,function(){if(!E){L-=parseFloat(o.curCSS(H,"padding"+this,true))||0}if(E==="margin"){L+=parseFloat(o.curCSS(H,"margin"+this,true))||0}else{L-=parseFloat(o.curCSS(H,"border"+this+"Width",true))||0}})}if(H.offsetWidth!==0){I()}else{o.swap(H,G,I)}return Math.max(0,Math.round(L))}return o.curCSS(H,F,J)},curCSS:function(I,F,G){var L,E=I.style;if(F=="opacity"&&!o.support.opacity){L=o.attr(E,"opacity");return L==""?"1":L}if(F.match(/float/i)){F=w}if(!G&&E&&E[F]){L=E[F]}else{if(q.getComputedStyle){if(F.match(/float/i)){F="float"}F=F.replace(/([A-Z])/g,"-$1").toLowerCase();var M=q.getComputedStyle(I,null);if(M){L=M.getPropertyValue(F)}if(F=="opacity"&&L==""){L="1"}}else{if(I.currentStyle){var J=F.replace(/\-(\w)/g,function(N,O){return O.toUpperCase()});L=I.currentStyle[F]||I.currentStyle[J];if(!/^\d+(px)?$/i.test(L)&&/^\d/.test(L)){var H=E.left,K=I.runtimeStyle.left;I.runtimeStyle.left=I.currentStyle.left;E.left=L||0;L=E.pixelLeft+"px";E.left=H;I.runtimeStyle.left=K}}}}return L},clean:function(F,K,I){K=K||document;if(typeof K.createElement==="undefined"){K=K.ownerDocument||K[0]&&K[0].ownerDocument||document}if(!I&&F.length===1&&typeof F[0]==="string"){var H=/^<(\w+)\s*\/?>$/.exec(F[0]);if(H){return[K.createElement(H[1])]}}var G=[],E=[],L=K.createElement("div");o.each(F,function(P,S){if(typeof S==="number"){S+=""}if(!S){return}if(typeof S==="string"){S=S.replace(/(<(\w+)[^>]*?)\/>/g,function(U,V,T){return T.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i)?U:V+">"});var O=S.replace(/^\s+/,"").substring(0,10).toLowerCase();var Q=!O.indexOf("",""]||!O.indexOf("",""]||O.match(/^<(thead|tbody|tfoot|colg|cap)/)&&[1,"","
        "]||!O.indexOf("",""]||(!O.indexOf("",""]||!O.indexOf("",""]||!o.support.htmlSerialize&&[1,"div
        ","
        "]||[0,"",""];L.innerHTML=Q[1]+S+Q[2];while(Q[0]--){L=L.lastChild}if(!o.support.tbody){var R=/"&&!R?L.childNodes:[];for(var M=N.length-1;M>=0;--M){if(o.nodeName(N[M],"tbody")&&!N[M].childNodes.length){N[M].parentNode.removeChild(N[M])}}}if(!o.support.leadingWhitespace&&/^\s/.test(S)){L.insertBefore(K.createTextNode(S.match(/^\s*/)[0]),L.firstChild)}S=o.makeArray(L.childNodes)}if(S.nodeType){G.push(S)}else{G=o.merge(G,S)}});if(I){for(var J=0;G[J];J++){if(o.nodeName(G[J],"script")&&(!G[J].type||G[J].type.toLowerCase()==="text/javascript")){E.push(G[J].parentNode?G[J].parentNode.removeChild(G[J]):G[J])}else{if(G[J].nodeType===1){G.splice.apply(G,[J+1,0].concat(o.makeArray(G[J].getElementsByTagName("script"))))}I.appendChild(G[J])}}return E}return G},attr:function(J,G,K){if(!J||J.nodeType==3||J.nodeType==8){return g}var H=!o.isXMLDoc(J),L=K!==g;G=H&&o.props[G]||G;if(J.tagName){var F=/href|src|style/.test(G);if(G=="selected"&&J.parentNode){J.parentNode.selectedIndex}if(G in J&&H&&!F){if(L){if(G=="type"&&o.nodeName(J,"input")&&J.parentNode){throw"type property can't be changed"}J[G]=K}if(o.nodeName(J,"form")&&J.getAttributeNode(G)){return J.getAttributeNode(G).nodeValue}if(G=="tabIndex"){var I=J.getAttributeNode("tabIndex");return I&&I.specified?I.value:J.nodeName.match(/(button|input|object|select|textarea)/i)?0:J.nodeName.match(/^(a|area)$/i)&&J.href?0:g}return J[G]}if(!o.support.style&&H&&G=="style"){return o.attr(J.style,"cssText",K)}if(L){J.setAttribute(G,""+K)}var E=!o.support.hrefNormalized&&H&&F?J.getAttribute(G,2):J.getAttribute(G);return E===null?g:E}if(!o.support.opacity&&G=="opacity"){if(L){J.zoom=1;J.filter=(J.filter||"").replace(/alpha\([^)]*\)/,"")+(parseInt(K)+""=="NaN"?"":"alpha(opacity="+K*100+")")}return J.filter&&J.filter.indexOf("opacity=")>=0?(parseFloat(J.filter.match(/opacity=([^)]*)/)[1])/100)+"":""}G=G.replace(/-([a-z])/ig,function(M,N){return N.toUpperCase()});if(L){J[G]=K}return J[G]},trim:function(E){return(E||"").replace(/^\s+|\s+$/g,"")},makeArray:function(G){var E=[];if(G!=null){var F=G.length;if(F==null||typeof G==="string"||o.isFunction(G)||G.setInterval){E[0]=G}else{while(F){E[--F]=G[F]}}}return E},inArray:function(G,H){for(var E=0,F=H.length;E0?this.clone(true):this).get();o.fn[F].apply(o(L[K]),I);J=J.concat(I)}return this.pushStack(J,E,G)}});o.each({removeAttr:function(E){o.attr(this,E,"");if(this.nodeType==1){this.removeAttribute(E)}},addClass:function(E){o.className.add(this,E)},removeClass:function(E){o.className.remove(this,E)},toggleClass:function(F,E){if(typeof E!=="boolean"){E=!o.className.has(this,F)}o.className[E?"add":"remove"](this,F)},remove:function(E){if(!E||o.filter(E,[this]).length){o("*",this).add([this]).each(function(){o.event.remove(this);o.removeData(this)});if(this.parentNode){this.parentNode.removeChild(this)}}},empty:function(){o(this).children().remove();while(this.firstChild){this.removeChild(this.firstChild)}}},function(E,F){o.fn[E]=function(){return this.each(F,arguments)}});function j(E,F){return E[0]&&parseInt(o.curCSS(E[0],F,true),10)||0}var h="jQuery"+e(),v=0,A={};o.extend({cache:{},data:function(F,E,G){F=F==l?A:F;var H=F[h];if(!H){H=F[h]=++v}if(E&&!o.cache[H]){o.cache[H]={}}if(G!==g){o.cache[H][E]=G}return E?o.cache[H][E]:H},removeData:function(F,E){F=F==l?A:F;var H=F[h];if(E){if(o.cache[H]){delete o.cache[H][E];E="";for(E in o.cache[H]){break}if(!E){o.removeData(F)}}}else{try{delete F[h]}catch(G){if(F.removeAttribute){F.removeAttribute(h)}}delete o.cache[H]}},queue:function(F,E,H){if(F){E=(E||"fx")+"queue";var G=o.data(F,E);if(!G||o.isArray(H)){G=o.data(F,E,o.makeArray(H))}else{if(H){G.push(H)}}}return G},dequeue:function(H,G){var E=o.queue(H,G),F=E.shift();if(!G||G==="fx"){F=E[0]}if(F!==g){F.call(H)}}});o.fn.extend({data:function(E,G){var H=E.split(".");H[1]=H[1]?"."+H[1]:"";if(G===g){var F=this.triggerHandler("getData"+H[1]+"!",[H[0]]);if(F===g&&this.length){F=o.data(this[0],E)}return F===g&&H[1]?this.data(H[0]):F}else{return this.trigger("setData"+H[1]+"!",[H[0],G]).each(function(){o.data(this,E,G)})}},removeData:function(E){return this.each(function(){o.removeData(this,E)})},queue:function(E,F){if(typeof E!=="string"){F=E;E="fx"}if(F===g){return o.queue(this[0],E)}return this.each(function(){var G=o.queue(this,E,F);if(E=="fx"&&G.length==1){G[0].call(this)}})},dequeue:function(E){return this.each(function(){o.dequeue(this,E)})}}); diff --git a/trunk/src/jquery_fx.js b/trunk/src/jquery_fx.js new file mode 100644 index 0000000..f3e326e --- /dev/null +++ b/trunk/src/jquery_fx.js @@ -0,0 +1,47 @@ +/* + * jQuery UI Effects 1.8.16 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Effects/ + */ +jQuery.effects||function(f,j){function m(c){var a;if(c&&c.constructor==Array&&c.length==3)return c;if(a=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(c))return[parseInt(a[1],10),parseInt(a[2],10),parseInt(a[3],10)];if(a=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(c))return[parseFloat(a[1])*2.55,parseFloat(a[2])*2.55,parseFloat(a[3])*2.55];if(a=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(c))return[parseInt(a[1], +16),parseInt(a[2],16),parseInt(a[3],16)];if(a=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(c))return[parseInt(a[1]+a[1],16),parseInt(a[2]+a[2],16),parseInt(a[3]+a[3],16)];if(/rgba\(0, 0, 0, 0\)/.exec(c))return n.transparent;return n[f.trim(c).toLowerCase()]}function s(c,a){var b;do{b=f.curCSS(c,a);if(b!=""&&b!="transparent"||f.nodeName(c,"body"))break;a="backgroundColor"}while(c=c.parentNode);return m(b)}function o(){var c=document.defaultView?document.defaultView.getComputedStyle(this,null):this.currentStyle, +a={},b,d;if(c&&c.length&&c[0]&&c[c[0]])for(var e=c.length;e--;){b=c[e];if(typeof c[b]=="string"){d=b.replace(/\-(\w)/g,function(g,h){return h.toUpperCase()});a[d]=c[b]}}else for(b in c)if(typeof c[b]==="string")a[b]=c[b];return a}function p(c){var a,b;for(a in c){b=c[a];if(b==null||f.isFunction(b)||a in t||/scrollbar/.test(a)||!/color/i.test(a)&&isNaN(parseFloat(b)))delete c[a]}return c}function u(c,a){var b={_:0},d;for(d in a)if(c[d]!=a[d])b[d]=a[d];return b}function k(c,a,b,d){if(typeof c=="object"){d= +a;b=null;a=c;c=a.effect}if(f.isFunction(a)){d=a;b=null;a={}}if(typeof a=="number"||f.fx.speeds[a]){d=b;b=a;a={}}if(f.isFunction(b)){d=b;b=null}a=a||{};b=b||a.duration;b=f.fx.off?0:typeof b=="number"?b:b in f.fx.speeds?f.fx.speeds[b]:f.fx.speeds._default;d=d||a.complete;return[c,a,b,d]}function l(c){if(!c||typeof c==="number"||f.fx.speeds[c])return true;if(typeof c==="string"&&!f.effects[c])return true;return false}f.effects={};f.each(["backgroundColor","borderBottomColor","borderLeftColor","borderRightColor", +"borderTopColor","borderColor","color","outlineColor"],function(c,a){f.fx.step[a]=function(b){if(!b.colorInit){b.start=s(b.elem,a);b.end=m(b.end);b.colorInit=true}b.elem.style[a]="rgb("+Math.max(Math.min(parseInt(b.pos*(b.end[0]-b.start[0])+b.start[0],10),255),0)+","+Math.max(Math.min(parseInt(b.pos*(b.end[1]-b.start[1])+b.start[1],10),255),0)+","+Math.max(Math.min(parseInt(b.pos*(b.end[2]-b.start[2])+b.start[2],10),255),0)+")"}});var n={aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0, +0,0],blue:[0,0,255],brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],darkgreen:[0,100,0],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],lightgrey:[211, +211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,165,0],pink:[255,192,203],purple:[128,0,128],violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0],transparent:[255,255,255]},q=["add","remove","toggle"],t={border:1,borderBottom:1,borderColor:1,borderLeft:1,borderRight:1,borderTop:1,borderWidth:1,margin:1,padding:1};f.effects.animateClass=function(c,a,b, +d){if(f.isFunction(b)){d=b;b=null}return this.queue(function(){var e=f(this),g=e.attr("style")||" ",h=p(o.call(this)),r,v=e.attr("class");f.each(q,function(w,i){c[i]&&e[i+"Class"](c[i])});r=p(o.call(this));e.attr("class",v);e.animate(u(h,r),{queue:false,duration:a,easing:b,complete:function(){f.each(q,function(w,i){c[i]&&e[i+"Class"](c[i])});if(typeof e.attr("style")=="object"){e.attr("style").cssText="";e.attr("style").cssText=g}else e.attr("style",g);d&&d.apply(this,arguments);f.dequeue(this)}})})}; +f.fn.extend({_addClass:f.fn.addClass,addClass:function(c,a,b,d){return a?f.effects.animateClass.apply(this,[{add:c},a,b,d]):this._addClass(c)},_removeClass:f.fn.removeClass,removeClass:function(c,a,b,d){return a?f.effects.animateClass.apply(this,[{remove:c},a,b,d]):this._removeClass(c)},_toggleClass:f.fn.toggleClass,toggleClass:function(c,a,b,d,e){return typeof a=="boolean"||a===j?b?f.effects.animateClass.apply(this,[a?{add:c}:{remove:c},b,d,e]):this._toggleClass(c,a):f.effects.animateClass.apply(this, +[{toggle:c},a,b,d])},switchClass:function(c,a,b,d,e){return f.effects.animateClass.apply(this,[{add:a,remove:c},b,d,e])}});f.extend(f.effects,{version:"1.8.16",save:function(c,a){for(var b=0;b
      ").addClass("ui-effects-wrapper").css({fontSize:"100%",background:"transparent",border:"none",margin:0,padding:0}), +d=document.activeElement;c.wrap(b);if(c[0]===d||f.contains(c[0],d))f(d).focus();b=c.parent();if(c.css("position")=="static"){b.css({position:"relative"});c.css({position:"relative"})}else{f.extend(a,{position:c.css("position"),zIndex:c.css("z-index")});f.each(["top","left","bottom","right"],function(e,g){a[g]=c.css(g);if(isNaN(parseInt(a[g],10)))a[g]="auto"});c.css({position:"relative",top:0,left:0,right:"auto",bottom:"auto"})}return b.css(a).show()},removeWrapper:function(c){var a,b=document.activeElement; +if(c.parent().is(".ui-effects-wrapper")){a=c.parent().replaceWith(c);if(c[0]===b||f.contains(c[0],b))f(b).focus();return a}return c},setTransition:function(c,a,b,d){d=d||{};f.each(a,function(e,g){unit=c.cssUnit(g);if(unit[0]>0)d[g]=unit[0]*b+unit[1]});return d}});f.fn.extend({effect:function(c){var a=k.apply(this,arguments),b={options:a[1],duration:a[2],callback:a[3]};a=b.options.mode;var d=f.effects[c];if(f.fx.off||!d)return a?this[a](b.duration,b.callback):this.each(function(){b.callback&&b.callback.call(this)}); +return d.call(this,b)},_show:f.fn.show,show:function(c){if(l(c))return this._show.apply(this,arguments);else{var a=k.apply(this,arguments);a[1].mode="show";return this.effect.apply(this,a)}},_hide:f.fn.hide,hide:function(c){if(l(c))return this._hide.apply(this,arguments);else{var a=k.apply(this,arguments);a[1].mode="hide";return this.effect.apply(this,a)}},__toggle:f.fn.toggle,toggle:function(c){if(l(c)||typeof c==="boolean"||f.isFunction(c))return this.__toggle.apply(this,arguments);else{var a=k.apply(this, +arguments);a[1].mode="toggle";return this.effect.apply(this,a)}},cssUnit:function(c){var a=this.css(c),b=[];f.each(["em","px","%","pt"],function(d,e){if(a.indexOf(e)>0)b=[parseFloat(a),e]});return b}});f.easing.jswing=f.easing.swing;f.extend(f.easing,{def:"easeOutQuad",swing:function(c,a,b,d,e){return f.easing[f.easing.def](c,a,b,d,e)},easeInQuad:function(c,a,b,d,e){return d*(a/=e)*a+b},easeOutQuad:function(c,a,b,d,e){return-d*(a/=e)*(a-2)+b},easeInOutQuad:function(c,a,b,d,e){if((a/=e/2)<1)return d/ +2*a*a+b;return-d/2*(--a*(a-2)-1)+b},easeInCubic:function(c,a,b,d,e){return d*(a/=e)*a*a+b},easeOutCubic:function(c,a,b,d,e){return d*((a=a/e-1)*a*a+1)+b},easeInOutCubic:function(c,a,b,d,e){if((a/=e/2)<1)return d/2*a*a*a+b;return d/2*((a-=2)*a*a+2)+b},easeInQuart:function(c,a,b,d,e){return d*(a/=e)*a*a*a+b},easeOutQuart:function(c,a,b,d,e){return-d*((a=a/e-1)*a*a*a-1)+b},easeInOutQuart:function(c,a,b,d,e){if((a/=e/2)<1)return d/2*a*a*a*a+b;return-d/2*((a-=2)*a*a*a-2)+b},easeInQuint:function(c,a,b, +d,e){return d*(a/=e)*a*a*a*a+b},easeOutQuint:function(c,a,b,d,e){return d*((a=a/e-1)*a*a*a*a+1)+b},easeInOutQuint:function(c,a,b,d,e){if((a/=e/2)<1)return d/2*a*a*a*a*a+b;return d/2*((a-=2)*a*a*a*a+2)+b},easeInSine:function(c,a,b,d,e){return-d*Math.cos(a/e*(Math.PI/2))+d+b},easeOutSine:function(c,a,b,d,e){return d*Math.sin(a/e*(Math.PI/2))+b},easeInOutSine:function(c,a,b,d,e){return-d/2*(Math.cos(Math.PI*a/e)-1)+b},easeInExpo:function(c,a,b,d,e){return a==0?b:d*Math.pow(2,10*(a/e-1))+b},easeOutExpo:function(c, +a,b,d,e){return a==e?b+d:d*(-Math.pow(2,-10*a/e)+1)+b},easeInOutExpo:function(c,a,b,d,e){if(a==0)return b;if(a==e)return b+d;if((a/=e/2)<1)return d/2*Math.pow(2,10*(a-1))+b;return d/2*(-Math.pow(2,-10*--a)+2)+b},easeInCirc:function(c,a,b,d,e){return-d*(Math.sqrt(1-(a/=e)*a)-1)+b},easeOutCirc:function(c,a,b,d,e){return d*Math.sqrt(1-(a=a/e-1)*a)+b},easeInOutCirc:function(c,a,b,d,e){if((a/=e/2)<1)return-d/2*(Math.sqrt(1-a*a)-1)+b;return d/2*(Math.sqrt(1-(a-=2)*a)+1)+b},easeInElastic:function(c,a,b, +d,e){c=1.70158;var g=0,h=d;if(a==0)return b;if((a/=e)==1)return b+d;g||(g=e*0.3);if(h
  • \").addClass(\"ui-effects-wrapper\").css({fontSize:\"100%\",background:\"transparent\",border:\"none\",margin:0,padding:0}),\n" +"d=document.activeElement;c.wrap(b);if(c[0]===d||f.contains(c[0],d))f(d).focus();b=c.parent();if(c.css(\"position\")==\"static\"){b.css({position:\"relative\"});c.css({position:\"relative\"})}else{f.extend(a,{position:c.css(\"position\"),zIndex:c.css(\"z-index\")});f.each([\"top\",\"left\",\"bottom\",\"right\"],function(e,g){a[g]=c.css(g);if(isNaN(parseInt(a[g],10)))a[g]=\"auto\"});c.css({position:\"relative\",top:0,left:0,right:\"auto\",bottom:\"auto\"})}return b.css(a).show()},removeWrapper:function(c){var a,b=document.activeElement;\n" +"if(c.parent().is(\".ui-effects-wrapper\")){a=c.parent().replaceWith(c);if(c[0]===b||f.contains(c[0],b))f(b).focus();return a}return c},setTransition:function(c,a,b,d){d=d||{};f.each(a,function(e,g){unit=c.cssUnit(g);if(unit[0]>0)d[g]=unit[0]*b+unit[1]});return d}});f.fn.extend({effect:function(c){var a=k.apply(this,arguments),b={options:a[1],duration:a[2],callback:a[3]};a=b.options.mode;var d=f.effects[c];if(f.fx.off||!d)return a?this[a](b.duration,b.callback):this.each(function(){b.callback&&b.callback.call(this)});\n" +"return d.call(this,b)},_show:f.fn.show,show:function(c){if(l(c))return this._show.apply(this,arguments);else{var a=k.apply(this,arguments);a[1].mode=\"show\";return this.effect.apply(this,a)}},_hide:f.fn.hide,hide:function(c){if(l(c))return this._hide.apply(this,arguments);else{var a=k.apply(this,arguments);a[1].mode=\"hide\";return this.effect.apply(this,a)}},__toggle:f.fn.toggle,toggle:function(c){if(l(c)||typeof c===\"boolean\"||f.isFunction(c))return this.__toggle.apply(this,arguments);else{var a=k.apply(this,\n" +"arguments);a[1].mode=\"toggle\";return this.effect.apply(this,a)}},cssUnit:function(c){var a=this.css(c),b=[];f.each([\"em\",\"px\",\"%\",\"pt\"],function(d,e){if(a.indexOf(e)>0)b=[parseFloat(a),e]});return b}});f.easing.jswing=f.easing.swing;f.extend(f.easing,{def:\"easeOutQuad\",swing:function(c,a,b,d,e){return f.easing[f.easing.def](c,a,b,d,e)},easeInQuad:function(c,a,b,d,e){return d*(a/=e)*a+b},easeOutQuad:function(c,a,b,d,e){return-d*(a/=e)*(a-2)+b},easeInOutQuad:function(c,a,b,d,e){if((a/=e/2)<1)return d/\n" +"2*a*a+b;return-d/2*(--a*(a-2)-1)+b},easeInCubic:function(c,a,b,d,e){return d*(a/=e)*a*a+b},easeOutCubic:function(c,a,b,d,e){return d*((a=a/e-1)*a*a+1)+b},easeInOutCubic:function(c,a,b,d,e){if((a/=e/2)<1)return d/2*a*a*a+b;return d/2*((a-=2)*a*a+2)+b},easeInQuart:function(c,a,b,d,e){return d*(a/=e)*a*a*a+b},easeOutQuart:function(c,a,b,d,e){return-d*((a=a/e-1)*a*a*a-1)+b},easeInOutQuart:function(c,a,b,d,e){if((a/=e/2)<1)return d/2*a*a*a*a+b;return-d/2*((a-=2)*a*a*a-2)+b},easeInQuint:function(c,a,b,\n" +"d,e){return d*(a/=e)*a*a*a*a+b},easeOutQuint:function(c,a,b,d,e){return d*((a=a/e-1)*a*a*a*a+1)+b},easeInOutQuint:function(c,a,b,d,e){if((a/=e/2)<1)return d/2*a*a*a*a*a+b;return d/2*((a-=2)*a*a*a*a+2)+b},easeInSine:function(c,a,b,d,e){return-d*Math.cos(a/e*(Math.PI/2))+d+b},easeOutSine:function(c,a,b,d,e){return d*Math.sin(a/e*(Math.PI/2))+b},easeInOutSine:function(c,a,b,d,e){return-d/2*(Math.cos(Math.PI*a/e)-1)+b},easeInExpo:function(c,a,b,d,e){return a==0?b:d*Math.pow(2,10*(a/e-1))+b},easeOutExpo:function(c,\n" +"a,b,d,e){return a==e?b+d:d*(-Math.pow(2,-10*a/e)+1)+b},easeInOutExpo:function(c,a,b,d,e){if(a==0)return b;if(a==e)return b+d;if((a/=e/2)<1)return d/2*Math.pow(2,10*(a-1))+b;return d/2*(-Math.pow(2,-10*--a)+2)+b},easeInCirc:function(c,a,b,d,e){return-d*(Math.sqrt(1-(a/=e)*a)-1)+b},easeOutCirc:function(c,a,b,d,e){return d*Math.sqrt(1-(a=a/e-1)*a)+b},easeInOutCirc:function(c,a,b,d,e){if((a/=e/2)<1)return-d/2*(Math.sqrt(1-a*a)-1)+b;return d/2*(Math.sqrt(1-(a-=2)*a)+1)+b},easeInElastic:function(c,a,b,\n" +"d,e){c=1.70158;var g=0,h=d;if(a==0)return b;if((a/=e)==1)return b+d;g||(g=e*0.3);if(h)[^>]*$|^#([\\w-]+)$/,f=/^.[^:#\\[\\.,]*$/;o.fn=o.prototype={init:function(E,H){E=E||document;if(E.nodeType){this[0]=E;this.length=1;this.context=E;return this}if(typeof E===\"string\"){var G=D.exec(E);if(G&&(G[1]||!H)){if(G[1]){E=o.clean([G[1]],H)}else{var I=document.getElementById(G[3]);if(I&&I.id!=G[3]){return o().find(E)}var F=o(I||[]);F.context=document;F.selector=E;return F}}else{return o(H).find(E)}}else{if(o.isFunction(E)){return o(document).ready(E)}}if(E.selector&&E.context){this.selector=E.selector;this.context=E.context}return this.setArray(o.isArray(E)?E:o.makeArray(E))},selector:\"\",jquery:\"1.3.2\",size:function(){return this.length},get:function(E){return E===g?Array.prototype.slice.call(this):this[E]},pushStack:function(F,H,E){var G=o(F);G.prevObject=this;G.context=this.context;if(H===\"find\"){G.selector=this.selector+(this.selector?\" \":\"\")+E}else{if(H){G.selector=this.selector+\".\"+H+\"(\"+E+\")\"}}return G},setArray:function(E){this.length=0;Array.prototype.push.apply(this,E);return this},each:function(F,E){return o.each(this,F,E)},index:function(E){return o.inArray(E&&E.jquery?E[0]:E,this)},attr:function(F,H,G){var E=F;if(typeof F===\"string\"){if(H===g){return this[0]&&o[G||\"attr\"](this[0],F)}else{E={};E[F]=H}}return this.each(function(I){for(F in E){o.attr(G?this.style:this,F,o.prop(this,E[F],G,I,F))}})},css:function(E,F){if((E==\"width\"||E==\"height\")&&parseFloat(F)<0){F=g}return this.attr(E,F,\"curCSS\")},text:function(F){if(typeof F!==\"object\"&&F!=null){return this.empty().append((this[0]&&this[0].ownerDocument||document).createTextNode(F))}var E=\"\";o.each(F||this,function(){o.each(this.childNodes,function(){if(this.nodeType!=8){E+=this.nodeType!=1?this.nodeValue:o.fn.text([this])}})});return E},wrapAll:function(E){if(this[0]){var F=o(E,this[0].ownerDocument).clone();if(this[0].parentNode){F.insertBefore(this[0])}F.map(function(){var G=this;while(G.firstChild){G=G.firstChild}return G}).append(this)}return this},wrapInner:function(E){return this.each(function(){o(this).contents().wrapAll(E)})},wrap:function(E){return this.each(function(){o(this).wrapAll(E)})},append:function(){return this.domManip(arguments,true,function(E){if(this.nodeType==1){this.appendChild(E)}})},prepend:function(){return this.domManip(arguments,true,function(E){if(this.nodeType==1){this.insertBefore(E,this.firstChild)}})},before:function(){return this.domManip(arguments,false,function(E){this.parentNode.insertBefore(E,this)})},after:function(){return this.domManip(arguments,false,function(E){this.parentNode.insertBefore(E,this.nextSibling)})},end:function(){return this.prevObject||o([])},push:[].push,sort:[].sort,splice:[].splice,find:function(E){if(this.length===1){var F=this.pushStack([],\"find\",E);F.length=0;o.find(E,this[0],F);return F}else{return this.pushStack(o.unique(o.map(this,function(G){return o.find(E,G)})),\"find\",E)}},clone:function(G){var E=this.map(function(){if(!o.support.noCloneEvent&&!o.isXMLDoc(this)){var I=this.outerHTML;if(!I){var J=this.ownerDocument.createElement(\"div\");J.appendChild(this.cloneNode(true));I=J.innerHTML}return o.clean([I.replace(/ jQuery\\d+=\"(?:\\d+|null)\"/g,\"\").replace(/^\\s*/,\"\")])[0]}else{return this.cloneNode(true)}});if(G===true){var H=this.find(\"*\").andSelf(),F=0;E.find(\"*\").andSelf().each(function(){if(this.nodeName!==H[F].nodeName){return}var I=o.data(H[F],\"events\");for(var K in I){for(var J in I[K]){o.event.add(this,K,I[K][J],I[K][J].data)}}F++})}return E},filter:function(E){return this.pushStack(o.isFunction(E)&&o.grep(this,function(G,F){return E.call(G,F)})||o.multiFilter(E,o.grep(this,function(F){return F.nodeType===1})),\"filter\",E)},closest:function(E){var G=o.expr.match.POS.test(E)?o(E):null,F=0;return this.map(function(){var H=this;while(H&&H.ownerDocument){if(G?G.index(H)>-1:o(H).is(E)){o.data(H,\"closest\",F);return H}H=H.parentNode;F++}})},not:function(E){if(typeof E===\"string\"){if(f.test(E)){return this.pushStack(o.multiFilter(E,this,true),\"not\",E)}else{E=o.multiFilter(E,this)}}var F=E.length&&E[E.length-1]!==g&&!E.nodeType;return this.filter(function(){return F?o.inArray(this,E)<0:this!=E})},add:function(E){return this.pushStack(o.unique(o.merge(this.get(),typeof E===\"string\"?o(E):o.makeArray(E))))},is:function(E){return !!E&&o.multiFilter(E,this).length>0},hasClass:function(E){return !!E&&this.is(\".\"+E)},val:function(K){if(K===g){var E=this[0];if(E){if(o.nodeName(E,\"option\")){return(E.attributes.value||{}).specified?E.value:E.text}if(o.nodeName(E,\"select\")){var I=E.selectedIndex,L=[],M=E.options,H=E.type==\"select-one\";if(I<0){return null}for(var F=H?I:0,J=H?I+1:M.length;F=0||o.inArray(this.name,K)>=0)}else{if(o.nodeName(this,\"select\")){var N=o.makeArray(K);o(\"option\",this).each(function(){this.selected=(o.inArray(this.value,N)>=0||o.inArray(this.text,N)>=0)});if(!N.length){this.selectedIndex=-1}}else{this.value=K}}})},html:function(E){return E===g?(this[0]?this[0].innerHTML.replace(/ jQuery\\d+=\"(?:\\d+|null)\"/g,\"\"):null):this.empty().append(E)},replaceWith:function(E){return this.after(E).remove()},eq:function(E){return this.slice(E,+E+1)},slice:function(){return this.pushStack(Array.prototype.slice.apply(this,arguments),\"slice\",Array.prototype.slice.call(arguments).join(\",\"))},map:function(E){return this.pushStack(o.map(this,function(G,F){return E.call(G,F,G)}))},andSelf:function(){return this.add(this.prevObject)},domManip:function(J,M,L){if(this[0]){var I=(this[0].ownerDocument||this[0]).createDocumentFragment(),F=o.clean(J,(this[0].ownerDocument||this[0]),I),H=I.firstChild;if(H){for(var G=0,E=this.length;G1||G>0?I.cloneNode(true):I)}}if(F){o.each(F,z)}}return this;function K(N,O){return M&&o.nodeName(N,\"table\")&&o.nodeName(O,\"tr\")?(N.getElementsByTagName(\"tbody\")[0]||N.appendChild(N.ownerDocument.createElement(\"tbody\"))):N}}};o.fn.init.prototype=o.fn;function z(E,F){if(F.src){o.ajax({url:F.src,async:false,dataType:\"script\"})}else{o.globalEval(F.text||F.textContent||F.innerHTML||\"\")}if(F.parentNode){F.parentNode.removeChild(F)}}function e(){return +new Date}o.extend=o.fn.extend=function(){var J=arguments[0]||{},H=1,I=arguments.length,E=false,G;if(typeof J===\"boolean\"){E=J;J=arguments[1]||{};H=2}if(typeof J!==\"object\"&&!o.isFunction(J)){J={}}if(I==H){J=this;--H}for(;H-1}},swap:function(H,G,I){var E={};for(var F in G){E[F]=H.style[F];H.style[F]=G[F]}I.call(H);for(var F in G){H.style[F]=E[F]}},css:function(H,F,J,E){if(F==\"width\"||F==\"height\"){var L,G={position:\"absolute\",visibility:\"hidden\",display:\"block\"},K=F==\"width\"?[\"Left\",\"Right\"]:[\"Top\",\"Bottom\"];function I(){L=F==\"width\"?H.offsetWidth:H.offsetHeight;if(E===\"border\"){return}o.each(K,function(){if(!E){L-=parseFloat(o.curCSS(H,\"padding\"+this,true))||0}if(E===\"margin\"){L+=parseFloat(o.curCSS(H,\"margin\"+this,true))||0}else{L-=parseFloat(o.curCSS(H,\"border\"+this+\"Width\",true))||0}})}if(H.offsetWidth!==0){I()}else{o.swap(H,G,I)}return Math.max(0,Math.round(L))}return o.curCSS(H,F,J)},curCSS:function(I,F,G){var L,E=I.style;if(F==\"opacity\"&&!o.support.opacity){L=o.attr(E,\"opacity\");return L==\"\"?\"1\":L}if(F.match(/float/i)){F=w}if(!G&&E&&E[F]){L=E[F]}else{if(q.getComputedStyle){if(F.match(/float/i)){F=\"float\"}F=F.replace(/([A-Z])/g,\"-$1\").toLowerCase();var M=q.getComputedStyle(I,null);if(M){L=M.getPropertyValue(F)}if(F==\"opacity\"&&L==\"\"){L=\"1\"}}else{if(I.currentStyle){var J=F.replace(/\\-(\\w)/g,function(N,O){return O.toUpperCase()});L=I.currentStyle[F]||I.currentStyle[J];if(!/^\\d+(px)?$/i.test(L)&&/^\\d/.test(L)){var H=E.left,K=I.runtimeStyle.left;I.runtimeStyle.left=I.currentStyle.left;E.left=L||0;L=E.pixelLeft+\"px\";E.left=H;I.runtimeStyle.left=K}}}}return L},clean:function(F,K,I){K=K||document;if(typeof K.createElement===\"undefined\"){K=K.ownerDocument||K[0]&&K[0].ownerDocument||document}if(!I&&F.length===1&&typeof F[0]===\"string\"){var H=/^<(\\w+)\\s*\\/?>$/.exec(F[0]);if(H){return[K.createElement(H[1])]}}var G=[],E=[],L=K.createElement(\"div\");o.each(F,function(P,S){if(typeof S===\"number\"){S+=\"\"}if(!S){return}if(typeof S===\"string\"){S=S.replace(/(<(\\w+)[^>]*?)\\/>/g,function(U,V,T){return T.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i)?U:V+\">\"});var O=S.replace(/^\\s+/,\"\").substring(0,10).toLowerCase();var Q=!O.indexOf(\"\",\"\"]||!O.indexOf(\"\",\"\"]||O.match(/^<(thead|tbody|tfoot|colg|cap)/)&&[1,\"\",\"
    \"]||!O.indexOf(\"\",\"\"]||(!O.indexOf(\"\",\"\"]||!O.indexOf(\"\",\"\"]||!o.support.htmlSerialize&&[1,\"div
    \",\"
    \"]||[0,\"\",\"\"];L.innerHTML=Q[1]+S+Q[2];while(Q[0]--){L=L.lastChild}if(!o.support.tbody){var R=/\"&&!R?L.childNodes:[];for(var M=N.length-1;M>=0;--M){if(o.nodeName(N[M],\"tbody\")&&!N[M].childNodes.length){N[M].parentNode.removeChild(N[M])}}}if(!o.support.leadingWhitespace&&/^\\s/.test(S)){L.insertBefore(K.createTextNode(S.match(/^\\s*/)[0]),L.firstChild)}S=o.makeArray(L.childNodes)}if(S.nodeType){G.push(S)}else{G=o.merge(G,S)}});if(I){for(var J=0;G[J];J++){if(o.nodeName(G[J],\"script\")&&(!G[J].type||G[J].type.toLowerCase()===\"text/javascript\")){E.push(G[J].parentNode?G[J].parentNode.removeChild(G[J]):G[J])}else{if(G[J].nodeType===1){G.splice.apply(G,[J+1,0].concat(o.makeArray(G[J].getElementsByTagName(\"script\"))))}I.appendChild(G[J])}}return E}return G},attr:function(J,G,K){if(!J||J.nodeType==3||J.nodeType==8){return g}var H=!o.isXMLDoc(J),L=K!==g;G=H&&o.props[G]||G;if(J.tagName){var F=/href|src|style/.test(G);if(G==\"selected\"&&J.parentNode){J.parentNode.selectedIndex}if(G in J&&H&&!F){if(L){if(G==\"type\"&&o.nodeName(J,\"input\")&&J.parentNode){throw\"type property can't be changed\"}J[G]=K}if(o.nodeName(J,\"form\")&&J.getAttributeNode(G)){return J.getAttributeNode(G).nodeValue}if(G==\"tabIndex\"){var I=J.getAttributeNode(\"tabIndex\");return I&&I.specified?I.value:J.nodeName.match(/(button|input|object|select|textarea)/i)?0:J.nodeName.match(/^(a|area)$/i)&&J.href?0:g}return J[G]}if(!o.support.style&&H&&G==\"style\"){return o.attr(J.style,\"cssText\",K)}if(L){J.setAttribute(G,\"\"+K)}var E=!o.support.hrefNormalized&&H&&F?J.getAttribute(G,2):J.getAttribute(G);return E===null?g:E}if(!o.support.opacity&&G==\"opacity\"){if(L){J.zoom=1;J.filter=(J.filter||\"\").replace(/alpha\\([^)]*\\)/,\"\")+(parseInt(K)+\"\"==\"NaN\"?\"\":\"alpha(opacity=\"+K*100+\")\")}return J.filter&&J.filter.indexOf(\"opacity=\")>=0?(parseFloat(J.filter.match(/opacity=([^)]*)/)[1])/100)+\"\":\"\"}G=G.replace(/-([a-z])/ig,function(M,N){return N.toUpperCase()});if(L){J[G]=K}return J[G]},trim:function(E){return(E||\"\").replace(/^\\s+|\\s+$/g,\"\")},makeArray:function(G){var E=[];if(G!=null){var F=G.length;if(F==null||typeof G===\"string\"||o.isFunction(G)||G.setInterval){E[0]=G}else{while(F){E[--F]=G[F]}}}return E},inArray:function(G,H){for(var E=0,F=H.length;E0?this.clone(true):this).get();o.fn[F].apply(o(L[K]),I);J=J.concat(I)}return this.pushStack(J,E,G)}});o.each({removeAttr:function(E){o.attr(this,E,\"\");if(this.nodeType==1){this.removeAttribute(E)}},addClass:function(E){o.className.add(this,E)},removeClass:function(E){o.className.remove(this,E)},toggleClass:function(F,E){if(typeof E!==\"boolean\"){E=!o.className.has(this,F)}o.className[E?\"add\":\"remove\"](this,F)},remove:function(E){if(!E||o.filter(E,[this]).length){o(\"*\",this).add([this]).each(function(){o.event.remove(this);o.removeData(this)});if(this.parentNode){this.parentNode.removeChild(this)}}},empty:function(){o(this).children().remove();while(this.firstChild){this.removeChild(this.firstChild)}}},function(E,F){o.fn[E]=function(){return this.each(F,arguments)}});function j(E,F){return E[0]&&parseInt(o.curCSS(E[0],F,true),10)||0}var h=\"jQuery\"+e(),v=0,A={};o.extend({cache:{},data:function(F,E,G){F=F==l?A:F;var H=F[h];if(!H){H=F[h]=++v}if(E&&!o.cache[H]){o.cache[H]={}}if(G!==g){o.cache[H][E]=G}return E?o.cache[H][E]:H},removeData:function(F,E){F=F==l?A:F;var H=F[h];if(E){if(o.cache[H]){delete o.cache[H][E];E=\"\";for(E in o.cache[H]){break}if(!E){o.removeData(F)}}}else{try{delete F[h]}catch(G){if(F.removeAttribute){F.removeAttribute(h)}}delete o.cache[H]}},queue:function(F,E,H){if(F){E=(E||\"fx\")+\"queue\";var G=o.data(F,E);if(!G||o.isArray(H)){G=o.data(F,E,o.makeArray(H))}else{if(H){G.push(H)}}}return G},dequeue:function(H,G){var E=o.queue(H,G),F=E.shift();if(!G||G===\"fx\"){F=E[0]}if(F!==g){F.call(H)}}});o.fn.extend({data:function(E,G){var H=E.split(\".\");H[1]=H[1]?\".\"+H[1]:\"\";if(G===g){var F=this.triggerHandler(\"getData\"+H[1]+\"!\",[H[0]]);if(F===g&&this.length){F=o.data(this[0],E)}return F===g&&H[1]?this.data(H[0]):F}else{return this.trigger(\"setData\"+H[1]+\"!\",[H[0],G]).each(function(){o.data(this,E,G)})}},removeData:function(E){return this.each(function(){o.removeData(this,E)})},queue:function(E,F){if(typeof E!==\"string\"){F=E;E=\"fx\"}if(F===g){return o.queue(this[0],E)}return this.each(function(){var G=o.queue(this,E,F);if(E==\"fx\"&&G.length==1){G[0].call(this)}})},dequeue:function(E){return this.each(function(){o.dequeue(this,E)})}});\n" diff --git a/trunk/src/jquery_ui.js b/trunk/src/jquery_ui.js new file mode 100644 index 0000000..facb8dd --- /dev/null +++ b/trunk/src/jquery_ui.js @@ -0,0 +1,32 @@ +/* + * jQuery UI 1.7.2 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI + */ +jQuery.ui||(function(c){var i=c.fn.remove,d=c.browser.mozilla&&(parseFloat(c.browser.version)<1.9);c.ui={version:"1.7.2",plugin:{add:function(k,l,n){var m=c.ui[k].prototype;for(var j in n){m.plugins[j]=m.plugins[j]||[];m.plugins[j].push([l,n[j]])}},call:function(j,l,k){var n=j.plugins[l];if(!n||!j.element[0].parentNode){return}for(var m=0;m0){return true}m[j]=1;l=(m[j]>0);m[j]=0;return l},isOverAxis:function(k,j,l){return(k>j)&&(k<(j+l))},isOver:function(o,k,n,m,j,l){return c.ui.isOverAxis(o,n,j)&&c.ui.isOverAxis(k,m,l)},keyCode:{BACKSPACE:8,CAPS_LOCK:20,COMMA:188,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SHIFT:16,SPACE:32,TAB:9,UP:38}};if(d){var f=c.attr,e=c.fn.removeAttr,h="http://www.w3.org/2005/07/aaa",a=/^aria-/,b=/^wairole:/;c.attr=function(k,j,l){var m=l!==undefined;return(j=="role"?(m?f.call(this,k,j,"wairole:"+l):(f.apply(this,arguments)||"").replace(b,"")):(a.test(j)?(m?k.setAttributeNS(h,j.replace(a,"aaa:"),l):f.call(this,k,j.replace(a,"aaa:"))):f.apply(this,arguments)))};c.fn.removeAttr=function(j){return(a.test(j)?this.each(function(){this.removeAttributeNS(h,j.replace(a,""))}):e.call(this,j))}}c.fn.extend({remove:function(){c("*",this).add(this).each(function(){c(this).triggerHandler("remove")});return i.apply(this,arguments)},enableSelection:function(){return this.attr("unselectable","off").css("MozUserSelect","").unbind("selectstart.ui")},disableSelection:function(){return this.attr("unselectable","on").css("MozUserSelect","none").bind("selectstart.ui",function(){return false})},scrollParent:function(){var j;if((c.browser.msie&&(/(static|relative)/).test(this.css("position")))||(/absolute/).test(this.css("position"))){j=this.parents().filter(function(){return(/(relative|absolute|fixed)/).test(c.curCSS(this,"position",1))&&(/(auto|scroll)/).test(c.curCSS(this,"overflow",1)+c.curCSS(this,"overflow-y",1)+c.curCSS(this,"overflow-x",1))}).eq(0)}else{j=this.parents().filter(function(){return(/(auto|scroll)/).test(c.curCSS(this,"overflow",1)+c.curCSS(this,"overflow-y",1)+c.curCSS(this,"overflow-x",1))}).eq(0)}return(/fixed/).test(this.css("position"))||!j.length?c(document):j}});c.extend(c.expr[":"],{data:function(l,k,j){return !!c.data(l,j[3])},focusable:function(k){var l=k.nodeName.toLowerCase(),j=c.attr(k,"tabindex");return(/input|select|textarea|button|object/.test(l)?!k.disabled:"a"==l||"area"==l?k.href||!isNaN(j):!isNaN(j))&&!c(k)["area"==l?"parents":"closest"](":hidden").length},tabbable:function(k){var j=c.attr(k,"tabindex");return(isNaN(j)||j>=0)&&c(k).is(":focusable")}});function g(m,n,o,l){function k(q){var p=c[m][n][q]||[];return(typeof p=="string"?p.split(/,?\s+/):p)}var j=k("getter");if(l.length==1&&typeof l[0]=="string"){j=j.concat(k("getterSetter"))}return(c.inArray(o,j)!=-1)}c.widget=function(k,j){var l=k.split(".")[0];k=k.split(".")[1];c.fn[k]=function(p){var n=(typeof p=="string"),o=Array.prototype.slice.call(arguments,1);if(n&&p.substring(0,1)=="_"){return this}if(n&&g(l,k,p,o)){var m=c.data(this[0],k);return(m?m[p].apply(m,o):undefined)}return this.each(function(){var q=c.data(this,k);(!q&&!n&&c.data(this,k,new c[l][k](this,p))._init());(q&&n&&c.isFunction(q[p])&&q[p].apply(q,o))})};c[l]=c[l]||{};c[l][k]=function(o,n){var m=this;this.namespace=l;this.widgetName=k;this.widgetEventPrefix=c[l][k].eventPrefix||k;this.widgetBaseClass=l+"-"+k;this.options=c.extend({},c.widget.defaults,c[l][k].defaults,c.metadata&&c.metadata.get(o)[k],n);this.element=c(o).bind("setData."+k,function(q,p,r){if(q.target==o){return m._setData(p,r)}}).bind("getData."+k,function(q,p){if(q.target==o){return m._getData(p)}}).bind("remove",function(){return m.destroy()})};c[l][k].prototype=c.extend({},c.widget.prototype,j);c[l][k].getterSetter="option"};c.widget.prototype={_init:function(){},destroy:function(){this.element.removeData(this.widgetName).removeClass(this.widgetBaseClass+"-disabled "+this.namespace+"-state-disabled").removeAttr("aria-disabled")},option:function(l,m){var k=l,j=this;if(typeof l=="string"){if(m===undefined){return this._getData(l)}k={};k[l]=m}c.each(k,function(n,o){j._setData(n,o)})},_getData:function(j){return this.options[j]},_setData:function(j,k){this.options[j]=k;if(j=="disabled"){this.element[k?"addClass":"removeClass"](this.widgetBaseClass+"-disabled "+this.namespace+"-state-disabled").attr("aria-disabled",k)}},enable:function(){this._setData("disabled",false)},disable:function(){this._setData("disabled",true)},_trigger:function(l,m,n){var p=this.options[l],j=(l==this.widgetEventPrefix?l:this.widgetEventPrefix+l);m=c.Event(m);m.type=j;if(m.originalEvent){for(var k=c.event.props.length,o;k;){o=c.event.props[--k];m[o]=m.originalEvent[o]}}this.element.trigger(m,n);return !(c.isFunction(p)&&p.call(this.element[0],m,n)===false||m.isDefaultPrevented())}};c.widget.defaults={disabled:false};c.ui.mouse={_mouseInit:function(){var j=this;this.element.bind("mousedown."+this.widgetName,function(k){return j._mouseDown(k)}).bind("click."+this.widgetName,function(k){if(j._preventClickEvent){j._preventClickEvent=false;k.stopImmediatePropagation();return false}});if(c.browser.msie){this._mouseUnselectable=this.element.attr("unselectable");this.element.attr("unselectable","on")}this.started=false},_mouseDestroy:function(){this.element.unbind("."+this.widgetName);(c.browser.msie&&this.element.attr("unselectable",this._mouseUnselectable))},_mouseDown:function(l){l.originalEvent=l.originalEvent||{};if(l.originalEvent.mouseHandled){return}(this._mouseStarted&&this._mouseUp(l));this._mouseDownEvent=l;var k=this,m=(l.which==1),j=(typeof this.options.cancel=="string"?c(l.target).parents().add(l.target).filter(this.options.cancel).length:false);if(!m||j||!this._mouseCapture(l)){return true}this.mouseDelayMet=!this.options.delay;if(!this.mouseDelayMet){this._mouseDelayTimer=setTimeout(function(){k.mouseDelayMet=true},this.options.delay)}if(this._mouseDistanceMet(l)&&this._mouseDelayMet(l)){this._mouseStarted=(this._mouseStart(l)!==false);if(!this._mouseStarted){l.preventDefault();return true}}this._mouseMoveDelegate=function(n){return k._mouseMove(n)};this._mouseUpDelegate=function(n){return k._mouseUp(n)};c(document).bind("mousemove."+this.widgetName,this._mouseMoveDelegate).bind("mouseup."+this.widgetName,this._mouseUpDelegate);(c.browser.safari||l.preventDefault());l.originalEvent.mouseHandled=true;return true},_mouseMove:function(j){if(c.browser.msie&&!j.button){return this._mouseUp(j)}if(this._mouseStarted){this._mouseDrag(j);return j.preventDefault()}if(this._mouseDistanceMet(j)&&this._mouseDelayMet(j)){this._mouseStarted=(this._mouseStart(this._mouseDownEvent,j)!==false);(this._mouseStarted?this._mouseDrag(j):this._mouseUp(j))}return !this._mouseStarted},_mouseUp:function(j){c(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate);if(this._mouseStarted){this._mouseStarted=false;this._preventClickEvent=(j.target==this._mouseDownEvent.target);this._mouseStop(j)}return false},_mouseDistanceMet:function(j){return(Math.max(Math.abs(this._mouseDownEvent.pageX-j.pageX),Math.abs(this._mouseDownEvent.pageY-j.pageY))>=this.options.distance)},_mouseDelayMet:function(j){return this.mouseDelayMet},_mouseStart:function(j){},_mouseDrag:function(j){},_mouseStop:function(j){},_mouseCapture:function(j){return true}};c.ui.mouse.defaults={cancel:null,distance:1,delay:0}})(jQuery);;/* * jQuery UI Resizable 1.7.2 + * + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Resizables + * + * Depends: + * ui.core.js + */ +(function(c){c.widget("ui.resizable",c.extend({},c.ui.mouse,{_init:function(){var e=this,j=this.options;this.element.addClass("ui-resizable");c.extend(this,{_aspectRatio:!!(j.aspectRatio),aspectRatio:j.aspectRatio,originalElement:this.element,_proportionallyResizeElements:[],_helper:j.helper||j.ghost||j.animate?j.helper||"ui-resizable-helper":null});if(this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)){if(/relative/.test(this.element.css("position"))&&c.browser.opera){this.element.css({position:"relative",top:"auto",left:"auto"})}this.element.wrap(c('
    ').css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(),top:this.element.css("top"),left:this.element.css("left")}));this.element=this.element.parent().data("resizable",this.element.data("resizable"));this.elementIsWrapper=true;this.element.css({marginLeft:this.originalElement.css("marginLeft"),marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom")});this.originalElement.css({marginLeft:0,marginTop:0,marginRight:0,marginBottom:0});this.originalResizeStyle=this.originalElement.css("resize");this.originalElement.css("resize","none");this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"}));this.originalElement.css({margin:this.originalElement.css("margin")});this._proportionallyResize()}this.handles=j.handles||(!c(".ui-resizable-handle",this.element).length?"e,s,se":{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne",nw:".ui-resizable-nw"});if(this.handles.constructor==String){if(this.handles=="all"){this.handles="n,e,s,w,se,sw,ne,nw"}var k=this.handles.split(",");this.handles={};for(var f=0;f
    ');if(/sw|se|ne|nw/.test(h)){g.css({zIndex:++j.zIndex})}if("se"==h){g.addClass("ui-icon ui-icon-gripsmall-diagonal-se")}this.handles[h]=".ui-resizable-"+h;this.element.append(g)}}this._renderAxis=function(p){p=p||this.element;for(var m in this.handles){if(this.handles[m].constructor==String){this.handles[m]=c(this.handles[m],this.element).show()}if(this.elementIsWrapper&&this.originalElement[0].nodeName.match(/textarea|input|select|button/i)){var n=c(this.handles[m],this.element),o=0;o=/sw|ne|nw|se|n|s/.test(m)?n.outerHeight():n.outerWidth();var l=["padding",/ne|nw|n/.test(m)?"Top":/se|sw|s/.test(m)?"Bottom":/^e$/.test(m)?"Right":"Left"].join("");p.css(l,o);this._proportionallyResize()}if(!c(this.handles[m]).length){continue}}};this._renderAxis(this.element);this._handles=c(".ui-resizable-handle",this.element).disableSelection();this._handles.mouseover(function(){if(!e.resizing){if(this.className){var i=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i)}e.axis=i&&i[1]?i[1]:"se"}});if(j.autoHide){this._handles.hide();c(this.element).addClass("ui-resizable-autohide").hover(function(){c(this).removeClass("ui-resizable-autohide");e._handles.show()},function(){if(!e.resizing){c(this).addClass("ui-resizable-autohide");e._handles.hide()}})}this._mouseInit()},destroy:function(){this._mouseDestroy();var d=function(f){c(f).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing").removeData("resizable").unbind(".resizable").find(".ui-resizable-handle").remove()};if(this.elementIsWrapper){d(this.element);var e=this.element;e.parent().append(this.originalElement.css({position:e.css("position"),width:e.outerWidth(),height:e.outerHeight(),top:e.css("top"),left:e.css("left")})).end().remove()}this.originalElement.css("resize",this.originalResizeStyle);d(this.originalElement)},_mouseCapture:function(e){var f=false;for(var d in this.handles){if(c(this.handles[d])[0]==e.target){f=true}}return this.options.disabled||!!f},_mouseStart:function(f){var i=this.options,e=this.element.position(),d=this.element;this.resizing=true;this.documentScroll={top:c(document).scrollTop(),left:c(document).scrollLeft()};if(d.is(".ui-draggable")||(/absolute/).test(d.css("position"))){d.css({position:"absolute",top:e.top,left:e.left})}if(c.browser.opera&&(/relative/).test(d.css("position"))){d.css({position:"relative",top:"auto",left:"auto"})}this._renderProxy();var j=b(this.helper.css("left")),g=b(this.helper.css("top"));if(i.containment){j+=c(i.containment).scrollLeft()||0;g+=c(i.containment).scrollTop()||0}this.offset=this.helper.offset();this.position={left:j,top:g};this.size=this._helper?{width:d.outerWidth(),height:d.outerHeight()}:{width:d.width(),height:d.height()};this.originalSize=this._helper?{width:d.outerWidth(),height:d.outerHeight()}:{width:d.width(),height:d.height()};this.originalPosition={left:j,top:g};this.sizeDiff={width:d.outerWidth()-d.width(),height:d.outerHeight()-d.height()};this.originalMousePosition={left:f.pageX,top:f.pageY};this.aspectRatio=(typeof i.aspectRatio=="number")?i.aspectRatio:((this.originalSize.width/this.originalSize.height)||1);var h=c(".ui-resizable-"+this.axis).css("cursor");c("body").css("cursor",h=="auto"?this.axis+"-resize":h);d.addClass("ui-resizable-resizing");this._propagate("start",f);return true},_mouseDrag:function(d){var g=this.helper,f=this.options,l={},p=this,i=this.originalMousePosition,m=this.axis;var q=(d.pageX-i.left)||0,n=(d.pageY-i.top)||0;var h=this._change[m];if(!h){return false}var k=h.apply(this,[d,q,n]),j=c.browser.msie&&c.browser.version<7,e=this.sizeDiff;if(this._aspectRatio||d.shiftKey){k=this._updateRatio(k,d)}k=this._respectSize(k,d);this._propagate("resize",d);g.css({top:this.position.top+"px",left:this.position.left+"px",width:this.size.width+"px",height:this.size.height+"px"});if(!this._helper&&this._proportionallyResizeElements.length){this._proportionallyResize()}this._updateCache(k);this._trigger("resize",d,this.ui());return false},_mouseStop:function(g){this.resizing=false;var h=this.options,l=this;if(this._helper){var f=this._proportionallyResizeElements,d=f.length&&(/textarea/i).test(f[0].nodeName),e=d&&c.ui.hasScroll(f[0],"left")?0:l.sizeDiff.height,j=d?0:l.sizeDiff.width;var m={width:(l.size.width-j),height:(l.size.height-e)},i=(parseInt(l.element.css("left"),10)+(l.position.left-l.originalPosition.left))||null,k=(parseInt(l.element.css("top"),10)+(l.position.top-l.originalPosition.top))||null;if(!h.animate){this.element.css(c.extend(m,{top:k,left:i}))}l.helper.height(l.size.height);l.helper.width(l.size.width);if(this._helper&&!h.animate){this._proportionallyResize()}}c("body").css("cursor","auto");this.element.removeClass("ui-resizable-resizing");this._propagate("stop",g);if(this._helper){this.helper.remove()}return false},_updateCache:function(d){var e=this.options;this.offset=this.helper.offset();if(a(d.left)){this.position.left=d.left}if(a(d.top)){this.position.top=d.top}if(a(d.height)){this.size.height=d.height}if(a(d.width)){this.size.width=d.width}},_updateRatio:function(g,f){var h=this.options,i=this.position,e=this.size,d=this.axis;if(g.height){g.width=(e.height*this.aspectRatio)}else{if(g.width){g.height=(e.width/this.aspectRatio)}}if(d=="sw"){g.left=i.left+(e.width-g.width);g.top=null}if(d=="nw"){g.top=i.top+(e.height-g.height);g.left=i.left+(e.width-g.width)}return g},_respectSize:function(k,f){var i=this.helper,h=this.options,q=this._aspectRatio||f.shiftKey,p=this.axis,s=a(k.width)&&h.maxWidth&&(h.maxWidthk.width),r=a(k.height)&&h.minHeight&&(h.minHeight>k.height);if(g){k.width=h.minWidth}if(r){k.height=h.minHeight}if(s){k.width=h.maxWidth}if(l){k.height=h.maxHeight}var e=this.originalPosition.left+this.originalSize.width,n=this.position.top+this.size.height;var j=/sw|nw|w/.test(p),d=/nw|ne|n/.test(p);if(g&&j){k.left=e-h.minWidth}if(s&&j){k.left=e-h.maxWidth}if(r&&d){k.top=n-h.minHeight}if(l&&d){k.top=n-h.maxHeight}var m=!k.width&&!k.height;if(m&&!k.left&&k.top){k.top=null}else{if(m&&!k.top&&k.left){k.left=null}}return k},_proportionallyResize:function(){var j=this.options;if(!this._proportionallyResizeElements.length){return}var f=this.helper||this.element;for(var e=0;e');var d=c.browser.msie&&c.browser.version<7,f=(d?1:0),g=(d?2:-1);this.helper.addClass(this._helper).css({width:this.element.outerWidth()+g,height:this.element.outerHeight()+g,position:"absolute",left:this.elementOffset.left-f+"px",top:this.elementOffset.top-f+"px",zIndex:++h.zIndex});this.helper.appendTo("body").disableSelection()}else{this.helper=this.element}},_change:{e:function(f,e,d){return{width:this.originalSize.width+e}},w:function(g,e,d){var i=this.options,f=this.originalSize,h=this.originalPosition;return{left:h.left+e,width:f.width-e}},n:function(g,e,d){var i=this.options,f=this.originalSize,h=this.originalPosition;return{top:h.top+d,height:f.height-d}},s:function(f,e,d){return{height:this.originalSize.height+d}},se:function(f,e,d){return c.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[f,e,d]))},sw:function(f,e,d){return c.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[f,e,d]))},ne:function(f,e,d){return c.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[f,e,d]))},nw:function(f,e,d){return c.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[f,e,d]))}},_propagate:function(e,d){c.ui.plugin.call(this,e,[d,this.ui()]);(e!="resize"&&this._trigger(e,d,this.ui()))},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}}));c.extend(c.ui.resizable,{version:"1.7.2",eventPrefix:"resize",defaults:{alsoResize:false,animate:false,animateDuration:"slow",animateEasing:"swing",aspectRatio:false,autoHide:false,cancel:":input,option",containment:false,delay:0,distance:1,ghost:false,grid:false,handles:"e,s,se",helper:false,maxHeight:null,maxWidth:null,minHeight:10,minWidth:10,zIndex:1000}});c.ui.plugin.add("resizable","alsoResize",{start:function(e,f){var d=c(this).data("resizable"),g=d.options;_store=function(h){c(h).each(function(){c(this).data("resizable-alsoresize",{width:parseInt(c(this).width(),10),height:parseInt(c(this).height(),10),left:parseInt(c(this).css("left"),10),top:parseInt(c(this).css("top"),10)})})};if(typeof(g.alsoResize)=="object"&&!g.alsoResize.parentNode){if(g.alsoResize.length){g.alsoResize=g.alsoResize[0];_store(g.alsoResize)}else{c.each(g.alsoResize,function(h,i){_store(h)})}}else{_store(g.alsoResize)}},resize:function(f,h){var e=c(this).data("resizable"),i=e.options,g=e.originalSize,k=e.originalPosition;var j={height:(e.size.height-g.height)||0,width:(e.size.width-g.width)||0,top:(e.position.top-k.top)||0,left:(e.position.left-k.left)||0},d=function(l,m){c(l).each(function(){var p=c(this),q=c(this).data("resizable-alsoresize"),o={},n=m&&m.length?m:["width","height","top","left"];c.each(n||["width","height","top","left"],function(r,t){var s=(q[t]||0)+(j[t]||0);if(s&&s>=0){o[t]=s||null}});if(/relative/.test(p.css("position"))&&c.browser.opera){e._revertToRelativePosition=true;p.css({position:"absolute",top:"auto",left:"auto"})}p.css(o)})};if(typeof(i.alsoResize)=="object"&&!i.alsoResize.nodeType){c.each(i.alsoResize,function(l,m){d(l,m)})}else{d(i.alsoResize)}},stop:function(e,f){var d=c(this).data("resizable");if(d._revertToRelativePosition&&c.browser.opera){d._revertToRelativePosition=false;el.css({position:"relative"})}c(this).removeData("resizable-alsoresize-start")}});c.ui.plugin.add("resizable","animate",{stop:function(h,m){var n=c(this).data("resizable"),i=n.options;var g=n._proportionallyResizeElements,d=g.length&&(/textarea/i).test(g[0].nodeName),e=d&&c.ui.hasScroll(g[0],"left")?0:n.sizeDiff.height,k=d?0:n.sizeDiff.width;var f={width:(n.size.width-k),height:(n.size.height-e)},j=(parseInt(n.element.css("left"),10)+(n.position.left-n.originalPosition.left))||null,l=(parseInt(n.element.css("top"),10)+(n.position.top-n.originalPosition.top))||null;n.element.animate(c.extend(f,l&&j?{top:l,left:j}:{}),{duration:i.animateDuration,easing:i.animateEasing,step:function(){var o={width:parseInt(n.element.css("width"),10),height:parseInt(n.element.css("height"),10),top:parseInt(n.element.css("top"),10),left:parseInt(n.element.css("left"),10)};if(g&&g.length){c(g[0]).css({width:o.width,height:o.height})}n._updateCache(o);n._propagate("resize",h)}})}});c.ui.plugin.add("resizable","containment",{start:function(e,q){var s=c(this).data("resizable"),i=s.options,k=s.element;var f=i.containment,j=(f instanceof c)?f.get(0):(/parent/.test(f))?k.parent().get(0):f;if(!j){return}s.containerElement=c(j);if(/document/.test(f)||f==document){s.containerOffset={left:0,top:0};s.containerPosition={left:0,top:0};s.parentData={element:c(document),left:0,top:0,width:c(document).width(),height:c(document).height()||document.body.parentNode.scrollHeight}}else{var m=c(j),h=[];c(["Top","Right","Left","Bottom"]).each(function(p,o){h[p]=b(m.css("padding"+o))});s.containerOffset=m.offset();s.containerPosition=m.position();s.containerSize={height:(m.innerHeight()-h[3]),width:(m.innerWidth()-h[1])};var n=s.containerOffset,d=s.containerSize.height,l=s.containerSize.width,g=(c.ui.hasScroll(j,"left")?j.scrollWidth:l),r=(c.ui.hasScroll(j)?j.scrollHeight:d);s.parentData={element:j,left:n.left,top:n.top,width:g,height:r}}},resize:function(f,p){var s=c(this).data("resizable"),h=s.options,e=s.containerSize,n=s.containerOffset,l=s.size,m=s.position,q=s._aspectRatio||f.shiftKey,d={top:0,left:0},g=s.containerElement;if(g[0]!=document&&(/static/).test(g.css("position"))){d=n}if(m.left<(s._helper?n.left:0)){s.size.width=s.size.width+(s._helper?(s.position.left-n.left):(s.position.left-d.left));if(q){s.size.height=s.size.width/h.aspectRatio}s.position.left=h.helper?n.left:0}if(m.top<(s._helper?n.top:0)) +{s.size.height=s.size.height+(s._helper?(s.position.top-n.top):s.position.top);if(q){s.size.width=s.size.height*h.aspectRatio}s.position.top=s._helper?n.top:0}s.offset.left=s.parentData.left+s.position.left;s.offset.top=s.parentData.top+s.position.top;var k=Math.abs((s._helper?s.offset.left-d.left:(s.offset.left-d.left))+s.sizeDiff.width),r=Math.abs((s._helper?s.offset.top-d.top:(s.offset.top-n.top))+s.sizeDiff.height);var j=s.containerElement.get(0)==s.element.parent().get(0),i=/relative|absolute/.test(s.containerElement.css("position"));if(j&&i){k-=s.parentData.left}if(k+s.size.width>=s.parentData.width){s.size.width=s.parentData.width-k;if(q){s.size.height=s.size.width/s.aspectRatio}}if(r+s.size.height>=s.parentData.height){s.size.height=s.parentData.height-r;if(q){s.size.width=s.size.height*s.aspectRatio}}},stop:function(e,m){var p=c(this).data("resizable"),f=p.options,k=p.position,l=p.containerOffset,d=p.containerPosition,g=p.containerElement;var i=c(p.helper),q=i.offset(),n=i.outerWidth()-p.sizeDiff.width,j=i.outerHeight()-p.sizeDiff.height;if(p._helper&&!f.animate&&(/relative/).test(g.css("position"))){c(this).css({left:q.left-d.left-l.left,width:n,height:j})}if(p._helper&&!f.animate&&(/static/).test(g.css("position"))){c(this).css({left:q.left-d.left-l.left,width:n,height:j})}}});c.ui.plugin.add("resizable","ghost",{start:function(f,g){var d=c(this).data("resizable"),h=d.options,e=d.size;d.ghost=d.originalElement.clone();d.ghost.css({opacity:0.25,display:"block",position:"relative",height:e.height,width:e.width,margin:0,left:0,top:0}).addClass("ui-resizable-ghost").addClass(typeof h.ghost=="string"?h.ghost:"");d.ghost.appendTo(d.helper)},resize:function(e,f){var d=c(this).data("resizable"),g=d.options;if(d.ghost){d.ghost.css({position:"relative",height:d.size.height,width:d.size.width})}},stop:function(e,f){var d=c(this).data("resizable"),g=d.options;if(d.ghost&&d.helper){d.helper.get(0).removeChild(d.ghost.get(0))}}});c.ui.plugin.add("resizable","grid",{resize:function(d,l){var n=c(this).data("resizable"),g=n.options,j=n.size,h=n.originalSize,i=n.originalPosition,m=n.axis,k=g._aspectRatio||d.shiftKey;g.grid=typeof g.grid=="number"?[g.grid,g.grid]:g.grid;var f=Math.round((j.width-h.width)/(g.grid[0]||1))*(g.grid[0]||1),e=Math.round((j.height-h.height)/(g.grid[1]||1))*(g.grid[1]||1);if(/^(se|s|e)$/.test(m)){n.size.width=h.width+f;n.size.height=h.height+e}else{if(/^(ne)$/.test(m)){n.size.width=h.width+f;n.size.height=h.height+e;n.position.top=i.top-e}else{if(/^(sw)$/.test(m)){n.size.width=h.width+f;n.size.height=h.height+e;n.position.left=i.left-f}else{n.size.width=h.width+f;n.size.height=h.height+e;n.position.top=i.top-e;n.position.left=i.left-f}}}}});var b=function(d){return parseInt(d,10)||0};var a=function(d){return !isNaN(parseInt(d,10))}})(jQuery);; +/** + * jQuery.ScrollTo - Easy element scrolling using jQuery. + * Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com + * Licensed under GPL license (http://www.opensource.org/licenses/gpl-license.php). + * Date: 2/8/2008 + * @author Ariel Flesler + * @version 1.3.2 + */ +;(function($){var o=$.scrollTo=function(a,b,c){o.window().scrollTo(a,b,c)};o.defaults={axis:'y',duration:1};o.window=function(){return $($.browser.safari?'body':'html')};$.fn.scrollTo=function(l,m,n){if(typeof m=='object'){n=m;m=0}n=$.extend({},o.defaults,n);m=m||n.speed||n.duration;n.queue=n.queue&&n.axis.length>1;if(n.queue)m/=2;n.offset=j(n.offset);n.over=j(n.over);return this.each(function(){var a=this,b=$(a),t=l,c,d={},w=b.is('html,body');switch(typeof t){case'number':case'string':if(/^([+-]=)?\d+(px)?$/.test(t)){t=j(t);break}t=$(t,this);case'object':if(t.is||t.style)c=(t=$(t)).offset()}$.each(n.axis.split(''),function(i,f){var P=f=='x'?'Left':'Top',p=P.toLowerCase(),k='scroll'+P,e=a[k],D=f=='x'?'Width':'Height';if(c){d[k]=c[p]+(w?0:e-b.offset()[p]);if(n.margin){d[k]-=parseInt(t.css('margin'+P))||0;d[k]-=parseInt(t.css('border'+P+'Width'))||0}d[k]+=n.offset[p]||0;if(n.over[p])d[k]+=t[D.toLowerCase()]()*n.over[p]}else d[k]=t[p];if(/^\d+$/.test(d[k]))d[k]=d[k]<=0?0:Math.min(d[k],h(D));if(!i&&n.queue){if(e!=d[k])g(n.onAfterFirst);delete d[k]}});g(n.onAfter);function g(a){b.animate(d,m,n.easing,a&&function(){a.call(this,l)})};function h(D){var b=w?$.browser.opera?document.body:document.documentElement:a;return b['scroll'+D]-b['client'+D]}})};function j(a){return typeof a=='object'?a:{top:a,left:a}}})(jQuery); + diff --git a/trunk/src/jquery_ui_js.h b/trunk/src/jquery_ui_js.h new file mode 100644 index 0000000..3b90c22 --- /dev/null +++ b/trunk/src/jquery_ui_js.h @@ -0,0 +1,32 @@ +"/*\n" +" * jQuery UI 1.7.2\n" +" *\n" +" * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)\n" +" * Dual licensed under the MIT (MIT-LICENSE.txt)\n" +" * and GPL (GPL-LICENSE.txt) licenses.\n" +" *\n" +" * http://docs.jquery.com/UI\n" +" */\n" +"jQuery.ui||(function(c){var i=c.fn.remove,d=c.browser.mozilla&&(parseFloat(c.browser.version)<1.9);c.ui={version:\"1.7.2\",plugin:{add:function(k,l,n){var m=c.ui[k].prototype;for(var j in n){m.plugins[j]=m.plugins[j]||[];m.plugins[j].push([l,n[j]])}},call:function(j,l,k){var n=j.plugins[l];if(!n||!j.element[0].parentNode){return}for(var m=0;m0){return true}m[j]=1;l=(m[j]>0);m[j]=0;return l},isOverAxis:function(k,j,l){return(k>j)&&(k<(j+l))},isOver:function(o,k,n,m,j,l){return c.ui.isOverAxis(o,n,j)&&c.ui.isOverAxis(k,m,l)},keyCode:{BACKSPACE:8,CAPS_LOCK:20,COMMA:188,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SHIFT:16,SPACE:32,TAB:9,UP:38}};if(d){var f=c.attr,e=c.fn.removeAttr,h=\"http://www.w3.org/2005/07/aaa\",a=/^aria-/,b=/^wairole:/;c.attr=function(k,j,l){var m=l!==undefined;return(j==\"role\"?(m?f.call(this,k,j,\"wairole:\"+l):(f.apply(this,arguments)||\"\").replace(b,\"\")):(a.test(j)?(m?k.setAttributeNS(h,j.replace(a,\"aaa:\"),l):f.call(this,k,j.replace(a,\"aaa:\"))):f.apply(this,arguments)))};c.fn.removeAttr=function(j){return(a.test(j)?this.each(function(){this.removeAttributeNS(h,j.replace(a,\"\"))}):e.call(this,j))}}c.fn.extend({remove:function(){c(\"*\",this).add(this).each(function(){c(this).triggerHandler(\"remove\")});return i.apply(this,arguments)},enableSelection:function(){return this.attr(\"unselectable\",\"off\").css(\"MozUserSelect\",\"\").unbind(\"selectstart.ui\")},disableSelection:function(){return this.attr(\"unselectable\",\"on\").css(\"MozUserSelect\",\"none\").bind(\"selectstart.ui\",function(){return false})},scrollParent:function(){var j;if((c.browser.msie&&(/(static|relative)/).test(this.css(\"position\")))||(/absolute/).test(this.css(\"position\"))){j=this.parents().filter(function(){return(/(relative|absolute|fixed)/).test(c.curCSS(this,\"position\",1))&&(/(auto|scroll)/).test(c.curCSS(this,\"overflow\",1)+c.curCSS(this,\"overflow-y\",1)+c.curCSS(this,\"overflow-x\",1))}).eq(0)}else{j=this.parents().filter(function(){return(/(auto|scroll)/).test(c.curCSS(this,\"overflow\",1)+c.curCSS(this,\"overflow-y\",1)+c.curCSS(this,\"overflow-x\",1))}).eq(0)}return(/fixed/).test(this.css(\"position\"))||!j.length?c(document):j}});c.extend(c.expr[\":\"],{data:function(l,k,j){return !!c.data(l,j[3])},focusable:function(k){var l=k.nodeName.toLowerCase(),j=c.attr(k,\"tabindex\");return(/input|select|textarea|button|object/.test(l)?!k.disabled:\"a\"==l||\"area\"==l?k.href||!isNaN(j):!isNaN(j))&&!c(k)[\"area\"==l?\"parents\":\"closest\"](\":hidden\").length},tabbable:function(k){var j=c.attr(k,\"tabindex\");return(isNaN(j)||j>=0)&&c(k).is(\":focusable\")}});function g(m,n,o,l){function k(q){var p=c[m][n][q]||[];return(typeof p==\"string\"?p.split(/,?\\s+/):p)}var j=k(\"getter\");if(l.length==1&&typeof l[0]==\"string\"){j=j.concat(k(\"getterSetter\"))}return(c.inArray(o,j)!=-1)}c.widget=function(k,j){var l=k.split(\".\")[0];k=k.split(\".\")[1];c.fn[k]=function(p){var n=(typeof p==\"string\"),o=Array.prototype.slice.call(arguments,1);if(n&&p.substring(0,1)==\"_\"){return this}if(n&&g(l,k,p,o)){var m=c.data(this[0],k);return(m?m[p].apply(m,o):undefined)}return this.each(function(){var q=c.data(this,k);(!q&&!n&&c.data(this,k,new c[l][k](this,p))._init());(q&&n&&c.isFunction(q[p])&&q[p].apply(q,o))})};c[l]=c[l]||{};c[l][k]=function(o,n){var m=this;this.namespace=l;this.widgetName=k;this.widgetEventPrefix=c[l][k].eventPrefix||k;this.widgetBaseClass=l+\"-\"+k;this.options=c.extend({},c.widget.defaults,c[l][k].defaults,c.metadata&&c.metadata.get(o)[k],n);this.element=c(o).bind(\"setData.\"+k,function(q,p,r){if(q.target==o){return m._setData(p,r)}}).bind(\"getData.\"+k,function(q,p){if(q.target==o){return m._getData(p)}}).bind(\"remove\",function(){return m.destroy()})};c[l][k].prototype=c.extend({},c.widget.prototype,j);c[l][k].getterSetter=\"option\"};c.widget.prototype={_init:function(){},destroy:function(){this.element.removeData(this.widgetName).removeClass(this.widgetBaseClass+\"-disabled \"+this.namespace+\"-state-disabled\").removeAttr(\"aria-disabled\")},option:function(l,m){var k=l,j=this;if(typeof l==\"string\"){if(m===undefined){return this._getData(l)}k={};k[l]=m}c.each(k,function(n,o){j._setData(n,o)})},_getData:function(j){return this.options[j]},_setData:function(j,k){this.options[j]=k;if(j==\"disabled\"){this.element[k?\"addClass\":\"removeClass\"](this.widgetBaseClass+\"-disabled \"+this.namespace+\"-state-disabled\").attr(\"aria-disabled\",k)}},enable:function(){this._setData(\"disabled\",false)},disable:function(){this._setData(\"disabled\",true)},_trigger:function(l,m,n){var p=this.options[l],j=(l==this.widgetEventPrefix?l:this.widgetEventPrefix+l);m=c.Event(m);m.type=j;if(m.originalEvent){for(var k=c.event.props.length,o;k;){o=c.event.props[--k];m[o]=m.originalEvent[o]}}this.element.trigger(m,n);return !(c.isFunction(p)&&p.call(this.element[0],m,n)===false||m.isDefaultPrevented())}};c.widget.defaults={disabled:false};c.ui.mouse={_mouseInit:function(){var j=this;this.element.bind(\"mousedown.\"+this.widgetName,function(k){return j._mouseDown(k)}).bind(\"click.\"+this.widgetName,function(k){if(j._preventClickEvent){j._preventClickEvent=false;k.stopImmediatePropagation();return false}});if(c.browser.msie){this._mouseUnselectable=this.element.attr(\"unselectable\");this.element.attr(\"unselectable\",\"on\")}this.started=false},_mouseDestroy:function(){this.element.unbind(\".\"+this.widgetName);(c.browser.msie&&this.element.attr(\"unselectable\",this._mouseUnselectable))},_mouseDown:function(l){l.originalEvent=l.originalEvent||{};if(l.originalEvent.mouseHandled){return}(this._mouseStarted&&this._mouseUp(l));this._mouseDownEvent=l;var k=this,m=(l.which==1),j=(typeof this.options.cancel==\"string\"?c(l.target).parents().add(l.target).filter(this.options.cancel).length:false);if(!m||j||!this._mouseCapture(l)){return true}this.mouseDelayMet=!this.options.delay;if(!this.mouseDelayMet){this._mouseDelayTimer=setTimeout(function(){k.mouseDelayMet=true},this.options.delay)}if(this._mouseDistanceMet(l)&&this._mouseDelayMet(l)){this._mouseStarted=(this._mouseStart(l)!==false);if(!this._mouseStarted){l.preventDefault();return true}}this._mouseMoveDelegate=function(n){return k._mouseMove(n)};this._mouseUpDelegate=function(n){return k._mouseUp(n)};c(document).bind(\"mousemove.\"+this.widgetName,this._mouseMoveDelegate).bind(\"mouseup.\"+this.widgetName,this._mouseUpDelegate);(c.browser.safari||l.preventDefault());l.originalEvent.mouseHandled=true;return true},_mouseMove:function(j){if(c.browser.msie&&!j.button){return this._mouseUp(j)}if(this._mouseStarted){this._mouseDrag(j);return j.preventDefault()}if(this._mouseDistanceMet(j)&&this._mouseDelayMet(j)){this._mouseStarted=(this._mouseStart(this._mouseDownEvent,j)!==false);(this._mouseStarted?this._mouseDrag(j):this._mouseUp(j))}return !this._mouseStarted},_mouseUp:function(j){c(document).unbind(\"mousemove.\"+this.widgetName,this._mouseMoveDelegate).unbind(\"mouseup.\"+this.widgetName,this._mouseUpDelegate);if(this._mouseStarted){this._mouseStarted=false;this._preventClickEvent=(j.target==this._mouseDownEvent.target);this._mouseStop(j)}return false},_mouseDistanceMet:function(j){return(Math.max(Math.abs(this._mouseDownEvent.pageX-j.pageX),Math.abs(this._mouseDownEvent.pageY-j.pageY))>=this.options.distance)},_mouseDelayMet:function(j){return this.mouseDelayMet},_mouseStart:function(j){},_mouseDrag:function(j){},_mouseStop:function(j){},_mouseCapture:function(j){return true}};c.ui.mouse.defaults={cancel:null,distance:1,delay:0}})(jQuery);;/* * jQuery UI Resizable 1.7.2\n" +" *\n" +" * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)\n" +" * Dual licensed under the MIT (MIT-LICENSE.txt)\n" +" * and GPL (GPL-LICENSE.txt) licenses.\n" +" *\n" +" * http://docs.jquery.com/UI/Resizables\n" +" *\n" +" * Depends:\n" +" * ui.core.js\n" +" */\n" +"(function(c){c.widget(\"ui.resizable\",c.extend({},c.ui.mouse,{_init:function(){var e=this,j=this.options;this.element.addClass(\"ui-resizable\");c.extend(this,{_aspectRatio:!!(j.aspectRatio),aspectRatio:j.aspectRatio,originalElement:this.element,_proportionallyResizeElements:[],_helper:j.helper||j.ghost||j.animate?j.helper||\"ui-resizable-helper\":null});if(this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)){if(/relative/.test(this.element.css(\"position\"))&&c.browser.opera){this.element.css({position:\"relative\",top:\"auto\",left:\"auto\"})}this.element.wrap(c('
    ').css({position:this.element.css(\"position\"),width:this.element.outerWidth(),height:this.element.outerHeight(),top:this.element.css(\"top\"),left:this.element.css(\"left\")}));this.element=this.element.parent().data(\"resizable\",this.element.data(\"resizable\"));this.elementIsWrapper=true;this.element.css({marginLeft:this.originalElement.css(\"marginLeft\"),marginTop:this.originalElement.css(\"marginTop\"),marginRight:this.originalElement.css(\"marginRight\"),marginBottom:this.originalElement.css(\"marginBottom\")});this.originalElement.css({marginLeft:0,marginTop:0,marginRight:0,marginBottom:0});this.originalResizeStyle=this.originalElement.css(\"resize\");this.originalElement.css(\"resize\",\"none\");this._proportionallyResizeElements.push(this.originalElement.css({position:\"static\",zoom:1,display:\"block\"}));this.originalElement.css({margin:this.originalElement.css(\"margin\")});this._proportionallyResize()}this.handles=j.handles||(!c(\".ui-resizable-handle\",this.element).length?\"e,s,se\":{n:\".ui-resizable-n\",e:\".ui-resizable-e\",s:\".ui-resizable-s\",w:\".ui-resizable-w\",se:\".ui-resizable-se\",sw:\".ui-resizable-sw\",ne:\".ui-resizable-ne\",nw:\".ui-resizable-nw\"});if(this.handles.constructor==String){if(this.handles==\"all\"){this.handles=\"n,e,s,w,se,sw,ne,nw\"}var k=this.handles.split(\",\");this.handles={};for(var f=0;f');if(/sw|se|ne|nw/.test(h)){g.css({zIndex:++j.zIndex})}if(\"se\"==h){g.addClass(\"ui-icon ui-icon-gripsmall-diagonal-se\")}this.handles[h]=\".ui-resizable-\"+h;this.element.append(g)}}this._renderAxis=function(p){p=p||this.element;for(var m in this.handles){if(this.handles[m].constructor==String){this.handles[m]=c(this.handles[m],this.element).show()}if(this.elementIsWrapper&&this.originalElement[0].nodeName.match(/textarea|input|select|button/i)){var n=c(this.handles[m],this.element),o=0;o=/sw|ne|nw|se|n|s/.test(m)?n.outerHeight():n.outerWidth();var l=[\"padding\",/ne|nw|n/.test(m)?\"Top\":/se|sw|s/.test(m)?\"Bottom\":/^e$/.test(m)?\"Right\":\"Left\"].join(\"\");p.css(l,o);this._proportionallyResize()}if(!c(this.handles[m]).length){continue}}};this._renderAxis(this.element);this._handles=c(\".ui-resizable-handle\",this.element).disableSelection();this._handles.mouseover(function(){if(!e.resizing){if(this.className){var i=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i)}e.axis=i&&i[1]?i[1]:\"se\"}});if(j.autoHide){this._handles.hide();c(this.element).addClass(\"ui-resizable-autohide\").hover(function(){c(this).removeClass(\"ui-resizable-autohide\");e._handles.show()},function(){if(!e.resizing){c(this).addClass(\"ui-resizable-autohide\");e._handles.hide()}})}this._mouseInit()},destroy:function(){this._mouseDestroy();var d=function(f){c(f).removeClass(\"ui-resizable ui-resizable-disabled ui-resizable-resizing\").removeData(\"resizable\").unbind(\".resizable\").find(\".ui-resizable-handle\").remove()};if(this.elementIsWrapper){d(this.element);var e=this.element;e.parent().append(this.originalElement.css({position:e.css(\"position\"),width:e.outerWidth(),height:e.outerHeight(),top:e.css(\"top\"),left:e.css(\"left\")})).end().remove()}this.originalElement.css(\"resize\",this.originalResizeStyle);d(this.originalElement)},_mouseCapture:function(e){var f=false;for(var d in this.handles){if(c(this.handles[d])[0]==e.target){f=true}}return this.options.disabled||!!f},_mouseStart:function(f){var i=this.options,e=this.element.position(),d=this.element;this.resizing=true;this.documentScroll={top:c(document).scrollTop(),left:c(document).scrollLeft()};if(d.is(\".ui-draggable\")||(/absolute/).test(d.css(\"position\"))){d.css({position:\"absolute\",top:e.top,left:e.left})}if(c.browser.opera&&(/relative/).test(d.css(\"position\"))){d.css({position:\"relative\",top:\"auto\",left:\"auto\"})}this._renderProxy();var j=b(this.helper.css(\"left\")),g=b(this.helper.css(\"top\"));if(i.containment){j+=c(i.containment).scrollLeft()||0;g+=c(i.containment).scrollTop()||0}this.offset=this.helper.offset();this.position={left:j,top:g};this.size=this._helper?{width:d.outerWidth(),height:d.outerHeight()}:{width:d.width(),height:d.height()};this.originalSize=this._helper?{width:d.outerWidth(),height:d.outerHeight()}:{width:d.width(),height:d.height()};this.originalPosition={left:j,top:g};this.sizeDiff={width:d.outerWidth()-d.width(),height:d.outerHeight()-d.height()};this.originalMousePosition={left:f.pageX,top:f.pageY};this.aspectRatio=(typeof i.aspectRatio==\"number\")?i.aspectRatio:((this.originalSize.width/this.originalSize.height)||1);var h=c(\".ui-resizable-\"+this.axis).css(\"cursor\");c(\"body\").css(\"cursor\",h==\"auto\"?this.axis+\"-resize\":h);d.addClass(\"ui-resizable-resizing\");this._propagate(\"start\",f);return true},_mouseDrag:function(d){var g=this.helper,f=this.options,l={},p=this,i=this.originalMousePosition,m=this.axis;var q=(d.pageX-i.left)||0,n=(d.pageY-i.top)||0;var h=this._change[m];if(!h){return false}var k=h.apply(this,[d,q,n]),j=c.browser.msie&&c.browser.version<7,e=this.sizeDiff;if(this._aspectRatio||d.shiftKey){k=this._updateRatio(k,d)}k=this._respectSize(k,d);this._propagate(\"resize\",d);g.css({top:this.position.top+\"px\",left:this.position.left+\"px\",width:this.size.width+\"px\",height:this.size.height+\"px\"});if(!this._helper&&this._proportionallyResizeElements.length){this._proportionallyResize()}this._updateCache(k);this._trigger(\"resize\",d,this.ui());return false},_mouseStop:function(g){this.resizing=false;var h=this.options,l=this;if(this._helper){var f=this._proportionallyResizeElements,d=f.length&&(/textarea/i).test(f[0].nodeName),e=d&&c.ui.hasScroll(f[0],\"left\")?0:l.sizeDiff.height,j=d?0:l.sizeDiff.width;var m={width:(l.size.width-j),height:(l.size.height-e)},i=(parseInt(l.element.css(\"left\"),10)+(l.position.left-l.originalPosition.left))||null,k=(parseInt(l.element.css(\"top\"),10)+(l.position.top-l.originalPosition.top))||null;if(!h.animate){this.element.css(c.extend(m,{top:k,left:i}))}l.helper.height(l.size.height);l.helper.width(l.size.width);if(this._helper&&!h.animate){this._proportionallyResize()}}c(\"body\").css(\"cursor\",\"auto\");this.element.removeClass(\"ui-resizable-resizing\");this._propagate(\"stop\",g);if(this._helper){this.helper.remove()}return false},_updateCache:function(d){var e=this.options;this.offset=this.helper.offset();if(a(d.left)){this.position.left=d.left}if(a(d.top)){this.position.top=d.top}if(a(d.height)){this.size.height=d.height}if(a(d.width)){this.size.width=d.width}},_updateRatio:function(g,f){var h=this.options,i=this.position,e=this.size,d=this.axis;if(g.height){g.width=(e.height*this.aspectRatio)}else{if(g.width){g.height=(e.width/this.aspectRatio)}}if(d==\"sw\"){g.left=i.left+(e.width-g.width);g.top=null}if(d==\"nw\"){g.top=i.top+(e.height-g.height);g.left=i.left+(e.width-g.width)}return g},_respectSize:function(k,f){var i=this.helper,h=this.options,q=this._aspectRatio||f.shiftKey,p=this.axis,s=a(k.width)&&h.maxWidth&&(h.maxWidthk.width),r=a(k.height)&&h.minHeight&&(h.minHeight>k.height);if(g){k.width=h.minWidth}if(r){k.height=h.minHeight}if(s){k.width=h.maxWidth}if(l){k.height=h.maxHeight}var e=this.originalPosition.left+this.originalSize.width,n=this.position.top+this.size.height;var j=/sw|nw|w/.test(p),d=/nw|ne|n/.test(p);if(g&&j){k.left=e-h.minWidth}if(s&&j){k.left=e-h.maxWidth}if(r&&d){k.top=n-h.minHeight}if(l&&d){k.top=n-h.maxHeight}var m=!k.width&&!k.height;if(m&&!k.left&&k.top){k.top=null}else{if(m&&!k.top&&k.left){k.left=null}}return k},_proportionallyResize:function(){var j=this.options;if(!this._proportionallyResizeElements.length){return}var f=this.helper||this.element;for(var e=0;e');var d=c.browser.msie&&c.browser.version<7,f=(d?1:0),g=(d?2:-1);this.helper.addClass(this._helper).css({width:this.element.outerWidth()+g,height:this.element.outerHeight()+g,position:\"absolute\",left:this.elementOffset.left-f+\"px\",top:this.elementOffset.top-f+\"px\",zIndex:++h.zIndex});this.helper.appendTo(\"body\").disableSelection()}else{this.helper=this.element}},_change:{e:function(f,e,d){return{width:this.originalSize.width+e}},w:function(g,e,d){var i=this.options,f=this.originalSize,h=this.originalPosition;return{left:h.left+e,width:f.width-e}},n:function(g,e,d){var i=this.options,f=this.originalSize,h=this.originalPosition;return{top:h.top+d,height:f.height-d}},s:function(f,e,d){return{height:this.originalSize.height+d}},se:function(f,e,d){return c.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[f,e,d]))},sw:function(f,e,d){return c.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[f,e,d]))},ne:function(f,e,d){return c.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[f,e,d]))},nw:function(f,e,d){return c.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[f,e,d]))}},_propagate:function(e,d){c.ui.plugin.call(this,e,[d,this.ui()]);(e!=\"resize\"&&this._trigger(e,d,this.ui()))},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}}));c.extend(c.ui.resizable,{version:\"1.7.2\",eventPrefix:\"resize\",defaults:{alsoResize:false,animate:false,animateDuration:\"slow\",animateEasing:\"swing\",aspectRatio:false,autoHide:false,cancel:\":input,option\",containment:false,delay:0,distance:1,ghost:false,grid:false,handles:\"e,s,se\",helper:false,maxHeight:null,maxWidth:null,minHeight:10,minWidth:10,zIndex:1000}});c.ui.plugin.add(\"resizable\",\"alsoResize\",{start:function(e,f){var d=c(this).data(\"resizable\"),g=d.options;_store=function(h){c(h).each(function(){c(this).data(\"resizable-alsoresize\",{width:parseInt(c(this).width(),10),height:parseInt(c(this).height(),10),left:parseInt(c(this).css(\"left\"),10),top:parseInt(c(this).css(\"top\"),10)})})};if(typeof(g.alsoResize)==\"object\"&&!g.alsoResize.parentNode){if(g.alsoResize.length){g.alsoResize=g.alsoResize[0];_store(g.alsoResize)}else{c.each(g.alsoResize,function(h,i){_store(h)})}}else{_store(g.alsoResize)}},resize:function(f,h){var e=c(this).data(\"resizable\"),i=e.options,g=e.originalSize,k=e.originalPosition;var j={height:(e.size.height-g.height)||0,width:(e.size.width-g.width)||0,top:(e.position.top-k.top)||0,left:(e.position.left-k.left)||0},d=function(l,m){c(l).each(function(){var p=c(this),q=c(this).data(\"resizable-alsoresize\"),o={},n=m&&m.length?m:[\"width\",\"height\",\"top\",\"left\"];c.each(n||[\"width\",\"height\",\"top\",\"left\"],function(r,t){var s=(q[t]||0)+(j[t]||0);if(s&&s>=0){o[t]=s||null}});if(/relative/.test(p.css(\"position\"))&&c.browser.opera){e._revertToRelativePosition=true;p.css({position:\"absolute\",top:\"auto\",left:\"auto\"})}p.css(o)})};if(typeof(i.alsoResize)==\"object\"&&!i.alsoResize.nodeType){c.each(i.alsoResize,function(l,m){d(l,m)})}else{d(i.alsoResize)}},stop:function(e,f){var d=c(this).data(\"resizable\");if(d._revertToRelativePosition&&c.browser.opera){d._revertToRelativePosition=false;el.css({position:\"relative\"})}c(this).removeData(\"resizable-alsoresize-start\")}});c.ui.plugin.add(\"resizable\",\"animate\",{stop:function(h,m){var n=c(this).data(\"resizable\"),i=n.options;var g=n._proportionallyResizeElements,d=g.length&&(/textarea/i).test(g[0].nodeName),e=d&&c.ui.hasScroll(g[0],\"left\")?0:n.sizeDiff.height,k=d?0:n.sizeDiff.width;var f={width:(n.size.width-k),height:(n.size.height-e)},j=(parseInt(n.element.css(\"left\"),10)+(n.position.left-n.originalPosition.left))||null,l=(parseInt(n.element.css(\"top\"),10)+(n.position.top-n.originalPosition.top))||null;n.element.animate(c.extend(f,l&&j?{top:l,left:j}:{}),{duration:i.animateDuration,easing:i.animateEasing,step:function(){var o={width:parseInt(n.element.css(\"width\"),10),height:parseInt(n.element.css(\"height\"),10),top:parseInt(n.element.css(\"top\"),10),left:parseInt(n.element.css(\"left\"),10)};if(g&&g.length){c(g[0]).css({width:o.width,height:o.height})}n._updateCache(o);n._propagate(\"resize\",h)}})}});c.ui.plugin.add(\"resizable\",\"containment\",{start:function(e,q){var s=c(this).data(\"resizable\"),i=s.options,k=s.element;var f=i.containment,j=(f instanceof c)?f.get(0):(/parent/.test(f))?k.parent().get(0):f;if(!j){return}s.containerElement=c(j);if(/document/.test(f)||f==document){s.containerOffset={left:0,top:0};s.containerPosition={left:0,top:0};s.parentData={element:c(document),left:0,top:0,width:c(document).width(),height:c(document).height()||document.body.parentNode.scrollHeight}}else{var m=c(j),h=[];c([\"Top\",\"Right\",\"Left\",\"Bottom\"]).each(function(p,o){h[p]=b(m.css(\"padding\"+o))});s.containerOffset=m.offset();s.containerPosition=m.position();s.containerSize={height:(m.innerHeight()-h[3]),width:(m.innerWidth()-h[1])};var n=s.containerOffset,d=s.containerSize.height,l=s.containerSize.width,g=(c.ui.hasScroll(j,\"left\")?j.scrollWidth:l),r=(c.ui.hasScroll(j)?j.scrollHeight:d);s.parentData={element:j,left:n.left,top:n.top,width:g,height:r}}},resize:function(f,p){var s=c(this).data(\"resizable\"),h=s.options,e=s.containerSize,n=s.containerOffset,l=s.size,m=s.position,q=s._aspectRatio||f.shiftKey,d={top:0,left:0},g=s.containerElement;if(g[0]!=document&&(/static/).test(g.css(\"position\"))){d=n}if(m.left<(s._helper?n.left:0)){s.size.width=s.size.width+(s._helper?(s.position.left-n.left):(s.position.left-d.left));if(q){s.size.height=s.size.width/h.aspectRatio}s.position.left=h.helper?n.left:0}if(m.top<(s._helper?n.top:0))\n" +"{s.size.height=s.size.height+(s._helper?(s.position.top-n.top):s.position.top);if(q){s.size.width=s.size.height*h.aspectRatio}s.position.top=s._helper?n.top:0}s.offset.left=s.parentData.left+s.position.left;s.offset.top=s.parentData.top+s.position.top;var k=Math.abs((s._helper?s.offset.left-d.left:(s.offset.left-d.left))+s.sizeDiff.width),r=Math.abs((s._helper?s.offset.top-d.top:(s.offset.top-n.top))+s.sizeDiff.height);var j=s.containerElement.get(0)==s.element.parent().get(0),i=/relative|absolute/.test(s.containerElement.css(\"position\"));if(j&&i){k-=s.parentData.left}if(k+s.size.width>=s.parentData.width){s.size.width=s.parentData.width-k;if(q){s.size.height=s.size.width/s.aspectRatio}}if(r+s.size.height>=s.parentData.height){s.size.height=s.parentData.height-r;if(q){s.size.width=s.size.height*s.aspectRatio}}},stop:function(e,m){var p=c(this).data(\"resizable\"),f=p.options,k=p.position,l=p.containerOffset,d=p.containerPosition,g=p.containerElement;var i=c(p.helper),q=i.offset(),n=i.outerWidth()-p.sizeDiff.width,j=i.outerHeight()-p.sizeDiff.height;if(p._helper&&!f.animate&&(/relative/).test(g.css(\"position\"))){c(this).css({left:q.left-d.left-l.left,width:n,height:j})}if(p._helper&&!f.animate&&(/static/).test(g.css(\"position\"))){c(this).css({left:q.left-d.left-l.left,width:n,height:j})}}});c.ui.plugin.add(\"resizable\",\"ghost\",{start:function(f,g){var d=c(this).data(\"resizable\"),h=d.options,e=d.size;d.ghost=d.originalElement.clone();d.ghost.css({opacity:0.25,display:\"block\",position:\"relative\",height:e.height,width:e.width,margin:0,left:0,top:0}).addClass(\"ui-resizable-ghost\").addClass(typeof h.ghost==\"string\"?h.ghost:\"\");d.ghost.appendTo(d.helper)},resize:function(e,f){var d=c(this).data(\"resizable\"),g=d.options;if(d.ghost){d.ghost.css({position:\"relative\",height:d.size.height,width:d.size.width})}},stop:function(e,f){var d=c(this).data(\"resizable\"),g=d.options;if(d.ghost&&d.helper){d.helper.get(0).removeChild(d.ghost.get(0))}}});c.ui.plugin.add(\"resizable\",\"grid\",{resize:function(d,l){var n=c(this).data(\"resizable\"),g=n.options,j=n.size,h=n.originalSize,i=n.originalPosition,m=n.axis,k=g._aspectRatio||d.shiftKey;g.grid=typeof g.grid==\"number\"?[g.grid,g.grid]:g.grid;var f=Math.round((j.width-h.width)/(g.grid[0]||1))*(g.grid[0]||1),e=Math.round((j.height-h.height)/(g.grid[1]||1))*(g.grid[1]||1);if(/^(se|s|e)$/.test(m)){n.size.width=h.width+f;n.size.height=h.height+e}else{if(/^(ne)$/.test(m)){n.size.width=h.width+f;n.size.height=h.height+e;n.position.top=i.top-e}else{if(/^(sw)$/.test(m)){n.size.width=h.width+f;n.size.height=h.height+e;n.position.left=i.left-f}else{n.size.width=h.width+f;n.size.height=h.height+e;n.position.top=i.top-e;n.position.left=i.left-f}}}}});var b=function(d){return parseInt(d,10)||0};var a=function(d){return !isNaN(parseInt(d,10))}})(jQuery);;\n" +"/**\n" +" * jQuery.ScrollTo - Easy element scrolling using jQuery.\n" +" * Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com\n" +" * Licensed under GPL license (http://www.opensource.org/licenses/gpl-license.php).\n" +" * Date: 2/8/2008\n" +" * @author Ariel Flesler\n" +" * @version 1.3.2\n" +" */\n" +";(function($){var o=$.scrollTo=function(a,b,c){o.window().scrollTo(a,b,c)};o.defaults={axis:'y',duration:1};o.window=function(){return $($.browser.safari?'body':'html')};$.fn.scrollTo=function(l,m,n){if(typeof m=='object'){n=m;m=0}n=$.extend({},o.defaults,n);m=m||n.speed||n.duration;n.queue=n.queue&&n.axis.length>1;if(n.queue)m/=2;n.offset=j(n.offset);n.over=j(n.over);return this.each(function(){var a=this,b=$(a),t=l,c,d={},w=b.is('html,body');switch(typeof t){case'number':case'string':if(/^([+-]=)?\\d+(px)?$/.test(t)){t=j(t);break}t=$(t,this);case'object':if(t.is||t.style)c=(t=$(t)).offset()}$.each(n.axis.split(''),function(i,f){var P=f=='x'?'Left':'Top',p=P.toLowerCase(),k='scroll'+P,e=a[k],D=f=='x'?'Width':'Height';if(c){d[k]=c[p]+(w?0:e-b.offset()[p]);if(n.margin){d[k]-=parseInt(t.css('margin'+P))||0;d[k]-=parseInt(t.css('border'+P+'Width'))||0}d[k]+=n.offset[p]||0;if(n.over[p])d[k]+=t[D.toLowerCase()]()*n.over[p]}else d[k]=t[p];if(/^\\d+$/.test(d[k]))d[k]=d[k]<=0?0:Math.min(d[k],h(D));if(!i&&n.queue){if(e!=d[k])g(n.onAfterFirst);delete d[k]}});g(n.onAfter);function g(a){b.animate(d,m,n.easing,a&&function(){a.call(this,l)})};function h(D){var b=w?$.browser.opera?document.body:document.documentElement:a;return b['scroll'+D]-b['client'+D]}})};function j(a){return typeof a=='object'?a:{top:a,left:a}}})(jQuery);\n" +"\n" diff --git a/trunk/src/lang_cfg.h b/trunk/src/lang_cfg.h new file mode 100644 index 0000000..72305af --- /dev/null +++ b/trunk/src/lang_cfg.h @@ -0,0 +1,40 @@ +#define LANG_NL +#define LANG_SV +#define LANG_CZ +#define LANG_FR +#define LANG_ID +#define LANG_IT +#define LANG_DE +#define LANG_JP +#define LANG_JE +#define LANG_ES +#define LANG_FI +#define LANG_RU +#define LANG_HR +#define LANG_PL +#define LANG_PT +#define LANG_HU +#define LANG_KR +#define LANG_KE +#define LANG_RO +#define LANG_SI +#define LANG_CN +#define LANG_NO +#define LANG_MK +#define LANG_BR +#define LANG_DK +#define LANG_SK +#define LANG_UA +#define LANG_GR +#define LANG_TW +#define LANG_SR +#define LANG_CA +#define LANG_LT +#define LANG_ZA +#define LANG_AR +#define LANG_FA +#define LANG_SC +#define LANG_VI +#define LANG_TR +#define LANG_EO +#define LANG_AM diff --git a/trunk/src/language.cpp b/trunk/src/language.cpp new file mode 100644 index 0000000..3afa5b9 --- /dev/null +++ b/trunk/src/language.cpp @@ -0,0 +1,422 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#include "message.h" +#include "language.h" +#include "lang_cfg.h" +#include "translator.h" +#include "translatordecoder.h" +#include "translator_en.h" +#if !defined(ENGLISH_ONLY) +#include "translator_adapter.h" +#ifdef LANG_NL +#include "translator_nl.h" +#endif +#ifdef LANG_AM +#include "translator_am.h" +#endif +#ifdef LANG_SV +#include "translator_sv.h" +#endif +#ifdef LANG_CZ +#include "translator_cz.h" +#endif +#ifdef LANG_FR +#include "translator_fr.h" +#endif +#ifdef LANG_ID +#include "translator_id.h" +#endif +#ifdef LANG_IT +#include "translator_it.h" +#endif +#ifdef LANG_DE +#include "translator_de.h" +#endif +#ifdef LANG_JP +#include "translator_jp.h" +#endif +#ifdef LANG_JE +#include "translator_je.h" +#endif +#ifdef LANG_ES +#include "translator_es.h" +#endif +#ifdef LANG_EO +#include "translator_eo.h" +#endif +#ifdef LANG_FI +#include "translator_fi.h" +#endif +#ifdef LANG_RU +#include "translator_ru.h" +#endif +#ifdef LANG_HR +#include "translator_hr.h" +#endif +#ifdef LANG_PL +#include "translator_pl.h" +#endif +#ifdef LANG_PT +#include "translator_pt.h" +#endif +#ifdef LANG_HU +#include "translator_hu.h" +#endif +#ifdef LANG_KE +#include "translator_ke.h" +#endif +#ifdef LANG_KR +#include "translator_kr.h" +#endif +#ifdef LANG_RO +#include "translator_ro.h" +#endif +#ifdef LANG_SI +#include "translator_si.h" +#endif +#ifdef LANG_CN +#include "translator_cn.h" +#endif +#ifdef LANG_TW +#include "translator_tw.h" +#endif +#ifdef LANG_NO +#include "translator_no.h" +#endif +#ifdef LANG_BR +#include "translator_br.h" +#endif +#ifdef LANG_DK +#include "translator_dk.h" +#endif +#ifdef LANG_SK +#include "translator_sk.h" +#endif +#ifdef LANG_UA +#include "translator_ua.h" +#endif +#ifdef LANG_GR +#include "translator_gr.h" +#endif +#ifdef LANG_SR +#include "translator_sr.h" +#endif +#ifdef LANG_CA +#include "translator_ca.h" +#endif +//#ifdef LANG_JS +//#include "translator_js.h" +//#endif +#ifdef LANG_LT +#include "translator_lt.h" +#endif +#ifdef LANG_ZA +#include "translator_za.h" +#endif +#ifdef LANG_AR +#include "translator_ar.h" +#endif +#ifdef LANG_FA +#include "translator_fa.h" +#endif +#ifdef LANG_MK +#include "translator_mk.h" +#endif +#ifdef LANG_SC +#include "translator_sc.h" +#endif +#ifdef LANG_VI +#include "translator_vi.h" +#endif +#ifdef LANG_TR +#include "translator_tr.h" +#endif +#endif // !ENGLISH_ONLY + +#define L_EQUAL(a) !stricmp(langName,a) + +Translator *theTranslator=0; + +static const char obsoleteMsg[] = + "---------\n" + "ERROR: The selected language is no longer supported!\n" + "If you want doxygen to produce output in this language \n" + "you are kindly requested to help bringing the documentation \n" + "up to date. Please read the development section of the manual \n" + "for more information or contact Petr Prikryl (Prikryl@skil.cz).\n" + "Thanks in advance!\n" + "---------\n"; + +bool setTranslator(const char *langName) +{ + if (L_EQUAL("english")) + { + theTranslator=new TranslatorEnglish; + } +#if !defined(ENGLISH_ONLY) +#ifdef LANG_NL + else if (L_EQUAL("dutch")) + { + theTranslator=new TranslatorDutch; + } +#endif +#ifdef LANG_AM + else if (L_EQUAL("armenian")) + { + theTranslator=new TranslatorArmenian; + } +#endif +#ifdef LANG_SV + else if (L_EQUAL("swedish")) + { + theTranslator=new TranslatorDecoder(new TranslatorSwedish); + } +#endif +#ifdef LANG_CZ + else if (L_EQUAL("czech")) + { + theTranslator=new TranslatorCzech; + } +#endif +#ifdef LANG_FR + else if (L_EQUAL("french")) + { + theTranslator=new TranslatorDecoder(new TranslatorFrench); + } +#endif +#ifdef LANG_ID + else if (L_EQUAL("indonesian")) + { + theTranslator=new TranslatorDecoder(new TranslatorIndonesian); + } +#endif +#ifdef LANG_IT + else if (L_EQUAL("italian")) + { + theTranslator=new TranslatorItalian; + } +#endif +#ifdef LANG_DE + else if (L_EQUAL("german")) + { + theTranslator=new TranslatorGerman; + } +#endif +#ifdef LANG_JP + else if (L_EQUAL("japanese")) + { + theTranslator=new TranslatorDecoder(new TranslatorJapanese); + } +#endif +#ifdef LANG_JE + else if (L_EQUAL("japanese-en")) + { + theTranslator=new TranslatorDecoder(new TranslatorJapaneseEn); + } +#endif +#ifdef LANG_ES + else if (L_EQUAL("spanish")) + { + theTranslator=new TranslatorSpanish; + } +#endif +#ifdef LANG_FI + else if (L_EQUAL("finnish")) + { + theTranslator=new TranslatorFinnish; + } +#endif +#ifdef LANG_RU + else if (L_EQUAL("russian")) + { + theTranslator=new TranslatorDecoder(new TranslatorRussian); + } +#endif +#ifdef LANG_HR + else if (L_EQUAL("croatian")) + { + theTranslator=new TranslatorCroatian; + } +#endif +#ifdef LANG_PL + else if (L_EQUAL("polish")) + { + theTranslator=new TranslatorPolish; + } +#endif +#ifdef LANG_PT + else if (L_EQUAL("portuguese")) + { + theTranslator=new TranslatorPortuguese; + } +#endif +#ifdef LANG_HU + else if (L_EQUAL("hungarian")) + { + theTranslator=new TranslatorDecoder(new TranslatorHungarian); + } +#endif +#ifdef LANG_KR + else if (L_EQUAL("korean")) + { + theTranslator=new TranslatorDecoder(new TranslatorKorean); + } +#endif +#ifdef LANG_KE + else if (L_EQUAL("korean-en")) + { + theTranslator=new TranslatorDecoder(new TranslatorKoreanEn); + } +#endif +#ifdef LANG_RO + else if (L_EQUAL("romanian")) + { + theTranslator=new TranslatorDecoder(new TranslatorRomanian); + } +#endif +#ifdef LANG_SI + else if (L_EQUAL("slovene")) + { + theTranslator=new TranslatorDecoder(new TranslatorSlovene); + } +#endif +#ifdef LANG_CN + else if (L_EQUAL("chinese")) + { + theTranslator=new TranslatorChinese; + } +#endif +#ifdef LANG_TW + else if (L_EQUAL("chinese-traditional")) + { + theTranslator=new TranslatorDecoder(new TranslatorChinesetraditional); + } +#endif +#ifdef LANG_NO + else if (L_EQUAL("norwegian")) + { + theTranslator=new TranslatorDecoder(new TranslatorNorwegian); + } +#endif +#ifdef LANG_BR + else if (L_EQUAL("brazilian")) + { + theTranslator=new TranslatorBrazilian; + } +#endif +#ifdef LANG_DK + else if (L_EQUAL("danish")) + { + theTranslator=new TranslatorDecoder(new TranslatorDanish); + } +#endif +#ifdef LANG_SK + else if (L_EQUAL("slovak")) + { + theTranslator=new TranslatorSlovak; + } +#endif +#ifdef LANG_UA + else if (L_EQUAL("ukrainian")) + { + theTranslator=new TranslatorDecoder(new TranslatorUkrainian); + } +#endif +#ifdef LANG_GR + else if (L_EQUAL("greek")) + { + theTranslator=new TranslatorGreek; + } +#endif +#ifdef LANG_SR + else if (L_EQUAL("serbian")) + { + theTranslator=new TranslatorDecoder(new TranslatorSerbian); + } +#endif +#ifdef LANG_SC + else if (L_EQUAL("serbian-cyrilic")) + { + theTranslator=new TranslatorSerbian; + } +#endif +#ifdef LANG_CA + else if (L_EQUAL("catalan")) + { + theTranslator=new TranslatorCatalan; + } +#endif +#ifdef LANG_LT + else if (L_EQUAL("lithuanian")) + { + theTranslator=new TranslatorDecoder(new TranslatorLithuanian); + } +#endif +#ifdef LANG_ZA + else if (L_EQUAL("afrikaans")) + { + theTranslator=new TranslatorDecoder(new TranslatorAfrikaans); + } +#endif +#ifdef LANG_AR + else if (L_EQUAL("arabic")) + { + theTranslator=new TranslatorDecoder(new TranslatorArabic); + } +#endif +#ifdef LANG_FA + else if (L_EQUAL("persian") || L_EQUAL("farsi")) + { + theTranslator=new TranslatorPersian; + } +#endif +#ifdef LANG_MK + else if (L_EQUAL("macedonian")) + { + theTranslator=new TranslatorMacedonian; + } +#endif +#ifdef LANG_VI + else if (L_EQUAL("vietnamese")) + { + theTranslator=new TranslatorVietnamese; + } +#endif +#ifdef LANG_TR + else if (L_EQUAL("turkish")) + { + theTranslator=new TranslatorTurkish; + } +#endif +#ifdef LANG_EO + else if (L_EQUAL("esperanto")) + { + theTranslator=new TranslatorEsperanto; + } +#endif +#endif // ENGLISH_ONLY + else // use the default language (i.e. english) + { + theTranslator=new TranslatorEnglish; + return FALSE; + } + + QCString msg = theTranslator->updateNeededMessage(); + if (!msg.isEmpty()) err(msg); + return TRUE; +} diff --git a/trunk/src/language.h b/trunk/src/language.h new file mode 100644 index 0000000..17f5800 --- /dev/null +++ b/trunk/src/language.h @@ -0,0 +1,26 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#ifndef LANGUAGE_H +#define LANGUAGE_H + +#include "translator.h" + +extern Translator *theTranslator; +extern bool setTranslator(const char *languageName); + +#endif diff --git a/trunk/src/latexdocvisitor.cpp b/trunk/src/latexdocvisitor.cpp new file mode 100644 index 0000000..0e9d0c2 --- /dev/null +++ b/trunk/src/latexdocvisitor.cpp @@ -0,0 +1,1825 @@ +/****************************************************************************** + * + * + * + * + * Copyright (C) 1997-2012 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. + * + */ +#include +#include "latexdocvisitor.h" +#include "docparser.h" +#include "language.h" +#include "doxygen.h" +#include "outputgen.h" +#include "dot.h" +#include "util.h" +#include "message.h" +#include "parserintf.h" +#include "msc.h" +#include "htmlattrib.h" +#include "cite.h" + +static QCString escapeLabelName(const char *s) +{ + QCString result; + const char *p=s; + char c; + while ((c=*p++)) + { + switch (c) + { + case '%': result+="\\%"; break; + case '|': result+="\\texttt{\"|}"; break; + case '!': result+="\"!"; break; + default: result+=c; + } + } + return result; +} + +const int maxLevels=5; +static const char *secLabels[maxLevels] = + { "section","subsection","subsubsection","paragraph","subparagraph" }; + +static const char *getSectionName(int level) +{ + static bool compactLatex = Config_getBool("COMPACT_LATEX"); + int l = level; + if (compactLatex) l++; + if (Doxygen::insideMainPage) l--; + return secLabels[QMIN(maxLevels-1,l)]; +} + +#if 0 +static int rowspan(DocHtmlCell *cell) +{ + int retval = 0; + HtmlAttribList attrs = cell->attribs(); + uint i; + for (i=0; iname.lower()=="rowspan") + { + retval = attrs.at(i)->value.toInt(); + break; + } + } + return retval; +} + +static int colspan(DocHtmlCell *cell) +{ + int retval = 1; + HtmlAttribList attrs = cell->attribs(); + uint i; + for (i=0; iname.lower()=="colspan") + { + retval = QMAX(1,attrs.at(i)->value.toInt()); + break; + } + } + return retval; +} + +static int align(DocHtmlCell *cell) +{ + HtmlAttribList attrs = cell->attribs(); + uint i; + for (i=0; iname.lower()=="align") + { + if (attrs.at(i)->value.lower()=="center") + return 1; + else if (attrs.at(i)->value.lower()=="right") + return 2; + else return 0; + } + } + return 0; +} + +struct ActiveRowSpan +{ + ActiveRowSpan(int rows,int col) : rowsLeft(rows), column(col) {} + int rowsLeft; + int column; +}; + +typedef QList RowSpanList; + +static int determineNumCols(DocHtmlTable *table) +{ + RowSpanList rowSpans; + rowSpans.setAutoDelete(TRUE); + int maxCols=0; + int rowIdx=1; + QListIterator li(table->children()); + DocNode *rowNode; + for (li.toFirst();(rowNode=li.current());++li) + { + int colIdx=1; + int cells=0; + if (rowNode->kind()==DocNode::Kind_HtmlRow) + { + uint i; + DocHtmlRow *row = (DocHtmlRow*)rowNode; + QListIterator rli(row->children()); + DocNode *cellNode; + for (rli.toFirst();(cellNode=rli.current());++rli) + { + if (cellNode->kind()==DocNode::Kind_HtmlCell) + { + DocHtmlCell *cell = (DocHtmlCell*)cellNode; + int rs = rowspan(cell); + int cs = colspan(cell); + + for (i=0;irowsLeft>0 && + rowSpans.at(i)->column==colIdx) + { + colIdx=rowSpans.at(i)->column+1; + cells++; + } + } + if (rs>0) rowSpans.append(new ActiveRowSpan(rs,colIdx)); + cell->setRowIndex(rowIdx); + cell->setColumnIndex(colIdx); + colIdx+=cs; + cells++; + } + } + for (i=0;irowsLeft>0) rowSpans.at(i)->rowsLeft--; + } + row->setVisibleCells(cells); + rowIdx++; + } + if (colIdx-1>maxCols) maxCols=colIdx-1; + } + return maxCols; +} +#endif + +QCString LatexDocVisitor::escapeMakeIndexChars(const char *s) +{ + QCString result; + const char *p=s; + char str[2]; str[1]=0; + char c; + while ((c=*p++)) + { + switch (c) + { + case '!': m_t << "\"!"; break; + case '"': m_t << "\"\""; break; + case '@': m_t << "\"@"; break; + case '|': m_t << "\\texttt{\"|}"; break; + case '[': m_t << "["; break; + case ']': m_t << "]"; break; + default: str[0]=c; filter(str); break; + } + } + return result; +} + + +LatexDocVisitor::LatexDocVisitor(FTextStream &t,CodeOutputInterface &ci, + const char *langExt,bool insideTabbing) + : DocVisitor(DocVisitor_Latex), m_t(t), m_ci(ci), m_insidePre(FALSE), + m_insideItem(FALSE), m_hide(FALSE), m_insideTabbing(insideTabbing), + m_insideTable(FALSE), m_langExt(langExt), m_currentColumn(0), + m_inRowspan(FALSE), m_inColspan(FALSE) +{ + m_rowSpans.setAutoDelete(TRUE); +} + + //-------------------------------------- + // visitor functions for leaf nodes + //-------------------------------------- + +void LatexDocVisitor::visit(DocWord *w) +{ + if (m_hide) return; + filter(w->word()); +} + +void LatexDocVisitor::visit(DocLinkedWord *w) +{ + if (m_hide) return; + startLink(w->ref(),w->file(),w->anchor()); + filter(w->word()); + endLink(w->ref(),w->file(),w->anchor()); +} + +void LatexDocVisitor::visit(DocWhiteSpace *w) +{ + if (m_hide) return; + if (m_insidePre) + { + m_t << w->chars(); + } + else + { + m_t << " "; + } +} + +void LatexDocVisitor::visit(DocSymbol *s) +{ + if (m_hide) return; + switch(s->symbol()) + { + case DocSymbol::BSlash: m_t << "$\\backslash$"; break; + case DocSymbol::At: m_t << "@"; break; + case DocSymbol::Less: if (m_insidePre) m_t << "<"; else m_t << "$<$"; + break; + case DocSymbol::Greater: if (m_insidePre) m_t << ">"; else m_t << "$>$"; break; + case DocSymbol::Amp: m_t << "\\&"; break; + case DocSymbol::Dollar: m_t << "\\$"; break; + case DocSymbol::Hash: m_t << "\\#"; break; + case DocSymbol::DoubleColon: m_t << "::"; break; + case DocSymbol::Percent: m_t << "\\%"; break; + case DocSymbol::Copy: m_t << "\\copyright"; break; + case DocSymbol::Tm: m_t << "\\texttrademark"; break; + case DocSymbol::Reg: m_t << "\\textregistered"; break; + case DocSymbol::Apos: m_t << "'"; break; + case DocSymbol::Quot: m_t << "\""; break; + case DocSymbol::Lsquo: m_t << "`"; break; + case DocSymbol::Rsquo: m_t << "'"; break; + case DocSymbol::Ldquo: m_t << "``"; break; + case DocSymbol::Rdquo: m_t << "''"; break; + case DocSymbol::Ndash: m_t << "--"; break; + case DocSymbol::Mdash: m_t << "---"; break; + case DocSymbol::Uml: + if (s->letter()=='i') + m_t << "\\\"{\\i}"; + else + m_t << "\\\"{" << s->letter() << "}"; + break; + case DocSymbol::Acute: + if (s->letter()=='i') + m_t << "\\'{\\i}"; + else + m_t << "\\'{" << s->letter() << "}"; + break; + case DocSymbol::Grave: + if (s->letter()=='i') + m_t << "\\`{\\i}"; + else + m_t << "\\`{" << s->letter() << "}"; + break; + case DocSymbol::Circ: + if (s->letter()=='i') + m_t << "\\^{\\i}"; + else + m_t << "\\^{" << s->letter() << "}"; + break; + case DocSymbol::Slash: if (tolower(s->letter())=='o') + m_t << "{\\" << s->letter() << "}"; + else + m_t << s->letter(); + break; + case DocSymbol::Tilde: m_t << "\\~{" << s->letter() << "}"; break; + case DocSymbol::Szlig: m_t << "{\\ss}"; break; + case DocSymbol::Cedil: m_t << "\\c{" << s->letter() << "}"; break; + case DocSymbol::Ring: m_t << "\\" << s->letter() << s->letter(); break; + case DocSymbol::Nbsp: m_t << "~"; break; + case DocSymbol::AElig: m_t << "{\\AE}"; break; + case DocSymbol::Aelig: m_t << "{\\ae}"; break; + default: + err("error: unknown symbol found\n"); + } +} + +void LatexDocVisitor::visit(DocURL *u) +{ + if (m_hide) return; + if (Config_getBool("PDF_HYPERLINKS")) + { + m_t << "\\href{"; + if (u->isEmail()) m_t << "mailto:"; + m_t << u->url() << "}"; + } + m_t << "{\\tt "; + filter(u->url()); + m_t << "}"; +} + +void LatexDocVisitor::visit(DocLineBreak *) +{ + if (m_hide) return; + if (m_insideTable) m_t << "\\newline\n"; + else m_t << "\\par\n"; +} + +void LatexDocVisitor::visit(DocHorRuler *) +{ + if (m_hide) return; + m_t << "\n\n"; +} + +void LatexDocVisitor::visit(DocStyleChange *s) +{ + if (m_hide) return; + switch (s->style()) + { + case DocStyleChange::Bold: + if (s->enable()) m_t << "{\\bfseries "; else m_t << "}"; + break; + case DocStyleChange::Italic: + if (s->enable()) m_t << "{\\itshape "; else m_t << "}"; + break; + case DocStyleChange::Code: + if (s->enable()) m_t << "{\\ttfamily "; else m_t << "}"; + break; + case DocStyleChange::Subscript: + if (s->enable()) m_t << "$_{\\mbox{"; else m_t << "}}$ "; + break; + case DocStyleChange::Superscript: + if (s->enable()) m_t << "$^{\\mbox{"; else m_t << "}}$ "; + break; + case DocStyleChange::Center: + if (s->enable()) m_t << "\\begin{center}"; else m_t << "\\end{center} "; + break; + case DocStyleChange::Small: + if (s->enable()) m_t << "\n\\footnotesize "; else m_t << "\n\\normalsize "; + break; + case DocStyleChange::Preformatted: + if (s->enable()) + { + m_t << "\n\\begin{DoxyPre}"; + m_insidePre=TRUE; + } + else + { + m_insidePre=FALSE; + m_t << "\\end{DoxyPre}\n"; + } + break; + case DocStyleChange::Div: /* HTML only */ break; + case DocStyleChange::Span: /* HTML only */ break; + } +} + +void LatexDocVisitor::visit(DocVerbatim *s) +{ + //static bool latexSourceCode = Config_getBool("LATEX_SOURCE_CODE"); + if (m_hide) return; + QCString lang = m_langExt; + if (!s->language().isEmpty()) // explicit language setting + { + lang = s->language(); + } + switch(s->type()) + { + case DocVerbatim::Code: + { + m_t << "\n\\begin{DoxyCode}\n"; + Doxygen::parserManager->getParser(lang) + ->parseCode(m_ci,s->context(),s->text(), + s->isExample(),s->exampleFile()); + m_t << "\\end{DoxyCode}\n"; + } + break; + case DocVerbatim::Verbatim: + m_t << "\\begin{DoxyVerb}"; + m_t << s->text(); + m_t << "\\end{DoxyVerb}\n"; + break; + case DocVerbatim::HtmlOnly: + case DocVerbatim::XmlOnly: + case DocVerbatim::ManOnly: + /* nothing */ + break; + case DocVerbatim::LatexOnly: + m_t << s->text(); + break; + case DocVerbatim::Dot: + { + static int dotindex = 1; + QCString fileName(4096); + + fileName.sprintf("%s%d%s", + (Config_getString("LATEX_OUTPUT")+"/inline_dotgraph_").data(), + dotindex++, + ".dot" + ); + QFile file(fileName); + if (!file.open(IO_WriteOnly)) + { + err("Could not open file %s for writing\n",fileName.data()); + } + file.writeBlock( s->text(), s->text().length() ); + file.close(); + + m_t << "\\begin{center}\n"; + startDotFile(fileName,"","",FALSE); + endDotFile(FALSE); + m_t << "\\end{center}\n"; + + if (Config_getBool("DOT_CLEANUP")) file.remove(); + } + break; + case DocVerbatim::Msc: + { + static int mscindex = 1; + QCString baseName(4096); + + baseName.sprintf("%s%d", + (Config_getString("LATEX_OUTPUT")+"/inline_mscgraph_").data(), + mscindex++ + ); + QFile file(baseName+".msc"); + if (!file.open(IO_WriteOnly)) + { + err("Could not open file %s.msc for writing\n",baseName.data()); + } + QCString text = "msc {"; + text+=s->text(); + text+="}"; + file.writeBlock( text, text.length() ); + file.close(); + + m_t << "\\begin{center}\n"; + writeMscFile(baseName); + m_t << "\\end{center}\n"; + + if (Config_getBool("DOT_CLEANUP")) file.remove(); + } + break; + } +} + +void LatexDocVisitor::visit(DocAnchor *anc) +{ + if (m_hide) return; + m_t << "\\label{" << anc->file() << "_" << anc->anchor() << "}%" << endl; + if (!anc->file().isEmpty() && Config_getBool("PDF_HYPERLINKS")) + { + m_t << "\\hypertarget{" << anc->file() << "_" << anc->anchor() + << "}{}%" << endl; + } +} + +void LatexDocVisitor::visit(DocInclude *inc) +{ + if (m_hide) return; + switch(inc->type()) + { + case DocInclude::IncWithLines: + { + m_t << "\n\\begin{DoxyCodeInclude}\n"; + QFileInfo cfi( inc->file() ); + FileDef fd( cfi.dirPath(), cfi.fileName() ); + Doxygen::parserManager->getParser(inc->extension()) + ->parseCode(m_ci,inc->context(), + inc->text(), + inc->isExample(), + inc->exampleFile(), &fd); + m_t << "\\end{DoxyCodeInclude}" << endl; + } + break; + case DocInclude::Include: + m_t << "\n\\begin{DoxyCodeInclude}\n"; + Doxygen::parserManager->getParser(inc->extension()) + ->parseCode(m_ci,inc->context(), + inc->text(),inc->isExample(), + inc->exampleFile()); + m_t << "\\end{DoxyCodeInclude}\n"; + break; + case DocInclude::DontInclude: + break; + case DocInclude::HtmlInclude: + break; + case DocInclude::VerbInclude: + m_t << "\n\\begin{DoxyVerbInclude}\n"; + m_t << inc->text(); + m_t << "\\end{DoxyVerbInclude}\n"; + break; + case DocInclude::Snippet: + { + m_t << "\n\\begin{DoxyCodeInclude}\n"; + Doxygen::parserManager->getParser(inc->extension()) + ->parseCode(m_ci, + inc->context(), + extractBlock(inc->text(),inc->blockId()), + inc->isExample(), + inc->exampleFile() + ); + m_t << "\\end{DoxyCodeInclude}" << endl; + } + break; + } +} + +void LatexDocVisitor::visit(DocIncOperator *op) +{ + //printf("DocIncOperator: type=%d first=%d, last=%d text=`%s'\n", + // op->type(),op->isFirst(),op->isLast(),op->text().data()); + if (op->isFirst()) + { + if (!m_hide) m_t << "\n\\begin{DoxyCodeInclude}\n"; + pushEnabled(); + m_hide = TRUE; + } + if (op->type()!=DocIncOperator::Skip) + { + popEnabled(); + if (!m_hide) + { + Doxygen::parserManager->getParser(m_langExt) + ->parseCode(m_ci,op->context(),op->text(), + op->isExample(),op->exampleFile()); + } + pushEnabled(); + m_hide=TRUE; + } + if (op->isLast()) + { + popEnabled(); + if (!m_hide) m_t << "\n\\end{DoxyCodeInclude}\n"; + } + else + { + if (!m_hide) m_t << endl; + } +} + +void LatexDocVisitor::visit(DocFormula *f) +{ + if (m_hide) return; + m_t << f->text(); +} + +void LatexDocVisitor::visit(DocIndexEntry *i) +{ + if (m_hide) return; + m_t << "\\index{" << escapeLabelName(i->entry()) << "@{"; + escapeMakeIndexChars(i->entry()); + m_t << "}}"; +} + +void LatexDocVisitor::visit(DocSimpleSectSep *) +{ +} + +void LatexDocVisitor::visit(DocCite *cite) +{ + if (m_hide) return; + if (!cite->file().isEmpty()) + { + //startLink(cite->ref(),cite->file(),cite->anchor()); + QCString anchor = cite->anchor(); + anchor = anchor.mid(CiteConsts::anchorPrefix.length()); // strip prefix + m_t << "\\cite{" << anchor << "}"; + } + else + { + m_t << "{\\bfseries ["; + filter(cite->text()); + m_t << "]}"; + } +} + +//-------------------------------------- +// visitor functions for compound nodes +//-------------------------------------- + +void LatexDocVisitor::visitPre(DocAutoList *l) +{ + if (m_hide) return; + if (l->isEnumList()) + { + m_t << "\n\\begin{DoxyEnumerate}"; + } + else + { + m_t << "\n\\begin{DoxyItemize}"; + } +} + +void LatexDocVisitor::visitPost(DocAutoList *l) +{ + if (m_hide) return; + if (l->isEnumList()) + { + m_t << "\n\\end{DoxyEnumerate}"; + } + else + { + m_t << "\n\\end{DoxyItemize}"; + } +} + +void LatexDocVisitor::visitPre(DocAutoListItem *) +{ + if (m_hide) return; + m_t << "\n\\item "; +} + +void LatexDocVisitor::visitPost(DocAutoListItem *) +{ +} + +void LatexDocVisitor::visitPre(DocPara *) +{ +} + +void LatexDocVisitor::visitPost(DocPara *p) +{ + if (m_hide) return; + if (!p->isLast() && // omit

    for last paragraph + !(p->parent() && // and for parameter sections + p->parent()->kind()==DocNode::Kind_ParamSect + ) + ) m_t << endl << endl; +} + +void LatexDocVisitor::visitPre(DocRoot *) +{ +} + +void LatexDocVisitor::visitPost(DocRoot *) +{ +} + +void LatexDocVisitor::visitPre(DocSimpleSect *s) +{ + if (m_hide) return; + switch(s->type()) + { + case DocSimpleSect::See: + m_t << "\\begin{DoxySeeAlso}{"; + filter(theTranslator->trSeeAlso()); + break; + case DocSimpleSect::Return: + m_t << "\\begin{DoxyReturn}{"; + filter(theTranslator->trReturns()); + break; + case DocSimpleSect::Author: + m_t << "\\begin{DoxyAuthor}{"; + filter(theTranslator->trAuthor(TRUE,TRUE)); + break; + case DocSimpleSect::Authors: + m_t << "\\begin{DoxyAuthor}{"; + filter(theTranslator->trAuthor(TRUE,FALSE)); + break; + case DocSimpleSect::Version: + m_t << "\\begin{DoxyVersion}{"; + filter(theTranslator->trVersion()); + break; + case DocSimpleSect::Since: + m_t << "\\begin{DoxySince}{"; + filter(theTranslator->trSince()); + break; + case DocSimpleSect::Date: + m_t << "\\begin{DoxyDate}{"; + filter(theTranslator->trDate()); + break; + case DocSimpleSect::Note: + m_t << "\\begin{DoxyNote}{"; + filter(theTranslator->trNote()); + break; + case DocSimpleSect::Warning: + m_t << "\\begin{DoxyWarning}{"; + filter(theTranslator->trWarning()); + break; + case DocSimpleSect::Pre: + m_t << "\\begin{DoxyPrecond}{"; + filter(theTranslator->trPrecondition()); + break; + case DocSimpleSect::Post: + m_t << "\\begin{DoxyPostcond}{"; + filter(theTranslator->trPostcondition()); + break; + case DocSimpleSect::Copyright: + m_t << "\\begin{DoxyCopyright}{"; + filter(theTranslator->trCopyright()); + break; + case DocSimpleSect::Invar: + m_t << "\\begin{DoxyInvariant}{"; + filter(theTranslator->trInvariant()); + break; + case DocSimpleSect::Remark: + m_t << "\\begin{DoxyRemark}{"; + filter(theTranslator->trRemarks()); + break; + case DocSimpleSect::Attention: + m_t << "\\begin{DoxyAttention}{"; + filter(theTranslator->trAttention()); + break; + case DocSimpleSect::User: + m_t << "\\begin{DoxyParagraph}{"; + break; + case DocSimpleSect::Rcs: + m_t << "\\begin{DoxyParagraph}{"; + break; + case DocSimpleSect::Unknown: break; + } + + // special case 1: user defined title + if (s->type()!=DocSimpleSect::User && s->type()!=DocSimpleSect::Rcs) + { + m_t << "}\n"; + } + else + { + m_insideItem=TRUE; + } +} + +void LatexDocVisitor::visitPost(DocSimpleSect *s) +{ + if (m_hide) return; + switch(s->type()) + { + case DocSimpleSect::See: + m_t << "\n\\end{DoxySeeAlso}\n"; + break; + case DocSimpleSect::Return: + m_t << "\n\\end{DoxyReturn}\n"; + break; + case DocSimpleSect::Author: + m_t << "\n\\end{DoxyAuthor}\n"; + break; + case DocSimpleSect::Authors: + m_t << "\n\\end{DoxyAuthor}\n"; + break; + case DocSimpleSect::Version: + m_t << "\n\\end{DoxyVersion}\n"; + break; + case DocSimpleSect::Since: + m_t << "\n\\end{DoxySince}\n"; + break; + case DocSimpleSect::Date: + m_t << "\n\\end{DoxyDate}\n"; + break; + case DocSimpleSect::Note: + m_t << "\n\\end{DoxyNote}\n"; + break; + case DocSimpleSect::Warning: + m_t << "\n\\end{DoxyWarning}\n"; + break; + case DocSimpleSect::Pre: + m_t << "\n\\end{DoxyPrecond}\n"; + break; + case DocSimpleSect::Post: + m_t << "\n\\end{DoxyPostcond}\n"; + break; + case DocSimpleSect::Copyright: + m_t << "\n\\end{DoxyCopyright}\n"; + break; + case DocSimpleSect::Invar: + m_t << "\n\\end{DoxyInvariant}\n"; + break; + case DocSimpleSect::Remark: + m_t << "\n\\end{DoxyRemark}\n"; + break; + case DocSimpleSect::Attention: + m_t << "\n\\end{DoxyAttention}\n"; + break; + case DocSimpleSect::User: + m_t << "\n\\end{DoxyParagraph}\n"; + break; + case DocSimpleSect::Rcs: + m_t << "\n\\end{DoxyParagraph}\n"; + break; + default: + break; + } +} + +void LatexDocVisitor::visitPre(DocTitle *) +{ +} + +void LatexDocVisitor::visitPost(DocTitle *) +{ + if (m_hide) return; + m_insideItem=FALSE; + m_t << "}\n"; +} + +void LatexDocVisitor::visitPre(DocSimpleList *) +{ + if (m_hide) return; + m_t << "\\begin{DoxyItemize}" << endl; +} + +void LatexDocVisitor::visitPost(DocSimpleList *) +{ + if (m_hide) return; + m_t << "\\end{DoxyItemize}" << endl; +} + +void LatexDocVisitor::visitPre(DocSimpleListItem *) +{ + if (m_hide) return; + m_t << "\\item "; +} + +void LatexDocVisitor::visitPost(DocSimpleListItem *) +{ +} + +void LatexDocVisitor::visitPre(DocSection *s) +{ + if (m_hide) return; + if (Config_getBool("PDF_HYPERLINKS")) + { + m_t << "\\hypertarget{" << s->file() << "_" << s->anchor() << "}{}"; + } + m_t << "\\" << getSectionName(s->level()) << "{"; + filter(convertCharEntitiesToUTF8(s->title().data())); + m_t << "}\\label{" << s->file() << "_" << s->anchor() << "}" << endl; +} + +void LatexDocVisitor::visitPost(DocSection *) +{ +} + +void LatexDocVisitor::visitPre(DocHtmlList *s) +{ + if (m_hide) return; + if (s->type()==DocHtmlList::Ordered) + m_t << "\n\\begin{DoxyEnumerate}"; + else + m_t << "\n\\begin{DoxyItemize}"; +} + +void LatexDocVisitor::visitPost(DocHtmlList *s) +{ + if (m_hide) return; + if (s->type()==DocHtmlList::Ordered) + m_t << "\n\\end{DoxyEnumerate}"; + else + m_t << "\n\\end{DoxyItemize}"; +} + +void LatexDocVisitor::visitPre(DocHtmlListItem *) +{ + if (m_hide) return; + m_t << "\n\\item "; +} + +void LatexDocVisitor::visitPost(DocHtmlListItem *) +{ +} + +//void LatexDocVisitor::visitPre(DocHtmlPre *) +//{ +// m_t << "\\small\\begin{alltt}"; +// m_insidePre=TRUE; +//} + +//void LatexDocVisitor::visitPost(DocHtmlPre *) +//{ +// m_insidePre=FALSE; +// m_t << "\\end{alltt}\\normalsize " << endl; +//} + +void LatexDocVisitor::visitPre(DocHtmlDescList *dl) +{ + if (m_hide) return; + QCString val = dl->attribs().find("class"); + if (val=="reflist") + { + m_t << "\n\\begin{DoxyRefList}"; + } + else + { + m_t << "\n\\begin{DoxyDescription}"; + } +} + +void LatexDocVisitor::visitPost(DocHtmlDescList *dl) +{ + if (m_hide) return; + QCString val = dl->attribs().find("class"); + if (val=="reflist") + { + m_t << "\n\\end{DoxyRefList}"; + } + else + { + m_t << "\n\\end{DoxyDescription}"; + } +} + +void LatexDocVisitor::visitPre(DocHtmlDescTitle *) +{ + if (m_hide) return; + m_t << "\n\\item["; + m_insideItem=TRUE; +} + +void LatexDocVisitor::visitPost(DocHtmlDescTitle *) +{ + if (m_hide) return; + m_insideItem=FALSE; + m_t << "]"; +} + +void LatexDocVisitor::visitPre(DocHtmlDescData *) +{ +} + +void LatexDocVisitor::visitPost(DocHtmlDescData *) +{ +} + +void LatexDocVisitor::visitPre(DocHtmlTable *t) +{ + m_rowSpans.clear(); + m_insideTable=TRUE; + if (m_hide) return; + if (t->hasCaption()) + { + m_t << "\\begin{table}[h]"; + } + m_t << "\\begin{TabularC}{" << t->numColumns() << "}\n"; + m_numCols = t->numColumns(); + m_t << "\\hline\n"; +} + +void LatexDocVisitor::visitPost(DocHtmlTable *t) +{ + m_insideTable=FALSE; + if (m_hide) return; + if (t->hasCaption()) + { + m_t << "\\end{table}\n"; + } + else + { + m_t << "\\end{TabularC}\n"; + } +} + +void LatexDocVisitor::visitPre(DocHtmlCaption *) +{ + if (m_hide) return; + m_t << "\\end{TabularC}\n\\centering\n\\caption{"; +} + +void LatexDocVisitor::visitPost(DocHtmlCaption *) +{ + if (m_hide) return; + m_t << "}\n"; +} + +void LatexDocVisitor::visitPre(DocHtmlRow *r) +{ + m_currentColumn = 0; + if (r->isHeading()) m_t << "\\rowcolor{lightgray}"; +} + +void LatexDocVisitor::visitPost(DocHtmlRow *row) +{ + if (m_hide) return; + + int c=m_currentColumn; + while (c<=m_numCols) // end of row while inside a row span? + { + uint i; + for (i=0;irowIdx=%d\n", + // span->column, span->rowSpan,span->colSpan,row->rowIndex(),span->cell->rowIndex()); + if (span->rowSpan>0 && span->column==c && // we are at a cell in a row span + row->rowIndex()>span->cell->rowIndex() // but not the row that started the span + ) + { + m_t << "&"; + if (span->colSpan>1) // row span is also part of a column span + { + m_t << "\\multicolumn{" << span->colSpan << "}{"; + m_t << "p{(\\linewidth-\\tabcolsep*" + << m_numCols << "-\\arrayrulewidth*" + << row->visibleCells() << ")*" + << span->colSpan <<"/"<< m_numCols << "}|}{}"; + } + else // solitary row span + { + m_t << "\\multicolumn{1}{c|}{}"; + } + } + } + c++; + } + + m_t << "\\\\"; + + int col = 1; + uint i; + for (i=0;irowSpan>0) span->rowSpan--; + if (span->rowSpan<=0) + { + // inactive span + } + else if (span->column>col) + { + m_t << "\\cline{" << col << "-" << (span->column-1) << "}"; + col = span->column+span->colSpan; + } + else + { + col = span->column+span->colSpan; + } + } + + if (col <= m_numCols) + { + m_t << "\\cline{" << col << "-" << m_numCols << "}"; + } + + m_t << "\n"; +} + +void LatexDocVisitor::visitPre(DocHtmlCell *c) +{ + if (m_hide) return; + + DocHtmlRow *row = 0; + if (c->parent() && c->parent()->kind()==DocNode::Kind_HtmlRow) + { + row = (DocHtmlRow*)c->parent(); + } + + m_currentColumn++; + + //Skip columns that span from above. + uint i; + for (i=0;irowSpan>0 && span->column==m_currentColumn) + { + if (row && span->colSpan>1) + { + m_t << "\\multicolumn{" << span->colSpan << "}{"; + if (m_currentColumn /*c->columnIndex()*/==1) // add extra | for first column + { + m_t << "|"; + } + m_t << "p{(\\linewidth-\\tabcolsep*" + << m_numCols << "-\\arrayrulewidth*" + << row->visibleCells() << ")*" + << span->colSpan <<"/"<< m_numCols << "}|}{}"; + m_currentColumn+=span->colSpan; + } + else + { + m_currentColumn++; + } + m_t << "&"; + } + } + +#if 0 + QMap::Iterator it = m_rowspanIndices.find(m_currentColumn); + if (it!=m_rowspanIndices.end() && it.data()>0) + { + m_t << "&"; + m_currentColumn++; + it++; + } +#endif + + int cs = c->colSpan(); + if (cs>1 && row) + { + m_inColspan = TRUE; + m_t << "\\multicolumn{" << cs << "}{"; + if (c->columnIndex()==1) // add extra | for first column + { + m_t << "|"; + } + m_t << "p{(\\linewidth-\\tabcolsep*" + << m_numCols << "-\\arrayrulewidth*" + << row->visibleCells() << ")*" + << cs <<"/"<< m_numCols << "}|}{"; + if (c->isHeading()) m_t << "\\cellcolor{lightgray}"; + } + int rs = c->rowSpan(); + if (rs>0) + { + m_inRowspan = TRUE; + //m_rowspanIndices[m_currentColumn] = rs; + m_rowSpans.append(new ActiveRowSpan(c,rs,cs,m_currentColumn)); + m_t << "\\multirow{" << rs << "}{\\linewidth}{"; + } + int a = c->alignment(); + if (a==DocHtmlCell::Center) + { + m_t << "\\PBS\\centering "; + } + else if (a==DocHtmlCell::Right) + { + m_t << "\\PBS\\raggedleft "; + } + if (c->isHeading()) + { + m_t << "{\\bf "; + } + if (cs>1) + { + m_currentColumn+=cs-1; + } +} + +void LatexDocVisitor::visitPost(DocHtmlCell *c) +{ + if (m_hide) return; + if (c->isHeading()) + { + m_t << "}"; + } + if (m_inRowspan) + { + m_inRowspan = FALSE; + m_t << "}"; + } + if (m_inColspan) + { + m_inColspan = FALSE; + m_t << "}"; + } + if (!c->isLast()) m_t << "&"; +} + +void LatexDocVisitor::visitPre(DocInternal *) +{ + if (m_hide) return; + //m_t << "\\begin{DoxyInternal}{"; + //filter(theTranslator->trForInternalUseOnly()); + //m_t << "}\n"; +} + +void LatexDocVisitor::visitPost(DocInternal *) +{ + if (m_hide) return; + //m_t << "\\end{DoxyInternal}" << endl; +} + +void LatexDocVisitor::visitPre(DocHRef *href) +{ + if (m_hide) return; + if (Config_getBool("PDF_HYPERLINKS")) + { + m_t << "\\href{"; + m_t << href->url(); + m_t << "}"; + } + m_t << "{\\tt "; +} + +void LatexDocVisitor::visitPost(DocHRef *) +{ + if (m_hide) return; + m_t << "}"; +} + +void LatexDocVisitor::visitPre(DocHtmlHeader *header) +{ + if (m_hide) return; + m_t << "\\" << getSectionName(header->level()) << "*{"; +} + +void LatexDocVisitor::visitPost(DocHtmlHeader *) +{ + if (m_hide) return; + m_t << "}"; +} + +void LatexDocVisitor::visitPre(DocImage *img) +{ + if (img->type()==DocImage::Latex) + { + if (m_hide) return; + if (img->hasCaption()) + { + m_t << "\n\\begin{DoxyImage}\n"; + } + else + { + m_t << "\n\\begin{DoxyImageNoCaption}\n" + " \\mbox{"; + } + QCString gfxName = img->name(); + if (gfxName.right(4)==".eps" || gfxName.right(4)==".pdf") + { + gfxName=gfxName.left(gfxName.length()-4); + } + m_t << "\\includegraphics"; + if (!img->width().isEmpty()) + { + m_t << "[width=" << img->width() << "]"; + } + else if (!img->height().isEmpty()) + { + m_t << "[height=" << img->height() << "]"; + } + m_t << "{" << gfxName << "}"; + if (img->hasCaption()) + { + m_t << "\n\\caption{"; + } + } + else // other format -> skip + { + pushEnabled(); + m_hide=TRUE; + } +} + +void LatexDocVisitor::visitPost(DocImage *img) +{ + if (img->type()==DocImage::Latex) + { + if (m_hide) return; + m_t << "}\n"; // end mbox or caption + if (img->hasCaption()) + { + m_t << "\\end{DoxyImage}\n"; + } + else{ + m_t << "\\end{DoxyImageNoCaption}\n"; + } + } + else // other format + { + popEnabled(); + } +} + +void LatexDocVisitor::visitPre(DocDotFile *df) +{ + if (m_hide) return; + startDotFile(df->file(),df->width(),df->height(),df->hasCaption()); +} + +void LatexDocVisitor::visitPost(DocDotFile *df) +{ + if (m_hide) return; + endDotFile(df->hasCaption()); +} +void LatexDocVisitor::visitPre(DocMscFile *df) +{ + if (m_hide) return; + startMscFile(df->file(),df->width(),df->height(),df->hasCaption()); +} + +void LatexDocVisitor::visitPost(DocMscFile *df) +{ + if (m_hide) return; + endMscFile(df->hasCaption()); +} +void LatexDocVisitor::visitPre(DocLink *lnk) +{ + if (m_hide) return; + startLink(lnk->ref(),lnk->file(),lnk->anchor()); +} + +void LatexDocVisitor::visitPost(DocLink *lnk) +{ + if (m_hide) return; + endLink(lnk->ref(),lnk->file(),lnk->anchor()); +} + +void LatexDocVisitor::visitPre(DocRef *ref) +{ + if (m_hide) return; + // when ref->isSubPage()==TRUE we use ref->file() for HTML and + // ref->anchor() for LaTeX/RTF + if (ref->isSubPage()) + { + startLink(ref->ref(),0,ref->anchor()); + } + else + { + if (!ref->file().isEmpty()) startLink(ref->ref(),ref->file(),ref->anchor()); + } + if (!ref->hasLinkText()) filter(ref->targetTitle()); +} + +void LatexDocVisitor::visitPost(DocRef *ref) +{ + if (m_hide) return; + if (ref->isSubPage()) + { + endLink(ref->ref(),0,ref->anchor()); + } + else + { + if (!ref->file().isEmpty()) endLink(ref->ref(),ref->file(),ref->anchor()); + } +} + +void LatexDocVisitor::visitPre(DocSecRefItem *) +{ + if (m_hide) return; + m_t << "\\item \\contentsline{section}{"; +} + +void LatexDocVisitor::visitPost(DocSecRefItem *ref) +{ + if (m_hide) return; + m_t << "}{\\ref{" << ref->file() << "_" << ref->anchor() << "}}{}" << endl; +} + +void LatexDocVisitor::visitPre(DocSecRefList *) +{ + if (m_hide) return; + m_t << "\\footnotesize" << endl; + m_t << "\\begin{multicols}{2}" << endl; + m_t << "\\begin{DoxyCompactList}" << endl; +} + +void LatexDocVisitor::visitPost(DocSecRefList *) +{ + if (m_hide) return; + m_t << "\\end{DoxyCompactList}" << endl; + m_t << "\\end{multicols}" << endl; + m_t << "\\normalsize" << endl; +} + +//void LatexDocVisitor::visitPre(DocLanguage *l) +//{ +// QCString langId = Config_getEnum("OUTPUT_LANGUAGE"); +// if (l->id().lower()!=langId.lower()) +// { +// pushEnabled(); +// m_hide = TRUE; +// } +//} +// +//void LatexDocVisitor::visitPost(DocLanguage *l) +//{ +// QCString langId = Config_getEnum("OUTPUT_LANGUAGE"); +// if (l->id().lower()!=langId.lower()) +// { +// popEnabled(); +// } +//} + +void LatexDocVisitor::visitPre(DocParamSect *s) +{ + if (m_hide) return; + bool hasInOutSpecs = s->hasInOutSpecifier(); + bool hasTypeSpecs = s->hasTypeSpecifier(); + switch(s->type()) + { + case DocParamSect::Param: + m_t << "\n\\begin{DoxyParams}"; + if (hasInOutSpecs && hasTypeSpecs) m_t << "[2]"; // 2 extra cols + else if (hasInOutSpecs || hasTypeSpecs) m_t << "[1]"; // 1 extra col + m_t << "{"; + filter(theTranslator->trParameters()); + break; + case DocParamSect::RetVal: + m_t << "\n\\begin{DoxyRetVals}{"; + filter(theTranslator->trReturnValues()); + break; + case DocParamSect::Exception: + m_t << "\n\\begin{DoxyExceptions}{"; + filter(theTranslator->trExceptions()); + break; + case DocParamSect::TemplateParam: + /* TODO: add this + filter(theTranslator->trTemplateParam()); break; + */ + m_t << "\n\\begin{DoxyTemplParams}{"; + filter("Template Parameters"); + break; + default: + ASSERT(0); + } + m_t << "}\n"; +} + +void LatexDocVisitor::visitPost(DocParamSect *s) +{ + if (m_hide) return; + switch(s->type()) + { + case DocParamSect::Param: + m_t << "\\end{DoxyParams}\n"; + break; + case DocParamSect::RetVal: + m_t << "\\end{DoxyRetVals}\n"; + break; + case DocParamSect::Exception: + m_t << "\\end{DoxyExceptions}\n"; + break; + case DocParamSect::TemplateParam: + m_t << "\\end{DoxyTemplParams}\n"; + break; + default: + ASSERT(0); + } +} + +void LatexDocVisitor::visitPre(DocParamList *pl) +{ + if (m_hide) return; + DocParamSect::Type parentType = DocParamSect::Unknown; + DocParamSect *sect = 0; + if (pl->parent() && pl->parent()->kind()==DocNode::Kind_ParamSect) + { + parentType = ((DocParamSect*)pl->parent())->type(); + sect=(DocParamSect*)pl->parent(); + } + bool useTable = parentType==DocParamSect::Param || + parentType==DocParamSect::RetVal || + parentType==DocParamSect::Exception || + parentType==DocParamSect::TemplateParam; + if (!useTable) + { + m_t << "\\item["; + } + if (sect && sect->hasInOutSpecifier()) + { + if (pl->direction()!=DocParamSect::Unspecified) + { + m_t << "\\mbox{\\tt "; + if (pl->direction()==DocParamSect::In) + { + m_t << "in"; + } + else if (pl->direction()==DocParamSect::Out) + { + m_t << "out"; + } + else if (pl->direction()==DocParamSect::InOut) + { + m_t << "in,out"; + } + m_t << "} "; + } + if (useTable) m_t << " & "; + } + if (sect && sect->hasTypeSpecifier()) + { + QListIterator li(pl->paramTypes()); + DocNode *type; + bool first=TRUE; + for (li.toFirst();(type=li.current());++li) + { + if (!first) m_t << " | "; else first=FALSE; + if (type->kind()==DocNode::Kind_Word) + { + visit((DocWord*)type); + } + else if (type->kind()==DocNode::Kind_LinkedWord) + { + visit((DocLinkedWord*)type); + } + } + if (useTable) m_t << " & "; + } + m_t << "{\\em "; + //QStrListIterator li(pl->parameters()); + //const char *s; + QListIterator li(pl->parameters()); + DocNode *param; + bool first=TRUE; + for (li.toFirst();(param=li.current());++li) + { + if (!first) m_t << ","; else first=FALSE; + m_insideItem=TRUE; + if (param->kind()==DocNode::Kind_Word) + { + visit((DocWord*)param); + } + else if (param->kind()==DocNode::Kind_LinkedWord) + { + visit((DocLinkedWord*)param); + } + m_insideItem=FALSE; + } + m_t << "}"; + if (useTable) + { + m_t << " & "; + } + else + { + m_t << "]"; + } +} + +void LatexDocVisitor::visitPost(DocParamList *pl) +{ + if (m_hide) return; + DocParamSect::Type parentType = DocParamSect::Unknown; + if (pl->parent() && pl->parent()->kind()==DocNode::Kind_ParamSect) + { + parentType = ((DocParamSect*)pl->parent())->type(); + } + bool useTable = parentType==DocParamSect::Param || + parentType==DocParamSect::RetVal || + parentType==DocParamSect::Exception || + parentType==DocParamSect::TemplateParam; + if (useTable) + { + m_t << "\\\\" << endl + << "\\hline" << endl; + } +} + +void LatexDocVisitor::visitPre(DocXRefItem *x) +{ + if (m_hide) return; + m_t << "\\begin{DoxyRefDesc}{"; + filter(x->title()); + m_t << "}" << endl; + bool anonymousEnum = x->file()=="@"; + m_t << "\\item["; + if (Config_getBool("PDF_HYPERLINKS") && !anonymousEnum) + { + m_t << "\\hyperlink{" << stripPath(x->file()) << "_" << x->anchor() << "}{"; + } + else + { + m_t << "{\\bf "; + } + m_insideItem=TRUE; + filter(x->title()); + m_insideItem=FALSE; + m_t << "}]"; +} + +void LatexDocVisitor::visitPost(DocXRefItem *) +{ + if (m_hide) return; + m_t << "\\end{DoxyRefDesc}" << endl; +} + +void LatexDocVisitor::visitPre(DocInternalRef *ref) +{ + if (m_hide) return; + startLink(0,ref->file(),ref->anchor()); +} + +void LatexDocVisitor::visitPost(DocInternalRef *ref) +{ + if (m_hide) return; + endLink(0,ref->file(),ref->anchor()); +} + +void LatexDocVisitor::visitPre(DocCopy *) +{ +} + +void LatexDocVisitor::visitPost(DocCopy *) +{ +} + +void LatexDocVisitor::visitPre(DocText *) +{ +} + +void LatexDocVisitor::visitPost(DocText *) +{ +} + +void LatexDocVisitor::visitPre(DocHtmlBlockQuote *) +{ + if (m_hide) return; + m_t << "\\begin{quotation}" << endl; +} + +void LatexDocVisitor::visitPost(DocHtmlBlockQuote *) +{ + if (m_hide) return; + m_t << "\\end{quotation}" << endl; +} + +void LatexDocVisitor::filter(const char *str) +{ + filterLatexString(m_t,str,m_insideTabbing,m_insidePre,m_insideItem); +} + +void LatexDocVisitor::startLink(const QCString &ref,const QCString &file,const QCString &anchor) +{ + if (ref.isEmpty() && Config_getBool("PDF_HYPERLINKS")) // internal PDF link + { + if (ref.isEmpty()) { + m_t << "\\hyperlink{"; + if (!file.isEmpty()) m_t << stripPath(file); + if (!file.isEmpty() && !anchor.isEmpty()) m_t << "_"; + if (!anchor.isEmpty()) m_t << anchor; + m_t << "}{"; + } + else + { + QCString *dest; + m_t << "\\href{"; + if ((dest=Doxygen::tagDestinationDict[ref])) m_t << *dest << "/"; + if (!file.isEmpty()) m_t << file << Doxygen::htmlFileExtension; + if (!anchor.isEmpty()) m_t << "#" << anchor; + m_t << "}{"; + } + } + else if (ref.isEmpty()) // internal non-PDF link + { + m_t << "\\doxyref{"; + } + else // external link + { + m_t << "{\\bf "; + } +} + +void LatexDocVisitor::endLink(const QCString &ref,const QCString &file,const QCString &anchor) +{ + m_t << "}"; + if (ref.isEmpty() && !Config_getBool("PDF_HYPERLINKS")) + { + m_t << "{"; + filter(theTranslator->trPageAbbreviation()); + m_t << "}{" << file; + if (!anchor.isEmpty()) m_t << "_" << anchor; + m_t << "}"; + } +} + +void LatexDocVisitor::pushEnabled() +{ + m_enabled.push(new bool(m_hide)); +} + +void LatexDocVisitor::popEnabled() +{ + bool *v=m_enabled.pop(); + ASSERT(v!=0); + m_hide = *v; + delete v; +} + +void LatexDocVisitor::startDotFile(const QCString &fileName, + const QCString &width, + const QCString &height, + bool hasCaption + ) +{ + QCString baseName=fileName; + int i; + if ((i=baseName.findRev('/'))!=-1) + { + baseName=baseName.right(baseName.length()-i-1); + } + if ((i=baseName.find('.'))!=-1) + { + baseName=baseName.left(i); + } + baseName.prepend("dot_"); + QCString outDir = Config_getString("LATEX_OUTPUT"); + QCString name = fileName; + writeDotGraphFromFile(name,outDir,baseName,EPS); + if (hasCaption) + { + m_t << "\n\\begin{DoxyImage}\n"; + } + else + { + m_t << "\n\\begin{DoxyImageNoCaption}\n" + " \\mbox{"; + } + m_t << "\\includegraphics"; + if (!width.isEmpty()) + { + m_t << "[width=" << width << "]"; + } + else if (!height.isEmpty()) + { + m_t << "[height=" << height << "]"; + } + else + { + m_t << "[width=\\textwidth]"; + } + m_t << "{" << baseName << "}"; + + if (hasCaption) + { + m_t << "\n\\caption{"; + } +} + +void LatexDocVisitor::endDotFile(bool hasCaption) +{ + if (m_hide) return; + m_t << "}\n"; // end caption or mbox + if (hasCaption) + { + m_t << "\\end{DoxyImage}\n"; + } + else + { + m_t << "\\end{DoxyImageNoCaption}\n"; + } +} + +void LatexDocVisitor::startMscFile(const QCString &fileName, + const QCString &width, + const QCString &height, + bool hasCaption + ) +{ + QCString baseName=fileName; + int i; + if ((i=baseName.findRev('/'))!=-1) + { + baseName=baseName.right(baseName.length()-i-1); + } + if ((i=baseName.find('.'))!=-1) + { + baseName=baseName.left(i); + } + baseName.prepend("msc_"); + + QCString outDir = Config_getString("LATEX_OUTPUT"); + writeMscGraphFromFile(fileName,outDir,baseName,MSC_EPS); + if (hasCaption) + { + m_t << "\n\\begin{DoxyImage}\n"; + } + else + { + m_t << "\n\\begin{DoxyImageNoCaption}\n" + " \\mbox{"; + } + m_t << "\\includegraphics"; + if (!width.isEmpty()) + { + m_t << "[width=" << width << "]"; + } + else if (!height.isEmpty()) + { + m_t << "[height=" << height << "]"; + } + else + { + m_t << "[width=\\textwidth]"; + } + m_t << "{" << baseName << "}"; + + if (hasCaption) + { + m_t << "\n\\caption{"; + } +} + +void LatexDocVisitor::endMscFile(bool hasCaption) +{ + if (m_hide) return; + m_t << "}\n"; // end caption or mbox + if (hasCaption) + { + m_t << "\\end{DoxyImage}\n"; + } + else + { + m_t << "\\end{DoxyImageNoCaption}\n"; + } +} + + +void LatexDocVisitor::writeMscFile(const QCString &baseName) +{ + QCString shortName = baseName; + int i; + if ((i=shortName.findRev('/'))!=-1) + { + shortName=shortName.right(shortName.length()-i-1); + } + QCString outDir = Config_getString("LATEX_OUTPUT"); + writeMscGraphFromFile(baseName+".msc",outDir,shortName,MSC_EPS); + m_t << "\n\\begin{DoxyImageNoCaption}" + " \\mbox{\\includegraphics"; + m_t << "{" << shortName << "}"; + m_t << "}\n"; // end mbox + m_t << "\\end{DoxyImageNoCaption}\n"; +} + diff --git a/trunk/src/latexdocvisitor.h b/trunk/src/latexdocvisitor.h new file mode 100644 index 0000000..a4892ce --- /dev/null +++ b/trunk/src/latexdocvisitor.h @@ -0,0 +1,192 @@ +/****************************************************************************** + * + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#ifndef _LATEXDOCVISITOR_H +#define _LATEXDOCVISITOR_H + +#include "docvisitor.h" +#include +#include +#include +//#include + +class FTextStream; +class CodeOutputInterface; + +/*! @brief Concrete visitor implementation for LaTeX output. */ +class LatexDocVisitor : public DocVisitor +{ + public: + LatexDocVisitor(FTextStream &t,CodeOutputInterface &ci, + const char *langExt,bool insideTabbing); + + //-------------------------------------- + // visitor functions for leaf nodes + //-------------------------------------- + + void visit(DocWord *); + void visit(DocLinkedWord *); + void visit(DocWhiteSpace *); + void visit(DocSymbol *); + void visit(DocURL *); + void visit(DocLineBreak *); + void visit(DocHorRuler *); + void visit(DocStyleChange *); + void visit(DocVerbatim *); + void visit(DocAnchor *); + void visit(DocInclude *); + void visit(DocIncOperator *); + void visit(DocFormula *); + void visit(DocIndexEntry *); + void visit(DocSimpleSectSep *); + void visit(DocCite *); + + //-------------------------------------- + // visitor functions for compound nodes + //-------------------------------------- + + void visitPre(DocAutoList *); + void visitPost(DocAutoList *); + void visitPre(DocAutoListItem *); + void visitPost(DocAutoListItem *); + void visitPre(DocPara *); + void visitPost(DocPara *); + void visitPre(DocRoot *); + void visitPost(DocRoot *); + void visitPre(DocSimpleSect *); + void visitPost(DocSimpleSect *); + void visitPre(DocTitle *); + void visitPost(DocTitle *); + void visitPre(DocSimpleList *); + void visitPost(DocSimpleList *); + void visitPre(DocSimpleListItem *); + void visitPost(DocSimpleListItem *); + void visitPre(DocSection *s); + void visitPost(DocSection *); + void visitPre(DocHtmlList *s); + void visitPost(DocHtmlList *s); + void visitPre(DocHtmlListItem *); + void visitPost(DocHtmlListItem *); + //void visitPre(DocHtmlPre *); + //void visitPost(DocHtmlPre *); + void visitPre(DocHtmlDescList *); + void visitPost(DocHtmlDescList *); + void visitPre(DocHtmlDescTitle *); + void visitPost(DocHtmlDescTitle *); + void visitPre(DocHtmlDescData *); + void visitPost(DocHtmlDescData *); + void visitPre(DocHtmlTable *t); + void visitPost(DocHtmlTable *t); + void visitPre(DocHtmlCaption *); + void visitPost(DocHtmlCaption *); + void visitPre(DocHtmlRow *); + void visitPost(DocHtmlRow *) ; + void visitPre(DocHtmlCell *); + void visitPost(DocHtmlCell *); + void visitPre(DocInternal *); + void visitPost(DocInternal *); + void visitPre(DocHRef *); + void visitPost(DocHRef *); + void visitPre(DocHtmlHeader *); + void visitPost(DocHtmlHeader *) ; + void visitPre(DocImage *); + void visitPost(DocImage *); + void visitPre(DocDotFile *); + void visitPost(DocDotFile *); + void visitPre(DocMscFile *); + void visitPost(DocMscFile *); + void visitPre(DocLink *lnk); + void visitPost(DocLink *); + void visitPre(DocRef *ref); + void visitPost(DocRef *); + void visitPre(DocSecRefItem *); + void visitPost(DocSecRefItem *); + void visitPre(DocSecRefList *); + void visitPost(DocSecRefList *); + void visitPre(DocParamSect *); + void visitPost(DocParamSect *); + void visitPre(DocParamList *); + void visitPost(DocParamList *); + void visitPre(DocXRefItem *); + void visitPost(DocXRefItem *); + void visitPre(DocInternalRef *); + void visitPost(DocInternalRef *); + void visitPre(DocCopy *); + void visitPost(DocCopy *); + void visitPre(DocText *); + void visitPost(DocText *); + void visitPre(DocHtmlBlockQuote *); + void visitPost(DocHtmlBlockQuote *); + + private: + + struct ActiveRowSpan + { + ActiveRowSpan(DocHtmlCell *c,int rs,int cs,int col) + : cell(c), rowSpan(rs), colSpan(cs), column(col) {} + DocHtmlCell *cell; + int rowSpan; + int colSpan; + int column; + }; + + typedef QList RowSpanList; + + //-------------------------------------- + // helper functions + //-------------------------------------- + + void filter(const char *str); + void startLink(const QCString &ref,const QCString &file, + const QCString &anchor); + void endLink(const QCString &ref,const QCString &file, + const QCString &anchor); + QCString escapeMakeIndexChars(const char *s); + void startDotFile(const QCString &fileName,const QCString &width, + const QCString &height, bool hasCaption); + void endDotFile(bool hasCaption); + + void startMscFile(const QCString &fileName,const QCString &width, + const QCString &height, bool hasCaption); + void endMscFile(bool hasCaption); + void writeMscFile(const QCString &fileName); + + void pushEnabled(); + void popEnabled(); + + //-------------------------------------- + // state variables + //-------------------------------------- + + FTextStream &m_t; + CodeOutputInterface &m_ci; + bool m_insidePre; + bool m_insideItem; + bool m_hide; + bool m_insideTabbing; + bool m_insideTable; + int m_numCols; + QStack m_enabled; + QCString m_langExt; + RowSpanList m_rowSpans; + int m_currentColumn; + bool m_inRowspan; + bool m_inColspan; +}; + +#endif diff --git a/trunk/src/latexgen.cpp b/trunk/src/latexgen.cpp new file mode 100644 index 0000000..ebf6a43 --- /dev/null +++ b/trunk/src/latexgen.cpp @@ -0,0 +1,2623 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#include + +#include "qtbc.h" +#include +#include "latexgen.h" +#include "config.h" +#include "message.h" +#include "doxygen.h" +#include "util.h" +#include "diagram.h" +#include "language.h" +#include "version.h" +#include "dot.h" +#include "pagedef.h" +#include "docparser.h" +#include "latexdocvisitor.h" +#include "dirdef.h" +#include "cite.h" + +//static QCString filterTitle(const char *s) +//{ +// QCString tmp=s,result; +// uint i;for (i=0;iisEmpty(); + QCString dir=Config_getString("LATEX_OUTPUT"); + QCString fileName=dir+"/Makefile"; + QFile file(fileName); + if (!file.open(IO_WriteOnly)) + { + err("Could not open file %s for writing\n",fileName.data()); + exit(1); + } + // inserted by KONNO Akihisa 2002-03-05 + QCString latex_command = Config_getString("LATEX_CMD_NAME"); + QCString mkidx_command = Config_getString("MAKEINDEX_CMD_NAME"); + // end insertion by KONNO Akihisa 2002-03-05 + FTextStream t(&file); + if (!Config_getBool("USE_PDFLATEX")) // use plain old latex + { + t << "all: refman.dvi" << endl + << endl + << "ps: refman.ps" << endl + << endl + << "pdf: refman.pdf" << endl + << endl + << "ps_2on1: refman_2on1.ps" << endl + << endl + << "pdf_2on1: refman_2on1.pdf" << endl + << endl + << "refman.ps: refman.dvi" << endl + << "\tdvips -o refman.ps refman.dvi" << endl + << endl; + t << "refman.pdf: refman.ps" << endl; + t << "\tps2pdf refman.ps refman.pdf" << endl << endl; + t << "refman.dvi: clean refman.tex doxygen.sty" << endl + << "\techo \"Running latex...\"" << endl + << "\t" << latex_command << " refman.tex" << endl + << "\techo \"Running makeindex...\"" << endl + << "\t" << mkidx_command << " refman.idx" << endl; + if (generateBib) + { + t << "\techo \"Running bibtex...\"" << endl; + t << "\tbibtex refman" << endl; + t << "\techo \"Rerunning latex....\"" << endl; + t << "\t" << latex_command << " refman.tex" << endl; + } + t << "\techo \"Rerunning latex....\"" << endl + << "\t" << latex_command << " refman.tex" << endl + << "\tlatex_count=5 ; \\" << endl + << "\twhile egrep -s 'Rerun (LaTeX|to get cross-references right)' refman.log && [ $$latex_count -gt 0 ] ;\\" << endl + << "\t do \\" << endl + << "\t echo \"Rerunning latex....\" ;\\" << endl + << "\t " << latex_command << " refman.tex ;\\" << endl + << "\t latex_count=`expr $$latex_count - 1` ;\\" << endl + << "\t done" << endl << endl + << "refman_2on1.ps: refman.ps" << endl + << "\tpsnup -2 refman.ps >refman_2on1.ps" << endl + << endl + << "refman_2on1.pdf: refman_2on1.ps" << endl + << "\tps2pdf refman_2on1.ps refman_2on1.pdf" << endl; + } + else // use pdflatex for higher quality output + { + t << "all: refman.pdf" << endl << endl + << "pdf: refman.pdf" << endl << endl; + t << "refman.pdf: clean refman.tex" << endl; + t << "\tpdflatex refman" << endl; + t << "\t" << mkidx_command << " refman.idx" << endl; + if (generateBib) + { + t << "\tbibtex refman" << endl; + t << "\tpdflatex refman" << endl; + } + t << "\tpdflatex refman" << endl + << "\tlatex_count=5 ; \\" << endl + << "\twhile egrep -s 'Rerun (LaTeX|to get cross-references right)' refman.log && [ $$latex_count -gt 0 ] ;\\" << endl + << "\t do \\" << endl + << "\t echo \"Rerunning latex....\" ;\\" << endl + << "\t pdflatex refman ;\\" << endl + << "\t latex_count=`expr $$latex_count - 1` ;\\" << endl + << "\t done" << endl << endl; + } + + t << endl + << "clean:" << endl + << "\trm -f " + << "*.ps *.dvi *.aux *.toc *.idx *.ind *.ilg *.log *.out *.brf *.blg *.bbl refman.pdf" << endl; +} + +static void writeMakeBat() +{ +#if defined(_MSC_VER) + QCString dir=Config_getString("LATEX_OUTPUT"); + QCString fileName=dir+"/make.bat"; + QCString latex_command = Config_getString("LATEX_CMD_NAME"); + QCString mkidx_command = Config_getString("MAKEINDEX_CMD_NAME"); + QFile file(fileName); + bool generateBib = !Doxygen::citeDict->isEmpty(); + if (!file.open(IO_WriteOnly)) + { + err("Could not open file %s for writing\n",fileName.data()); + exit(1); + } + FTextStream t(&file); + t << "del /s /f *.ps *.dvi *.aux *.toc *.idx *.ind *.ilg *.log *.out *.brf *.blg *.bbl refman.pdf\n\n"; + if (!Config_getBool("USE_PDFLATEX")) // use plain old latex + { + t << latex_command << " refman.tex\n"; + t << "echo ----\n"; + t << mkidx_command << " refman.idx\n"; + if (generateBib) + { + t << "bibtex refman\n"; + t << "echo ----\n"; + t << latex_command << " refman.tex\n"; + } + t << "setlocal enabledelayedexpansion\n"; + t << "set count=5\n"; + t << ":repeat\n"; + t << "set content=X\n"; + t << "for /F \"tokens=*\" %%T in ( 'findstr /C:\"Rerun LaTeX\" refman.log' ) do set content=\"%%~T\"\n"; + t << "if !content! == X for /F \"tokens=*\" %%T in ( 'findstr /C:\"Rerun to get cross-references right\" refman.log' ) do set content=\"%%~T\"\n"; + t << "if !content! == X goto :skip\n"; + t << "set /a count-=1\n"; + t << "if !count! EQU 0 goto :skip\n\n"; + t << "echo ----\n"; + t << latex_command << " refman.tex\n"; + t << "goto :repeat\n"; + t << ":skip\n"; + t << "endlocal\n"; + t << "dvips -o refman.ps refman.dvi\n"; + t << "gswin32c -q -dNOPAUSE -dBATCH -sDEVICE=pdfwrite " + "-sOutputFile=refman.pdf -c save pop -f refman.ps\n"; + } + else // use pdflatex + { + t << "pdflatex refman\n"; + t << "echo ----\n"; + t << mkidx_command << " refman.idx\n"; + if (generateBib) + { + t << "bibtex refman" << endl; + t << "pdflatex refman" << endl; + } + t << "echo ----\n"; + t << "pdflatex refman\n\n"; + t << "setlocal enabledelayedexpansion\n"; + t << "set count=5\n"; + t << ":repeat\n"; + t << "set content=X\n"; + t << "for /F \"tokens=*\" %%T in ( 'findstr /C:\"Rerun LaTeX\" refman.log' ) do set content=\"%%~T\"\n"; + t << "if !content! == X for /F \"tokens=*\" %%T in ( 'findstr /C:\"Rerun to get cross-references right\" refman.log' ) do set content=\"%%~T\"\n"; + t << "if !content! == X goto :skip\n"; + t << "set /a count-=1\n"; + t << "if !count! EQU 0 goto :skip\n\n"; + t << "echo ----\n"; + t << "pdflatex refman\n"; + t << "goto :repeat\n"; + t << ":skip\n"; + t << "endlocal\n"; + } +#endif +} + +void LatexGenerator::init() +{ + + QCString dir=Config_getString("LATEX_OUTPUT"); + QDir d(dir); + if (!d.exists() && !d.mkdir(dir)) + { + err("Could not create output directory %s\n",dir.data()); + exit(1); + } + + writeLatexMakefile(); + writeMakeBat(); + + createSubDirs(d); +} + +static void writeDefaultHeaderPart1(FTextStream &t) +{ + // part 1 + + QCString paperName; + if (Config_getBool("LATEX_BATCHMODE")) t << "\\batchmode" << endl; + QCString &paperType=Config_getEnum("PAPER_TYPE"); + if (paperType=="a4wide") + paperName="a4"; + else + paperName=paperType; + t << "\\documentclass"; + //"[" << paperName << "paper"; + //t << "]"; + t << "{"; + if (Config_getBool("COMPACT_LATEX")) t << "article"; else t << "book"; + t << "}\n"; + // the next package is obsolete (see bug 563698) + //if (paperType=="a4wide") t << "\\usepackage{a4wide}\n"; + t << + "\\usepackage["<latexLanguageSupportCommand()); + + if (!sLanguageSupportCommand.isEmpty()) + { + // The command is not empty. Put it to the output. + // if the command is empty, no output is needed. + t << sLanguageSupportCommand << endl; + } + t << "\\usepackage{mathptmx}\n"; + t << "\\usepackage[scaled=.90]{helvet}\n"; + t << "\\usepackage{courier}\n"; + t << "\\usepackage{sectsty}\n"; + t << "\\usepackage[titles]{tocloft}\n"; + t << "\\usepackage{doxygen}\n"; + + // define option for listings + t << "\\lstset{language=C++," + "inputencoding=utf8," + "basicstyle=\\footnotesize," + "breaklines=true," + "breakatwhitespace=true," + "tabsize=" << Config_getInt("TAB_SIZE") <<"," + "numbers=left }" << endl; + + QStrList &extraPackages = Config_getList("EXTRA_PACKAGES"); + const char *s=extraPackages.first(); + while (s) + { + t << "\\usepackage{" << s << "}\n"; + s=extraPackages.next(); + } + t << "\\makeindex\n" + "\\setcounter{tocdepth}{3}\n" + "\\renewcommand{\\footrulewidth}{0.4pt}\n" + "\\renewcommand{\\familydefault}{\\sfdefault}\n" + "\\hfuzz=15pt\n" // allow a bit of overflow to go unnoticed + "\\setlength{\\emergencystretch}{15pt}\n" + "\\hbadness=750\n" + "\\tolerance=750\n" + "\\begin{document}\n"; + static bool pdfHyperlinks = Config_getBool("PDF_HYPERLINKS"); + static bool usePDFLatex = Config_getBool("USE_PDFLATEX"); + if (pdfHyperlinks && usePDFLatex) + { + // to avoid duplicate page anchors due to reuse of same numbers for + // the index (be it as roman numbers) + t << "\\hypersetup{pageanchor=false,citecolor=blue}" << endl; + } + if (theTranslator->idLanguage()=="greek") t << "\\selectlanguage{greek}\n"; + t << "\\begin{titlepage}\n" + "\\vspace*{7cm}\n" + "\\begin{center}\n" + "{\\Large "; + +} + +static void writeDefaultHeaderPart2(FTextStream &t) +{ + // part 2 + t << "}\\\\" << endl + << "\\vspace*{1cm}" << endl + << "{\\large "; +} + +static void writeDefaultHeaderPart3(FTextStream &t) +{ + // part 3 + t << " Doxygen " << versionString << "}\\\\" << endl + << "\\vspace*{0.5cm}" << endl + << "{\\small " << dateToString(TRUE) << "}\\\\" << endl + << "\\end{center}" << endl + << "\\end{titlepage}" << endl; + if (!Config_getBool("COMPACT_LATEX")) t << "\\clearemptydoublepage\n"; + t << "\\pagenumbering{roman}\n"; + t << "\\tableofcontents\n"; + if (!Config_getBool("COMPACT_LATEX")) t << "\\clearemptydoublepage\n"; + t << "\\pagenumbering{arabic}\n"; + static bool pdfHyperlinks = Config_getBool("PDF_HYPERLINKS"); + static bool usePDFLatex = Config_getBool("USE_PDFLATEX"); + if (pdfHyperlinks && usePDFLatex) + { + t << "\\hypersetup{pageanchor=true,citecolor=blue}" << endl; + } +} + +static void writeDefaultStyleSheetPart1(FTextStream &t) +{ + // part 1 + t << "\\NeedsTeXFormat{LaTeX2e}\n" + "\\ProvidesPackage{doxygen}\n\n"; + t << "% Packages used by this style file\n" + "\\RequirePackage{alltt}\n" + "\\RequirePackage{array}\n" + "\\RequirePackage{calc}\n" + "\\RequirePackage{color}\n" + "\\RequirePackage{fancyhdr}\n" + "\\RequirePackage{longtable}\n" + "\\RequirePackage{verbatim}\n" + "\\RequirePackage{ifthen}\n" + "\\RequirePackage{xtab}\n" + "\\RequirePackage{multirow}\n" + "\\RequirePackage[table]{xcolor}\n\n"; + + t << "% Use helvetica font instead of times roman\n" + "\\RequirePackage{helvet}\n" + "\\RequirePackage{sectsty}\n" + "\\RequirePackage{tocloft}\n" +// "\\allsectionsfont{\\usefont{OT1}{phv}{bc}{n}\\selectfont}\n" +// "\\providecommand{\\cftchapfont}{%\n" +// " \\fontsize{11}{13}\\usefont{OT1}{phv}{bc}{n}\\selectfont\n" +// "}\n" +// "\\providecommand{\\cftchappagefont}{%\n" +// " \\fontsize{11}{13}\\usefont{OT1}{phv}{c}{n}\\selectfont\n" +// "}\n" +// "\\providecommand{\\cftsecfont}{%\n" +// " \\fontsize{10}{12}\\usefont{OT1}{phv}{c}{n}\\selectfont\n" +// "}\n" +// "\\providecommand{\\cftsecpagefont}{%\n" +// " \\fontsize{10}{12}\\usefont{OT1}{phv}{c}{n}\\selectfont\n" +// "}\n" +// "\\providecommand{\\cftsubsecfont}{%\n" +// " \\fontsize{10}{12}\\usefont{OT1}{phv}{c}{n}\\selectfont\n" +// "}\n" +// "\\providecommand{\\cftsubsecpagefont}{%\n" +// " \\fontsize{10}{12}\\usefont{OT1}{phv}{c}{n}\\selectfont\n" +// "}\n" +// "\\providecommand{\\cftsubsubsecfont}{%\n" +// " \\fontsize{9}{11}\\usefont{OT1}{phv}{c}{n}\\selectfont\n" +// "}\n" +// "\\providecommand{\\cftsubsubsecpagefont}{%\n" +// " \\fontsize{9}{11}\\usefont{OT1}{phv}{c}{n}\\selectfont\n" +// "}\n" +// "\\providecommand{\\cftparafont}{%\n" +// " \\fontsize{9}{11}\\usefont{OT1}{phv}{c}{n}\\selectfont\n" +// "}\n" +// "\\providecommand{\\cftparapagefont}{%\n" +// " \\fontsize{9}{11}\\usefont{OT1}{phv}{c}{n}\\selectfont\n" +// "}\n" +// "\\providecommand{\\cfttoctitlefont}{%\n" +// " \\fontsize{20}{22}\\usefont{OT1}{phv}{b}{n}\\selectfont\n" +// "}\n" + "\\providecommand{\\rmdefault}{phv}\n" + "\\providecommand{\\bfdefault}{bc}\n" + "\n\n"; + + t << "% Setup fancy headings\n" + "\\pagestyle{fancyplain}\n" + "\\newcommand{\\clearemptydoublepage}{%\n" + " \\newpage{\\pagestyle{empty}\\cleardoublepage}%\n" + "}\n"; + if (!Config_getBool("COMPACT_LATEX")) + t << "\\renewcommand{\\chaptermark}[1]{%\n" + " \\markboth{#1}{}%\n" + "}\n"; + t << "\\renewcommand{\\sectionmark}[1]{%\n" + " \\markright{\\thesection\\ #1}%\n" + "}\n"; + + //t << "\\lhead[\\fancyplain{}{\\bfseries\\thepage}]{%\n" + // " \\fancyplain{}{\\bfseries\\rightmark}%\n" + // "}\n"; + //t << "\\rhead[\\fancyplain{}{\\bfseries\\leftmark}]{%\n" + // " \\fancyplain{}{\\bfseries\\thepage}%\n" + // "}\n"; + //t << "\\rfoot[\\fancyplain{}{\\bfseries\\scriptsize%\n "; + t << "\\fancyhead[LE]{\\fancyplain{}{\\bfseries\\thepage}}\n"; + t << "\\fancyhead[CE]{\\fancyplain{}{}}\n"; + t << "\\fancyhead[RE]{\\fancyplain{}{\\bfseries\\leftmark}}\n"; + t << "\\fancyhead[LO]{\\fancyplain{}{\\bfseries\\rightmark}}\n"; + t << "\\fancyhead[CO]{\\fancyplain{}{}}\n"; + t << "\\fancyhead[RO]{\\fancyplain{}{\\bfseries\\thepage}}\n"; + + t << "\\fancyfoot[LE]{\\fancyplain{}{}}\n"; + t << "\\fancyfoot[CE]{\\fancyplain{}{}}\n"; + t << "\\fancyfoot[RE]{\\fancyplain{}{\\bfseries\\scriptsize "; +} + +static void writeDefaultStyleSheetPart2(FTextStream &t) +{ + t << "}}\n"; + t << "\\fancyfoot[LO]{\\fancyplain{}{\\bfseries\\scriptsize "; + //t << "\\lfoot[]{\\fancyplain{}{\\bfseries\\scriptsize%\n "; + +} + +static void writeDefaultStyleSheetPart3(FTextStream &t) +{ + static bool latexSourceCode = Config_getBool("LATEX_SOURCE_CODE"); + t << "}}\n"; + //t << "\\cfoot{}\n\n"; + t << "\\fancyfoot[CO]{\\fancyplain{}{}}\n"; + t << "\\fancyfoot[RO]{\\fancyplain{}{}}\n"; + + t << "%---------- Internal commands used in this style file ----------------\n\n"; + + t << "\\newcommand\\tabfill[1]{%\n"; + t << " \\dimen@\\linewidth%\n"; + t << " \\advance\\dimen@\\@totalleftmargin%\n"; + t << " \\advance\\dimen@-\\dimen\\@curtab%\n"; + t << " \\parbox[t]\\dimen@{\\raggedright #1\\ifhmode\\strut\\fi}%\n"; + t << "}\n\n"; + + t << "\\newcommand{\\ensurespace}[1]{%\n"; + t << " \\begingroup\n"; + t << " \\setlength{\\dimen@}{#1}%\n"; + t << " \\vskip\\z@\\@plus\\dimen@\n"; + t << " \\penalty -100\\vskip\\z@\\@plus -\\dimen@\n"; + t << " \\vskip\\dimen@\n"; + t << " \\penalty 9999%\n"; + t << " \\vskip -\\dimen@\n"; + t << " \\vskip\\z@skip % hide the previous |\\vskip| from |\\addvspace|\n"; + t << " \\endgroup\n"; + t << "}\n\n"; + + t << "% Generic environment used by all paragraph-based environments defined\n" + "% below. Note that the command \\title{...} needs to be defined inside\n" + "% those environments!\n" + "\\newenvironment{DoxyDesc}[1]{%\n" + //" \\filbreak%\n" + " \\ensurespace{4\\baselineskip}%\n" + " \\begin{list}{}%\n" + " {%\n" + " \\settowidth{\\labelwidth}{40pt}%\n" + " \\setlength{\\leftmargin}{\\labelwidth}%\n" + " \\setlength{\\parsep}{0pt}%\n" + " \\setlength{\\itemsep}{-4pt}%\n" + " \\renewcommand{\\makelabel}{\\entrylabel}%\n" + " }%\n" + " \\item[#1]%\n" + "}{%\n" + " \\end{list}%\n" + "}\n\n"; + t << "%---------- Commands used by doxygen LaTeX output generator ----------\n\n"; + t << "% Used by

     ... 
    \n" + "\\newenvironment{DoxyPre}{%\n" + " \\small%\n" + " \\begin{alltt}%\n" + "}{%\n" + " \\end{alltt}%\n" + " \\normalsize%\n" + "}\n\n"; + t << "% Used by @code ... @endcode\n" + "\\newenvironment{DoxyCode}{%\n"; + if (latexSourceCode) + { + t << "\n\n\\begin{scriptsize}\\begin{alltt}%" << endl; + } + else + { + t << " \\footnotesize%\n" + " \\verbatim%\n"; + } + t << "}{%\n"; + if (latexSourceCode) + { + t << "\\end{alltt}\\end{scriptsize}%" << endl; + } + else + { + t << " \\endverbatim%\n" + " \\normalsize%\n"; + } + t << "}\n\n"; + t << "% Used by @example, @include, @includelineno and @dontinclude\n" + "\\newenvironment{DoxyCodeInclude}{%\n" + " \\DoxyCode%\n" + "}{%\n" + " \\endDoxyCode%\n" + "}\n\n"; + t << "% Used by @verbatim ... @endverbatim\n" + "\\newenvironment{DoxyVerb}{%\n" + " \\footnotesize%\n" + " \\verbatim%\n" + "}{%\n" + " \\endverbatim%\n" + " \\normalsize%\n" + "}\n\n"; + t << "% Used by @verbinclude\n" + "\\newenvironment{DoxyVerbInclude}{%\n" + " \\DoxyVerb%\n" + "}{%\n" + " \\endDoxyVerb%\n" + "}\n\n"; + t << "% Used by numbered lists (using '-#' or
      ...
    )\n" + "\\newenvironment{DoxyEnumerate}{%\n" + " \\enumerate%\n" + "}{%\n" + " \\endenumerate%\n" + "}\n\n"; + t << "% Used by bullet lists (using '-', @li, @arg, or
      ...
    )\n" + "\\newenvironment{DoxyItemize}{%\n" + " \\itemize%\n" + "}{%\n" + " \\enditemize%\n" + "}\n\n"; + t << "% Used by description lists (using
    ...
    )\n" + "\\newenvironment{DoxyDescription}{%\n" + " \\description%\n" + "}{%\n" + " \\enddescription%\n" + "}\n\n"; + t << "% Used by @image, @dotfile, and @dot ... @enddot\n" + "% (only if caption is specified)\n" + "\\newenvironment{DoxyImage}{%\n" + " \\begin{figure}[H]%\n" + " \\begin{center}%\n" + "}{%\n" + " \\end{center}%\n" + " \\end{figure}%\n" + "}\n\n"; + t << "% Used by @image, @dotfile, @dot ... @enddot, and @msc ... @endmsc\n" + "% (only if no caption is specified)\n" + "\\newenvironment{DoxyImageNoCaption}{%\n" + "}{%\n" + "}\n\n"; + t << "% Used by @attention\n" + "\\newenvironment{DoxyAttention}[1]{%\n" + " \\begin{DoxyDesc}{#1}%\n" + "}{%\n" + " \\end{DoxyDesc}%\n" + "}\n\n"; + t << "% Used by @author and @authors\n" + "\\newenvironment{DoxyAuthor}[1]{%\n" + " \\begin{DoxyDesc}{#1}%\n" + "}{%\n" + " \\end{DoxyDesc}%\n" + "}\n\n"; + t << "% Used by @date\n" + "\\newenvironment{DoxyDate}[1]{%\n" + " \\begin{DoxyDesc}{#1}%\n" + "}{%\n" + " \\end{DoxyDesc}%\n" + "}\n\n"; + t << "% Used by @invariant\n" + "\\newenvironment{DoxyInvariant}[1]{%\n" + " \\begin{DoxyDesc}{#1}%\n" + "}{%\n" + " \\end{DoxyDesc}%\n" + "}\n\n"; + t << "% Used by @note\n" + "\\newenvironment{DoxyNote}[1]{%\n" + " \\begin{DoxyDesc}{#1}%\n" + "}{%\n" + " \\end{DoxyDesc}%\n" + "}\n\n"; + t << "% Used by @post\n" + "\\newenvironment{DoxyPostcond}[1]{%\n" + " \\begin{DoxyDesc}{#1}%\n" + "}{%\n" + " \\end{DoxyDesc}%\n" + "}\n\n"; + t << "% Used by @pre\n" + "\\newenvironment{DoxyPrecond}[1]{%\n" + " \\begin{DoxyDesc}{#1}%\n" + "}{%\n" + " \\end{DoxyDesc}%\n" + "}\n\n"; + t << "% Used by @copyright\n" + "\\newenvironment{DoxyCopyright}[1]{%\n" + " \\begin{DoxyDesc}{#1}%\n" + "}{%\n" + " \\end{DoxyDesc}%\n" + "}\n\n"; + t << "% Used by @remark\n" + "\\newenvironment{DoxyRemark}[1]{%\n" + " \\begin{DoxyDesc}{#1}%\n" + "}{%\n" + " \\end{DoxyDesc}%\n" + "}\n\n"; + t << "% Used by @return\n" + "\\newenvironment{DoxyReturn}[1]{%\n" + " \\begin{DoxyDesc}{#1}%\n" + "}{%\n" + " \\end{DoxyDesc}%\n" + "}\n\n"; + t << "% Used by @since\n" + "\\newenvironment{DoxySince}[1]{%\n" + " \\begin{DoxyDesc}{#1}%\n" + "}{%\n" + " \\end{DoxyDesc}%\n" + "}\n\n"; + t << "% Used by @see\n" + "\\newenvironment{DoxySeeAlso}[1]{%\n" + " \\begin{DoxyDesc}{#1}%\n" + "}{%\n" + " \\end{DoxyDesc}%\n" + "}\n\n"; + t << "% Used by @version\n" + "\\newenvironment{DoxyVersion}[1]{%\n" + " \\begin{DoxyDesc}{#1}%\n" + "}{%\n" + " \\end{DoxyDesc}%\n" + "}\n\n"; + t << "% Used by @warning\n" + "\\newenvironment{DoxyWarning}[1]{%\n" + " \\begin{DoxyDesc}{#1}%\n" + "}{%\n" + " \\end{DoxyDesc}%\n" + "}\n\n"; + t << "% Used by @internal\n" + "\\newenvironment{DoxyInternal}[1]{%\n" + " \\paragraph*{#1}%\n" + "}{%\n" + "}\n\n"; + t << "% Used by @par and @paragraph\n" + "\\newenvironment{DoxyParagraph}[1]{%\n" + " \\begin{list}{}%\n" + " {%\n" + " \\settowidth{\\labelwidth}{40pt}%\n" + " \\setlength{\\leftmargin}{\\labelwidth}%\n" + " \\setlength{\\parsep}{0pt}%\n" + " \\setlength{\\itemsep}{-4pt}%\n" + " \\renewcommand{\\makelabel}{\\entrylabel}%\n" + " }%\n" + " \\item[#1]%\n" + "}{%\n" + " \\end{list}%\n" + "}\n\n"; + t << "% Used by parameter lists\n" + "\\newenvironment{DoxyParams}[2][]{%\n" + " \\begin{DoxyDesc}{#2}%\n" + //" \\begin{description}%\n" + " \\item[] \\hspace{\\fill} \\vspace{-40pt}%\n" + //" \\definecolor{tableShade}{HTML}{F8F8F8}%\n" + //" \\rowcolors{1}{white}{tableShade}%\n" + //" \\arrayrulecolor{gray}%\n" + " \\settowidth{\\labelwidth}{40pt}%\n" + //" \\setlength{\\LTleft}{\\labelwidth}%\n" + " \\setlength{\\LTleft}{0pt}%\n" + " \\setlength{\\tabcolsep}{0.01\\textwidth}%\n" + " \\ifthenelse{\\equal{#1}{}}%\n" // default: name, docs columns + " {\\begin{longtable}{|>{\\raggedleft\\hspace{0pt}}p{0.15\\textwidth}|%\n" + " p{0.815\\textwidth}|}}%\n" + " {\\ifthenelse{\\equal{#1}{1}}%\n" // inout, name, docs columns, or type, name, docs columns + " {\\begin{longtable}{|>{\\centering}p{0.10\\textwidth}|%\n" + " >{\\raggedleft\\hspace{0pt}}p{0.15\\textwidth}|%\n" + " p{0.685\\textwidth}|}}%\n" + " {\\begin{longtable}{|>{\\centering}p{0.10\\textwidth}|%\n" // inout, type, name, docs columns + " >{\\centering\\hspace{0pt}}p{0.15\\textwidth}|%\n" + " >{\\raggedleft\\hspace{0pt}}p{0.15\\textwidth}|%\n" + " p{0.515\\textwidth}|}}%\n" + " }\\hline%\n" + "}{%\n" + " \\end{longtable}%\n" + //" \\end{description}%\n" + " \\end{DoxyDesc}%\n" + "}\n\n"; + t << "% Used for fields of simple structs\n" + "\\newenvironment{DoxyFields}[1]{%\n" + " \\begin{DoxyDesc}{#1}%\n" + " \\item[] \\hspace{\\fill} \\vspace{-40pt}%\n" + " \\settowidth{\\labelwidth}{40pt}%\n" + " \\setlength{\\LTleft}{0pt}%\n" + " \\setlength{\\tabcolsep}{0.01\\textwidth}%\n" + " \\begin{longtable}{|>{\\raggedleft\\hspace{0pt}}p{0.15\\textwidth}|%\n" + " p{0.15\\textwidth}|%\n" + " p{0.635\\textwidth}|}%\n" + //"\\hline{\\sf\\textbf{Type}} & {\\sf\\textbf{Name}} & {\\sf\\textbf{Description}}\\endhead%\n" + " \\hline%\n" + "}{%\n" + " \\end{longtable}%\n" + //" \\end{description}%\n" + " \\end{DoxyDesc}%\n" + "}\n\n"; + t << "% is used for parameters within a detailed function description\n" + "\\newenvironment{DoxyParamCaption}{%\n" + " \\renewcommand{\\item}[2][]{##1 {\\em ##2}}%\n" + " }{%\n" + "}\n\n"; + t << "% Used by return value lists\n" + "\\newenvironment{DoxyRetVals}[1]{%\n" + " \\begin{DoxyDesc}{#1}%\n" + " \\begin{description}%\n" + " \\item[] \\hspace{\\fill} \\vspace{-25pt}%\n" + //" \\definecolor{tableShade}{HTML}{F8F8F8}%\n" + //" \\rowcolors{1}{white}{tableShade}%\n" + //" \\arrayrulecolor{gray}%\n" + " \\setlength{\\tabcolsep}{0.01\\textwidth}%\n" + " \\begin{longtable}{|>{\\raggedleft\\hspace{0pt}}p{0.25\\textwidth}|%\n" + " p{0.77\\textwidth}|}%\n" + " \\hline%\n" + "}{%\n" + " \\end{longtable}%\n" + " \\end{description}%\n" + " \\end{DoxyDesc}%\n" + "}\n\n"; + t << "% Used by exception lists\n" + "\\newenvironment{DoxyExceptions}[1]{%\n" + " \\begin{DoxyDesc}{#1}%\n" + " \\begin{description}%\n" + " \\item[] \\hspace{\\fill} \\vspace{-25pt}%\n" + " \\definecolor{tableShade}{HTML}{F8F8F8}%\n" + " \\rowcolors{1}{white}{tableShade}%\n" + " \\arrayrulecolor{gray}%\n" + " \\setlength{\\tabcolsep}{0.01\\textwidth}%\n" + " \\begin{longtable}{|>{\\raggedleft\\hspace{0pt}}p{0.25\\textwidth}|%\n" + " p{0.77\\textwidth}|}%\n" + " \\hline%\n" + "}{%\n" + " \\end{longtable}%\n" + " \\end{description}%\n" + " \\end{DoxyDesc}%\n" + "}\n\n"; + t << "% Used by template parameter lists\n" + "\\newenvironment{DoxyTemplParams}[1]{%\n" + " \\begin{DoxyDesc}{#1}%\n" + " \\begin{description}%\n" + " \\item[] \\hspace{\\fill} \\vspace{-25pt}%\n" + " \\definecolor{tableShade}{HTML}{F8F8F8}%\n" + " \\rowcolors{1}{white}{tableShade}%\n" + " \\arrayrulecolor{gray}%\n" + " \\setlength{\\tabcolsep}{0.01\\textwidth}%\n" + " \\begin{longtable}{|>{\\raggedleft\\hspace{0pt}}p{0.25\\textwidth}|%\n" + " p{0.77\\textwidth}|}%\n" + " \\hline%\n" + "}{%\n" + " \\end{longtable}%\n" + " \\end{description}%\n" + " \\end{DoxyDesc}%\n" + "}\n\n"; + t << "\\newcommand{\\doxyref}[3]{\\textbf{#1} (\\textnormal{#2}\\,\\pageref{#3})}\n"; + t << "\\newenvironment{DoxyCompactList}\n"; + t << "{\\begin{list}{}{\n"; + t << " \\setlength{\\leftmargin}{0.5cm}\n"; + t << " \\setlength{\\itemsep}{0pt}\n"; + t << " \\setlength{\\parsep}{0pt}\n"; + t << " \\setlength{\\topsep}{0pt}\n"; + t << " \\renewcommand{\\makelabel}{\\hfill}}}\n"; + t << "{\\end{list}}\n"; + t << "\\newenvironment{DoxyCompactItemize}\n"; + t << "{\n"; + t << " \\begin{itemize}\n"; + t << " \\setlength{\\itemsep}{-3pt}\n"; + t << " \\setlength{\\parsep}{0pt}\n"; + t << " \\setlength{\\topsep}{0pt}\n"; + t << " \\setlength{\\partopsep}{0pt}\n"; + t << "}\n"; + t << "{\\end{itemize}}\n"; + t << "\\newcommand{\\PBS}[1]{\\let\\temp=\\\\#1\\let\\\\=\\temp}\n"; + t << "\\newlength{\\tmplength}\n"; + t << "\\newenvironment{TabularC}[1]\n"; + t << "{\n"; + t << "\\setlength{\\tmplength}\n"; + t << " {\\linewidth/(#1)-\\tabcolsep*2-\\arrayrulewidth*(#1+1)/(#1)}\n"; + t << " \\par\\begin{xtabular*}{\\linewidth}\n"; + t << " {*{#1}{|>{\\PBS\\raggedright\\hspace{0pt}}p{\\the\\tmplength}}|}\n"; + t << "}\n"; + t << "{\\end{xtabular*}\\par}\n"; + t << "\\newcommand{\\entrylabel}[1]{\n"; + t << " {\\parbox[b]{\\labelwidth-4pt}{\\makebox[0pt][l]{%\n"; + t << " \\usefont{OT1}{phv}{bc}{n}\\color{darkgray}#1}\\vspace{1.5\\baselineskip}}}}\n"; + t << "\\newenvironment{Desc}\n"; + t << "{\\begin{list}{}\n"; + t << " {\n"; + t << " \\settowidth{\\labelwidth}{40pt}\n"; + t << " \\setlength{\\leftmargin}{\\labelwidth}\n"; + t << " \\setlength{\\parsep}{0pt}\n"; + t << " \\setlength{\\itemsep}{-4pt}\n"; + t << " \\renewcommand{\\makelabel}{\\entrylabel}\n"; + t << " }\n"; + t << "}\n"; + t << "{\\end{list}}\n"; + + t << "\\newsavebox{\\xrefbox}\n"; + t << "\\newlength{\\xreflength}\n"; + t << "\\newcommand{\\xreflabel}[1]{%\n"; + t << " \\sbox{\\xrefbox}{#1}%\n"; + t << " \\setlength{\\xreflength}{\\wd\\xrefbox}%\n"; + t << " \\ifthenelse{\\xreflength>\\labelwidth}{%\n"; + t << " \\begin{minipage}{\\textwidth}%\n"; + t << " \\setlength{\\parindent}{0pt}%\n"; + t << " \\hangindent=15pt\\bfseries #1\\vspace{1.2\\itemsep}%\n"; + t << " \\end{minipage}%\n"; + t << " }{%\n"; + t << " \\parbox[b]{\\labelwidth}{\\makebox[0pt][l]{\\textbf{#1}}}%\n"; + t << " }}%\n"; + t << "\\newenvironment{DoxyRefList}{%\n"; + t << " \\begin{list}{}{%\n"; + t << " \\setlength{\\labelwidth}{10pt}%\n"; + t << " \\setlength{\\leftmargin}{\\labelwidth}%\n"; + t << " \\addtolength{\\leftmargin}{\\labelsep}%\n"; + t << " \\renewcommand{\\makelabel}{\\xreflabel}%\n"; + t << " }%\n"; + t << " }%\n"; + t << "{\\end{list}}\n"; + t << "\\newenvironment{DoxyRefDesc}[1]\n"; + t << "{\\begin{list}{}{%\n"; + t << " \\renewcommand\\makelabel[1]{\\textbf{##1}}\n"; + t << " \\settowidth\\labelwidth{\\makelabel{#1}}\n"; + t << " \\setlength\\leftmargin{\\labelwidth+\\labelsep}}}\n"; + t << "{\\end{list}}\n"; + t << "\\newenvironment{Indent}\n"; + t << " {\\begin{list}{}{\\setlength{\\leftmargin}{0.5cm}}\n"; + t << " \\item[]\\ignorespaces}\n"; + t << " {\\unskip\\end{list}}\n"; + + t << "\\setlength{\\parindent}{0cm}\n"; + t << "\\setlength{\\parskip}{0.2cm}\n"; + t << "\\addtocounter{secnumdepth}{2}\n"; + // \sloppy should not be used, see bug 563698 + //t << "\\sloppy\n"; + t << "\\usepackage[T1]{fontenc}\n"; + t << "\\makeatletter\n"; + t << "\\renewcommand{\\paragraph}{\\@startsection{paragraph}{4}{0ex}%\n"; + t << " {-1.0ex}%\n"; + t << " {1.0ex}%\n"; + t << " {\\usefont{OT1}{phv}{bc}{n}\\color{darkgray}}}\n"; + t << "\\renewcommand{\\subparagraph}{\\@startsection{subparagraph}{5}{0ex}%\n"; + t << " {-1.0ex}%\n"; + t << " {1.0ex}%\n"; + t << " {\\usefont{OT1}{phv}{bc}{n}\\color{darkgray}}}\n"; + t << "\\makeatother\n"; + t << "\\allsectionsfont{\\usefont{OT1}{phv}{bc}{n}\\selectfont\\color{darkgray}}\n"; + t << "\\stepcounter{secnumdepth}\n"; + t << "\\stepcounter{tocdepth}\n"; + t << "\\definecolor{comment}{rgb}{0.5,0.0,0.0}\n"; + t << "\\definecolor{keyword}{rgb}{0.0,0.5,0.0}\n"; + t << "\\definecolor{keywordtype}{rgb}{0.38,0.25,0.125}\n"; + t << "\\definecolor{keywordflow}{rgb}{0.88,0.5,0.0}\n"; + t << "\\definecolor{preprocessor}{rgb}{0.5,0.38,0.125}\n"; + t << "\\definecolor{stringliteral}{rgb}{0.0,0.125,0.25}\n"; + t << "\\definecolor{charliteral}{rgb}{0.0,0.5,0.5}\n"; + t << "\\definecolor{vhdldigit}{rgb}{1.0,0.0,1.0}\n"; + t << "\\definecolor{vhdlkeyword}{rgb}{0.43,0.0,0.43}\n"; + t << "\\definecolor{vhdllogic}{rgb}{1.0,0.0,0.0}\n"; + t << "\\definecolor{vhdlchar}{rgb}{0.0,0.0,0.0}\n"; +} + +static void writeDefaultFooter(FTextStream &t) +{ + Doxygen::citeDict->writeLatexBibliography(t); + t << "\\printindex\n"; + t << "\\end{document}\n"; +} + +void LatexGenerator::writeHeaderFile(QFile &f) +{ + FTextStream t(&f); + writeDefaultHeaderPart1(t); + t << "Your title here"; + writeDefaultHeaderPart2(t); + t << "Generated by"; + writeDefaultHeaderPart3(t); +} + +void LatexGenerator::writeFooterFile(QFile &f) +{ + FTextStream t(&f); + writeDefaultFooter(t); +} + +void LatexGenerator::writeStyleSheetFile(QFile &f) +{ + FTextStream t(&f); + + writeDefaultStyleSheetPart1(t); + QCString &projectName = Config_getString("PROJECT_NAME"); + + t << theTranslator->trGeneratedAt( dateToString(TRUE), projectName ); + t << " doxygen"; + //t << " " << theTranslator->trWrittenBy() << " "; + //t << "Dimitri van Heesch \\copyright~1997-2012"; + writeDefaultStyleSheetPart2(t); + t << theTranslator->trGeneratedAt( dateToString(TRUE), projectName ); + t << " doxygen"; + //t << " << theTranslator->trWrittenBy() << " "; + //t << "Dimitri van Heesch \\copyright~1997-2012"; + writeDefaultStyleSheetPart3(t); +} + +void LatexGenerator::startFile(const char *name,const char *,const char *) +{ +#if 0 + setEncoding(Config_getString("LATEX_OUTPUT_ENCODING")); +#endif + QCString fileName=name; + relPath = relativePathToRoot(fileName); + sourceFileName = stripPath(fileName); + if (fileName.right(4)!=".tex" && fileName.right(4)!=".sty") fileName+=".tex"; + startPlainFile(fileName); +} + +void LatexGenerator::endFile() +{ + endPlainFile(); + sourceFileName.resize(0); +} + +//void LatexGenerator::writeIndex() +//{ +// startFile("refman.tex"); +//} + +void LatexGenerator::startProjectNumber() +{ + t << "\\\\[1ex]\\large "; +} + +void LatexGenerator::startIndexSection(IndexSections is) +{ + bool &compactLatex = Config_getBool("COMPACT_LATEX"); + QCString &latexHeader = Config_getString("LATEX_HEADER"); + switch (is) + { + case isTitlePageStart: + { + if (latexHeader.isEmpty()) + { + writeDefaultHeaderPart1(t); + } + else + { + QCString header = fileToString(latexHeader); + t << substituteKeywords(header,0, + Config_getString("PROJECT_NAME"), + Config_getString("PROJECT_NUMBER"), + Config_getString("PROJECT_BRIEF")); + } + } + break; + case isTitlePageAuthor: + if (latexHeader.isEmpty()) + { + writeDefaultHeaderPart2(t); + } + break; + case isMainPage: + if (compactLatex) t << "\\section"; else t << "\\chapter"; + t << "{"; //Introduction}\n" + break; + //case isPackageIndex: + // if (compactLatex) t << "\\section"; else t << "\\chapter"; + // t << "{"; //Package Index}\n" + // break; + case isModuleIndex: + if (compactLatex) t << "\\section"; else t << "\\chapter"; + t << "{"; //Module Index}\n" + break; + case isDirIndex: + if (compactLatex) t << "\\section"; else t << "\\chapter"; + t << "{"; //Directory Index}\n" + break; + case isNamespaceIndex: + if (compactLatex) t << "\\section"; else t << "\\chapter"; + t << "{"; //Namespace Index}\" + break; + case isClassHierarchyIndex: + if (compactLatex) t << "\\section"; else t << "\\chapter"; + t << "{"; //Hierarchical Index}\n" + break; + case isCompoundIndex: + if (compactLatex) t << "\\section"; else t << "\\chapter"; + t << "{"; //Annotated Compound Index}\n" + break; + case isFileIndex: + if (compactLatex) t << "\\section"; else t << "\\chapter"; + t << "{"; //Annotated File Index}\n" + break; + case isPageIndex: + if (compactLatex) t << "\\section"; else t << "\\chapter"; + t << "{"; //Annotated Page Index}\n" + break; + case isModuleDocumentation: + { + GroupSDict::Iterator gli(*Doxygen::groupSDict); + GroupDef *gd; + bool found=FALSE; + for (gli.toFirst();(gd=gli.current()) && !found;++gli) + { + if (!gd->isReference()) + { + if (compactLatex) t << "\\section"; else t << "\\chapter"; + t << "{"; //Module Documentation}\n"; + found=TRUE; + } + } + } + break; + case isDirDocumentation: + { + SDict::Iterator dli(*Doxygen::directories); + DirDef *dd; + bool found=FALSE; + for (dli.toFirst();(dd=dli.current()) && !found;++dli) + { + if (dd->isLinkableInProject()) + { + if (compactLatex) t << "\\section"; else t << "\\chapter"; + t << "{"; //Module Documentation}\n"; + found=TRUE; + } + } + } + break; + case isNamespaceDocumentation: + { + NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict); + NamespaceDef *nd; + bool found=FALSE; + for (nli.toFirst();(nd=nli.current()) && !found;++nli) + { + if (nd->isLinkableInProject()) + { + if (compactLatex) t << "\\section"; else t << "\\chapter"; + t << "{"; // Namespace Documentation}\n": + found=TRUE; + } + } + } + break; + case isClassDocumentation: + { + ClassSDict::Iterator cli(*Doxygen::classSDict); + ClassDef *cd=0; + bool found=FALSE; + for (cli.toFirst();(cd=cli.current()) && !found;++cli) + { + if (cd->isLinkableInProject() && + cd->templateMaster()==0 && + !cd->isEmbeddedInOuterScope() + ) + { + if (compactLatex) t << "\\section"; else t << "\\chapter"; + t << "{"; //Compound Documentation}\n"; + found=TRUE; + } + } + } + break; + case isFileDocumentation: + { + bool isFirst=TRUE; + FileName *fn=Doxygen::inputNameList->first(); + while (fn) + { + FileDef *fd=fn->first(); + while (fd) + { + if (fd->isLinkableInProject()) + { + if (isFirst) + { + if (compactLatex) t << "\\section"; else t << "\\chapter"; + t << "{"; //File Documentation}\n"; + isFirst=FALSE; + break; + } + } + fd=fn->next(); + } + fn=Doxygen::inputNameList->next(); + } + } + break; + case isExampleDocumentation: + { + if (compactLatex) t << "\\section"; else t << "\\chapter"; + t << "{"; //Example Documentation}\n"; + } + break; + case isPageDocumentation: + { + if (compactLatex) t << "\\section"; else t << "\\chapter"; + t << "{"; //Page Documentation}\n"; + } + break; + case isPageDocumentation2: + break; + case isEndIndex: + break; + } +} + +void LatexGenerator::endIndexSection(IndexSections is) +{ + //static bool compactLatex = Config_getBool("COMPACT_LATEX"); + static bool sourceBrowser = Config_getBool("SOURCE_BROWSER"); + static QCString latexHeader = Config_getString("LATEX_HEADER"); + static QCString latexFooter = Config_getString("LATEX_FOOTER"); + switch (is) + { + case isTitlePageStart: + break; + case isTitlePageAuthor: + if (latexHeader.isEmpty()) + { + writeDefaultHeaderPart3(t); + } + break; + case isMainPage: + { + //QCString indexName=Config_getBool("GENERATE_TREEVIEW")?"main":"index"; + QCString indexName="index"; + t << "}\n\\label{index}"; + if (Config_getBool("PDF_HYPERLINKS")) t << "\\hypertarget{index}{}"; + t << "\\input{" << indexName << "}\n"; + } + break; + case isModuleIndex: + t << "}\n\\input{modules}\n"; + break; + case isDirIndex: + t << "}\n\\input{dirs}\n"; + break; + case isNamespaceIndex: + t << "}\n\\input{namespaces}\n"; + break; + case isClassHierarchyIndex: + t << "}\n\\input{hierarchy}\n"; + break; + case isCompoundIndex: + t << "}\n\\input{annotated}\n"; + break; + case isFileIndex: + t << "}\n\\input{files}\n"; + break; + case isPageIndex: + t << "}\n\\input{pages}\n"; + break; + case isModuleDocumentation: + { + GroupSDict::Iterator gli(*Doxygen::groupSDict); + GroupDef *gd; + bool found=FALSE; + for (gli.toFirst();(gd=gli.current()) && !found;++gli) + { + if (!gd->isReference()) + { + t << "}\n\\input{" << gd->getOutputFileBase() << "}\n"; + found=TRUE; + } + } + for (;(gd=gli.current());++gli) + { + if (!gd->isReference()) + { + //if (compactLatex) t << "\\input"; else t << "\\include"; + t << "\\include"; + t << "{" << gd->getOutputFileBase() << "}\n"; + } + } + } + break; + case isDirDocumentation: + { + SDict::Iterator dli(*Doxygen::directories); + DirDef *dd; + bool found=FALSE; + for (dli.toFirst();(dd=dli.current()) && !found;++dli) + { + if (dd->isLinkableInProject()) + { + t << "}\n\\input{" << dd->getOutputFileBase() << "}\n"; + found=TRUE; + } + } + for (;(dd=dli.current());++dli) + { + if (dd->isLinkableInProject()) + { + //if (compactLatex) t << "\\input"; else t << "\\include"; + t << "\\input"; + t << "{" << dd->getOutputFileBase() << "}\n"; + } + } + } + break; + case isNamespaceDocumentation: + { + NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict); + NamespaceDef *nd; + bool found=FALSE; + for (nli.toFirst();(nd=nli.current()) && !found;++nli) + { + if (nd->isLinkableInProject()) + { + t << "}\n\\input{" << nd->getOutputFileBase() << "}\n"; + found=TRUE; + } + } + while ((nd=nli.current())) + { + if (nd->isLinkableInProject()) + { + //if (compactLatex) t << "\\input"; else t << "\\include"; + t << "\\input"; + t << "{" << nd->getOutputFileBase() << "}\n"; + } + ++nli; + } + } + break; + case isClassDocumentation: + { + ClassSDict::Iterator cli(*Doxygen::classSDict); + ClassDef *cd=0; + bool found=FALSE; + for (cli.toFirst();(cd=cli.current()) && !found;++cli) + { + if (cd->isLinkableInProject() && + cd->templateMaster()==0 && + !cd->isEmbeddedInOuterScope() + ) + { + t << "}\n\\input{" << cd->getOutputFileBase() << "}\n"; + found=TRUE; + } + } + for (;(cd=cli.current());++cli) + { + if (cd->isLinkableInProject() && + cd->templateMaster()==0 && + !cd->isEmbeddedInOuterScope() + ) + { + //if (compactLatex) t << "\\input"; else t << "\\include"; + t << "\\input"; + t << "{" << cd->getOutputFileBase() << "}\n"; + } + } + } + break; + case isFileDocumentation: + { + bool isFirst=TRUE; + FileName *fn=Doxygen::inputNameList->first(); + while (fn) + { + FileDef *fd=fn->first(); + while (fd) + { + if (fd->isLinkableInProject()) + { + if (isFirst) + { + t << "}\n\\input{" << fd->getOutputFileBase() << "}\n"; + if (sourceBrowser && m_prettyCode && fd->generateSourceFile()) + { + //t << "\\include{" << fd->getSourceFileBase() << "}\n"; + t << "\\input{" << fd->getSourceFileBase() << "}\n"; + } + isFirst=FALSE; + } + else + { + //if (compactLatex) t << "\\input" ; else t << "\\include"; + t << "\\input" ; + t << "{" << fd->getOutputFileBase() << "}\n"; + if (sourceBrowser && m_prettyCode && fd->generateSourceFile()) + { + //t << "\\include{" << fd->getSourceFileBase() << "}\n"; + t << "\\input{" << fd->getSourceFileBase() << "}\n"; + } + } + } + fd=fn->next(); + } + fn=Doxygen::inputNameList->next(); + } + } + break; + case isExampleDocumentation: + { + t << "}\n"; + PageSDict::Iterator pdi(*Doxygen::exampleSDict); + PageDef *pd=pdi.toFirst(); + if (pd) + { + t << "\\input{" << pd->getOutputFileBase() << "}\n"; + } + for (++pdi;(pd=pdi.current());++pdi) + { + //if (compactLatex) t << "\\input" ; else t << "\\include"; + t << "\\input"; + t << "{" << pd->getOutputFileBase() << "}\n"; + } + } + break; + case isPageDocumentation: + { + t << "}\n"; +#if 0 + PageSDict::Iterator pdi(*Doxygen::pageSDict); + PageDef *pd=pdi.toFirst(); + bool first=TRUE; + for (pdi.toFirst();(pd=pdi.current());++pdi) + { + if (!pd->getGroupDef() && !pd->isReference()) + { + if (compactLatex) t << "\\section"; else t << "\\chapter"; + t << "{" << pd->title(); + t << "}\n"; + + if (compactLatex || first) t << "\\input" ; else t << "\\include"; + t << "{" << pd->getOutputFileBase() << "}\n"; + first=FALSE; + } + } +#endif + } + break; + case isPageDocumentation2: + break; + case isEndIndex: + if (latexFooter.isEmpty()) + { + writeDefaultFooter(t); + } + else + { + QCString footer = fileToString(latexFooter); + t << substituteKeywords(footer,0, + Config_getString("PROJECT_NAME"), + Config_getString("PROJECT_NUMBER"), + Config_getString("PROJECT_BRIEF")); + } + break; + } +} + +void LatexGenerator::writePageLink(const char *name, bool /*first*/) +{ + //bool &compactLatex = Config_getBool("COMPACT_LATEX"); + // next is remove for bug615957 + //if (compactLatex || first) t << "\\input" ; else t << "\\include"; + t << "\\input" ; + t << "{" << name << "}\n"; +} + + +void LatexGenerator::writeStyleInfo(int part) +{ + switch(part) + { + case 0: + { + //QCString pname=Config_getString("PROJECT_NAME").stripWhiteSpace(); + startPlainFile("doxygen.sty"); + writeDefaultStyleSheetPart1(t); + } + break; + case 1: + case 3: + t << " Doxygen "; + break; + case 2: + { + writeDefaultStyleSheetPart2(t); + } + break; + case 4: + { + writeDefaultStyleSheetPart3(t); + endPlainFile(); + } + break; + } +} + +void LatexGenerator::newParagraph() +{ + t << endl << endl; +} + +void LatexGenerator::startParagraph() +{ + t << endl << endl; +} + +void LatexGenerator::endParagraph() +{ + t << endl << endl; +} + +void LatexGenerator::writeString(const char *text) +{ + t << text; +} + +void LatexGenerator::startIndexItem(const char *ref,const char *fn) +{ + t << "\\item "; + if (!ref && fn) + { + t << "\\contentsline{section}{"; + } +} + +void LatexGenerator::endIndexItem(const char *ref,const char *fn) +{ + if (!ref && fn) + { + t << "}{\\pageref{" << fn << "}}{}" << endl; + } +} + +//void LatexGenerator::writeIndexFileItem(const char *,const char *text) +//{ +// t << "\\item\\contentsline{section}{"; +// docify(text); +// t << "}{\\pageref{" << text << "}}" << endl; +//} + + +void LatexGenerator::startHtmlLink(const char *url) +{ + if (Config_getBool("PDF_HYPERLINKS")) + { + t << "\\href{"; + t << url; + t << "}"; + } + t << "{\\tt "; +} + +void LatexGenerator::endHtmlLink() +{ + t << "}"; +} + +//void LatexGenerator::writeMailLink(const char *url) +//{ +// if (Config_getBool("PDF_HYPERLINKS")) +// { +// t << "\\href{mailto:"; +// t << url; +// t << "}"; +// } +// t << "{\\tt "; +// docify(url); +// t << "}"; +//} + +void LatexGenerator::writeStartAnnoItem(const char *,const char *, + const char *path,const char *name) +{ + t << "\\item\\contentsline{section}{\\bf "; + if (path) docify(path); + docify(name); + t << "} "; +} + +void LatexGenerator::writeEndAnnoItem(const char *name) +{ + t << "}{\\pageref{" << name << "}}{}" << endl; +} + +void LatexGenerator::startIndexKey() +{ + t << "\\item\\contentsline{section}{"; +} + +void LatexGenerator::endIndexKey() +{ +} + +void LatexGenerator::startIndexValue(bool hasBrief) +{ + t << " "; + if (hasBrief) t << "\\\\*"; +} + +void LatexGenerator::endIndexValue(const char *name,bool /*hasBrief*/) +{ + //if (hasBrief) t << ")"; + t << "}{\\pageref{" << name << "}}{}" << endl; +} + +//void LatexGenerator::writeClassLink(const char *,const char *, +// const char *,const char *name) +//{ +// t << "{\\bf "; +// docify(name); +// t << "}"; +//} + +void LatexGenerator::startTextLink(const char *f,const char *anchor) +{ + if (!disableLinks && Config_getBool("PDF_HYPERLINKS")) + { + t << "\\hyperlink{"; + if (f) t << stripPath(f); + if (anchor) t << "_" << anchor; + t << "}{"; + } + else + { + t << "{\\bf "; + } +} + +void LatexGenerator::endTextLink() +{ + t << "}"; +} + +void LatexGenerator::writeObjectLink(const char *ref, const char *f, + const char *anchor, const char *text) +{ + if (!disableLinks && !ref && Config_getBool("PDF_HYPERLINKS")) + { + t << "\\hyperlink{"; + if (f) t << stripPath(f); + if (f && anchor) t << "_"; + if (anchor) t << anchor; + t << "}{"; + docify(text); + t << "}"; + } + else + { + t << "{\\bf "; + docify(text); + t << "}"; + } +} + +void LatexGenerator::startPageRef() +{ + t << " \\doxyref{}{"; +} + +void LatexGenerator::endPageRef(const char *clname, const char *anchor) +{ + t << "}{"; + if (clname) t << clname; + if (anchor) t << "_" << anchor; + t << "}"; +} + +void LatexGenerator::writeCodeLink(const char *ref,const char *f, + const char *anchor,const char *name, + const char *) +{ + static bool pdfHyperlinks = Config_getBool("PDF_HYPERLINKS"); + static bool usePDFLatex = Config_getBool("USE_PDFLATEX"); + int l = strlen(name); + if (col+l>80) + { + t << "\n "; + col=0; + } + if (m_prettyCode && !disableLinks && !ref && usePDFLatex && pdfHyperlinks) + { + t << "\\hyperlink{"; + if (f) t << stripPath(f); + if (f && anchor) t << "_"; + if (anchor) t << anchor; + t << "}{" << name << "}"; + } + else + { + t << name; + } + col+=l; +} + +void LatexGenerator::startTitleHead(const char *fileName) +{ + static bool pdfHyperlinks = Config_getBool("PDF_HYPERLINKS"); + static bool usePDFLatex = Config_getBool("USE_PDFLATEX"); + if (usePDFLatex && pdfHyperlinks && fileName) + { + t << "\\hypertarget{" << stripPath(fileName) << "}{"; + } + if (Config_getBool("COMPACT_LATEX")) + { + t << "\\subsection{"; + } + else + { + t << "\\section{"; + } +} + +void LatexGenerator::endTitleHead(const char *fileName,const char *name) +{ + static bool pdfHyperlinks = Config_getBool("PDF_HYPERLINKS"); + static bool usePDFLatex = Config_getBool("USE_PDFLATEX"); + t << "}" << endl; + if (name) + { + t << "\\label{" << fileName << "}\\index{"; + escapeLabelName(name); + t << "@{"; + escapeMakeIndexChars(name); + t << "}}" << endl; + } + if (usePDFLatex && pdfHyperlinks && fileName) + { + t << "}" << endl; + } +} + +void LatexGenerator::startTitle() +{ + if (Config_getBool("COMPACT_LATEX")) + { + t << "\\subsection{"; + } + else + { + t << "\\section{"; + } +} + +void LatexGenerator::startGroupHeader(int extraIndentLevel) +{ + if (Config_getBool("COMPACT_LATEX")) + { + extraIndentLevel++; + } + + if (extraIndentLevel==3) + { + t << "\\subparagraph*{"; + } + else if (extraIndentLevel==2) + { + t << "\\paragraph{"; + } + else if (extraIndentLevel==1) + { + t << "\\subsubsection{"; + } + else // extraIndentLevel==0 + { + t << "\\subsection{"; + } + disableLinks=TRUE; +} + +void LatexGenerator::endGroupHeader(int) +{ + disableLinks=FALSE; + t << "}" << endl; +} + +void LatexGenerator::startMemberHeader(const char *) +{ + if (Config_getBool("COMPACT_LATEX")) + { + t << "\\subsubsection*{"; + } + else + { + t << "\\subsection*{"; + } + disableLinks=TRUE; +} + +void LatexGenerator::endMemberHeader() +{ + disableLinks=FALSE; + t << "}" << endl; +} + +void LatexGenerator::startMemberDoc(const char *clname, + const char *memname, + const char *, + const char *title, + bool showInline) +{ + if (memname && memname[0]!='@') + { + t << "\\index{"; + if (clname) + { + escapeLabelName(clname); + t << "@{"; + escapeMakeIndexChars(clname); + t << "}!"; + } + escapeLabelName(memname); + t << "@{"; + escapeMakeIndexChars(memname); + t << "}}" << endl; + + t << "\\index{"; + escapeLabelName(memname); + t << "@{"; + escapeMakeIndexChars(memname); + t << "}"; + if (clname) + { + t << "!" << clname << "@{"; + docify(clname); + t << "}"; + } + t << "}" << endl; + } + static const char *levelLab[] = { "subsubsection","paragraph","subparagraph", "subparagraph" }; + static bool compactLatex = Config_getBool("COMPACT_LATEX"); + int level=0; + if (showInline) level+=2; + if (compactLatex) level++; + t << "\\" << levelLab[level]; + + //if (Config_getBool("PDF_HYPERLINKS") && memname) + //{ + // t << "["; + // escapeMakeIndexChars(this,t,memname); + // t << "]"; + //} + t << "[{"; + escapeMakeIndexChars(title); + t << "}]"; + t << "{\\setlength{\\rightskip}{0pt plus 5cm}"; + disableLinks=TRUE; +} + +void LatexGenerator::endMemberDoc(bool) +{ + disableLinks=FALSE; + t << "}"; + //if (Config_getBool("COMPACT_LATEX")) t << "\\hfill"; +} + +void LatexGenerator::startDoxyAnchor(const char *fName,const char *, + const char *anchor, const char *, + const char *) +{ + static bool pdfHyperlinks = Config_getBool("PDF_HYPERLINKS"); + static bool usePDFLatex = Config_getBool("USE_PDFLATEX"); + if (usePDFLatex && pdfHyperlinks) + { + t << "\\hypertarget{"; + if (fName) t << stripPath(fName); + if (anchor) t << "_" << anchor; + t << "}{"; + } +} + +void LatexGenerator::endDoxyAnchor(const char *fName,const char *anchor) +{ + static bool pdfHyperlinks = Config_getBool("PDF_HYPERLINKS"); + static bool usePDFLatex = Config_getBool("USE_PDFLATEX"); + if (usePDFLatex && pdfHyperlinks) + { + t << "}"; + } + t << "\\label{"; + if (fName) t << fName; + if (anchor) t << "_" << anchor; + t << "}" << endl; +} + +void LatexGenerator::writeAnchor(const char *fName,const char *name) +{ + //printf("LatexGenerator::writeAnchor(%s,%s)\n",fName,name); + t << "\\label{" << name << "}" << endl; + static bool pdfHyperlinks = Config_getBool("PDF_HYPERLINKS"); + static bool usePDFLatex = Config_getBool("USE_PDFLATEX"); + if (usePDFLatex && pdfHyperlinks) + { + if (fName) + { + t << "\\hypertarget{" << stripPath(fName) << "_" << name << "}{}" << endl; + } + else + { + t << "\\hypertarget{" << name << "}{}" << endl; + } + } +} + + +//void LatexGenerator::writeLatexLabel(const char *clName,const char *anchor) +//{ +// writeDoxyAnchor(0,clName,anchor,0); +//} + +void LatexGenerator::addIndexItem(const char *s1,const char *s2) +{ + if (s1) + { + t << "\\index{"; + escapeLabelName(s1); + t << "@{"; + escapeMakeIndexChars(s1); + t << "}"; + if (s2) + { + t << "!"; + escapeLabelName(s2); + t << "@{"; + escapeMakeIndexChars(s2); + t << "}"; + } + t << "}"; + } +} + + +void LatexGenerator::startSection(const char *lab,const char *,SectionInfo::SectionType type) +{ + static bool pdfHyperlinks = Config_getBool("PDF_HYPERLINKS"); + static bool usePDFLatex = Config_getBool("USE_PDFLATEX"); + if (usePDFLatex && pdfHyperlinks) + { + t << "\\hypertarget{" << stripPath(lab) << "}{}"; + } + t << "\\"; + if (Config_getBool("COMPACT_LATEX")) + { + switch(type) + { + case SectionInfo::Page: t << "subsection"; break; + case SectionInfo::Section: t << "subsubsection"; break; + case SectionInfo::Subsection: t << "paragraph"; break; + case SectionInfo::Subsubsection: t << "subparagraph"; break; + case SectionInfo::Paragraph: t << "subparagraph"; break; + default: ASSERT(0); break; + } + t << "{"; + } + else + { + switch(type) + { + case SectionInfo::Page: t << "section"; break; + case SectionInfo::Section: t << "subsection"; break; + case SectionInfo::Subsection: t << "subsubsection"; break; + case SectionInfo::Subsubsection: t << "paragraph"; break; + case SectionInfo::Paragraph: t << "subparagraph"; break; + default: ASSERT(0); break; + } + t << "{"; + } +} + +void LatexGenerator::endSection(const char *lab,SectionInfo::SectionType) +{ + t << "}\\label{" << lab << "}" << endl; +} + + +void LatexGenerator::docify(const char *str) +{ + filterLatexString(t,str,insideTabbing,FALSE,FALSE); +} + +void LatexGenerator::codify(const char *str) +{ + if (str) + { + const char *p=str; + char c; + //char cs[5]; + int spacesToNextTabStop; + static int tabSize = Config_getInt("TAB_SIZE"); + const int maxLineLen = 80; + QCString result(4*maxLineLen+1); // worst case for 1 line of 4-byte chars + int i; + while ((c=*p)) + { + switch(c) + { + case 0x0c: p++; // remove ^L + break; + case '\t': spacesToNextTabStop = + tabSize - (col%tabSize); + t << Doxygen::spaces.left(spacesToNextTabStop); + col+=spacesToNextTabStop; + p++; + break; + case '\n': t << '\n'; col=0; p++; + break; + default: + i=0; + +#undef COPYCHAR +// helper macro to copy a single utf8 character, dealing with multibyte chars. +#define COPYCHAR() do { \ + result[i++]=c; p++; \ + if (c<0) /* multibyte utf-8 character */ \ + { \ + /* 1xxx.xxxx: >=2 byte character */ \ + result[i++]=*p++; \ + if (((uchar)c&0xE0)==0xE0) \ + { \ + /* 111x.xxxx: >=3 byte character */ \ + result[i++]=*p++; \ + } \ + if (((uchar)c&0xF0)==0xF0) \ + { \ + /* 1111.xxxx: 4 byte character */ \ + result[i++]=*p++; \ + } \ + } \ + col++; \ + } while(0) + + // gather characters until we find whitespace or are at + // the end of a line + COPYCHAR(); + if (col>=maxLineLen) // force line break + { + t << "\n "; + col=0; + } + else // copy more characters + { + while (col=maxLineLen) // force line break + { + t << "\n "; + col=0; + } + } + result[i]=0; // add terminator + if (m_prettyCode) + { + filterLatexString(t,result,insideTabbing,TRUE); + } + else + { + t << result; + } + break; + } + } + } +} + +void LatexGenerator::writeChar(char c) +{ + char cs[2]; + cs[0]=c; + cs[1]=0; + docify(cs); +} + +void LatexGenerator::startClassDiagram() +{ + //if (Config_getBool("COMPACT_LATEX")) t << "\\subsubsection"; else t << "\\subsection"; + //t << "{"; +} + +void LatexGenerator::endClassDiagram(const ClassDiagram &d, + const char *fileName,const char *) +{ + d.writeFigure(t,dir,fileName); +} + + +void LatexGenerator::startAnonTypeScope(int indent) +{ + if (indent==0) + { + t << "\\begin{tabbing}" << endl; + t << "xx\\=xx\\=xx\\=xx\\=xx\\=xx\\=xx\\=xx\\=xx\\=\\kill" << endl; + insideTabbing=TRUE; + } + m_indent=indent; +} + +void LatexGenerator::endAnonTypeScope(int indent) +{ + if (indent==0) + { + t << endl << "\\end{tabbing}"; + insideTabbing=FALSE; + } + m_indent=indent; +} + +void LatexGenerator::startMemberTemplateParams() +{ + if (templateMemberItem) + { + t << "{\\footnotesize "; + } +} + +void LatexGenerator::endMemberTemplateParams(const char *) +{ + if (templateMemberItem) + { + t << "}\\\\"; + } +} + +void LatexGenerator::startMemberItem(const char *,int annoType) +{ + //printf("LatexGenerator::startMemberItem(%d)\n",annType); + if (!insideTabbing) + { + t << "\\item " << endl; + templateMemberItem = (annoType == 3); + } +} + +void LatexGenerator::endMemberItem() +{ + if (insideTabbing) + { + t << "\\\\"; + } + templateMemberItem = FALSE; + t << endl; +} + +void LatexGenerator::startMemberDescription(const char *) +{ + if (!insideTabbing) + { + t << "\\begin{DoxyCompactList}\\small\\item\\em "; + } + else + { + for (int i=0;i"; + t << "{\\em "; + } +} + +void LatexGenerator::endMemberDescription() +{ + if (!insideTabbing) + { + //t << "\\item\\end{DoxyCompactList}"; + t << "\\end{DoxyCompactList}"; + } + else + { + t << "}\\\\\n"; + } +} + + +void LatexGenerator::writeNonBreakableSpace(int) +{ + //printf("writeNonBreakbleSpace()\n"); + if (insideTabbing) + { + t << "\\>"; + } + else + { + t << "~"; + } +} + +void LatexGenerator::startMemberList() +{ + if (!insideTabbing) + { + t << "\\begin{DoxyCompactItemize}" << endl; + } +} + +void LatexGenerator::endMemberList() +{ + //printf("LatexGenerator::endMemberList(%d)\n",insideTabbing); + if (!insideTabbing) + { + t << "\\end{DoxyCompactItemize}" << endl; + } +} + + +void LatexGenerator::startMemberGroupHeader(bool hasHeader) +{ + if (hasHeader) t << "\\begin{Indent}"; + t << "{\\bf "; + // changed back to rev 756 due to bug 660501 + //if (Config_getBool("COMPACT_LATEX")) + //{ + // t << "\\subparagraph*{"; + //} + //else + //{ + // t << "\\paragraph*{"; + //} +} + +void LatexGenerator::endMemberGroupHeader() +{ + // changed back to rev 756 due to bug 660501 + t << "}\\par" << endl; + //t << "}" << endl; +} + +void LatexGenerator::startMemberGroupDocs() +{ + t << "{\\em "; +} + +void LatexGenerator::endMemberGroupDocs() +{ + t << "}"; +} + +void LatexGenerator::startMemberGroup() +{ +} + +void LatexGenerator::endMemberGroup(bool hasHeader) +{ + if (hasHeader)t << "\\end{Indent}"; + t << endl; +} + +void LatexGenerator::startDotGraph() +{ + newParagraph(); +} + +void LatexGenerator::endDotGraph(const DotClassGraph &g) +{ + g.writeGraph(t,EPS,Config_getString("LATEX_OUTPUT"),fileName,relPath); +} + +void LatexGenerator::startInclDepGraph() +{ +} + +void LatexGenerator::endInclDepGraph(const DotInclDepGraph &g) +{ + g.writeGraph(t,EPS,Config_getString("LATEX_OUTPUT"),fileName,relPath); +} + +void LatexGenerator::startGroupCollaboration() +{ +} + +void LatexGenerator::endGroupCollaboration(const DotGroupCollaboration &g) +{ + g.writeGraph(t,EPS,Config_getString("LATEX_OUTPUT"),fileName,relPath); +} + +void LatexGenerator::startCallGraph() +{ +} + +void LatexGenerator::endCallGraph(const DotCallGraph &g) +{ + g.writeGraph(t,EPS,Config_getString("LATEX_OUTPUT"),fileName,relPath); +} + +void LatexGenerator::startDirDepGraph() +{ +} + +void LatexGenerator::endDirDepGraph(const DotDirDeps &g) +{ + g.writeGraph(t,EPS,Config_getString("LATEX_OUTPUT"),fileName,relPath); +} + +void LatexGenerator::startDescription() +{ + t << "\\begin{description}" << endl; +} + +void LatexGenerator::endDescription() +{ + t << "\\end{description}" << endl; + firstDescItem=TRUE; +} + +void LatexGenerator::startDescItem() +{ + firstDescItem=TRUE; + t << "\\item["; +} + +void LatexGenerator::endDescItem() +{ + if (firstDescItem) + { + t << "]" << endl; + firstDescItem=FALSE; + } + else + { + lineBreak(); + } +} + +void LatexGenerator::startSimpleSect(SectionTypes,const char *file, + const char *anchor,const char *title) +{ + t << "\\begin{Desc}\n\\item["; + if (file) + { + writeObjectLink(0,file,anchor,title); + } + else + { + docify(title); + } + t << "]"; +} + +void LatexGenerator::endSimpleSect() +{ + t << "\\end{Desc}" << endl; +} + +void LatexGenerator::startParamList(ParamListTypes,const char *title) +{ + t << "\\begin{Desc}\n\\item["; + docify(title); + t << "]"; +} + +void LatexGenerator::endParamList() +{ + t << "\\end{Desc}" << endl; +} + +void LatexGenerator::startParameterList(bool openBracket) +{ + /* start of ParameterType ParameterName list */ + if (openBracket) t << "("; + t << endl << "\\begin{DoxyParamCaption}" << endl; +} + +void LatexGenerator::endParameterList() +{ +} + +void LatexGenerator::startParameterType(bool first,const char *key) +{ + t << "\\item[{"; + if (!first && key) t << key; +} + +void LatexGenerator::endParameterType() +{ + t << "}]"; +} + +void LatexGenerator::startParameterName(bool /*oneArgOnly*/) +{ + t << "{"; +} + +void LatexGenerator::endParameterName(bool last,bool /* emptyList */,bool closeBracket) +{ + t << "}" << endl; + + if (last) + { + t << "\\end{DoxyParamCaption}" << endl; + if (closeBracket) t << ")"; + } +} + + +void LatexGenerator::printDoc(DocNode *n,const char *langExt) +{ + LatexDocVisitor *visitor = new LatexDocVisitor(t,*this,langExt,insideTabbing); + n->accept(visitor); + delete visitor; +} + +void LatexGenerator::startConstraintList(const char *header) +{ + t << "\\begin{Desc}\n\\item["; + docify(header); + t << "]"; + t << "\\begin{description}" << endl; +} + +void LatexGenerator::startConstraintParam() +{ + t << "\\item[{\\em "; +} + +void LatexGenerator::endConstraintParam() +{ +} + +void LatexGenerator::startConstraintType() +{ + t << "} : {\\em "; +} + +void LatexGenerator::endConstraintType() +{ + t << "}]"; +} + +void LatexGenerator::startConstraintDocs() +{ +} + +void LatexGenerator::endConstraintDocs() +{ +} + +void LatexGenerator::endConstraintList() +{ + t << "\\end{description}" << endl; + t << "\\end{Desc}" << endl; +} + +void LatexGenerator::escapeLabelName(const char *s) +{ + if (s==0) return; + const char *p=s; + char c; + QCString result(strlen(s)+1); // worst case allocation + int i; + while ((c=*p++)) + { + switch (c) + { + case '%': t << "\\%"; break; + // NOTE: adding a case here, means adding it to while below as well! + default: + i=0; + // collect as long string as possible, before handing it to docify + result[i++]=c; + while ((c=*p) && c!='%') + { + result[i++]=c; + p++; + } + result[i]=0; + docify(result); + break; + } + } +} + +void LatexGenerator::escapeMakeIndexChars(const char *s) +{ + if (s==0) return; + const char *p=s; + char c; + QCString result(strlen(s)+1); // worst case allocation + int i; + while ((c=*p++)) + { + switch (c) + { + case '"': t << "\"\""; break; + case '@': t << "\"@"; break; + case '[': t << "["; break; + case ']': t << "]"; break; + // NOTE: adding a case here, means adding it to while below as well! + default: + i=0; + // collect as long string as possible, before handing it to docify + result[i++]=c; + while ((c=*p) && c!='"' && c!='@' && c!='[' && c!=']') + { + result[i++]=c; + p++; + } + result[i]=0; + docify(result); + break; + } + } +} + +void LatexGenerator::startCodeFragment() +{ + t << "\n\\begin{DoxyCode}\n"; +} + +void LatexGenerator::endCodeFragment() +{ + t << "\\end{DoxyCode}\n"; +} + +void LatexGenerator::writeLineNumber(const char *ref,const char *fileName,const char *anchor,int l) +{ + if (m_prettyCode) + { + QCString lineNumber; + lineNumber.sprintf("%05d",l); + + if (fileName && !sourceFileName.isEmpty()) + { + QCString lineAnchor; + lineAnchor.sprintf("_l%05d",l); + lineAnchor.prepend(sourceFileName); + startCodeAnchor(lineAnchor); + writeCodeLink(ref,fileName,anchor,lineNumber,0); + endCodeAnchor(); + } + else + { + codify(lineNumber); + } + t << " "; + } + else + { + t << l << " "; + } +} + +void LatexGenerator::startCodeLine() +{ + col=0; +} + +void LatexGenerator::endCodeLine() +{ + codify("\n"); +} + +void LatexGenerator::startFontClass(const char *name) +{ + if (!m_prettyCode) return; + t << "\\textcolor{" << name << "}{"; +} + +void LatexGenerator::endFontClass() +{ + if (!m_prettyCode) return; + t << "}"; +} + +void LatexGenerator::startCodeAnchor(const char *name) +{ + static bool usePDFLatex = Config_getBool("USE_PDFLATEX"); + static bool pdfHyperlinks = Config_getBool("PDF_HYPERLINKS"); + if (!m_prettyCode) return; + if (usePDFLatex && pdfHyperlinks) + { + t << "\\hypertarget{" << stripPath(name) << "}{}"; + } +} + +void LatexGenerator::endCodeAnchor() +{ +} + +void LatexGenerator::startInlineHeader() +{ + if (Config_getBool("COMPACT_LATEX")) + { + t << "\\paragraph*{"; + } + else + { + t << "\\subsubsection*{"; + } +} + +void LatexGenerator::endInlineHeader() +{ + t << "}" << endl; +} + +void LatexGenerator::lineBreak(const char *) +{ + if (insideTabbing) + { + t << "\\\\\n"; + } + else + { + t << "\\\\*\n"; + } +} + +void LatexGenerator::startMemberDocSimple() +{ + t << "\\begin{DoxyFields}{"; + docify(theTranslator->trCompoundMembers()); + t << "}" << endl; +} + +void LatexGenerator::endMemberDocSimple() +{ + t << "\\end{DoxyFields}" << endl; +} + +void LatexGenerator::startInlineMemberType() +{ +} + +void LatexGenerator::endInlineMemberType() +{ + t << "&" << endl; +} + +void LatexGenerator::startInlineMemberName() +{ +} + +void LatexGenerator::endInlineMemberName() +{ + t << "&" << endl; +} + +void LatexGenerator::startInlineMemberDoc() +{ +} + +void LatexGenerator::endInlineMemberDoc() +{ + t << "\\\\\n\\hline\n" << endl; +} + diff --git a/trunk/src/latexgen.h b/trunk/src/latexgen.h new file mode 100644 index 0000000..36246fd --- /dev/null +++ b/trunk/src/latexgen.h @@ -0,0 +1,272 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#ifndef LATEXGEN_H +#define LATEXGEN_H + +#include "outputgen.h" + +class QFile; + +class LatexGenerator : public OutputGenerator +{ + public: + LatexGenerator(); + ~LatexGenerator(); + static void init(); + static void writeStyleSheetFile(QFile &f); + static void writeHeaderFile(QFile &f); + static void writeFooterFile(QFile &f); + + //OutputGenerator *copy(); + //OutputGenerator *clone() { return new LatexGenerator(*this); } + //void append(const OutputGenerator *o); + void enable() + { if (genStack->top()) active=*genStack->top(); else active=TRUE; } + void disable() { active=FALSE; } + void enableIf(OutputType o) { if (o==Latex) enable(); } + void disableIf(OutputType o) { if (o==Latex) disable(); } + void disableIfNot(OutputType o) { if (o!=Latex) disable(); } + bool isEnabled(OutputType o) { return (o==Latex && active); } + OutputGenerator *get(OutputType o) { return (o==Latex) ? this : 0; } + + void printDoc(DocNode *,const char *); + + void startFile(const char *name,const char *manName,const char *title); + void writeSearchInfo() {} + void writeFooter() {} + void endFile(); + void clearBuffer(); + + void startIndexSection(IndexSections); + void endIndexSection(IndexSections); + void writePageLink(const char *,bool); + void startProjectNumber(); + void endProjectNumber() {} + void writeStyleInfo(int part); + void startTitleHead(const char *); + void startTitle(); + void endTitleHead(const char *,const char *name); + void endTitle() { t << "}"; } + + void newParagraph(); + void startParagraph(); + void endParagraph(); + void writeString(const char *text); + void startIndexListItem() {} + void endIndexListItem() {} + void startIndexList() { t << "\\begin{DoxyCompactList}" << endl; } + void endIndexList() { t << "\\end{DoxyCompactList}" << endl; } + void startIndexKey(); + void endIndexKey(); + void startIndexValue(bool); + void endIndexValue(const char *,bool); + void startItemList() { t << "\\begin{DoxyCompactItemize}" << endl; } + void endItemList() { t << "\\end{DoxyCompactItemize}" << endl; } + void startIndexItem(const char *ref,const char *file); + void endIndexItem(const char *ref,const char *file); + void docify(const char *text); + void codify(const char *text); + void writeObjectLink(const char *ref,const char *file, + const char *anchor,const char *name); + void writeCodeLink(const char *ref, const char *file, + const char *anchor,const char *name, + const char *tooltip); + void startTextLink(const char *,const char *); + void endTextLink(); + void startHtmlLink(const char *url); + void endHtmlLink(); + void startTypewriter() { t << "{\\ttfamily "; } + void endTypewriter() { t << "}"; } + void startGroupHeader(int); + void endGroupHeader(int); + void startItemListItem() { t << "\\item " << endl; } + void endItemListItem() {} + + void startMemberSections() {} + void endMemberSections() {} + void startHeaderSection() {} + void endHeaderSection() {} + void startMemberHeader(const char *); + void endMemberHeader(); + void startMemberSubtitle() {} + void endMemberSubtitle() {} + void startMemberDocList() {} + void endMemberDocList() {} + void startMemberList(); + void endMemberList(); + void startInlineHeader(); + void endInlineHeader(); + void startAnonTypeScope(int); + void endAnonTypeScope(int); + void startMemberItem(const char *,int); + void endMemberItem(); + void startMemberTemplateParams(); + void endMemberTemplateParams(const char *); + + void startMemberGroupHeader(bool); + void endMemberGroupHeader(); + void startMemberGroupDocs(); + void endMemberGroupDocs(); + void startMemberGroup(); + void endMemberGroup(bool); + + void insertMemberAlign(bool) {} + + void writeRuler() { t << endl << endl; } + void writeAnchor(const char *fileName,const char *name); + void startCodeFragment(); + void endCodeFragment(); + void writeLineNumber(const char *,const char *,const char *,int l); + void startCodeLine(); + void endCodeLine(); + void startEmphasis() { t << "{\\em "; } + void endEmphasis() { t << "}"; } + void startBold() { t << "{\\bfseries "; } + void endBold() { t << "}"; } + void startDescription(); + void endDescription(); + void startDescItem(); + void endDescItem(); + void lineBreak(const char *style=0); + void startMemberDoc(const char *,const char *,const char *,const char *,bool); + void endMemberDoc(bool); + void startDoxyAnchor(const char *,const char *,const char *,const char *,const char *); + void endDoxyAnchor(const char *,const char *); + void startCodeAnchor(const char *); + void endCodeAnchor(); + void writeChar(char c); + void writeLatexSpacing() { t << "\\hspace{0.3cm}"; } + void writeStartAnnoItem(const char *type,const char *file, + const char *path,const char *name); + void writeEndAnnoItem(const char *name); + void startSubsection() { t << "\\subsection*{"; } + void endSubsection() { t << "}" << endl; } + void startSubsubsection() { t << "\\subsubsection*{"; } + void endSubsubsection() { t << "}" << endl; } + void startCenter() { t << "\\begin{center}" << endl; } + void endCenter() { t << "\\end{center}" << endl; } + void startSmall() { t << "\\footnotesize "; } + void endSmall() { t << "\\normalsize "; } + void startMemberDescription(const char *); + void endMemberDescription(); + void startDescList(SectionTypes) { t << "\\begin{Desc}\n\\item["; } + void endDescList() { t << "\\end{Desc}" << endl; } + void startSimpleSect(SectionTypes,const char *,const char *,const char *); + void endSimpleSect(); + void startParamList(ParamListTypes,const char *title); + void endParamList(); + void startDescForItem() { t << "\\par" << endl; } + void endDescForItem() {} + void startSection(const char *,const char *,SectionInfo::SectionType); + void endSection(const char *,SectionInfo::SectionType); + void addIndexItem(const char *,const char *); + void startIndent() {} + void endIndent() {} + void writeSynopsis() {} + void startClassDiagram(); + void endClassDiagram(const ClassDiagram &,const char *,const char *); + void startPageRef(); + void endPageRef(const char *,const char *); + void startQuickIndices() {} + void endQuickIndices() {} + void writeSplitBar(const char *) {} + void writeLogo() {} + void writeQuickLinks(bool,HighlightedItem,const char*) {} + void startContents() {} + void endContents() {} + void writeNonBreakableSpace(int); + + void startDescTable() + { t << "\\begin{description}" << endl; } + void endDescTable() + { t << "\\end{description}" << endl; } + void startDescTableTitle() + { t << "\\item[{\\em " << endl; } + void endDescTableTitle() + { t << "}]"; } + void startDescTableData() {} + void endDescTableData() {} + void lastIndexPage() {} + + void startDotGraph(); + void endDotGraph(const DotClassGraph &); + void startInclDepGraph(); + void endInclDepGraph(const DotInclDepGraph &); + void startCallGraph(); + void startGroupCollaboration(); + void endGroupCollaboration(const DotGroupCollaboration &g); + void endCallGraph(const DotCallGraph &); + void startDirDepGraph(); + void endDirDepGraph(const DotDirDeps &g); + void writeGraphicalHierarchy(const DotGfxHierarchyTable &) {} + + void startTextBlock(bool) {} + void endTextBlock(bool) {} + + void startMemberDocPrefixItem() {} + void endMemberDocPrefixItem() {} + void startMemberDocName(bool) {} + void endMemberDocName() {} + void startParameterType(bool,const char *); + void endParameterType(); + void startParameterName(bool); + void endParameterName(bool,bool,bool); + void startParameterList(bool); + void endParameterList(); + + void startConstraintList(const char *); + void startConstraintParam(); + void endConstraintParam(); + void startConstraintType(); + void endConstraintType(); + void startConstraintDocs(); + void endConstraintDocs(); + void endConstraintList(); + + void startMemberDocSimple(); + void endMemberDocSimple(); + void startInlineMemberType(); + void endInlineMemberType(); + void startInlineMemberName(); + void endInlineMemberName(); + void startInlineMemberDoc(); + void endInlineMemberDoc(); + + void startFontClass(const char *); // {} + void endFontClass(); // {} + + void writeCodeAnchor(const char *) {} + void linkableSymbol(int,const char *,Definition *,Definition *) {} + + private: + LatexGenerator(const LatexGenerator &); + LatexGenerator &operator=(const LatexGenerator &); + void escapeLabelName(const char *s); + void escapeMakeIndexChars(const char *s); + int col; + bool insideTabbing; + bool firstDescItem; + bool disableLinks; + QCString relPath; + QCString sourceFileName; + int m_indent; + bool templateMemberItem; + bool m_prettyCode; +}; + +#endif diff --git a/trunk/src/layout.cpp b/trunk/src/layout.cpp new file mode 100644 index 0000000..b4a94f2 --- /dev/null +++ b/trunk/src/layout.cpp @@ -0,0 +1,1328 @@ +/****************************************************************************** + * + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#include "layout.h" +#include "message.h" +#include "language.h" +#include "vhdldocgen.h" +#include "util.h" +#include "doxygen.h" + +#include +#include +#include +#include +#include + +static const char layout_default[] = +#include "layout_default.h" +; + +static bool elemIsVisible(const QXmlAttributes &attrib,bool defVal=TRUE) +{ + QCString visible = convertToQCString(attrib.value("visible")); + if (visible.isEmpty()) return defVal; + if (visible.at(0)=='$' && visible.length()>1) + { + QCString id = visible.mid(1); + ConfigOption *opt = Config::instance()->get(id); + if (opt && opt->kind()==ConfigOption::O_Bool) + { + return *((ConfigBool *)opt)->valueRef(); + } + else if (!opt) + { + err("error: found unsupported value %s for visible attribute in layout file\n", + visible.data()); + } + } + return visible!="no" && visible!="0"; +} + +//--------------------------------------------------------------------------------- + +LayoutNavEntry *LayoutNavEntry::find(LayoutNavEntry::Kind kind, + const char *file) const +{ + LayoutNavEntry *result=0; + QListIterator li(m_children); + LayoutNavEntry *entry; + for (li.toFirst();(entry=li.current());++li) + { + // depth first search, needed to find the entry furthest from the + // root in case an entry is in the tree twice + result = entry->find(kind,file); + if (result) return result; + if (entry->kind()==kind && (file==0 || entry->baseFile()==file)) + { + return entry; + } + } + return result; +} + +QCString LayoutNavEntry::url() const +{ + QCString url = baseFile().stripWhiteSpace(); + if (kind()!=LayoutNavEntry::User) + { + url+=Doxygen::htmlFileExtension; + } + else if (url.left(5)=="@ref " || url.left(5)=="\\ref ") + { + Definition *d; + QCString anchor; + bool found=FALSE; + if (resolveLink(0,url.mid(5).stripWhiteSpace(),TRUE,&d,anchor)) + { + if (d && d->isLinkable()) + { + url=d->getOutputFileBase()+Doxygen::htmlFileExtension; + if (!anchor.isEmpty()) + { + url+="#"+anchor; + } + found=TRUE; + } + } + if (!found) + { + msg("warning: explicit link request to '%s' in layout file '%s' could not be resolved\n",qPrint(url.mid(5)),qPrint(Config_getString("LAYOUT_FILE"))); + } + } + //printf("LayoutNavEntry::url()=%s\n",url.data()); + return url; +} + +//--------------------------------------------------------------------------------- + +class LayoutParser : public QXmlDefaultHandler +{ + private: + class StartElementHandler + { + typedef void (LayoutParser::*Handler)(const QXmlAttributes &attrib); + public: + StartElementHandler(LayoutParser *parent, Handler h) + : m_parent(parent), m_handler(h) {} + virtual ~StartElementHandler() {} + virtual void operator()(const QXmlAttributes &attrib) + { + (m_parent->*m_handler)(attrib); + } + protected: + StartElementHandler() : m_parent(0), m_handler(0) {} + private: + LayoutParser *m_parent; + Handler m_handler; + }; + + class StartElementHandlerKind : public StartElementHandler + { + typedef void (LayoutParser::*Handler)(LayoutDocEntry::Kind kind, + const QXmlAttributes &attrib); + public: + StartElementHandlerKind(LayoutParser *parent, LayoutDocEntry::Kind k,Handler h) + : m_parent(parent), m_kind(k), m_handler(h) {} + void operator()(const QXmlAttributes &attrib) + { + (m_parent->*m_handler)(m_kind,attrib); + } + private: + LayoutParser *m_parent; + LayoutDocEntry::Kind m_kind; + Handler m_handler; + }; + + class StartElementHandlerSection : public StartElementHandler + { + typedef void (LayoutParser::*Handler)(LayoutDocEntry::Kind kind, + const QXmlAttributes &attrib, + const QCString &title); + public: + StartElementHandlerSection(LayoutParser *parent, LayoutDocEntry::Kind k,Handler h, + const QCString &title) + : m_parent(parent), m_kind(k), m_handler(h), m_title(title) {} + void operator()(const QXmlAttributes &attrib) + { + (m_parent->*m_handler)(m_kind,attrib,m_title); + } + private: + LayoutParser *m_parent; + LayoutDocEntry::Kind m_kind; + Handler m_handler; + QCString m_title; + }; + + class StartElementHandlerMember : public StartElementHandler + { + typedef void (LayoutParser::*Handler)(const QXmlAttributes &attrib, + MemberList::ListType type, + const QCString &title, + const QCString &subtitle); + public: + StartElementHandlerMember(LayoutParser *parent, + Handler h, + MemberList::ListType type, + const QCString &tl, + const QCString &ss = QCString() + ) + : m_parent(parent), m_handler(h), m_type(type), + m_title(tl), m_subscript(ss) {} + void operator()(const QXmlAttributes &attrib) + { + (m_parent->*m_handler)(attrib,m_type,m_title,m_subscript); + } + private: + LayoutParser *m_parent; + Handler m_handler; + MemberList::ListType m_type; + QCString m_title; + QCString m_subscript; + }; + + class StartElementHandlerNavEntry : public StartElementHandler + { + typedef void (LayoutParser::*Handler)(LayoutNavEntry::Kind kind, + const QXmlAttributes &attrib, + const QCString &title); + public: + StartElementHandlerNavEntry(LayoutParser *parent, + LayoutNavEntry::Kind kind, + Handler h, + const QCString &tl + ) + : m_parent(parent), m_kind(kind), m_handler(h), m_title(tl) {} + void operator()(const QXmlAttributes &attrib) + { + (m_parent->*m_handler)(m_kind,attrib,m_title); + } + private: + LayoutParser *m_parent; + LayoutNavEntry::Kind m_kind; + Handler m_handler; + QCString m_title; + }; + + class EndElementHandler + { + typedef void (LayoutParser::*Handler)(); + public: + EndElementHandler(LayoutParser *parent, Handler h) : m_parent(parent), m_handler(h) {} + void operator()() { (m_parent->*m_handler)(); } + private: + LayoutParser *m_parent; + Handler m_handler; + }; + + + public: + static LayoutParser &instance() + { + static LayoutParser *theInstance = new LayoutParser; + return *theInstance; + } + void init() + { + m_sHandler.setAutoDelete(TRUE); + m_eHandler.setAutoDelete(TRUE); + m_part = -1; // invalid + m_rootNav = 0; + + bool fortranOpt = Config_getBool("OPTIMIZE_FOR_FORTRAN"); + bool vhdlOpt = Config_getBool("OPTIMIZE_OUTPUT_VHDL"); + bool javaOpt = Config_getBool("OPTIMIZE_OUTPUT_JAVA"); + + // start & end handlers + m_sHandler.insert("doxygenlayout", + new StartElementHandler(this,&LayoutParser::startLayout)); + m_eHandler.insert("doxygenlayout", + new EndElementHandler(this,&LayoutParser::endLayout)); + + // class layout handlers + m_sHandler.insert("navindex", + new StartElementHandler(this,&LayoutParser::startNavIndex)); + m_sHandler.insert("navindex/tab", + new StartElementHandler(this,&LayoutParser::startNavEntry)); + m_eHandler.insert("navindex/tab", + new EndElementHandler(this,&LayoutParser::endNavEntry)); + m_eHandler.insert("navindex", + new EndElementHandler(this,&LayoutParser::endNavIndex)); + + // class layout handlers + m_sHandler.insert("class", + new StartElementHandler(this,&LayoutParser::startClass)); + m_sHandler.insert("class/briefdescription", + new StartElementHandlerKind(this,LayoutDocEntry::BriefDesc,&LayoutParser::startSimpleEntry)); + m_sHandler.insert("class/detaileddescription", + new StartElementHandlerSection(this,LayoutDocEntry::DetailedDesc,&LayoutParser::startSectionEntry, + theTranslator->trDetailedDescription())); + m_sHandler.insert("class/authorsection", + new StartElementHandlerKind(this,LayoutDocEntry::AuthorSection,&LayoutParser::startSimpleEntry)); + m_sHandler.insert("class/includes", + new StartElementHandlerKind(this,LayoutDocEntry::ClassIncludes,&LayoutParser::startSimpleEntry)); + m_sHandler.insert("class/inheritancegraph", + new StartElementHandlerKind(this,LayoutDocEntry::ClassInheritanceGraph,&LayoutParser::startSimpleEntry)); + m_sHandler.insert("class/collaborationgraph", + new StartElementHandlerKind(this,LayoutDocEntry::ClassCollaborationGraph,&LayoutParser::startSimpleEntry)); + m_sHandler.insert("class/allmemberslink", + new StartElementHandlerKind(this,LayoutDocEntry::ClassAllMembersLink,&LayoutParser::startSimpleEntry)); + m_sHandler.insert("class/usedfiles", + new StartElementHandlerKind(this,LayoutDocEntry::ClassUsedFiles,&LayoutParser::startSimpleEntry)); + m_sHandler.insert("class/memberdecl", + new StartElementHandler(this,&LayoutParser::startMemberDecl)); + m_sHandler.insert("class/memberdecl/membergroups", + new StartElementHandlerKind(this,LayoutDocEntry::MemberGroups,&LayoutParser::startSimpleEntry)); + m_sHandler.insert("class/memberdecl/nestedclasses", + new StartElementHandlerSection(this,LayoutDocEntry::ClassNestedClasses,&LayoutParser::startSectionEntry, + vhdlOpt ? VhdlDocGen::trVhdlType(VhdlDocGen::ENTITY,FALSE) : + fortranOpt ? theTranslator->trDataTypes() : + theTranslator->trCompounds() + )); + m_sHandler.insert("class/memberdecl/publictypes", + new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, + MemberList::pubTypes,theTranslator->trPublicTypes())); + m_sHandler.insert("class/memberdecl/publicslots", + new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, + MemberList::pubSlots,theTranslator->trPublicSlots())); + m_sHandler.insert("class/memberdecl/signals", + new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, + MemberList::signals,theTranslator->trSignals())); + m_sHandler.insert("class/memberdecl/publicmethods", + new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, + MemberList::pubMethods,theTranslator->trPublicMembers())); + m_sHandler.insert("class/memberdecl/publicstaticmethods", + new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, + MemberList::pubStaticMethods,theTranslator->trStaticPublicMembers())); + m_sHandler.insert("class/memberdecl/publicattributes", + new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, + MemberList::pubAttribs,theTranslator->trPublicAttribs())); + m_sHandler.insert("class/memberdecl/publicstaticattributes", + new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, + MemberList::pubStaticAttribs,theTranslator->trStaticPublicAttribs())); + m_sHandler.insert("class/memberdecl/protectedtypes", + new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, + MemberList::proTypes,theTranslator->trProtectedTypes())); + m_sHandler.insert("class/memberdecl/protectedslots", + new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, + MemberList::proSlots,theTranslator->trProtectedSlots())); + m_sHandler.insert("class/memberdecl/protectedmethods", + new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, + MemberList::proMethods,theTranslator->trProtectedMembers())); + m_sHandler.insert("class/memberdecl/protectedstaticmethods", + new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, + MemberList::proStaticMethods,theTranslator->trStaticProtectedMembers())); + m_sHandler.insert("class/memberdecl/protectedattributes", + new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, + MemberList::proAttribs,theTranslator->trProtectedAttribs())); + m_sHandler.insert("class/memberdecl/protectedstaticattributes", + new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, + MemberList::proStaticAttribs,theTranslator->trStaticProtectedAttribs())); + m_sHandler.insert("class/memberdecl/packagetypes", + new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, + MemberList::pacTypes,theTranslator->trPackageTypes())); + m_sHandler.insert("class/memberdecl/packagemethods", + new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, + MemberList::pacMethods,theTranslator->trPackageMembers())); + m_sHandler.insert("class/memberdecl/packagestaticmethods", + new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, + MemberList::pacStaticMethods,theTranslator->trStaticPackageMembers())); + m_sHandler.insert("class/memberdecl/packageattributes", + new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, + MemberList::pacAttribs,theTranslator->trPackageAttribs())); + m_sHandler.insert("class/memberdecl/packagestaticattributes", + new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, + MemberList::pacStaticAttribs,theTranslator->trStaticPackageAttribs())); + m_sHandler.insert("class/memberdecl/properties", + new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, + MemberList::properties,theTranslator->trProperties())); + m_sHandler.insert("class/memberdecl/events", + new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, + MemberList::events,theTranslator->trEvents())); + m_sHandler.insert("class/memberdecl/privatetypes", + new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, + MemberList::priTypes,theTranslator->trPrivateTypes())); + m_sHandler.insert("class/memberdecl/privateslots", + new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, + MemberList::priSlots,theTranslator->trPrivateSlots())); + m_sHandler.insert("class/memberdecl/privatemethods", + new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, + MemberList::priMethods,theTranslator->trPrivateMembers())); + m_sHandler.insert("class/memberdecl/privatestaticmethods", + new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, + MemberList::priStaticMethods,theTranslator->trStaticPrivateMembers())); + m_sHandler.insert("class/memberdecl/privateattributes", + new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, + MemberList::priAttribs,theTranslator->trPrivateAttribs())); + m_sHandler.insert("class/memberdecl/privatestaticattributes", + new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, + MemberList::priStaticAttribs,theTranslator->trStaticPrivateAttribs())); + m_sHandler.insert("class/memberdecl/friends", + new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, + MemberList::friends,theTranslator->trFriends())); + m_sHandler.insert("class/memberdecl/related", + new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, + MemberList::related,theTranslator->trRelatedFunctions(), + theTranslator->trRelatedSubscript())); + m_eHandler.insert("class/memberdecl", + new EndElementHandler(this,&LayoutParser::endMemberDecl)); + m_sHandler.insert("class/memberdef", + new StartElementHandler(this,&LayoutParser::startMemberDef)); + m_sHandler.insert("class/memberdef/inlineclasses", + new StartElementHandlerSection(this,LayoutDocEntry::ClassInlineClasses,&LayoutParser::startSectionEntry, + fortranOpt ? theTranslator->trTypeDocumentation() : + theTranslator->trClassDocumentation() + )); + m_sHandler.insert("class/memberdef/typedefs", + new StartElementHandlerMember(this,&LayoutParser::startMemberDefEntry, + MemberList::typedefMembers,theTranslator->trMemberTypedefDocumentation())); + m_sHandler.insert("class/memberdef/enums", + new StartElementHandlerMember(this,&LayoutParser::startMemberDefEntry, + MemberList::enumMembers,theTranslator->trMemberEnumerationDocumentation())); + m_sHandler.insert("class/memberdef/constructors", + new StartElementHandlerMember(this,&LayoutParser::startMemberDefEntry, + MemberList::constructors,theTranslator->trConstructorDocumentation())); + m_sHandler.insert("class/memberdef/functions", + new StartElementHandlerMember(this,&LayoutParser::startMemberDefEntry, + MemberList::functionMembers, + fortranOpt ? + theTranslator->trMemberFunctionDocumentationFortran() : + theTranslator->trMemberFunctionDocumentation())); + m_sHandler.insert("class/memberdef/related", + new StartElementHandlerMember(this,&LayoutParser::startMemberDefEntry, + MemberList::relatedMembers,theTranslator->trRelatedFunctionDocumentation())); + m_sHandler.insert("class/memberdef/variables", + new StartElementHandlerMember(this,&LayoutParser::startMemberDefEntry, + MemberList::variableMembers,theTranslator->trMemberDataDocumentation())); + m_sHandler.insert("class/memberdef/properties", + new StartElementHandlerMember(this,&LayoutParser::startMemberDefEntry, + MemberList::propertyMembers,theTranslator->trPropertyDocumentation())); + m_sHandler.insert("class/memberdef/events", + new StartElementHandlerMember(this,&LayoutParser::startMemberDefEntry, + MemberList::eventMembers,theTranslator->trEventDocumentation())); + m_eHandler.insert("class/memberdef", + new EndElementHandler(this,&LayoutParser::endMemberDef)); + m_eHandler.insert("class", + new EndElementHandler(this,&LayoutParser::endClass)); + + + // namespace layout handlers + m_sHandler.insert("namespace", + new StartElementHandler(this,&LayoutParser::startNamespace)); + m_sHandler.insert("namespace/briefdescription", + new StartElementHandlerKind(this,LayoutDocEntry::BriefDesc,&LayoutParser::startSimpleEntry)); + m_sHandler.insert("namespace/detaileddescription", + new StartElementHandlerSection(this,LayoutDocEntry::DetailedDesc,&LayoutParser::startSectionEntry, + theTranslator->trDetailedDescription())); + m_sHandler.insert("namespace/authorsection", + new StartElementHandlerKind(this,LayoutDocEntry::AuthorSection,&LayoutParser::startSimpleEntry)); + m_sHandler.insert("namespace/memberdecl", + new StartElementHandler(this,&LayoutParser::startMemberDecl)); + m_sHandler.insert("namespace/memberdecl/nestednamespaces", + new StartElementHandlerSection(this,LayoutDocEntry::NamespaceNestedNamespaces,&LayoutParser::startSectionEntry, + javaOpt || vhdlOpt ? theTranslator->trPackages() : + fortranOpt ? theTranslator->trModules() : + theTranslator->trNamespaces() + )); + m_sHandler.insert("namespace/memberdecl/classes", + new StartElementHandlerSection(this,LayoutDocEntry::NamespaceClasses,&LayoutParser::startSectionEntry, + vhdlOpt ? VhdlDocGen::trVhdlType(VhdlDocGen::ENTITY,FALSE) : + fortranOpt ? theTranslator->trDataTypes() : + theTranslator->trCompounds() + )); + m_sHandler.insert("namespace/memberdecl/membergroups", + new StartElementHandlerKind(this,LayoutDocEntry::MemberGroups,&LayoutParser::startSimpleEntry)); + m_sHandler.insert("namespace/memberdecl/typedefs", + new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, + MemberList::decTypedefMembers,theTranslator->trTypedefs())); + m_sHandler.insert("namespace/memberdecl/enums", + new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, + MemberList::decEnumMembers,theTranslator->trEnumerations())); + m_sHandler.insert("namespace/memberdecl/functions", + new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, + MemberList::decFuncMembers, + fortranOpt ? theTranslator->trSubprograms() : + vhdlOpt ? VhdlDocGen::trFunctionAndProc() : + theTranslator->trFunctions())); + m_sHandler.insert("namespace/memberdecl/variables", + new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, + MemberList::decVarMembers,theTranslator->trVariables())); + m_eHandler.insert("namespace/memberdecl", + new EndElementHandler(this,&LayoutParser::endMemberDecl)); + m_sHandler.insert("namespace/memberdef", + new StartElementHandler(this,&LayoutParser::startMemberDef)); + m_sHandler.insert("namespace/memberdef/inlineclasses", + new StartElementHandlerSection(this,LayoutDocEntry::NamespaceInlineClasses,&LayoutParser::startSectionEntry, + fortranOpt ? theTranslator->trTypeDocumentation() : + theTranslator->trClassDocumentation() + )); + m_sHandler.insert("namespace/memberdef/typedefs", + new StartElementHandlerMember(this,&LayoutParser::startMemberDefEntry, + MemberList::docTypedefMembers,theTranslator->trTypedefDocumentation())); + m_sHandler.insert("namespace/memberdef/enums", + new StartElementHandlerMember(this,&LayoutParser::startMemberDefEntry, + MemberList::docEnumMembers,theTranslator->trEnumerationTypeDocumentation())); + m_sHandler.insert("namespace/memberdef/functions", + new StartElementHandlerMember(this,&LayoutParser::startMemberDefEntry, + MemberList::docFuncMembers, + fortranOpt ? + theTranslator->trSubprogramDocumentation() : + theTranslator->trFunctionDocumentation())); + m_sHandler.insert("namespace/memberdef/variables", + new StartElementHandlerMember(this,&LayoutParser::startMemberDefEntry, + MemberList::docVarMembers,theTranslator->trVariableDocumentation())); + m_eHandler.insert("namespace/memberdef", + new EndElementHandler(this,&LayoutParser::endMemberDef)); + m_eHandler.insert("namespace", + new EndElementHandler(this,&LayoutParser::endNamespace)); + + // file layout handlers + m_sHandler.insert("file", + new StartElementHandler(this,&LayoutParser::startFile)); + m_sHandler.insert("file/briefdescription", + new StartElementHandlerKind(this,LayoutDocEntry::BriefDesc,&LayoutParser::startSimpleEntry)); + m_sHandler.insert("file/detaileddescription", + new StartElementHandlerSection(this,LayoutDocEntry::DetailedDesc,&LayoutParser::startSectionEntry, + theTranslator->trDetailedDescription())); + m_sHandler.insert("file/authorsection", + new StartElementHandlerKind(this,LayoutDocEntry::AuthorSection,&LayoutParser::startSimpleEntry)); + m_sHandler.insert("file/includes", + new StartElementHandlerKind(this,LayoutDocEntry::FileIncludes,&LayoutParser::startSimpleEntry)); + m_sHandler.insert("file/includegraph", + new StartElementHandlerKind(this,LayoutDocEntry::FileIncludeGraph,&LayoutParser::startSimpleEntry)); + m_sHandler.insert("file/includedbygraph", + new StartElementHandlerKind(this,LayoutDocEntry::FileIncludedByGraph,&LayoutParser::startSimpleEntry)); + m_sHandler.insert("file/sourcelink", + new StartElementHandlerKind(this,LayoutDocEntry::FileSourceLink,&LayoutParser::startSimpleEntry)); + m_sHandler.insert("file/memberdecl/membergroups", + new StartElementHandlerKind(this,LayoutDocEntry::MemberGroups,&LayoutParser::startSimpleEntry)); + m_sHandler.insert("file/memberdecl", + new StartElementHandler(this,&LayoutParser::startMemberDecl)); + m_sHandler.insert("file/memberdecl/classes", + new StartElementHandlerSection(this,LayoutDocEntry::FileClasses,&LayoutParser::startSectionEntry, + vhdlOpt ? VhdlDocGen::trVhdlType(VhdlDocGen::ENTITY,FALSE) : + fortranOpt ? theTranslator->trDataTypes() : + theTranslator->trCompounds() + )); + m_sHandler.insert("file/memberdecl/namespaces", + new StartElementHandlerSection(this,LayoutDocEntry::FileNamespaces,&LayoutParser::startSectionEntry, + javaOpt ? theTranslator->trPackages() : + fortranOpt ? theTranslator->trModules() : + theTranslator->trNamespaces() + )); + m_sHandler.insert("file/memberdecl/defines", + new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, + MemberList::decDefineMembers,theTranslator->trDefines())); + m_sHandler.insert("file/memberdecl/typedefs", + new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, + MemberList::decTypedefMembers,theTranslator->trTypedefs())); + m_sHandler.insert("file/memberdecl/enums", + new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, + MemberList::decEnumMembers,theTranslator->trEnumerations())); + m_sHandler.insert("file/memberdecl/functions", + new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, + MemberList::decFuncMembers, + fortranOpt ? theTranslator->trSubprograms() : + vhdlOpt ? VhdlDocGen::trFunctionAndProc() : + theTranslator->trFunctions())) ; + m_sHandler.insert("file/memberdecl/variables", + new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, + MemberList::decVarMembers,theTranslator->trVariables())); + + m_eHandler.insert("file/memberdecl", + new EndElementHandler(this,&LayoutParser::endMemberDecl)); + m_sHandler.insert("file/memberdef", + new StartElementHandler(this,&LayoutParser::startMemberDef)); + m_sHandler.insert("file/memberdef/inlineclasses", + new StartElementHandlerSection(this,LayoutDocEntry::FileInlineClasses,&LayoutParser::startSectionEntry, + fortranOpt ? theTranslator->trTypeDocumentation() : + theTranslator->trClassDocumentation() + )); + m_sHandler.insert("file/memberdef/defines", + new StartElementHandlerMember(this,&LayoutParser::startMemberDefEntry, + MemberList::docDefineMembers,theTranslator->trDefineDocumentation())); + m_sHandler.insert("file/memberdef/typedefs", + new StartElementHandlerMember(this,&LayoutParser::startMemberDefEntry, + MemberList::docTypedefMembers,theTranslator->trTypedefDocumentation())); + m_sHandler.insert("file/memberdef/enums", + new StartElementHandlerMember(this,&LayoutParser::startMemberDefEntry, + MemberList::docEnumMembers, + theTranslator->trEnumerationTypeDocumentation())); + m_sHandler.insert("file/memberdef/functions", + new StartElementHandlerMember(this,&LayoutParser::startMemberDefEntry, + MemberList::docFuncMembers, + fortranOpt ? theTranslator->trSubprogramDocumentation() : theTranslator->trFunctionDocumentation())); + m_sHandler.insert("file/memberdef/variables", + new StartElementHandlerMember(this,&LayoutParser::startMemberDefEntry, + MemberList::docVarMembers,theTranslator->trVariableDocumentation())); + m_eHandler.insert("file/memberdef", + new EndElementHandler(this,&LayoutParser::endMemberDef)); + m_eHandler.insert("file", + new EndElementHandler(this,&LayoutParser::endFile)); + + // group layout handlers + m_sHandler.insert("group", + new StartElementHandler(this,&LayoutParser::startGroup)); + m_sHandler.insert("group/briefdescription", + new StartElementHandlerKind(this,LayoutDocEntry::BriefDesc,&LayoutParser::startSimpleEntry)); + m_sHandler.insert("group/detaileddescription", + new StartElementHandlerSection(this,LayoutDocEntry::DetailedDesc,&LayoutParser::startSectionEntry, + theTranslator->trDetailedDescription())); + m_sHandler.insert("group/authorsection", + new StartElementHandlerKind(this,LayoutDocEntry::AuthorSection,&LayoutParser::startSimpleEntry)); + m_sHandler.insert("group/groupgraph", + new StartElementHandlerKind(this,LayoutDocEntry::GroupGraph,&LayoutParser::startSimpleEntry)); + m_sHandler.insert("group/memberdecl/membergroups", + new StartElementHandlerKind(this,LayoutDocEntry::MemberGroups,&LayoutParser::startSimpleEntry)); + m_sHandler.insert("group/memberdecl", + new StartElementHandler(this,&LayoutParser::startMemberDecl)); + m_sHandler.insert("group/memberdecl/classes", + new StartElementHandlerSection(this,LayoutDocEntry::GroupClasses,&LayoutParser::startSectionEntry, + vhdlOpt ? VhdlDocGen::trVhdlType(VhdlDocGen::ENTITY,FALSE) : + fortranOpt ? theTranslator->trDataTypes() : + theTranslator->trCompounds() + )); + m_sHandler.insert("group/memberdecl/namespaces", + new StartElementHandlerSection(this,LayoutDocEntry::GroupNamespaces,&LayoutParser::startSectionEntry, + javaOpt ? theTranslator->trPackages() : + fortranOpt ? theTranslator->trModules() : + theTranslator->trNamespaces() + )); + m_sHandler.insert("group/memberdecl/dirs", + new StartElementHandlerSection(this,LayoutDocEntry::GroupDirs,&LayoutParser::startSectionEntry, + theTranslator->trDirectories() + )); + m_sHandler.insert("group/memberdecl/nestedgroups", + new StartElementHandlerSection(this,LayoutDocEntry::GroupNestedGroups,&LayoutParser::startSectionEntry, + theTranslator->trModules() + )); + m_sHandler.insert("group/memberdecl/files", + new StartElementHandlerSection(this,LayoutDocEntry::GroupFiles,&LayoutParser::startSectionEntry, + theTranslator->trFile(TRUE,FALSE) + )); + + m_sHandler.insert("group/memberdecl/defines", + new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, + MemberList::decDefineMembers,theTranslator->trDefines())); + m_sHandler.insert("group/memberdecl/typedefs", + new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, + MemberList::decTypedefMembers,theTranslator->trTypedefs())); + m_sHandler.insert("group/memberdecl/enums", + new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, + MemberList::decEnumMembers,theTranslator->trEnumerations())); + m_sHandler.insert("group/memberdecl/enumvalues", + new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, + MemberList::decEnumValMembers,theTranslator->trEnumerationValues())); + m_sHandler.insert("group/memberdecl/functions", + new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, + MemberList::decFuncMembers, + fortranOpt ? theTranslator->trSubprograms() : + vhdlOpt ? VhdlDocGen::trFunctionAndProc() : + theTranslator->trFunctions())); + m_sHandler.insert("group/memberdecl/variables", + new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, + MemberList::decVarMembers,theTranslator->trVariables())); + m_sHandler.insert("group/memberdecl/signals", + new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, + MemberList::decSignalMembers,theTranslator->trSignals())); + m_sHandler.insert("group/memberdecl/publicslots", + new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, + MemberList::decPubSlotMembers,theTranslator->trPublicSlots())); + m_sHandler.insert("group/memberdecl/protectedslots", + new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, + MemberList::decProSlotMembers,theTranslator->trProtectedSlots())); + m_sHandler.insert("group/memberdecl/privateslots", + new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, + MemberList::decPriSlotMembers,theTranslator->trPrivateSlots())); + m_sHandler.insert("group/memberdecl/events", + new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, + MemberList::decEventMembers,theTranslator->trEvents())); + m_sHandler.insert("group/memberdecl/properties", + new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, + MemberList::decPropMembers,theTranslator->trProperties())); + m_sHandler.insert("group/memberdecl/friends", + new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, + MemberList::decFriendMembers,theTranslator->trFriends())); + m_eHandler.insert("group/memberdecl", + new EndElementHandler(this,&LayoutParser::endMemberDecl)); + m_sHandler.insert("group/memberdef", + new StartElementHandler(this,&LayoutParser::startMemberDef)); + m_sHandler.insert("group/memberdef/pagedocs", + new StartElementHandlerKind(this,LayoutDocEntry::GroupPageDocs,&LayoutParser::startSimpleEntry)); + m_sHandler.insert("group/memberdef/inlineclasses", + new StartElementHandlerSection(this,LayoutDocEntry::GroupInlineClasses,&LayoutParser::startSectionEntry, + fortranOpt ? theTranslator->trTypeDocumentation() : + theTranslator->trClassDocumentation() + )); + m_sHandler.insert("group/memberdef/defines", + new StartElementHandlerMember(this,&LayoutParser::startMemberDefEntry, + MemberList::docDefineMembers,theTranslator->trDefineDocumentation())); + m_sHandler.insert("group/memberdef/typedefs", + new StartElementHandlerMember(this,&LayoutParser::startMemberDefEntry, + MemberList::docTypedefMembers,theTranslator->trTypedefDocumentation())); + m_sHandler.insert("group/memberdef/enums", + new StartElementHandlerMember(this,&LayoutParser::startMemberDefEntry, + MemberList::docEnumMembers,theTranslator->trEnumerationTypeDocumentation())); + m_sHandler.insert("group/memberdef/enumvalues", + new StartElementHandlerMember(this,&LayoutParser::startMemberDefEntry, + MemberList::docEnumValMembers,theTranslator->trEnumerationValueDocumentation())); + m_sHandler.insert("group/memberdef/functions", + new StartElementHandlerMember(this,&LayoutParser::startMemberDefEntry, + MemberList::docFuncMembers, + fortranOpt? + theTranslator->trSubprogramDocumentation(): + theTranslator->trFunctionDocumentation())); + m_sHandler.insert("group/memberdef/variables", + new StartElementHandlerMember(this,&LayoutParser::startMemberDefEntry, + MemberList::docVarMembers,theTranslator->trVariableDocumentation())); + m_sHandler.insert("group/memberdef/signals", + new StartElementHandlerMember(this,&LayoutParser::startMemberDefEntry, + MemberList::docSignalMembers,theTranslator->trSignals())); + m_sHandler.insert("group/memberdef/publicslots", + new StartElementHandlerMember(this,&LayoutParser::startMemberDefEntry, + MemberList::docPubSlotMembers,theTranslator->trPublicSlots())); + m_sHandler.insert("group/memberdef/protectedslots", + new StartElementHandlerMember(this,&LayoutParser::startMemberDefEntry, + MemberList::docProSlotMembers,theTranslator->trProtectedSlots())); + m_sHandler.insert("group/memberdef/privateslots", + new StartElementHandlerMember(this,&LayoutParser::startMemberDefEntry, + MemberList::docPriSlotMembers,theTranslator->trPrivateSlots())); + m_sHandler.insert("group/memberdef/events", + new StartElementHandlerMember(this,&LayoutParser::startMemberDefEntry, + MemberList::docEventMembers,theTranslator->trEvents())); + m_sHandler.insert("group/memberdef/properties", + new StartElementHandlerMember(this,&LayoutParser::startMemberDefEntry, + MemberList::docPropMembers,theTranslator->trProperties())); + m_sHandler.insert("group/memberdef/friends", + new StartElementHandlerMember(this,&LayoutParser::startMemberDefEntry, + MemberList::docFriendMembers,theTranslator->trFriends())); + m_eHandler.insert("group/memberdef", + new EndElementHandler(this,&LayoutParser::endMemberDef)); + m_eHandler.insert("group", + new EndElementHandler(this,&LayoutParser::endGroup)); + + // directory layout handlers + m_sHandler.insert("directory", + new StartElementHandler(this,&LayoutParser::startDirectory)); + m_sHandler.insert("directory/briefdescription", + new StartElementHandlerKind(this,LayoutDocEntry::BriefDesc,&LayoutParser::startSimpleEntry)); + m_sHandler.insert("directory/detaileddescription", + new StartElementHandlerSection(this,LayoutDocEntry::DetailedDesc,&LayoutParser::startSectionEntry, + theTranslator->trDetailedDescription())); + m_sHandler.insert("directory/directorygraph", + new StartElementHandlerKind(this,LayoutDocEntry::DirGraph,&LayoutParser::startSimpleEntry)); + m_sHandler.insert("directory/memberdecl", + new StartElementHandler(this,&LayoutParser::startMemberDecl)); + m_sHandler.insert("directory/memberdecl/dirs", + new StartElementHandlerKind(this,LayoutDocEntry::DirSubDirs,&LayoutParser::startSimpleEntry)); + m_sHandler.insert("directory/memberdecl/files", + new StartElementHandlerKind(this,LayoutDocEntry::DirFiles,&LayoutParser::startSimpleEntry)); + m_eHandler.insert("directory/memberdecl", + new EndElementHandler(this,&LayoutParser::endMemberDecl)); + m_eHandler.insert("directory", + new EndElementHandler(this,&LayoutParser::endDirectory)); + } + + void startSimpleEntry(LayoutDocEntry::Kind k,const QXmlAttributes &attrib) + { + bool isVisible = elemIsVisible(attrib); + if (m_part!=-1 && isVisible) + { + LayoutDocManager::instance().addEntry((LayoutDocManager::LayoutPart)m_part, + new LayoutDocEntrySimple(k)); + } + } + + void startSectionEntry(LayoutDocEntry::Kind k,const QXmlAttributes &attrib, + const QCString &title) + { + bool isVisible = elemIsVisible(attrib); + QCString userTitle = convertToQCString(attrib.value("title")); + //printf("startSectionEntry: title='%s' userTitle='%s'\n", + // title.data(),userTitle.data()); + if (userTitle.isEmpty()) userTitle = title; + if (m_part!=-1 && isVisible) + { + LayoutDocManager::instance().addEntry((LayoutDocManager::LayoutPart)m_part, + new LayoutDocEntrySection(k,userTitle)); + } + } + + + void startMemberDeclEntry(const QXmlAttributes &attrib,MemberList::ListType type, + const QCString &title,const QCString &subscript) + { + //QCString visible = convertToQCString(attrib.value("visible")); + //bool isVisible = visible.isEmpty() || (visible!="no" && visible!="0"); + QCString userTitle = convertToQCString(attrib.value("title")); + QCString userSubscript = convertToQCString(attrib.value("subtitle")); + if (userTitle.isEmpty()) userTitle = title; + if (userSubscript.isEmpty()) userSubscript = subscript; + //printf("memberdecl: %s\n",userTitle.data()); + if (m_part!=-1 /*&& isVisible*/) + { + LayoutDocManager::instance().addEntry((LayoutDocManager::LayoutPart)m_part, + new LayoutDocEntryMemberDecl(type,userTitle,userSubscript)); + } + } + + void startMemberDefEntry(const QXmlAttributes &attrib,MemberList::ListType type, + const QCString &title,const QCString &) + { + QCString userTitle = convertToQCString(attrib.value("title")); + if (userTitle.isEmpty()) userTitle = title; + //printf("memberdef: %s\n",userTitle.data()); + if (m_part!=-1 /*&& isVisible*/) + { + LayoutDocManager::instance().addEntry((LayoutDocManager::LayoutPart)m_part, + new LayoutDocEntryMemberDef(type,userTitle)); + } + } + + void startLayout(const QXmlAttributes &) + { + } + + void endLayout() + { + } + + void startNavIndex(const QXmlAttributes &) + { + m_scope="navindex/"; + m_rootNav = LayoutDocManager::instance().rootNavEntry(); + if (m_rootNav) m_rootNav->clear(); + } + + void endNavIndex() + { + m_scope=""; + if (m_rootNav && !m_rootNav->find(LayoutNavEntry::MainPage)) + { + // no MainPage node... add one the first item of the root node... + new LayoutNavEntry(m_rootNav,LayoutNavEntry::MainPage, TRUE, + /*Config_getBool("GENERATE_TREEVIEW") ? "main" :*/ "index", + theTranslator->trMainPage(),TRUE); + } + } + + void startNavEntry(const QXmlAttributes &attrib) + { + static bool javaOpt = Config_getBool("OPTIMIZE_OUTPUT_JAVA"); + static bool fortranOpt = Config_getBool("OPTIMIZE_FOR_FORTRAN"); + static bool vhdlOpt = Config_getBool("OPTIMIZE_OUTPUT_VHDL"); + static bool hasGraphicalHierarchy = Config_getBool("HAVE_DOT") && + Config_getBool("GRAPHICAL_HIERARCHY"); + static bool extractAll = Config_getBool("EXTRACT_ALL"); + static struct NavEntryMap + { + const char *typeStr; // type attribute name in the XML file + LayoutNavEntry::Kind kind; // corresponding enum name + QCString mainName; // default title for an item if it has children + QCString subName; // optional name for an item if it is rendered as a child + QCString intro; // introduction text to be put on the index page + QCString baseFile; // base name of the file containing the index page + } mapping[] = + { + { "mainpage", + LayoutNavEntry::MainPage, + theTranslator->trMainPage(), + QCString(), + QCString(), + "index" + }, + { "pages", + LayoutNavEntry::Pages, + theTranslator->trRelatedPages(), + QCString(), + theTranslator->trRelatedPagesDescription(), + "pages" + }, + { "modules", + LayoutNavEntry::Modules, + theTranslator->trModules(), + QCString(), + theTranslator->trModulesDescription(), + "modules" + }, + { "namespaces", + LayoutNavEntry::Namespaces, + javaOpt || vhdlOpt ? theTranslator->trPackages() : fortranOpt ? theTranslator->trModules() : theTranslator->trNamespaces(), + javaOpt || vhdlOpt ? theTranslator->trPackages() : fortranOpt ? theTranslator->trModulesList() : theTranslator->trNamespaceList(), + javaOpt || vhdlOpt ? theTranslator->trPackageListDescription() : fortranOpt ? theTranslator->trModulesListDescription(extractAll) : theTranslator->trNamespaceListDescription(extractAll), + "namespaces" + }, + { "namespacelist", + LayoutNavEntry::NamespaceList, + javaOpt || vhdlOpt ? theTranslator->trPackages() : fortranOpt ? theTranslator->trModulesList() : theTranslator->trNamespaceList(), + QCString(), + javaOpt || vhdlOpt ? theTranslator->trPackageListDescription() : fortranOpt ? theTranslator->trModulesListDescription(extractAll) : theTranslator->trNamespaceListDescription(extractAll), + "namespaces" + }, + { "namespacemembers", + LayoutNavEntry::NamespaceMembers, + javaOpt || vhdlOpt ? theTranslator->trPackageMembers() : fortranOpt ? theTranslator->trModulesMembers() : theTranslator->trNamespaceMembers(), + QCString(), + fortranOpt ? theTranslator->trModulesMemberDescription(extractAll) : theTranslator->trNamespaceMemberDescription(extractAll), + "namespacemembers" + }, + { "classindex", + LayoutNavEntry::ClassIndex, + fortranOpt ? theTranslator->trDataTypes() : vhdlOpt ? VhdlDocGen::trDesignUnits() : theTranslator->trCompoundIndex(), + QCString(), + QCString(), + "classes" + }, + { "classes", + LayoutNavEntry::Classes, + fortranOpt ? theTranslator->trCompoundListFortran() : vhdlOpt ? VhdlDocGen::trDesignUnitList() : theTranslator->trClasses(), + theTranslator->trCompoundList(), + fortranOpt ? theTranslator->trCompoundListDescriptionFortran() : vhdlOpt ? VhdlDocGen::trDesignUnitListDescription() : theTranslator->trCompoundListDescription(), + "annotated" + }, + { "classlist", + LayoutNavEntry::ClassList, + fortranOpt ? theTranslator->trCompoundListFortran() : vhdlOpt ? VhdlDocGen::trDesignUnitList() : theTranslator->trCompoundList(), + QCString(), + fortranOpt ? theTranslator->trCompoundListDescriptionFortran() : vhdlOpt ? VhdlDocGen::trDesignUnitListDescription() : theTranslator->trCompoundListDescription(), + "annotated" + }, + { "hierarchy", + LayoutNavEntry::ClassHierarchy, + vhdlOpt ? VhdlDocGen::trDesignUnitHierarchy() : theTranslator->trClassHierarchy(), + QCString(), + theTranslator->trClassHierarchyDescription(), + hasGraphicalHierarchy ? "inherits" : "hierarchy" + }, + { "classmembers", + LayoutNavEntry::ClassMembers, + fortranOpt ? theTranslator->trCompoundMembersFortran() : vhdlOpt ? VhdlDocGen::trDesignUnitMembers() : theTranslator->trCompoundMembers(), + QCString(), + fortranOpt ? theTranslator->trCompoundMembersDescriptionFortran(extractAll) : theTranslator->trCompoundMembersDescription(extractAll), + "functions" + }, + { "files", + LayoutNavEntry::Files, + theTranslator->trFile(TRUE,FALSE), + theTranslator->trFileList(), + theTranslator->trFileListDescription(extractAll), + "files" + }, + { "filelist", + LayoutNavEntry::FileList, + theTranslator->trFileList(), + QCString(), + theTranslator->trFileListDescription(extractAll), + "files" + }, + { "globals", + LayoutNavEntry::FileGlobals, + theTranslator->trFileMembers(), + QCString(), + theTranslator->trFileMembersDescription(extractAll), + "globals" + }, + { "dirs", + LayoutNavEntry::Dirs, + theTranslator->trDirectories(), + QCString(), + theTranslator->trDirDescription(), + "dirs" + }, + { "examples", + LayoutNavEntry::Examples, + theTranslator->trExamples(), + QCString(), + theTranslator->trExamplesDescription(), + "examples" + }, + { "user", + LayoutNavEntry::User, + QCString(), + QCString(), + QCString(), + "user" + }, + { "usergroup", + LayoutNavEntry::UserGroup, + QCString(), + QCString(), + QCString(), + "usergroup" + }, + { 0, // end of list + (LayoutNavEntry::Kind)0, + QCString(), + QCString(), + QCString(), + QCString() + } + }; + LayoutNavEntry::Kind kind; + // find type in the table + int i=0; + QString type = attrib.value("type"); + while (mapping[i].typeStr) + { + if (mapping[i].typeStr==type) + { + kind = mapping[i].kind; + break; + } + i++; + } + if (mapping[i].typeStr==0) + { + if (type.isEmpty()) + { + err("error: an entry tag within a navindex has no type attribute! Check your layout file!\n"); + } + else + { + err("error: the type '%s' is not supported for the entry tag within a navindex! Check your layout file!\n",type.data()); + } + m_invalidEntry=TRUE; + return; + } + QCString baseFile = mapping[i].baseFile; + QCString title = convertToQCString(attrib.value("title")); + bool isVisible = elemIsVisible(attrib); + if (title.isEmpty()) // use default title + { + title = mapping[i].mainName; // use title for main row + if (m_rootNav!=LayoutDocManager::instance().rootNavEntry() && !mapping[i].subName.isEmpty()) + { + title = mapping[i].subName; // if this is a child of another row, use the subName if available + // this is mainly done to get compatible naming with older versions. + } + } + QCString intro = convertToQCString(attrib.value("intro")); + if (intro.isEmpty()) // use default intro text + { + intro = mapping[i].intro; + } + QCString url = convertToQCString(attrib.value("url")); + if (mapping[i].kind==LayoutNavEntry::User && !url.isEmpty()) + { + baseFile=url; + } + else if (kind==LayoutNavEntry::UserGroup) + { + baseFile+=QCString().sprintf("%d",m_userGroupCount++); + } + // create new item and make it the new root + m_rootNav = new LayoutNavEntry(m_rootNav,kind,kind==LayoutNavEntry::MainPage?TRUE:isVisible,baseFile,title,intro); + } + + void endNavEntry() + { + // set the root back to the parent + if (m_rootNav && !m_invalidEntry) m_rootNav = m_rootNav->parent(); + m_invalidEntry=FALSE; + } + + void startClass(const QXmlAttributes &) + { + LayoutDocManager::instance().clear(LayoutDocManager::Class); + m_scope="class/"; + m_part = (int)LayoutDocManager::Class; + } + + void endClass() + { + m_scope=""; + m_part = -1; + } + + void startNamespace(const QXmlAttributes &) + { + LayoutDocManager::instance().clear(LayoutDocManager::Namespace); + m_scope="namespace/"; + m_part = (int)LayoutDocManager::Namespace; + } + + void endNamespace() + { + m_scope=""; + m_part = -1; + } + + void startFile(const QXmlAttributes &) + { + LayoutDocManager::instance().clear(LayoutDocManager::File); + m_scope="file/"; + m_part = (int)LayoutDocManager::File; + } + + void endFile() + { + m_scope=""; + m_part = -1; + } + + void startGroup(const QXmlAttributes &) + { + LayoutDocManager::instance().clear(LayoutDocManager::Group); + m_scope="group/"; + m_part = (int)LayoutDocManager::Group; + } + + void endGroup() + { + m_scope=""; + m_part = -1; + } + + void startDirectory(const QXmlAttributes &) + { + LayoutDocManager::instance().clear(LayoutDocManager::Directory); + m_scope="directory/"; + m_part = (int)LayoutDocManager::Directory; + } + + void endDirectory() + { + m_scope=""; + m_part = -1; + } + + void startMemberDef(const QXmlAttributes &) + { + m_scope+="memberdef/"; + if (m_part!=-1) + { + LayoutDocManager::instance().addEntry((LayoutDocManager::LayoutPart)m_part, + new LayoutDocEntrySimple(LayoutDocEntry::MemberDefStart)); + } + } + + void endMemberDef() + { + int i=m_scope.findRev("memberdef/"); + if (i!=-1) + { + m_scope=m_scope.left(i); + if (m_part!=-1) + { + LayoutDocManager::instance().addEntry((LayoutDocManager::LayoutPart)m_part, + new LayoutDocEntrySimple(LayoutDocEntry::MemberDefEnd)); + } + } + } + + void startMemberDecl(const QXmlAttributes &) + { + m_scope+="memberdecl/"; + if (m_part!=-1) + { + LayoutDocManager::instance().addEntry((LayoutDocManager::LayoutPart)m_part, + new LayoutDocEntrySimple(LayoutDocEntry::MemberDeclStart)); + } + } + + void endMemberDecl() + { + int i=m_scope.findRev("memberdecl/"); + if (i!=-1) + { + m_scope=m_scope.left(i); + if (m_part!=-1) + { + LayoutDocManager::instance().addEntry((LayoutDocManager::LayoutPart)m_part, + new LayoutDocEntrySimple(LayoutDocEntry::MemberDeclEnd)); + } + } + } + + // reimplemented from QXmlDefaultHandler + bool startElement( const QString&, const QString&, + const QString& name, const QXmlAttributes& attrib ) + { + //printf("startElement [%s]::[%s]\n",m_scope.data(),name.data()); + StartElementHandler *handler = m_sHandler[m_scope+name]; + if (handler) + { + (*handler)(attrib); + } + else + { + err("error: Unexpected start tag `%s' found in scope='%s'!\n", + name.data(),m_scope.data()); + } + return TRUE; + } + bool endElement( const QString&, const QString&, const QString& name ) + { + //printf("endElement [%s]::[%s]\n",m_scope.data(),name.data()); + EndElementHandler *handler; + if (!m_scope.isEmpty() && m_scope.right(name.length()+1)==name+"/") + { // element ends current scope + handler = m_eHandler[m_scope.left(m_scope.length()-1)]; + } + else // continue with current scope + { + handler = m_eHandler[m_scope+name]; + } + if (handler) + { + (*handler)(); + } + return TRUE; + } + bool startDocument() + { + return TRUE; + } + + private: + LayoutParser() : m_sHandler(163), m_eHandler(17), m_invalidEntry(FALSE) { } + + QDict m_sHandler; + QDict m_eHandler; + QString m_scope; + int m_part; + LayoutNavEntry *m_rootNav; + bool m_invalidEntry; + static int m_userGroupCount; +}; + +int LayoutParser::m_userGroupCount=0; + +//--------------------------------------------------------------------------------- + +class LayoutErrorHandler : public QXmlErrorHandler +{ + public: + LayoutErrorHandler(const char *fn) : fileName(fn) {} + bool warning( const QXmlParseException &exception ) + { + err("warning: at line %d column %d of %s: %s\n", + exception.lineNumber(),exception.columnNumber(),fileName.data(), + exception.message().data()); + return FALSE; + } + bool error( const QXmlParseException &exception ) + { + err("error: at line %d column %d of %s: %s\n", + exception.lineNumber(),exception.columnNumber(),fileName.data(), + exception.message().data()); + return FALSE; + } + bool fatalError( const QXmlParseException &exception ) + { + err("fatal error: at line %d column %d of %s: %s\n", + exception.lineNumber(),exception.columnNumber(),fileName.data(), + exception.message().data()); + return FALSE; + } + QString errorString() { return ""; } + + private: + QString errorMsg; + QString fileName; +}; + +//--------------------------------------------------------------------------------- + +class LayoutDocManager::Private +{ + public: + QList docEntries[LayoutDocManager::NrParts]; + LayoutNavEntry *rootNav; +}; + +LayoutDocManager::LayoutDocManager() +{ + d = new Private; + int i; + for (i=0;idocEntries[i].setAutoDelete(TRUE); + } + d->rootNav = new LayoutNavEntry; + LayoutParser::instance().init(); +} + + +void LayoutDocManager::init() +{ + // parse the default layout + LayoutErrorHandler errorHandler( "layout_default.xml" ); + QXmlInputSource source; + source.setData( layout_default ); + QXmlSimpleReader reader; + reader.setContentHandler( &LayoutParser::instance() ); + reader.setErrorHandler( &errorHandler ); + reader.parse( source ); +} + +LayoutDocManager::~LayoutDocManager() +{ + delete d->rootNav; + delete d; +} + +LayoutDocManager & LayoutDocManager::instance() +{ + static LayoutDocManager *theInstance = new LayoutDocManager; + return *theInstance; +} + +const QList &LayoutDocManager::docEntries(LayoutDocManager::LayoutPart part) const +{ + return d->docEntries[(int)part]; +} + +LayoutNavEntry* LayoutDocManager::rootNavEntry() const +{ + return d->rootNav; +} + +void LayoutDocManager::addEntry(LayoutDocManager::LayoutPart p,LayoutDocEntry *e) +{ + d->docEntries[(int)p].append(e); +} + +void LayoutDocManager::clear(LayoutDocManager::LayoutPart p) +{ + d->docEntries[(int)p].clear(); +} + +void LayoutDocManager::parse(QTextStream &t,const char *fileName) +{ + LayoutErrorHandler errorHandler(fileName); + QXmlInputSource source( t ); + QXmlSimpleReader reader; + reader.setContentHandler( &LayoutParser::instance() ); + reader.setErrorHandler( &errorHandler ); + reader.parse( source ); +} + +//--------------------------------------------------------------------------------- + +void writeDefaultLayoutFile(const char *fileName) +{ + QFile f(fileName); + if (!f.open(IO_WriteOnly)) + { + err("Failed to open file %s for writing!\n",fileName); + return; + } + QTextStream t(&f); + t << layout_default; +} diff --git a/trunk/src/layout.h b/trunk/src/layout.h new file mode 100644 index 0000000..e0ea4ca --- /dev/null +++ b/trunk/src/layout.h @@ -0,0 +1,198 @@ +/****************************************************************************** + * + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#ifndef LAYOUT_H +#define LAYOUT_H + +#include "qtbc.h" +#include "memberlist.h" +#include + +class LayoutParser; + +/** @brief Base class representing a piece of a documentation page */ +struct LayoutDocEntry +{ + virtual ~LayoutDocEntry() {} + enum Kind { + // Generic items for all pages + MemberGroups, + MemberDeclStart, MemberDeclEnd, MemberDecl, + MemberDefStart, MemberDefEnd, MemberDef, + BriefDesc, DetailedDesc, + AuthorSection, + + // Class specific items + ClassIncludes, ClassInlineClasses, + ClassInheritanceGraph, ClassNestedClasses, + ClassCollaborationGraph, ClassAllMembersLink, + ClassUsedFiles, + + // Namespace specific items + NamespaceNestedNamespaces, NamespaceClasses, + NamespaceInlineClasses, + + // File specific items + FileClasses, FileNamespaces, + FileIncludes, FileIncludeGraph, + FileIncludedByGraph, FileSourceLink, + FileInlineClasses, + + // Group specific items + GroupClasses, GroupInlineClasses, GroupNamespaces, + GroupDirs, GroupNestedGroups, GroupFiles, + GroupGraph, GroupPageDocs, + + // Directory specific items + DirSubDirs, DirFiles, DirGraph + + }; + virtual Kind kind() const = 0; +}; + +/** @brief Represents of a piece of a documentation page without configurable parts */ +struct LayoutDocEntrySimple : LayoutDocEntry +{ + public: + LayoutDocEntrySimple(Kind k) : m_kind(k) {} + Kind kind() const { return m_kind; } + private: + Kind m_kind; +}; + +struct LayoutDocEntrySection: public LayoutDocEntrySimple +{ + LayoutDocEntrySection(Kind k,const QCString &tl) : + LayoutDocEntrySimple(k), title(tl) {} + QCString title; +}; + +/** @brief Represents of a member declaration list with configurable title and subtitle. */ +struct LayoutDocEntryMemberDecl: public LayoutDocEntry +{ + LayoutDocEntryMemberDecl(MemberList::ListType tp, + const QCString &tl,const QCString &ss) + : type(tp), title(tl),subscript(ss) {} + + Kind kind() const { return MemberDecl; } + MemberList::ListType type; + QCString title; + QCString subscript; +}; + +/** @brief Represents of a member definition list with configurable title. */ +struct LayoutDocEntryMemberDef: public LayoutDocEntry +{ + LayoutDocEntryMemberDef(MemberList::ListType tp,const QCString &tl) + : type(tp), title(tl) {} + + Kind kind() const { return MemberDef; } + MemberList::ListType type; + QCString title; +}; + +/** @brief Base class for the layout of a navigation item at the top of the HTML pages. */ +struct LayoutNavEntry +{ + public: + enum Kind { + MainPage, + Pages, + Modules, + Namespaces, + NamespaceList, + NamespaceMembers, + Classes, + ClassList, + ClassIndex, + ClassHierarchy, + ClassMembers, + Files, + FileList, + FileGlobals, + Dirs, + Examples, + User, + UserGroup + }; + LayoutNavEntry(LayoutNavEntry *parent,Kind k,bool vs,const QCString &bf, + const QCString &tl,const QCString &intro,bool prepend=FALSE) + : m_parent(parent), m_kind(k), m_visible(vs), m_baseFile(bf), m_title(tl), m_intro(intro) + { m_children.setAutoDelete(TRUE); + if (parent) { if (prepend) parent->prependChild(this); else parent->addChild(this); } + } + LayoutNavEntry *parent() const { return m_parent; } + Kind kind() const { return m_kind; } + QCString baseFile() const { return m_baseFile; } + QCString title() const { return m_title; } + QCString intro() const { return m_intro; } + QCString url() const; + bool visible() { return m_visible; } + void clear() { m_children.clear(); } + void addChild(LayoutNavEntry *e) { m_children.append(e); } + void prependChild(LayoutNavEntry *e) { m_children.prepend(e); } + const QList &children() const { return m_children; } + LayoutNavEntry *find(LayoutNavEntry::Kind k,const char *file=0) const; + + private: + LayoutNavEntry() : m_parent(0) {} + LayoutNavEntry *m_parent; + Kind m_kind; + bool m_visible; + QCString m_baseFile; + QCString m_title; + QCString m_intro; + QList m_children; + friend class LayoutDocManager; +}; + +/** @brief Singleton providing access to the (user configurable) layout of the documentation */ +class LayoutDocManager +{ + class Private; + public: + enum LayoutPart + { + Class, Namespace, File, Group, Directory, + NrParts + }; + /** Returns a reference to this singleton. */ + static LayoutDocManager &instance(); + + /** Returns the list of LayoutDocEntry's in representation order for a given page identified by @a part. */ + const QList &docEntries(LayoutPart part) const; + + /** returns the (invisible) root of the navigation tree. */ + LayoutNavEntry *rootNavEntry() const; + + /** Parses a user provided layout */ + void parse(QTextStream &t,const char *fileName); + void init(); + private: + void addEntry(LayoutPart p,LayoutDocEntry*e); + void clear(LayoutPart p); + LayoutDocManager(); + ~LayoutDocManager(); + Private *d; + friend class LayoutParser; +}; + +void writeDefaultLayoutFile(const char *fileName); + +#endif + diff --git a/trunk/src/layout_default.h b/trunk/src/layout_default.h new file mode 100644 index 0000000..6a1ff8f --- /dev/null +++ b/trunk/src/layout_default.h @@ -0,0 +1,188 @@ +"\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"\n" diff --git a/trunk/src/layout_default.xml b/trunk/src/layout_default.xml new file mode 100644 index 0000000..7f62755 --- /dev/null +++ b/trunk/src/layout_default.xml @@ -0,0 +1,188 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/trunk/src/libdoxycfg.pro.in b/trunk/src/libdoxycfg.pro.in new file mode 100644 index 0000000..800c373 --- /dev/null +++ b/trunk/src/libdoxycfg.pro.in @@ -0,0 +1,27 @@ +# +# +# +# Copyright (C) 1997-2012 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. +# +# TMake project file for doxygen + +TEMPLATE = libdoxycfg.t +CONFIG = console warn_on staticlib $extraopts +HEADERS = config.h configoptions.h portable.h +SOURCES = config.cpp configoptions.cpp portable.cpp portable_c.c +win32:TMAKE_CXXFLAGS += -DQT_NODLL +win32-g++:TMAKE_CXXFLAGS += -fno-exceptions -fno-rtti +INCLUDEPATH += ../qtools +win32:INCLUDEPATH += . +DESTDIR = ../lib +TARGET = doxycfg +OBJECTS_DIR = ../objects diff --git a/trunk/src/libdoxycfg.t.in b/trunk/src/libdoxycfg.t.in new file mode 100644 index 0000000..29b1623 --- /dev/null +++ b/trunk/src/libdoxycfg.t.in @@ -0,0 +1,52 @@ +# +# +# +# Copyright (C) 1997-2012 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. +#! +#! doxygen.t: This is a custom template for building Doxygen +#! +#$ IncludeTemplate("lib.t"); + +LEX = %%FLEX%% +YACC = %%BISON%% + +#${ +sub GenerateDep { + my($obj,$src,$dep) = @_; + my(@objv,$srcv,$i,$s,$o,$d,$c); + @objv = split(/\s+/,$obj); + @srcv = split(/\s+/,$src); + for $i ( 0..$#objv ) { + $s = $srcv[$i]; + $o = $objv[$i]; + next if $s eq ""; + $text .= $o . ": " . $s; + $text .= " ${linebreak}\n\t\t" . $dep if $dep ne ""; + if ( $moc_output{$s} ne "" ) { + $text .= " ${linebreak}\n\t\t" . $moc_output{$s}; + } + $d = &make_depend($s); + $text .= " ${linebreak}\n\t\t" . $d if $d ne ""; + $text .= "\n"; + } + chop $text; +} +#$} + +#################### + +#$ GenerateDep("config.cpp","config.l"); + $(LEX) -PconfigYY -t config.l >config.cpp + +configoptions.cpp: config.xml + python configgen.py config.xml >configoptions.cpp + diff --git a/trunk/src/libdoxygen.pro.in b/trunk/src/libdoxygen.pro.in new file mode 100644 index 0000000..b6c7dec --- /dev/null +++ b/trunk/src/libdoxygen.pro.in @@ -0,0 +1,274 @@ +# +# +# +# Copyright (C) 1997-2012 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. +# +# TMake project file for doxygen + +TEMPLATE = libdoxygen.t +CONFIG = console warn_on staticlib $extraopts +HEADERS = arguments.h \ + bufstr.h \ + cite.h \ + classdef.h \ + classlist.h \ + cmdmapper.h \ + code.h \ + commentcnv.h \ + commentscan.h \ + compound_xsd.h \ + config.h \ + constexp.h \ + cppvalue.h \ + debug.h \ + declinfo.h \ + defargs.h \ + defgen.h \ + define.h \ + definition.h \ + diagram.h \ + dirdef.h \ + docparser.h \ + docsets.h \ + doctokenizer.h \ + docvisitor.h \ + dot.h \ + doxygen.h \ + doxygen_bst.h \ + doxygen_css.h \ + eclipsehelp.h \ + entry.h \ + example.h \ + filedef.h \ + filename.h \ + footer_html.h \ + formula.h \ + ftextstream.h \ + ftvhelp.h \ + groupdef.h \ + header_html.h \ + htags.h \ + htmlattrib.h \ + htmldocvisitor.h \ + htmlgen.h \ + htmlhelp.h \ + indexlog.h \ + image.h \ + index.h \ + index_xsd.h \ + jquery_js.h \ + jquery_ui_js.h \ + sizzle_js.h \ + svgpan_js.h \ + language.h \ + latexdocvisitor.h \ + latexgen.h \ + layout.h \ + layout_default.h \ + lockingptr.h \ + logos.h \ + mandocvisitor.h \ + mangen.h \ + markdown.h \ + marshal.h \ + memberdef.h \ + membergroup.h \ + memberlist.h \ + membername.h \ + message.h \ + msc.h \ + namespacedef.h \ + navtree_css.h \ + navtree_js.h \ + objcache.h \ + outputgen.h \ + outputlist.h \ + pagedef.h \ + perlmodgen.h \ + lodepng.h \ + pre.h \ + printdocvisitor.h \ + pycode.h \ + pyscanner.h \ + fortrancode.h \ + fortranscanner.h \ + dbusxmlscanner.h \ + qhp.h \ + qhpxmlwriter.h \ + qtbc.h \ + reflist.h \ + resize_js.h \ + rtfdocvisitor.h \ + rtfgen.h \ + rtfstyle.h \ + scanner.h \ + searchindex.h \ + search_css.h \ + search_js.h \ + search_functions_php.h \ + search_opensearch_php.h \ + section.h \ + sortdict.h \ + store.h \ + tagreader.h \ + tclscanner.h \ + textdocvisitor.h \ + translator.h \ + translator_adapter.h \ + translator_am.h \ + translator_br.h \ + translator_ca.h \ + translator_cn.h \ + translator_cz.h \ + translator_de.h \ + translator_dk.h \ + translator_en.h \ + translator_es.h \ + translator_fi.h \ + translator_fr.h \ + translator_gr.h \ + translator_hr.h \ + translator_hu.h \ + translator_id.h \ + translator_it.h \ + translator_je.h \ + translator_jp.h \ + translator_ke.h \ + translator_kr.h \ + translator_nl.h \ + translator_no.h \ + translator_mk.h \ + translator_pl.h \ + translator_pt.h \ + translator_ro.h \ + translator_ru.h \ + translator_se.h \ + translator_si.h \ + translator_sk.h \ + translator_sr.h \ + translator_tw.h \ + translator_ua.h \ + translator_vi.h \ + translator_za.h \ + types.h \ + unistd.h \ + util.h \ + version.h \ + vhdlcode.h \ + vhdldocgen.h \ + vhdlscanner.h \ + xmldocvisitor.h \ + xmlgen.h + +SOURCES = arguments.cpp \ + ce_lex.cpp \ + ce_parse.cpp \ + cite.cpp \ + classdef.cpp \ + classlist.cpp \ + cmdmapper.cpp \ + code.cpp \ + commentcnv.cpp \ + commentscan.cpp \ + cppvalue.cpp \ + dbusxmlscanner.cpp \ + debug.cpp \ + defgen.cpp \ + declinfo.cpp \ + defargs.cpp \ + define.cpp \ + definition.cpp \ + diagram.cpp \ + dirdef.cpp \ + docparser.cpp \ + docsets.cpp \ + doctokenizer.cpp \ + dot.cpp \ + doxygen.cpp \ + eclipsehelp.cpp \ + entry.cpp \ + filedef.cpp \ + filename.cpp \ + formula.cpp \ + ftextstream.cpp \ + ftvhelp.cpp \ + fortrancode.cpp \ + fortranscanner.cpp \ + groupdef.cpp \ + htags.cpp \ + htmldocvisitor.cpp \ + htmlgen.cpp \ + htmlhelp.cpp \ + indexlog.cpp \ + image.cpp \ + index.cpp \ + language.cpp \ + latexdocvisitor.cpp \ + latexgen.cpp \ + layout.cpp \ + lodepng.cpp \ + logos.cpp \ + mandocvisitor.cpp \ + mangen.cpp \ + markdown.cpp \ + marshal.cpp \ + memberdef.cpp \ + membergroup.cpp \ + memberlist.cpp \ + membername.cpp \ + message.cpp \ + msc.cpp \ + namespacedef.cpp \ + objcache.cpp \ + outputgen.cpp \ + outputlist.cpp \ + pagedef.cpp \ + perlmodgen.cpp \ + pre.cpp \ + pycode.cpp \ + pyscanner.cpp \ + qhp.cpp \ + qhpxmlwriter.cpp \ + reflist.cpp \ + rtfdocvisitor.cpp \ + rtfgen.cpp \ + rtfstyle.cpp \ + scanner.cpp \ + searchindex.cpp \ + store.cpp \ + tagreader.cpp \ + tclscanner.cpp \ + textdocvisitor.cpp \ + translator.cpp \ + util.cpp \ + version.cpp \ + vhdlcode.cpp \ + vhdldocgen.cpp \ + vhdlparser.cpp \ + vhdlscanner.cpp \ + xmldocvisitor.cpp \ + xmlgen.cpp + +win32:TMAKE_CXXFLAGS += -DQT_NODLL +win32-msvc:TMAKE_CXXFLAGS += -Zm200 +win32-g++:TMAKE_CXXFLAGS += -fno-exceptions -fno-rtti +linux-g++:TMAKE_CXXFLAGS += -fno-exceptions -fno-rtti +INCLUDEPATH += ../qtools +#INCLUDEPATH += ../libpng +INCLUDEPATH += ../libmd5 +win32:INCLUDEPATH += . +#win32-g++:INCLUDEPATH = ../qtools /usr/include/libpng12 ../libmd5 +win32-g++:INCLUDEPATH = ../qtools ../libmd5 +DESTDIR = ../lib +TARGET = doxygen +OBJECTS_DIR = ../objects + diff --git a/trunk/src/libdoxygen.t.in b/trunk/src/libdoxygen.t.in new file mode 100644 index 0000000..accf5cf --- /dev/null +++ b/trunk/src/libdoxygen.t.in @@ -0,0 +1,177 @@ +# +# +# +# Copyright (C) 1997-2012 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. +#! +#! doxygen.t: This is a custom template for building Doxygen +#! +#$ IncludeTemplate("lib.t"); + +LEX = %%FLEX%% +YACC = %%BISON%% +INCBUFSIZE = $(PERL) increasebuffer.pl + +#${ +sub GenerateDep { + my($obj,$src,$dep) = @_; + my(@objv,$srcv,$i,$s,$o,$d,$c); + @objv = split(/\s+/,$obj); + @srcv = split(/\s+/,$src); + for $i ( 0..$#objv ) { + $s = $srcv[$i]; + $o = $objv[$i]; + next if $s eq ""; + $text .= $o . ": " . $s; + $text .= " ${linebreak}\n\t\t" . $dep if $dep ne ""; + if ( $moc_output{$s} ne "" ) { + $text .= " ${linebreak}\n\t\t" . $moc_output{$s}; + } + $d = &make_depend($s); + $text .= " ${linebreak}\n\t\t" . $d if $d ne ""; + $text .= "\n"; + } + chop $text; +} +#$} + +#################### + +#$ GenerateDep("scanner.cpp","scanner.l"); + $(LEX) -PscanYY -t scanner.l | $(INCBUFSIZE) >scanner.cpp + +#$ GenerateDep("code.cpp","code.l"); + $(LEX) -PcodeYY -t code.l | $(INCBUFSIZE) >code.cpp + +#$ GenerateDep("pyscanner.cpp","pyscanner.l"); + $(LEX) -PpyscanYY -t pyscanner.l | $(INCBUFSIZE) >pyscanner.cpp + +#$ GenerateDep("pycode.cpp","pycode.l"); + $(LEX) -PpycodeYY -t pycode.l | $(INCBUFSIZE) >pycode.cpp + +#$ GenerateDep("fortranscanner.cpp","fortranscanner.l"); + $(LEX) -i -PfscanYY -t fortranscanner.l | $(INCBUFSIZE) >fortranscanner.cpp + +#$ GenerateDep("fortrancode.cpp","fortrancode.l"); + $(LEX) -i -PfcodeYY -t fortrancode.l | $(INCBUFSIZE) >fortrancode.cpp + +#$ GenerateDep("vhdlcode.cpp","vhdlcode.l"); + $(LEX) -i -PvhdlcodeYY -t vhdlcode.l | $(INCBUFSIZE) >vhdlcode.cpp + +#$ GenerateDep("tclscanner.cpp","tclscanner.l"); + $(LEX) -i -PtclscanYY -t tclscanner.l | $(INCBUFSIZE) >tclscanner.cpp + +#$ GenerateDep("pre.cpp","pre.l"); + $(LEX) -PpreYY -t pre.l | $(INCBUFSIZE) >pre.cpp + +#$ GenerateDep("declinfo.cpp","declinfo.l"); + $(LEX) -PdeclinfoYY -t declinfo.l | $(INCBUFSIZE) >declinfo.cpp + +#$ GenerateDep("defargs.cpp","defargs.l"); + $(LEX) -PdefargsYY -t defargs.l | $(INCBUFSIZE) >defargs.cpp + +#$ GenerateDep("doctokenizer.cpp","doctokenizer.l"); + $(LEX) -PdoctokenizerYY -t doctokenizer.l | $(INCBUFSIZE) >doctokenizer.cpp + +#$ GenerateDep("commentcnv.cpp","commentcnv.l"); + $(LEX) -PcommentcnvYY -t commentcnv.l | $(INCBUFSIZE) >commentcnv.cpp + +#$ GenerateDep("commentscan.cpp","commentscan.l"); + $(LEX) -PcommentScanYY -t commentscan.l | $(INCBUFSIZE) >commentscan.cpp + +#$ GenerateDep("ce_lex.cpp","constexp.l","ce_parse.h"); + $(LEX) -PcppExpYY -t constexp.l | $(INCBUFSIZE) >ce_lex.cpp + +#$ GenerateDep("ce_parse.cpp","constexp.y"); + $(YACC) -l -p cppExpYY constexp.y -o ce_parse.cpp + +#$ GenerateDep("ce_parse.h","constexp.y"); + $(YACC) -l -d -p cppExpYY constexp.y -o ce_parse.c + -rm ce_parse.c + +#$ GenerateDep("vhdlscanner.cpp","vhdlscanner.l","vhdlparser.h"); + $(LEX) -i -PvhdlScanYY -t vhdlscanner.l | $(INCBUFSIZE) >vhdlscanner.cpp + +#$ GenerateDep("vhdlparser.cpp","vhdlparser.y"); + $(YACC) -l -p vhdlScanYY vhdlparser.y -o vhdlparser.cpp + +#$ GenerateDep("vhdlparser.h","vhdlparser.y"); + $(YACC) -l -d -p vhdlScanYY vhdlparser.y -o vhdlparser.c + -rm vhdlparser.c + +#$ GenerateDep("layout.cpp","layout_default.h"); + +TO_C_CMD=sed -e "s/\\\\/\\\\\\\\/g" -e "s/\"/\\\\\"/g" -e "s/^/\"/g" -e "s/$$/\\\\n\"/g" + +index_xsd.h: index.xsd + cat index.xsd | $(TO_C_CMD) >index_xsd.h + +compound_xsd.h: compound.xsd + cat compound.xsd | $(TO_C_CMD) >compound_xsd.h + +layout_default.h: layout_default.xml + cat layout_default.xml | $(TO_C_CMD) >layout_default.h + +header_html.h: header.html + cat header.html | $(TO_C_CMD) >header_html.h + +footer_html.h: footer.html + cat footer.html | $(TO_C_CMD) >footer_html.h + +search_functions_php.h: search_functions.php + cat search_functions.php | $(TO_C_CMD) >search_functions_php.h + +search_opensearch_php.h: search_opensearch.php + cat search_opensearch.php | $(TO_C_CMD) >search_opensearch_php.h + +search_js.h: search.js + cat search.js | $(TO_C_CMD) >search_js.h + +search_css.h: search.css + cat search.css | $(TO_C_CMD) >search_css.h + +doxygen_css.h: doxygen.css + cat doxygen.css | $(TO_C_CMD) >doxygen_css.h + +navtree_js.h: navtree.js + cat navtree.js | $(TO_C_CMD) >navtree_js.h + +navindex_js.h: navindex.js + cat navindex.js | $(TO_C_CMD) >navindex_js.h + +resize_js.h: resize.js + cat resize.js | $(TO_C_CMD) >resize_js.h + +jquery_js.h: jquery.js + cat jquery.js | $(TO_C_CMD) >jquery_js.h + +jquery_ui_js.h: jquery_ui.js + cat jquery_ui.js | $(TO_C_CMD) >jquery_ui_js.h + +jquery_fx_js.h: jquery_fx.js + cat jquery_fx.js | $(TO_C_CMD) >jquery_fx_js.h + +sizzle_js.h: sizzle.js + cat sizzle.js | $(TO_C_CMD) >sizzle_js.h + +navtree_css.h: navtree.css + cat navtree.css | $(TO_C_CMD) >navtree_css.h + +svgpan_js.h: svgpan.js + cat svgpan.js | $(TO_C_CMD) >svgpan_js.h + +doxygen_bst.h: doxygen.bst + cat doxygen.bst | $(TO_C_CMD) >doxygen_bst.h + +bib2xhtml.h: bib2xhtml.pl + cat bib2xhtml.pl | $(TO_C_CMD) >bib2xhtml.h + + diff --git a/trunk/src/lockingptr.h b/trunk/src/lockingptr.h new file mode 100644 index 0000000..5fc328d --- /dev/null +++ b/trunk/src/lockingptr.h @@ -0,0 +1,162 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#ifndef LOCKINGPTR_H +#define LOCKINGPTR_H + +/*! @brief Abstract interface for lockable objects. + * + * By implementing this interface, a smart pointer can be created which + * will lock this object. This is used to prevent that an internal pointer + * owned by a lockable object would become invalid when the object is removed from + * memory, leaving the client with an invalid pointer. By letting the client use + * a smart pointer instead of the real object the object will be locked into + * memory until the pointer is no longer used, at which point the owner object will be + * unlock and can be removed from memory. + */ +class LockableObj +{ + public: + LockableObj() : m_lockCount(0) {} + virtual ~LockableObj() {} + + /*! Returns TRUE if the object is currently locked. */ + bool isLocked() const { return m_lockCount>0; } + +//VC++6.0 workaround +// protected: + /*! Called when the object is locked. */ + virtual void lock() const = 0; + + /*! Called when the object is unlocked. */ + virtual void unlock() const = 0; + +//VC++6.0 workaround +// private: +// template friend class LockingPtr; + int m_lockCount; +}; + +/*! @brief Smart pointer which keeps a lock on the owner of the pointer. + * + * With the pointer an owner object derived from LockableObj is associated. + * As long as the smart object exists it will keep a lock on the obj by calling + * LockableObj::lock(). Smart pointers can be copied and passed by value. As + * soon as there or no more smart pointer references to the object, + * LockableObj::unlock() will be called automatically. + */ +template class LockingPtr +{ + LockableObj *m_owner; + const T *m_ptr; + + public: + /*! Creates a smart pointer for pointer \a p owned by object \a o. + */ + LockingPtr(const LockableObj *o,const T* p) + { + if (o->m_lockCount==0) o->lock(); + m_owner = (LockableObj *)o; + m_owner->m_lockCount++; + m_ptr = p; + } + + /*! Copies the smart pointer \a lp + */ + LockingPtr(const LockingPtr &lp) + { + m_ptr = lp.m_ptr; + m_owner = lp.m_owner; + m_owner->m_lockCount++; + } + + /*! Assigns the smart pointer \a lp + */ + LockingPtr &operator=(const LockingPtr &lp) + { + m_owner->m_lockCount--; + if (m_owner->m_lockCount==0) // no more references + { + m_owner->unlock(); + } + m_ptr = lp.m_ptr; + m_owner = lp.m_owner; + m_owner->m_lockCount++; + return *this; + } + + /*! Destroys the smart pointer, will unlock the owner. + */ + ~LockingPtr() + { + m_owner->m_lockCount--; + if (m_owner->m_lockCount==0) // no more references + { + m_owner->unlock(); + } + } + + bool isNull() const + { + return m_ptr==0; + } + + bool operator!() const + { + return !m_ptr; + } + + bool operator==(T *p) const + { + return m_ptr==p; + } + + bool operator==(const LockingPtr &lp) const + { + return m_ptr==lp.m_ptr; + } + + bool operator!=(T *p) const + { + return m_ptr!=p; + } + + bool operator!=(const LockingPtr &lp) const + { + return m_ptr!=lp.m_ptr; + } + + /*! Dereference operator */ + const T& operator* () const + { + return *m_ptr; + } + + T* pointer() const + { + return (T*)m_ptr; + } + + /*! Pointer operator */ + T* operator-> () const + { + return (T*)m_ptr; + } +}; + +#endif // LOCKINGPTR_H + diff --git a/trunk/src/lodepng.cpp b/trunk/src/lodepng.cpp new file mode 100644 index 0000000..638dbf4 --- /dev/null +++ b/trunk/src/lodepng.cpp @@ -0,0 +1,4158 @@ +/* +LodePNG version 20080927 + +Copyright (c) 2005-2008 Lode Vandevenne + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. +*/ + +/* +The manual and changelog can be found in the header file "lodepng.h" +You are free to name this file lodepng.cpp or lodepng.c depending on your usage. +*/ + +#include "lodepng.h" +#include "portable.h" + +#define USE_BRUTE_FORCE_ENCODING 1 + +#define VERSION_STRING "20080927" + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / Tools For C / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +/* +About these tools (vector, uivector, ucvector and string): +-LodePNG was originally written in C++. The vectors replace the std::vectors that were used in the C++ version. +-The string tools are made to avoid problems with compilers that declare things like strncat as deprecated. +-They're not used in the interface, only internally in this file, so all their functions are made static. +*/ + +#ifdef LODEPNG_COMPILE_ZLIB +#ifdef LODEPNG_COMPILE_ENCODER + +typedef struct vector /*this one is used only by the deflate compressor*/ +{ + void* data; + size_t size; /*in groups of bytes depending on type*/ + size_t allocsize; /*in bytes*/ + unsigned typesize; /*sizeof the type you store in data*/ +} vector; + +static unsigned vector_resize(vector* p, size_t size) /*returns 1 if success, 0 if failure ==> nothing done*/ +{ + if(size * p->typesize > p->allocsize) + { + size_t newsize = size * p->typesize * 2; + void* data = realloc(p->data, newsize); + if(data) + { + p->allocsize = newsize; + p->data = data; + p->size = size; + } + else return 0; + } + else p->size = size; + return 1; +} + +static unsigned vector_resized(vector* p, size_t size, void dtor(void*)) /*resize and use destructor on elements if it gets smaller*/ +{ + size_t i; + if(size < p->size) for(i = size; i < p->size; i++) dtor(&((char*)(p->data))[i * p->typesize]); + return vector_resize(p, size); +} + +static void vector_cleanup(void* p) +{ + ((vector*)p)->size = ((vector*)p)->allocsize = 0; + free(((vector*)p)->data); + ((vector*)p)->data = NULL; +} + +static void vector_cleanupd(vector* p, void dtor(void*)) /*clear and use destructor on elements*/ +{ + vector_resized(p, 0, dtor); + vector_cleanup(p); +} + +static void vector_init(vector* p, unsigned typesize) +{ + p->data = NULL; + p->size = p->allocsize = 0; + p->typesize = typesize; +} + +static void vector_swap(vector* p, vector* q) /*they're supposed to have the same typesize*/ +{ + size_t tmp; + void* tmpp; + tmp = p->size; p->size = q->size; q->size = tmp; + tmp = p->allocsize; p->allocsize = q->allocsize; q->allocsize = tmp; + tmpp = p->data; p->data = q->data; q->data = tmpp; +} + +static void* vector_get(vector* p, size_t index) +{ + return &((char*)p->data)[index * p->typesize]; +} +#endif /*LODEPNG_COMPILE_ENCODER*/ +#endif /*LODEPNG_COMPILE_ZLIB*/ + +/* /////////////////////////////////////////////////////////////////////////// */ + +#ifdef LODEPNG_COMPILE_ZLIB +typedef struct uivector +{ + unsigned* data; + size_t size; /*size in number of unsigned longs*/ + size_t allocsize; /*allocated size in bytes*/ +} uivector; + +static void uivector_cleanup(void* p) +{ + ((uivector*)p)->size = ((uivector*)p)->allocsize = 0; + free(((uivector*)p)->data); + ((uivector*)p)->data = NULL; +} + +static unsigned uivector_resize(uivector* p, size_t size) /*returns 1 if success, 0 if failure ==> nothing done*/ +{ + if(size * sizeof(unsigned) > p->allocsize) + { + size_t newsize = size * sizeof(unsigned) * 2; + void* data = realloc(p->data, newsize); + if(data) + { + p->allocsize = newsize; + p->data = (unsigned*)data; + p->size = size; + } + else return 0; + } + else p->size = size; + return 1; +} + +static unsigned uivector_resizev(uivector* p, size_t size, unsigned value) /*resize and give all new elements the value*/ +{ + size_t oldsize = p->size, i; + if(!uivector_resize(p, size)) return 0; + for(i = oldsize; i < size; i++) p->data[i] = value; + return 1; +} + +static void uivector_init(uivector* p) +{ + p->data = NULL; + p->size = p->allocsize = 0; +} + +#ifdef LODEPNG_COMPILE_ENCODER +static unsigned uivector_push_back(uivector* p, unsigned c) /*returns 1 if success, 0 if failure ==> nothing done*/ +{ + if(!uivector_resize(p, p->size + 1)) return 0; + p->data[p->size - 1] = c; + return 1; +} + +static unsigned uivector_copy(uivector* p, const uivector* q) /*copy q to p, returns 1 if success, 0 if failure ==> nothing done*/ +{ + size_t i; + if(!uivector_resize(p, q->size)) return 0; + for(i = 0; i < q->size; i++) p->data[i] = q->data[i]; + return 1; +} + +static void uivector_swap(uivector* p, uivector* q) +{ + size_t tmp; + unsigned* tmpp; + tmp = p->size; p->size = q->size; q->size = tmp; + tmp = p->allocsize; p->allocsize = q->allocsize; q->allocsize = tmp; + tmpp = p->data; p->data = q->data; q->data = tmpp; +} +#endif /*LODEPNG_COMPILE_ENCODER*/ +#endif /*LODEPNG_COMPILE_ZLIB*/ + +/* /////////////////////////////////////////////////////////////////////////// */ + +typedef struct ucvector +{ + unsigned char* data; + size_t size; /*used size*/ + size_t allocsize; /*allocated size*/ +} ucvector; + +static void ucvector_cleanup(void* p) +{ + ((ucvector*)p)->size = ((ucvector*)p)->allocsize = 0; + free(((ucvector*)p)->data); + ((ucvector*)p)->data = NULL; +} + +static unsigned ucvector_resize(ucvector* p, size_t size) /*returns 1 if success, 0 if failure ==> nothing done*/ +{ + if(size * sizeof(unsigned) > p->allocsize) + { + size_t newsize = size * sizeof(unsigned) * 2; + void* data = realloc(p->data, newsize); + if(data) + { + p->allocsize = newsize; + p->data = (unsigned char*)data; + p->size = size; + } + else return 0; /*error: not enough memory*/ + } + else p->size = size; + return 1; +} + +#ifdef LODEPNG_COMPILE_DECODER +#ifdef LODEPNG_COMPILE_PNG +static unsigned ucvector_resizev(ucvector* p, size_t size, unsigned char value) /*resize and give all new elements the value*/ +{ + size_t oldsize = p->size, i; + if(!ucvector_resize(p, size)) return 0; + for(i = oldsize; i < size; i++) p->data[i] = value; + return 1; +} +#endif /*LODEPNG_COMPILE_PNG*/ +#endif /*LODEPNG_COMPILE_DECODER*/ + +static void ucvector_init(ucvector* p) +{ + p->data = NULL; + p->size = p->allocsize = 0; +} + +#ifdef LODEPNG_COMPILE_ZLIB +/*you can both convert from vector to buffer&size and vica versa*/ +static void ucvector_init_buffer(ucvector* p, unsigned char* buffer, size_t size) +{ + p->data = buffer; + p->allocsize = p->size = size; +} +#endif /*LODEPNG_COMPILE_ZLIB*/ + +static unsigned ucvector_push_back(ucvector* p, unsigned char c) /*returns 1 if success, 0 if failure ==> nothing done*/ +{ + if(!ucvector_resize(p, p->size + 1)) return 0; + p->data[p->size - 1] = c; + return 1; +} + +/* /////////////////////////////////////////////////////////////////////////// */ + +#ifdef LODEPNG_COMPILE_PNG +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS +static unsigned string_resize(char** out, size_t size) /*returns 1 if success, 0 if failure ==> nothing done*/ +{ + char* data = (char*)realloc(*out, size + 1); + if(data) + { + data[size] = 0; /*null termination char*/ + *out = data; + } + return data != 0; +} + +static void string_init(char** out) /*init a {char*, size_t} pair for use as string*/ +{ + *out = NULL; + string_resize(out, 0); +} + +static void string_cleanup(char** out) /*free the above pair again*/ +{ + free(*out); + *out = NULL; +} + +static void string_set(char** out, const char* in) +{ + size_t insize = strlen(in), i = 0; + if(string_resize(out, insize)) for(i = 0; i < insize; i++) (*out)[i] = in[i]; +} +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ +#endif /*LODEPNG_COMPILE_PNG*/ + +#ifdef LODEPNG_COMPILE_ZLIB + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / Reading and writing single bits and bytes from/to stream for Deflate / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +#ifdef LODEPNG_COMPILE_ENCODER +static void addBitToStream(size_t* bitpointer, ucvector* bitstream, unsigned char bit) +{ + if((*bitpointer) % 8 == 0) ucvector_push_back(bitstream, 0); /*add a new byte at the end*/ + (bitstream->data[bitstream->size - 1]) |= (bit << ((*bitpointer) & 0x7)); /*earlier bit of huffman code is in a lesser significant bit of an earlier byte*/ + (*bitpointer)++; +} + +static void addBitsToStream(size_t* bitpointer, ucvector* bitstream, unsigned value, size_t nbits) +{ + size_t i; + for(i = 0; i < nbits; i++) addBitToStream(bitpointer, bitstream, (unsigned char)((value >> i) & 1)); +} + +static void addBitsToStreamReversed(size_t* bitpointer, ucvector* bitstream, unsigned value, size_t nbits) +{ + size_t i; + for(i = 0; i < nbits; i++) addBitToStream(bitpointer, bitstream, (unsigned char)((value >> (nbits - 1 - i)) & 1)); +} +#endif /*LODEPNG_COMPILE_ENCODER*/ + +#ifdef LODEPNG_COMPILE_DECODER +static unsigned char readBitFromStream(size_t* bitpointer, const unsigned char* bitstream) +{ + unsigned char result = (unsigned char)((bitstream[(*bitpointer) >> 3] >> ((*bitpointer) & 0x7)) & 1); + (*bitpointer)++; + return result; +} + +static unsigned readBitsFromStream(size_t* bitpointer, const unsigned char* bitstream, size_t nbits) +{ + unsigned result = 0, i; + for(i = 0; i < nbits; i++) result += ((unsigned)readBitFromStream(bitpointer, bitstream)) << i; + return result; +} +#endif /*LODEPNG_COMPILE_DECODER*/ + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / Deflate - Huffman / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +#define FIRST_LENGTH_CODE_INDEX 257 +#define LAST_LENGTH_CODE_INDEX 285 +#define NUM_DEFLATE_CODE_SYMBOLS 288 /*256 literals, the end code, some length codes, and 2 unused codes*/ +#define NUM_DISTANCE_SYMBOLS 32 /*the distance codes have their own symbols, 30 used, 2 unused*/ +#define NUM_CODE_LENGTH_CODES 19 /*the code length codes. 0-15: code lengths, 16: copy previous 3-6 times, 17: 3-10 zeros, 18: 11-138 zeros*/ + +static const unsigned LENGTHBASE[29] /*the base lengths represented by codes 257-285*/ + = {3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258}; +static const unsigned LENGTHEXTRA[29] /*the extra bits used by codes 257-285 (added to base length)*/ + = {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0}; +static const unsigned DISTANCEBASE[30] /*the base backwards distances (the bits of distance codes appear after length codes and use their own huffman tree)*/ + = {1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577}; +static const unsigned DISTANCEEXTRA[30] /*the extra bits of backwards distances (added to base)*/ + = {0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13}; +static const unsigned CLCL[NUM_CODE_LENGTH_CODES] /*the order in which "code length alphabet code lengths" are stored, out of this the huffman tree of the dynamic huffman tree lengths is generated*/ + = {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + +/* /////////////////////////////////////////////////////////////////////////// */ + +#ifdef LODEPNG_COMPILE_ENCODER +/*terminology used for the package-merge algorithm and the coin collector's problem*/ +typedef struct Coin /*a coin can be multiple coins (when they're merged)*/ +{ + uivector symbols; + float weight; /*the sum of all weights in this coin*/ +} Coin; + +static void Coin_init(Coin* c) +{ + uivector_init(&c->symbols); +} + +static void Coin_cleanup(void* c) /*void* so that this dtor can be given as function pointer to the vector resize function*/ +{ + uivector_cleanup(&((Coin*)c)->symbols); +} + +static void Coin_copy(Coin* c1, const Coin* c2) +{ + c1->weight = c2->weight; + uivector_copy(&c1->symbols, &c2->symbols); +} + +static void addCoins(Coin* c1, const Coin* c2) +{ + unsigned i; + for(i = 0; i < c2->symbols.size; i++) uivector_push_back(&c1->symbols, c2->symbols.data[i]); + c1->weight += c2->weight; +} + +static void Coin_sort(Coin* data, size_t amount) /*combsort*/ +{ + size_t gap = amount; + unsigned char swapped = 0; + while(gap > 1 || swapped) + { + size_t i; + gap = (gap * 10) / 13; /*shrink factor 1.3*/ + if(gap == 9 || gap == 10) gap = 11; /*combsort11*/ + if(gap < 1) gap = 1; + swapped = 0; + for(i = 0; i < amount - gap; i++) + { + size_t j = i + gap; + if(data[j].weight < data[i].weight) + { + float temp = data[j].weight; data[j].weight = data[i].weight; data[i].weight = temp; + uivector_swap(&data[i].symbols, &data[j].symbols); + swapped = 1; + } + } + } +} +#endif /*LODEPNG_COMPILE_ENCODER*/ + +typedef struct HuffmanTree +{ + uivector tree2d; + uivector tree1d; + uivector lengths; /*the lengths of the codes of the 1d-tree*/ + unsigned maxbitlen; /*maximum number of bits a single code can get*/ + unsigned numcodes; /*number of symbols in the alphabet = number of codes*/ +} HuffmanTree; + +/*function used for debug purposes*/ +/*#include +static void HuffmanTree_draw(HuffmanTree* tree) +{ + std::cout << "tree. length: " << tree->numcodes << " maxbitlen: " << tree->maxbitlen << std::endl; + for(size_t i = 0; i < tree->tree1d.size; i++) + { + if(tree->lengths.data[i]) + std::cout << i << " " << tree->tree1d.data[i] << " " << tree->lengths.data[i] << std::endl; + } + std::cout << std::endl; +}*/ + +static void HuffmanTree_init(HuffmanTree* tree) +{ + uivector_init(&tree->tree2d); + uivector_init(&tree->tree1d); + uivector_init(&tree->lengths); +} + +static void HuffmanTree_cleanup(HuffmanTree* tree) +{ + uivector_cleanup(&tree->tree2d); + uivector_cleanup(&tree->tree1d); + uivector_cleanup(&tree->lengths); +} + +/*the tree representation used by the decoder. return value is error*/ +static unsigned HuffmanTree_make2DTree(HuffmanTree* tree) +{ + unsigned nodefilled = 0; /*up to which node it is filled*/ + unsigned treepos = 0; /*position in the tree (1 of the numcodes columns)*/ + unsigned n, i; + + if(!uivector_resize(&tree->tree2d, tree->numcodes * 2)) return 9901; /*if failed return not enough memory error*/ + /*convert tree1d[] to tree2d[][]. In the 2D array, a value of 32767 means uninited, a value >= numcodes is an address to another bit, a value < numcodes is a code. The 2 rows are the 2 possible bit values (0 or 1), there are as many columns as codes - 1 + a good huffmann tree has N * 2 - 1 nodes, of which N - 1 are internal nodes. Here, the internal nodes are stored (what their 0 and 1 option point to). There is only memory for such good tree currently, if there are more nodes (due to too long length codes), error 55 will happen*/ + for(n = 0; n < tree->numcodes * 2; n++) tree->tree2d.data[n] = 32767; /*32767 here means the tree2d isn't filled there yet*/ + + for(n = 0; n < tree->numcodes; n++) /*the codes*/ + for(i = 0; i < tree->lengths.data[n]; i++) /*the bits for this code*/ + { + unsigned char bit = (unsigned char)((tree->tree1d.data[n] >> (tree->lengths.data[n] - i - 1)) & 1); + if(treepos > tree->numcodes - 2) return 55; /*error 55: oversubscribed; see description in header*/ + if(tree->tree2d.data[2 * treepos + bit] == 32767) /*not yet filled in*/ + { + if(i + 1 == tree->lengths.data[n]) /*last bit*/ + { + tree->tree2d.data[2 * treepos + bit] = n; /*put the current code in it*/ + treepos = 0; + } + else /*put address of the next step in here, first that address has to be found of course (it's just nodefilled + 1)...*/ + { + nodefilled++; + tree->tree2d.data[2 * treepos + bit] = nodefilled + tree->numcodes; /*addresses encoded with numcodes added to it*/ + treepos = nodefilled; + } + } + else treepos = tree->tree2d.data[2 * treepos + bit] - tree->numcodes; + } + for(n = 0; n < tree->numcodes * 2; n++) if(tree->tree2d.data[n] == 32767) tree->tree2d.data[n] = 0; /*remove possible remaining 32767's*/ + + return 0; +} + +static unsigned HuffmanTree_makeFromLengths2(HuffmanTree* tree) /*given that numcodes, lengths and maxbitlen are already filled in correctly. return value is error.*/ +{ + uivector blcount; + uivector nextcode; + unsigned bits, n, error = 0; + + uivector_init(&blcount); + uivector_init(&nextcode); + if(!uivector_resize(&tree->tree1d, tree->numcodes) + || !uivector_resizev(&blcount, tree->maxbitlen + 1, 0) + || !uivector_resizev(&nextcode, tree->maxbitlen + 1, 0)) + error = 9902; + + if(!error) + { + /*step 1: count number of instances of each code length*/ + for(bits = 0; bits < tree->numcodes; bits++) blcount.data[tree->lengths.data[bits]]++; + /*step 2: generate the nextcode values*/ + for(bits = 1; bits <= tree->maxbitlen; bits++) nextcode.data[bits] = (nextcode.data[bits - 1] + blcount.data[bits - 1]) << 1; + /*step 3: generate all the codes*/ + for(n = 0; n < tree->numcodes; n++) if(tree->lengths.data[n] != 0) tree->tree1d.data[n] = nextcode.data[tree->lengths.data[n]]++; + } + + uivector_cleanup(&blcount); + uivector_cleanup(&nextcode); + + if(!error) return HuffmanTree_make2DTree(tree); + else return error; +} + +/*given the code lengths (as stored in the PNG file), generate the tree as defined by Deflate. maxbitlen is the maximum bits that a code in the tree can have. return value is error.*/ +static unsigned HuffmanTree_makeFromLengths(HuffmanTree* tree, const unsigned* bitlen, size_t numcodes, unsigned maxbitlen) +{ + unsigned i; + if(!uivector_resize(&tree->lengths, numcodes)) return 9903; + for(i = 0; i < numcodes; i++) tree->lengths.data[i] = bitlen[i]; + tree->numcodes = (unsigned)numcodes; /*number of symbols*/ + tree->maxbitlen = maxbitlen; + return HuffmanTree_makeFromLengths2(tree); +} + +#ifdef LODEPNG_COMPILE_ENCODER +static unsigned HuffmanTree_fillInCoins(vector* coins, const unsigned* frequencies, unsigned numcodes, size_t sum) +{ + unsigned i; + for(i = 0; i < numcodes; i++) + { + Coin* coin; + if(frequencies[i] == 0) continue; /*it's important to exclude symbols that aren't present*/ + if(!vector_resize(coins, coins->size + 1)) { vector_cleanup(coins); return 9904; } + coin = (Coin*)(vector_get(coins, coins->size - 1)); + Coin_init(coin); + coin->weight = frequencies[i] / (float)sum; + uivector_push_back(&coin->symbols, i); + } + if(coins->size) Coin_sort((Coin*)coins->data, coins->size); + return 0; +} + +static unsigned HuffmanTree_makeFromFrequencies(HuffmanTree* tree, const unsigned* frequencies, size_t numcodes, unsigned maxbitlen) +{ + unsigned i, j; + size_t sum = 0, numpresent = 0; + unsigned error = 0; + + vector prev_row; /*type Coin, the previous row of coins*/ + vector coins; /*type Coin, the coins of the currently calculated row*/ + + tree->maxbitlen = maxbitlen; + + for(i = 0; i < numcodes; i++) + { + if(frequencies[i] > 0) + { + numpresent++; + sum += frequencies[i]; + } + } + + if(numcodes == 0) return 80; /*error: a tree of 0 symbols is not supposed to be made*/ + tree->numcodes = (unsigned)numcodes; /*number of symbols*/ + uivector_resize(&tree->lengths, 0); + if(!uivector_resizev(&tree->lengths, tree->numcodes, 0)) return 9905; + + if(numpresent == 0) /*there are no symbols at all, in that case add one symbol of value 0 to the tree (see RFC 1951 section 3.2.7) */ + { + tree->lengths.data[0] = 1; + return HuffmanTree_makeFromLengths2(tree); + } + else if(numpresent == 1) /*the package merge algorithm gives wrong results if there's only one symbol (theoretically 0 bits would then suffice, but we need a proper symbol for zlib)*/ + { + for(i = 0; i < numcodes; i++) if(frequencies[i]) tree->lengths.data[i] = 1; + return HuffmanTree_makeFromLengths2(tree); + } + + vector_init(&coins, sizeof(Coin)); + vector_init(&prev_row, sizeof(Coin)); + + /*Package-Merge algorithm represented by coin collector's problem + For every symbol, maxbitlen coins will be created*/ + + /*first row, lowest denominator*/ + error = HuffmanTree_fillInCoins(&coins, frequencies, tree->numcodes, sum); + if(!error) + { + for(j = 1; j <= maxbitlen && !error; j++) /*each of the remaining rows*/ + { + vector_swap(&coins, &prev_row); /*swap instead of copying*/ + if(!vector_resized(&coins, 0, Coin_cleanup)) { error = 9906; break; } + + for(i = 0; i + 1 < prev_row.size; i += 2) + { + if(!vector_resize(&coins, coins.size + 1)) { error = 9907; break; } + Coin_init((Coin*)vector_get(&coins, coins.size - 1)); + Coin_copy((Coin*)vector_get(&coins, coins.size - 1), (Coin*)vector_get(&prev_row, i)); + addCoins((Coin*)vector_get(&coins, coins.size - 1), (Coin*)vector_get(&prev_row, i + 1)); /*merge the coins into packages*/ + } + if(j < maxbitlen) + { + error = HuffmanTree_fillInCoins(&coins, frequencies, tree->numcodes, sum); + } + } + } + + if(!error) + { + /*keep the coins with lowest weight, so that they add up to the amount of symbols - 1*/ + vector_resized(&coins, numpresent - 1, Coin_cleanup); + + /*calculate the lenghts of each symbol, as the amount of times a coin of each symbol is used*/ + for(i = 0; i < coins.size; i++) + { + Coin* coin = (Coin*)vector_get(&coins, i); + for(j = 0; j < coin->symbols.size; j++) tree->lengths.data[coin->symbols.data[j]]++; + } + + error = HuffmanTree_makeFromLengths2(tree); + } + + vector_cleanupd(&coins, Coin_cleanup); + vector_cleanupd(&prev_row, Coin_cleanup); + + return error; +} + +static unsigned HuffmanTree_getCode(const HuffmanTree* tree, unsigned index) { return tree->tree1d.data[index]; } +static unsigned HuffmanTree_getLength(const HuffmanTree* tree, unsigned index) { return tree->lengths.data[index]; } +#endif /*LODEPNG_COMPILE_ENCODER*/ + +/*get the tree of a deflated block with fixed tree, as specified in the deflate specification*/ +static unsigned generateFixedTree(HuffmanTree* tree) +{ + unsigned i, error = 0; + uivector bitlen; + uivector_init(&bitlen); + if(!uivector_resize(&bitlen, NUM_DEFLATE_CODE_SYMBOLS)) error = 9909; + + if(!error) + { + /*288 possible codes: 0-255=literals, 256=endcode, 257-285=lengthcodes, 286-287=unused*/ + for(i = 0; i <= 143; i++) bitlen.data[i] = 8; + for(i = 144; i <= 255; i++) bitlen.data[i] = 9; + for(i = 256; i <= 279; i++) bitlen.data[i] = 7; + for(i = 280; i <= 287; i++) bitlen.data[i] = 8; + + error = HuffmanTree_makeFromLengths(tree, bitlen.data, NUM_DEFLATE_CODE_SYMBOLS, 15); + } + + uivector_cleanup(&bitlen); + return error; +} + +static unsigned generateDistanceTree(HuffmanTree* tree) +{ + unsigned i, error = 0; + uivector bitlen; + uivector_init(&bitlen); + if(!uivector_resize(&bitlen, NUM_DISTANCE_SYMBOLS)) error = 9910; + + /*there are 32 distance codes, but 30-31 are unused*/ + if(!error) + { + for(i = 0; i < NUM_DISTANCE_SYMBOLS; i++) bitlen.data[i] = 5; + error = HuffmanTree_makeFromLengths(tree, bitlen.data, NUM_DISTANCE_SYMBOLS, 15); + } + uivector_cleanup(&bitlen); + return error; +} + +#ifdef LODEPNG_COMPILE_DECODER +/*Decodes a symbol from the tree +if decoded is true, then result contains the symbol, otherwise it contains something unspecified (because the symbol isn't fully decoded yet) +bit is the bit that was just read from the stream +you have to decode a full symbol (let the decode function return true) before you can try to decode another one, otherwise the state isn't reset +return value is error.*/ +static unsigned HuffmanTree_decode(const HuffmanTree* tree, unsigned* decoded, unsigned* result, unsigned* treepos, unsigned char bit) +{ + if((*treepos) >= tree->numcodes) return 11; /*error: it appeared outside the codetree*/ + + (*result) = tree->tree2d.data[2 * (*treepos) + bit]; + (*decoded) = ((*result) < tree->numcodes); + + if(*decoded) (*treepos) = 0; + else (*treepos) = (*result) - tree->numcodes; + + return 0; +} + +static unsigned huffmanDecodeSymbol(unsigned int* error, const unsigned char* in, size_t* bp, const HuffmanTree* codetree, size_t inlength) +{ + unsigned treepos = 0, decoded, ct; + for(;;) + { + unsigned char bit; + if(((*bp) & 0x07) == 0 && ((*bp) >> 3) > inlength) { *error = 10; return 0; } /*error: end of input memory reached without endcode*/ + bit = readBitFromStream(bp, in); + *error = HuffmanTree_decode(codetree, &decoded, &ct, &treepos, bit); + if(*error) return 0; /*stop, an error happened*/ + if(decoded) return ct; + } +} +#endif /*LODEPNG_COMPILE_DECODER*/ + +#ifdef LODEPNG_COMPILE_DECODER + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / Inflator / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +/*get the tree of a deflated block with fixed tree, as specified in the deflate specification*/ +static void getTreeInflateFixed(HuffmanTree* tree, HuffmanTree* treeD) +{ + /*error checking not done, this is fixed stuff, it works, it doesn't depend on the image*/ + generateFixedTree(tree); + generateDistanceTree(treeD); +} + +/*get the tree of a deflated block with dynamic tree, the tree itself is also Huffman compressed with a known tree*/ +static unsigned getTreeInflateDynamic(HuffmanTree* codetree, HuffmanTree* codetreeD, HuffmanTree* codelengthcodetree, + const unsigned char* in, size_t* bp, size_t inlength) +{ + /*make sure that length values that aren't filled in will be 0, or a wrong tree will be generated*/ + /*C-code note: use no "return" between ctor and dtor of an uivector!*/ + unsigned error = 0; + unsigned n, HLIT, HDIST, HCLEN, i; + uivector bitlen; + uivector bitlenD; + uivector codelengthcode; + + if((*bp) >> 3 >= inlength - 2) { return 49; } /*the bit pointer is or will go past the memory*/ + + HLIT = readBitsFromStream(bp, in, 5) + 257; /*number of literal/length codes + 257. Unlike the spec, the value 257 is added to it here already*/ + HDIST = readBitsFromStream(bp, in, 5) + 1; /*number of distance codes. Unlike the spec, the value 1 is added to it here already*/ + HCLEN = readBitsFromStream(bp, in, 4) + 4; /*number of code length codes. Unlike the spec, the value 4 is added to it here already*/ + + /*read the code length codes out of 3 * (amount of code length codes) bits*/ + uivector_init(&codelengthcode); + if(!uivector_resize(&codelengthcode, NUM_CODE_LENGTH_CODES)) error = 9911; + + if(!error) + { + for(i = 0; i < NUM_CODE_LENGTH_CODES; i++) + { + if(i < HCLEN) codelengthcode.data[CLCL[i]] = readBitsFromStream(bp, in, 3); + else codelengthcode.data[CLCL[i]] = 0; /*if not, it must stay 0*/ + } + + error = HuffmanTree_makeFromLengths(codelengthcodetree, codelengthcode.data, codelengthcode.size, 7); + } + + uivector_cleanup(&codelengthcode); + if(error) return error; + + /*now we can use this tree to read the lengths for the tree that this function will return*/ + uivector_init(&bitlen); + uivector_resizev(&bitlen, NUM_DEFLATE_CODE_SYMBOLS, 0); + uivector_init(&bitlenD); + uivector_resizev(&bitlenD, NUM_DISTANCE_SYMBOLS, 0); + i = 0; + if(!bitlen.data || !bitlenD.data) error = 9912; + else while(i < HLIT + HDIST) /*i is the current symbol we're reading in the part that contains the code lengths of lit/len codes and dist codes*/ + { + unsigned code = huffmanDecodeSymbol(&error, in, bp, codelengthcodetree, inlength); + if(error) break; + + if(code <= 15) /*a length code*/ + { + if(i < HLIT) bitlen.data[i] = code; + else bitlenD.data[i - HLIT] = code; + i++; + } + else if(code == 16) /*repeat previous*/ + { + unsigned replength = 3; /*read in the 2 bits that indicate repeat length (3-6)*/ + unsigned value; /*set value to the previous code*/ + + if((*bp) >> 3 >= inlength) { error = 50; break; } /*error, bit pointer jumps past memory*/ + + replength += readBitsFromStream(bp, in, 2); + + if((i - 1) < HLIT) value = bitlen.data[i - 1]; + else value = bitlenD.data[i - HLIT - 1]; + /*repeat this value in the next lengths*/ + for(n = 0; n < replength; n++) + { + if(i >= HLIT + HDIST) { error = 13; break; } /*error: i is larger than the amount of codes*/ + if(i < HLIT) bitlen.data[i] = value; + else bitlenD.data[i - HLIT] = value; + i++; + } + } + else if(code == 17) /*repeat "0" 3-10 times*/ + { + unsigned replength = 3; /*read in the bits that indicate repeat length*/ + if((*bp) >> 3 >= inlength) { error = 50; break; } /*error, bit pointer jumps past memory*/ + + replength += readBitsFromStream(bp, in, 3); + + /*repeat this value in the next lengths*/ + for(n = 0; n < replength; n++) + { + if(i >= HLIT + HDIST) { error = 14; break; } /*error: i is larger than the amount of codes*/ + if(i < HLIT) bitlen.data[i] = 0; + else bitlenD.data[i - HLIT] = 0; + i++; + } + } + else if(code == 18) /*repeat "0" 11-138 times*/ + { + unsigned replength = 11; /*read in the bits that indicate repeat length*/ + if((*bp) >> 3 >= inlength) { error = 50; break; } /*error, bit pointer jumps past memory*/ + replength += readBitsFromStream(bp, in, 7); + + /*repeat this value in the next lengths*/ + for(n = 0; n < replength; n++) + { + if(i >= HLIT + HDIST) { error = 15; break; } /*error: i is larger than the amount of codes*/ + if(i < HLIT) bitlen.data[i] = 0; + else bitlenD.data[i - HLIT] = 0; + i++; + } + } + else { error = 16; break; } /*error: somehow an unexisting code appeared. This can never happen.*/ + } + + if(!error && bitlen.data[256] == 0) { error = 64; } /*the length of the end code 256 must be larger than 0*/ + + /*now we've finally got HLIT and HDIST, so generate the code trees, and the function is done*/ + if(!error) error = HuffmanTree_makeFromLengths(codetree, &bitlen.data[0], bitlen.size, 15); + if(!error) error = HuffmanTree_makeFromLengths(codetreeD, &bitlenD.data[0], bitlenD.size, 15); + + uivector_cleanup(&bitlen); + uivector_cleanup(&bitlenD); + + return error; +} + +/*inflate a block with dynamic of fixed Huffman tree*/ +static unsigned inflateHuffmanBlock(ucvector* out, const unsigned char* in, size_t* bp, size_t* pos, size_t inlength, unsigned btype) +{ + unsigned endreached = 0, error = 0; + HuffmanTree codetree; /*287, the code tree for Huffman codes*/ + HuffmanTree codetreeD; /*31, the code tree for distance codes*/ + + HuffmanTree_init(&codetree); + HuffmanTree_init(&codetreeD); + + if(btype == 1) getTreeInflateFixed(&codetree, &codetreeD); + else if(btype == 2) + { + HuffmanTree codelengthcodetree; /*18, the code tree for code length codes*/ + HuffmanTree_init(&codelengthcodetree); + error = getTreeInflateDynamic(&codetree, &codetreeD, &codelengthcodetree, in, bp, inlength); + HuffmanTree_cleanup(&codelengthcodetree); + } + + while(!endreached && !error) + { + unsigned code = huffmanDecodeSymbol(&error, in, bp, &codetree, inlength); + if(error) break; /*some error happened in the above function*/ + if(code == 256) endreached = 1; /*end code*/ + else if(code <= 255) /*literal symbol*/ + { + if((*pos) >= out->size) ucvector_resize(out, ((*pos) + 1) * 2); /*reserve more room at once*/ + if((*pos) >= out->size) { error = 9913; break; } /*not enough memory*/ + out->data[(*pos)] = (unsigned char)(code); + (*pos)++; + } + else if(code >= FIRST_LENGTH_CODE_INDEX && code <= LAST_LENGTH_CODE_INDEX) /*length code*/ + { + /*part 1: get length base*/ + size_t length = LENGTHBASE[code - FIRST_LENGTH_CODE_INDEX]; + unsigned codeD, distance, numextrabitsD; + size_t start, forward, backward, numextrabits; + + /*part 2: get extra bits and add the value of that to length*/ + numextrabits = LENGTHEXTRA[code - FIRST_LENGTH_CODE_INDEX]; + if(((*bp) >> 3) >= inlength) { error = 51; break; } /*error, bit pointer will jump past memory*/ + length += readBitsFromStream(bp, in, numextrabits); + + /*part 3: get distance code*/ + codeD = huffmanDecodeSymbol(&error, in, bp, &codetreeD, inlength); + if(error) break; + if(codeD > 29) { error = 18; break; } /*error: invalid distance code (30-31 are never used)*/ + distance = DISTANCEBASE[codeD]; + + /*part 4: get extra bits from distance*/ + numextrabitsD = DISTANCEEXTRA[codeD]; + if(((*bp) >> 3) >= inlength) { error = 51; break; } /*error, bit pointer will jump past memory*/ + distance += readBitsFromStream(bp, in, numextrabitsD); + + /*part 5: fill in all the out[n] values based on the length and dist*/ + start = (*pos); + backward = start - distance; + if((*pos) + length >= out->size) ucvector_resize(out, ((*pos) + length) * 2); /*reserve more room at once*/ + if((*pos) + length >= out->size) { error = 9914; break; } /*not enough memory*/ + + for(forward = 0; forward < length; forward++) + { + out->data[(*pos)] = out->data[backward]; + (*pos)++; + backward++; + if(backward >= start) backward = start - distance; + } + } + } + + HuffmanTree_cleanup(&codetree); + HuffmanTree_cleanup(&codetreeD); + + return error; +} + +static unsigned inflateNoCompression(ucvector* out, const unsigned char* in, size_t* bp, size_t* pos, size_t inlength) +{ + /*go to first boundary of byte*/ + size_t p; + unsigned LEN, NLEN, n, error = 0; + while(((*bp) & 0x7) != 0) (*bp)++; + p = (*bp) / 8; /*byte position*/ + + /*read LEN (2 bytes) and NLEN (2 bytes)*/ + if(p >= inlength - 4) return 52; /*error, bit pointer will jump past memory*/ + LEN = in[p] + 256 * in[p + 1]; p += 2; + NLEN = in[p] + 256 * in[p + 1]; p += 2; + + /*check if 16-bit NLEN is really the one's complement of LEN*/ + if(LEN + NLEN != 65535) return 21; /*error: NLEN is not one's complement of LEN*/ + + if((*pos) + LEN >= out->size) { if(!ucvector_resize(out, (*pos) + LEN)) return 9915; } + + /*read the literal data: LEN bytes are now stored in the out buffer*/ + if(p + LEN > inlength) return 23; /*error: reading outside of in buffer*/ + for(n = 0; n < LEN; n++) out->data[(*pos)++] = in[p++]; + + (*bp) = p * 8; + + return error; +} + +/*inflate the deflated data (cfr. deflate spec); return value is the error*/ +unsigned LodeFlate_inflate(ucvector* out, const unsigned char* in, size_t insize, size_t inpos) +{ + size_t bp = 0; /*bit pointer in the "in" data, current byte is bp >> 3, current bit is bp & 0x7 (from lsb to msb of the byte)*/ + unsigned BFINAL = 0; + size_t pos = 0; /*byte position in the out buffer*/ + + unsigned error = 0; + + while(!BFINAL) + { + unsigned BTYPE; + if((bp >> 3) >= insize) return 52; /*error, bit pointer will jump past memory*/ + BFINAL = readBitFromStream(&bp, &in[inpos]); + BTYPE = 1 * readBitFromStream(&bp, &in[inpos]); BTYPE += 2 * readBitFromStream(&bp, &in[inpos]); + + if(BTYPE == 3) return 20; /*error: invalid BTYPE*/ + else if(BTYPE == 0) error = inflateNoCompression(out, &in[inpos], &bp, &pos, insize); /*no compression*/ + else error = inflateHuffmanBlock(out, &in[inpos], &bp, &pos, insize, BTYPE); /*compression, BTYPE 01 or 10*/ + if(error) return error; + } + + if(!ucvector_resize(out, pos)) error = 9916; /*Only now we know the true size of out, resize it to that*/ + + return error; +} + +#endif /*LODEPNG_COMPILE_DECODER*/ + +#ifdef LODEPNG_COMPILE_ENCODER + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / Deflator / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +static const size_t MAX_SUPPORTED_DEFLATE_LENGTH = 258; + +/*bitlen is the size in bits of the code*/ +static void addHuffmanSymbol(size_t* bp, ucvector* compressed, unsigned code, unsigned bitlen) +{ + addBitsToStreamReversed(bp, compressed, code, bitlen); +} + +/*search the index in the array, that has the largest value smaller than or equal to the given value, given array must be sorted (if no value is smaller, it returns the size of the given array)*/ +static size_t searchCodeIndex(const unsigned* array, size_t array_size, size_t value) +{ + /*linear search implementation*/ + /*for(size_t i = 1; i < array_size; i++) if(array[i] > value) return i - 1; + return array_size - 1;*/ + + /*binary search implementation (not that much faster) (precondition: array_size > 0)*/ + size_t left = 1; + size_t right = array_size - 1; + while(left <= right) + { + size_t mid = (left + right) / 2; + if(array[mid] <= value) left = mid + 1; /*the value to find is more to the right*/ + else if(array[mid - 1] > value) right = mid - 1; /*the value to find is more to the left*/ + else return mid - 1; + } + return array_size - 1; +} + +static void addLengthDistance(uivector* values, size_t length, size_t distance) +{ + /*values in encoded vector are those used by deflate: + 0-255: literal bytes + 256: end + 257-285: length/distance pair (length code, followed by extra length bits, distance code, extra distance bits) + 286-287: invalid*/ + + unsigned length_code = (unsigned)searchCodeIndex(LENGTHBASE, 29, length); + unsigned extra_length = (unsigned)(length - LENGTHBASE[length_code]); + unsigned dist_code = (unsigned)searchCodeIndex(DISTANCEBASE, 30, distance); + unsigned extra_distance = (unsigned)(distance - DISTANCEBASE[dist_code]); + + uivector_push_back(values, length_code + FIRST_LENGTH_CODE_INDEX); + uivector_push_back(values, extra_length); + uivector_push_back(values, dist_code); + uivector_push_back(values, extra_distance); +} + +#if USE_BRUTE_FORCE_ENCODING +#define encodeLZ77 encodeLZ77_brute +/*the "brute force" version of the encodeLZ7 algorithm, not used anymore, kept here for reference*/ +static unsigned encodeLZ77_brute(uivector* out, const unsigned char* in, size_t size, unsigned windowSize) +{ + size_t pos; + /*using pointer instead of vector for input makes it faster when NOT using optimization when compiling; no influence if optimization is used*/ + for(pos = 0; pos < size; pos++) + { + /*Phase 1: doxygen images often have long runs of the same color, try to find them*/ + const int minLength = 4; // Minimum length for a run to make sense + + if(pos < size - minLength * 4) + { + size_t p, fp; + size_t current_length; + + /*RGBA pixel run?*/ + p = pos; + fp = pos + 4; + current_length = 0; + + while(fp < size && in[p] == in[fp] && current_length < MAX_SUPPORTED_DEFLATE_LENGTH) + { + ++p; + ++fp; + ++current_length; + } + + if (current_length > (minLength - 1 ) * 4) /*worth using?*/ + { + uivector_push_back(out, in[pos ]); + uivector_push_back(out, in[pos + 1]); + uivector_push_back(out, in[pos + 2]); + uivector_push_back(out, in[pos + 3]); + addLengthDistance(out, current_length, 4); + + pos += current_length + 4 - 1; /*-1 for loop's pos++*/ + continue; + } + + /*RGB pixel run?*/ + p = pos; + fp = pos + 3; + current_length = 0; + + while(fp < size && in[p] == in[fp] && current_length < MAX_SUPPORTED_DEFLATE_LENGTH) + { + ++p; + ++fp; + ++current_length; + } + + if (current_length > (minLength - 1 ) * 3) /*worth using?*/ + { + uivector_push_back(out, in[pos ]); + uivector_push_back(out, in[pos + 1]); + uivector_push_back(out, in[pos + 2]); + addLengthDistance(out, current_length, 3); + + pos += current_length + 3 - 1; /*-1 for loop's pos++*/ + continue; + } + } + + size_t length = 0, offset = 0; /*the length and offset found for the current position*/ + size_t max_offset = pos < windowSize ? pos : windowSize; /*how far back to test*/ + size_t current_offset; + + /**search for the longest string**/ + for(current_offset = 1; current_offset < max_offset; current_offset++) /*search backwards through all possible distances (=offsets)*/ + { + size_t backpos = pos - current_offset; + if(in[backpos] == in[pos]) + { + /*test the next characters*/ + size_t current_length = 1; + size_t backtest = backpos + 1; + size_t foretest = pos + 1; + while(foretest < size && in[backtest] == in[foretest] && current_length < MAX_SUPPORTED_DEFLATE_LENGTH) /*maximum supporte length by deflate is max length*/ + { + if(backpos >= pos) backpos -= current_offset; /*continue as if we work on the decoded bytes after pos by jumping back before pos*/ + current_length++; + backtest++; + foretest++; + } + if(current_length > length) + { + length = current_length; /*the longest length*/ + offset = current_offset; /*the offset that is related to this longest length*/ + if(current_length == MAX_SUPPORTED_DEFLATE_LENGTH) break; /*you can jump out of this for loop once a length of max length is found (gives significant speed gain)*/ + } + } + } + + /**encode it as length/distance pair or literal value**/ + if(length < 3) /*only lengths of 3 or higher are supported as length/distance pair*/ + { + uivector_push_back(out, in[pos]); + } + else + { + addLengthDistance(out, length, offset); + pos += (length - 1); + } + } /*end of the loop through each character of input*/ + + return 0; +} +#endif + +static const unsigned HASH_NUM_VALUES = 65536; +static const unsigned HASH_NUM_CHARACTERS = 6; +static const unsigned HASH_SHIFT = 2; +/* +Good and fast values: HASH_NUM_VALUES=65536, HASH_NUM_CHARACTERS=6, HASH_SHIFT=2 +making HASH_NUM_CHARACTERS larger (like 8), makes the file size larger but is a bit faster +making HASH_NUM_CHARACTERS smaller (like 3), makes the file size smaller but is slower +*/ + +#if !defined(USE_BRUTE_FORCE_ENCODING) +static unsigned getHash(const unsigned char* data, size_t size, size_t pos) +{ + unsigned result = 0; + size_t amount, i; + if(pos >= size) return 0; + amount = HASH_NUM_CHARACTERS; if(pos + amount >= size) amount = size - pos; + for(i = 0; i < amount; i++) result ^= (data[pos + i] << (i * HASH_SHIFT)); + return result % HASH_NUM_VALUES; +} + +/*LZ77-encode the data using a hash table technique to let it encode faster. Return value is error code*/ +static unsigned encodeLZ77(uivector* out, const unsigned char* in, size_t size, unsigned windowSize) +{ + /**generate hash table**/ + vector table; /*HASH_NUM_VALUES uivectors; this represents what would be an std::vector > in C++*/ + uivector tablepos1, tablepos2; + unsigned pos, i, error = 0; + + vector_init(&table, sizeof(uivector)); + if(!vector_resize(&table, HASH_NUM_VALUES)) return 9917; + for(i = 0; i < HASH_NUM_VALUES; i++) + { + uivector* v = (uivector*)vector_get(&table, i); + uivector_init(v); + } + + /*remember start and end positions in the tables to searching in*/ + uivector_init(&tablepos1); + uivector_init(&tablepos2); + if(!uivector_resizev(&tablepos1, HASH_NUM_VALUES, 0)) error = 9918; + if(!uivector_resizev(&tablepos2, HASH_NUM_VALUES, 0)) error = 9919; + + if(!error) + { + for(pos = 0; pos < size; pos++) + { + unsigned length = 0, offset = 0; /*the length and offset found for the current position*/ + unsigned max_offset = pos < windowSize ? pos : windowSize; /*how far back to test*/ + unsigned tablepos; + + /*/search for the longest string*/ + /*first find out where in the table to start (the first value that is in the range from "pos - max_offset" to "pos")*/ + unsigned hash = getHash(in, size, pos); + if(!uivector_push_back((uivector*)vector_get(&table, hash), pos)) { error = 9920; break; } + + while(((uivector*)vector_get(&table, hash))->data[tablepos1.data[hash]] < pos - max_offset) tablepos1.data[hash]++; /*it now points to the first value in the table for which the index is larger than or equal to pos - max_offset*/ + while(((uivector*)vector_get(&table, hash))->data[tablepos2.data[hash]] < pos) tablepos2.data[hash]++; /*it now points to the first value in the table for which the index is larger than or equal to pos*/ + + for(tablepos = tablepos2.data[hash] - 1; tablepos >= tablepos1.data[hash] && tablepos < tablepos2.data[hash]; tablepos--) + { + unsigned backpos = ((uivector*)vector_get(&table, hash))->data[tablepos]; + unsigned current_offset = pos - backpos; + + /*test the next characters*/ + unsigned current_length = 0; + unsigned backtest = backpos; + unsigned foretest = pos; + while(foretest < size && in[backtest] == in[foretest] && current_length < MAX_SUPPORTED_DEFLATE_LENGTH) /*maximum supporte length by deflate is max length*/ + { + if(backpos >= pos) backpos -= current_offset; /*continue as if we work on the decoded bytes after pos by jumping back before pos*/ + current_length++; + backtest++; + foretest++; + } + if(current_length > length) + { + length = current_length; /*the longest length*/ + offset = current_offset; /*the offset that is related to this longest length*/ + if(current_length == MAX_SUPPORTED_DEFLATE_LENGTH) break; /*you can jump out of this for loop once a length of max length is found (gives significant speed gain)*/ + } + } + + /**encode it as length/distance pair or literal value**/ + if(length < 3) /*only lengths of 3 or higher are supported as length/distance pair*/ + { + if(!uivector_push_back(out, in[pos])) { error = 9921; break; } + } + else + { + unsigned j; + addLengthDistance(out, length, offset); + for(j = 0; j < length - 1; j++) + { + pos++; + if(!uivector_push_back((uivector*)vector_get(&table, getHash(in, size, pos)), pos)) { error = 9922; break; } + } + } + } /*end of the loop through each character of input*/ + } /*end of "if(!error)"*/ + + /*cleanup*/ + for(i = 0; i < table.size; i++) + { + uivector* v = (uivector*)vector_get(&table, i); + uivector_cleanup(v); + } + vector_cleanup(&table); + uivector_cleanup(&tablepos1); + uivector_cleanup(&tablepos2); + return error; +} +#endif + +/* /////////////////////////////////////////////////////////////////////////// */ + +static unsigned deflateNoCompression(ucvector* out, const unsigned char* data, size_t datasize) +{ + /*non compressed deflate block data: 1 bit BFINAL,2 bits BTYPE,(5 bits): it jumps to start of next byte, 2 bytes LEN, 2 bytes NLEN, LEN bytes literal DATA*/ + + size_t i, j, numdeflateblocks = datasize / 65536 + 1; + unsigned datapos = 0; + for(i = 0; i < numdeflateblocks; i++) + { + unsigned BFINAL, BTYPE, LEN, NLEN; + unsigned char firstbyte; + + BFINAL = (i == numdeflateblocks - 1); + BTYPE = 0; + + firstbyte = (unsigned char)(BFINAL + ((BTYPE & 1) << 1) + ((BTYPE & 2) << 1)); + ucvector_push_back(out, firstbyte); + + LEN = 65535; + if(datasize - datapos < 65535) LEN = (unsigned)datasize - datapos; + NLEN = 65535 - LEN; + + ucvector_push_back(out, (unsigned char)(LEN % 256)); + ucvector_push_back(out, (unsigned char)(LEN / 256)); + ucvector_push_back(out, (unsigned char)(NLEN % 256)); + ucvector_push_back(out, (unsigned char)(NLEN / 256)); + + /*Decompressed data*/ + for(j = 0; j < 65535 && datapos < datasize; j++) + { + ucvector_push_back(out, data[datapos++]); + } + } + + return 0; +} + +/*write the encoded data, using lit/len as well as distance codes*/ +static void writeLZ77data(size_t* bp, ucvector* out, const uivector* lz77_encoded, const HuffmanTree* codes, const HuffmanTree* codesD) +{ + size_t i = 0; + for(i = 0; i < lz77_encoded->size; i++) + { + unsigned val = lz77_encoded->data[i]; + addHuffmanSymbol(bp, out, HuffmanTree_getCode(codes, val), HuffmanTree_getLength(codes, val)); + if(val > 256) /*for a length code, 3 more things have to be added*/ + { + unsigned length_index = val - FIRST_LENGTH_CODE_INDEX; + unsigned n_length_extra_bits = LENGTHEXTRA[length_index]; + unsigned length_extra_bits = lz77_encoded->data[++i]; + + unsigned distance_code = lz77_encoded->data[++i]; + + unsigned distance_index = distance_code; + unsigned n_distance_extra_bits = DISTANCEEXTRA[distance_index]; + unsigned distance_extra_bits = lz77_encoded->data[++i]; + + addBitsToStream(bp, out, length_extra_bits, n_length_extra_bits); + addHuffmanSymbol(bp, out, HuffmanTree_getCode(codesD, distance_code), HuffmanTree_getLength(codesD, distance_code)); + addBitsToStream(bp, out, distance_extra_bits, n_distance_extra_bits); + } + } +} + +static unsigned deflateDynamic(ucvector* out, const unsigned char* data, size_t datasize, const LodeZlib_DeflateSettings* settings) +{ + /* + after the BFINAL and BTYPE, the dynamic block consists out of the following: + - 5 bits HLIT, 5 bits HDIST, 4 bits HCLEN + - (HCLEN+4)*3 bits code lengths of code length alphabet + - HLIT + 257 code lenghts of lit/length alphabet (encoded using the code length alphabet, + possible repetition codes 16, 17, 18) + - HDIST + 1 code lengths of distance alphabet (encoded using the code length alphabet, + possible repetition codes 16, 17, 18) + - compressed data + - 256 (end code) + */ + + unsigned error = 0; + + uivector lz77_encoded; + HuffmanTree codes; /*tree for literal values and length codes*/ + HuffmanTree codesD; /*tree for distance codes*/ + HuffmanTree codelengthcodes; + uivector frequencies; + uivector frequenciesD; + uivector amounts; /*the amounts in the "normal" order*/ + uivector lldl; + uivector lldll; /*lit/len & dist code lenghts*/ + uivector clcls; + + unsigned BFINAL = 1; /*make only one block... the first and final one*/ + size_t numcodes, numcodesD, i, bp = 0; /*the bit pointer*/ + unsigned HLIT, HDIST, HCLEN; + + uivector_init(&lz77_encoded); + HuffmanTree_init(&codes); + HuffmanTree_init(&codesD); + HuffmanTree_init(&codelengthcodes); + uivector_init(&frequencies); + uivector_init(&frequenciesD); + uivector_init(&amounts); + uivector_init(&lldl); + uivector_init(&lldll); + uivector_init(&clcls); + + while(!error) /*the goto-avoiding while construct: break out to go to the cleanup phase, a break at the end makes sure the while is never repeated*/ + { + if(settings->useLZ77) + { + error = encodeLZ77(&lz77_encoded, data, datasize, settings->windowSize); /*LZ77 encoded*/ + if(error) break; + } + else + { + if(!uivector_resize(&lz77_encoded, datasize)) { error = 9923; break; } + for(i = 0; i < datasize; i++) lz77_encoded.data[i] = data[i]; /*no LZ77, but still will be Huffman compressed*/ + } + + if(!uivector_resizev(&frequencies, 286, 0)) { error = 9924; break; } + if(!uivector_resizev(&frequenciesD, 30, 0)) { error = 9925; break; } + for(i = 0; i < lz77_encoded.size; i++) + { + unsigned symbol = lz77_encoded.data[i]; + frequencies.data[symbol]++; + if(symbol > 256) + { + unsigned dist = lz77_encoded.data[i + 2]; + frequenciesD.data[dist]++; + i += 3; + } + } + frequencies.data[256] = 1; /*there will be exactly 1 end code, at the end of the block*/ + + error = HuffmanTree_makeFromFrequencies(&codes, frequencies.data, frequencies.size, 15); + if(error) break; + error = HuffmanTree_makeFromFrequencies(&codesD, frequenciesD.data, frequenciesD.size, 15); + if(error) break; + + addBitToStream(&bp, out, BFINAL); + addBitToStream(&bp, out, 0); /*first bit of BTYPE "dynamic"*/ + addBitToStream(&bp, out, 1); /*second bit of BTYPE "dynamic"*/ + + numcodes = codes.numcodes; if(numcodes > 286) numcodes = 286; + numcodesD = codesD.numcodes; if(numcodesD > 30) numcodesD = 30; + for(i = 0; i < numcodes; i++) uivector_push_back(&lldll, HuffmanTree_getLength(&codes, (unsigned)i)); + for(i = 0; i < numcodesD; i++) uivector_push_back(&lldll, HuffmanTree_getLength(&codesD, (unsigned)i)); + + /*make lldl smaller by using repeat codes 16 (copy length 3-6 times), 17 (3-10 zeroes), 18 (11-138 zeroes)*/ + for(i = 0; i < (unsigned)lldll.size; i++) + { + unsigned j = 0; + while(i + j + 1 < (unsigned)lldll.size && lldll.data[i + j + 1] == lldll.data[i]) j++; + + if(lldll.data[i] == 0 && j >= 2) + { + j++; /*include the first zero*/ + if(j <= 10) { uivector_push_back(&lldl, 17); uivector_push_back(&lldl, j - 3); } + else + { + if(j > 138) j = 138; + uivector_push_back(&lldl, 18); uivector_push_back(&lldl, j - 11); + } + i += (j - 1); + } + else if(j >= 3) + { + size_t k; + unsigned num = j / 6, rest = j % 6; + uivector_push_back(&lldl, lldll.data[i]); + for(k = 0; k < num; k++) { uivector_push_back(&lldl, 16); uivector_push_back(&lldl, 6 - 3); } + if(rest >= 3) { uivector_push_back(&lldl, 16); uivector_push_back(&lldl, rest - 3); } + else j -= rest; + i += j; + } + else uivector_push_back(&lldl, lldll.data[i]); + } + + /*generate huffmantree for the length codes of lit/len and dist codes*/ + if(!uivector_resizev(&amounts, 19, 0)) { error = 9926; break; } /*16 possible lengths (0-15) and 3 repeat codes (16, 17 and 18)*/ + for(i = 0; i < lldl.size; i++) + { + amounts.data[lldl.data[i]]++; + if(lldl.data[i] >= 16) i++; /*after a repeat code come the bits that specify the amount, those don't need to be in the amounts calculation*/ + } + + error = HuffmanTree_makeFromFrequencies(&codelengthcodes, amounts.data, amounts.size, 7); + if(error) break; + + if(!uivector_resize(&clcls, 19)) { error = 9927; break; } + for(i = 0; i < 19; i++) clcls.data[i] = HuffmanTree_getLength(&codelengthcodes, CLCL[i]); /*lenghts of code length tree is in the order as specified by deflate*/ + while(clcls.data[clcls.size - 1] == 0 && clcls.size > 4) + { + if(!uivector_resize(&clcls, clcls.size - 1)) { error = 9928; break; } /*remove zeros at the end, but minimum size must be 4*/ + } + if(error) break; + + /*write the HLIT, HDIST and HCLEN values*/ + HLIT = (unsigned)(numcodes - 257); + HDIST = (unsigned)(numcodesD - 1); + HCLEN = (unsigned)clcls.size - 4; + addBitsToStream(&bp, out, HLIT, 5); + addBitsToStream(&bp, out, HDIST, 5); + addBitsToStream(&bp, out, HCLEN, 4); + + /*write the code lenghts of the code length alphabet*/ + for(i = 0; i < HCLEN + 4; i++) addBitsToStream(&bp, out, clcls.data[i], 3); + + /*write the lenghts of the lit/len AND the dist alphabet*/ + for(i = 0; i < lldl.size; i++) + { + addHuffmanSymbol(&bp, out, HuffmanTree_getCode(&codelengthcodes, lldl.data[i]), HuffmanTree_getLength(&codelengthcodes, lldl.data[i])); + /*extra bits of repeat codes*/ + if(lldl.data[i] == 16) addBitsToStream(&bp, out, lldl.data[++i], 2); + else if(lldl.data[i] == 17) addBitsToStream(&bp, out, lldl.data[++i], 3); + else if(lldl.data[i] == 18) addBitsToStream(&bp, out, lldl.data[++i], 7); + } + + /*write the compressed data symbols*/ + writeLZ77data(&bp, out, &lz77_encoded, &codes, &codesD); + if(HuffmanTree_getLength(&codes, 256) == 0) { error = 64; break; } /*the length of the end code 256 must be larger than 0*/ + addHuffmanSymbol(&bp, out, HuffmanTree_getCode(&codes, 256), HuffmanTree_getLength(&codes, 256)); /*end code*/ + + break; /*end of error-while*/ + } + + /*cleanup*/ + uivector_cleanup(&lz77_encoded); + HuffmanTree_cleanup(&codes); + HuffmanTree_cleanup(&codesD); + HuffmanTree_cleanup(&codelengthcodes); + uivector_cleanup(&frequencies); + uivector_cleanup(&frequenciesD); + uivector_cleanup(&amounts); + uivector_cleanup(&lldl); + uivector_cleanup(&lldll); + uivector_cleanup(&clcls); + + return error; +} + +static unsigned deflateFixed(ucvector* out, const unsigned char* data, size_t datasize, const LodeZlib_DeflateSettings* settings) +{ + HuffmanTree codes; /*tree for literal values and length codes*/ + HuffmanTree codesD; /*tree for distance codes*/ + + unsigned BFINAL = 1; /*make only one block... the first and final one*/ + unsigned error = 0; + size_t i, bp = 0; /*the bit pointer*/ + + HuffmanTree_init(&codes); + HuffmanTree_init(&codesD); + + generateFixedTree(&codes); + generateDistanceTree(&codesD); + + addBitToStream(&bp, out, BFINAL); + addBitToStream(&bp, out, 1); /*first bit of BTYPE*/ + addBitToStream(&bp, out, 0); /*second bit of BTYPE*/ + + if(settings->useLZ77) /*LZ77 encoded*/ + { + uivector lz77_encoded; + uivector_init(&lz77_encoded); + error = encodeLZ77(&lz77_encoded, data, datasize, settings->windowSize); + if(!error) writeLZ77data(&bp, out, &lz77_encoded, &codes, &codesD); + uivector_cleanup(&lz77_encoded); + } + else /*no LZ77, but still will be Huffman compressed*/ + { + for(i = 0; i < datasize; i++) addHuffmanSymbol(&bp, out, HuffmanTree_getCode(&codes, data[i]), HuffmanTree_getLength(&codes, data[i])); + } + if(!error) addHuffmanSymbol(&bp, out, HuffmanTree_getCode(&codes, 256), HuffmanTree_getLength(&codes, 256)); /*"end" code*/ + + /*cleanup*/ + HuffmanTree_cleanup(&codes); + HuffmanTree_cleanup(&codesD); + + return error; +} + +unsigned LodeFlate_deflate(ucvector* out, const unsigned char* data, size_t datasize, const LodeZlib_DeflateSettings* settings) +{ + unsigned error = 0; + if(settings->btype == 0) error = deflateNoCompression(out, data, datasize); + else if(settings->btype == 1) error = deflateFixed(out, data, datasize, settings); + else if(settings->btype == 2) error = deflateDynamic(out, data, datasize, settings); + else error = 61; + return error; +} + +#endif /*LODEPNG_COMPILE_DECODER*/ + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / Adler32 */ +/* ////////////////////////////////////////////////////////////////////////// */ + +static unsigned update_adler32(unsigned adler, const unsigned char* data, unsigned len) +{ + unsigned s1 = adler & 0xffff; + unsigned s2 = (adler >> 16) & 0xffff; + + while(len > 0) + { + /*at least 5550 sums can be done before the sums overflow, saving us from a lot of module divisions*/ + unsigned amount = len > 5550 ? 5550 : len; + len -= amount; + while(amount > 0) + { + s1 = (s1 + *data++); + s2 = (s2 + s1); + amount--; + } + s1 %= 65521; + s2 %= 65521; + } + + return (s2 << 16) | s1; +} + +/*Return the adler32 of the bytes data[0..len-1]*/ +static unsigned adler32(const unsigned char* data, unsigned len) +{ + return update_adler32(1L, data, len); +} + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / Reading and writing single bits and bytes from/to stream for Zlib / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +#ifdef LODEPNG_COMPILE_ENCODER +void LodeZlib_add32bitInt(ucvector* buffer, unsigned value) +{ + ucvector_push_back(buffer, (unsigned char)((value >> 24) & 0xff)); + ucvector_push_back(buffer, (unsigned char)((value >> 16) & 0xff)); + ucvector_push_back(buffer, (unsigned char)((value >> 8) & 0xff)); + ucvector_push_back(buffer, (unsigned char)((value ) & 0xff)); +} +#endif /*LODEPNG_COMPILE_ENCODER*/ + +unsigned LodeZlib_read32bitInt(const unsigned char* buffer) +{ + return (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3]; +} + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / Zlib / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +#ifdef LODEPNG_COMPILE_DECODER + +unsigned LodeZlib_decompress(unsigned char** out, size_t* outsize, const unsigned char* in, size_t insize, const LodeZlib_DecompressSettings* settings) +{ + unsigned error = 0; + unsigned CM, CINFO, FDICT; + ucvector outv; + + if(insize < 2) { error = 53; return error; } /*error, size of zlib data too small*/ + /*read information from zlib header*/ + if((in[0] * 256 + in[1]) % 31 != 0) { error = 24; return error; } /*error: 256 * in[0] + in[1] must be a multiple of 31, the FCHECK value is supposed to be made that way*/ + + CM = in[0] & 15; + CINFO = (in[0] >> 4) & 15; + /*FCHECK = in[1] & 31; //FCHECK is already tested above*/ + FDICT = (in[1] >> 5) & 1; + /*FLEVEL = (in[1] >> 6) & 3; //not really important, all it does it to give a compiler warning about unused variable, we don't care what encoding setting the encoder used*/ + + if(CM != 8 || CINFO > 7) { error = 25; return error; } /*error: only compression method 8: inflate with sliding window of 32k is supported by the PNG spec*/ + if(FDICT != 0) { error = 26; return error; } /*error: the specification of PNG says about the zlib stream: "The additional flags shall not specify a preset dictionary."*/ + + ucvector_init_buffer(&outv, *out, *outsize); /*ucvector-controlled version of the output buffer, for dynamic array*/ + error = LodeFlate_inflate(&outv, in, insize, 2); + *out = outv.data; + *outsize = outv.size; + if(error) return error; + + if(!settings->ignoreAdler32) + { + unsigned ADLER32 = LodeZlib_read32bitInt(&in[insize - 4]); + unsigned checksum = adler32(outv.data, (unsigned)outv.size); + if(checksum != ADLER32) { error = 58; return error; } + } + + return error; +} + +#endif /*LODEPNG_COMPILE_DECODER*/ + +#ifdef LODEPNG_COMPILE_ENCODER + +unsigned LodeZlib_compress(unsigned char** out, size_t* outsize, const unsigned char* in, size_t insize, const LodeZlib_DeflateSettings* settings) +{ + /*initially, *out must be NULL and outsize 0, if you just give some random *out that's pointing to a non allocated buffer, this'll crash*/ + ucvector deflatedata, outv; + size_t i; + unsigned error; + + unsigned ADLER32; + /*zlib data: 1 byte CMF (CM+CINFO), 1 byte FLG, deflate data, 4 byte ADLER32 checksum of the Decompressed data*/ + unsigned CMF = 120; /*0b01111000: CM 8, CINFO 7. With CINFO 7, any window size up to 32768 can be used.*/ + unsigned FLEVEL = 0; + unsigned FDICT = 0; + unsigned CMFFLG = 256 * CMF + FDICT * 32 + FLEVEL * 64; + unsigned FCHECK = 31 - CMFFLG % 31; + CMFFLG += FCHECK; + + ucvector_init_buffer(&outv, *out, *outsize); /*ucvector-controlled version of the output buffer, for dynamic array*/ + + ucvector_push_back(&outv, (unsigned char)(CMFFLG / 256)); + ucvector_push_back(&outv, (unsigned char)(CMFFLG % 256)); + + ucvector_init(&deflatedata); + error = LodeFlate_deflate(&deflatedata, in, insize, settings); + + if(!error) + { + ADLER32 = adler32(in, (unsigned)insize); + for(i = 0; i < deflatedata.size; i++) ucvector_push_back(&outv, deflatedata.data[i]); + ucvector_cleanup(&deflatedata); + LodeZlib_add32bitInt(&outv, ADLER32); + } + + *out = outv.data; + *outsize = outv.size; + + return error; +} + +#endif /*LODEPNG_COMPILE_ENCODER*/ + +#endif /*LODEPNG_COMPILE_ZLIB*/ + +/* ////////////////////////////////////////////////////////////////////////// */ + +#ifdef LODEPNG_COMPILE_ENCODER + +void LodeZlib_DeflateSettings_init(LodeZlib_DeflateSettings* settings) +{ + settings->btype = 2; /*compress with dynamic huffman tree (not in the mathematical sense, just not the predefined one)*/ + settings->useLZ77 = 1; + settings->windowSize = 2048; /*this is a good tradeoff between speed and compression ratio*/ +} + +const LodeZlib_DeflateSettings LodeZlib_defaultDeflateSettings = {2, 1, 2048}; + +#endif /*LODEPNG_COMPILE_ENCODER*/ + +#ifdef LODEPNG_COMPILE_DECODER + +void LodeZlib_DecompressSettings_init(LodeZlib_DecompressSettings* settings) +{ + settings->ignoreAdler32 = 0; +} + +const LodeZlib_DecompressSettings LodeZlib_defaultDecompressSettings = {0}; + +#endif /*LODEPNG_COMPILE_DECODER*/ + +/* ////////////////////////////////////////////////////////////////////////// */ +/* ////////////////////////////////////////////////////////////////////////// */ +/* ////////////////////////////////////////////////////////////////////////// */ +/* ////////////////////////////////////////////////////////////////////////// */ +/* ////////////////////////////////////////////////////////////////////////// */ +/* // End of Zlib related code, now comes the PNG related code that uses it// */ +/* ////////////////////////////////////////////////////////////////////////// */ +/* ////////////////////////////////////////////////////////////////////////// */ +/* ////////////////////////////////////////////////////////////////////////// */ +/* ////////////////////////////////////////////////////////////////////////// */ +/* ////////////////////////////////////////////////////////////////////////// */ + +#ifdef LODEPNG_COMPILE_PNG + +/* +The two functions below (LodePNG_decompress and LodePNG_compress) directly call the +LodeZlib_decompress and LodeZlib_compress functions. The only purpose of the functions +below, is to provide the ability to let LodePNG use a different Zlib encoder by only +changing the two functions below, instead of changing it inside the vareous places +in the other LodePNG functions. + +*out must be NULL and *outsize must be 0 initially, and after the function is done, +*out must point to the decompressed data, *outsize must be the size of it, and must +be the size of the useful data in bytes, not the alloc size. +*/ + +#ifdef LODEPNG_COMPILE_DECODER +static unsigned LodePNG_decompress(unsigned char** out, size_t* outsize, const unsigned char* in, size_t insize, const LodeZlib_DecompressSettings* settings) +{ + return LodeZlib_decompress(out, outsize, in, insize, settings); +} +#endif /*LODEPNG_COMPILE_DECODER*/ +#ifdef LODEPNG_COMPILE_ENCODER +static unsigned LodePNG_compress(unsigned char** out, size_t* outsize, const unsigned char* in, size_t insize, const LodeZlib_DeflateSettings* settings) +{ + return LodeZlib_compress(out, outsize, in, insize, settings); +} +#endif /*LODEPNG_COMPILE_ENCODER*/ + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / CRC32 / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +static unsigned Crc32_crc_table_computed = 0; +static unsigned Crc32_crc_table[256]; + +/*Make the table for a fast CRC.*/ +static void Crc32_make_crc_table(void) +{ + unsigned c, k, n; + for(n = 0; n < 256; n++) + { + c = n; + for(k = 0; k < 8; k++) + { + if(c & 1) c = 0xedb88320L ^ (c >> 1); + else c = c >> 1; + } + Crc32_crc_table[n] = c; + } + Crc32_crc_table_computed = 1; +} + +/*Update a running CRC with the bytes buf[0..len-1]--the CRC should be +initialized to all 1's, and the transmitted value is the 1's complement of the +final running CRC (see the crc() routine below).*/ +static unsigned Crc32_update_crc(const unsigned char* buf, unsigned crc, size_t len) +{ + unsigned c = crc; + size_t n; + + if(!Crc32_crc_table_computed) Crc32_make_crc_table(); + for(n = 0; n < len; n++) + { + c = Crc32_crc_table[(c ^ buf[n]) & 0xff] ^ (c >> 8); + } + return c; +} + +/*Return the CRC of the bytes buf[0..len-1].*/ +static unsigned Crc32_crc(const unsigned char* buf, size_t len) +{ + return Crc32_update_crc(buf, 0xffffffffL, len) ^ 0xffffffffL; +} + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / Reading and writing single bits and bytes from/to stream for LodePNG / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +static unsigned char readBitFromReversedStream(size_t* bitpointer, const unsigned char* bitstream) +{ + unsigned char result = (unsigned char)((bitstream[(*bitpointer) >> 3] >> (7 - ((*bitpointer) & 0x7))) & 1); + (*bitpointer)++; + return result; +} + +static unsigned readBitsFromReversedStream(size_t* bitpointer, const unsigned char* bitstream, size_t nbits) +{ + unsigned result = 0; + size_t i; + for(i = nbits - 1; i < nbits; i--) result += (unsigned)readBitFromReversedStream(bitpointer, bitstream) << i; + return result; +} + +#ifdef LODEPNG_COMPILE_DECODER +static void setBitOfReversedStream0(size_t* bitpointer, unsigned char* bitstream, unsigned char bit) +{ + /*the current bit in bitstream must be 0 for this to work*/ + if(bit) bitstream[(*bitpointer) >> 3] |= (bit << (7 - ((*bitpointer) & 0x7))); /*earlier bit of huffman code is in a lesser significant bit of an earlier byte*/ + (*bitpointer)++; +} +#endif /*LODEPNG_COMPILE_DECODER*/ + +static void setBitOfReversedStream(size_t* bitpointer, unsigned char* bitstream, unsigned char bit) +{ + /*the current bit in bitstream may be 0 or 1 for this to work*/ + if(bit == 0) bitstream[(*bitpointer) >> 3] &= (unsigned char)(~(1 << (7 - ((*bitpointer) & 0x7)))); + else bitstream[(*bitpointer) >> 3] |= (1 << (7 - ((*bitpointer) & 0x7))); + (*bitpointer)++; +} + +static unsigned LodePNG_read32bitInt(const unsigned char* buffer) +{ + return (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3]; +} + +static void LodePNG_set32bitInt(unsigned char* buffer, unsigned value) /*buffer must have at least 4 allocated bytes available*/ +{ + buffer[0] = (unsigned char)((value >> 24) & 0xff); + buffer[1] = (unsigned char)((value >> 16) & 0xff); + buffer[2] = (unsigned char)((value >> 8) & 0xff); + buffer[3] = (unsigned char)((value ) & 0xff); +} + +#ifdef LODEPNG_COMPILE_ENCODER +static void LodePNG_add32bitInt(ucvector* buffer, unsigned value) +{ + ucvector_resize(buffer, buffer->size + 4); + LodePNG_set32bitInt(&buffer->data[buffer->size - 4], value); +} +#endif /*LODEPNG_COMPILE_ENCODER*/ + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / PNG chunks / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +unsigned LodePNG_chunk_length(const unsigned char* chunk) /*get the length of the data of the chunk. Total chunk length has 12 bytes more.*/ +{ + return LodePNG_read32bitInt(&chunk[0]); +} + +void LodePNG_chunk_type(char type[5], const unsigned char* chunk) /*puts the 4-byte type in null terminated string*/ +{ + unsigned i; + for(i = 0; i < 4; i++) type[i] = chunk[4 + i]; + type[4] = 0; /*null termination char*/ +} + +unsigned char LodePNG_chunk_type_equals(const unsigned char* chunk, const char* type) /*check if the type is the given type*/ +{ + if(strlen(type) != 4) return 0; + return (chunk[4] == type[0] && chunk[5] == type[1] && chunk[6] == type[2] && chunk[7] == type[3]); +} + +/*properties of PNG chunks gotten from capitalization of chunk type name, as defined by the standard*/ +unsigned char LodePNG_chunk_critical(const unsigned char* chunk) /*0: ancillary chunk, 1: it's one of the critical chunk types*/ +{ + return((chunk[4] & 32) == 0); +} + +unsigned char LodePNG_chunk_private(const unsigned char* chunk) /*0: public, 1: private*/ +{ + return((chunk[6] & 32) != 0); +} + +unsigned char LodePNG_chunk_safetocopy(const unsigned char* chunk) /*0: the chunk is unsafe to copy, 1: the chunk is safe to copy*/ +{ + return((chunk[7] & 32) != 0); +} + +unsigned char* LodePNG_chunk_data(unsigned char* chunk) /*get pointer to the data of the chunk*/ +{ + return &chunk[8]; +} + +const unsigned char* LodePNG_chunk_data_const(const unsigned char* chunk) /*get pointer to the data of the chunk*/ +{ + return &chunk[8]; +} + +unsigned LodePNG_chunk_check_crc(const unsigned char* chunk) /*returns 0 if the crc is correct, error code if it's incorrect*/ +{ + unsigned length = LodePNG_chunk_length(chunk); + unsigned CRC = LodePNG_read32bitInt(&chunk[length + 8]); + unsigned checksum = Crc32_crc(&chunk[4], length + 4); /*the CRC is taken of the data and the 4 chunk type letters, not the length*/ + if(CRC != checksum) return 1; + else return 0; +} + +void LodePNG_chunk_generate_crc(unsigned char* chunk) /*generates the correct CRC from the data and puts it in the last 4 bytes of the chunk*/ +{ + unsigned length = LodePNG_chunk_length(chunk); + unsigned CRC = Crc32_crc(&chunk[4], length + 4); + LodePNG_set32bitInt(chunk + 8 + length, CRC); +} + +unsigned char* LodePNG_chunk_next(unsigned char* chunk) /*don't use on IEND chunk, as there is no next chunk then*/ +{ + unsigned total_chunk_length = LodePNG_chunk_length(chunk) + 12; + return &chunk[total_chunk_length]; +} + +const unsigned char* LodePNG_chunk_next_const(const unsigned char* chunk) /*don't use on IEND chunk, as there is no next chunk then*/ +{ + unsigned total_chunk_length = LodePNG_chunk_length(chunk) + 12; + return &chunk[total_chunk_length]; +} + +unsigned LodePNG_append_chunk(unsigned char** out, size_t* outlength, const unsigned char* chunk) /*appends chunk that was already created, to the data. Returns error code.*/ +{ + unsigned i; + unsigned total_chunk_length = LodePNG_chunk_length(chunk) + 12; + unsigned char *chunk_start, *new_buffer; + size_t new_length = (*outlength) + total_chunk_length; + if(new_length < total_chunk_length || new_length < (*outlength)) return 77; /*integer overflow happened*/ + + new_buffer = (unsigned char*)realloc(*out, new_length); + if(!new_buffer) return 9929; + (*out) = new_buffer; + (*outlength) = new_length; + chunk_start = &(*out)[new_length - total_chunk_length]; + + for(i = 0; i < total_chunk_length; i++) chunk_start[i] = chunk[i]; + + return 0; +} + +unsigned LodePNG_create_chunk(unsigned char** out, size_t* outlength, unsigned length, const char* type, const unsigned char* data) /*appends new chunk to out. Returns error code; may change memory address of out buffer*/ +{ + unsigned i; + unsigned char *chunk, *new_buffer; + size_t new_length = (*outlength) + length + 12; + if(new_length < length + 12 || new_length < (*outlength)) return 77; /*integer overflow happened*/ + new_buffer = (unsigned char*)realloc(*out, new_length); + if(!new_buffer) return 9930; + (*out) = new_buffer; + (*outlength) = new_length; + chunk = &(*out)[(*outlength) - length - 12]; + + /*1: length*/ + LodePNG_set32bitInt(chunk, (unsigned)length); + + /*2: chunk name (4 letters)*/ + chunk[4] = type[0]; + chunk[5] = type[1]; + chunk[6] = type[2]; + chunk[7] = type[3]; + + /*3: the data*/ + for(i = 0; i < length; i++) chunk[8 + i] = data[i]; + + /*4: CRC (of the chunkname characters and the data)*/ + LodePNG_chunk_generate_crc(chunk); + + return 0; +} + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / Color types and such / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +/*return type is a LodePNG error code*/ +static unsigned checkColorValidity(unsigned colorType, unsigned bd) /*bd = bitDepth*/ +{ + switch(colorType) + { + case 0: if(!(bd == 1 || bd == 2 || bd == 4 || bd == 8 || bd == 16)) return 37; break; /*grey*/ + case 2: if(!( bd == 8 || bd == 16)) return 37; break; /*RGB*/ + case 3: if(!(bd == 1 || bd == 2 || bd == 4 || bd == 8 )) return 37; break; /*palette*/ + case 4: if(!( bd == 8 || bd == 16)) return 37; break; /*grey + alpha*/ + case 6: if(!( bd == 8 || bd == 16)) return 37; break; /*RGBA*/ + default: return 31; + } + return 0; /*allowed color type / bits combination*/ +} + +static unsigned getNumColorChannels(unsigned colorType) +{ + switch(colorType) + { + case 0: return 1; /*grey*/ + case 2: return 3; /*RGB*/ + case 3: return 1; /*palette*/ + case 4: return 2; /*grey + alpha*/ + case 6: return 4; /*RGBA*/ + } + return 0; /*unexisting color type*/ +} + +static unsigned getBpp(unsigned colorType, unsigned bitDepth) +{ + return getNumColorChannels(colorType) * bitDepth; /*bits per pixel is amount of channels * bits per channel*/ +} + +/* ////////////////////////////////////////////////////////////////////////// */ + +void LodePNG_InfoColor_init(LodePNG_InfoColor* info) +{ + info->key_defined = 0; + info->key_r = info->key_g = info->key_b = 0; + info->colorType = 6; + info->bitDepth = 8; + info->palette = 0; + info->palettesize = 0; +} + +void LodePNG_InfoColor_cleanup(LodePNG_InfoColor* info) +{ + LodePNG_InfoColor_clearPalette(info); +} + +void LodePNG_InfoColor_clearPalette(LodePNG_InfoColor* info) +{ + if(info->palette) free(info->palette); + info->palettesize = 0; +} + +unsigned LodePNG_InfoColor_addPalette(LodePNG_InfoColor* info, unsigned char r, unsigned char g, unsigned char b, unsigned char a) +{ + unsigned char* data; + /*the same resize technique as C++ std::vectors is used, and here it's made so that for a palette with the max of 256 colors, it'll have the exact alloc size*/ + if(!(info->palettesize & (info->palettesize - 1))) /*if palettesize is 0 or a power of two*/ + { + /*allocated data must be at least 4* palettesize (for 4 color bytes)*/ + size_t alloc_size = info->palettesize == 0 ? 4 : info->palettesize * 4 * 2; + data = (unsigned char*)realloc(info->palette, alloc_size); + if(!data) return 9931; + else info->palette = data; + } + info->palette[4 * info->palettesize + 0] = r; + info->palette[4 * info->palettesize + 1] = g; + info->palette[4 * info->palettesize + 2] = b; + info->palette[4 * info->palettesize + 3] = a; + info->palettesize++; + return 0; +} + +unsigned LodePNG_InfoColor_getBpp(const LodePNG_InfoColor* info) { return getBpp(info->colorType, info->bitDepth); } /*calculate bits per pixel out of colorType and bitDepth*/ +unsigned LodePNG_InfoColor_getChannels(const LodePNG_InfoColor* info) { return getNumColorChannels(info->colorType); } +unsigned LodePNG_InfoColor_isGreyscaleType(const LodePNG_InfoColor* info) { return info->colorType == 0 || info->colorType == 4; } +unsigned LodePNG_InfoColor_isAlphaType(const LodePNG_InfoColor* info) { return (info->colorType & 4) != 0; } + +unsigned LodePNG_InfoColor_equal(const LodePNG_InfoColor* info1, const LodePNG_InfoColor* info2) +{ + return info1->colorType == info2->colorType + && info1->bitDepth == info2->bitDepth; /*palette and color key not compared*/ +} + +#ifdef LODEPNG_COMPILE_UNKNOWN_CHUNKS + +void LodePNG_UnknownChunks_init(LodePNG_UnknownChunks* chunks) +{ + unsigned i; + for(i = 0; i < 3; i++) chunks->data[i] = 0; + for(i = 0; i < 3; i++) chunks->datasize[i] = 0; +} + +void LodePNG_UnknownChunks_cleanup(LodePNG_UnknownChunks* chunks) +{ + unsigned i; + for(i = 0; i < 3; i++) free(chunks->data[i]); +} + +unsigned LodePNG_UnknownChunks_copy(LodePNG_UnknownChunks* dest, const LodePNG_UnknownChunks* src) +{ + unsigned i; + + LodePNG_UnknownChunks_cleanup(dest); + + for(i = 0; i < 3; i++) + { + size_t j; + dest->datasize[i] = src->datasize[i]; + dest->data[i] = (unsigned char*)malloc(src->datasize[i]); + if(!dest->data[i] && dest->datasize[i]) return 9932; + for(j = 0; j < src->datasize[i]; j++) dest->data[i][j] = src->data[i][j]; + } + + return 0; +} + +#endif /*LODEPNG_COMPILE_UNKNOWN_CHUNKS*/ + +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + +void LodePNG_Text_init(LodePNG_Text* text) +{ + text->num = 0; + text->keys = NULL; + text->strings = NULL; +} + +void LodePNG_Text_cleanup(LodePNG_Text* text) +{ + LodePNG_Text_clear(text); +} + +unsigned LodePNG_Text_copy(LodePNG_Text* dest, const LodePNG_Text* source) +{ + size_t i = 0; + dest->keys = 0; + dest->strings = 0; + dest->num = 0; + for(i = 0; i < source->num; i++) + { + unsigned error = LodePNG_Text_add(dest, source->keys[i], source->strings[i]); + if(error) return error; + } + return 0; +} + +void LodePNG_Text_clear(LodePNG_Text* text) +{ + size_t i; + for(i = 0; i < text->num; i++) + { + string_cleanup(&text->keys[i]); + string_cleanup(&text->strings[i]); + } + free(text->keys); + free(text->strings); +} + +unsigned LodePNG_Text_add(LodePNG_Text* text, const char* key, const char* str) +{ + char** new_keys = (char**)(realloc(text->keys, sizeof(char*) * (text->num + 1))); + char** new_strings = (char**)(realloc(text->strings, sizeof(char*) * (text->num + 1))); + if(!new_keys || !new_strings) + { + free(new_keys); + free(new_strings); + return 9933; + } + + text->num++; + text->keys = new_keys; + text->strings = new_strings; + + string_init(&text->keys[text->num - 1]); + string_set(&text->keys[text->num - 1], key); + + string_init(&text->strings[text->num - 1]); + string_set(&text->strings[text->num - 1], str); + + return 0; +} + +/******************************************************************************/ + +void LodePNG_IText_init(LodePNG_IText* text) +{ + text->num = 0; + text->keys = NULL; + text->langtags = NULL; + text->transkeys = NULL; + text->strings = NULL; +} + +void LodePNG_IText_cleanup(LodePNG_IText* text) +{ + LodePNG_IText_clear(text); +} + +unsigned LodePNG_IText_copy(LodePNG_IText* dest, const LodePNG_IText* source) +{ + size_t i = 0; + dest->keys = 0; + dest->langtags = 0; + dest->transkeys = 0; + dest->strings = 0; + dest->num = 0; + for(i = 0; i < source->num; i++) + { + unsigned error = LodePNG_IText_add(dest, source->keys[i], source->langtags[i], source->transkeys[i], source->strings[i]); + if(error) return error; + } + return 0; +} + +void LodePNG_IText_clear(LodePNG_IText* text) +{ + size_t i; + for(i = 0; i < text->num; i++) + { + string_cleanup(&text->keys[i]); + string_cleanup(&text->langtags[i]); + string_cleanup(&text->transkeys[i]); + string_cleanup(&text->strings[i]); + } + free(text->keys); + free(text->langtags); + free(text->transkeys); + free(text->strings); +} + +unsigned LodePNG_IText_add(LodePNG_IText* text, const char* key, const char* langtag, const char* transkey, const char* str) +{ + char** new_keys = (char**)(realloc(text->keys, sizeof(char*) * (text->num + 1))); + char** new_langtags = (char**)(realloc(text->langtags, sizeof(char*) * (text->num + 1))); + char** new_transkeys = (char**)(realloc(text->transkeys, sizeof(char*) * (text->num + 1))); + char** new_strings = (char**)(realloc(text->strings, sizeof(char*) * (text->num + 1))); + if(!new_keys || !new_langtags || !new_transkeys || !new_strings) + { + free(new_keys); + free(new_langtags); + free(new_transkeys); + free(new_strings); + return 9934; + } + + text->num++; + text->keys = new_keys; + text->langtags = new_langtags; + text->transkeys = new_transkeys; + text->strings = new_strings; + + string_init(&text->keys[text->num - 1]); + string_set(&text->keys[text->num - 1], key); + + string_init(&text->langtags[text->num - 1]); + string_set(&text->langtags[text->num - 1], langtag); + + string_init(&text->transkeys[text->num - 1]); + string_set(&text->transkeys[text->num - 1], transkey); + + string_init(&text->strings[text->num - 1]); + string_set(&text->strings[text->num - 1], str); + + return 0; +} + +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + +void LodePNG_InfoPng_init(LodePNG_InfoPng* info) +{ + info->width = info->height = 0; + LodePNG_InfoColor_init(&info->color); + info->interlaceMethod = 0; + info->compressionMethod = 0; + info->filterMethod = 0; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + info->background_defined = 0; + info->background_r = info->background_g = info->background_b = 0; + + LodePNG_Text_init(&info->text); + LodePNG_IText_init(&info->itext); + + info->time_defined = 0; + info->phys_defined = 0; +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ +#ifdef LODEPNG_COMPILE_UNKNOWN_CHUNKS + LodePNG_UnknownChunks_init(&info->unknown_chunks); +#endif /*LODEPNG_COMPILE_UNKNOWN_CHUNKS*/ +} + +void LodePNG_InfoPng_cleanup(LodePNG_InfoPng* info) +{ + LodePNG_InfoColor_cleanup(&info->color); +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + LodePNG_Text_cleanup(&info->text); + LodePNG_IText_cleanup(&info->itext); +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ +#ifdef LODEPNG_COMPILE_UNKNOWN_CHUNKS + LodePNG_UnknownChunks_cleanup(&info->unknown_chunks); +#endif /*LODEPNG_COMPILE_UNKNOWN_CHUNKS*/ +} + +unsigned LodePNG_InfoPng_copy(LodePNG_InfoPng* dest, const LodePNG_InfoPng* source) +{ + unsigned error = 0; + LodePNG_InfoPng_cleanup(dest); + *dest = *source; + LodePNG_InfoColor_init(&dest->color); + error = LodePNG_InfoColor_copy(&dest->color, &source->color); if(error) return error; + +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + error = LodePNG_Text_copy(&dest->text, &source->text); if(error) return error; + error = LodePNG_IText_copy(&dest->itext, &source->itext); if(error) return error; +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + +#ifdef LODEPNG_COMPILE_UNKNOWN_CHUNKS + LodePNG_UnknownChunks_init(&dest->unknown_chunks); + error = LodePNG_UnknownChunks_copy(&dest->unknown_chunks, &source->unknown_chunks); if(error) return error; +#endif /*LODEPNG_COMPILE_UNKNOWN_CHUNKS*/ + return error; +} + +void LodePNG_InfoPng_swap(LodePNG_InfoPng* a, LodePNG_InfoPng* b) +{ + LodePNG_InfoPng temp = *a; + *a = *b; + *b = temp; +} + +unsigned LodePNG_InfoColor_copy(LodePNG_InfoColor* dest, const LodePNG_InfoColor* source) +{ + size_t i; + LodePNG_InfoColor_cleanup(dest); + *dest = *source; + dest->palette = (unsigned char*)malloc(source->palettesize * 4); + if(!dest->palette && source->palettesize) return 9935; + for(i = 0; i < source->palettesize * 4; i++) dest->palette[i] = source->palette[i]; + return 0; +} + +void LodePNG_InfoRaw_init(LodePNG_InfoRaw* info) +{ + LodePNG_InfoColor_init(&info->color); +} + +void LodePNG_InfoRaw_cleanup(LodePNG_InfoRaw* info) +{ + LodePNG_InfoColor_cleanup(&info->color); +} + +unsigned LodePNG_InfoRaw_copy(LodePNG_InfoRaw* dest, const LodePNG_InfoRaw* source) +{ + unsigned error = 0; + LodePNG_InfoRaw_cleanup(dest); + *dest = *source; + LodePNG_InfoColor_init(&dest->color); + error = LodePNG_InfoColor_copy(&dest->color, &source->color); if(error) return error; + return error; +} + +/* ////////////////////////////////////////////////////////////////////////// */ + +/* +converts from any color type to 24-bit or 32-bit (later maybe more supported). return value = LodePNG error code +the out buffer must have (w * h * bpp + 7) / 8 bytes, where bpp is the bits per pixel of the output color type (LodePNG_InfoColor_getBpp) +for < 8 bpp images, there may _not_ be padding bits at the end of scanlines. +*/ +unsigned LodePNG_convert(unsigned char* out, const unsigned char* in, LodePNG_InfoColor* infoOut, LodePNG_InfoColor* infoIn, unsigned w, unsigned h) +{ + const size_t numpixels = w * h; /*amount of pixels*/ + const unsigned OUT_BYTES = LodePNG_InfoColor_getBpp(infoOut) / 8; /*bytes per pixel in the output image*/ + const unsigned OUT_ALPHA = LodePNG_InfoColor_isAlphaType(infoOut); /*use 8-bit alpha channel*/ + size_t i, c, bp = 0; /*bitpointer, used by less-than-8-bit color types*/ + + /*cases where in and out already have the same format*/ + if(LodePNG_InfoColor_equal(infoIn, infoOut)) + { + size_t i, size = (w * h * LodePNG_InfoColor_getBpp(infoIn) + 7) / 8; + for(i = 0; i < size; i++) out[i] = in[i]; + return 0; + } + + if((infoOut->colorType == 2 || infoOut->colorType == 6) && infoOut->bitDepth == 8) + { + if(infoIn->bitDepth == 8) + { + switch(infoIn->colorType) + { + case 0: /*greyscale color*/ + for(i = 0; i < numpixels; i++) + { + if(OUT_ALPHA) out[OUT_BYTES * i + 3] = 255; + out[OUT_BYTES * i + 0] = out[OUT_BYTES * i + 1] = out[OUT_BYTES * i + 2] = in[i]; + if(OUT_ALPHA && infoIn->key_defined && in[i] == infoIn->key_r) out[OUT_BYTES * i + 3] = 0; + } + break; + case 2: /*RGB color*/ + for(i = 0; i < numpixels; i++) + { + if(OUT_ALPHA) out[OUT_BYTES * i + 3] = 255; + for(c = 0; c < 3; c++) out[OUT_BYTES * i + c] = in[3 * i + c]; + if(OUT_ALPHA && infoIn->key_defined == 1 && in[3 * i + 0] == infoIn->key_r && in[3 * i + 1] == infoIn->key_g && in[3 * i + 2] == infoIn->key_b) out[OUT_BYTES * i + 3] = 0; + } + break; + case 3: /*indexed color (palette)*/ + for(i = 0; i < numpixels; i++) + { + if(OUT_ALPHA) out[OUT_BYTES * i + 3] = 255; + if(in[i] >= infoIn->palettesize) return 46; + for(c = 0; c < OUT_BYTES; c++) out[OUT_BYTES * i + c] = infoIn->palette[4 * in[i] + c]; /*get rgb colors from the palette*/ + } + break; + case 4: /*greyscale with alpha*/ + for(i = 0; i < numpixels; i++) + { + out[OUT_BYTES * i + 0] = out[OUT_BYTES * i + 1] = out[OUT_BYTES * i + 2] = in[2 * i + 0]; + if(OUT_ALPHA) out[OUT_BYTES * i + 3] = in[2 * i + 1]; + } + break; + case 6: /*RGB with alpha*/ + for(i = 0; i < numpixels; i++) + { + for(c = 0; c < OUT_BYTES; c++) out[OUT_BYTES * i + c] = in[4 * i + c]; + } + break; + default: break; + } + } + else if(infoIn->bitDepth == 16) + { + switch(infoIn->colorType) + { + case 0: /*greyscale color*/ + for(i = 0; i < numpixels; i++) + { + if(OUT_ALPHA) out[OUT_BYTES * i + 3] = 255; + out[OUT_BYTES * i + 0] = out[OUT_BYTES * i + 1] = out[OUT_BYTES * i + 2] = in[2 * i]; + if(OUT_ALPHA && infoIn->key_defined && 256U * in[i] + in[i + 1] == infoIn->key_r) out[OUT_BYTES * i + 3] = 0; + } + break; + case 2: /*RGB color*/ + for(i = 0; i < numpixels; i++) + { + if(OUT_ALPHA) out[OUT_BYTES * i + 3] = 255; + for(c = 0; c < 3; c++) out[OUT_BYTES * i + c] = in[6 * i + 2 * c]; + if(OUT_ALPHA && infoIn->key_defined && 256U * in[6 * i + 0] + in[6 * i + 1] == infoIn->key_r && 256U * in[6 * i + 2] + in[6 * i + 3] == infoIn->key_g && 256U * in[6 * i + 4] + in[6 * i + 5] == infoIn->key_b) out[OUT_BYTES * i + 3] = 0; + } + break; + case 4: /*greyscale with alpha*/ + for(i = 0; i < numpixels; i++) + { + out[OUT_BYTES * i + 0] = out[OUT_BYTES * i + 1] = out[OUT_BYTES * i + 2] = in[4 * i]; /*most significant byte*/ + if(OUT_ALPHA) out[OUT_BYTES * i + 3] = in[4 * i + 2]; + } + break; + case 6: /*RGB with alpha*/ + for(i = 0; i < numpixels; i++) + { + for(c = 0; c < OUT_BYTES; c++) out[OUT_BYTES * i + c] = in[8 * i + 2 * c]; + } + break; + default: break; + } + } + else /*infoIn->bitDepth is less than 8 bit per channel*/ + { + switch(infoIn->colorType) + { + case 0: /*greyscale color*/ + for(i = 0; i < numpixels; i++) + { + unsigned value = readBitsFromReversedStream(&bp, in, infoIn->bitDepth); + if(OUT_ALPHA) out[OUT_BYTES * i + 3] = 255; + if(OUT_ALPHA && infoIn->key_defined && value && ((1U << infoIn->bitDepth) - 1U) == infoIn->key_r && ((1U << infoIn->bitDepth) - 1U)) out[OUT_BYTES * i + 3] = 0; + value = (value * 255) / ((1 << infoIn->bitDepth) - 1); /*scale value from 0 to 255*/ + out[OUT_BYTES * i + 0] = out[OUT_BYTES * i + 1] = out[OUT_BYTES * i + 2] = (unsigned char)(value); + } + break; + case 3: /*indexed color (palette)*/ + for(i = 0; i < numpixels; i++) + { + unsigned value = readBitsFromReversedStream(&bp, in, infoIn->bitDepth); + if(OUT_ALPHA) out[OUT_BYTES * i + 3] = 255; + if(value >= infoIn->palettesize) return 47; + for(c = 0; c < OUT_BYTES; c++) out[OUT_BYTES * i + c] = infoIn->palette[4 * value + c]; /*get rgb colors from the palette*/ + } + break; + default: break; + } + } + } + else if(LodePNG_InfoColor_isGreyscaleType(infoOut) && infoOut->bitDepth == 8) /*conversion from greyscale to greyscale*/ + { + if(!LodePNG_InfoColor_isGreyscaleType(infoIn)) return 62; + if(infoIn->bitDepth == 8) + { + switch(infoIn->colorType) + { + case 0: /*greyscale color*/ + for(i = 0; i < numpixels; i++) + { + if(OUT_ALPHA) out[OUT_BYTES * i + 1] = 255; + out[OUT_BYTES * i] = in[i]; + if(OUT_ALPHA && infoIn->key_defined && in[i] == infoIn->key_r) out[OUT_BYTES * i + 1] = 0; + } + break; + case 4: /*greyscale with alpha*/ + for(i = 0; i < numpixels; i++) + { + out[OUT_BYTES * i + 0] = in[2 * i + 0]; + if(OUT_ALPHA) out[OUT_BYTES * i + 1] = in[2 * i + 1]; + } + break; + default: return 31; + } + } + else if(infoIn->bitDepth == 16) + { + switch(infoIn->colorType) + { + case 0: /*greyscale color*/ + for(i = 0; i < numpixels; i++) + { + if(OUT_ALPHA) out[OUT_BYTES * i + 1] = 255; + out[OUT_BYTES * i] = in[2 * i]; + if(OUT_ALPHA && infoIn->key_defined && 256U * in[i] + in[i + 1] == infoIn->key_r) out[OUT_BYTES * i + 1] = 0; + } + break; + case 4: /*greyscale with alpha*/ + for(i = 0; i < numpixels; i++) + { + out[OUT_BYTES * i] = in[4 * i]; /*most significant byte*/ + if(OUT_ALPHA) out[OUT_BYTES * i + 1] = in[4 * i + 2]; /*most significant byte*/ + } + break; + default: return 31; + } + } + else /*infoIn->bitDepth is less than 8 bit per channel*/ + { + if(infoIn->colorType != 0) return 31; /*colorType 0 is the only greyscale type with < 8 bits per channel*/ + for(i = 0; i < numpixels; i++) + { + unsigned value = readBitsFromReversedStream(&bp, in, infoIn->bitDepth); + if(OUT_ALPHA) out[OUT_BYTES * i + 1] = 255; + if(OUT_ALPHA && infoIn->key_defined && value && ((1U << infoIn->bitDepth) - 1U) == infoIn->key_r && ((1U << infoIn->bitDepth) - 1U)) out[OUT_BYTES * i + 1] = 0; + value = (value * 255) / ((1 << infoIn->bitDepth) - 1); /*scale value from 0 to 255*/ + out[OUT_BYTES * i] = (unsigned char)(value); + } + } + } + else return 59; + + return 0; +} + +/*Paeth predicter, used by PNG filter type 4*/ +static int paethPredictor(int a, int b, int c) +{ + int p = a + b - c; + int pa = p > a ? p - a : a - p; + int pb = p > b ? p - b : b - p; + int pc = p > c ? p - c : c - p; + + if(pa <= pb && pa <= pc) return a; + else if(pb <= pc) return b; + else return c; +} + +/*shared values used by multiple Adam7 related functions*/ + +static const unsigned ADAM7_IX[7] = { 0, 4, 0, 2, 0, 1, 0 }; /*x start values*/ +static const unsigned ADAM7_IY[7] = { 0, 0, 4, 0, 2, 0, 1 }; /*y start values*/ +static const unsigned ADAM7_DX[7] = { 8, 8, 4, 4, 2, 2, 1 }; /*x delta values*/ +static const unsigned ADAM7_DY[7] = { 8, 8, 8, 4, 4, 2, 2 }; /*y delta values*/ + +static void Adam7_getpassvalues(unsigned passw[7], unsigned passh[7], size_t filter_passstart[8], size_t padded_passstart[8], size_t passstart[8], unsigned w, unsigned h, unsigned bpp) +{ + /*the passstart values have 8 values: the 8th one actually indicates the byte after the end of the 7th (= last) pass*/ + unsigned i; + + /*calculate width and height in pixels of each pass*/ + for(i = 0; i < 7; i++) + { + passw[i] = (w + ADAM7_DX[i] - ADAM7_IX[i] - 1) / ADAM7_DX[i]; + passh[i] = (h + ADAM7_DY[i] - ADAM7_IY[i] - 1) / ADAM7_DY[i]; + if(passw[i] == 0) passh[i] = 0; + if(passh[i] == 0) passw[i] = 0; + } + + filter_passstart[0] = padded_passstart[0] = passstart[0] = 0; + for(i = 0; i < 7; i++) + { + filter_passstart[i + 1] = filter_passstart[i] + ((passw[i] && passh[i]) ? passh[i] * (1 + (passw[i] * bpp + 7) / 8) : 0); /*if passw[i] is 0, it's 0 bytes, not 1 (no filtertype-byte)*/ + padded_passstart[i + 1] = padded_passstart[i] + passh[i] * ((passw[i] * bpp + 7) / 8); /*bits padded if needed to fill full byte at end of each scanline*/ + passstart[i + 1] = passstart[i] + (passh[i] * passw[i] * bpp + 7) / 8; /*only padded at end of reduced image*/ + } +} + +#ifdef LODEPNG_COMPILE_DECODER + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / PNG Decoder / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +/*read the information from the header and store it in the LodePNG_Info. return value is error*/ +void LodePNG_inspect(LodePNG_Decoder* decoder, const unsigned char* in, size_t inlength) +{ + if(inlength == 0 || in == 0) { decoder->error = 48; return; } /*the given data is empty*/ + if(inlength < 29) { decoder->error = 27; return; } /*error: the data length is smaller than the length of the header*/ + + /*when decoding a new PNG image, make sure all parameters created after previous decoding are reset*/ + LodePNG_InfoPng_cleanup(&decoder->infoPng); + LodePNG_InfoPng_init(&decoder->infoPng); + decoder->error = 0; + + if(in[0] != 137 || in[1] != 80 || in[2] != 78 || in[3] != 71 || in[4] != 13 || in[5] != 10 || in[6] != 26 || in[7] != 10) { decoder->error = 28; return; } /*error: the first 8 bytes are not the correct PNG signature*/ + if(in[12] != 'I' || in[13] != 'H' || in[14] != 'D' || in[15] != 'R') { decoder->error = 29; return; } /*error: it doesn't start with a IHDR chunk!*/ + + /*read the values given in the header*/ + decoder->infoPng.width = LodePNG_read32bitInt(&in[16]); + decoder->infoPng.height = LodePNG_read32bitInt(&in[20]); + decoder->infoPng.color.bitDepth = in[24]; + decoder->infoPng.color.colorType = in[25]; + decoder->infoPng.compressionMethod = in[26]; + decoder->infoPng.filterMethod = in[27]; + decoder->infoPng.interlaceMethod = in[28]; + + if(!decoder->settings.ignoreCrc) + { + unsigned CRC = LodePNG_read32bitInt(&in[29]); + unsigned checksum = Crc32_crc(&in[12], 17); + if(CRC != checksum) { decoder->error = 57; return; } + } + + if(decoder->infoPng.compressionMethod != 0) { decoder->error = 32; return; } /*error: only compression method 0 is allowed in the specification*/ + if(decoder->infoPng.filterMethod != 0) { decoder->error = 33; return; } /*error: only filter method 0 is allowed in the specification*/ + if(decoder->infoPng.interlaceMethod > 1) { decoder->error = 34; return; } /*error: only interlace methods 0 and 1 exist in the specification*/ + + decoder->error = checkColorValidity(decoder->infoPng.color.colorType, decoder->infoPng.color.bitDepth); +} + +static unsigned unfilterScanline(unsigned char* recon, const unsigned char* scanline, const unsigned char* precon, size_t bytewidth, unsigned char filterType, size_t length) +{ + /* + For PNG filter method 0 + unfilter a PNG image scanline by scanline. when the pixels are smaller than 1 byte, the filter works byte per byte (bytewidth = 1) + precon is the previous unfiltered scanline, recon the result, scanline the current one + the incoming scanlines do NOT include the filtertype byte, that one is given in the parameter filterType instead + recon and scanline MAY be the same memory address! precon must be disjoint. + */ + + size_t i; + switch(filterType) + { + case 0: + for(i = 0; i < length; i++) recon[i] = scanline[i]; + break; + case 1: + for(i = 0; i < bytewidth; i++) recon[i] = scanline[i]; + for(i = bytewidth; i < length; i++) recon[i] = scanline[i] + recon[i - bytewidth]; + break; + case 2: + if(precon) for(i = 0; i < length; i++) recon[i] = scanline[i] + precon[i]; + else for(i = 0; i < length; i++) recon[i] = scanline[i]; + break; + case 3: + if(precon) + { + for(i = 0; i < bytewidth; i++) recon[i] = scanline[i] + precon[i] / 2; + for(i = bytewidth; i < length; i++) recon[i] = scanline[i] + ((recon[i - bytewidth] + precon[i]) / 2); + } + else + { + for(i = 0; i < bytewidth; i++) recon[i] = scanline[i]; + for(i = bytewidth; i < length; i++) recon[i] = scanline[i] + recon[i - bytewidth] / 2; + } + break; + case 4: + if(precon) + { + for(i = 0; i < bytewidth; i++) recon[i] = (unsigned char)(scanline[i] + paethPredictor(0, precon[i], 0)); + for(i = bytewidth; i < length; i++) recon[i] = (unsigned char)(scanline[i] + paethPredictor(recon[i - bytewidth], precon[i], precon[i - bytewidth])); + } + else + { + for(i = 0; i < bytewidth; i++) recon[i] = scanline[i]; + for(i = bytewidth; i < length; i++) recon[i] = (unsigned char)(scanline[i] + paethPredictor(recon[i - bytewidth], 0, 0)); + } + break; + default: return 36; /*error: unexisting filter type given*/ + } + return 0; +} + +static unsigned unfilter(unsigned char* out, const unsigned char* in, unsigned w, unsigned h, unsigned bpp) +{ + /* + For PNG filter method 0 + this function unfilters a single image (e.g. without interlacing this is called once, with Adam7 it's called 7 times) + out must have enough bytes allocated already, in must have the scanlines + 1 filtertype byte per scanline + w and h are image dimensions or dimensions of reduced image, bpp is bits per pixel + in and out are allowed to be the same memory address! + */ + + unsigned y; + unsigned char* prevline = 0; + + size_t bytewidth = (bpp + 7) / 8; /*bytewidth is used for filtering, is 1 when bpp < 8, number of bytes per pixel otherwise*/ + size_t linebytes = (w * bpp + 7) / 8; + + for(y = 0; y < h; y++) + { + size_t outindex = linebytes * y; + size_t inindex = (1 + linebytes) * y; /*the extra filterbyte added to each row*/ + unsigned char filterType = in[inindex]; + + unsigned error = unfilterScanline(&out[outindex], &in[inindex + 1], prevline, bytewidth, filterType, linebytes); + if(error) return error; + + prevline = &out[outindex]; + } + + return 0; +} + +static void Adam7_deinterlace(unsigned char* out, const unsigned char* in, unsigned w, unsigned h, unsigned bpp) +{ + /*Note: this function works on image buffers WITHOUT padding bits at end of scanlines with non-multiple-of-8 bit amounts, only between reduced images is padding + out must be big enough AND must be 0 everywhere if bpp < 8 in the current implementation (because that's likely a little bit faster)*/ + unsigned passw[7], passh[7]; size_t filter_passstart[8], padded_passstart[8], passstart[8]; + unsigned i; + + Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, passstart, w, h, bpp); + + if(bpp >= 8) + { + for(i = 0; i < 7; i++) + { + unsigned x, y, b; + size_t bytewidth = bpp / 8; + for(y = 0; y < passh[i]; y++) + for(x = 0; x < passw[i]; x++) + { + size_t pixelinstart = passstart[i] + (y * passw[i] + x) * bytewidth; + size_t pixeloutstart = ((ADAM7_IY[i] + y * ADAM7_DY[i]) * w + ADAM7_IX[i] + x * ADAM7_DX[i]) * bytewidth; + for(b = 0; b < bytewidth; b++) + { + out[pixeloutstart + b] = in[pixelinstart + b]; + } + } + } + } + else /*bpp < 8: Adam7 with pixels < 8 bit is a bit trickier: with bit pointers*/ + { + for(i = 0; i < 7; i++) + { + unsigned x, y, b; + unsigned ilinebits = bpp * passw[i]; + unsigned olinebits = bpp * w; + size_t obp, ibp; /*bit pointers (for out and in buffer)*/ + for(y = 0; y < passh[i]; y++) + for(x = 0; x < passw[i]; x++) + { + ibp = (8 * passstart[i]) + (y * ilinebits + x * bpp); + obp = (ADAM7_IY[i] + y * ADAM7_DY[i]) * olinebits + (ADAM7_IX[i] + x * ADAM7_DX[i]) * bpp; + for(b = 0; b < bpp; b++) + { + unsigned char bit = readBitFromReversedStream(&ibp, in); + setBitOfReversedStream0(&obp, out, bit); /*note that this function assumes the out buffer is completely 0, use setBitOfReversedStream otherwise*/ + } + } + } + } +} + +static void removePaddingBits(unsigned char* out, const unsigned char* in, size_t olinebits, size_t ilinebits, unsigned h) +{ + /* + After filtering there are still padding bits if scanlines have non multiple of 8 bit amounts. They need to be removed (except at last scanline of (Adam7-reduced) image) before working with pure image buffers for the Adam7 code, the color convert code and the output to the user. + in and out are allowed to be the same buffer, in may also be higher but still overlapping; in must have >= ilinebits*h bits, out must have >= olinebits*h bits, olinebits must be <= ilinebits + also used to move bits after earlier such operations happened, e.g. in a sequence of reduced images from Adam7 + only useful if (ilinebits - olinebits) is a value in the range 1..7 + */ + unsigned y; + size_t diff = ilinebits - olinebits; + size_t obp = 0, ibp = 0; /*bit pointers*/ + for(y = 0; y < h; y++) + { + size_t x; + for(x = 0; x < olinebits; x++) + { + unsigned char bit = readBitFromReversedStream(&ibp, in); + setBitOfReversedStream(&obp, out, bit); + } + ibp += diff; + } +} + +/*out must be buffer big enough to contain full image, and in must contain the full decompressed data from the IDAT chunks*/ +static unsigned postProcessScanlines(unsigned char* out, unsigned char* in, const LodePNG_InfoPng* infoPng) /*return value is error*/ +{ + /* + This function converts the filtered-padded-interlaced data into pure 2D image buffer with the PNG's colortype. Steps: + *) if no Adam7: 1) unfilter 2) remove padding bits (= posible extra bits per scanline if bpp < 8) + *) if adam7: 1) 7x unfilter 2) 7x remove padding bits 3) Adam7_deinterlace + NOTE: the in buffer will be overwritten with intermediate data! + */ + unsigned bpp = LodePNG_InfoColor_getBpp(&infoPng->color); + unsigned w = infoPng->width; + unsigned h = infoPng->height; + unsigned error = 0; + if(bpp == 0) return 31; /*error: invalid colortype*/ + + if(infoPng->interlaceMethod == 0) + { + if(bpp < 8 && w * bpp != ((w * bpp + 7) / 8) * 8) + { + error = unfilter(in, in, w, h, bpp); + if(error) return error; + removePaddingBits(out, in, w * bpp, ((w * bpp + 7) / 8) * 8, h); + } + else error = unfilter(out, in, w, h, bpp); /*we can immediatly filter into the out buffer, no other steps needed*/ + } + else /*interlaceMethod is 1 (Adam7)*/ + { + unsigned passw[7], passh[7]; size_t filter_passstart[8], padded_passstart[8], passstart[8]; + unsigned i; + + Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, passstart, w, h, bpp); + + for(i = 0; i < 7; i++) + { + error = unfilter(&in[padded_passstart[i]], &in[filter_passstart[i]], passw[i], passh[i], bpp); + if(error) return error; + if(bpp < 8) /*TODO: possible efficiency improvement: if in this reduced image the bits fit nicely in 1 scanline, move bytes instead of bits or move not at all*/ + { + /*remove padding bits in scanlines; after this there still may be padding bits between the different reduced images: each reduced image still starts nicely at a byte*/ + removePaddingBits(&in[passstart[i]], &in[padded_passstart[i]], passw[i] * bpp, ((passw[i] * bpp + 7) / 8) * 8, passh[i]); + } + } + + Adam7_deinterlace(out, in, w, h, bpp); + } + + return error; +} + +/*read a PNG, the result will be in the same color type as the PNG (hence "generic")*/ +static void decodeGeneric(LodePNG_Decoder* decoder, unsigned char** out, size_t* outsize, const unsigned char* in, size_t size) +{ + unsigned char IEND = 0; + const unsigned char* chunk; + size_t i; + ucvector idat; /*the data from idat chunks*/ + + /*for unknown chunk order*/ + unsigned unknown = 0; + unsigned critical_pos = 1; /*1 = after IHDR, 2 = after PLTE, 3 = after IDAT*/ + + /*provide some proper output values if error will happen*/ + *out = 0; + *outsize = 0; + + if(size == 0 || in == 0) { decoder->error = 48; return; } /*the given data is empty*/ + + LodePNG_inspect(decoder, in, size); /*reads header and resets other parameters in decoder->infoPng*/ + if(decoder->error) return; + + ucvector_init(&idat); + + chunk = &in[33]; /*first byte of the first chunk after the header*/ + + while(!IEND) /*loop through the chunks, ignoring unknown chunks and stopping at IEND chunk. IDAT data is put at the start of the in buffer*/ + { + unsigned chunkLength; + const unsigned char* data; /*the data in the chunk*/ + + if((size_t)((chunk - in) + 12) > size || chunk < in) { decoder->error = 30; break; } /*error: size of the in buffer too small to contain next chunk*/ + chunkLength = LodePNG_chunk_length(chunk); /*length of the data of the chunk, excluding the length bytes, chunk type and CRC bytes*/ + if(chunkLength > 2147483647) { decoder->error = 63; break; } + if((size_t)((chunk - in) + chunkLength + 12) > size || (chunk + chunkLength + 12) < in) { decoder->error = 35; break; } /*error: size of the in buffer too small to contain next chunk*/ + data = LodePNG_chunk_data_const(chunk); + + /*IDAT chunk, containing compressed image data*/ + if(LodePNG_chunk_type_equals(chunk, "IDAT")) + { + size_t oldsize = idat.size; + if(!ucvector_resize(&idat, oldsize + chunkLength)) { decoder->error = 9936; break; } + for(i = 0; i < chunkLength; i++) idat.data[oldsize + i] = data[i]; + critical_pos = 3; + } + /*IEND chunk*/ + else if(LodePNG_chunk_type_equals(chunk, "IEND")) + { + IEND = 1; + } + /*palette chunk (PLTE)*/ + else if(LodePNG_chunk_type_equals(chunk, "PLTE")) + { + unsigned pos = 0; + if(decoder->infoPng.color.palette) free(decoder->infoPng.color.palette); + decoder->infoPng.color.palettesize = chunkLength / 3; + decoder->infoPng.color.palette = (unsigned char*)malloc(4 * decoder->infoPng.color.palettesize); + if(!decoder->infoPng.color.palette && decoder->infoPng.color.palettesize) { decoder->error = 9937; break; } + if(!decoder->infoPng.color.palette) decoder->infoPng.color.palettesize = 0; /*malloc failed...*/ + if(decoder->infoPng.color.palettesize > 256) { decoder->error = 38; break; } /*error: palette too big*/ + for(i = 0; i < decoder->infoPng.color.palettesize; i++) + { + decoder->infoPng.color.palette[4 * i + 0] = data[pos++]; /*R*/ + decoder->infoPng.color.palette[4 * i + 1] = data[pos++]; /*G*/ + decoder->infoPng.color.palette[4 * i + 2] = data[pos++]; /*B*/ + decoder->infoPng.color.palette[4 * i + 3] = 255; /*alpha*/ + } + critical_pos = 2; + } + /*palette transparency chunk (tRNS)*/ + else if(LodePNG_chunk_type_equals(chunk, "tRNS")) + { + if(decoder->infoPng.color.colorType == 3) + { + if(chunkLength > decoder->infoPng.color.palettesize) { decoder->error = 39; break; } /*error: more alpha values given than there are palette entries*/ + for(i = 0; i < chunkLength; i++) decoder->infoPng.color.palette[4 * i + 3] = data[i]; + } + else if(decoder->infoPng.color.colorType == 0) + { + if(chunkLength != 2) { decoder->error = 40; break; } /*error: this chunk must be 2 bytes for greyscale image*/ + decoder->infoPng.color.key_defined = 1; + decoder->infoPng.color.key_r = decoder->infoPng.color.key_g = decoder->infoPng.color.key_b = 256 * data[0] + data[1]; + } + else if(decoder->infoPng.color.colorType == 2) + { + if(chunkLength != 6) { decoder->error = 41; break; } /*error: this chunk must be 6 bytes for RGB image*/ + decoder->infoPng.color.key_defined = 1; + decoder->infoPng.color.key_r = 256 * data[0] + data[1]; + decoder->infoPng.color.key_g = 256 * data[2] + data[3]; + decoder->infoPng.color.key_b = 256 * data[4] + data[5]; + } + else { decoder->error = 42; break; } /*error: tRNS chunk not allowed for other color models*/ + } +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + /*background color chunk (bKGD)*/ + else if(LodePNG_chunk_type_equals(chunk, "bKGD")) + { + if(decoder->infoPng.color.colorType == 3) + { + if(chunkLength != 1) { decoder->error = 43; break; } /*error: this chunk must be 1 byte for indexed color image*/ + decoder->infoPng.background_defined = 1; + decoder->infoPng.background_r = decoder->infoPng.background_g = decoder->infoPng.background_g = data[0]; + } + else if(decoder->infoPng.color.colorType == 0 || decoder->infoPng.color.colorType == 4) + { + if(chunkLength != 2) { decoder->error = 44; break; } /*error: this chunk must be 2 bytes for greyscale image*/ + decoder->infoPng.background_defined = 1; + decoder->infoPng.background_r = decoder->infoPng.background_g = decoder->infoPng.background_b = 256 * data[0] + data[1]; + } + else if(decoder->infoPng.color.colorType == 2 || decoder->infoPng.color.colorType == 6) + { + if(chunkLength != 6) { decoder->error = 45; break; } /*error: this chunk must be 6 bytes for greyscale image*/ + decoder->infoPng.background_defined = 1; + decoder->infoPng.background_r = 256 * data[0] + data[1]; + decoder->infoPng.background_g = 256 * data[2] + data[3]; + decoder->infoPng.background_b = 256 * data[4] + data[5]; + } + } + /*text chunk (tEXt)*/ + else if(LodePNG_chunk_type_equals(chunk, "tEXt")) + { + if(decoder->settings.readTextChunks) + { + char *key = 0, *str = 0; + + while(!decoder->error) /*not really a while loop, only used to break on error*/ + { + unsigned length, string2_begin; + + for(length = 0; length < chunkLength && data[length] != 0; length++) ; + if(length + 1 >= chunkLength) { decoder->error = 75; break; } + key = (char*)malloc(length + 1); + if(!key) { decoder->error = 9938; break; } + key[length] = 0; + for(i = 0; i < length; i++) key[i] = data[i]; + + string2_begin = length + 1; + if(string2_begin > chunkLength) { decoder->error = 75; break; } + length = chunkLength - string2_begin; + str = (char*)malloc(length + 1); + if(!str) { decoder->error = 9939; break; } + str[length] = 0; + for(i = 0; i < length; i++) str[i] = data[string2_begin + i]; + + decoder->error = LodePNG_Text_add(&decoder->infoPng.text, key, str); + + break; + } + + free(key); + free(str); + } + } + /*compressed text chunk (zTXt)*/ + else if(LodePNG_chunk_type_equals(chunk, "zTXt")) + { + if(decoder->settings.readTextChunks) + { + unsigned length, string2_begin; + char *key = 0; + ucvector decoded; + + ucvector_init(&decoded); + + while(!decoder->error) /*not really a while loop, only used to break on error*/ + { + for(length = 0; length < chunkLength && data[length] != 0; length++) ; + if(length + 2 >= chunkLength) { decoder->error = 75; break; } + key = (char*)malloc(length + 1); + if(!key) { decoder->error = 9940; break; } + key[length] = 0; + for(i = 0; i < length; i++) key[i] = data[i]; + + if(data[length + 1] != 0) { decoder->error = 72; break; } /*the 0 byte indicating compression must be 0*/ + + string2_begin = length + 2; + if(string2_begin > chunkLength) { decoder->error = 75; break; } + length = chunkLength - string2_begin; + decoder->error = LodePNG_decompress(&decoded.data, &decoded.size, (unsigned char*)(&data[string2_begin]), length, &decoder->settings.zlibsettings); + if(decoder->error) break; + ucvector_push_back(&decoded, 0); + + decoder->error = LodePNG_Text_add(&decoder->infoPng.text, key, (char*)decoded.data); + + break; + } + + free(key); + ucvector_cleanup(&decoded); + if(decoder->error) break; + } + } + /*international text chunk (iTXt)*/ + else if(LodePNG_chunk_type_equals(chunk, "iTXt")) + { + if(decoder->settings.readTextChunks) + { + unsigned length, begin, compressed; + char *key = 0, *langtag = 0, *transkey = 0; + ucvector decoded; + ucvector_init(&decoded); + + while(!decoder->error) /*not really a while loop, only used to break on error*/ + { + if(chunkLength < 5) { decoder->error = 76; break; } + for(length = 0; length < chunkLength && data[length] != 0; length++) ; + if(length + 2 >= chunkLength) { decoder->error = 75; break; } + key = (char*)malloc(length + 1); + if(!key) { decoder->error = 9941; break; } + key[length] = 0; + for(i = 0; i < length; i++) key[i] = data[i]; + + compressed = data[length + 1]; + if(data[length + 2] != 0) { decoder->error = 72; break; } /*the 0 byte indicating compression must be 0*/ + + begin = length + 3; + length = 0; + for(i = begin; i < chunkLength && data[i] != 0; i++) length++; + if(begin + length + 1 >= chunkLength) { decoder->error = 75; break; } + langtag = (char*)malloc(length + 1); + if(!langtag) { decoder->error = 9942; break; } + langtag[length] = 0; + for(i = 0; i < length; i++) langtag[i] = data[begin + i]; + + begin += length + 1; + length = 0; + for(i = begin; i < chunkLength && data[i] != 0; i++) length++; + if(begin + length + 1 >= chunkLength) { decoder->error = 75; break; } + transkey = (char*)malloc(length + 1); + if(!transkey) { decoder->error = 9943; break; } + transkey[length] = 0; + for(i = 0; i < length; i++) transkey[i] = data[begin + i]; + + begin += length + 1; + if(begin > chunkLength) { decoder->error = 75; break; } + length = chunkLength - begin; + + if(compressed) + { + decoder->error = LodePNG_decompress(&decoded.data, &decoded.size, (unsigned char*)(&data[begin]), length, &decoder->settings.zlibsettings); + if(decoder->error) break; + ucvector_push_back(&decoded, 0); + } + else + { + if(!ucvector_resize(&decoded, length + 1)) { decoder->error = 9944; break; } + decoded.data[length] = 0; + for(i = 0; i < length; i++) decoded.data[i] = data[begin + i]; + } + + decoder->error = LodePNG_IText_add(&decoder->infoPng.itext, key, langtag, transkey, (char*)decoded.data); + + break; + } + + free(key); + free(langtag); + free(transkey); + ucvector_cleanup(&decoded); + if(decoder->error) break; + } + } + else if(LodePNG_chunk_type_equals(chunk, "tIME")) + { + if(chunkLength != 7) { decoder->error = 73; break; } + decoder->infoPng.time_defined = 1; + decoder->infoPng.time.year = 256 * data[0] + data[+ 1]; + decoder->infoPng.time.month = data[2]; + decoder->infoPng.time.day = data[3]; + decoder->infoPng.time.hour = data[4]; + decoder->infoPng.time.minute = data[5]; + decoder->infoPng.time.second = data[6]; + } + else if(LodePNG_chunk_type_equals(chunk, "pHYs")) + { + if(chunkLength != 9) { decoder->error = 74; break; } + decoder->infoPng.phys_defined = 1; + decoder->infoPng.phys_x = 16777216 * data[0] + 65536 * data[1] + 256 * data[2] + data[3]; + decoder->infoPng.phys_y = 16777216 * data[4] + 65536 * data[5] + 256 * data[6] + data[7]; + decoder->infoPng.phys_unit = data[8]; + } +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + else /*it's not an implemented chunk type, so ignore it: skip over the data*/ + { + if(LodePNG_chunk_critical(chunk)) { decoder->error = 69; break; } /*error: unknown critical chunk (5th bit of first byte of chunk type is 0)*/ + unknown = 1; +#ifdef LODEPNG_COMPILE_UNKNOWN_CHUNKS + if(decoder->settings.rememberUnknownChunks) + { + LodePNG_UnknownChunks* unknown = &decoder->infoPng.unknown_chunks; + decoder->error = LodePNG_append_chunk(&unknown->data[critical_pos - 1], &unknown->datasize[critical_pos - 1], chunk); + if(decoder->error) break; + } +#endif /*LODEPNG_COMPILE_UNKNOWN_CHUNKS*/ + } + + if(!decoder->settings.ignoreCrc && !unknown) /*check CRC if wanted, only on known chunk types*/ + { + if(LodePNG_chunk_check_crc(chunk)) { decoder->error = 57; break; } + } + + if(!IEND) chunk = LodePNG_chunk_next_const(chunk); + } + + if(!decoder->error) + { + ucvector scanlines; + ucvector_init(&scanlines); + if(!ucvector_resize(&scanlines, ((decoder->infoPng.width * (decoder->infoPng.height * LodePNG_InfoColor_getBpp(&decoder->infoPng.color) + 7)) / 8) + decoder->infoPng.height)) decoder->error = 9945; /*maximum final image length is already reserved in the vector's length - this is not really necessary*/ + if(!decoder->error) decoder->error = LodePNG_decompress(&scanlines.data, &scanlines.size, idat.data, idat.size, &decoder->settings.zlibsettings); /*decompress with the Zlib decompressor*/ + + if(!decoder->error) + { + ucvector outv; + ucvector_init(&outv); + if(!ucvector_resizev(&outv, (decoder->infoPng.height * decoder->infoPng.width * LodePNG_InfoColor_getBpp(&decoder->infoPng.color) + 7) / 8, 0)) decoder->error = 9946; + if(!decoder->error) decoder->error = postProcessScanlines(outv.data, scanlines.data, &decoder->infoPng); + *out = outv.data; + *outsize = outv.size; + } + ucvector_cleanup(&scanlines); + } + + ucvector_cleanup(&idat); +} + +void LodePNG_decode(LodePNG_Decoder* decoder, unsigned char** out, size_t* outsize, const unsigned char* in, size_t insize) +{ + *out = 0; + *outsize = 0; + decodeGeneric(decoder, out, outsize, in, insize); + if(decoder->error) return; + if(!decoder->settings.color_convert || LodePNG_InfoColor_equal(&decoder->infoRaw.color, &decoder->infoPng.color)) + { + /*same color type, no copying or converting of data needed*/ + /*store the infoPng color settings on the infoRaw so that the infoRaw still reflects what colorType + the raw image has to the end user*/ + if(!decoder->settings.color_convert) + { + decoder->error = LodePNG_InfoColor_copy(&decoder->infoRaw.color, &decoder->infoPng.color); + if(decoder->error) return; + } + } + else + { + /*color conversion needed; sort of copy of the data*/ + unsigned char* data = *out; + + /*TODO: check if this works according to the statement in the documentation: "The converter can convert from greyscale input color type, to 8-bit greyscale or greyscale with alpha"*/ + if(!(decoder->infoRaw.color.colorType == 2 || decoder->infoRaw.color.colorType == 6) && !(decoder->infoRaw.color.bitDepth == 8)) { decoder->error = 56; return; } + + *outsize = (decoder->infoPng.width * decoder->infoPng.height * LodePNG_InfoColor_getBpp(&decoder->infoRaw.color) + 7) / 8; + *out = (unsigned char*)malloc(*outsize); + if(!(*out)) + { + decoder->error = 9947; + *outsize = 0; + } + else decoder->error = LodePNG_convert(*out, data, &decoder->infoRaw.color, &decoder->infoPng.color, decoder->infoPng.width, decoder->infoPng.height); + free(data); + } +} + +unsigned LodePNG_decode32(unsigned char** out, unsigned* w, unsigned* h, const unsigned char* in, size_t insize) +{ + unsigned error; + size_t dummy_size; + LodePNG_Decoder decoder; + LodePNG_Decoder_init(&decoder); + LodePNG_decode(&decoder, out, &dummy_size, in, insize); + error = decoder.error; + *w = decoder.infoPng.width; + *h = decoder.infoPng.height; + LodePNG_Decoder_cleanup(&decoder); + return error; +} + +#ifdef LODEPNG_COMPILE_DISK +unsigned LodePNG_decode32f(unsigned char** out, unsigned* w, unsigned* h, const char* filename) +{ + unsigned char* buffer; + size_t buffersize; + unsigned error; + error = LodePNG_loadFile(&buffer, &buffersize, filename); + if(!error) error = LodePNG_decode32(out, w, h, buffer, buffersize); + free(buffer); + return error; +} +#endif /*LODEPNG_COMPILE_DISK*/ + +void LodePNG_DecodeSettings_init(LodePNG_DecodeSettings* settings) +{ + settings->color_convert = 1; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + settings->readTextChunks = 1; +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + settings->ignoreCrc = 0; +#ifdef LODEPNG_COMPILE_UNKNOWN_CHUNKS + settings->rememberUnknownChunks = 0; +#endif /*LODEPNG_COMPILE_UNKNOWN_CHUNKS*/ + LodeZlib_DecompressSettings_init(&settings->zlibsettings); +} + +void LodePNG_Decoder_init(LodePNG_Decoder* decoder) +{ + LodePNG_DecodeSettings_init(&decoder->settings); + LodePNG_InfoRaw_init(&decoder->infoRaw); + LodePNG_InfoPng_init(&decoder->infoPng); + decoder->error = 1; +} + +void LodePNG_Decoder_cleanup(LodePNG_Decoder* decoder) +{ + LodePNG_InfoRaw_cleanup(&decoder->infoRaw); + LodePNG_InfoPng_cleanup(&decoder->infoPng); +} + +void LodePNG_Decoder_copy(LodePNG_Decoder* dest, const LodePNG_Decoder* source) +{ + LodePNG_Decoder_cleanup(dest); + *dest = *source; + LodePNG_InfoRaw_init(&dest->infoRaw); + LodePNG_InfoPng_init(&dest->infoPng); + dest->error = LodePNG_InfoRaw_copy(&dest->infoRaw, &source->infoRaw); if(dest->error) return; + dest->error = LodePNG_InfoPng_copy(&dest->infoPng, &source->infoPng); if(dest->error) return; +} + +#endif /*LODEPNG_COMPILE_DECODER*/ + +#ifdef LODEPNG_COMPILE_ENCODER + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / PNG Encoder / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +/*chunkName must be string of 4 characters*/ +static unsigned addChunk(ucvector* out, const char* chunkName, const unsigned char* data, size_t length) +{ + unsigned error = LodePNG_create_chunk(&out->data, &out->size, (unsigned)length, chunkName, data); + if(error) return error; + out->allocsize = out->size; /*fix the allocsize again*/ + return 0; +} + +static void writeSignature(ucvector* out) +{ + /*8 bytes PNG signature*/ + ucvector_push_back(out, 137); + ucvector_push_back(out, 80); + ucvector_push_back(out, 78); + ucvector_push_back(out, 71); + ucvector_push_back(out, 13); + ucvector_push_back(out, 10); + ucvector_push_back(out, 26); + ucvector_push_back(out, 10); +} + +static unsigned addChunk_IHDR(ucvector* out, unsigned w, unsigned h, unsigned bitDepth, unsigned colorType, unsigned interlaceMethod) +{ + unsigned error = 0; + ucvector header; + ucvector_init(&header); + + LodePNG_add32bitInt(&header, w); /*width*/ + LodePNG_add32bitInt(&header, h); /*height*/ + ucvector_push_back(&header, (unsigned char)bitDepth); /*bit depth*/ + ucvector_push_back(&header, (unsigned char)colorType); /*color type*/ + ucvector_push_back(&header, 0); /*compression method*/ + ucvector_push_back(&header, 0); /*filter method*/ + ucvector_push_back(&header, interlaceMethod); /*interlace method*/ + + error = addChunk(out, "IHDR", header.data, header.size); + ucvector_cleanup(&header); + + return error; +} + +static unsigned addChunk_PLTE(ucvector* out, const LodePNG_InfoColor* info) +{ + unsigned error = 0; + size_t i; + ucvector PLTE; + ucvector_init(&PLTE); + for(i = 0; i < info->palettesize * 4; i++) if(i % 4 != 3) ucvector_push_back(&PLTE, info->palette[i]); /*add all channels except alpha channel*/ + error = addChunk(out, "PLTE", PLTE.data, PLTE.size); + ucvector_cleanup(&PLTE); + + return error; +} + +static unsigned addChunk_tRNS(ucvector* out, const LodePNG_InfoColor* info) +{ + unsigned error = 0; + size_t i; + ucvector tRNS; + ucvector_init(&tRNS); + if(info->colorType == 3) + { + for(i = 0; i < info->palettesize; i++) ucvector_push_back(&tRNS, info->palette[4 * i + 3]); /*add only alpha channel*/ + } + else if(info->colorType == 0) + { + if(info->key_defined) + { + ucvector_push_back(&tRNS, (unsigned char)(info->key_r / 256)); + ucvector_push_back(&tRNS, (unsigned char)(info->key_r % 256)); + } + } + else if(info->colorType == 2) + { + if(info->key_defined) + { + ucvector_push_back(&tRNS, (unsigned char)(info->key_r / 256)); + ucvector_push_back(&tRNS, (unsigned char)(info->key_r % 256)); + ucvector_push_back(&tRNS, (unsigned char)(info->key_g / 256)); + ucvector_push_back(&tRNS, (unsigned char)(info->key_g % 256)); + ucvector_push_back(&tRNS, (unsigned char)(info->key_b / 256)); + ucvector_push_back(&tRNS, (unsigned char)(info->key_b % 256)); + } + } + + error = addChunk(out, "tRNS", tRNS.data, tRNS.size); + ucvector_cleanup(&tRNS); + + return error; +} + +static unsigned addChunk_IDAT(ucvector* out, const unsigned char* data, size_t datasize, LodeZlib_DeflateSettings* zlibsettings) +{ + ucvector zlibdata; + unsigned error = 0; + + /*compress with the Zlib compressor*/ + ucvector_init(&zlibdata); + error = LodePNG_compress(&zlibdata.data, &zlibdata.size, data, datasize, zlibsettings); + if(!error) error = addChunk(out, "IDAT", zlibdata.data, zlibdata.size); + ucvector_cleanup(&zlibdata); + + return error; +} + +static unsigned addChunk_IEND(ucvector* out) +{ + unsigned error = 0; + error = addChunk(out, "IEND", 0, 0); + return error; +} + +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + +static unsigned addChunk_tEXt(ucvector* out, const char* keyword, const char* textstring) /*add text chunk*/ +{ + unsigned error = 0; + size_t i; + ucvector text; + ucvector_init(&text); + for(i = 0; keyword[i] != 0; i++) ucvector_push_back(&text, (unsigned char)keyword[i]); + ucvector_push_back(&text, 0); + for(i = 0; textstring[i] != 0; i++) ucvector_push_back(&text, (unsigned char)textstring[i]); + error = addChunk(out, "tEXt", text.data, text.size); + ucvector_cleanup(&text); + + return error; +} + +static unsigned addChunk_zTXt(ucvector* out, const char* keyword, const char* textstring, LodeZlib_DeflateSettings* zlibsettings) +{ + unsigned error = 0; + ucvector data, compressed; + size_t i, textsize = strlen(textstring); + + ucvector_init(&data); + ucvector_init(&compressed); + for(i = 0; keyword[i] != 0; i++) ucvector_push_back(&data, (unsigned char)keyword[i]); + ucvector_push_back(&data, 0); /* 0 termination char*/ + ucvector_push_back(&data, 0); /*compression method: 0*/ + + error = LodePNG_compress(&compressed.data, &compressed.size, (unsigned char*)textstring, textsize, zlibsettings); + if(!error) + { + for(i = 0; i < compressed.size; i++) ucvector_push_back(&data, compressed.data[i]); + error = addChunk(out, "zTXt", data.data, data.size); + } + + ucvector_cleanup(&compressed); + ucvector_cleanup(&data); + return error; +} + +static unsigned addChunk_iTXt(ucvector* out, unsigned compressed, const char* keyword, const char* langtag, const char* transkey, const char* textstring, LodeZlib_DeflateSettings* zlibsettings) +{ + unsigned error = 0; + ucvector data, compressed_data; + size_t i, textsize = strlen(textstring); + + ucvector_init(&data); + + for(i = 0; keyword[i] != 0; i++) ucvector_push_back(&data, (unsigned char)keyword[i]); + ucvector_push_back(&data, 0); /*null termination char*/ + ucvector_push_back(&data, compressed ? 1 : 0); /*compression flag*/ + ucvector_push_back(&data, 0); /*compression method*/ + for(i = 0; langtag[i] != 0; i++) ucvector_push_back(&data, (unsigned char)langtag[i]); + ucvector_push_back(&data, 0); /*null termination char*/ + for(i = 0; transkey[i] != 0; i++) ucvector_push_back(&data, (unsigned char)transkey[i]); + ucvector_push_back(&data, 0); /*null termination char*/ + + if(compressed) + { + ucvector_init(&compressed_data); + error = LodePNG_compress(&compressed_data.data, &compressed_data.size, (unsigned char*)textstring, textsize, zlibsettings); + if(!error) + { + for(i = 0; i < compressed_data.size; i++) ucvector_push_back(&data, compressed_data.data[i]); + for(i = 0; textstring[i] != 0; i++) ucvector_push_back(&data, (unsigned char)textstring[i]); + } + } + else /*not compressed*/ + { + for(i = 0; textstring[i] != 0; i++) ucvector_push_back(&data, (unsigned char)textstring[i]); + } + + if(!error) error = addChunk(out, "iTXt", data.data, data.size); + ucvector_cleanup(&data); + return error; +} + +static unsigned addChunk_bKGD(ucvector* out, const LodePNG_InfoPng* info) +{ + unsigned error = 0; + ucvector bKGD; + ucvector_init(&bKGD); + if(info->color.colorType == 0 || info->color.colorType == 4) + { + ucvector_push_back(&bKGD, (unsigned char)(info->background_r / 256)); + ucvector_push_back(&bKGD, (unsigned char)(info->background_r % 256)); + } + else if(info->color.colorType == 2 || info->color.colorType == 6) + { + ucvector_push_back(&bKGD, (unsigned char)(info->background_r / 256)); + ucvector_push_back(&bKGD, (unsigned char)(info->background_r % 256)); + ucvector_push_back(&bKGD, (unsigned char)(info->background_g / 256)); + ucvector_push_back(&bKGD, (unsigned char)(info->background_g % 256)); + ucvector_push_back(&bKGD, (unsigned char)(info->background_b / 256)); + ucvector_push_back(&bKGD, (unsigned char)(info->background_b % 256)); + } + else if(info->color.colorType == 3) + { + ucvector_push_back(&bKGD, (unsigned char)(info->background_r % 256)); /*palette index*/ + } + + error = addChunk(out, "bKGD", bKGD.data, bKGD.size); + ucvector_cleanup(&bKGD); + + return error; +} + +static unsigned addChunk_tIME(ucvector* out, const LodePNG_Time* time) +{ + unsigned error = 0; + unsigned char* data = (unsigned char*)malloc(7); + if(!data) return 9948; + data[0] = (unsigned char)(time->year / 256); + data[1] = (unsigned char)(time->year % 256); + data[2] = time->month; + data[3] = time->day; + data[4] = time->hour; + data[5] = time->minute; + data[6] = time->second; + error = addChunk(out, "tIME", data, 7); + free(data); + return error; +} + +static unsigned addChunk_pHYs(ucvector* out, const LodePNG_InfoPng* info) +{ + unsigned error = 0; + ucvector data; + ucvector_init(&data); + + LodePNG_add32bitInt(&data, info->phys_x); + LodePNG_add32bitInt(&data, info->phys_y); + ucvector_push_back(&data, info->phys_unit); + + error = addChunk(out, "pHYs", data.data, data.size); + ucvector_cleanup(&data); + + return error; +} + +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + +static void filterScanline(unsigned char* out, const unsigned char* scanline, const unsigned char* prevline, size_t length, size_t bytewidth, unsigned char filterType) +{ + size_t i; + switch(filterType) + { + case 0: + if(prevline) for(i = 0; i < length; i++) out[i] = scanline[i]; + else for(i = 0; i < length; i++) out[i] = scanline[i]; + break; + case 1: + if(prevline) + { + for(i = 0; i < bytewidth; i++) out[i] = scanline[i]; + for(i = bytewidth; i < length ; i++) out[i] = scanline[i] - scanline[i - bytewidth]; + } + else + { + for(i = 0; i < bytewidth; i++) out[i] = scanline[i]; + for(i = bytewidth; i < length; i++) out[i] = scanline[i] - scanline[i - bytewidth]; + } + break; + case 2: + if(prevline) for(i = 0; i < length; i++) out[i] = scanline[i] - prevline[i]; + else for(i = 0; i < length; i++) out[i] = scanline[i]; + break; + case 3: + if(prevline) + { + for(i = 0; i < bytewidth; i++) out[i] = scanline[i] - prevline[i] / 2; + for(i = bytewidth; i < length; i++) out[i] = scanline[i] - ((scanline[i - bytewidth] + prevline[i]) / 2); + } + else + { + for(i = 0; i < length; i++) out[i] = scanline[i]; + for(i = bytewidth; i < length; i++) out[i] = scanline[i] - scanline[i - bytewidth] / 2; + } + break; + case 4: + if(prevline) + { + for(i = 0; i < bytewidth; i++) out[i] = (unsigned char)(scanline[i] - paethPredictor(0, prevline[i], 0)); + for(i = bytewidth; i < length; i++) out[i] = (unsigned char)(scanline[i] - paethPredictor(scanline[i - bytewidth], prevline[i], prevline[i - bytewidth])); + } + else + { + for(i = 0; i < bytewidth; i++) out[i] = scanline[i]; + for(i = bytewidth; i < length; i++) out[i] = (unsigned char)(scanline[i] - paethPredictor(scanline[i - bytewidth], 0, 0)); + } + break; + default: return; /*unexisting filter type given*/ + } +} + +static unsigned filter(unsigned char* out, const unsigned char* in, unsigned w, unsigned h, const LodePNG_InfoColor* info) +{ + /* + For PNG filter method 0 + out must be a buffer with as size: h + (w * h * bpp + 7) / 8, because there are the scanlines with 1 extra byte per scanline + + There is a nice heuristic described here: http://www.cs.toronto.edu/~cosmin/pngtech/optipng.html. It says: + * If the image type is Palette, or the bit depth is smaller than 8, then do not filter the image (i.e. use fixed filtering, with the filter None). + * (The other case) If the image type is Grayscale or RGB (with or without Alpha), and the bit depth is not smaller than 8, then use adaptive filtering heuristic as follows: independently for each row, apply all five filters and select the filter that produces the smallest sum of absolute values per row. + + Here the above method is used mostly. Note though that it appears to be better to use the adaptive filtering on the plasma 8-bit palette example, but that image isn't the best reference for palette images in general. + */ + + unsigned bpp = LodePNG_InfoColor_getBpp(info); + size_t linebytes = (w * bpp + 7) / 8; /*the width of a scanline in bytes, not including the filter type*/ + size_t bytewidth = (bpp + 7) / 8; /*bytewidth is used for filtering, is 1 when bpp < 8, number of bytes per pixel otherwise*/ + const unsigned char* prevline = 0; + unsigned x, y; + unsigned heuristic; + unsigned error = 0; + + if(bpp == 0) return 31; /*invalid color type*/ + + /*choose heuristic as described above*/ + if(info->colorType == 3 || info->bitDepth < 8) heuristic = 0; + else heuristic = 1; + + if(heuristic == 0) /*None filtertype for everything*/ + { + for(y = 0; y < h; y++) + { + size_t outindex = (1 + linebytes) * y; /*the extra filterbyte added to each row*/ + size_t inindex = linebytes * y; + const unsigned TYPE = 0; + out[outindex] = TYPE; /*filter type byte*/ + filterScanline(&out[outindex + 1], &in[inindex], prevline, linebytes, bytewidth, TYPE); + prevline = &in[inindex]; + } + } + else if(heuristic == 1) /*adaptive filtering*/ + { + size_t sum[5]; + ucvector attempt[5]; /*five filtering attempts, one for each filter type*/ + size_t smallest = 0; + unsigned type, bestType = 0; + + for(type = 0; type < 5; type++) ucvector_init(&attempt[type]); + for(type = 0; type < 5; type++) + { + if(!ucvector_resize(&attempt[type], linebytes)) { error = 9949; break; } + } + + if(!error) + { + for(y = 0; y < h; y++) + { + /*try the 5 filter types*/ + for(type = 0; type < 5; type++) + { + filterScanline(attempt[type].data, &in[y * linebytes], prevline, linebytes, bytewidth, type); + + /*calculate the sum of the result*/ + sum[type] = 0; + for(x = 0; x < attempt[type].size; x+=3) sum[type] += attempt[type].data[x]; /*note that not all pixels are checked to speed this up while still having probably the best choice*/ + + /*check if this is smallest sum (or if type == 0 it's the first case so always store the values)*/ + if(type == 0 || sum[type] < smallest) + { + bestType = type; + smallest = sum[type]; + } + } + + prevline = &in[y * linebytes]; + + /*now fill the out values*/ + out[y * (linebytes + 1)] = bestType; /*the first byte of a scanline will be the filter type*/ + for(x = 0; x < linebytes; x++) out[y * (linebytes + 1) + 1 + x] = attempt[bestType].data[x]; + } + } + + for(type = 0; type < 5; type++) ucvector_cleanup(&attempt[type]); + } + #if 0 /*deflate the scanline with a fixed tree after every filter attempt to see which one deflates best. This is slow, and _does not work as expected_: the heuristic gives smaller result!*/ + else if(heuristic == 2) /*adaptive filtering by using deflate*/ + { + size_t size[5]; + ucvector attempt[5]; /*five filtering attempts, one for each filter type*/ + size_t smallest; + unsigned type = 0, bestType = 0; + unsigned char* dummy; + LodeZlib_DeflateSettings deflatesettings = LodeZlib_defaultDeflateSettings; + deflatesettings.btype = 1; /*use fixed tree on the attempts so that the tree is not adapted to the filtertype on purpose, to simulate the true case where the tree is the same for the whole image*/ + for(type = 0; type < 5; type++) { ucvector_init(&attempt[type]); ucvector_resize(&attempt[type], linebytes); } + for(y = 0; y < h; y++) /*try the 5 filter types*/ + { + for(type = 0; type < 5; type++) + { + filterScanline(attempt[type].data, &in[y * linebytes], prevline, linebytes, bytewidth, type); + size[type] = 0; dummy = 0; + LodePNG_compress(&dummy, &size[type], attempt[type].data, attempt[type].size, &deflatesettings); + free(dummy); + /*check if this is smallest size (or if type == 0 it's the first case so always store the values)*/ + if(type == 0 || size[type] < smallest) { bestType = type; smallest = size[type]; } + } + prevline = &in[y * linebytes]; + out[y * (linebytes + 1)] = bestType; /*the first byte of a scanline will be the filter type*/ + for(x = 0; x < linebytes; x++) out[y * (linebytes + 1) + 1 + x] = attempt[bestType].data[x]; + } + for(type = 0; type < 5; type++) ucvector_cleanup(&attempt[type]); + } + #endif + + return error; +} + +static void addPaddingBits(unsigned char* out, const unsigned char* in, size_t olinebits, size_t ilinebits, unsigned h) +{ + /*The opposite of the removePaddingBits function + olinebits must be >= ilinebits*/ + unsigned y; + size_t diff = olinebits - ilinebits; + size_t obp = 0, ibp = 0; /*bit pointers*/ + for(y = 0; y < h; y++) + { + size_t x; + for(x = 0; x < ilinebits; x++) + { + unsigned char bit = readBitFromReversedStream(&ibp, in); + setBitOfReversedStream(&obp, out, bit); + } + /*obp += diff; --> no, fill in some value in the padding bits too, to avoid "Use of uninitialised value of size ###" warning from valgrind*/ + for(x = 0; x < diff; x++) setBitOfReversedStream(&obp, out, 0); + } +} + +static void Adam7_interlace(unsigned char* out, const unsigned char* in, unsigned w, unsigned h, unsigned bpp) +{ + /*Note: this function works on image buffers WITHOUT padding bits at end of scanlines with non-multiple-of-8 bit amounts, only between reduced images is padding*/ + unsigned passw[7], passh[7]; size_t filter_passstart[8], padded_passstart[8], passstart[8]; + unsigned i; + + Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, passstart, w, h, bpp); + + if(bpp >= 8) + { + for(i = 0; i < 7; i++) + { + unsigned x, y, b; + size_t bytewidth = bpp / 8; + for(y = 0; y < passh[i]; y++) + for(x = 0; x < passw[i]; x++) + { + size_t pixelinstart = ((ADAM7_IY[i] + y * ADAM7_DY[i]) * w + ADAM7_IX[i] + x * ADAM7_DX[i]) * bytewidth; + size_t pixeloutstart = passstart[i] + (y * passw[i] + x) * bytewidth; + for(b = 0; b < bytewidth; b++) + { + out[pixeloutstart + b] = in[pixelinstart + b]; + } + } + } + } + else /*bpp < 8: Adam7 with pixels < 8 bit is a bit trickier: with bit pointers*/ + { + for(i = 0; i < 7; i++) + { + unsigned x, y, b; + unsigned ilinebits = bpp * passw[i]; + unsigned olinebits = bpp * w; + size_t obp, ibp; /*bit pointers (for out and in buffer)*/ + for(y = 0; y < passh[i]; y++) + for(x = 0; x < passw[i]; x++) + { + ibp = (ADAM7_IY[i] + y * ADAM7_DY[i]) * olinebits + (ADAM7_IX[i] + x * ADAM7_DX[i]) * bpp; + obp = (8 * passstart[i]) + (y * ilinebits + x * bpp); + for(b = 0; b < bpp; b++) + { + unsigned char bit = readBitFromReversedStream(&ibp, in); + setBitOfReversedStream(&obp, out, bit); + } + } + } + } +} + +/*out must be buffer big enough to contain uncompressed IDAT chunk data, and in must contain the full image*/ +static unsigned preProcessScanlines(unsigned char** out, size_t* outsize, const unsigned char* in, const LodePNG_InfoPng* infoPng) /*return value is error*/ +{ + /* + This function converts the pure 2D image with the PNG's colortype, into filtered-padded-interlaced data. Steps: + *) if no Adam7: 1) add padding bits (= posible extra bits per scanline if bpp < 8) 2) filter + *) if adam7: 1) Adam7_interlace 2) 7x add padding bits 3) 7x filter + */ + unsigned bpp = LodePNG_InfoColor_getBpp(&infoPng->color); + unsigned w = infoPng->width; + unsigned h = infoPng->height; + unsigned error = 0; + + if(infoPng->interlaceMethod == 0) + { + *outsize = h + (h * ((w * bpp + 7) / 8)); /*image size plus an extra byte per scanline + possible padding bits*/ + *out = (unsigned char*)malloc(*outsize); + if(!(*out) && (*outsize)) error = 9950; + + if(!error) + { + if(bpp < 8 && w * bpp != ((w * bpp + 7) / 8) * 8) /*non multiple of 8 bits per scanline, padding bits needed per scanline*/ + { + ucvector padded; + ucvector_init(&padded); + if(!ucvector_resize(&padded, h * ((w * bpp + 7) / 8))) error = 9951; + if(!error) + { + addPaddingBits(padded.data, in, ((w * bpp + 7) / 8) * 8, w * bpp, h); + error = filter(*out, padded.data, w, h, &infoPng->color); + } + ucvector_cleanup(&padded); + } + else error = filter(*out, in, w, h, &infoPng->color); /*we can immediatly filter into the out buffer, no other steps needed*/ + } + } + else /*interlaceMethod is 1 (Adam7)*/ + { + unsigned char* adam7 = (unsigned char*)malloc((h * w * bpp + 7) / 8); + if(!adam7 && ((h * w * bpp + 7) / 8)) error = 9952; /*malloc failed*/ + + while(!error) /*not a real while loop, used to break out to cleanup to avoid a goto*/ + { + unsigned passw[7], passh[7]; size_t filter_passstart[8], padded_passstart[8], passstart[8]; + unsigned i; + + Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, passstart, w, h, bpp); + + *outsize = filter_passstart[7]; /*image size plus an extra byte per scanline + possible padding bits*/ + *out = (unsigned char*)malloc(*outsize); + if(!(*out) && (*outsize)) { error = 9953; break; } + + Adam7_interlace(adam7, in, w, h, bpp); + + for(i = 0; i < 7; i++) + { + if(bpp < 8) + { + ucvector padded; + ucvector_init(&padded); + if(!ucvector_resize(&padded, h * ((w * bpp + 7) / 8))) error = 9954; + if(!error) + { + addPaddingBits(&padded.data[padded_passstart[i]], &adam7[passstart[i]], ((passw[i] * bpp + 7) / 8) * 8, passw[i] * bpp, passh[i]); + error = filter(&(*out)[filter_passstart[i]], &padded.data[padded_passstart[i]], passw[i], passh[i], &infoPng->color); + } + + ucvector_cleanup(&padded); + } + else + { + error = filter(&(*out)[filter_passstart[i]], &adam7[padded_passstart[i]], passw[i], passh[i], &infoPng->color); + } + } + + break; + } + + free(adam7); + } + + return error; +} + +/*palette must have 4 * palettesize bytes allocated*/ +static unsigned isPaletteFullyOpaque(const unsigned char* palette, size_t palettesize) /*palette given in format RGBARGBARGBARGBA...*/ +{ + size_t i; + for(i = 0; i < palettesize; i++) + { + if(palette[4 * i + 3] != 255) return 0; + } + return 1; +} + +/*this function checks if the input image given by the user has no transparent pixels*/ +static unsigned isFullyOpaque(const unsigned char* image, unsigned w, unsigned h, const LodePNG_InfoColor* info) +{ + /*TODO: When the user specified a color key for the input image, then this function must also check for pixels that are the same as the color key and treat those as transparent.*/ + + unsigned i, numpixels = w * h; + if(info->colorType == 6) + { + if(info->bitDepth == 8) + { + for(i = 0; i < numpixels; i++) if(image[i * 4 + 3] != 255) return 0; + } + else + { + for(i = 0; i < numpixels; i++) if(image[i * 8 + 6] != 255 || image[i * 8 + 7] != 255) return 0; + } + return 1; /*no single pixel with alpha channel other than 255 found*/ + } + else if(info->colorType == 4) + { + if(info->bitDepth == 8) + { + for(i = 0; i < numpixels; i++) if(image[i * 2 + 1] != 255) return 0; + } + else + { + for(i = 0; i < numpixels; i++) if(image[i * 4 + 2] != 255 || image[i * 4 + 3] != 255) return 0; + } + return 1; /*no single pixel with alpha channel other than 255 found*/ + } + else if(info->colorType == 3) + { + /*when there's a palette, we could check every pixel for translucency, but much quicker is to just check the palette*/ + return(isPaletteFullyOpaque(info->palette, info->palettesize)); + } + + return 0; /*color type that isn't supported by this function yet, so assume there is transparency to be safe*/ +} + +#ifdef LODEPNG_COMPILE_UNKNOWN_CHUNKS +static unsigned addUnknownChunks(ucvector* out, unsigned char* data, size_t datasize) +{ + unsigned char* inchunk = data; + while((size_t)(inchunk - data) < datasize) + { + unsigned error = LodePNG_append_chunk(&out->data, &out->size, inchunk); + if(error) return error; /*error: not enough memory*/ + out->allocsize = out->size; /*fix the allocsize again*/ + inchunk = LodePNG_chunk_next(inchunk); + } + return 0; +} +#endif /*LODEPNG_COMPILE_UNKNOWN_CHUNKS*/ + +void LodePNG_encode(LodePNG_Encoder* encoder, unsigned char** out, size_t* outsize, const unsigned char* image, unsigned w, unsigned h) +{ + LodePNG_InfoPng info; + ucvector outv; + unsigned char* data = 0; /*uncompressed version of the IDAT chunk data*/ + size_t datasize = 0; + + /*provide some proper output values if error will happen*/ + *out = 0; + *outsize = 0; + encoder->error = 0; + + info = encoder->infoPng; /*UNSAFE copy to avoid having to cleanup! but we will only change primitive parameters, and not invoke the cleanup function nor touch the palette's buffer so we use it safely*/ + info.width = w; + info.height = h; + + if(encoder->settings.autoLeaveOutAlphaChannel && isFullyOpaque(image, w, h, &encoder->infoRaw.color)) + { + /*go to a color type without alpha channel*/ + if(info.color.colorType == 6) info.color.colorType = 2; + else if(info.color.colorType == 4) info.color.colorType = 0; + } + + if(encoder->settings.zlibsettings.windowSize > 32768) { encoder->error = 60; return; } /*error: windowsize larger than allowed*/ + if(encoder->settings.zlibsettings.btype > 2) { encoder->error = 61; return; } /*error: unexisting btype*/ + if(encoder->infoPng.interlaceMethod > 1) { encoder->error = 71; return; } /*error: unexisting interlace mode*/ + if((encoder->error = checkColorValidity(info.color.colorType, info.color.bitDepth))) return; /*error: unexisting color type given*/ + if((encoder->error = checkColorValidity(encoder->infoRaw.color.colorType, encoder->infoRaw.color.bitDepth))) return; /*error: unexisting color type given*/ + + if(!LodePNG_InfoColor_equal(&encoder->infoRaw.color, &info.color)) + { + unsigned char* converted; + size_t size = (w * h * LodePNG_InfoColor_getBpp(&info.color) + 7) / 8; + + if((info.color.colorType != 6 && info.color.colorType != 2) || (info.color.bitDepth != 8)) { encoder->error = 59; return; } /*for the output image, only these types are supported*/ + converted = (unsigned char*)malloc(size); + if(!converted && size) encoder->error = 9955; /*error: malloc failed*/ + if(!encoder->error) encoder->error = LodePNG_convert(converted, image, &info.color, &encoder->infoRaw.color, w, h); + if(!encoder->error) preProcessScanlines(&data, &datasize, converted, &info);/*filter(data.data, converted.data, w, h, LodePNG_InfoColor_getBpp(&info.color));*/ + free(converted); + } + else preProcessScanlines(&data, &datasize, image, &info);/*filter(data.data, image, w, h, LodePNG_InfoColor_getBpp(&info.color));*/ + + ucvector_init(&outv); + while(!encoder->error) /*not really a while loop, this is only used to break out if an error happens to avoid goto's to do the ucvector cleanup*/ + { +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + size_t i; +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + /*write signature and chunks*/ + writeSignature(&outv); + /*IHDR*/ + addChunk_IHDR(&outv, w, h, info.color.bitDepth, info.color.colorType, info.interlaceMethod); +#ifdef LODEPNG_COMPILE_UNKNOWN_CHUNKS + /*unknown chunks between IHDR and PLTE*/ + if(info.unknown_chunks.data[0]) { encoder->error = addUnknownChunks(&outv, info.unknown_chunks.data[0], info.unknown_chunks.datasize[0]); if(encoder->error) break; } +#endif /*LODEPNG_COMPILE_UNKNOWN_CHUNKS*/ + /*PLTE*/ + if(info.color.colorType == 3) + { + if(info.color.palettesize == 0 || info.color.palettesize > 256) { encoder->error = 68; break; } + addChunk_PLTE(&outv, &info.color); + } + if(encoder->settings.force_palette && (info.color.colorType == 2 || info.color.colorType == 6)) + { + if(info.color.palettesize == 0 || info.color.palettesize > 256) { encoder->error = 68; break; } + addChunk_PLTE(&outv, &info.color); + } + /*tRNS*/ + if(info.color.colorType == 3 && !isPaletteFullyOpaque(info.color.palette, info.color.palettesize)) addChunk_tRNS(&outv, &info.color); + if((info.color.colorType == 0 || info.color.colorType == 2) && info.color.key_defined) addChunk_tRNS(&outv, &info.color); +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + /*bKGD (must come between PLTE and the IDAt chunks*/ + if(info.background_defined) addChunk_bKGD(&outv, &info); + /*pHYs (must come before the IDAT chunks)*/ + if(info.phys_defined) addChunk_pHYs(&outv, &info); +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ +#ifdef LODEPNG_COMPILE_UNKNOWN_CHUNKS + /*unknown chunks between PLTE and IDAT*/ + if(info.unknown_chunks.data[1]) { encoder->error = addUnknownChunks(&outv, info.unknown_chunks.data[1], info.unknown_chunks.datasize[1]); if(encoder->error) break; } +#endif /*LODEPNG_COMPILE_UNKNOWN_CHUNKS*/ + /*IDAT (multiple IDAT chunks must be consecutive)*/ + encoder->error = addChunk_IDAT(&outv, data, datasize, &encoder->settings.zlibsettings); + if(encoder->error) break; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + /*tIME*/ + if(info.time_defined) addChunk_tIME(&outv, &info.time); + /*tEXt and/or zTXt*/ + for(i = 0; i < info.text.num; i++) + { + if(strlen(info.text.keys[i]) > 79) { encoder->error = 66; break; } + if(strlen(info.text.keys[i]) < 1) { encoder->error = 67; break; } + if(encoder->settings.text_compression) + addChunk_zTXt(&outv, info.text.keys[i], info.text.strings[i], &encoder->settings.zlibsettings); + else + addChunk_tEXt(&outv, info.text.keys[i], info.text.strings[i]); + } + /*LodePNG version id in text chunk*/ + if(encoder->settings.add_id) + { + unsigned alread_added_id_text = 0; + for(i = 0; i < info.text.num; i++) + if(!strcmp(info.text.keys[i], "LodePNG")) { alread_added_id_text = 1; break; } + if(alread_added_id_text == 0) + addChunk_tEXt(&outv, "LodePNG", VERSION_STRING); /*it's shorter as tEXt than as zTXt chunk*/ + } + /*iTXt*/ + for(i = 0; i < info.itext.num; i++) + { + if(strlen(info.itext.keys[i]) > 79) { encoder->error = 66; break; } + if(strlen(info.itext.keys[i]) < 1) { encoder->error = 67; break; } + addChunk_iTXt(&outv, encoder->settings.text_compression, + info.itext.keys[i], info.itext.langtags[i], info.itext.transkeys[i], info.itext.strings[i], + &encoder->settings.zlibsettings); + } +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ +#ifdef LODEPNG_COMPILE_UNKNOWN_CHUNKS + /*unknown chunks between IDAT and IEND*/ + if(info.unknown_chunks.data[2]) { encoder->error = addUnknownChunks(&outv, info.unknown_chunks.data[2], info.unknown_chunks.datasize[2]); if(encoder->error) break; } +#endif /*LODEPNG_COMPILE_UNKNOWN_CHUNKS*/ + /*IEND*/ + addChunk_IEND(&outv); + + break; /*this isn't really a while loop; no error happened so break out now!*/ + } + + free(data); + /*instead of cleaning the vector up, give it to the output*/ + *out = outv.data; + *outsize = outv.size; +} + +unsigned LodePNG_encode32(unsigned char** out, size_t* outsize, const unsigned char* image, unsigned w, unsigned h) +{ + unsigned error; + LodePNG_Encoder encoder; + LodePNG_Encoder_init(&encoder); + LodePNG_encode(&encoder, out, outsize, image, w, h); + error = encoder.error; + LodePNG_Encoder_cleanup(&encoder); + return error; +} + +#ifdef LODEPNG_COMPILE_DISK +unsigned LodePNG_encode32f(const char* filename, const unsigned char* image, unsigned w, unsigned h) +{ + unsigned char* buffer; + size_t buffersize; + unsigned error = LodePNG_encode32(&buffer, &buffersize, image, w, h); + LodePNG_saveFile(buffer, buffersize, filename); + free(buffer); + return error; +} +#endif /*LODEPNG_COMPILE_DISK*/ + +void LodePNG_EncodeSettings_init(LodePNG_EncodeSettings* settings) +{ + LodeZlib_DeflateSettings_init(&settings->zlibsettings); + settings->autoLeaveOutAlphaChannel = 1; + settings->force_palette = 0; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + settings->add_id = 1; + settings->text_compression = 0; +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ +} + +void LodePNG_Encoder_init(LodePNG_Encoder* encoder) +{ + LodePNG_EncodeSettings_init(&encoder->settings); + LodePNG_InfoPng_init(&encoder->infoPng); + LodePNG_InfoRaw_init(&encoder->infoRaw); + encoder->error = 1; +} + +void LodePNG_Encoder_cleanup(LodePNG_Encoder* encoder) +{ + LodePNG_InfoPng_cleanup(&encoder->infoPng); + LodePNG_InfoRaw_cleanup(&encoder->infoRaw); +} + +void LodePNG_Encoder_copy(LodePNG_Encoder* dest, const LodePNG_Encoder* source) +{ + LodePNG_Encoder_cleanup(dest); + *dest = *source; + LodePNG_InfoPng_init(&dest->infoPng); + LodePNG_InfoRaw_init(&dest->infoRaw); + dest->error = LodePNG_InfoPng_copy(&dest->infoPng, &source->infoPng); if(dest->error) return; + dest->error = LodePNG_InfoRaw_copy(&dest->infoRaw, &source->infoRaw); if(dest->error) return; +} + +#endif /*LODEPNG_COMPILE_ENCODER*/ + +#endif /*LODEPNG_COMPILE_PNG*/ + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / File IO / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +#ifdef LODEPNG_COMPILE_DISK + +unsigned LodePNG_loadFile(unsigned char** out, size_t* outsize, const char* filename) /*designed for loading files from hard disk in a dynamically allocated buffer*/ +{ + FILE* file; + long size; + + /*provide some proper output values if error will happen*/ + *out = 0; + *outsize = 0; + + file = portable_fopen(filename, "rb"); + if(!file) return 78; + + /*get filesize:*/ + fseek(file , 0 , SEEK_END); + size = ftell(file); + rewind(file); + + /*read contents of the file into the vector*/ + *outsize = 0; + *out = (unsigned char*)malloc((size_t)size); + if(size && (*out)) (*outsize) = fread(*out, 1, (size_t)size, file); + + fclose(file); + if(!(*out) && size) return 80; /*the above malloc failed*/ + return 0; +} + +/*write given buffer to the file, overwriting the file, it doesn't append to it.*/ +unsigned LodePNG_saveFile(const unsigned char* buffer, size_t buffersize, const char* filename) +{ + FILE* file; + file = portable_fopen(filename, "wb" ); + if(!file) return 79; + fwrite((char*)buffer , 1 , buffersize, file); + fclose(file); + return 0; +} + +#endif /*LODEPNG_COMPILE_DISK*/ + diff --git a/trunk/src/lodepng.h b/trunk/src/lodepng.h new file mode 100644 index 0000000..bbf40dc --- /dev/null +++ b/trunk/src/lodepng.h @@ -0,0 +1,1575 @@ +/* +LodePNG version 20080927 + +Copyright (c) 2005-2008 Lode Vandevenne + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. +*/ + +#ifndef LODEPNG_H +#define LODEPNG_H + +#include +#include +#include + +/* ////////////////////////////////////////////////////////////////////////// */ +/* Code Sections */ +/* ////////////////////////////////////////////////////////////////////////// */ + +/*The following defines can be commented disable code sections. Gives potential faster compile and smaller binary.*/ + +#define LODEPNG_COMPILE_ZLIB /*deflate&zlib encoder and deflate&zlib decoder*/ +#define LODEPNG_COMPILE_PNG /*png encoder and png decoder*/ +//#define LODEPNG_COMPILE_DECODER /*deflate&zlib decoder and png decoder*/ +#define LODEPNG_COMPILE_ENCODER /*deflate&zlib encoder and png encoder*/ +#define LODEPNG_COMPILE_DISK /*the optional built in harddisk file loading and saving functions*/ +//#define LODEPNG_COMPILE_ANCILLARY_CHUNKS /*any code or struct datamember related to chunks other than IHDR, IDAT, PLTE, tRNS, IEND*/ +//#define LODEPNG_COMPILE_UNKNOWN_CHUNKS /*handling of unknown chunks*/ + +/* ////////////////////////////////////////////////////////////////////////// */ +/* LodeFlate & LodeZlib Setting structs */ +/* ////////////////////////////////////////////////////////////////////////// */ + +#ifdef LODEPNG_COMPILE_DECODER +typedef struct LodeZlib_DecompressSettings +{ + unsigned ignoreAdler32; +} LodeZlib_DecompressSettings; + +extern const LodeZlib_DecompressSettings LodeZlib_defaultDecompressSettings; +void LodeZlib_DecompressSettings_init(LodeZlib_DecompressSettings* settings); +#endif /*LODEPNG_COMPILE_DECODER*/ + +#ifdef LODEPNG_COMPILE_ENCODER +typedef struct LodeZlib_DeflateSettings /*deflate = compress*/ +{ + /*LZ77 related settings*/ + unsigned btype; /*the block type for LZ*/ + unsigned useLZ77; /*whether or not to use LZ77*/ + unsigned windowSize; /*the maximum is 32768*/ +} LodeZlib_DeflateSettings; + +extern const LodeZlib_DeflateSettings LodeZlib_defaultDeflateSettings; +void LodeZlib_DeflateSettings_init(LodeZlib_DeflateSettings* settings); +#endif /*LODEPNG_COMPILE_ENCODER*/ + +#ifdef LODEPNG_COMPILE_ZLIB +/* ////////////////////////////////////////////////////////////////////////// */ +/* LodeFlate & LodeZlib */ +/* ////////////////////////////////////////////////////////////////////////// */ + +#ifdef LODEPNG_COMPILE_DECODER +/*This function reallocates the out buffer and appends the data. +Either, *out must be NULL and *outsize must be 0, or, *out must be a valid buffer and *outsize its size in bytes.*/ +unsigned LodeZlib_decompress(unsigned char** out, size_t* outsize, const unsigned char* in, size_t insize, const LodeZlib_DecompressSettings* settings); +#endif /*LODEPNG_COMPILE_DECODER*/ + +#ifdef LODEPNG_COMPILE_ENCODER +/*This function reallocates the out buffer and appends the data. +Either, *out must be NULL and *outsize must be 0, or, *out must be a valid buffer and *outsize its size in bytes.*/ +unsigned LodeZlib_compress(unsigned char** out, size_t* outsize, const unsigned char* in, size_t insize, const LodeZlib_DeflateSettings* settings); +#endif /*LODEPNG_COMPILE_ENCODER*/ +#endif /*LODEPNG_COMPILE_ZLIB*/ + +#ifdef LODEPNG_COMPILE_PNG + +/* ////////////////////////////////////////////////////////////////////////// */ +/* LodePNG */ +/* ////////////////////////////////////////////////////////////////////////// */ + +/*LodePNG_chunk functions: These functions need as input a large enough amount of allocated memory.*/ + +unsigned LodePNG_chunk_length(const unsigned char* chunk); /*get the length of the data of the chunk. Total chunk length has 12 bytes more.*/ + +void LodePNG_chunk_type(char type[5], const unsigned char* chunk); /*puts the 4-byte type in null terminated string*/ +unsigned char LodePNG_chunk_type_equals(const unsigned char* chunk, const char* type); /*check if the type is the given type*/ + +/*properties of PNG chunks gotten from capitalization of chunk type name, as defined by the standard*/ +unsigned char LodePNG_chunk_critical(const unsigned char* chunk); /*0: ancillary chunk, 1: it's one of the critical chunk types*/ +unsigned char LodePNG_chunk_private(const unsigned char* chunk); /*0: public, 1: private*/ +unsigned char LodePNG_chunk_safetocopy(const unsigned char* chunk); /*0: the chunk is unsafe to copy, 1: the chunk is safe to copy*/ + +unsigned char* LodePNG_chunk_data(unsigned char* chunk); /*get pointer to the data of the chunk*/ +const unsigned char* LodePNG_chunk_data_const(const unsigned char* chunk); /*get pointer to the data of the chunk*/ + +unsigned LodePNG_chunk_check_crc(const unsigned char* chunk); /*returns 0 if the crc is correct, 1 if it's incorrect*/ +void LodePNG_chunk_generate_crc(unsigned char* chunk); /*generates the correct CRC from the data and puts it in the last 4 bytes of the chunk*/ + +/*iterate to next chunks.*/ +unsigned char* LodePNG_chunk_next(unsigned char* chunk); +const unsigned char* LodePNG_chunk_next_const(const unsigned char* chunk); + +/*add chunks to out buffer. It reallocs the buffer to append the data. returns error code*/ +unsigned LodePNG_append_chunk(unsigned char** out, size_t* outlength, const unsigned char* chunk); /*appends chunk that was already created, to the data. Returns pointer to start of appended chunk, or NULL if error happened*/ +unsigned LodePNG_create_chunk(unsigned char** out, size_t* outlength, unsigned length, const char* type, const unsigned char* data); /*appends new chunk to out. Returns pointer to start of appended chunk, or NULL if error happened; may change memory address of out buffer*/ + +typedef struct LodePNG_InfoColor /*info about the color type of an image*/ +{ + /*header (IHDR)*/ + unsigned colorType; /*color type*/ + unsigned bitDepth; /*bits per sample*/ + + /*palette (PLTE)*/ + unsigned char* palette; /*palette in RGBARGBA... order*/ + size_t palettesize; /*palette size in number of colors (amount of bytes is 4 * palettesize)*/ + + /*transparent color key (tRNS)*/ + unsigned key_defined; /*is a transparent color key given?*/ + unsigned key_r; /*red component of color key*/ + unsigned key_g; /*green component of color key*/ + unsigned key_b; /*blue component of color key*/ +} LodePNG_InfoColor; + +void LodePNG_InfoColor_init(LodePNG_InfoColor* info); +void LodePNG_InfoColor_cleanup(LodePNG_InfoColor* info); +unsigned LodePNG_InfoColor_copy(LodePNG_InfoColor* dest, const LodePNG_InfoColor* source); + +/*Use these functions instead of allocating palette manually*/ +void LodePNG_InfoColor_clearPalette(LodePNG_InfoColor* info); +unsigned LodePNG_InfoColor_addPalette(LodePNG_InfoColor* info, unsigned char r, unsigned char g, unsigned char b, unsigned char a); /*add 1 color to the palette*/ + +/*additional color info*/ +unsigned LodePNG_InfoColor_getBpp(const LodePNG_InfoColor* info); /*bits per pixel*/ +unsigned LodePNG_InfoColor_getChannels(const LodePNG_InfoColor* info); /*amount of channels*/ +unsigned LodePNG_InfoColor_isGreyscaleType(const LodePNG_InfoColor* info); /*is it a greyscale type? (colorType 0 or 4)*/ +unsigned LodePNG_InfoColor_isAlphaType(const LodePNG_InfoColor* info); /*has it an alpha channel? (colorType 2 or 6)*/ + +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS +typedef struct LodePNG_Time /*LodePNG's encoder does not generate the current time. To make it add a time chunk the correct time has to be provided*/ +{ + unsigned year; /*2 bytes*/ + unsigned char month; /*1-12*/ + unsigned char day; /*1-31*/ + unsigned char hour; /*0-23*/ + unsigned char minute; /*0-59*/ + unsigned char second; /*0-60 (to allow for leap seconds)*/ +} LodePNG_Time; + +typedef struct LodePNG_Text /*non-international text*/ +{ + size_t num; + char** keys; /*the keyword of a text chunk (e.g. "Comment")*/ + char** strings; /*the actual text*/ +} LodePNG_Text; + +void LodePNG_Text_init(LodePNG_Text* text); +void LodePNG_Text_cleanup(LodePNG_Text* text); +unsigned LodePNG_Text_copy(LodePNG_Text* dest, const LodePNG_Text* source); + +/*Use these functions instead of allocating the char**s manually*/ +void LodePNG_Text_clear(LodePNG_Text* text); +unsigned LodePNG_Text_add(LodePNG_Text* text, const char* key, const char* str); /*push back both texts at once*/ + + +typedef struct LodePNG_IText /*international text*/ +{ + size_t num; + char** keys; /*the English keyword of the text chunk (e.g. "Comment")*/ + char** langtags; /*the language tag for this text's international language, ISO/IEC 646 string, e.g. ISO 639 language tag*/ + char** transkeys; /*keyword translated to the international language - UTF-8 string*/ + char** strings; /*the actual international text - UTF-8 string*/ +} LodePNG_IText; + +void LodePNG_IText_init(LodePNG_IText* text); +void LodePNG_IText_cleanup(LodePNG_IText* text); +unsigned LodePNG_IText_copy(LodePNG_IText* dest, const LodePNG_IText* source); + +/*Use these functions instead of allocating the char**s manually*/ +void LodePNG_IText_clear(LodePNG_IText* text); +unsigned LodePNG_IText_add(LodePNG_IText* text, const char* key, const char* langtag, const char* transkey, const char* str); /*push back the 4 texts of 1 chunk at once*/ +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + +#ifdef LODEPNG_COMPILE_UNKNOWN_CHUNKS +typedef struct LodePNG_UnknownChunks /*unknown chunks read from the PNG, or extra chunks the user wants to have added in the encoded PNG*/ +{ + /*There are 3 buffers, one for each position in the PNG where unknown chunks can appear + each buffer contains all unknown chunks for that position consecutively + The 3 buffers are the unknown chunks between certain critical chunks: + 0: IHDR-PLTE, 1: PLTE-IDAT, 2: IDAT-IEND*/ + unsigned char* data[3]; + size_t datasize[3]; /*size in bytes of the unknown chunks, given for protection*/ + +} LodePNG_UnknownChunks; + +void LodePNG_UnknownChunks_init(LodePNG_UnknownChunks* chunks); +void LodePNG_UnknownChunks_cleanup(LodePNG_UnknownChunks* chunks); +unsigned LodePNG_UnknownChunks_copy(LodePNG_UnknownChunks* dest, const LodePNG_UnknownChunks* src); +#endif /*LODEPNG_COMPILE_UNKNOWN_CHUNKS*/ + +typedef struct LodePNG_InfoPng /*information about the PNG image, except pixels and sometimes except width and height*/ +{ + /*header (IHDR), palette (PLTE) and transparency (tRNS)*/ + unsigned width; /*width of the image in pixels (ignored by encoder, but filled in by decoder)*/ + unsigned height; /*height of the image in pixels (ignored by encoder, but filled in by decoder)*/ + unsigned compressionMethod; /*compression method of the original file*/ + unsigned filterMethod; /*filter method of the original file*/ + unsigned interlaceMethod; /*interlace method of the original file*/ + LodePNG_InfoColor color; /*color type and bits, palette, transparency*/ + +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + + /*suggested background color (bKGD)*/ + unsigned background_defined; /*is a suggested background color given?*/ + unsigned background_r; /*red component of suggested background color*/ + unsigned background_g; /*green component of suggested background color*/ + unsigned background_b; /*blue component of suggested background color*/ + + /*non-international text chunks (tEXt and zTXt)*/ + LodePNG_Text text; + + /*international text chunks (iTXt)*/ + LodePNG_IText itext; + + /*time chunk (tIME)*/ + unsigned char time_defined; /*if 0, no tIME chunk was or will be generated in the PNG image*/ + LodePNG_Time time; + + /*phys chunk (pHYs)*/ + unsigned phys_defined; /*is pHYs chunk defined?*/ + unsigned phys_x; + unsigned phys_y; + unsigned char phys_unit; /*may be 0 (unknown unit) or 1 (metre)*/ + +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + +#ifdef LODEPNG_COMPILE_UNKNOWN_CHUNKS + /*unknown chunks*/ + LodePNG_UnknownChunks unknown_chunks; +#endif /*LODEPNG_COMPILE_UNKNOWN_CHUNKS*/ + +} LodePNG_InfoPng; + +void LodePNG_InfoPng_init(LodePNG_InfoPng* info); +void LodePNG_InfoPng_cleanup(LodePNG_InfoPng* info); +unsigned LodePNG_InfoPng_copy(LodePNG_InfoPng* dest, const LodePNG_InfoPng* source); + +typedef struct LodePNG_InfoRaw /*contains user-chosen information about the raw image data, which is independent of the PNG image*/ +{ + LodePNG_InfoColor color; +} LodePNG_InfoRaw; + +void LodePNG_InfoRaw_init(LodePNG_InfoRaw* info); +void LodePNG_InfoRaw_cleanup(LodePNG_InfoRaw* info); +unsigned LodePNG_InfoRaw_copy(LodePNG_InfoRaw* dest, const LodePNG_InfoRaw* source); + +/* +LodePNG_convert: Converts from any color type to 24-bit or 32-bit (later maybe more supported). return value = LodePNG error code +The out buffer must have (w * h * bpp + 7) / 8, where bpp is the bits per pixel of the output color type (LodePNG_InfoColor_getBpp) +*/ +unsigned LodePNG_convert(unsigned char* out, const unsigned char* in, LodePNG_InfoColor* infoOut, LodePNG_InfoColor* infoIn, unsigned w, unsigned h); + +#ifdef LODEPNG_COMPILE_DECODER + +typedef struct LodePNG_DecodeSettings +{ + LodeZlib_DecompressSettings zlibsettings; /*in here is the setting to ignore Adler32 checksums*/ + + unsigned ignoreCrc; /*ignore CRC checksums*/ + unsigned color_convert; /*whether to convert the PNG to the color type you want. Default: yes*/ + +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + unsigned readTextChunks; /*if false but rememberUnknownChunks is true, they're stored in the unknown chunks*/ +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + +#ifdef LODEPNG_COMPILE_UNKNOWN_CHUNKS + unsigned rememberUnknownChunks; /*store all bytes from unknown chunks in the InfoPng (off by default, useful for a png editor)*/ +#endif /*LODEPNG_COMPILE_UNKNOWN_CHUNKS*/ +} LodePNG_DecodeSettings; + +void LodePNG_DecodeSettings_init(LodePNG_DecodeSettings* settings); + +typedef struct LodePNG_Decoder +{ + LodePNG_DecodeSettings settings; + LodePNG_InfoRaw infoRaw; + LodePNG_InfoPng infoPng; /*info of the PNG image obtained after decoding*/ + unsigned error; +} LodePNG_Decoder; + +void LodePNG_Decoder_init(LodePNG_Decoder* decoder); +void LodePNG_Decoder_cleanup(LodePNG_Decoder* decoder); +void LodePNG_Decoder_copy(LodePNG_Decoder* dest, const LodePNG_Decoder* source); + +/*decoding functions*/ +/*This function allocates the out buffer and stores the size in *outsize.*/ +void LodePNG_decode(LodePNG_Decoder* decoder, unsigned char** out, size_t* outsize, const unsigned char* in, size_t insize); +unsigned LodePNG_decode32(unsigned char** out, unsigned* w, unsigned* h, const unsigned char* in, size_t insize); /*return value is error*/ +#ifdef LODEPNG_COMPILE_DISK +unsigned LodePNG_decode32f(unsigned char** out, unsigned* w, unsigned* h, const char* filename); +#endif /*LODEPNG_COMPILE_DISK*/ +void LodePNG_inspect(LodePNG_Decoder* decoder, const unsigned char* in, size_t size); /*read the png header*/ + +#endif /*LODEPNG_COMPILE_DECODER*/ + +#ifdef LODEPNG_COMPILE_ENCODER + +typedef struct LodePNG_EncodeSettings +{ + LodeZlib_DeflateSettings zlibsettings; /*settings for the zlib encoder, such as window size, ...*/ + + unsigned autoLeaveOutAlphaChannel; /*automatically use color type without alpha instead of given one, if given image is opaque*/ + unsigned force_palette; /*force creating a PLTE chunk if colortype is 2 or 6 (= a suggested palette). If colortype is 3, PLTE is _always_ created.*/ +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + unsigned add_id; /*add LodePNG version as text chunk*/ + unsigned text_compression; /*encode text chunks as zTXt chunks instead of tEXt chunks, and use compression in iTXt chunks*/ +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ +} LodePNG_EncodeSettings; + +void LodePNG_EncodeSettings_init(LodePNG_EncodeSettings* settings); + +typedef struct LodePNG_Encoder +{ + LodePNG_EncodeSettings settings; + LodePNG_InfoPng infoPng; /*the info specified by the user may not be changed by the encoder. The encoder will try to generate a PNG close to the given info.*/ + LodePNG_InfoRaw infoRaw; /*put the properties of the input raw image in here*/ + unsigned error; +} LodePNG_Encoder; + +void LodePNG_Encoder_init(LodePNG_Encoder* encoder); +void LodePNG_Encoder_cleanup(LodePNG_Encoder* encoder); +void LodePNG_Encoder_copy(LodePNG_Encoder* dest, const LodePNG_Encoder* source); + +/*This function allocates the out buffer and stores the size in *outsize.*/ +void LodePNG_encode(LodePNG_Encoder* encoder, unsigned char** out, size_t* outsize, const unsigned char* image, unsigned w, unsigned h); +unsigned LodePNG_encode32(unsigned char** out, size_t* outsize, const unsigned char* image, unsigned w, unsigned h); /*return value is error*/ +#ifdef LODEPNG_COMPILE_DISK +unsigned LodePNG_encode32f(const char* filename, const unsigned char* image, unsigned w, unsigned h); +#endif /*LODEPNG_COMPILE_DISK*/ +#endif /*LODEPNG_COMPILE_ENCODER*/ +#endif /*LODEPNG_COMPILE_PNG*/ + +#ifdef LODEPNG_COMPILE_DISK +/*free functions allowing to load and save a file from/to harddisk*/ +/*This function allocates the out buffer and stores the size in *outsize.*/ +unsigned LodePNG_loadFile(unsigned char** out, size_t* outsize, const char* filename); +unsigned LodePNG_saveFile(const unsigned char* buffer, size_t buffersize, const char* filename); +#endif /*LODEPNG_COMPILE_DISK*/ + + +/* +TODO: +[ ] test if there are no memory leaks or security exploits - done a lot but needs to be checked often +[ ] LZ77 encoder more like the one described in zlib - to make sure it's patentfree +[ ] converting color to 16-bit types +[ ] read all public PNG chunk types (but never let the color profile and gamma ones ever touch RGB values, that is very annoying for textures as well as images in a browser) +[ ] make sure encoder generates no chunks with size > (2^31)-1 +[ ] partial decoding (stream processing) +[ ] let the "isFullyOpaque" function check color keys and transparent palettes too +[ ] better name for the variables "codes", "codesD", "codelengthcodes", "clcl" and "lldl" +[ ] check compatibility with vareous compilers - done but needs to be redone for every newer version +[ ] don't stop decoding on errors like 69, 57, 58 (make warnings that the decoder stores in the error at the very end? and make some errors just let it stop with this one chunk but still do the next ones) +[ ] make option to choose if the raw image with non multiple of 8 bits per scanline should have padding bits or not, if people like storing raw images that way +*/ + +#endif + +/* +LodePNG Documentation +--------------------- + +0. table of contents +-------------------- + + 1. about + 1.1. supported features + 1.2. features not supported + 2. C and C++ version + 3. A note about security! + 4. simple functions + 4.1 C Simple Functions + 4.2 C++ Simple Functions + 5. decoder + 6. encoder + 7. color conversions + 8. info values + 9. error values + 10. file IO + 11. chunks and PNG editing + 12. compiler support + 13. examples + 13.1. decoder example + 13.2. encoder example + 14. LodeZlib + 15. changes + 16. contact information + + +1. about +-------- + +PNG is a file format to store raster images losslessly with good compression, +supporting different color types. It can be implemented in a patent-free way. + +LodePNG is a PNG codec according to the Portable Network Graphics (PNG) +Specification (Second Edition) - W3C Recommendation 10 November 2003. + +The specifications used are: + +*) Portable Network Graphics (PNG) Specification (Second Edition): + http://www.w3.org/TR/2003/REC-PNG-20031110 +*) RFC 1950 ZLIB Compressed Data Format version 3.3: + http://www.gzip.org/zlib/rfc-zlib.html +*) RFC 1951 DEFLATE Compressed Data Format Specification ver 1.3: + http://www.gzip.org/zlib/rfc-deflate.html + +The most recent version of LodePNG can currently be found at +http://members.gamedev.net/lode/projects/LodePNG/ + +LodePNG works both in C (ISO C90) and C++, with a C++ wrapper that adds +extra functionality. + +LodePNG exists out of two files: +-lodepng.h: the header file for both C and C++ +-lodepng.c(pp): give it the name lodepng.c or lodepng.cpp depending on your usage + +If you want to start using LodePNG right away without reading this doc, get the +files lodepng_examples.c or lodepng_examples.cpp to see how to use it in code, +or check the (smaller) examples in chapter 13 here. + +LodePNG is simple but only supports the basic requirements. To achieve +simplicity, the following design choices were made: There are no dependencies +on any external library. To decode PNGs, there's a Decoder struct or class that +can convert any PNG file data into an RGBA image buffer with a single function +call. To encode PNGs, there's an Encoder struct or class that can convert image +data into PNG file data with a single function call. To read and write files, +there are simple functions to convert the files to/from buffers in memory. + +This all makes LodePNG suitable for loading textures in games, demoscene +productions, saving a screenshot, images in programs that require them for simple +usage, ... It's less suitable for full fledged image editors, loading PNGs +over network (it requires all the image data to be available before decoding can +begin), life-critical systems, ... +LodePNG has a standards conformant decoder and encoder, and supports the ability +to make a somewhat conformant editor. + +1.1. supported features +----------------------- + +The following features are supported by the decoder: + +*) decoding of PNGs with any color type, bit depth and interlace mode, to a 24- or 32-bit color raw image, or the same color type as the PNG +*) encoding of PNGs, from any raw image to 24- or 32-bit color, or the same color type as the raw image +*) Adam7 interlace and deinterlace for any color type +*) loading the image from harddisk or decoding it from a buffer from other sources than harddisk +*) support for alpha channels, including RGBA color model, translucent palettes and color keying +*) zlib decompression (inflate) +*) zlib compression (deflate) +*) CRC32 and ADLER32 checksums +*) handling of unknown chunks, allowing making a PNG editor that stores custom and unknown chunks. +*) the following chunks are supported (generated/interpreted) by both encoder and decoder: + IHDR: header information + PLTE: color palette + IDAT: pixel data + IEND: the final chunk + tRNS: transparency for palettized images + tEXt: textual information + zTXt: compressed textual information + iTXt: international textual information + bKGD: suggested background color + pHYs: physical dimensions + tIME: modification time + +1.2. features not supported +--------------------------- + +The following features are _not_ supported: + +*) some features needed to make a conformant PNG-Editor might be still missing. +*) partial loading/stream processing. All data must be available and is processed in one call. +*) The following public chunks are not supported but treated as unknown chunks by LodePNG + cHRM, gAMA, iCCP, sRGB, sBIT, hIST, sPLT + + +2. C and C++ version +-------------------- + +The C version uses buffers allocated with alloc instead that you need to free() +yourself. On top of that, you need to use init and cleanup functions for each +struct whenever using a struct from the C version to avoid exploits and memory leaks. + +The C++ version has constructors and destructors that take care of these things, +and uses std::vectors in the interface for storing data. + +Both the C and the C++ version are contained in this file! The C++ code depends on +the C code, the C code works on its own. + +These files work without modification for both C and C++ compilers because all the +additional C++ code is in "#ifdef __cplusplus" blocks that make C-compilers ignore +it, and the C code is made to compile both with strict ISO C90 and C++. + +To use the C++ version, you need to rename the source file to lodepng.cpp (instead +of lodepng.c), and compile it with a C++ compiler. + +To use the C version, you need to rename the source file to lodepng.c (instead +of lodepng.cpp), and compile it with a C compiler. + + +3. A note about security! +------------------------- + +Despite being used already and having received bug fixes whenever bugs were reported, +LodePNG may still contain possible exploits. + +If you discover a possible exploit, please let me know, and it will be eliminated. + +When using LodePNG, care has to be taken with the C version of LodePNG, as well as the C-style +structs when working with C++. The following conventions are used for all C-style structs: + +-if a struct has a corresponding init function, always call the init function when making a new one, to avoid exploits +-if a struct has a corresponding cleanup function, call it before the struct disappears to avoid memory leaks +-if a struct has a corresponding copy function, use the copy function instead of "=". The destination must be inited already! + + +4. "Simple" Functions +--------------------- + +For the most simple usage cases of loading and saving a PNG image, there +are some simple functions that do everything in 1 call (instead of you +having to instantiate a struct or class). + +The simple versions always use 32-bit RGBA color for the raw image, but +still support loading arbitrary-colortype PNG images. + +The later sections of this manual are devoted to the complex versions, where +you can use other color types and conversions. + +4.1 C Simple Functions +---------------------- + +The C simple functions have a "32" or "32f" in their name, and don't take a struct as +parameter, unlike the non-simple ones (see more down in the documentation). + +unsigned LodePNG_decode32(unsigned char** out, unsigned* w, unsigned* h, const unsigned char* in, size_t insize); + +Load PNG from given buffer. +As input, give an unsigned char* buffer gotten by loading the .png file and its size. +As output, you get a dynamically allocated buffer of large enough size, and the width and height of the image. +The buffer's size is w * h * 4. The image is in RGBA format. +The return value is the error (0 if ok). +You need to do free(out) after usage to clean up the memory. + +unsigned LodePNG_decode32f(unsigned char** out, unsigned* w, unsigned* h, const char* filename); + +Load PNG from disk, from file with given name. +Same as decode32, except you give a filename instead of an input buffer. + +unsigned LodePNG_encode32(unsigned char** out, size_t* outsize, const unsigned char* image, unsigned w, unsigned h); + +Encode PNG into buffer. +As input, give a image buffer of size w * h * 4, in RGBA format. +As output, you get a dynamically allocated buffer and its size, which is a PNG file that can +directly be saved in this form to the harddisk. +The return value is the error (0 if ok). +You need to do free(out) after usage to clean up the memory. + +unsigned LodePNG_encode32f(const char* filename, const unsigned char* image, unsigned w, unsigned h); + +Encode PNG into file on disk with given name. +If the file exists, it's overwritten without warning! +Same parameters as encode2, except the result is stored in a file instead of a dynamic buffer. + +4.2 C++ Simple Functions +------------------------ + +For decoding a PNG there are: + +unsigned LodePNG::decode(std::vector& out, unsigned& w, unsigned& h, const unsigned char* in, unsigned size); +unsigned LodePNG::decode(std::vector& out, unsigned& w, unsigned& h, const std::vector& in); +unsigned LodePNG::decode(std::vector& out, unsigned& w, unsigned& h, const std::string& filename); + +These store the pixel data as 32-bit RGBA color in the out vector, and the width +and height of the image in w and h. +The 3 functions each have a different input type: The first as unsigned char +buffer, the second as std::vector buffer, and the third allows you to give the +filename in case you want to load the PNG from disk instead of from a buffer. +The return value is the error (0 if ok). + +For encoding a PNG there are: + +unsigned LodePNG::encode(std::vector& out, const unsigned char* in, unsigned w, unsigned h); +unsigned LodePNG::encode(std::vector& out, const std::vector& in, unsigned w, unsigned h); +unsigned LodePNG::encode(const std::string& filename, const std::vector& in, unsigned w, unsigned h); +unsigned LodePNG::encode(const std::string& filename, const unsigned char* in, unsigned w, unsigned h); + +Specify the width and height of the input image with w and h. +You can choose to get the output in an std::vector or stored in a file, and +the input can come from an std::vector or an unsigned char* buffer. The input +buffer must be in RGBA format and the size must be w * h * 4 bytes. + +The first two functions append to the out buffer, they don't clear it, clear it +first before encoding into a buffer that you expect to only contain this result. + +On the other hand, the functions that encode to a file will completely overwrite +the original file without warning if it exists. + +The return value is the error (0 if ok). + +5. Decoder +---------- + +This is about the LodePNG_Decoder struct in the C version, and the +LodePNG::Decoder class in the C++ version. The C++ version inherits +from the C struct and adds functions in the interface. + +The Decoder class can be used to convert a PNG image to a raw image. + +Usage: + +-in C++: + declare a LodePNG::Decoder + call its decode member function with the parameters described below + +-in C more needs to be done due to the lack of constructors and destructors: + declare a LodePNG_Decoder struct + call LodePNG_Decoder_init with the struct as parameter + call LodePNG_Decode with the parameters described below + after usage, call LodePNG_Decoder_cleanup with the struct as parameter + after usage, free() the out buffer with image data that was created by the decode function + +The other parameters of the decode function are: +*) out: this buffer will be filled with the raw image pixels +*) in: pointer to the PNG image data or std::vector with the data +*) size: the size of the PNG image data (not needed for std::vector version) + +After decoding you need to read the width and height of the image from the +decoder, see further down in this manual to see how. + +There's also an optional function "inspect". It has the same parameters as decode except +the "out" parameter. This function will read only the header chunk of the PNG +image, and store the information from it in the LodePNG_InfoPng (see below). +This allows knowing information about the image without decoding it. Only the +header (IHDR) information is read by this, not text chunks, not the palette, ... + +During the decoding it's possible that an error can happen, for example if the +PNG image was corrupted. To check if an error happened during the last decoding, +check the value error, which is a member of the decoder struct. +In the C++ version, use hasError() and getError() of the Decoder. +The error codes are explained in another section. + +Now about colors and settings... + +The Decoder contains 3 components: +*) LodePNG_InfoPng: it stores information about the PNG (the input) in an LodePNG_InfoPng struct, don't modify this one yourself +*) Settings: you can specify a few other settings for the decoder to use +*) LodePNG_InfoRaw: here you can say what type of raw image (the output) you want to get + +Some of the parameters described below may be inside the sub-struct "LodePNG_InfoColor color". +In the C and C++ version, when using Info structs outside of the decoder or encoder, you need to use their +init and cleanup functions, but normally you use the ones in the decoder that are already handled +in the init and cleanup functions of the decoder itself. + +=LodePNG_InfoPng= + +This contains information such as the original color type of the PNG image, text +comments, suggested background color, etc... More details about the LodePNG_InfoPng struct +are in another section. + +Because the dimensions of the image are important, there are shortcuts to get them in the +C++ version: use decoder.getWidth() and decoder.getHeight(). +In the C version, use decoder.infoPng.width and decoder.infoPng.height. + +=LodePNG_InfoRaw= + +In the LodePNG_InfoRaw struct of the Decoder, you can specify which color type you want +the resulting raw image to be. If this is different from the colorType of the +PNG, then the decoder will automatically convert the result to your LodePNG_InfoRaw +settings. Currently the following options are supported to convert to: +-colorType 6, bitDepth 8: 32-bit RGBA +-colorType 2, bitDepth 8: 24-bit RGB +-other color types if it's exactly the same as that in the PNG image + +Palette of LodePNG_InfoRaw isn't used by the Decoder, when converting from palette color +to palette color, the values of the pixels are left untouched so that the colors +will change if the palette is different. Color key of LodePNG_InfoRaw is not used by the +Decoder. If setting color_convert is false then LodePNG_InfoRaw is completely ignored, +but it will be modified to match the color type of the PNG so will be overwritten. + +By default, 32-bit color is used for the result. + +=Settings= + +The Settings can be used to ignore the errors created by invalid CRC and Adler32 +chunks, and to disable the decoding of tEXt chunks. + +There's also a setting color_convert, true by default. If false, no conversion +is done, the resulting data will be as it was in the PNG (after decompression) +and you'll have to puzzle the colors of the pixels together yourself using the +color type information in the LodePNG_InfoPng. + + +6. Encoder +---------- + +This is about the LodePNG_Encoder struct in the C version, and the +LodePNG::Encoder class in the C++ version. + +The Encoder class can be used to convert raw image data into a PNG image. + +The PNG part of the encoder is working good, the zlib compression part is +becoming quite fine but not as good as the official zlib yet, because it's not +as fast and doesn't provide an as high compression ratio. + +Usage: + +-in C++: + declare a LodePNG::Encoder + call its encode member function with the parameters described below + +-in C more needs to be done due to the lack of constructors and destructors: + declare a LodePNG_Encoder struct + call LodePNG_Encoder_init with the struct as parameter + call LodePNG_Encode with the parameters described below + after usage, call LodePNG_Encoder_cleanup with the struct as parameter + after usage, free() the out buffer with PNG data that was created by the encode function + +The raw image given to the encoder is an unsigned char* buffer. You also have to +specify the width and height of the raw image. The result is stored in a given +buffer. These buffers can be unsigned char* pointers, std::vectors or dynamically +allocated unsigned char* buffers that you have to free() yourself, depending on +which you use. + +The parameters of the encode function are: +*) out: in this buffer the PNG file data will be stored (it will be appended) +*) in: vector of or pointer to a buffer containing the raw image +*) w and h: the width and height of the raw image in pixels + +Make sure that the in buffer you provide, is big enough to contain w * h pixels +of the color type specified by the LodePNG_InfoRaw. + +In the C version, you need to free() the out buffer after usage to avoid memory leaks. +In the C version, you need to use the LodePNG_Encoder_init function before using the decoder, +and the LodePNG_Encoder_cleanup function after using it. +In the C++ version, you don't need to do this since RAII takes care of it. + +The encoder generates some errors but not for everything, because, unlike when +decoding a PNG, when encoding one there aren't so much parameters of the input +that can be corrupted. It's the responsibility of the user to make sure that all +preconditions are satesfied, such as giving a correct window size, giving an +existing btype, making sure the given buffer is large enough to contain an image +with the given width and height and colortype, ... The encoder can generate +some errors, see the section with the explanations of errors for those. + +Like the Decoder, the Encoder has 3 components: +*) LodePNG_InfoRaw: here you say what color type of the raw image (the input) has +*) Settings: you can specify a few settings for the encoder to use +*) LodePNG_InfoPng: the same LodePNG_InfoPng struct as created by the Decoder. For the encoder, +with this you specify how you want the PNG (the output) to be. + +Some of the parameters described below may be inside the sub-struct "LodePNG_InfoColor color". +In the C and C++ version, when using Info structs outside of the decoder or encoder, you need to use their +init and cleanup functions, but normally you use the ones in the encoder that are already handled +in the init and cleanup functions of the decoder itself. + +=LodePNG_InfoPng= + +The Decoder class stores information about the PNG image in an LodePNG_InfoPng object. With +the Encoder you can do the opposite: you give it an LodePNG_InfoPng object, and it'll try +to match the LodePNG_InfoPng you give as close as possible in the PNG it encodes. For +example in the LodePNG_InfoPng you can specify the color type you want to use, possible +tEXt chunks you want the PNG to contain, etc... For an explanation of all the +values in LodePNG_InfoPng see a further section. Not all PNG color types are supported +by the Encoder. + +Note that the encoder will only TRY to match the LodePNG_InfoPng struct you give. +Some things are ignored by the encoder. The width and height of LodePNG_InfoPng are +ignored as well, because instead the width and height of the raw image you give +in the input are used. In fact the encoder currently uses only the following +settings from it: +-colorType: the ones it supports +-text chunks, that you can add to the LodePNG_InfoPng with "addText" +-the color key, if applicable for the given color type +-the palette, if you encode to a PNG with colorType 3 +-the background color: it'll add a bKGD chunk to the PNG if one is given +-the interlaceMethod: None (0) or Adam7 (1) + +When encoding to a PNG with colorType 3, the encoder will generate a PLTE chunk. +If the palette contains any colors for which the alpha channel is not 255 (so +there are translucent colors in the palette), it'll add a tRNS chunk. + +=LodePNG_InfoRaw= + +You specify the color type of the raw image that you give to the input here, +including a possible transparent color key and palette you happen to be using in +your raw image data. + +By default, 32-bit color is assumed, meaning your input has to be in RGBA +format with 4 bytes (unsigned chars) per pixel. + +=Settings= + +The following settings are supported (some are in sub-structs): +*) autoLeaveOutAlphaChannel: when this option is enabled, when you specify a PNG +color type with alpha channel (not to be confused with the color type of the raw +image you specify!!), but the encoder detects that all pixels of the given image +are opaque, then it'll automatically use the corresponding type without alpha +channel, resulting in a smaller PNG image. +*) btype: the block type for LZ77. 0 = uncompressed, 1 = fixed huffman tree, 2 = dynamic huffman tree (best compression) +*) useLZ77: whether or not to use LZ77 for compressed block types +*) windowSize: the window size used by the LZ77 encoder (1 - 32768) +*) force_palette: if colorType is 2 or 6, you can make the encoder write a PLTE + chunk if force_palette is true. This can used as suggested palette to convert + to by viewers that don't support more than 256 colors (if those still exist) +*) add_id: add text chunk "Encoder: LodePNG " to the image. +*) text_compression: default 0. If 1, it'll store texts as zTXt instead of tEXt chunks. + zTXt chunks use zlib compression on the text. This gives a smaller result on + large texts but a larger result on small texts (such as a single program name). + It's all tEXt or all zTXt though, there's no separate setting per text yet. + + +7. color conversions +-------------------- + +For trickier usage of LodePNG, you need to understand about PNG color types and +about how and when LodePNG uses the settings in LodePNG_InfoPng, LodePNG_InfoRaw and Settings. + +=PNG color types= + +A PNG image can have many color types, ranging from 1-bit color to 64-bit color, +as well as palettized color modes. After the zlib decompression and unfiltering +in the PNG image is done, the raw pixel data will have that color type and thus +a certain amount of bits per pixel. If you want the output raw image after +decoding to have another color type, a conversion is done by LodePNG. + +The PNG specification mentions the following color types: + +0: greyscale, bit depths 1, 2, 4, 8, 16 +2: RGB, bit depths 8 and 16 +3: palette, bit depths 1, 2, 4 and 8 +4: greyscale with alpha, bit depths 8 and 16 +6: RGBA, bit depths 8 and 16 + +Bit depth is the amount of bits per color channel. + +=Default Behaviour of LodePNG= + +By default, the Decoder will convert the data from the PNG to 32-bit RGBA color, +no matter what color type the PNG has, so that the result can be used directly +as a texture in OpenGL etc... without worries about what color type the original +image has. + +The Encoder assumes by default that the raw input you give it is a 32-bit RGBA +buffer and will store the PNG as either 32 bit or 24 bit depending on whether +or not any translucent pixels were detected in it. + +To get the default behaviour, don't change the values of LodePNG_InfoRaw and LodePNG_InfoPng of +the encoder, and don't change the values of LodePNG_InfoRaw of the decoder. + +=Color Conversions= + +As explained in the sections about the Encoder and Decoder, you can specify +color types and bit depths in LodePNG_InfoPng and LodePNG_InfoRaw, to change the default behaviour +explained above. (for the Decoder you can only specify the LodePNG_InfoRaw, because the +LodePNG_InfoPng contains what the PNG file has). + +To avoid some confusion: +-the Decoder converts from PNG to raw image +-the Encoder converts from raw image to PNG +-the color type and bit depth in LodePNG_InfoRaw, are those of the raw image +-the color type and bit depth in LodePNG_InfoPng, are those of the PNG +-if the color type of the LodePNG_InfoRaw and PNG image aren't the same, a conversion +between the color types is done if the color types are supported + +Supported color types: +-It's possible to load PNGs from any colortype and to save PNGs of any colorType. +-Both encoder and decoder use the same converter. So both encoder and decoder +suport the same color types at the input and the output. So the decoder supports +any type of PNG image and can convert it to certain types of raw image, while the +encoder supports any type of raw data but only certain color types for the output PNG. +-The converter can convert from _any_ input color type, to 24-bit RGB or 32-bit RGBA +-The converter can convert from greyscale input color type, to 8-bit greyscale or greyscale with alpha +-If both color types are the same, conversion from anything to anything is possible +-Color types that are invalid according to the PNG specification are not allowed +-When converting from a type with alpha channel to one without, the alpha channel information is discarded +-When converting from a type without alpha channel to one with, the result will be opaque except pixels that have the same color as the color key of the input if one was given +-When converting from 16-bit bitDepth to 8-bit bitDepth, the 16-bit precision information is lost, only the most significant byte is kept +-Converting from color to greyscale is not supported on purpose: choosing what kind of color to greyscale conversion to do is not a decision a PNG codec should make +-Converting from/to a palette type, only keeps the indices, it ignores the colors defined in the palette + +No conversion needed...: +-If the color type of the PNG image and raw image are the same, then no +conversion is done, and all color types are supported. +-In the encoder, you can make it save a PNG with any color by giving the +LodePNG_InfoRaw and LodePNG_InfoPng the same color type. +-In the decoder, you can make it store the pixel data in the same color type +as the PNG has, by setting the color_convert setting to false. Settings in +infoRaw are then ignored. + +The function LodePNG_convert does this, which is available in the interface but +normally isn't needed since the encoder and decoder already call it. + +=More Notes= + +In the PNG file format, if a less than 8-bit per pixel color type is used and the scanlines +have a bit amount that isn't a multiple of 8, then padding bits are used so that each +scanline starts at a fresh byte. +However: The input image you give to the encoder, and the output image you get from the decoder +will NOT have these padding bits in that case, e.g. in the case of a 1-bit image with a width +of 7 pixels, the first pixel of the second scanline will the the 8th bit of the first byte, +not the first bit of a new byte. + +8. info values +-------------- + +Both the encoder and decoder use a variable of type LodePNG_InfoPng and LodePNG_InfoRaw, which +both also contain a LodePNG_InfoColor. Here's a list of each of the values stored in them: + +*) info from the PNG header (IHDR chunk): + +width: width of the image in pixels +height: height of the image in pixels +colorType: color type of the original PNG file +bitDepth: bits per sample +compressionMethod: compression method of the original file. Always 0. +filterMethod: filter method of the original file. Always 0. +interlaceMethod: interlace method of the original file. 0 is no interlace, 1 is adam7 interlace. + +Note: width and height are only used as information of a decoded PNG image. When encoding one, you don't have +to specify width and height in an LodePNG_Info struct, but you give them as parameters of the encode function. +The rest of the LodePNG_Info struct IS used by the encoder though! + +*) palette: + +This is a dynamically allocated unsigned char array with the colors of the palette. The value palettesize +indicates the amount of colors in the palette. The allocated size of the buffer is 4 * palettesize bytes, +because there are 4 values per color: R, G, B and A. Even if less color channels are used, the palette +is always in RGBA format, in the order RGBARGBARGBA..... + +When encoding a PNG, to store your colors in the palette of the LodePNG_InfoRaw, first use +LodePNG_InfoColor_clearPalette, then for each color use LodePNG_InfoColor_addPalette. +In the C++ version the Encoder class also has the above functions available directly in its interface. + +Note that the palette information from the tRNS chunk is also already included in this palette vector. + +If you encode an image with palette, don't forget that you have to set the alpha channels (A) of the palette +too, set them to 255 for an opaque palette. If you leave them at zero, the image will be encoded as +fully invisible. This both for the palette in the infoRaw and the infoPng if the png is to have a palette. + +*) transparent color key + +key_defined: is a transparent color key given? +key_r: red/greyscale component of color key +key_g: green component of color key +key_b: blue component of color key + +For greyscale PNGs, r, g and b will all 3 be set to the same. + +This color is 8-bit for 8-bit PNGs, 16-bit for 16-bit per channel PNGs. + +*) suggested background color + +background_defined: is a suggested background color given? +background_r: red component of sugg. background color +background_g: green component of sugg. background color +background_b: blue component of sugg. background color + +This color is 8-bit for 8-bit PNGs, 16-bit for 16-bit PNGs + +For greyscale PNGs, r, g and b will all 3 be set to the same. When encoding +the encoder writes the red one away. +For palette PNGs: When decoding, the RGB value will be stored, no a palette +index. But when encoding, specify the index of the palette in background_r, +the other two are then ignored. + +The decoder pretty much ignores this background color, after all if you make a +PNG translucent normally you intend it to be used against any background, on +websites, as translucent textures in games, ... But you can get the color this +way if needed. + +*) text and itext + +Non-international text: + +-text.keys: a char** buffer containing the keywords (see below) +-text.strings: a char** buffer containing the texts (see below) +-text.num: the amount of texts in the above char** buffers (there may be more texts in itext) +-LodePNG_InfoText_clearText: use this to clear the texts again after you filled them in +-LodePNG_InfoText_addText: this function is used to push back a keyword and text + +International text: This is stored in separate arrays! The sum text.num and itext.num is the real amount of texts. + +-itext.keys: keyword in English +-itext.langtags: ISO 639 letter code for the language +-itext.transkeys: keyword in this language +-itext.strings: the text in this language, in UTF-8 +-itext.num: the amount of international texts in this PNG +-LodePNG_InfoIText_clearText: use this to clear the itexts again after you filled them in +-LodePNG_InfoIText_addText: this function is used to push back all 4 parts of an itext + +Don't allocate these text buffers yourself. Use the init/cleanup functions +correctly and use addText and clearText. + +In the C++ version the Encoder class also has the above functions available directly in its interface. +The char** buffers are used like the argv parameter of a main() function, and (i)text.num takes the role +of argc. + +In a text, there must be as much keys as strings because they always form pairs. In an itext, +there must always be as much keys, langtags, transkeys and strings. + +They keyword of text chunks gives a short description what the actual text +represents. There are a few standard standard keywords recognised +by many programs: Title, Author, Description, Copyright, Creation Time, +Software, Disclaimer, Warning, Source, Comment. It's allowed to use other keys. + +The keyword is minimum 1 character and maximum 79 characters long. It's +discouraged to use a single line length longer than 79 characters for texts. + +*) additional color info + +These functions are available with longer names in the C version, and directly +in the Decoder's interface in the C++ version. + +getBpp(): bits per pixel of the PNG image +getChannels(): amount of color channels of the PNG image +isGreyscaleType(): its color type 0 or 4 +isAlphaType(): its color type 2 or 6 + +These values are calculated out of color type and bit depth of InfoColor. + +The difference between bits per pixel and bit depth is that bit depth is the +number of bits per color channel, while a pixel can have multiple channels. + +*) pHYs chunk (image dimensions) + +phys_defined: if 0, there is no pHYs chunk and the values are undefined, if 1 else there is one +phys_x: pixels per unit in x direction +phys_y: pixels per unit in y direction +phys_unit: the unit, 0 is no unit (x and y only give the ratio), 1 is metre + +*) tIME chunk (modification time) + +time_defined: if 0, there is no tIME chunk and the values are undefined, if 1 there is one +time: this struct contains year as a 2-byte number (0-65535), month, day, hour, minute, +second as 1-byte numbers that must be in the correct range + +Note: to make the encoder add a time chunk, set time_defined to 1 and fill in +the correct values in all the time parameters, LodePNG will not fill the current +time in these values itself, all it does is copy them over into the chunk bytes. + + +9. error values +--------------- + +The meanings of the LodePNG error values: + +*) 0: no error, everything went ok +*) 1: the Encoder/Decoder has done nothing yet, so error checking makes no sense yet +*) 10: while huffman decoding: end of input memory reached without endcode +*) 11: while huffman decoding: error in code tree made it jump outside of tree +*) 13: problem while processing dynamic deflate block +*) 14: problem while processing dynamic deflate block +*) 15: problem while processing dynamic deflate block +*) 16: unexisting code while processing dynamic deflate block +*) 17: while inflating: end of out buffer memory reached +*) 18: while inflating: invalid distance code +*) 19: while inflating: end of out buffer memory reached +*) 20: invalid deflate block BTYPE encountered while decoding +*) 21: NLEN is not ones complement of LEN in a deflate block +*) 22: while inflating: end of out buffer memory reached. + This can happen if the inflated deflate data is longer than the amount of bytes required to fill up + all the pixels of the image, given the color depth and image dimensions. Something that doesn't + happen in a normal, well encoded, PNG image. +*) 23: while inflating: end of in buffer memory reached +*) 24: invalid FCHECK in zlib header +*) 25: invalid compression method in zlib header +*) 26: FDICT encountered in zlib header while it's not used for PNG +*) 27: PNG file is smaller than a PNG header +*) 28: incorrect PNG signature (the first 8 bytes of the PNG file) + Maybe it's not a PNG, or a PNG file that got corrupted so that the header indicates the corruption. +*) 29: first chunk is not the header chunk +*) 30: chunk length too large, chunk broken off at end of file +*) 31: illegal PNG color type or bpp +*) 32: illegal PNG compression method +*) 33: illegal PNG filter method +*) 34: illegal PNG interlace method +*) 35: chunk length of a chunk is too large or the chunk too small +*) 36: illegal PNG filter type encountered +*) 37: illegal bit depth for this color type given +*) 38: the palette is too big (more than 256 colors) +*) 39: more palette alpha values given in tRNS, than there are colors in the palette +*) 40: tRNS chunk has wrong size for greyscale image +*) 41: tRNS chunk has wrong size for RGB image +*) 42: tRNS chunk appeared while it was not allowed for this color type +*) 43: bKGD chunk has wrong size for palette image +*) 44: bKGD chunk has wrong size for greyscale image +*) 45: bKGD chunk has wrong size for RGB image +*) 46: value encountered in indexed image is larger than the palette size (bitdepth == 8). Is the palette too small? +*) 47: value encountered in indexed image is larger than the palette size (bitdepth < 8). Is the palette too small? +*) 48: the input data is empty. Maybe a PNG file you tried to load doesn't exist or is in the wrong path. +*) 49: jumped past memory while generating dynamic huffman tree +*) 50: jumped past memory while generating dynamic huffman tree +*) 51: jumped past memory while inflating huffman block +*) 52: jumped past memory while inflating +*) 53: size of zlib data too small +*) 55: jumped past tree while generating huffman tree, this could be when the + tree will have more leaves than symbols after generating it out of the + given lengths. They call this an oversubscribed dynamic bit lengths tree in zlib. +*) 56: given output image colorType or bitDepth not supported for color conversion +*) 57: invalid CRC encountered (checking CRC can be disabled) +*) 58: invalid ADLER32 encountered (checking ADLER32 can be disabled) +*) 59: conversion to unexisting or unsupported color type or bit depth requested by encoder or decoder +*) 60: invalid window size given in the settings of the encoder (must be 0-32768) +*) 61: invalid BTYPE given in the settings of the encoder (only 0, 1 and 2 are allowed) +*) 62: conversion from non-greyscale color to greyscale color requested by encoder or decoder. LodePNG + leaves the choice of RGB to greyscale conversion formula to the user. +*) 63: length of a chunk too long, max allowed for PNG is 2147483647 bytes per chunk (2^31-1) +*) 64: the length of the "end" symbol 256 in the Huffman tree is 0, resulting in the inability of a deflated + block to ever contain an end code. It must be at least 1. +*) 66: the length of a text chunk keyword given to the encoder is longer than the maximum 79 bytes. +*) 67: the length of a text chunk keyword given to the encoder is smaller than the minimum 1 byte. +*) 68: tried to encode a PLTE chunk with a palette that has less than 1 or more than 256 colors +*) 69: unknown chunk type with "critical" flag encountered by the decoder +*) 71: unexisting interlace mode given to encoder (must be 0 or 1) +*) 72: while decoding, unexisting compression method encountering in zTXt or iTXt chunk (it must be 0) +*) 73: invalid tIME chunk size +*) 74: invalid pHYs chunk size +*) 75: no null termination char found while decoding any kind of text chunk, or wrong length +*) 76: iTXt chunk too short to contain required bytes +*) 77: integer overflow in buffer size happened somewhere +*) 78: file doesn't exist or couldn't be opened for reading +*) 79: file couldn't be opened for writing +*) 80: tried creating a tree for 0 symbols +*) 9900-9999: out of memory while allocating chunk of memory somewhere + + +10. file IO +----------- + +For cases where you want to load the PNG image from a file, you can use your own +file loading code, or the file loading and saving functions provided with +LodePNG. These use the same unsigned char format used by the Decoder and Encoder. + +The loadFile function fills the given buffer up with the file from harddisk +with the given name. + +The saveFile function saves the contents of the given buffer to the file +with given name. Warning: this overwrites the contents that were previously in +the file if it already existed, without warning. + +Note that you don't have to decode a PNG image from a file, you can as well +retrieve the buffer another way in your code, because the decode function takes +a buffer as parameter, not a filename. + +Both C and C++ versions of the loadFile and saveFile functions are available. +For the C version of loadFile, you need to free() the buffer after use. The +C++ versions use std::vectors so they clean themselves automatically. + + +11. chunks and PNG editing +-------------------------- + +If you want to add extra chunks to a PNG you encode, or use LodePNG for a PNG +editor that should follow the rules about handling of unknown chunks, or if you +program is able to read other types of chunks than the ones handled by LodePNG, +then that's possible with the chunk functions of LodePNG. + +A PNG chunk has the following layout: + +4 bytes length +4 bytes type name +length bytes data +4 bytes CRC + + +11.1 iterating through chunks +----------------------------- + +If you have a buffer containing the PNG image data, then the first chunk (the +IHDR chunk) starts at byte number 8 of that buffer. The first 8 bytes are the +signature of the PNG and are not part of a chunk. But if you start at byte 8 +then you have a chunk, and can check the following things of it. + +NOTE: none of these functions check for memory buffer boundaries. To avoid +exploits, always make sure the buffer contains all the data of the chunks. +When using LodePNG_chunk_next, make sure the returned value is within the +allocated memory. + +unsigned LodePNG_chunk_length(const unsigned char* chunk): + +Get the length of the chunk's data. The total chunk length is this length + 12. + +void LodePNG_chunk_type(char type[5], const unsigned char* chunk): +unsigned char LodePNG_chunk_type_equals(const unsigned char* chunk, const char* type): + +Get the type of the chunk or compare if it's a certain type + +unsigned char LodePNG_chunk_critical(const unsigned char* chunk): +unsigned char LodePNG_chunk_private(const unsigned char* chunk): +unsigned char LodePNG_chunk_safetocopy(const unsigned char* chunk): + +Check if the chunk is critical in the PNG standard (only IHDR, PLTE, IDAT and IEND are). +Check if the chunk is private (public chunks are part of the standard, private ones not). +Check if the chunk is safe to copy. If it's not, then, when modifying data in a critical +chunk, unsafe to copy chunks of the old image may NOT be saved in the new one if your +program doesn't handle that type of unknown chunk. + +unsigned char* LodePNG_chunk_data(unsigned char* chunk): +const unsigned char* LodePNG_chunk_data_const(const unsigned char* chunk): + +Get a pointer to the start of the data of the chunk. + +unsigned LodePNG_chunk_check_crc(const unsigned char* chunk): +void LodePNG_chunk_generate_crc(unsigned char* chunk): + +Check if the crc is correct or generate a correct one. + +unsigned char* LodePNG_chunk_next(unsigned char* chunk): +const unsigned char* LodePNG_chunk_next_const(const unsigned char* chunk): + +Iterate to the next chunk. This works if you have a buffer with consecutive chunks. Note that these +functions do no boundary checking of the allocated data whatsoever, so make sure there is enough +data available in the buffer to be able to go to the next chunk. + +unsigned LodePNG_append_chunk(unsigned char** out, size_t* outlength, const unsigned char* chunk): +unsigned LodePNG_create_chunk(unsigned char** out, size_t* outlength, unsigned length, const char* type, const unsigned char* data): + +These functions are used to create new chunks that are appended to the data in *out that has +length *outlength. The append function appends an existing chunk to the new data. The create +function creates a new chunk with the given parameters and appends it. Type is the 4-letter +name of the chunk. + + +11.2 chunks in infoPng +---------------------- + +The LodePNG_InfoPng struct contains a struct LodePNG_UnknownChunks in it. This +struct has 3 buffers (each with size) to contain 3 types of unknown chunks: +the ones that come before the PLTE chunk, the ones that come between the PLTE +and the IDAT chunks, and the ones that come after the IDAT chunks. +It's necessary to make the distionction between these 3 cases because the PNG +standard forces to keep the ordering of unknown chunks compared to the critical +chunks, but does not force any other ordering rules. + +infoPng.unknown_chunks.data[0] is the chunks before PLTE +infoPng.unknown_chunks.data[1] is the chunks after PLTE, before IDAT +infoPng.unknown_chunks.data[2] is the chunks after IDAT + +The chunks in these 3 buffers can be iterated through and read by using the same +way described in the previous subchapter. + +When using the decoder to decode a PNG, you can make it store all unknown chunks +if you set the option settings.rememberUnknownChunks to 1. By default, this option +is off and is 0. + +The encoder will always encode unknown chunks that are stored in the infoPng. If +you need it to add a particular chunk that isn't known by LodePNG, you can use +LodePNG_append_chunk or LodePNG_create_chunk to the chunk data in +infoPng.unknown_chunks.data[x]. + +Chunks that are known by LodePNG should not be added in that way. E.g. to make +LodePNG add a bKGD chunk, set background_defined to true and add the correct +parameters there and LodePNG will generate the chunk. + + +12. compiler support +-------------------- + +No libraries other than the current standard C library are needed to compile +LodePNG. For the C++ version, only the standard C++ library is needed on top. +Add the files lodepng.c(pp) and lodepng.h to your project, include +lodepng.h where needed, and your program can read/write PNG files. + +Use optimization! For both the encoder and decoder, compiling with the best +optimizations makes a large difference. + +Make sure that LodePNG is compiled with the same compiler of the same version +and with the same settings as the rest of the program, or the interfaces with +std::vectors and std::strings in C++ can be incompatible resulting in bad things. + +CHAR_BITS must be 8 or higher, because LodePNG uses unsigned chars for octets. + +*) gcc and g++ + +LodePNG is developed in gcc so this compiler is natively supported. It gives no +warnings with compiler options "-Wall -Wextra -pedantic -ansi", with gcc and g++ +version 4.2.2 on Linux. + +*) Mingw and Bloodshed DevC++ + +The Mingw compiler (a port of gcc) used by Bloodshed DevC++ for Windows is fully +supported by LodePNG. + +*) Visual Studio 2005 and Visual C++ 2005 Express Edition + +Versions 20070604 up to 20080107 have been tested on VS2005 and work. There are no +warnings, except two warnings about 'fopen' being deprecated. 'fopen' is a function +required by the C standard, so this warning is the fault of VS2005, it's nice of +them to enforce secure code, however the multiplatform LodePNG can't follow their +non-standard extensions. LodePNG is fully ISO C90 compliant. + +If you're using LodePNG in VS2005 and don't want to see the deprecated warnings, +put this on top of lodepng.h before the inclusions: #define _CRT_SECURE_NO_DEPRECATE + +*) Visual Studio 6.0 + +The C++ version of LodePNG was not supported by Visual Studio 6.0 because Visual +Studio 6.0 doesn't follow the C++ standard and implements it incorrectly. +The current C version of LodePNG has not been tested in VS6 but may work now. + +*) Comeau C/C++ + +Vesion 20070107 compiles without problems on the Comeau C/C++ Online Test Drive +at http://www.comeaucomputing.com/tryitout in both C90 and C++ mode. + +*) Compilers on Macintosh + +I'd love to support Macintosh but don't have one available to test it on. +If it doesn't work with your compiler, maybe it can be gotten to work with the +gcc compiler for Macintosh. Someone reported that it doesn't work well at all +for Macintosh. All information on attempts to get it to work on Mac is welcome. + +*) Other Compilers + +If you encounter problems on other compilers, I'm happy to help out make LodePNG +support the compiler if it supports the ISO C90 and C++ standard well enough. If +the required modification to support the compiler requires using non standard or +lesser C/C++ code or headers, I won't support it. + + +13. examples +------------ + +This decoder and encoder example show the most basic usage of LodePNG (using the +classes, not the simple functions, which would be trivial) + +More complex examples can be found in: +-lodepng_examples.c: 9 different examples in C, such as showing the image with SDL, ... +-lodepng_examples.cpp: the exact same examples in C++ using the C++ wrapper of LodePNG + + +13.1. decoder C++ example +------------------------- + +//////////////////////////////////////////////////////////////////////////////// +#include "lodepng.h" +#include + +int main(int argc, char *argv[]) +{ + const char* filename = argc > 1 ? argv[1] : "test.png"; + + //load and decode + std::vector buffer, image; + LodePNG::loadFile(buffer, filename); //load the image file with given filename + LodePNG::Decoder decoder; + decoder.decode(image, buffer.size() ? &buffer[0] : 0, (unsigned)buffer.size()); //decode the png + + //if there's an error, display it + if(decoder.hasError()) std::cout << "error: " << decoder.getError() << std::endl; + + //the pixels are now in the vector "image", use it as texture, draw it, ... +} + +//alternative version using the "simple" function +int main(int argc, char *argv[]) +{ + const char* filename = argc > 1 ? argv[1] : "test.png"; + + //load and decode + std::vector image; + unsigned w, h; + unsigned error = LodePNG::decode(image, w, h, filename); + + //if there's an error, display it + if(error != 0) std::cout << "error: " << error << std::endl; + + //the pixels are now in the vector "image", use it as texture, draw it, ... +} +//////////////////////////////////////////////////////////////////////////////// + + +13.2 encoder C++ example +------------------------ + +//////////////////////////////////////////////////////////////////////////////// +#include "lodepng.h" +#include + +int main(int argc, char *argv[]) +{ + //check if user gave a filename + if(argc <= 1) + { + std::cout << "please provide a filename to save to\n"; + return 0; + } + + //generate some image + std::vector image; + image.resize(512 * 512 * 4); + for(unsigned y = 0; y < 512; y++) + for(unsigned x = 0; x < 512; x++) + { + image[4 * 512 * y + 4 * x + 0] = 255 * !(x & y); + image[4 * 512 * y + 4 * x + 1] = x ^ y; + image[4 * 512 * y + 4 * x + 2] = x | y; + image[4 * 512 * y + 4 * x + 3] = 255; + } + + //encode and save + std::vector buffer; + LodePNG::Encoder encoder; + encoder.encode(buffer, image, 512, 512); + LodePNG::saveFile(buffer, argv[1]); + + //the same as the 4 lines of code above, but in 1 call: + //LodePNG::encode(argv[1], image, 512, 512); +} +//////////////////////////////////////////////////////////////////////////////// + + +13.3 Decoder C example +---------------------- + +This example loads the PNG in 1 function call + +#include "lodepng.h" + +int main(int argc, char *argv[]) +{ + unsigned error; + unsigned char* image; + size_t w, h; + + if(argc <= 1) return 0; + + error = LodePNG_decode3(&image, &w, &h, filename); + + free(image); +} + + +14. LodeZlib +------------ + +Also available in the interface is LodeZlib. Both C and C++ versions of these +functions are available. The interface is similar to that of the "simple" PNG +encoding and decoding functions. + +LodeZlib can be used to zlib compress and decompress a buffer. It cannot be +used to create gzip files however. Also, it only supports the part of zlib +that is required for PNG, it does not support compression and decompression +with dictionaries. + + +15. changes +----------- + +The version number of LodePNG is the date of the change given in the format +yyyymmdd. + +Some changes aren't backwards compatible. Those are indicated with a (!) +symbol. + +*) 02 sep 2008: fixed bug where it could create empty tree that linux apps could + read by ignoring the problem but windows apps couldn't. +*) 06 jun 2008: added more error checks for out of memory cases. +*) 26 apr 2008: added a few more checks here and there to ensure more safety. +*) 06 mar 2008: crash with encoding of strings fixed +*) 02 feb 2008: support for international text chunks added (iTXt) +*) 23 jan 2008: small cleanups, and #defines to divide code in sections +*) 20 jan 2008: support for unknown chunks allowing using LodePNG for an editor. +*) 18 jan 2008: support for tIME and pHYs chunks added to encoder and decoder. +*) 17 jan 2008: ability to encode and decode compressed zTXt chunks added + Also vareous fixes, such as in the deflate and the padding bits code. +*) 13 jan 2008: Added ability to encode Adam7-interlaced images. Improved + filtering code of encoder. +*) 07 jan 2008: (!) changed LodePNG to use ISO C90 instead of C++. A + C++ wrapper around this provides an interface almost identical to before. + Having LodePNG be pure ISO C90 makes it more portable. The C and C++ code + are together in these files but it works both for C and C++ compilers. +*) 29 dec 2007: (!) changed most integer types to unsigned int + other tweaks +*) 30 aug 2007: bug fixed which makes this Borland C++ compatible +*) 09 aug 2007: some VS2005 warnings removed again +*) 21 jul 2007: deflate code placed in new namespace separate from zlib code +*) 08 jun 2007: fixed bug with 2- and 4-bit color, and small interlaced images +*) 04 jun 2007: improved support for Visual Studio 2005: crash with accessing + invalid std::vector element [0] fixed, and level 3 and 4 warnings removed +*) 02 jun 2007: made the encoder add a tag with version by default +*) 27 may 2007: zlib and png code separated (but still in the same file), + simple encoder/decoder functions added for more simple usage cases +*) 19 may 2007: minor fixes, some code cleaning, new error added (error 69), + moved some examples from here to lodepng_examples.cpp +*) 12 may 2007: palette decoding bug fixed +*) 24 apr 2007: changed the license from BSD to the zlib license +*) 11 mar 2007: very simple addition: ability to encode bKGD chunks. +*) 04 mar 2007: (!) tEXt chunk related fixes, and support for encoding + palettized PNG images. Plus little interface change with palette and texts. +*) 03 mar 2007: Made it encode dynamic Huffman shorter with repeat codes. + Fixed a bug where the end code of a block had length 0 in the Huffman tree. +*) 26 feb 2007: Huffman compression with dynamic trees (BTYPE 2) now implemented + and supported by the encoder, resulting in smaller PNGs at the output. +*) 27 jan 2007: Made the Adler-32 test faster so that a timewaste is gone. +*) 24 jan 2007: gave encoder an error interface. Added color conversion from any + greyscale type to 8-bit greyscale with or without alpha. +*) 21 jan 2007: (!) Totally changed the interface. It allows more color types + to convert to and is more uniform. See the manual for how it works now. +*) 07 jan 2007: Some cleanup & fixes, and a few changes over the last days: + encode/decode custom tEXt chunks, separate classes for zlib & deflate, and + at last made the decoder give errors for incorrect Adler32 or Crc. +*) 01 jan 2007: Fixed bug with encoding PNGs with less than 8 bits per channel. +*) 29 dec 2006: Added support for encoding images without alpha channel, and + cleaned out code as well as making certain parts faster. +*) 28 dec 2006: Added "Settings" to the encoder. +*) 26 dec 2006: The encoder now does LZ77 encoding and produces much smaller files now. + Removed some code duplication in the decoder. Fixed little bug in an example. +*) 09 dec 2006: (!) Placed output parameters of public functions as first parameter. + Fixed a bug of the decoder with 16-bit per color. +*) 15 okt 2006: Changed documentation structure +*) 09 okt 2006: Encoder class added. It encodes a valid PNG image from the + given image buffer, however for now it's not compressed. +*) 08 sep 2006: (!) Changed to interface with a Decoder class +*) 30 jul 2006: (!) LodePNG_InfoPng , width and height are now retrieved in different + way. Renamed decodePNG to decodePNGGeneric. +*) 29 jul 2006: (!) Changed the interface: image info is now returned as a + struct of type LodePNG::LodePNG_Info, instead of a vector, which was a bit clumsy. +*) 28 jul 2006: Cleaned the code and added new error checks. + Corrected terminology "deflate" into "inflate". +*) 23 jun 2006: Added SDL example in the documentation in the header, this + example allows easy debugging by displaying the PNG and its transparency. +*) 22 jun 2006: (!) Changed way to obtain error value. Added + loadFile function for convenience. Made decodePNG32 faster. +*) 21 jun 2006: (!) Changed type of info vector to unsigned. + Changed position of palette in info vector. Fixed an important bug that + happened on PNGs with an uncompressed block. +*) 16 jun 2006: Internally changed unsigned into unsigned where + needed, and performed some optimizations. +*) 07 jun 2006: (!) Renamed functions to decodePNG and placed them + in LodePNG namespace. Changed the order of the parameters. Rewrote the + documentation in the header. Renamed files to lodepng.cpp and lodepng.h +*) 22 apr 2006: Optimized and improved some code +*) 07 sep 2005: (!) Changed to std::vector interface +*) 12 aug 2005: Initial release + + +16. contact information +----------------------- + +Feel free to contact me with suggestions, problems, comments, ... concerning +LodePNG. If you encounter a PNG image that doesn't work properly with this +decoder, feel free to send it and I'll use it to find and fix the problem. + +My email address is (puzzle the account and domain together with an @ symbol): +Domain: gmail dot com. +Account: lode dot vandevenne. + + +Copyright (c) 2005-2008 Lode Vandevenne +*/ diff --git a/trunk/src/logos.cpp b/trunk/src/logos.cpp new file mode 100644 index 0000000..afc93cb --- /dev/null +++ b/trunk/src/logos.cpp @@ -0,0 +1,1986 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#include + +#include "qtbc.h" +#include +#include + +// Stripped version of FreeSans.ttf part of FreeFonts package, +// see http://www.nongnu.org/freefont for more info +unsigned char FreeSans_ttf[] = { + 0x00, 0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x80, 0x00, 0x03, 0x00, 0x70, + 0x47, 0x44, 0x45, 0x46, 0x01, 0x0a, 0x00, 0xe3, 0x00, 0x00, 0x48, 0x28, + 0x00, 0x00, 0x00, 0x2a, 0x47, 0x50, 0x4f, 0x53, 0x9d, 0x1a, 0x99, 0x8a, + 0x00, 0x00, 0x49, 0x50, 0x00, 0x00, 0x10, 0x42, 0x47, 0x53, 0x55, 0x42, + 0xa8, 0x85, 0x92, 0x0c, 0x00, 0x00, 0x48, 0x54, 0x00, 0x00, 0x00, 0xfc, + 0x4f, 0x53, 0x2f, 0x32, 0x67, 0x3f, 0xcf, 0x10, 0x00, 0x00, 0x01, 0x78, + 0x00, 0x00, 0x00, 0x56, 0x63, 0x6d, 0x61, 0x70, 0xe6, 0xd7, 0x91, 0x3d, + 0x00, 0x00, 0x04, 0xec, 0x00, 0x00, 0x01, 0x8a, 0x63, 0x76, 0x74, 0x20, + 0x00, 0x21, 0x02, 0x79, 0x00, 0x00, 0x06, 0x78, 0x00, 0x00, 0x00, 0x04, + 0x67, 0x61, 0x73, 0x70, 0xff, 0xff, 0x00, 0x03, 0x00, 0x00, 0x48, 0x20, + 0x00, 0x00, 0x00, 0x08, 0x67, 0x6c, 0x79, 0x66, 0xb3, 0x58, 0xaf, 0x41, + 0x00, 0x00, 0x08, 0x10, 0x00, 0x00, 0x37, 0xca, 0x68, 0x65, 0x61, 0x64, + 0xe7, 0x18, 0xbe, 0xac, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x36, + 0x68, 0x68, 0x65, 0x61, 0x10, 0xbb, 0x06, 0xf2, 0x00, 0x00, 0x01, 0x34, + 0x00, 0x00, 0x00, 0x24, 0x68, 0x6d, 0x74, 0x78, 0x55, 0x0d, 0x49, 0xe2, + 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00, 0x03, 0x1a, 0x6c, 0x6f, 0x63, 0x61, + 0x1f, 0xdd, 0x2c, 0xb6, 0x00, 0x00, 0x06, 0x7c, 0x00, 0x00, 0x01, 0x94, + 0x6d, 0x61, 0x78, 0x70, 0x01, 0x16, 0x00, 0xb3, 0x00, 0x00, 0x01, 0x58, + 0x00, 0x00, 0x00, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x85, 0x1f, 0xf3, 0x73, + 0x00, 0x00, 0x3f, 0xdc, 0x00, 0x00, 0x06, 0x69, 0x70, 0x6f, 0x73, 0x74, + 0x46, 0xf5, 0x10, 0xd8, 0x00, 0x00, 0x46, 0x48, 0x00, 0x00, 0x01, 0xd6, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0xc2, 0x8f, 0x00, 0x8a, 0xba, 0xad, + 0x5f, 0x0f, 0x3c, 0xf5, 0x00, 0x0b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xc0, 0x44, 0xd8, 0x89, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x44, 0xd8, 0x89, + 0xff, 0xd3, 0xfe, 0x3d, 0x07, 0x9c, 0x07, 0xd1, 0x00, 0x00, 0x00, 0x08, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x07, 0xd1, 0xfe, 0x3d, 0x01, 0x78, 0x08, 0x1e, 0xff, 0xd3, 0xff, 0xd2, + 0x07, 0x9c, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc4, 0x00, 0x01, 0x00, 0x00, + 0x00, 0xc9, 0x00, 0x66, 0x00, 0x05, 0x00, 0x49, 0x00, 0x04, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0x03, 0x87, 0x01, 0x90, 0x00, 0x05, + 0x00, 0x00, 0x05, 0x33, 0x05, 0x99, 0x00, 0x00, 0x03, 0xd7, 0x05, 0x33, + 0x05, 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x02, 0x12, 0x00, 0x00, + 0x02, 0x0b, 0x05, 0x04, 0x02, 0x02, 0x02, 0x02, 0x02, 0x04, 0x00, 0x00, + 0x00, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x50, 0x66, 0x45, 0x64, 0x00, 0x40, 0x00, 0x0d, 0x02, 0xdc, + 0x06, 0x66, 0xfe, 0x66, 0x00, 0x00, 0x07, 0xd1, 0x01, 0xc3, 0x80, 0x02, + 0x00, 0xbf, 0xdf, 0xf7, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x89, + 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0xb2, 0x00, 0x00, + 0x02, 0x39, 0x00, 0x00, 0x02, 0x39, 0x00, 0xfe, 0x02, 0xd7, 0x00, 0x6a, + 0x04, 0x72, 0x00, 0x1d, 0x04, 0x72, 0x00, 0x44, 0x07, 0x1c, 0x00, 0x3b, + 0x05, 0x56, 0x00, 0x6a, 0x01, 0x87, 0x00, 0x62, 0x02, 0xa9, 0x00, 0x96, + 0x02, 0xa9, 0x00, 0x4e, 0x03, 0x1c, 0x00, 0x52, 0x04, 0xac, 0x00, 0x66, + 0x02, 0x39, 0x00, 0xb2, 0x02, 0xa9, 0x00, 0x5e, 0x02, 0x39, 0x00, 0xb2, + 0x02, 0x39, 0xff, 0xf0, 0x04, 0x72, 0x00, 0x58, 0x04, 0x72, 0x00, 0xd1, + 0x04, 0x72, 0x00, 0x46, 0x04, 0x72, 0x00, 0x42, 0x04, 0x72, 0x00, 0x39, + 0x04, 0x72, 0x00, 0x48, 0x04, 0x72, 0x00, 0x58, 0x04, 0x72, 0x00, 0x5e, + 0x04, 0x72, 0x00, 0x4c, 0x04, 0x72, 0x00, 0x4e, 0x02, 0x39, 0x00, 0xe1, + 0x02, 0x39, 0x00, 0xe1, 0x04, 0xac, 0x00, 0x5c, 0x04, 0xac, 0x00, 0x66, + 0x04, 0xac, 0x00, 0x66, 0x04, 0x72, 0x00, 0x9e, 0x08, 0x1e, 0x00, 0x46, + 0x05, 0x56, 0x00, 0x23, 0x05, 0x56, 0x00, 0xa2, 0x05, 0xc6, 0x00, 0x62, + 0x05, 0xc6, 0x00, 0xb6, 0x05, 0x56, 0x00, 0xb8, 0x04, 0xe3, 0x00, 0xb8, + 0x06, 0x39, 0x00, 0x5a, 0x05, 0xc6, 0x00, 0xaa, 0x02, 0x39, 0x00, 0xcd, + 0x04, 0x00, 0x00, 0x23, 0x05, 0x56, 0x00, 0xa2, 0x04, 0x72, 0x00, 0xa4, + 0x06, 0xa9, 0x00, 0x9a, 0x05, 0xc6, 0x00, 0x9c, 0x06, 0x39, 0x00, 0x4e, + 0x05, 0x56, 0x00, 0xba, 0x06, 0x39, 0x00, 0x4e, 0x05, 0xc6, 0x00, 0xbe, + 0x05, 0x56, 0x00, 0x62, 0x04, 0xe3, 0x00, 0x2b, 0x05, 0xc6, 0x00, 0xae, + 0x05, 0x56, 0x00, 0x3d, 0x07, 0x8d, 0x00, 0x2d, 0x05, 0x56, 0x00, 0x2d, + 0x05, 0x56, 0x00, 0x1b, 0x04, 0xe3, 0x00, 0x39, 0x02, 0x39, 0x00, 0x83, + 0x02, 0x39, 0xff, 0xf0, 0x02, 0x39, 0x00, 0x2f, 0x03, 0xc0, 0x00, 0x5a, + 0x04, 0x72, 0xff, 0xd3, 0x02, 0xa9, 0x00, 0x2d, 0x04, 0x72, 0x00, 0x56, + 0x04, 0x72, 0x00, 0x6f, 0x04, 0x00, 0x00, 0x3f, 0x04, 0x72, 0x00, 0x35, + 0x04, 0x72, 0x00, 0x52, 0x02, 0x39, 0x00, 0x25, 0x04, 0x72, 0x00, 0x3b, + 0x04, 0x72, 0x00, 0x8f, 0x01, 0xc6, 0x00, 0x87, 0x01, 0xc6, 0xff, 0xdb, + 0x04, 0x00, 0x00, 0x77, 0x01, 0xc6, 0x00, 0x8b, 0x06, 0xa9, 0x00, 0x8f, + 0x04, 0x72, 0x00, 0x8f, 0x04, 0x72, 0x00, 0x4a, 0x04, 0x72, 0x00, 0x6f, + 0x04, 0x72, 0x00, 0x35, 0x02, 0xa9, 0x00, 0x8d, 0x04, 0x00, 0x00, 0x46, + 0x02, 0x39, 0x00, 0x1d, 0x04, 0x72, 0x00, 0x85, 0x04, 0x00, 0x00, 0x14, + 0x05, 0xc6, 0x00, 0x0c, 0x04, 0x00, 0x00, 0x23, 0x04, 0x00, 0x00, 0x29, + 0x04, 0x00, 0x00, 0x3f, 0x02, 0xac, 0x00, 0x58, 0x02, 0x14, 0x00, 0xcd, + 0x02, 0xac, 0x00, 0x3b, 0x04, 0xac, 0x00, 0x9a, 0x02, 0x39, 0x00, 0x00, + 0x02, 0x39, 0x00, 0xfa, 0x04, 0x72, 0x00, 0x6a, 0x04, 0x72, 0x00, 0x35, + 0x04, 0x72, 0x00, 0x89, 0x04, 0x72, 0x00, 0x17, 0x02, 0x14, 0x00, 0xcd, + 0x04, 0x72, 0x00, 0x58, 0x02, 0xa9, 0x00, 0x3d, 0x05, 0xe5, 0xff, 0xe5, + 0x02, 0xf5, 0x00, 0x4c, 0x04, 0x72, 0x00, 0xc9, 0x04, 0xac, 0x00, 0x52, + 0x02, 0xa9, 0x00, 0x5e, 0x05, 0xe5, 0xff, 0xe5, 0x02, 0xa9, 0x00, 0x39, + 0x04, 0xd9, 0x01, 0x35, 0x04, 0xac, 0x00, 0x66, 0x02, 0xce, 0x00, 0x27, + 0x02, 0xce, 0x00, 0x21, 0x02, 0xa9, 0x00, 0xbc, 0x04, 0x72, 0x00, 0x85, + 0x04, 0x4b, 0x00, 0x62, 0x02, 0x39, 0x00, 0xb2, 0x02, 0xa9, 0x00, 0x50, + 0x02, 0xce, 0x00, 0x7d, 0x02, 0xeb, 0x00, 0x52, 0x04, 0x72, 0x00, 0xc9, + 0x06, 0xf3, 0x00, 0x7d, 0x06, 0xf3, 0x00, 0x7d, 0x06, 0xf3, 0x00, 0x21, + 0x04, 0x72, 0x00, 0xc5, 0x05, 0x56, 0x00, 0x23, 0x05, 0x56, 0x00, 0x23, + 0x05, 0x56, 0x00, 0x23, 0x05, 0x56, 0x00, 0x23, 0x05, 0x56, 0x00, 0x23, + 0x05, 0x56, 0x00, 0x23, 0x08, 0x00, 0x00, 0x17, 0x05, 0xc6, 0x00, 0x62, + 0x05, 0x56, 0x00, 0xb8, 0x05, 0x56, 0x00, 0xb8, 0x05, 0x56, 0x00, 0xb8, + 0x05, 0x56, 0x00, 0xb8, 0x02, 0x39, 0x00, 0xcd, 0x02, 0x39, 0x00, 0xcd, + 0x02, 0x39, 0x00, 0xcd, 0x02, 0x39, 0x00, 0x1c, 0x05, 0xc6, 0x00, 0x29, + 0x05, 0xc6, 0x00, 0x9c, 0x06, 0x39, 0x00, 0x4e, 0x06, 0x39, 0x00, 0x4e, + 0x06, 0x39, 0x00, 0x4e, 0x06, 0x39, 0x00, 0x4e, 0x06, 0x39, 0x00, 0x4e, + 0x04, 0xac, 0x00, 0xc3, 0x06, 0x39, 0x00, 0x3d, 0x05, 0xc6, 0x00, 0xae, + 0x05, 0xc6, 0x00, 0xae, 0x05, 0xc6, 0x00, 0xae, 0x05, 0xc6, 0x00, 0xae, + 0x05, 0x56, 0x00, 0x1b, 0x05, 0x53, 0x00, 0xba, 0x04, 0xe3, 0x00, 0x89, + 0x04, 0x72, 0x00, 0x56, 0x04, 0x72, 0x00, 0x56, 0x04, 0x72, 0x00, 0x56, + 0x04, 0x72, 0x00, 0x56, 0x04, 0x72, 0x00, 0x56, 0x04, 0x72, 0x00, 0x56, + 0x07, 0x1c, 0x00, 0x46, 0x04, 0x00, 0x00, 0x3f, 0x04, 0x72, 0x00, 0x52, + 0x04, 0x72, 0x00, 0x52, 0x04, 0x72, 0x00, 0x52, 0x04, 0x72, 0x00, 0x52, + 0x02, 0x39, 0x00, 0x00, 0x02, 0x39, 0x00, 0x00, 0x02, 0x39, 0x00, 0x00, + 0x02, 0x39, 0x00, 0x06, 0x04, 0x72, 0x00, 0x4a, 0x04, 0x72, 0x00, 0x8f, + 0x04, 0x72, 0x00, 0x4a, 0x04, 0x72, 0x00, 0x4a, 0x04, 0x72, 0x00, 0x4a, + 0x04, 0x72, 0x00, 0x4a, 0x04, 0x72, 0x00, 0x4a, 0x04, 0xac, 0x00, 0x66, + 0x04, 0xe3, 0x00, 0x25, 0x04, 0x72, 0x00, 0x85, 0x04, 0x72, 0x00, 0x85, + 0x04, 0x72, 0x00, 0x85, 0x04, 0x72, 0x00, 0x85, 0x04, 0x00, 0x00, 0x29, + 0x04, 0x70, 0x00, 0x6f, 0x04, 0x00, 0x00, 0x29, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x1c, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0x00, 0x03, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x1c, 0x00, 0x04, 0x00, 0x68, 0x00, 0x00, 0x00, 0x16, + 0x00, 0x10, 0x00, 0x03, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x0e, + 0x00, 0x7e, 0x00, 0xff, 0x01, 0x31, 0x02, 0xc6, 0x02, 0xcb, 0x02, 0xda, + 0x02, 0xdc, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x0e, + 0x00, 0x20, 0x00, 0xa0, 0x01, 0x31, 0x02, 0xc6, 0x02, 0xca, 0x02, 0xda, + 0x02, 0xdc, 0xff, 0xff, 0x00, 0x01, 0xff, 0xf6, 0xff, 0xf5, 0xff, 0xe4, + 0xff, 0xc3, 0xff, 0x92, 0xfd, 0xfe, 0xfd, 0xfb, 0xfd, 0xed, 0xfd, 0xec, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x01, 0x93, 0xb3, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0xc0, 0x02, 0x00, 0xa1, 0xc1, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x80, 0x7f, 0x7c, 0x81, 0x76, 0x75, 0x69, 0x70, 0x9a, + 0x00, 0x00, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, + 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, + 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, + 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, + 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, + 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, + 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, + 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, + 0x62, 0x00, 0x87, 0x88, 0x8a, 0x8c, 0x94, 0x99, 0x9f, 0xa4, 0xa3, 0xa5, + 0xa7, 0xa6, 0xa8, 0xaa, 0xac, 0xab, 0xad, 0xae, 0xb0, 0xaf, 0xb1, 0xb2, + 0xb4, 0xb6, 0xb5, 0xb7, 0xb9, 0xb8, 0xbd, 0xbc, 0xbe, 0xbf, 0x00, 0x73, + 0x65, 0x66, 0x6a, 0x00, 0x79, 0xa2, 0x71, 0x6c, 0x00, 0x77, 0x6b, 0x00, + 0x89, 0x9b, 0x00, 0x74, 0x00, 0x00, 0x68, 0x78, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x6d, 0x7d, 0x00, 0xa9, 0xbb, 0x82, 0x64, 0x6f, 0x00, 0x00, 0x00, + 0x00, 0x6e, 0x7e, 0x00, 0x63, 0x83, 0x86, 0x98, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xba, 0x00, 0xc2, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x7a, 0x00, 0x00, 0x00, 0x85, 0x8d, 0x84, 0x8e, 0x8b, + 0x90, 0x91, 0x92, 0x8f, 0x96, 0x97, 0x00, 0x95, 0x9d, 0x9e, 0x9c, 0x00, + 0x00, 0x00, 0x72, 0x00, 0x00, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x21, 0x02, 0x79, 0x00, 0x00, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, + 0x00, 0x16, 0x00, 0x16, 0x00, 0x2e, 0x00, 0x48, 0x00, 0x7f, 0x00, 0xe5, + 0x01, 0x5d, 0x01, 0xc9, 0x01, 0xd9, 0x01, 0xfd, 0x02, 0x20, 0x02, 0x3e, + 0x02, 0x56, 0x02, 0x6c, 0x02, 0x79, 0x02, 0x85, 0x02, 0x93, 0x02, 0xc3, + 0x02, 0xda, 0x03, 0x16, 0x03, 0x63, 0x03, 0x80, 0x03, 0xbe, 0x04, 0x0c, + 0x04, 0x2a, 0x04, 0x84, 0x04, 0xd4, 0x04, 0xe6, 0x05, 0x03, 0x05, 0x17, + 0x05, 0x2b, 0x05, 0x3f, 0x05, 0x7d, 0x06, 0x10, 0x06, 0x2c, 0x06, 0x6d, + 0x06, 0xaa, 0x06, 0xd3, 0x06, 0xec, 0x07, 0x02, 0x07, 0x50, 0x07, 0x68, + 0x07, 0x76, 0x07, 0x99, 0x07, 0xb5, 0x07, 0xc6, 0x07, 0xe2, 0x07, 0xfa, + 0x08, 0x47, 0x08, 0x72, 0x08, 0xc7, 0x09, 0x08, 0x09, 0x57, 0x09, 0x6a, + 0x09, 0x8f, 0x09, 0xa2, 0x09, 0xc1, 0x09, 0xe0, 0x09, 0xf7, 0x0a, 0x0e, + 0x0a, 0x20, 0x0a, 0x2f, 0x0a, 0x41, 0x0a, 0x54, 0x0a, 0x61, 0x0a, 0x70, + 0x0a, 0xd1, 0x0b, 0x0b, 0x0b, 0x3e, 0x0b, 0x79, 0x0b, 0xba, 0x0b, 0xdc, + 0x0c, 0x34, 0x0c, 0x5b, 0x0c, 0x6f, 0x0c, 0x91, 0x0c, 0xae, 0x0c, 0xbc, + 0x0c, 0xfb, 0x0d, 0x21, 0x0d, 0x55, 0x0d, 0x8c, 0x0d, 0xc6, 0x0d, 0xe3, + 0x0e, 0x2f, 0x0e, 0x55, 0x0e, 0x7b, 0x0e, 0x8e, 0x0e, 0xaa, 0x0e, 0xc9, + 0x0e, 0xec, 0x0f, 0x03, 0x0f, 0x43, 0x0f, 0x50, 0x0f, 0x8f, 0x0f, 0xc0, + 0x0f, 0xc8, 0x0f, 0xd2, 0x10, 0x13, 0x10, 0x73, 0x10, 0xbe, 0x10, 0xe8, + 0x10, 0xfb, 0x11, 0x77, 0x11, 0x89, 0x12, 0x03, 0x12, 0x5c, 0x12, 0x78, + 0x12, 0x88, 0x12, 0x95, 0x13, 0x17, 0x13, 0x24, 0x13, 0x55, 0x13, 0x74, + 0x13, 0xb1, 0x13, 0xf8, 0x14, 0x06, 0x14, 0x38, 0x14, 0x5a, 0x14, 0x68, + 0x14, 0x99, 0x14, 0xb1, 0x14, 0xea, 0x15, 0x07, 0x15, 0x3d, 0x15, 0x94, + 0x15, 0xf9, 0x16, 0x03, 0x16, 0x0f, 0x16, 0x1b, 0x16, 0x27, 0x16, 0x33, + 0x16, 0x3f, 0x16, 0x4b, 0x16, 0x72, 0x16, 0xdc, 0x16, 0xe8, 0x16, 0xf4, + 0x17, 0x00, 0x17, 0x0c, 0x17, 0x18, 0x17, 0x24, 0x17, 0x30, 0x17, 0x3c, + 0x17, 0x70, 0x17, 0x7c, 0x17, 0x88, 0x17, 0x94, 0x17, 0xa0, 0x17, 0xac, + 0x17, 0xb8, 0x17, 0xd9, 0x18, 0x2e, 0x18, 0x3a, 0x18, 0x46, 0x18, 0x52, + 0x18, 0x5e, 0x18, 0x6a, 0x18, 0x95, 0x18, 0xdf, 0x18, 0xeb, 0x18, 0xf7, + 0x19, 0x03, 0x19, 0x0f, 0x19, 0x1b, 0x19, 0x27, 0x19, 0xa9, 0x1a, 0x05, + 0x1a, 0x11, 0x1a, 0x1d, 0x1a, 0x29, 0x1a, 0x35, 0x1a, 0x40, 0x1a, 0x4b, + 0x1a, 0x56, 0x1a, 0x61, 0x1a, 0xb5, 0x1a, 0xc1, 0x1a, 0xcd, 0x1a, 0xd9, + 0x1a, 0xe5, 0x1a, 0xf1, 0x1a, 0xfd, 0x1b, 0x17, 0x1b, 0x60, 0x1b, 0x6c, + 0x1b, 0x78, 0x1b, 0x84, 0x1b, 0x90, 0x1b, 0x9c, 0x1b, 0xd7, 0x1b, 0xe3, + 0x1b, 0xe3, 0x1b, 0xe3, 0x1b, 0xe3, 0x1b, 0xe3, 0x1b, 0xe3, 0x1b, 0xe3, + 0x00, 0x02, 0x00, 0x89, 0x00, 0x00, 0x03, 0xbe, 0x07, 0xd1, 0x00, 0x03, + 0x00, 0x07, 0x00, 0x00, 0x01, 0x11, 0x21, 0x11, 0x05, 0x21, 0x11, 0x21, + 0x03, 0xbe, 0xfc, 0xcb, 0x02, 0xac, 0xfd, 0xdd, 0x02, 0x23, 0x07, 0xd1, + 0xf8, 0x2f, 0x07, 0xd1, 0x89, 0xf9, 0x41, 0x00, 0x00, 0x02, 0x00, 0xfe, + 0x00, 0x00, 0x01, 0xaa, 0x05, 0xd5, 0x00, 0x05, 0x00, 0x09, 0x00, 0x00, + 0x01, 0x11, 0x03, 0x23, 0x03, 0x11, 0x13, 0x15, 0x23, 0x35, 0x01, 0xaa, + 0x2d, 0x50, 0x2d, 0xaa, 0xac, 0x05, 0xd5, 0xfd, 0x4c, 0xfe, 0x37, 0x01, + 0xc9, 0x02, 0xb4, 0xfb, 0x00, 0xd5, 0xd5, 0x00, 0x00, 0x02, 0x00, 0x6a, + 0x03, 0xb6, 0x02, 0x71, 0x05, 0xac, 0x00, 0x05, 0x00, 0x0b, 0x00, 0x00, + 0x13, 0x33, 0x15, 0x03, 0x23, 0x03, 0x25, 0x33, 0x15, 0x03, 0x23, 0x03, + 0x6a, 0xbf, 0x37, 0x50, 0x38, 0x01, 0x48, 0xbf, 0x38, 0x50, 0x37, 0x05, + 0xac, 0xe3, 0xfe, 0xed, 0x01, 0x13, 0xe3, 0xe3, 0xfe, 0xed, 0x01, 0x13, + 0x00, 0x02, 0x00, 0x1d, 0xff, 0xd7, 0x04, 0x56, 0x05, 0x93, 0x00, 0x1b, + 0x00, 0x1f, 0x00, 0x00, 0x01, 0x03, 0x33, 0x15, 0x23, 0x03, 0x33, 0x15, + 0x23, 0x03, 0x23, 0x13, 0x23, 0x03, 0x23, 0x13, 0x23, 0x35, 0x33, 0x13, + 0x23, 0x35, 0x33, 0x13, 0x33, 0x03, 0x21, 0x13, 0x03, 0x23, 0x03, 0x21, + 0x03, 0xe1, 0x49, 0xbe, 0xd9, 0x40, 0xd7, 0xef, 0x50, 0x9c, 0x4e, 0xfe, + 0x50, 0x9b, 0x4e, 0xcf, 0xe9, 0x40, 0xde, 0xf8, 0x4a, 0x9c, 0x4a, 0x01, + 0x00, 0x48, 0x63, 0xfe, 0x41, 0x01, 0x00, 0x05, 0x93, 0xfe, 0x6f, 0x8b, + 0xfe, 0x9b, 0x8b, 0xfe, 0x50, 0x01, 0xb0, 0xfe, 0x50, 0x01, 0xb0, 0x8b, + 0x01, 0x65, 0x8b, 0x01, 0x91, 0xfe, 0x6f, 0x01, 0x91, 0xfd, 0xe4, 0xfe, + 0x9b, 0x00, 0x00, 0x03, 0x00, 0x44, 0xfe, 0xfe, 0x04, 0x25, 0x06, 0x29, + 0x00, 0x2f, 0x00, 0x38, 0x00, 0x41, 0x00, 0x00, 0x01, 0x14, 0x07, 0x06, + 0x07, 0x15, 0x23, 0x35, 0x24, 0x27, 0x26, 0x3d, 0x01, 0x33, 0x16, 0x17, + 0x16, 0x17, 0x16, 0x17, 0x11, 0x26, 0x27, 0x26, 0x27, 0x26, 0x35, 0x34, + 0x37, 0x36, 0x37, 0x35, 0x33, 0x15, 0x16, 0x17, 0x16, 0x15, 0x23, 0x26, + 0x27, 0x26, 0x27, 0x11, 0x17, 0x16, 0x17, 0x16, 0x01, 0x11, 0x06, 0x07, + 0x06, 0x15, 0x14, 0x17, 0x16, 0x13, 0x36, 0x37, 0x36, 0x35, 0x34, 0x27, + 0x26, 0x27, 0x04, 0x25, 0xb0, 0x6a, 0xa1, 0x78, 0xfe, 0xec, 0x66, 0x34, + 0xa1, 0x0b, 0x12, 0x2e, 0x9b, 0x13, 0x14, 0xab, 0x3e, 0x0c, 0x0d, 0x92, + 0xcc, 0x54, 0x74, 0x78, 0xdb, 0x69, 0x4a, 0xa2, 0x02, 0x59, 0x3c, 0x55, + 0x8a, 0xde, 0x3c, 0x17, 0xfd, 0xcd, 0xa9, 0x33, 0x12, 0xbe, 0x16, 0x92, + 0xbd, 0x3e, 0x18, 0x41, 0x3c, 0x96, 0x01, 0x8f, 0xf9, 0x74, 0x46, 0x0b, + 0xd3, 0xd3, 0x12, 0xbd, 0x61, 0x86, 0x23, 0x77, 0x31, 0x7d, 0x20, 0x04, + 0x03, 0x02, 0x2d, 0x33, 0x27, 0x08, 0x09, 0x68, 0xc3, 0xf8, 0x68, 0x2b, + 0x0e, 0x6f, 0x6f, 0x10, 0x8f, 0x64, 0x90, 0x85, 0x49, 0x32, 0x04, 0xfe, + 0x02, 0x27, 0x49, 0xa1, 0x3f, 0x01, 0x60, 0x01, 0xec, 0x17, 0x7a, 0x2d, + 0x36, 0xa6, 0x43, 0x08, 0xfd, 0x1a, 0x17, 0x89, 0x36, 0x43, 0x69, 0x39, + 0x33, 0x2d, 0x00, 0x05, 0x00, 0x3b, 0xff, 0xd7, 0x06, 0xdf, 0x05, 0xac, + 0x00, 0x15, 0x00, 0x25, 0x00, 0x29, 0x00, 0x3f, 0x00, 0x4f, 0x00, 0x00, + 0x01, 0x32, 0x17, 0x16, 0x17, 0x14, 0x07, 0x06, 0x07, 0x06, 0x23, 0x22, + 0x27, 0x26, 0x27, 0x34, 0x35, 0x34, 0x37, 0x36, 0x37, 0x36, 0x17, 0x22, + 0x07, 0x06, 0x15, 0x14, 0x17, 0x16, 0x33, 0x32, 0x37, 0x36, 0x35, 0x34, + 0x27, 0x26, 0x25, 0x33, 0x01, 0x23, 0x01, 0x32, 0x17, 0x16, 0x17, 0x14, + 0x07, 0x06, 0x07, 0x06, 0x23, 0x22, 0x27, 0x26, 0x27, 0x34, 0x35, 0x34, + 0x37, 0x36, 0x37, 0x36, 0x17, 0x22, 0x07, 0x06, 0x15, 0x14, 0x17, 0x16, + 0x33, 0x32, 0x37, 0x36, 0x35, 0x34, 0x27, 0x26, 0x01, 0x98, 0x91, 0x65, + 0x65, 0x03, 0x60, 0x60, 0x87, 0x0b, 0x0a, 0x8d, 0x66, 0x65, 0x07, 0x62, + 0x60, 0x88, 0x0a, 0x09, 0x5e, 0x3e, 0x33, 0x48, 0x3b, 0x4e, 0x5c, 0x3f, + 0x33, 0x48, 0x3a, 0x02, 0xf9, 0x87, 0xfc, 0xd7, 0x87, 0x03, 0xcb, 0x93, + 0x65, 0x64, 0x02, 0x61, 0x5f, 0x85, 0x0b, 0x0c, 0x8c, 0x65, 0x65, 0x08, + 0x61, 0x60, 0x88, 0x0a, 0x09, 0x5e, 0x3e, 0x33, 0x48, 0x3b, 0x4e, 0x5d, + 0x3f, 0x33, 0x4a, 0x39, 0x05, 0x7b, 0x65, 0x6b, 0x92, 0x89, 0x65, 0x64, + 0x08, 0x01, 0x62, 0x61, 0x8a, 0x09, 0x09, 0x8b, 0x66, 0x65, 0x07, 0x01, + 0x8f, 0x47, 0x3b, 0x4d, 0x5d, 0x3f, 0x33, 0x46, 0x3a, 0x4d, 0x61, 0x3e, + 0x32, 0xc0, 0xfa, 0x2b, 0x02, 0xbc, 0x65, 0x69, 0x92, 0x88, 0x65, 0x63, + 0x09, 0x01, 0x62, 0x60, 0x89, 0x0a, 0x09, 0x8b, 0x65, 0x64, 0x07, 0x01, + 0x8f, 0x47, 0x3a, 0x4c, 0x5e, 0x3e, 0x33, 0x47, 0x39, 0x4b, 0x62, 0x3e, + 0x31, 0x00, 0x00, 0x03, 0x00, 0x6a, 0xff, 0xd1, 0x05, 0x19, 0x05, 0xac, + 0x00, 0x29, 0x00, 0x39, 0x00, 0x46, 0x00, 0x00, 0x25, 0x06, 0x07, 0x06, + 0x23, 0x22, 0x27, 0x26, 0x35, 0x34, 0x37, 0x36, 0x37, 0x26, 0x27, 0x26, + 0x35, 0x34, 0x37, 0x36, 0x33, 0x32, 0x17, 0x16, 0x15, 0x14, 0x07, 0x06, + 0x07, 0x01, 0x36, 0x37, 0x34, 0x3d, 0x01, 0x33, 0x14, 0x07, 0x06, 0x07, + 0x13, 0x23, 0x01, 0x36, 0x37, 0x36, 0x35, 0x34, 0x27, 0x26, 0x23, 0x22, + 0x07, 0x06, 0x15, 0x14, 0x17, 0x16, 0x09, 0x01, 0x06, 0x07, 0x06, 0x15, + 0x14, 0x17, 0x16, 0x33, 0x32, 0x37, 0x36, 0x03, 0xba, 0x4a, 0x27, 0x8e, + 0xad, 0xc8, 0x74, 0x68, 0x49, 0x46, 0xbd, 0x7c, 0x1c, 0x0e, 0x65, 0x66, + 0x94, 0x9c, 0x5e, 0x53, 0x4b, 0x3f, 0x90, 0x01, 0x10, 0x3a, 0x06, 0xa4, + 0x6d, 0x05, 0x05, 0xfa, 0xe0, 0xfe, 0x0f, 0x8f, 0x29, 0x1b, 0x46, 0x2f, + 0x3e, 0x67, 0x2f, 0x1a, 0x1f, 0x1b, 0x01, 0x66, 0xfe, 0xb8, 0xa9, 0x31, + 0x1f, 0x53, 0x4e, 0x6b, 0x75, 0x6e, 0x27, 0xa0, 0x49, 0x1d, 0x69, 0x7b, + 0x6e, 0xae, 0x8e, 0x5d, 0x5c, 0x6e, 0x9c, 0x56, 0x2b, 0x30, 0x86, 0x5d, + 0x5f, 0x65, 0x59, 0x84, 0x79, 0x53, 0x46, 0x52, 0xfe, 0xb2, 0x68, 0x73, + 0x09, 0x08, 0x08, 0xb4, 0xb3, 0x08, 0x08, 0xfe, 0xcb, 0x03, 0x73, 0x5a, + 0x40, 0x2b, 0x37, 0x5a, 0x32, 0x22, 0x4c, 0x2b, 0x39, 0x3a, 0x32, 0x2c, + 0xfd, 0x44, 0x01, 0x99, 0x6c, 0x57, 0x36, 0x42, 0x70, 0x4d, 0x49, 0x5b, + 0x1f, 0x00, 0x00, 0x01, 0x00, 0x62, 0x03, 0xb6, 0x01, 0x23, 0x05, 0xac, + 0x00, 0x05, 0x00, 0x00, 0x13, 0x33, 0x15, 0x03, 0x23, 0x03, 0x62, 0xc1, + 0x37, 0x52, 0x38, 0x05, 0xac, 0xe3, 0xfe, 0xed, 0x01, 0x13, 0x00, 0x01, + 0x00, 0x96, 0xfe, 0x4e, 0x02, 0x54, 0x05, 0xd5, 0x00, 0x11, 0x00, 0x00, + 0x01, 0x33, 0x02, 0x03, 0x06, 0x15, 0x10, 0x13, 0x16, 0x17, 0x23, 0x26, + 0x03, 0x26, 0x35, 0x10, 0x13, 0x36, 0x01, 0xe3, 0x71, 0xd3, 0x36, 0x10, + 0xb3, 0x2e, 0x38, 0x71, 0xbe, 0x58, 0x37, 0x89, 0x51, 0x05, 0xd5, 0xfe, + 0xab, 0xfe, 0x77, 0x74, 0x71, 0xfe, 0x76, 0xfe, 0x82, 0x61, 0x5b, 0xfa, + 0x01, 0x47, 0xc9, 0xba, 0x01, 0x31, 0x01, 0x3f, 0xbd, 0x00, 0x00, 0x01, + 0x00, 0x4e, 0xfe, 0x4e, 0x02, 0x0c, 0x05, 0xd5, 0x00, 0x11, 0x00, 0x00, + 0x13, 0x23, 0x12, 0x13, 0x36, 0x35, 0x10, 0x03, 0x26, 0x27, 0x33, 0x16, + 0x13, 0x16, 0x15, 0x10, 0x03, 0x06, 0xbe, 0x70, 0xd2, 0x36, 0x10, 0xb4, + 0x2d, 0x37, 0x70, 0xbf, 0x59, 0x36, 0x89, 0x52, 0xfe, 0x4e, 0x01, 0x53, + 0x01, 0x8a, 0x74, 0x71, 0x01, 0x8e, 0x01, 0x7e, 0x60, 0x59, 0xfa, 0xfe, + 0xb9, 0xca, 0xba, 0xfe, 0xd1, 0xfe, 0xc2, 0xbe, 0x00, 0x01, 0x00, 0x52, + 0x03, 0x87, 0x02, 0xbe, 0x05, 0xd5, 0x00, 0x0e, 0x00, 0x00, 0x01, 0x33, + 0x07, 0x37, 0x17, 0x07, 0x17, 0x07, 0x27, 0x07, 0x27, 0x37, 0x27, 0x37, + 0x17, 0x01, 0x48, 0x81, 0x0b, 0xda, 0x26, 0xdd, 0x90, 0x69, 0x7f, 0x81, + 0x66, 0x8d, 0xdd, 0x27, 0xd9, 0x05, 0xd5, 0xe5, 0x4d, 0x78, 0x3e, 0xb6, + 0x4a, 0xbf, 0xbf, 0x4a, 0xb6, 0x3e, 0x78, 0x4d, 0x00, 0x01, 0x00, 0x66, + 0xff, 0xec, 0x04, 0x46, 0x03, 0xcb, 0x00, 0x0b, 0x00, 0x00, 0x01, 0x15, + 0x21, 0x11, 0x23, 0x11, 0x21, 0x35, 0x21, 0x11, 0x33, 0x11, 0x04, 0x46, + 0xfe, 0x58, 0x90, 0xfe, 0x58, 0x01, 0xa8, 0x90, 0x02, 0x23, 0x90, 0xfe, + 0x59, 0x01, 0xa7, 0x90, 0x01, 0xa8, 0xfe, 0x58, 0x00, 0x01, 0x00, 0xb2, + 0xfe, 0xd3, 0x01, 0x89, 0x00, 0xd5, 0x00, 0x0b, 0x00, 0x00, 0x37, 0x33, + 0x15, 0x10, 0x23, 0x35, 0x36, 0x37, 0x36, 0x3d, 0x01, 0x23, 0xb2, 0xd7, + 0xd7, 0x4c, 0x19, 0x16, 0x7b, 0xd5, 0xf6, 0xfe, 0xf4, 0x4e, 0x03, 0x2c, + 0x27, 0x64, 0x25, 0x00, 0x00, 0x01, 0x00, 0x5e, 0x01, 0xec, 0x02, 0x46, + 0x02, 0x7f, 0x00, 0x03, 0x00, 0x00, 0x01, 0x15, 0x21, 0x35, 0x02, 0x46, + 0xfe, 0x18, 0x02, 0x7f, 0x93, 0x93, 0x00, 0x01, 0x00, 0xb2, 0x00, 0x00, + 0x01, 0x87, 0x00, 0xd5, 0x00, 0x03, 0x00, 0x00, 0x25, 0x15, 0x23, 0x35, + 0x01, 0x87, 0xd5, 0xd5, 0xd5, 0xd5, 0x00, 0x01, 0xff, 0xf0, 0xff, 0xd7, + 0x02, 0x46, 0x05, 0xd5, 0x00, 0x03, 0x00, 0x00, 0x01, 0x33, 0x01, 0x23, + 0x01, 0xd5, 0x71, 0xfe, 0x1a, 0x70, 0x05, 0xd5, 0xfa, 0x02, 0x00, 0x02, + 0x00, 0x58, 0xff, 0xd1, 0x04, 0x0e, 0x05, 0xac, 0x00, 0x0f, 0x00, 0x19, + 0x00, 0x00, 0x13, 0x10, 0x25, 0x36, 0x33, 0x20, 0x13, 0x16, 0x15, 0x10, + 0x07, 0x06, 0x23, 0x20, 0x03, 0x26, 0x01, 0x20, 0x11, 0x10, 0x21, 0x32, + 0x13, 0x36, 0x35, 0x10, 0x58, 0x01, 0x24, 0x52, 0x65, 0x01, 0x7d, 0x4c, + 0x12, 0xd1, 0x6c, 0x9e, 0xfe, 0xcf, 0x6f, 0x3b, 0x01, 0xdb, 0xfe, 0xdd, + 0x01, 0x1f, 0xc7, 0x3f, 0x21, 0x02, 0xbe, 0x02, 0x43, 0x86, 0x25, 0xfe, + 0x10, 0x77, 0x93, 0xfe, 0x27, 0xae, 0x5a, 0x01, 0x44, 0xab, 0x03, 0x4c, + 0xfd, 0xb0, 0xfd, 0xaa, 0x01, 0x06, 0x86, 0xd1, 0x02, 0x49, 0x00, 0x01, + 0x00, 0xd1, 0x00, 0x00, 0x02, 0xc7, 0x05, 0xac, 0x00, 0x0a, 0x00, 0x00, + 0x01, 0x21, 0x35, 0x3e, 0x01, 0x37, 0x36, 0x37, 0x33, 0x11, 0x23, 0x02, + 0x12, 0xfe, 0xbf, 0xb3, 0x7f, 0x24, 0x12, 0x17, 0x77, 0xb5, 0x04, 0x0a, + 0x81, 0x16, 0x43, 0x50, 0x29, 0x4f, 0xfa, 0x54, 0x00, 0x01, 0x00, 0x46, + 0x00, 0x00, 0x04, 0x17, 0x05, 0xac, 0x00, 0x23, 0x00, 0x00, 0x13, 0x12, + 0x21, 0x32, 0x17, 0x16, 0x15, 0x10, 0x05, 0x06, 0x0f, 0x01, 0x06, 0x07, + 0x06, 0x07, 0x21, 0x15, 0x21, 0x36, 0x37, 0x36, 0x37, 0x36, 0x3f, 0x01, + 0x36, 0x35, 0x34, 0x27, 0x26, 0x23, 0x20, 0x03, 0x06, 0x07, 0x66, 0x0f, + 0x01, 0xd1, 0xd0, 0x82, 0x7f, 0xfe, 0xec, 0x0f, 0x11, 0xcc, 0xa8, 0x37, + 0x1d, 0x0b, 0x02, 0xfc, 0xfc, 0x3a, 0x0b, 0x48, 0x45, 0xa7, 0x28, 0x30, + 0xbd, 0xc4, 0x5b, 0x51, 0x73, 0xfe, 0xfe, 0x1f, 0x02, 0x01, 0x03, 0xb4, + 0x01, 0xf8, 0x79, 0x76, 0xbb, 0xff, 0x00, 0xa4, 0x09, 0x09, 0x6f, 0x5a, + 0x5e, 0x31, 0x42, 0xb2, 0xe0, 0x7d, 0x78, 0x6b, 0x1a, 0x1b, 0x6a, 0x70, + 0xaf, 0x7c, 0x4f, 0x45, 0xfe, 0xcd, 0x12, 0x15, 0x00, 0x01, 0x00, 0x42, + 0xff, 0xd1, 0x04, 0x0c, 0x05, 0xac, 0x00, 0x32, 0x00, 0x00, 0x01, 0x22, + 0x07, 0x06, 0x07, 0x23, 0x12, 0x25, 0x36, 0x33, 0x32, 0x17, 0x16, 0x15, + 0x14, 0x07, 0x16, 0x17, 0x16, 0x15, 0x14, 0x07, 0x06, 0x23, 0x20, 0x03, + 0x26, 0x27, 0x33, 0x16, 0x17, 0x16, 0x33, 0x32, 0x37, 0x36, 0x35, 0x34, + 0x27, 0x26, 0x23, 0x07, 0x23, 0x35, 0x36, 0x37, 0x36, 0x35, 0x34, 0x27, + 0x26, 0x02, 0x29, 0xd2, 0x32, 0x0f, 0x02, 0xb4, 0x07, 0x01, 0x1a, 0x4a, + 0x5c, 0xf3, 0x75, 0x52, 0xca, 0xa3, 0x34, 0x1e, 0x8e, 0x85, 0xd8, 0xfe, + 0xa3, 0x5f, 0x1c, 0x07, 0xb4, 0x0d, 0xa0, 0x38, 0x4c, 0xb3, 0x4d, 0x2d, + 0xff, 0x16, 0x18, 0x4c, 0x16, 0xc4, 0x4b, 0x55, 0x6b, 0x3e, 0x05, 0x0e, + 0xb3, 0x36, 0x4e, 0x01, 0x70, 0x50, 0x15, 0x8f, 0x65, 0x9b, 0xde, 0x4f, + 0x38, 0x77, 0x45, 0x66, 0xd6, 0x7c, 0x73, 0x01, 0x18, 0x52, 0x6b, 0xea, + 0x38, 0x13, 0x77, 0x46, 0x65, 0xf3, 0x14, 0x02, 0x02, 0x99, 0x03, 0x2b, + 0x32, 0x84, 0x93, 0x40, 0x24, 0x00, 0x00, 0x02, 0x00, 0x39, 0x00, 0x00, + 0x04, 0x29, 0x05, 0xac, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0x00, 0x01, 0x21, + 0x35, 0x01, 0x33, 0x11, 0x33, 0x15, 0x23, 0x11, 0x23, 0x19, 0x01, 0x01, + 0x02, 0x9e, 0xfd, 0x9b, 0x02, 0x94, 0x85, 0xd7, 0xd7, 0xb4, 0xfe, 0x39, + 0x01, 0x5c, 0xbf, 0x03, 0x91, 0xfc, 0x52, 0xa2, 0xfe, 0xa4, 0x01, 0xfe, + 0x02, 0x7b, 0xfd, 0x85, 0x00, 0x01, 0x00, 0x48, 0xff, 0xd1, 0x04, 0x1b, + 0x05, 0xac, 0x00, 0x26, 0x00, 0x00, 0x01, 0x15, 0x21, 0x03, 0x36, 0x37, + 0x32, 0x17, 0x16, 0x17, 0x14, 0x07, 0x06, 0x07, 0x06, 0x23, 0x20, 0x03, + 0x26, 0x27, 0x33, 0x16, 0x17, 0x16, 0x33, 0x32, 0x37, 0x36, 0x35, 0x34, + 0x27, 0x26, 0x23, 0x22, 0x07, 0x06, 0x07, 0x23, 0x13, 0x03, 0xcf, 0xfd, + 0xa4, 0x3a, 0x7c, 0x91, 0xcf, 0x82, 0x83, 0x01, 0x85, 0x82, 0xce, 0x0e, + 0x0f, 0xfe, 0x71, 0x4d, 0x02, 0x03, 0xb4, 0x3d, 0xd5, 0x0b, 0x0c, 0xb0, + 0x54, 0x39, 0x74, 0x51, 0x78, 0x71, 0x4d, 0x24, 0x28, 0xa6, 0x6c, 0x05, + 0xac, 0xb2, 0xfe, 0x6a, 0x56, 0x02, 0x84, 0x86, 0xd9, 0xe0, 0x91, 0x8c, + 0x0a, 0x01, 0x01, 0x7b, 0x06, 0x12, 0xe7, 0x0b, 0x01, 0x7c, 0x55, 0x7f, + 0xbe, 0x5d, 0x41, 0x3b, 0x1d, 0x2f, 0x03, 0x16, 0x00, 0x02, 0x00, 0x58, + 0xff, 0xd1, 0x04, 0x1b, 0x05, 0xac, 0x00, 0x22, 0x00, 0x32, 0x00, 0x00, + 0x13, 0x10, 0x25, 0x36, 0x33, 0x32, 0x17, 0x16, 0x17, 0x23, 0x26, 0x27, + 0x26, 0x23, 0x22, 0x07, 0x06, 0x07, 0x36, 0x33, 0x32, 0x17, 0x16, 0x17, + 0x14, 0x15, 0x14, 0x07, 0x06, 0x07, 0x06, 0x23, 0x20, 0x03, 0x26, 0x25, + 0x22, 0x07, 0x06, 0x15, 0x14, 0x17, 0x16, 0x33, 0x32, 0x37, 0x36, 0x35, + 0x34, 0x27, 0x26, 0x58, 0x01, 0x17, 0x69, 0x88, 0xc8, 0x72, 0x4d, 0x15, + 0xb4, 0x20, 0x76, 0x2b, 0x33, 0xc2, 0x51, 0x30, 0x01, 0x76, 0xd8, 0xbf, + 0x7c, 0x7e, 0x04, 0x7d, 0x7b, 0xc1, 0x11, 0x12, 0xfe, 0x42, 0x26, 0x03, + 0x01, 0xf0, 0x93, 0x55, 0x45, 0x5d, 0x53, 0x77, 0x81, 0x53, 0x4c, 0x6f, + 0x46, 0x02, 0x96, 0x02, 0x33, 0xa5, 0x3e, 0x8d, 0x5f, 0x8f, 0x9b, 0x2f, + 0x11, 0xdb, 0x84, 0xc8, 0xa2, 0x7c, 0x7e, 0xc7, 0x06, 0x06, 0xcd, 0x89, + 0x86, 0x0c, 0x01, 0x02, 0x56, 0x35, 0x8b, 0x65, 0x52, 0x7a, 0x93, 0x5e, + 0x54, 0x60, 0x59, 0x82, 0xb4, 0x53, 0x34, 0x00, 0x00, 0x01, 0x00, 0x5e, + 0x00, 0x00, 0x04, 0x29, 0x05, 0xac, 0x00, 0x0c, 0x00, 0x00, 0x01, 0x15, + 0x00, 0x03, 0x06, 0x07, 0x23, 0x12, 0x13, 0x12, 0x13, 0x21, 0x35, 0x04, + 0x29, 0xfe, 0xa5, 0x94, 0x3c, 0x23, 0xc0, 0x56, 0x8b, 0x7e, 0xf5, 0xfc, + 0xef, 0x05, 0xac, 0x98, 0xfe, 0x33, 0xfe, 0x3c, 0xba, 0xc9, 0x01, 0x7a, + 0x01, 0x20, 0x01, 0x03, 0x01, 0x5d, 0xb2, 0x00, 0x00, 0x03, 0x00, 0x4c, + 0xff, 0xd1, 0x04, 0x1b, 0x05, 0xac, 0x00, 0x1c, 0x00, 0x2c, 0x00, 0x3c, + 0x00, 0x00, 0x01, 0x16, 0x15, 0x14, 0x07, 0x06, 0x07, 0x22, 0x23, 0x22, + 0x27, 0x26, 0x27, 0x34, 0x37, 0x26, 0x27, 0x26, 0x35, 0x34, 0x36, 0x33, + 0x32, 0x17, 0x16, 0x15, 0x14, 0x07, 0x06, 0x01, 0x22, 0x07, 0x06, 0x15, + 0x14, 0x17, 0x16, 0x33, 0x32, 0x37, 0x36, 0x35, 0x34, 0x27, 0x26, 0x03, + 0x22, 0x07, 0x06, 0x15, 0x14, 0x17, 0x16, 0x33, 0x32, 0x37, 0x36, 0x35, + 0x34, 0x27, 0x26, 0x03, 0x21, 0xfa, 0x83, 0x85, 0xd5, 0x05, 0x06, 0xd7, + 0x88, 0x85, 0x03, 0xf8, 0x7e, 0x29, 0x1e, 0xf4, 0xc0, 0xc8, 0x7a, 0x72, + 0x3e, 0x2c, 0xfe, 0xb6, 0x8b, 0x44, 0x2d, 0x5e, 0x41, 0x5d, 0x8b, 0x45, + 0x2c, 0x63, 0x3f, 0x5a, 0x99, 0x54, 0x42, 0x63, 0x51, 0x77, 0x9f, 0x55, + 0x3f, 0x66, 0x51, 0x02, 0xfc, 0x77, 0xf4, 0xc2, 0x7c, 0x7e, 0x04, 0x7d, + 0x83, 0xc2, 0xf1, 0x78, 0x4f, 0x4d, 0x3a, 0x57, 0xaa, 0xd9, 0x73, 0x6b, + 0xa5, 0x78, 0x49, 0x34, 0x01, 0xd8, 0x59, 0x3a, 0x52, 0x7a, 0x3e, 0x2b, + 0x58, 0x39, 0x50, 0x82, 0x3e, 0x27, 0xfd, 0xa0, 0x62, 0x4c, 0x6f, 0x8c, + 0x51, 0x41, 0x65, 0x4b, 0x6e, 0x8e, 0x50, 0x3f, 0x00, 0x02, 0x00, 0x4e, + 0xff, 0xd1, 0x04, 0x12, 0x05, 0xac, 0x00, 0x22, 0x00, 0x32, 0x00, 0x00, + 0x01, 0x10, 0x05, 0x06, 0x23, 0x22, 0x27, 0x26, 0x27, 0x33, 0x16, 0x17, + 0x16, 0x33, 0x32, 0x37, 0x36, 0x37, 0x06, 0x07, 0x06, 0x23, 0x22, 0x27, + 0x26, 0x27, 0x34, 0x37, 0x36, 0x37, 0x36, 0x33, 0x20, 0x13, 0x16, 0x01, + 0x22, 0x07, 0x06, 0x15, 0x14, 0x17, 0x16, 0x33, 0x32, 0x37, 0x36, 0x35, + 0x34, 0x27, 0x26, 0x04, 0x12, 0xfe, 0xea, 0x6a, 0x8a, 0xc7, 0x72, 0x4d, + 0x15, 0xb4, 0x1e, 0x72, 0x2d, 0x36, 0xc2, 0x51, 0x30, 0x01, 0x6e, 0x8e, + 0x25, 0x2b, 0xc2, 0x7d, 0x7d, 0x02, 0x7d, 0x7a, 0xc1, 0x11, 0x12, 0x01, + 0x9e, 0x40, 0x0b, 0xfe, 0x15, 0x83, 0x53, 0x4b, 0x6e, 0x47, 0x66, 0x8f, + 0x55, 0x49, 0x5d, 0x53, 0x02, 0xe7, 0xfd, 0xd0, 0xa6, 0x40, 0x8c, 0x5f, + 0x90, 0x97, 0x31, 0x13, 0xdb, 0x84, 0xc8, 0x84, 0x18, 0x06, 0x7e, 0x86, + 0xc9, 0xcd, 0x89, 0x86, 0x0c, 0x01, 0xfe, 0x01, 0x5b, 0x01, 0xbc, 0x62, + 0x58, 0x83, 0xb3, 0x53, 0x35, 0x62, 0x53, 0x7c, 0x95, 0x5e, 0x54, 0x00, + 0x00, 0x02, 0x00, 0xe1, 0x00, 0x00, 0x01, 0xb6, 0x04, 0x31, 0x00, 0x03, + 0x00, 0x07, 0x00, 0x00, 0x25, 0x15, 0x23, 0x35, 0x13, 0x15, 0x23, 0x35, + 0x01, 0xb6, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0x03, 0x5c, 0xd5, 0xd5, + 0x00, 0x02, 0x00, 0xe1, 0xfe, 0xd3, 0x01, 0xb8, 0x04, 0x31, 0x00, 0x03, + 0x00, 0x0f, 0x00, 0x00, 0x01, 0x15, 0x23, 0x35, 0x03, 0x33, 0x15, 0x10, + 0x23, 0x35, 0x36, 0x37, 0x36, 0x3d, 0x01, 0x23, 0x01, 0xb8, 0xd5, 0x02, + 0xd7, 0xd7, 0x4d, 0x18, 0x16, 0x7b, 0x04, 0x31, 0xd5, 0xd5, 0xfc, 0xa4, + 0xf6, 0xfe, 0xf4, 0x4e, 0x03, 0x2c, 0x27, 0x64, 0x25, 0x00, 0x00, 0x01, + 0x00, 0x5c, 0xff, 0xee, 0x04, 0x46, 0x03, 0xcb, 0x00, 0x06, 0x00, 0x00, + 0x13, 0x35, 0x01, 0x15, 0x09, 0x01, 0x15, 0x5c, 0x03, 0xea, 0xfc, 0xd9, + 0x03, 0x27, 0x01, 0x96, 0x8d, 0x01, 0xa8, 0xa2, 0xfe, 0xb6, 0xfe, 0xb0, + 0xa1, 0x00, 0x00, 0x02, 0x00, 0x66, 0x00, 0xe3, 0x04, 0x46, 0x02, 0xd3, + 0x00, 0x03, 0x00, 0x07, 0x00, 0x00, 0x01, 0x15, 0x21, 0x35, 0x01, 0x15, + 0x21, 0x35, 0x04, 0x46, 0xfc, 0x20, 0x03, 0xe0, 0xfc, 0x20, 0x02, 0xd3, + 0x8f, 0x8f, 0xfe, 0xa0, 0x90, 0x90, 0x00, 0x01, 0x00, 0x66, 0xff, 0xee, + 0x04, 0x50, 0x03, 0xcb, 0x00, 0x06, 0x00, 0x00, 0x01, 0x15, 0x01, 0x35, + 0x09, 0x01, 0x35, 0x04, 0x50, 0xfc, 0x16, 0x03, 0x27, 0xfc, 0xd9, 0x02, + 0x23, 0x8d, 0xfe, 0x58, 0xa1, 0x01, 0x4a, 0x01, 0x50, 0xa2, 0x00, 0x02, + 0x00, 0x9e, 0x00, 0x00, 0x04, 0x12, 0x05, 0xee, 0x00, 0x23, 0x00, 0x27, + 0x00, 0x00, 0x01, 0x14, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x1d, 0x01, + 0x23, 0x35, 0x34, 0x37, 0x36, 0x37, 0x36, 0x37, 0x36, 0x35, 0x34, 0x27, + 0x26, 0x23, 0x22, 0x07, 0x06, 0x15, 0x23, 0x10, 0x25, 0x36, 0x33, 0x32, + 0x17, 0x16, 0x01, 0x15, 0x23, 0x35, 0x04, 0x12, 0x6e, 0x1a, 0x5b, 0x58, + 0x1c, 0x17, 0xb8, 0x66, 0x14, 0x5d, 0x61, 0x1f, 0x17, 0x5f, 0x44, 0x63, + 0xc4, 0x31, 0x13, 0xae, 0x01, 0x1f, 0x48, 0x59, 0xdc, 0x77, 0x61, 0xfe, + 0x92, 0xb8, 0x04, 0x64, 0x99, 0x7a, 0x1c, 0x51, 0x50, 0x3a, 0x2e, 0x34, + 0x60, 0x70, 0x78, 0x6f, 0x15, 0x58, 0x5a, 0x43, 0x33, 0x38, 0x7b, 0x41, + 0x2e, 0xa2, 0x3f, 0x5f, 0x01, 0x7c, 0x50, 0x14, 0x80, 0x68, 0xfb, 0xcf, + 0xd5, 0xd5, 0x00, 0x02, 0x00, 0x46, 0xfe, 0xdd, 0x07, 0x9c, 0x05, 0xee, + 0x00, 0x51, 0x00, 0x65, 0x00, 0x00, 0x01, 0x33, 0x03, 0x06, 0x15, 0x14, + 0x17, 0x16, 0x33, 0x32, 0x37, 0x36, 0x37, 0x36, 0x35, 0x34, 0x27, 0x26, + 0x27, 0x26, 0x23, 0x22, 0x07, 0x06, 0x07, 0x06, 0x15, 0x14, 0x17, 0x16, + 0x17, 0x16, 0x33, 0x32, 0x37, 0x17, 0x06, 0x23, 0x20, 0x27, 0x26, 0x27, + 0x26, 0x35, 0x10, 0x37, 0x36, 0x37, 0x36, 0x37, 0x36, 0x33, 0x20, 0x17, + 0x16, 0x17, 0x16, 0x15, 0x14, 0x07, 0x06, 0x07, 0x06, 0x23, 0x22, 0x27, + 0x06, 0x07, 0x06, 0x23, 0x22, 0x27, 0x26, 0x35, 0x34, 0x37, 0x36, 0x37, + 0x36, 0x33, 0x32, 0x17, 0x01, 0x32, 0x37, 0x36, 0x37, 0x36, 0x35, 0x34, + 0x27, 0x26, 0x23, 0x22, 0x07, 0x06, 0x07, 0x06, 0x15, 0x14, 0x17, 0x16, + 0x05, 0x52, 0xaa, 0xb8, 0x19, 0x2e, 0x1a, 0x1e, 0x6f, 0x62, 0x65, 0x1b, + 0x07, 0x92, 0x8c, 0xd9, 0x6a, 0x6f, 0xfd, 0xd4, 0xc1, 0x59, 0x3a, 0x9e, + 0x97, 0xf1, 0x69, 0x71, 0xa3, 0xe8, 0x39, 0xe6, 0xe9, 0xfe, 0xc9, 0xf6, + 0xd9, 0x60, 0x3d, 0x8d, 0x4c, 0x6a, 0xb6, 0xfc, 0x7e, 0x7a, 0x01, 0x1e, + 0xe9, 0xcd, 0x5b, 0x3a, 0x7b, 0x18, 0x1d, 0x9b, 0xe2, 0xc5, 0x1d, 0x75, + 0x7f, 0x17, 0x18, 0x8d, 0x5f, 0x61, 0x78, 0x6d, 0x9e, 0x45, 0x46, 0xac, + 0x4e, 0xfe, 0x7b, 0x79, 0x5f, 0x4e, 0x14, 0x05, 0x47, 0x33, 0x46, 0x72, + 0x5f, 0x61, 0x14, 0x04, 0x48, 0x39, 0x04, 0x02, 0xfd, 0xc3, 0x45, 0x22, + 0x2f, 0x1c, 0x0f, 0x6e, 0x72, 0x9f, 0x2c, 0x2c, 0xcf, 0xa9, 0xa1, 0x3e, + 0x1e, 0x9a, 0x8d, 0xd8, 0x8d, 0x95, 0xf3, 0xb9, 0xb0, 0x3d, 0x1b, 0x41, + 0x89, 0x56, 0xa1, 0x8e, 0xdf, 0x8c, 0x99, 0x01, 0x07, 0xee, 0x80, 0x60, + 0xa6, 0x42, 0x21, 0x99, 0x86, 0xce, 0x82, 0x8b, 0xcc, 0xb7, 0x25, 0x21, + 0xb6, 0x9d, 0x7f, 0x11, 0x03, 0x6a, 0x6c, 0xa1, 0xbc, 0x9f, 0x90, 0x35, + 0x17, 0xb2, 0xfd, 0x87, 0x99, 0x7e, 0x98, 0x23, 0x1e, 0x5b, 0x36, 0x27, + 0x6c, 0x6f, 0x9c, 0x20, 0x1f, 0x72, 0x48, 0x38, 0x00, 0x02, 0x00, 0x23, + 0x00, 0x00, 0x05, 0x39, 0x05, 0xd5, 0x00, 0x07, 0x00, 0x0a, 0x00, 0x00, + 0x01, 0x21, 0x03, 0x23, 0x01, 0x33, 0x01, 0x23, 0x0b, 0x02, 0x03, 0xcb, + 0xfd, 0xc0, 0x9d, 0xcb, 0x02, 0x14, 0xf6, 0x02, 0x0c, 0xd5, 0xce, 0xe6, + 0xf6, 0x01, 0xc1, 0xfe, 0x3f, 0x05, 0xd5, 0xfa, 0x2b, 0x02, 0x60, 0x02, + 0xa8, 0xfd, 0x58, 0x00, 0x00, 0x03, 0x00, 0xa2, 0x00, 0x00, 0x04, 0xfc, + 0x05, 0xd5, 0x00, 0x10, 0x00, 0x1b, 0x00, 0x26, 0x00, 0x00, 0x01, 0x14, + 0x07, 0x06, 0x23, 0x21, 0x11, 0x21, 0x20, 0x17, 0x16, 0x15, 0x14, 0x07, + 0x16, 0x17, 0x16, 0x01, 0x34, 0x27, 0x26, 0x23, 0x21, 0x11, 0x21, 0x32, + 0x37, 0x36, 0x03, 0x32, 0x37, 0x36, 0x35, 0x34, 0x27, 0x26, 0x23, 0x21, + 0x11, 0x04, 0xfc, 0x82, 0x77, 0xbf, 0xfd, 0x5e, 0x02, 0x5e, 0x01, 0x17, + 0x6d, 0x36, 0xce, 0xbd, 0x37, 0x1c, 0xff, 0x00, 0xd0, 0x29, 0x32, 0xfe, + 0x8f, 0x01, 0x71, 0xf7, 0x2b, 0x09, 0xcb, 0xb8, 0x3d, 0x17, 0x67, 0x42, + 0x63, 0xfe, 0x2f, 0x01, 0xaa, 0xc7, 0x76, 0x6d, 0x05, 0xd5, 0xb4, 0x59, + 0x6e, 0xe4, 0x62, 0x48, 0x85, 0x43, 0x02, 0x3b, 0xc9, 0x1f, 0x06, 0xfe, + 0x25, 0x9f, 0x23, 0xfc, 0x94, 0x8c, 0x35, 0x3f, 0x92, 0x44, 0x2c, 0xfd, + 0xfe, 0x00, 0x00, 0x01, 0x00, 0x62, 0xff, 0xd1, 0x05, 0x6a, 0x05, 0xee, + 0x00, 0x23, 0x00, 0x00, 0x13, 0x34, 0x37, 0x12, 0x25, 0x36, 0x33, 0x20, + 0x13, 0x16, 0x17, 0x23, 0x26, 0x27, 0x26, 0x23, 0x22, 0x07, 0x06, 0x11, + 0x10, 0x17, 0x16, 0x33, 0x32, 0x37, 0x36, 0x37, 0x33, 0x02, 0x21, 0x20, + 0x03, 0x26, 0x03, 0x26, 0x62, 0x65, 0x92, 0x01, 0x3a, 0x3a, 0x3f, 0x01, + 0xa2, 0x7c, 0x15, 0x0d, 0xc3, 0x2f, 0xb2, 0x4c, 0x66, 0xde, 0x7e, 0x79, + 0x91, 0x81, 0xd3, 0xec, 0x66, 0x36, 0x18, 0xc4, 0x43, 0xfd, 0xdd, 0xfe, + 0x8f, 0xb1, 0x76, 0x09, 0x01, 0x02, 0xd9, 0xfc, 0xc5, 0x01, 0x1d, 0x2e, + 0x09, 0xfe, 0x9b, 0x3c, 0x47, 0xe6, 0x3f, 0x1b, 0xad, 0xa5, 0xfe, 0xe7, + 0xfe, 0xd9, 0xa6, 0x95, 0xb2, 0x5e, 0x98, 0xfd, 0xb0, 0x01, 0x1d, 0xbc, + 0x01, 0x08, 0x14, 0x00, 0x00, 0x02, 0x00, 0xb6, 0x00, 0x00, 0x05, 0x56, + 0x05, 0xd5, 0x00, 0x09, 0x00, 0x14, 0x00, 0x00, 0x33, 0x11, 0x21, 0x20, + 0x00, 0x11, 0x10, 0x07, 0x06, 0x21, 0x25, 0x21, 0x20, 0x13, 0x36, 0x35, + 0x10, 0x25, 0x26, 0x23, 0x21, 0xb6, 0x02, 0x40, 0x01, 0x1b, 0x01, 0x45, + 0xaf, 0xa2, 0xfe, 0xf1, 0xfe, 0x7f, 0x01, 0x60, 0x01, 0x2f, 0x65, 0x2f, + 0xff, 0x00, 0x55, 0x6e, 0xfe, 0xa0, 0x05, 0xd5, 0xfe, 0x72, 0xfe, 0xa5, + 0xfe, 0x95, 0xc9, 0xb8, 0xa8, 0x01, 0x10, 0x7d, 0xb4, 0x01, 0xaf, 0x70, + 0x25, 0x00, 0x00, 0x01, 0x00, 0xb8, 0x00, 0x00, 0x04, 0xe7, 0x05, 0xd5, + 0x00, 0x0b, 0x00, 0x00, 0x01, 0x11, 0x21, 0x15, 0x21, 0x11, 0x21, 0x15, + 0x21, 0x11, 0x21, 0x15, 0x01, 0x77, 0x03, 0x70, 0xfb, 0xd1, 0x04, 0x0b, + 0xfc, 0xb4, 0x03, 0x2d, 0x02, 0xa8, 0xfe, 0x00, 0xa8, 0x05, 0xd5, 0xa8, + 0xfe, 0x23, 0xa8, 0x00, 0x00, 0x01, 0x00, 0xb8, 0x00, 0x00, 0x04, 0xa2, + 0x05, 0xd5, 0x00, 0x09, 0x00, 0x00, 0x01, 0x11, 0x23, 0x11, 0x21, 0x15, + 0x21, 0x11, 0x21, 0x15, 0x01, 0x77, 0xbf, 0x03, 0xea, 0xfc, 0xd5, 0x02, + 0xc8, 0x02, 0xa8, 0xfd, 0x58, 0x05, 0xd5, 0xa8, 0xfe, 0x23, 0xa8, 0x00, + 0x00, 0x01, 0x00, 0x5a, 0xff, 0xd1, 0x05, 0xac, 0x05, 0xee, 0x00, 0x31, + 0x00, 0x00, 0x01, 0x14, 0x17, 0x16, 0x05, 0x32, 0x33, 0x32, 0x37, 0x36, + 0x37, 0x36, 0x3d, 0x01, 0x21, 0x35, 0x21, 0x11, 0x23, 0x27, 0x06, 0x07, + 0x06, 0x23, 0x20, 0x27, 0x26, 0x03, 0x26, 0x35, 0x34, 0x37, 0x12, 0x25, + 0x36, 0x33, 0x20, 0x17, 0x16, 0x17, 0x23, 0x26, 0x27, 0x26, 0x23, 0x22, + 0x07, 0x06, 0x03, 0x14, 0x01, 0x19, 0x58, 0x88, 0x01, 0x28, 0x07, 0x07, + 0xc6, 0x84, 0x81, 0x09, 0x01, 0xfe, 0x39, 0x02, 0x6f, 0x79, 0x2f, 0xbe, + 0xfb, 0x22, 0x23, 0xfe, 0xf7, 0xb7, 0xb4, 0x2c, 0x0c, 0x61, 0x8d, 0x01, + 0x30, 0x52, 0x5d, 0x01, 0x35, 0xaa, 0x72, 0x20, 0xc3, 0x24, 0x95, 0x6a, + 0x8d, 0xe5, 0x8f, 0x93, 0x05, 0x02, 0xe5, 0xd1, 0xa0, 0xf5, 0x06, 0x7b, + 0x79, 0xbc, 0x0e, 0x0d, 0x29, 0xa7, 0xfc, 0xe4, 0xc6, 0xd3, 0x17, 0x03, + 0xab, 0xa7, 0x01, 0x17, 0x4e, 0x53, 0xea, 0xc0, 0x01, 0x19, 0x3f, 0x11, + 0xb2, 0x76, 0xb6, 0xaa, 0x52, 0x3a, 0x9d, 0xa2, 0xfe, 0xef, 0x08, 0x00, + 0x00, 0x01, 0x00, 0xaa, 0x00, 0x00, 0x05, 0x27, 0x05, 0xd5, 0x00, 0x0b, + 0x00, 0x00, 0x01, 0x21, 0x11, 0x23, 0x11, 0x33, 0x11, 0x21, 0x11, 0x33, + 0x11, 0x23, 0x04, 0x68, 0xfd, 0x00, 0xbe, 0xbe, 0x03, 0x00, 0xbf, 0xbf, + 0x02, 0xa8, 0xfd, 0x58, 0x05, 0xd5, 0xfd, 0x7b, 0x02, 0x85, 0xfa, 0x2b, + 0x00, 0x01, 0x00, 0xcd, 0x00, 0x00, 0x01, 0x8d, 0x05, 0xd5, 0x00, 0x03, + 0x00, 0x00, 0x01, 0x11, 0x23, 0x11, 0x01, 0x8d, 0xc0, 0x05, 0xd5, 0xfa, + 0x2b, 0x05, 0xd5, 0x00, 0x00, 0x01, 0x00, 0x23, 0xff, 0xd1, 0x03, 0x68, + 0x05, 0xd5, 0x00, 0x15, 0x00, 0x00, 0x25, 0x32, 0x37, 0x36, 0x35, 0x11, + 0x33, 0x11, 0x14, 0x07, 0x06, 0x23, 0x22, 0x27, 0x26, 0x3d, 0x01, 0x33, + 0x15, 0x14, 0x17, 0x16, 0x01, 0xc5, 0xa7, 0x2c, 0x12, 0xbe, 0x88, 0x6f, + 0xae, 0xd6, 0x71, 0x59, 0xc2, 0x80, 0x2a, 0x71, 0xa0, 0x42, 0x67, 0x04, + 0x1b, 0xfb, 0xa0, 0xd6, 0x72, 0x5c, 0x83, 0x67, 0xa1, 0x83, 0x60, 0xc6, + 0x36, 0x12, 0x00, 0x01, 0x00, 0xa2, 0x00, 0x00, 0x05, 0x44, 0x05, 0xd5, + 0x00, 0x0b, 0x00, 0x00, 0x01, 0x11, 0x23, 0x11, 0x33, 0x11, 0x01, 0x33, + 0x09, 0x01, 0x23, 0x01, 0x01, 0x60, 0xbe, 0xbe, 0x02, 0xe8, 0xf5, 0xfd, + 0xa0, 0x02, 0x67, 0xe2, 0xfd, 0xf2, 0x02, 0x0a, 0xfd, 0xf6, 0x05, 0xd5, + 0xfd, 0x0c, 0x02, 0xf4, 0xfd, 0xa0, 0xfc, 0x8b, 0x02, 0xfe, 0x00, 0x01, + 0x00, 0xa4, 0x00, 0x00, 0x04, 0x44, 0x05, 0xd5, 0x00, 0x05, 0x00, 0x00, + 0x01, 0x11, 0x21, 0x15, 0x21, 0x11, 0x01, 0x62, 0x02, 0xe2, 0xfc, 0x60, + 0x05, 0xd5, 0xfa, 0xd3, 0xa8, 0x05, 0xd5, 0x00, 0x00, 0x01, 0x00, 0x9a, + 0x00, 0x00, 0x06, 0x17, 0x05, 0xd5, 0x00, 0x0c, 0x00, 0x00, 0x21, 0x23, + 0x01, 0x11, 0x23, 0x11, 0x21, 0x09, 0x01, 0x21, 0x11, 0x23, 0x11, 0x03, + 0xbe, 0xc8, 0xfe, 0x58, 0xb4, 0x01, 0x08, 0x01, 0xba, 0x01, 0xb2, 0x01, + 0x09, 0xb5, 0x04, 0xe3, 0xfb, 0x1d, 0x05, 0xd5, 0xfa, 0xec, 0x05, 0x14, + 0xfa, 0x2b, 0x04, 0xe3, 0x00, 0x01, 0x00, 0x9c, 0x00, 0x00, 0x05, 0x2b, + 0x05, 0xd5, 0x00, 0x09, 0x00, 0x00, 0x01, 0x11, 0x23, 0x01, 0x11, 0x23, + 0x11, 0x33, 0x01, 0x11, 0x05, 0x2b, 0xd7, 0xfc, 0xfc, 0xb4, 0xce, 0x03, + 0x0d, 0x05, 0xd5, 0xfa, 0x2b, 0x04, 0xba, 0xfb, 0x46, 0x05, 0xd5, 0xfb, + 0x3b, 0x04, 0xc5, 0x00, 0x00, 0x02, 0x00, 0x4e, 0xff, 0xd1, 0x05, 0xf0, + 0x05, 0xee, 0x00, 0x16, 0x00, 0x2c, 0x00, 0x00, 0x01, 0x10, 0x00, 0x07, + 0x06, 0x23, 0x20, 0x27, 0x26, 0x03, 0x26, 0x35, 0x10, 0x37, 0x36, 0x25, + 0x36, 0x33, 0x20, 0x17, 0x16, 0x13, 0x16, 0x01, 0x22, 0x07, 0x06, 0x03, + 0x06, 0x15, 0x10, 0x17, 0x16, 0x17, 0x16, 0x33, 0x32, 0x37, 0x36, 0x37, + 0x36, 0x35, 0x10, 0x27, 0x26, 0x05, 0xf0, 0xfe, 0xd4, 0xfc, 0x51, 0x58, + 0xfe, 0xe0, 0xc1, 0xbd, 0x29, 0x0a, 0xa8, 0x9d, 0x01, 0x03, 0x41, 0x46, + 0x01, 0x2d, 0xc2, 0xbf, 0x20, 0x05, 0xfd, 0x2d, 0xe2, 0x90, 0x94, 0x0a, + 0x01, 0x8f, 0x88, 0xdd, 0x0f, 0x10, 0xde, 0x91, 0x93, 0x0f, 0x01, 0x94, + 0x96, 0x02, 0xd3, 0xfe, 0xe0, 0xfe, 0x66, 0x36, 0x12, 0xb0, 0xac, 0x01, + 0x20, 0x47, 0x4b, 0x01, 0x3f, 0xd3, 0xc6, 0x2c, 0x0b, 0xb9, 0xb8, 0xfe, + 0xc7, 0x37, 0x02, 0x39, 0x9a, 0x9f, 0xfe, 0xf7, 0x12, 0x13, 0xfe, 0xf0, + 0xa9, 0xa1, 0x0b, 0x01, 0x97, 0x98, 0xfc, 0x19, 0x1a, 0x01, 0x1e, 0xab, + 0xa3, 0x00, 0x00, 0x02, 0x00, 0xba, 0x00, 0x00, 0x04, 0xf0, 0x05, 0xd5, + 0x00, 0x0c, 0x00, 0x17, 0x00, 0x00, 0x01, 0x14, 0x07, 0x06, 0x23, 0x21, + 0x11, 0x23, 0x11, 0x21, 0x20, 0x17, 0x16, 0x01, 0x21, 0x32, 0x37, 0x36, + 0x35, 0x34, 0x27, 0x26, 0x23, 0x21, 0x04, 0xf0, 0x7e, 0x72, 0xb2, 0xfe, + 0x2b, 0xbf, 0x02, 0x69, 0x01, 0x17, 0x73, 0x43, 0xfc, 0x89, 0x01, 0x8d, + 0xb1, 0x4a, 0x28, 0x77, 0x46, 0x66, 0xfe, 0x73, 0x04, 0x1f, 0xc7, 0x75, + 0x6a, 0xfd, 0x87, 0x05, 0xd5, 0xb1, 0x69, 0xfe, 0x66, 0x71, 0x3e, 0x57, + 0x9b, 0x43, 0x28, 0x00, 0x00, 0x02, 0x00, 0x4e, 0xff, 0x87, 0x05, 0xf0, + 0x05, 0xee, 0x00, 0x18, 0x00, 0x33, 0x00, 0x00, 0x05, 0x07, 0x27, 0x06, + 0x23, 0x20, 0x27, 0x26, 0x03, 0x26, 0x35, 0x10, 0x37, 0x36, 0x25, 0x36, + 0x33, 0x20, 0x17, 0x16, 0x13, 0x16, 0x15, 0x10, 0x07, 0x01, 0x17, 0x36, + 0x11, 0x10, 0x27, 0x26, 0x27, 0x26, 0x23, 0x22, 0x07, 0x06, 0x03, 0x06, + 0x15, 0x10, 0x17, 0x16, 0x17, 0x16, 0x33, 0x32, 0x37, 0x36, 0x37, 0x27, + 0x05, 0xdd, 0x60, 0xd7, 0xb1, 0xd6, 0xfe, 0xe0, 0xc1, 0xbd, 0x29, 0x0a, + 0xa8, 0x9e, 0x01, 0x04, 0x41, 0x46, 0x01, 0x1f, 0xc2, 0xbb, 0x2a, 0x0b, + 0xd3, 0xfe, 0xbc, 0xb6, 0xa2, 0x8e, 0x87, 0xdc, 0x10, 0x11, 0xe4, 0x90, + 0x94, 0x0a, 0x01, 0x8f, 0x89, 0xdf, 0x0d, 0x0d, 0x75, 0x6f, 0x08, 0x09, + 0x97, 0x02, 0x77, 0xb2, 0x68, 0xb0, 0xac, 0x01, 0x20, 0x47, 0x4b, 0x01, + 0x3f, 0xd3, 0xc6, 0x2c, 0x0b, 0xaf, 0xaa, 0xfe, 0xe3, 0x48, 0x4d, 0xfe, + 0xa1, 0xe8, 0x01, 0x08, 0x96, 0xb6, 0x01, 0x1d, 0x01, 0x0f, 0xa8, 0xa1, + 0x0c, 0x01, 0x9b, 0x9f, 0xfe, 0xf6, 0x11, 0x12, 0xfe, 0xee, 0xa9, 0xa1, + 0x09, 0x01, 0x31, 0x04, 0x04, 0x7f, 0x00, 0x02, 0x00, 0xbe, 0x00, 0x00, + 0x05, 0x6f, 0x05, 0xd5, 0x00, 0x1d, 0x00, 0x28, 0x00, 0x00, 0x01, 0x16, + 0x17, 0x16, 0x07, 0x06, 0x17, 0x16, 0x17, 0x15, 0x23, 0x26, 0x3d, 0x01, + 0x34, 0x27, 0x26, 0x23, 0x21, 0x11, 0x23, 0x11, 0x21, 0x20, 0x17, 0x16, + 0x15, 0x14, 0x07, 0x06, 0x03, 0x34, 0x27, 0x26, 0x23, 0x21, 0x11, 0x21, + 0x32, 0x37, 0x36, 0x04, 0x4a, 0x9d, 0x23, 0x0e, 0x02, 0x02, 0x14, 0x15, + 0x32, 0xe8, 0x29, 0x7b, 0x32, 0x49, 0xfe, 0x15, 0xbf, 0x02, 0xb1, 0x01, + 0x28, 0x6a, 0x34, 0x67, 0x32, 0x2d, 0xa6, 0x35, 0x4a, 0xfe, 0x33, 0x01, + 0xcd, 0xdb, 0x36, 0x14, 0x02, 0xe1, 0x44, 0x91, 0x3d, 0x89, 0x81, 0x39, + 0x3a, 0x23, 0x2f, 0x60, 0x94, 0x85, 0xc3, 0x32, 0x15, 0xfd, 0x7d, 0x05, + 0xd5, 0xb6, 0x5a, 0x7f, 0xab, 0x62, 0x30, 0x01, 0x22, 0xc9, 0x2b, 0x0e, + 0xfd, 0xfe, 0x86, 0x32, 0x00, 0x01, 0x00, 0x62, 0xff, 0xd1, 0x04, 0xf8, + 0x05, 0xee, 0x00, 0x32, 0x00, 0x00, 0x25, 0x20, 0x37, 0x36, 0x35, 0x34, + 0x27, 0x26, 0x27, 0x25, 0x24, 0x11, 0x34, 0x37, 0x36, 0x33, 0x20, 0x17, + 0x16, 0x17, 0x23, 0x26, 0x27, 0x26, 0x23, 0x22, 0x07, 0x06, 0x15, 0x14, + 0x17, 0x16, 0x17, 0x05, 0x16, 0x17, 0x16, 0x15, 0x14, 0x07, 0x06, 0x21, + 0x20, 0x27, 0x26, 0x27, 0x33, 0x15, 0x14, 0x17, 0x16, 0x02, 0xbc, 0x01, + 0x22, 0x47, 0x14, 0xa5, 0x2f, 0x3e, 0xfe, 0x8d, 0xfe, 0xdb, 0x9e, 0x8d, + 0xe8, 0x01, 0x31, 0x8e, 0x63, 0x01, 0xb5, 0x02, 0xa5, 0x54, 0x79, 0xb2, + 0x5c, 0x40, 0x4b, 0x37, 0x74, 0x01, 0x76, 0xd2, 0x4a, 0x22, 0x62, 0x97, + 0xfe, 0xb1, 0xfe, 0xe4, 0x9c, 0x93, 0x03, 0xb5, 0x74, 0x6c, 0x79, 0xa8, + 0x2f, 0x37, 0x87, 0x47, 0x14, 0x10, 0x62, 0x4c, 0x01, 0x10, 0xd7, 0x76, + 0x6a, 0xa7, 0x74, 0xb4, 0xc1, 0x49, 0x25, 0x5e, 0x41, 0x5d, 0x62, 0x35, + 0x27, 0x1f, 0x65, 0x39, 0x9d, 0x49, 0x57, 0x9f, 0x75, 0xb5, 0x8d, 0x86, + 0xf7, 0x0a, 0xa7, 0x5c, 0x55, 0x00, 0x00, 0x01, 0x00, 0x2b, 0x00, 0x00, + 0x04, 0xbe, 0x05, 0xd5, 0x00, 0x07, 0x00, 0x00, 0x01, 0x11, 0x23, 0x11, + 0x21, 0x35, 0x21, 0x15, 0x02, 0xd5, 0xbe, 0xfe, 0x14, 0x04, 0x93, 0x05, + 0x2d, 0xfa, 0xd3, 0x05, 0x2d, 0xa8, 0xa8, 0x00, 0x00, 0x01, 0x00, 0xae, + 0xff, 0xd1, 0x05, 0x29, 0x05, 0xd5, 0x00, 0x15, 0x00, 0x00, 0x01, 0x33, + 0x11, 0x14, 0x07, 0x06, 0x21, 0x20, 0x27, 0x26, 0x35, 0x11, 0x33, 0x11, + 0x14, 0x17, 0x16, 0x33, 0x32, 0x37, 0x36, 0x35, 0x04, 0x6a, 0xbf, 0x9d, + 0x9d, 0xfe, 0xfa, 0xfe, 0xe0, 0x9a, 0x81, 0xbf, 0xae, 0x56, 0x78, 0xd9, + 0x66, 0x42, 0x05, 0xd5, 0xfb, 0xe7, 0xe1, 0x86, 0x84, 0x9a, 0x81, 0xd0, + 0x04, 0x19, 0xfb, 0xe7, 0xd0, 0x4d, 0x26, 0x7b, 0x50, 0x78, 0x00, 0x01, + 0x00, 0x3d, 0x00, 0x00, 0x05, 0x29, 0x05, 0xd5, 0x00, 0x06, 0x00, 0x00, + 0x21, 0x23, 0x01, 0x33, 0x09, 0x01, 0x33, 0x03, 0x23, 0xcd, 0xfd, 0xe7, + 0xcd, 0x01, 0xb7, 0x01, 0x9d, 0xcb, 0x05, 0xd5, 0xfb, 0x10, 0x04, 0xf0, + 0x00, 0x01, 0x00, 0x2d, 0x00, 0x00, 0x07, 0x6f, 0x05, 0xd5, 0x00, 0x0c, + 0x00, 0x00, 0x21, 0x23, 0x09, 0x01, 0x23, 0x01, 0x33, 0x09, 0x01, 0x33, + 0x09, 0x01, 0x33, 0x05, 0xf4, 0xd1, 0xfe, 0xa8, 0xfe, 0xb2, 0xd1, 0xfe, + 0x81, 0xd5, 0x01, 0x19, 0x01, 0x4b, 0xcd, 0x01, 0x54, 0x01, 0x13, 0xd5, + 0x04, 0xcb, 0xfb, 0x35, 0x05, 0xd5, 0xfb, 0x44, 0x04, 0xbc, 0xfb, 0x44, + 0x04, 0xbc, 0x00, 0x01, 0x00, 0x2d, 0x00, 0x00, 0x05, 0x31, 0x05, 0xd5, + 0x00, 0x0b, 0x00, 0x00, 0x09, 0x01, 0x23, 0x09, 0x01, 0x23, 0x09, 0x01, + 0x33, 0x09, 0x01, 0x33, 0x03, 0x21, 0x02, 0x10, 0xeb, 0xfe, 0x68, 0xfe, + 0x66, 0xe7, 0x02, 0x10, 0xfe, 0x11, 0xe7, 0x01, 0x7f, 0x01, 0x81, 0xe4, + 0x02, 0xfe, 0xfd, 0x02, 0x02, 0x6f, 0xfd, 0x91, 0x02, 0xfe, 0x02, 0xd7, + 0xfd, 0xb6, 0x02, 0x4a, 0x00, 0x01, 0x00, 0x1b, 0x00, 0x00, 0x05, 0x4a, + 0x05, 0xd5, 0x00, 0x08, 0x00, 0x00, 0x01, 0x11, 0x23, 0x11, 0x01, 0x33, + 0x09, 0x01, 0x33, 0x03, 0x19, 0xbf, 0xfd, 0xc1, 0xeb, 0x01, 0xb6, 0x01, + 0xaa, 0xe4, 0x02, 0x4a, 0xfd, 0xb6, 0x02, 0x4a, 0x03, 0x8b, 0xfd, 0x29, + 0x02, 0xd7, 0x00, 0x01, 0x00, 0x39, 0x00, 0x00, 0x04, 0xaa, 0x05, 0xd5, + 0x00, 0x09, 0x00, 0x00, 0x01, 0x15, 0x01, 0x21, 0x15, 0x21, 0x35, 0x01, + 0x21, 0x35, 0x04, 0xa6, 0xfc, 0x83, 0x03, 0x81, 0xfb, 0x8f, 0x03, 0x81, + 0xfc, 0xb9, 0x05, 0xd5, 0xac, 0xfb, 0x7f, 0xa8, 0xa8, 0x04, 0x85, 0xa8, + 0x00, 0x01, 0x00, 0x83, 0xfe, 0x4e, 0x02, 0x00, 0x05, 0xd5, 0x00, 0x07, + 0x00, 0x00, 0x01, 0x15, 0x23, 0x11, 0x33, 0x15, 0x21, 0x11, 0x02, 0x00, + 0xd3, 0xd3, 0xfe, 0x83, 0x05, 0xd5, 0x93, 0xf9, 0x9f, 0x93, 0x07, 0x87, + 0x00, 0x01, 0xff, 0xf0, 0xff, 0xd7, 0x02, 0x46, 0x05, 0xd5, 0x00, 0x03, + 0x00, 0x00, 0x13, 0x01, 0x23, 0x01, 0x60, 0x01, 0xe6, 0x71, 0xfe, 0x1b, + 0x05, 0xd5, 0xfa, 0x02, 0x05, 0xfe, 0x00, 0x01, 0x00, 0x2f, 0xfe, 0x4e, + 0x01, 0xac, 0x05, 0xd5, 0x00, 0x07, 0x00, 0x00, 0x13, 0x35, 0x33, 0x11, + 0x23, 0x35, 0x21, 0x11, 0x2f, 0xd3, 0xd3, 0x01, 0x7d, 0xfe, 0x4e, 0x93, + 0x06, 0x61, 0x93, 0xf8, 0x79, 0x00, 0x00, 0x01, 0x00, 0x5a, 0x02, 0xa2, + 0x03, 0x66, 0x05, 0xac, 0x00, 0x06, 0x00, 0x00, 0x01, 0x33, 0x01, 0x23, + 0x0b, 0x01, 0x23, 0x01, 0x93, 0x96, 0x01, 0x3d, 0x8d, 0xfa, 0xf8, 0x8d, + 0x05, 0xac, 0xfc, 0xf6, 0x02, 0x66, 0xfd, 0x9a, 0x00, 0x01, 0xff, 0xd3, + 0xfe, 0x98, 0x04, 0xa0, 0xfe, 0xfe, 0x00, 0x03, 0x00, 0x00, 0x01, 0x15, + 0x21, 0x35, 0x04, 0xa0, 0xfb, 0x33, 0xfe, 0xfe, 0x66, 0x66, 0x00, 0x01, + 0x00, 0x2d, 0x04, 0xbc, 0x01, 0xd9, 0x05, 0xec, 0x00, 0x03, 0x00, 0x00, + 0x01, 0x13, 0x23, 0x01, 0x01, 0x14, 0xc5, 0x7b, 0xfe, 0xcf, 0x05, 0xec, + 0xfe, 0xd0, 0x01, 0x30, 0x00, 0x02, 0x00, 0x56, 0xff, 0xd1, 0x04, 0x48, + 0x04, 0x50, 0x00, 0x31, 0x00, 0x40, 0x00, 0x00, 0x13, 0x12, 0x25, 0x36, + 0x33, 0x20, 0x17, 0x16, 0x15, 0x11, 0x14, 0x17, 0x16, 0x33, 0x32, 0x37, + 0x15, 0x06, 0x23, 0x22, 0x27, 0x26, 0x27, 0x06, 0x07, 0x06, 0x23, 0x22, + 0x27, 0x26, 0x35, 0x34, 0x37, 0x36, 0x37, 0x36, 0x37, 0x36, 0x37, 0x36, + 0x3d, 0x01, 0x34, 0x27, 0x26, 0x23, 0x22, 0x07, 0x06, 0x07, 0x13, 0x32, + 0x37, 0x36, 0x3d, 0x01, 0x06, 0x07, 0x06, 0x07, 0x06, 0x15, 0x14, 0x17, + 0x16, 0x85, 0x0a, 0x01, 0x43, 0x2e, 0x33, 0x01, 0x31, 0x4c, 0x17, 0x46, + 0x0a, 0x0c, 0x12, 0x13, 0x48, 0x2d, 0x7f, 0x23, 0x0a, 0x04, 0x90, 0x94, + 0x23, 0x26, 0xc0, 0x5e, 0x42, 0x77, 0x54, 0xc6, 0x25, 0x5e, 0x84, 0x20, + 0x0f, 0x82, 0x30, 0x3e, 0xb7, 0x31, 0x0f, 0x05, 0xaa, 0x9b, 0x61, 0x46, + 0x38, 0x98, 0x9c, 0x3c, 0x6d, 0x66, 0x2e, 0x02, 0xf4, 0x01, 0x30, 0x27, + 0x05, 0xae, 0x34, 0x43, 0xfd, 0x89, 0x48, 0x0a, 0x02, 0x04, 0x81, 0x12, + 0x5e, 0x1c, 0x24, 0x84, 0x15, 0x05, 0x74, 0x51, 0x78, 0xb0, 0x4c, 0x36, + 0x1d, 0x06, 0x0c, 0x10, 0x2d, 0x16, 0x23, 0x2d, 0x72, 0x22, 0x0c, 0x70, + 0x21, 0x2d, 0xfd, 0x72, 0x5d, 0x43, 0x4c, 0xc0, 0x19, 0x17, 0x17, 0x1b, + 0x31, 0x6d, 0x70, 0x29, 0x13, 0x00, 0x00, 0x02, 0x00, 0x6f, 0xff, 0xd1, + 0x04, 0x2f, 0x05, 0xd5, 0x00, 0x14, 0x00, 0x24, 0x00, 0x00, 0x13, 0x33, + 0x11, 0x36, 0x37, 0x36, 0x33, 0x32, 0x17, 0x16, 0x15, 0x10, 0x07, 0x06, + 0x23, 0x22, 0x27, 0x26, 0x27, 0x15, 0x23, 0x01, 0x22, 0x07, 0x06, 0x15, + 0x14, 0x17, 0x16, 0x33, 0x32, 0x37, 0x36, 0x35, 0x34, 0x27, 0x26, 0x6f, + 0xaa, 0x68, 0xb6, 0x16, 0x17, 0xdd, 0x7c, 0x72, 0x8a, 0x7e, 0xcb, 0xd5, + 0x77, 0x04, 0x04, 0x99, 0x01, 0xd5, 0x91, 0x53, 0x47, 0x6b, 0x4d, 0x73, + 0x90, 0x57, 0x52, 0x6e, 0x51, 0x05, 0xd5, 0xfd, 0xcb, 0x9f, 0x0f, 0x02, + 0xa3, 0x96, 0xfa, 0xfe, 0xe8, 0xa1, 0x93, 0xac, 0x06, 0x06, 0x89, 0x03, + 0xb0, 0x81, 0x6f, 0xb0, 0xdb, 0x72, 0x52, 0x78, 0x71, 0xb0, 0xdd, 0x73, + 0x56, 0x00, 0x00, 0x01, 0x00, 0x3f, 0xff, 0xd1, 0x03, 0xd1, 0x04, 0x50, + 0x00, 0x1f, 0x00, 0x00, 0x01, 0x23, 0x26, 0x27, 0x26, 0x23, 0x22, 0x07, + 0x06, 0x15, 0x14, 0x17, 0x16, 0x33, 0x32, 0x13, 0x33, 0x06, 0x07, 0x06, + 0x23, 0x22, 0x27, 0x26, 0x11, 0x10, 0x37, 0x36, 0x33, 0x32, 0x17, 0x16, + 0x03, 0xc5, 0xac, 0x18, 0x83, 0x2c, 0x37, 0xa5, 0x4d, 0x37, 0x7a, 0x49, + 0x6a, 0xdb, 0x2b, 0xac, 0x13, 0xa3, 0x69, 0x97, 0xde, 0x81, 0x7d, 0x8b, + 0x82, 0xd1, 0xf3, 0x6d, 0x3d, 0x02, 0xc9, 0xa9, 0x30, 0x10, 0x99, 0x6c, + 0xa7, 0xf0, 0x69, 0x3e, 0x01, 0x02, 0xf0, 0x6b, 0x45, 0x9d, 0x99, 0x00, + 0xff, 0x01, 0x14, 0xa1, 0x95, 0xa5, 0x5c, 0x00, 0x00, 0x02, 0x00, 0x35, + 0xff, 0xd1, 0x03, 0xf6, 0x05, 0xd5, 0x00, 0x14, 0x00, 0x24, 0x00, 0x00, + 0x01, 0x11, 0x23, 0x35, 0x06, 0x07, 0x06, 0x23, 0x22, 0x27, 0x26, 0x11, + 0x10, 0x37, 0x36, 0x33, 0x32, 0x17, 0x16, 0x17, 0x11, 0x01, 0x22, 0x07, + 0x06, 0x15, 0x14, 0x17, 0x16, 0x33, 0x32, 0x37, 0x36, 0x35, 0x34, 0x27, + 0x26, 0x03, 0xf6, 0x98, 0x62, 0x85, 0x32, 0x3d, 0xe2, 0x7e, 0x73, 0x87, + 0x7d, 0xc9, 0xd4, 0x6e, 0x04, 0x04, 0xfe, 0xd3, 0x93, 0x57, 0x4e, 0x6b, + 0x53, 0x7c, 0x8f, 0x53, 0x49, 0x6e, 0x4d, 0x05, 0xd5, 0xfa, 0x2b, 0x8d, + 0x8e, 0x21, 0x0d, 0xaa, 0x9b, 0x01, 0x05, 0x01, 0x0a, 0x9c, 0x8f, 0x9a, + 0x06, 0x06, 0x02, 0x2b, 0xfd, 0xdb, 0x7d, 0x71, 0xb2, 0xd2, 0x73, 0x5a, + 0x7d, 0x6f, 0xaf, 0xe2, 0x72, 0x50, 0x00, 0x02, 0x00, 0x52, 0xff, 0xd1, + 0x04, 0x1b, 0x04, 0x50, 0x00, 0x1d, 0x00, 0x28, 0x00, 0x00, 0x01, 0x21, + 0x16, 0x17, 0x16, 0x17, 0x16, 0x17, 0x16, 0x33, 0x32, 0x37, 0x33, 0x06, + 0x07, 0x06, 0x23, 0x22, 0x27, 0x26, 0x35, 0x10, 0x37, 0x36, 0x33, 0x32, + 0x17, 0x16, 0x17, 0x16, 0x05, 0x21, 0x36, 0x35, 0x34, 0x27, 0x26, 0x23, + 0x22, 0x07, 0x06, 0x04, 0x1b, 0xfc, 0xe9, 0x02, 0x28, 0x07, 0x08, 0x4f, + 0x90, 0x11, 0x12, 0xd2, 0x47, 0xac, 0x27, 0xa3, 0x6d, 0x94, 0xec, 0x83, + 0x78, 0x8d, 0x85, 0xd9, 0xc5, 0x83, 0x46, 0x25, 0x2b, 0xfc, 0xed, 0x02, + 0x5a, 0x02, 0x5a, 0x55, 0x7a, 0x95, 0x56, 0x3e, 0x01, 0xdf, 0x84, 0x48, + 0x0d, 0x0c, 0x7b, 0x0e, 0x02, 0xd7, 0xd3, 0x61, 0x41, 0xa6, 0x97, 0xfc, + 0x01, 0x11, 0x9f, 0x96, 0x7c, 0x42, 0x5d, 0x73, 0x58, 0x05, 0x08, 0x88, + 0x5c, 0x57, 0x74, 0x55, 0x00, 0x01, 0x00, 0x25, 0x00, 0x00, 0x02, 0x10, + 0x05, 0xdb, 0x00, 0x15, 0x00, 0x00, 0x01, 0x15, 0x23, 0x11, 0x23, 0x11, + 0x23, 0x35, 0x33, 0x35, 0x34, 0x37, 0x36, 0x33, 0x32, 0x17, 0x15, 0x26, + 0x23, 0x22, 0x1d, 0x01, 0x02, 0x10, 0xb2, 0xaa, 0x8f, 0x8f, 0x72, 0x3a, + 0x50, 0x2f, 0x31, 0x27, 0x14, 0x77, 0x04, 0x31, 0x8b, 0xfc, 0x5a, 0x03, + 0xa6, 0x8b, 0xb6, 0x9a, 0x3c, 0x1e, 0x0a, 0x8d, 0x02, 0x6d, 0xa8, 0x00, + 0x00, 0x02, 0x00, 0x3b, 0xfe, 0x42, 0x03, 0xe9, 0x04, 0x50, 0x00, 0x2a, + 0x00, 0x3a, 0x00, 0x00, 0x05, 0x22, 0x27, 0x26, 0x27, 0x26, 0x35, 0x10, + 0x37, 0x36, 0x37, 0x32, 0x33, 0x32, 0x17, 0x16, 0x17, 0x35, 0x33, 0x11, + 0x10, 0x07, 0x06, 0x07, 0x06, 0x23, 0x22, 0x27, 0x26, 0x27, 0x33, 0x16, + 0x17, 0x16, 0x33, 0x32, 0x37, 0x36, 0x3d, 0x01, 0x06, 0x07, 0x06, 0x03, + 0x22, 0x07, 0x06, 0x15, 0x14, 0x17, 0x16, 0x33, 0x32, 0x37, 0x36, 0x35, + 0x10, 0x27, 0x26, 0x01, 0xf6, 0xac, 0x79, 0x89, 0x0c, 0x01, 0x80, 0x78, + 0xbf, 0x09, 0x09, 0xc4, 0x7e, 0x03, 0x03, 0x9d, 0x45, 0x5a, 0xf0, 0x26, + 0x2a, 0xf3, 0x70, 0x3f, 0x0a, 0xae, 0x18, 0xa2, 0x22, 0x28, 0xbe, 0x41, + 0x2c, 0x64, 0x73, 0x32, 0x1b, 0x99, 0x50, 0x40, 0x78, 0x49, 0x6a, 0x9b, + 0x4d, 0x3a, 0x80, 0x44, 0x2f, 0x81, 0x91, 0xf8, 0x15, 0x16, 0x01, 0x07, + 0xa3, 0x98, 0x08, 0xb1, 0x04, 0x05, 0x9b, 0xfc, 0x7f, 0xfe, 0xe3, 0x87, + 0xb0, 0x16, 0x04, 0x89, 0x4c, 0x6e, 0x92, 0x1c, 0x06, 0x82, 0x58, 0xaf, + 0x37, 0x8d, 0x24, 0x0f, 0x03, 0xe1, 0x89, 0x6d, 0xac, 0xf4, 0x6c, 0x41, + 0x8d, 0x69, 0xa5, 0x01, 0x09, 0x68, 0x37, 0x00, 0x00, 0x01, 0x00, 0x8f, + 0x00, 0x00, 0x03, 0xe3, 0x05, 0xd5, 0x00, 0x17, 0x00, 0x00, 0x01, 0x34, + 0x27, 0x26, 0x23, 0x22, 0x07, 0x06, 0x15, 0x11, 0x23, 0x11, 0x33, 0x11, + 0x36, 0x37, 0x36, 0x33, 0x32, 0x17, 0x16, 0x15, 0x11, 0x23, 0x03, 0x39, + 0x79, 0x2f, 0x35, 0x91, 0x50, 0x42, 0xaa, 0xaa, 0x5e, 0x67, 0x3e, 0x55, + 0xbe, 0x59, 0x3b, 0xaa, 0x02, 0xe7, 0x90, 0x30, 0x13, 0x75, 0x61, 0x94, + 0xfd, 0xb0, 0x05, 0xd5, 0xfd, 0xc9, 0x7a, 0x23, 0x15, 0x70, 0x4a, 0x6b, + 0xfc, 0xd5, 0x00, 0x02, 0x00, 0x87, 0x00, 0x00, 0x01, 0x33, 0x05, 0xd5, + 0x00, 0x03, 0x00, 0x07, 0x00, 0x00, 0x01, 0x15, 0x23, 0x35, 0x13, 0x11, + 0x23, 0x11, 0x01, 0x33, 0xac, 0xac, 0xa9, 0x05, 0xd5, 0xd7, 0xd7, 0xfe, + 0x5c, 0xfb, 0xcf, 0x04, 0x31, 0x00, 0x00, 0x02, 0xff, 0xdb, 0xfe, 0x42, + 0x01, 0x39, 0x05, 0xd5, 0x00, 0x03, 0x00, 0x13, 0x00, 0x00, 0x01, 0x15, + 0x23, 0x35, 0x11, 0x33, 0x11, 0x14, 0x07, 0x06, 0x23, 0x22, 0x27, 0x35, + 0x16, 0x33, 0x32, 0x37, 0x36, 0x35, 0x01, 0x39, 0xaa, 0xaa, 0xce, 0x28, + 0x2f, 0x1a, 0x1f, 0x23, 0x06, 0x5d, 0x1c, 0x12, 0x05, 0xd5, 0xd7, 0xd7, + 0xfe, 0x5c, 0xfa, 0xf0, 0xb9, 0x20, 0x06, 0x06, 0x91, 0x02, 0x2e, 0x1f, + 0x40, 0x00, 0x00, 0x01, 0x00, 0x77, 0x00, 0x00, 0x04, 0x04, 0x05, 0xd5, + 0x00, 0x0b, 0x00, 0x00, 0x01, 0x11, 0x01, 0x33, 0x09, 0x01, 0x23, 0x01, + 0x07, 0x11, 0x23, 0x11, 0x01, 0x21, 0x01, 0xc6, 0xdc, 0xfe, 0x8b, 0x01, + 0xb6, 0xd3, 0xfe, 0x96, 0xa6, 0xaa, 0x05, 0xd5, 0xfc, 0x95, 0x01, 0xc7, + 0xfe, 0x8d, 0xfd, 0x42, 0x02, 0x46, 0xa4, 0xfe, 0x5e, 0x05, 0xd5, 0x00, + 0x00, 0x01, 0x00, 0x8b, 0x00, 0x00, 0x01, 0x37, 0x05, 0xd5, 0x00, 0x03, + 0x00, 0x00, 0x01, 0x11, 0x23, 0x11, 0x01, 0x37, 0xac, 0x05, 0xd5, 0xfa, + 0x2b, 0x05, 0xd5, 0x00, 0x00, 0x01, 0x00, 0x8f, 0x00, 0x00, 0x06, 0x19, + 0x04, 0x50, 0x00, 0x2a, 0x00, 0x00, 0x13, 0x33, 0x15, 0x36, 0x37, 0x36, + 0x33, 0x32, 0x17, 0x16, 0x17, 0x36, 0x37, 0x36, 0x33, 0x32, 0x17, 0x16, + 0x15, 0x11, 0x23, 0x11, 0x34, 0x27, 0x26, 0x23, 0x22, 0x07, 0x06, 0x15, + 0x11, 0x23, 0x11, 0x34, 0x27, 0x26, 0x23, 0x22, 0x07, 0x06, 0x15, 0x11, + 0x23, 0x8f, 0x9e, 0x5d, 0x72, 0x36, 0x45, 0x9d, 0x54, 0x1a, 0x16, 0x5e, + 0x62, 0x3a, 0x4f, 0xd4, 0x46, 0x1e, 0xac, 0x62, 0x2b, 0x3a, 0x6c, 0x4a, + 0x46, 0xac, 0x71, 0x25, 0x31, 0x6c, 0x4a, 0x46, 0xac, 0x04, 0x31, 0x97, + 0x83, 0x22, 0x11, 0x5e, 0x1e, 0x28, 0x71, 0x20, 0x13, 0x95, 0x40, 0x56, + 0xfc, 0xdb, 0x02, 0xe3, 0x8e, 0x32, 0x17, 0x56, 0x51, 0x71, 0xfd, 0x5e, + 0x02, 0xe3, 0x9c, 0x2c, 0x0f, 0x56, 0x51, 0x71, 0xfd, 0x5e, 0x00, 0x01, + 0x00, 0x8f, 0x00, 0x00, 0x03, 0xe5, 0x04, 0x50, 0x00, 0x17, 0x00, 0x00, + 0x13, 0x33, 0x15, 0x36, 0x37, 0x36, 0x33, 0x32, 0x17, 0x16, 0x15, 0x11, + 0x23, 0x11, 0x34, 0x27, 0x26, 0x23, 0x22, 0x07, 0x06, 0x15, 0x11, 0x23, + 0x8f, 0x9e, 0x5d, 0x7a, 0x3d, 0x50, 0xb6, 0x5d, 0x41, 0xaa, 0x5c, 0x35, + 0x4c, 0x91, 0x50, 0x42, 0xac, 0x04, 0x31, 0xb4, 0x94, 0x2a, 0x15, 0x6b, + 0x4b, 0x6f, 0xfc, 0xd5, 0x02, 0xe7, 0x7a, 0x38, 0x21, 0x75, 0x61, 0x94, + 0xfd, 0xb0, 0x00, 0x02, 0x00, 0x4a, 0xff, 0xd1, 0x04, 0x14, 0x04, 0x50, + 0x00, 0x0f, 0x00, 0x1f, 0x00, 0x00, 0x01, 0x20, 0x17, 0x16, 0x15, 0x10, + 0x07, 0x06, 0x23, 0x22, 0x27, 0x26, 0x35, 0x10, 0x37, 0x36, 0x17, 0x22, + 0x07, 0x06, 0x15, 0x14, 0x17, 0x16, 0x33, 0x32, 0x37, 0x36, 0x35, 0x34, + 0x27, 0x26, 0x02, 0x2d, 0x01, 0x08, 0x7f, 0x60, 0x9a, 0x7f, 0xcc, 0xf9, + 0x81, 0x6b, 0xa0, 0x7c, 0xc9, 0x9f, 0x53, 0x41, 0x77, 0x4c, 0x70, 0x9d, + 0x53, 0x43, 0x7e, 0x4a, 0x04, 0x50, 0xc3, 0x95, 0xf0, 0xfe, 0xde, 0x98, + 0x7d, 0xb4, 0x95, 0xf6, 0x01, 0x2f, 0x99, 0x78, 0x9e, 0x8a, 0x6d, 0xab, + 0xee, 0x6d, 0x46, 0x86, 0x6c, 0xa9, 0xfd, 0x6c, 0x3f, 0x00, 0x00, 0x02, + 0x00, 0x6f, 0xfe, 0x42, 0x04, 0x2f, 0x04, 0x50, 0x00, 0x11, 0x00, 0x21, + 0x00, 0x00, 0x13, 0x11, 0x33, 0x15, 0x36, 0x20, 0x17, 0x16, 0x11, 0x10, + 0x07, 0x06, 0x23, 0x22, 0x27, 0x26, 0x27, 0x11, 0x01, 0x22, 0x07, 0x06, + 0x15, 0x14, 0x17, 0x16, 0x33, 0x32, 0x37, 0x36, 0x35, 0x34, 0x27, 0x26, + 0x6f, 0x9d, 0x7a, 0x01, 0xb8, 0x7d, 0x74, 0x88, 0x7c, 0xc7, 0xa9, 0x72, + 0x17, 0x17, 0x01, 0x2b, 0x91, 0x53, 0x47, 0x6b, 0x4d, 0x73, 0x91, 0x57, + 0x4f, 0x6d, 0x51, 0xfe, 0x42, 0x05, 0xef, 0xa2, 0xc1, 0xa7, 0x9d, 0xfe, + 0xfa, 0xfe, 0xf5, 0x9c, 0x8e, 0x6d, 0x17, 0x1c, 0xfd, 0xd1, 0x05, 0x6e, + 0x81, 0x6f, 0xb0, 0xdb, 0x72, 0x52, 0x7a, 0x70, 0xaf, 0xdc, 0x73, 0x57, + 0x00, 0x02, 0x00, 0x35, 0xfe, 0x42, 0x03, 0xf6, 0x04, 0x50, 0x00, 0x14, + 0x00, 0x24, 0x00, 0x00, 0x01, 0x23, 0x11, 0x06, 0x07, 0x06, 0x23, 0x22, + 0x27, 0x26, 0x35, 0x10, 0x37, 0x36, 0x33, 0x32, 0x17, 0x16, 0x17, 0x35, + 0x33, 0x05, 0x22, 0x07, 0x06, 0x15, 0x14, 0x17, 0x16, 0x33, 0x32, 0x37, + 0x36, 0x35, 0x34, 0x27, 0x26, 0x03, 0xf6, 0xaa, 0x60, 0x9d, 0x25, 0x2a, + 0xdd, 0x7c, 0x72, 0x89, 0x7f, 0xcb, 0xc3, 0x7a, 0x0d, 0x0c, 0x98, 0xfe, + 0x2b, 0x94, 0x57, 0x4f, 0x6b, 0x53, 0x7c, 0x8f, 0x53, 0x49, 0x6d, 0x4d, + 0xfe, 0x42, 0x02, 0x39, 0x8d, 0x17, 0x06, 0xa3, 0x96, 0xfa, 0x01, 0x15, + 0xa2, 0x95, 0x8e, 0x0f, 0x11, 0x8f, 0x81, 0x7d, 0x71, 0xb2, 0xd2, 0x73, + 0x5a, 0x7d, 0x6e, 0xae, 0xe3, 0x73, 0x50, 0x00, 0x00, 0x01, 0x00, 0x8d, + 0x00, 0x00, 0x02, 0x91, 0x04, 0x50, 0x00, 0x0f, 0x00, 0x00, 0x01, 0x06, + 0x07, 0x06, 0x15, 0x11, 0x23, 0x11, 0x33, 0x15, 0x36, 0x37, 0x36, 0x33, + 0x32, 0x17, 0x02, 0x91, 0xb0, 0x4e, 0x5a, 0xac, 0x9e, 0x64, 0x5f, 0x2d, + 0x35, 0x17, 0x2a, 0x03, 0x9c, 0x03, 0x49, 0x55, 0xce, 0xfd, 0xd3, 0x04, + 0x31, 0xc2, 0xa2, 0x2b, 0x14, 0x06, 0x00, 0x01, 0x00, 0x46, 0xff, 0xd1, + 0x03, 0xac, 0x04, 0x50, 0x00, 0x32, 0x00, 0x00, 0x13, 0x1e, 0x01, 0x33, + 0x32, 0x37, 0x36, 0x35, 0x34, 0x27, 0x26, 0x2f, 0x01, 0x26, 0x27, 0x26, + 0x35, 0x34, 0x37, 0x36, 0x33, 0x32, 0x17, 0x16, 0x17, 0x23, 0x26, 0x27, + 0x26, 0x23, 0x22, 0x07, 0x06, 0x15, 0x14, 0x17, 0x16, 0x1f, 0x01, 0x16, + 0x17, 0x16, 0x15, 0x14, 0x07, 0x06, 0x23, 0x20, 0x27, 0x26, 0x27, 0xfa, + 0x0f, 0x7e, 0x79, 0x93, 0x42, 0x25, 0x4f, 0x22, 0x35, 0xa0, 0xd4, 0x48, + 0x38, 0x80, 0x6f, 0xad, 0xfc, 0x5c, 0x2c, 0x01, 0xb4, 0x05, 0xa3, 0x16, + 0x19, 0x8f, 0x3a, 0x1b, 0x65, 0x28, 0x3a, 0xa4, 0xd1, 0x3e, 0x20, 0x88, + 0x76, 0xbc, 0xfe, 0xa4, 0x41, 0x0d, 0x02, 0x01, 0x3f, 0x72, 0x5e, 0x4a, + 0x28, 0x36, 0x50, 0x27, 0x11, 0x0d, 0x27, 0x33, 0x52, 0x41, 0x6f, 0xa1, + 0x5a, 0x4d, 0x9a, 0x49, 0x67, 0x96, 0x13, 0x03, 0x4d, 0x25, 0x30, 0x50, + 0x2b, 0x10, 0x0e, 0x27, 0x32, 0x6d, 0x3a, 0x52, 0xa6, 0x5d, 0x51, 0xfc, + 0x34, 0x3e, 0x00, 0x01, 0x00, 0x1d, 0xff, 0xd1, 0x02, 0x08, 0x05, 0x58, + 0x00, 0x17, 0x00, 0x00, 0x01, 0x15, 0x23, 0x11, 0x14, 0x17, 0x16, 0x33, + 0x32, 0x37, 0x15, 0x06, 0x23, 0x22, 0x27, 0x26, 0x35, 0x11, 0x23, 0x35, + 0x33, 0x11, 0x33, 0x11, 0x02, 0x08, 0xb0, 0x1f, 0x14, 0x2b, 0x36, 0x1c, + 0x50, 0x3b, 0x9e, 0x26, 0x0b, 0x91, 0x91, 0xaa, 0x04, 0x31, 0x8b, 0xfd, + 0x21, 0x45, 0x11, 0x0b, 0x09, 0x90, 0x0e, 0x69, 0x1d, 0x24, 0x03, 0x2b, + 0x8b, 0x01, 0x27, 0xfe, 0xd9, 0x00, 0x00, 0x01, 0x00, 0x85, 0xff, 0xd1, + 0x03, 0xdb, 0x04, 0x31, 0x00, 0x17, 0x00, 0x00, 0x21, 0x23, 0x35, 0x06, + 0x07, 0x06, 0x23, 0x22, 0x27, 0x26, 0x35, 0x11, 0x33, 0x11, 0x14, 0x17, + 0x16, 0x33, 0x32, 0x37, 0x36, 0x35, 0x11, 0x33, 0x03, 0xdb, 0x99, 0x60, + 0x71, 0x41, 0x55, 0xb9, 0x5c, 0x41, 0xaa, 0x5c, 0x35, 0x4c, 0x93, 0x50, + 0x42, 0xaa, 0x96, 0x87, 0x28, 0x16, 0x6c, 0x4b, 0x6e, 0x03, 0x3b, 0xfd, + 0x08, 0x7a, 0x38, 0x21, 0x76, 0x61, 0x94, 0x02, 0x60, 0x00, 0x00, 0x01, + 0x00, 0x14, 0x00, 0x00, 0x03, 0xe3, 0x04, 0x31, 0x00, 0x06, 0x00, 0x00, + 0x21, 0x23, 0x01, 0x33, 0x09, 0x01, 0x33, 0x02, 0x48, 0xbb, 0xfe, 0x87, + 0xc1, 0x01, 0x1f, 0x01, 0x2f, 0xc0, 0x04, 0x31, 0xfc, 0x9a, 0x03, 0x66, + 0x00, 0x01, 0x00, 0x0c, 0x00, 0x00, 0x05, 0xaa, 0x04, 0x31, 0x00, 0x0c, + 0x00, 0x00, 0x21, 0x23, 0x0b, 0x01, 0x23, 0x01, 0x33, 0x1b, 0x01, 0x33, + 0x1b, 0x01, 0x33, 0x04, 0x6f, 0xc3, 0xd9, 0xcf, 0xc0, 0xfe, 0xc8, 0xbd, + 0xdb, 0xcd, 0xd1, 0xd2, 0xd5, 0xc1, 0x03, 0x4a, 0xfc, 0xb6, 0x04, 0x31, + 0xfc, 0xbd, 0x03, 0x43, 0xfc, 0xbd, 0x03, 0x43, 0x00, 0x01, 0x00, 0x23, + 0x00, 0x00, 0x03, 0xc9, 0x04, 0x31, 0x00, 0x0b, 0x00, 0x00, 0x09, 0x01, + 0x23, 0x09, 0x01, 0x23, 0x09, 0x01, 0x33, 0x09, 0x01, 0x33, 0x02, 0x56, + 0x01, 0x73, 0xc7, 0xfe, 0xf4, 0xfe, 0xef, 0xc2, 0x01, 0x7b, 0xfe, 0x99, + 0xc3, 0x01, 0x02, 0x01, 0x02, 0xc0, 0x02, 0x2b, 0xfd, 0xd5, 0x01, 0x9c, + 0xfe, 0x64, 0x02, 0x23, 0x02, 0x0e, 0xfe, 0x7b, 0x01, 0x85, 0x00, 0x01, + 0x00, 0x29, 0xfe, 0x42, 0x03, 0xd3, 0x04, 0x31, 0x00, 0x11, 0x00, 0x00, + 0x01, 0x33, 0x01, 0x06, 0x23, 0x22, 0x27, 0x35, 0x16, 0x33, 0x32, 0x37, + 0x36, 0x3f, 0x01, 0x01, 0x33, 0x01, 0x03, 0x1b, 0xb8, 0xfe, 0x23, 0x54, + 0xc1, 0x41, 0x31, 0x3b, 0x1f, 0x4c, 0x24, 0x0d, 0x0c, 0x41, 0xfe, 0x96, + 0xb6, 0x01, 0x13, 0x04, 0x31, 0xfa, 0xee, 0xdd, 0x1a, 0x9a, 0x0d, 0x36, + 0x15, 0x1e, 0xaa, 0x04, 0x35, 0xfc, 0xbd, 0x00, 0x00, 0x01, 0x00, 0x3f, + 0x00, 0x00, 0x03, 0xa8, 0x04, 0x31, 0x00, 0x09, 0x00, 0x00, 0x01, 0x15, + 0x01, 0x21, 0x15, 0x21, 0x35, 0x01, 0x21, 0x35, 0x03, 0x8b, 0xfd, 0x83, + 0x02, 0x9a, 0xfc, 0x97, 0x02, 0x82, 0xfd, 0xa9, 0x04, 0x31, 0x97, 0xfc, + 0xfc, 0x96, 0x9a, 0x03, 0x02, 0x95, 0x00, 0x01, 0x00, 0x58, 0xfe, 0x4e, + 0x02, 0x35, 0x05, 0xd5, 0x00, 0x2a, 0x00, 0x00, 0x01, 0x15, 0x23, 0x22, + 0x07, 0x06, 0x15, 0x11, 0x14, 0x07, 0x06, 0x07, 0x16, 0x17, 0x16, 0x15, + 0x11, 0x14, 0x17, 0x16, 0x3b, 0x01, 0x15, 0x23, 0x22, 0x27, 0x26, 0x35, + 0x11, 0x34, 0x27, 0x26, 0x27, 0x35, 0x36, 0x37, 0x36, 0x35, 0x11, 0x34, + 0x37, 0x36, 0x33, 0x02, 0x35, 0x1e, 0x55, 0x19, 0x13, 0x3d, 0x25, 0x46, + 0x8b, 0x18, 0x05, 0x25, 0x1b, 0x41, 0x1e, 0x5e, 0x8e, 0x36, 0x1b, 0x32, + 0x23, 0x4b, 0x5e, 0x22, 0x20, 0x6f, 0x30, 0x40, 0x05, 0xd5, 0x85, 0x26, + 0x1e, 0x45, 0xfe, 0x8d, 0xae, 0x4a, 0x2e, 0x1c, 0x41, 0xad, 0x27, 0x2e, + 0xfe, 0x8d, 0x5b, 0x1a, 0x14, 0x85, 0x7a, 0x3d, 0x55, 0x01, 0x56, 0xa6, + 0x3c, 0x2a, 0x0f, 0x8d, 0x13, 0x41, 0x3d, 0x8a, 0x01, 0x56, 0xb3, 0x3e, + 0x1b, 0x00, 0x00, 0x01, 0x00, 0xcd, 0xfe, 0x4e, 0x01, 0x48, 0x05, 0xd5, + 0x00, 0x03, 0x00, 0x00, 0x13, 0x33, 0x11, 0x23, 0xcd, 0x7b, 0x7b, 0x05, + 0xd5, 0xf8, 0x79, 0x00, 0x00, 0x01, 0x00, 0x3b, 0xfe, 0x4e, 0x02, 0x19, + 0x05, 0xd5, 0x00, 0x2a, 0x00, 0x00, 0x13, 0x35, 0x33, 0x32, 0x37, 0x36, + 0x35, 0x11, 0x34, 0x37, 0x36, 0x37, 0x26, 0x27, 0x26, 0x35, 0x11, 0x34, + 0x27, 0x26, 0x2b, 0x01, 0x35, 0x33, 0x32, 0x17, 0x16, 0x15, 0x11, 0x14, + 0x17, 0x16, 0x17, 0x15, 0x06, 0x07, 0x06, 0x15, 0x11, 0x14, 0x07, 0x06, + 0x23, 0x3b, 0x21, 0x56, 0x1a, 0x13, 0x79, 0x15, 0x1a, 0x8f, 0x15, 0x04, + 0x25, 0x1c, 0x42, 0x21, 0x61, 0x92, 0x35, 0x1a, 0x33, 0x22, 0x47, 0x5d, + 0x21, 0x1e, 0x71, 0x30, 0x40, 0xfe, 0x4e, 0x85, 0x26, 0x1d, 0x46, 0x01, + 0x73, 0xd4, 0x53, 0x0f, 0x0b, 0x43, 0xb7, 0x22, 0x28, 0x01, 0x73, 0x5b, + 0x1a, 0x14, 0x85, 0x7d, 0x3c, 0x53, 0xfe, 0xaa, 0xa7, 0x3c, 0x29, 0x0f, + 0x8d, 0x14, 0x44, 0x3e, 0x85, 0xfe, 0xaa, 0xb4, 0x3e, 0x1a, 0x00, 0x01, + 0x00, 0x9a, 0x02, 0x25, 0x04, 0x10, 0x03, 0x81, 0x00, 0x1f, 0x00, 0x00, + 0x01, 0x22, 0x07, 0x06, 0x15, 0x23, 0x36, 0x37, 0x36, 0x33, 0x32, 0x1f, + 0x01, 0x16, 0x33, 0x32, 0x37, 0x36, 0x3d, 0x01, 0x33, 0x15, 0x14, 0x07, + 0x06, 0x23, 0x22, 0x2f, 0x01, 0x26, 0x27, 0x26, 0x01, 0x73, 0x5e, 0x0e, + 0x01, 0x6c, 0x0c, 0x87, 0x22, 0x28, 0x39, 0x35, 0xf0, 0x39, 0x2d, 0x51, + 0x12, 0x06, 0x6c, 0x59, 0x35, 0x49, 0x4f, 0x57, 0xc8, 0x28, 0x28, 0x05, + 0x02, 0xf8, 0x95, 0x05, 0x06, 0xea, 0x32, 0x0d, 0x21, 0x8d, 0x23, 0x4d, + 0x1b, 0x27, 0x0b, 0x21, 0x96, 0x45, 0x29, 0x35, 0x81, 0x17, 0x05, 0x01, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x06, + 0x00, 0x04, 0x00, 0x00, 0xff, 0xff, 0x00, 0xfa, 0xfe, 0x5c, 0x01, 0xa6, + 0x04, 0x31, 0x10, 0x0f, 0x00, 0x05, 0x02, 0xa4, 0x04, 0x31, 0xc0, 0x00, + 0x00, 0x02, 0x00, 0x6a, 0xff, 0x0a, 0x04, 0x14, 0x05, 0x06, 0x00, 0x1e, + 0x00, 0x27, 0x00, 0x00, 0x01, 0x11, 0x36, 0x37, 0x33, 0x06, 0x07, 0x06, + 0x07, 0x15, 0x23, 0x35, 0x26, 0x27, 0x26, 0x35, 0x10, 0x37, 0x36, 0x37, + 0x35, 0x33, 0x15, 0x16, 0x17, 0x16, 0x17, 0x23, 0x26, 0x27, 0x26, 0x03, + 0x11, 0x06, 0x03, 0x06, 0x15, 0x14, 0x17, 0x16, 0x02, 0x7f, 0xc6, 0x23, + 0xac, 0x0c, 0x8f, 0x65, 0x95, 0x56, 0xe0, 0x78, 0x67, 0x96, 0x73, 0xb6, + 0x56, 0xef, 0x62, 0x32, 0x06, 0xac, 0x0f, 0x6b, 0x2c, 0x8d, 0xe7, 0x20, + 0x05, 0x80, 0x3b, 0x03, 0xb2, 0xfc, 0xbb, 0x15, 0xef, 0xd8, 0x71, 0x50, + 0x07, 0xc7, 0xc9, 0x14, 0xac, 0x93, 0xe0, 0x01, 0x1a, 0xa0, 0x7b, 0x13, + 0xb8, 0xb6, 0x11, 0xa9, 0x56, 0x77, 0x93, 0x3a, 0x18, 0xfc, 0xc3, 0x03, + 0x3f, 0x2b, 0xfe, 0xdf, 0x2c, 0x32, 0xef, 0x69, 0x31, 0x00, 0x00, 0x01, + 0x00, 0x35, 0xff, 0xd1, 0x04, 0x48, 0x05, 0xd5, 0x00, 0x41, 0x00, 0x00, + 0x01, 0x14, 0x1f, 0x01, 0x16, 0x17, 0x21, 0x15, 0x21, 0x16, 0x15, 0x14, + 0x07, 0x06, 0x07, 0x36, 0x33, 0x32, 0x17, 0x16, 0x33, 0x32, 0x37, 0x17, + 0x06, 0x07, 0x06, 0x23, 0x22, 0x27, 0x26, 0x27, 0x26, 0x23, 0x22, 0x07, + 0x27, 0x36, 0x37, 0x36, 0x35, 0x34, 0x27, 0x23, 0x35, 0x33, 0x26, 0x27, + 0x26, 0x35, 0x34, 0x37, 0x36, 0x37, 0x36, 0x33, 0x32, 0x17, 0x16, 0x17, + 0x23, 0x02, 0x21, 0x22, 0x07, 0x06, 0x01, 0x2d, 0x34, 0x3e, 0x04, 0x03, + 0x01, 0x48, 0xfe, 0xe9, 0x1f, 0x4f, 0x35, 0x6e, 0x79, 0x81, 0x45, 0x72, + 0x60, 0x33, 0x4f, 0x5b, 0x56, 0x67, 0x7b, 0x15, 0x16, 0x58, 0x82, 0x75, + 0x36, 0x17, 0x16, 0x6d, 0x72, 0x62, 0xb3, 0x31, 0x1c, 0x31, 0xe2, 0xa6, + 0x54, 0x0f, 0x09, 0x7a, 0x7a, 0xba, 0x1c, 0x1d, 0xf8, 0x74, 0x54, 0x03, + 0xb5, 0x09, 0xfe, 0xf3, 0x9a, 0x50, 0x37, 0x04, 0x2f, 0x56, 0x5d, 0x6d, + 0x06, 0x07, 0x71, 0x57, 0x3a, 0x5f, 0x6c, 0x49, 0x6f, 0x50, 0x23, 0x1d, + 0x3e, 0x87, 0x65, 0x0c, 0x02, 0x2c, 0x29, 0x06, 0x03, 0x4c, 0x87, 0x9a, + 0x6e, 0x3d, 0x43, 0x4c, 0x53, 0x71, 0x8b, 0x3a, 0x24, 0x34, 0xac, 0x7b, + 0x7a, 0x12, 0x03, 0xa1, 0x76, 0xc4, 0x01, 0x3b, 0x61, 0x43, 0x00, 0x02, + 0x00, 0x89, 0x01, 0x10, 0x03, 0xe9, 0x04, 0x68, 0x00, 0x1f, 0x00, 0x2f, + 0x00, 0x00, 0x01, 0x07, 0x27, 0x06, 0x23, 0x22, 0x27, 0x07, 0x27, 0x37, + 0x26, 0x27, 0x34, 0x35, 0x34, 0x37, 0x36, 0x37, 0x27, 0x37, 0x17, 0x36, + 0x33, 0x32, 0x17, 0x37, 0x17, 0x07, 0x16, 0x17, 0x14, 0x07, 0x01, 0x22, + 0x07, 0x06, 0x15, 0x14, 0x17, 0x16, 0x33, 0x32, 0x37, 0x36, 0x35, 0x34, + 0x27, 0x26, 0x03, 0xe1, 0x77, 0x6c, 0x52, 0x7b, 0x6e, 0x52, 0x69, 0x72, + 0x62, 0x3c, 0x06, 0x3f, 0x01, 0x02, 0x6f, 0x73, 0x71, 0x59, 0x6d, 0x77, + 0x52, 0x79, 0x74, 0x70, 0x32, 0x03, 0x3b, 0xfe, 0xbe, 0x62, 0x41, 0x36, + 0x4a, 0x3e, 0x53, 0x5e, 0x42, 0x39, 0x4b, 0x3d, 0x01, 0x85, 0x6e, 0x6c, + 0x3d, 0x33, 0x69, 0x75, 0x64, 0x52, 0x6e, 0x09, 0x08, 0x71, 0x5b, 0x03, + 0x02, 0x71, 0x6c, 0x70, 0x35, 0x39, 0x6c, 0x77, 0x70, 0x57, 0x68, 0x67, + 0x5f, 0x01, 0x9b, 0x49, 0x3d, 0x51, 0x5f, 0x40, 0x36, 0x47, 0x3d, 0x4f, + 0x64, 0x41, 0x34, 0x00, 0x00, 0x01, 0x00, 0x17, 0x00, 0x00, 0x04, 0x5c, + 0x05, 0xac, 0x00, 0x16, 0x00, 0x00, 0x01, 0x15, 0x21, 0x15, 0x21, 0x15, + 0x21, 0x11, 0x23, 0x11, 0x21, 0x35, 0x21, 0x35, 0x21, 0x35, 0x21, 0x01, + 0x33, 0x09, 0x01, 0x33, 0x01, 0x03, 0xf6, 0xfe, 0xa4, 0x01, 0x5c, 0xfe, + 0xa4, 0xb5, 0xfe, 0xa0, 0x01, 0x60, 0xfe, 0xa0, 0x01, 0x35, 0xfe, 0x5d, + 0xae, 0x01, 0x7a, 0x01, 0x6f, 0xae, 0xfe, 0x65, 0x02, 0xd5, 0x68, 0x9e, + 0x69, 0xfe, 0x9a, 0x01, 0x66, 0x69, 0x9e, 0x68, 0x02, 0xd7, 0xfd, 0x6d, + 0x02, 0x93, 0xfd, 0x29, 0x00, 0x02, 0x00, 0xcd, 0xfe, 0x4e, 0x01, 0x48, + 0x05, 0xd5, 0x00, 0x03, 0x00, 0x07, 0x00, 0x00, 0x13, 0x33, 0x11, 0x23, + 0x11, 0x33, 0x11, 0x23, 0xcd, 0x7b, 0x7b, 0x7b, 0x7b, 0x05, 0xd5, 0xfc, + 0xcb, 0xfe, 0xe3, 0xfc, 0xcb, 0x00, 0x00, 0x02, 0x00, 0x58, 0xfe, 0x4c, + 0x04, 0x0c, 0x05, 0xd5, 0x00, 0x45, 0x00, 0x55, 0x00, 0x00, 0x05, 0x14, + 0x17, 0x16, 0x33, 0x32, 0x37, 0x36, 0x35, 0x34, 0x27, 0x26, 0x27, 0x25, + 0x26, 0x27, 0x26, 0x35, 0x34, 0x37, 0x36, 0x37, 0x26, 0x27, 0x26, 0x35, + 0x34, 0x37, 0x36, 0x37, 0x32, 0x33, 0x32, 0x17, 0x16, 0x1d, 0x01, 0x23, + 0x35, 0x34, 0x27, 0x26, 0x23, 0x22, 0x07, 0x06, 0x15, 0x14, 0x17, 0x16, + 0x17, 0x05, 0x16, 0x17, 0x16, 0x15, 0x14, 0x07, 0x16, 0x17, 0x16, 0x15, + 0x14, 0x07, 0x06, 0x23, 0x22, 0x27, 0x26, 0x35, 0x13, 0x05, 0x36, 0x37, + 0x36, 0x35, 0x34, 0x27, 0x25, 0x06, 0x07, 0x06, 0x15, 0x14, 0x17, 0x16, + 0x01, 0x4c, 0x92, 0x1d, 0x22, 0x6d, 0x36, 0x21, 0x54, 0x0d, 0x0f, 0xfe, + 0xa3, 0x91, 0x20, 0x0b, 0x71, 0x2a, 0x3c, 0x4d, 0x0a, 0x03, 0x68, 0x6b, + 0x9d, 0x06, 0x05, 0xac, 0x63, 0x57, 0xac, 0x54, 0x30, 0x42, 0x60, 0x34, + 0x23, 0x3b, 0x17, 0x23, 0x01, 0x2b, 0x90, 0x2e, 0x21, 0xdf, 0x56, 0x11, + 0x06, 0x6c, 0x6d, 0xa6, 0xc0, 0x64, 0x59, 0xe3, 0x01, 0x54, 0x7b, 0x16, + 0x04, 0x95, 0xfe, 0xb6, 0x6b, 0x1a, 0x0c, 0x27, 0x1c, 0x1d, 0xcc, 0x26, + 0x08, 0x49, 0x2c, 0x3c, 0x5b, 0x44, 0x0a, 0x0b, 0xef, 0x65, 0x7d, 0x2c, + 0x34, 0x93, 0x5e, 0x22, 0x20, 0x5a, 0x4f, 0x13, 0x15, 0x89, 0x61, 0x64, + 0x04, 0x71, 0x63, 0x97, 0x39, 0x35, 0x7a, 0x37, 0x20, 0x44, 0x2d, 0x3d, + 0x3e, 0x34, 0x14, 0x17, 0xc1, 0x5c, 0x5c, 0x41, 0x5d, 0xec, 0x53, 0x62, + 0x4e, 0x1e, 0x24, 0x92, 0x62, 0x64, 0x75, 0x68, 0xba, 0x01, 0xf2, 0xfc, + 0x41, 0x69, 0x13, 0x14, 0x7e, 0x67, 0xe0, 0x47, 0x42, 0x20, 0x26, 0x48, + 0x2f, 0x22, 0x00, 0x02, 0x00, 0x3d, 0x04, 0xe5, 0x02, 0x5e, 0x05, 0xb8, + 0x00, 0x03, 0x00, 0x07, 0x00, 0x00, 0x01, 0x15, 0x23, 0x35, 0x21, 0x15, + 0x23, 0x35, 0x01, 0x12, 0xd5, 0x02, 0x21, 0xd5, 0x05, 0xb8, 0xd3, 0xd3, + 0xd3, 0xd3, 0x00, 0x03, 0xff, 0xe5, 0xff, 0xd3, 0x06, 0x02, 0x05, 0xf0, + 0x00, 0x21, 0x00, 0x39, 0x00, 0x51, 0x00, 0x00, 0x01, 0x06, 0x07, 0x06, + 0x23, 0x22, 0x27, 0x26, 0x35, 0x34, 0x37, 0x36, 0x33, 0x32, 0x17, 0x16, + 0x17, 0x23, 0x26, 0x27, 0x26, 0x23, 0x22, 0x07, 0x06, 0x15, 0x14, 0x17, + 0x16, 0x33, 0x32, 0x37, 0x36, 0x37, 0x03, 0x20, 0x17, 0x16, 0x17, 0x16, + 0x15, 0x10, 0x07, 0x06, 0x07, 0x06, 0x23, 0x22, 0x27, 0x26, 0x27, 0x26, + 0x35, 0x10, 0x37, 0x36, 0x37, 0x36, 0x17, 0x22, 0x07, 0x06, 0x07, 0x06, + 0x15, 0x14, 0x17, 0x16, 0x17, 0x16, 0x33, 0x32, 0x37, 0x36, 0x37, 0x36, + 0x35, 0x34, 0x27, 0x26, 0x27, 0x26, 0x04, 0x6a, 0x1c, 0x28, 0x5e, 0xc8, + 0xaf, 0x6f, 0x6f, 0x79, 0x6e, 0xac, 0xd7, 0x56, 0x18, 0x0f, 0x91, 0x24, + 0x4d, 0x24, 0x34, 0x84, 0x46, 0x36, 0x51, 0x46, 0x69, 0x96, 0x35, 0x08, + 0x06, 0xe5, 0x01, 0x04, 0xd0, 0xbf, 0x4f, 0x2c, 0x9f, 0x92, 0xe8, 0x7b, + 0x85, 0xf8, 0xcd, 0xbc, 0x52, 0x31, 0x9c, 0x8e, 0xe0, 0x7e, 0x87, 0xde, + 0xaf, 0xa4, 0x39, 0x19, 0x88, 0x7e, 0xc0, 0x58, 0x5d, 0xe7, 0xb1, 0xa6, + 0x37, 0x16, 0x8b, 0x80, 0xc5, 0x58, 0x02, 0x7f, 0x8a, 0x49, 0xaa, 0x83, + 0x84, 0xd2, 0xe2, 0x86, 0x79, 0xc4, 0x35, 0x44, 0x89, 0x24, 0x11, 0x78, + 0x5c, 0x8c, 0xa2, 0x64, 0x56, 0xbc, 0x1f, 0x23, 0x03, 0x71, 0x9c, 0x8e, + 0xdf, 0x7e, 0x86, 0xfe, 0xf6, 0xd1, 0xc0, 0x4c, 0x29, 0x99, 0x8c, 0xdb, + 0x83, 0x8b, 0x01, 0x04, 0xd0, 0xbf, 0x4f, 0x2d, 0x7f, 0x8d, 0x83, 0xcb, + 0x58, 0x5d, 0xdf, 0xb3, 0xa5, 0x3c, 0x1c, 0x8f, 0x86, 0xcf, 0x54, 0x59, + 0xe2, 0xb2, 0xa6, 0x3a, 0x1a, 0x00, 0x00, 0x03, 0x00, 0x4c, 0x02, 0x6d, + 0x02, 0xaa, 0x05, 0xf0, 0x00, 0x03, 0x00, 0x2d, 0x00, 0x3c, 0x00, 0x00, + 0x01, 0x15, 0x21, 0x35, 0x25, 0x15, 0x06, 0x23, 0x22, 0x27, 0x26, 0x27, + 0x06, 0x23, 0x22, 0x27, 0x26, 0x35, 0x34, 0x37, 0x36, 0x37, 0x36, 0x37, + 0x36, 0x3d, 0x01, 0x34, 0x27, 0x26, 0x23, 0x22, 0x07, 0x06, 0x07, 0x23, + 0x36, 0x37, 0x36, 0x33, 0x32, 0x15, 0x11, 0x14, 0x33, 0x32, 0x27, 0x06, + 0x07, 0x06, 0x07, 0x06, 0x15, 0x14, 0x17, 0x16, 0x33, 0x32, 0x37, 0x36, + 0x35, 0x02, 0x8f, 0xfd, 0xc9, 0x02, 0x52, 0x20, 0x22, 0x50, 0x17, 0x06, + 0x03, 0x65, 0x72, 0x81, 0x37, 0x1d, 0x4b, 0x4a, 0xac, 0x4f, 0x10, 0x06, + 0x54, 0x18, 0x1e, 0x53, 0x1d, 0x12, 0x09, 0x79, 0x05, 0xab, 0x29, 0x30, + 0xf9, 0x30, 0x09, 0xad, 0x25, 0x6a, 0x63, 0x20, 0x1d, 0x4e, 0x11, 0x15, + 0x5b, 0x39, 0x27, 0x02, 0xd5, 0x68, 0x68, 0xc3, 0x5b, 0x0c, 0x38, 0x0e, + 0x12, 0x58, 0x57, 0x2f, 0x3f, 0x6b, 0x30, 0x2f, 0x0d, 0x06, 0x1d, 0x0c, + 0x14, 0x1b, 0x44, 0x11, 0x05, 0x27, 0x19, 0x33, 0xb2, 0x24, 0x08, 0xc1, + 0xfe, 0x92, 0x30, 0xfa, 0x10, 0x0f, 0x0e, 0x1b, 0x1a, 0x2d, 0x4c, 0x10, + 0x04, 0x36, 0x25, 0x2c, 0x00, 0x02, 0x00, 0xc9, 0x00, 0xd9, 0x03, 0xa4, + 0x03, 0x81, 0x00, 0x06, 0x00, 0x0d, 0x00, 0x00, 0x13, 0x35, 0x25, 0x15, + 0x07, 0x17, 0x15, 0x37, 0x35, 0x25, 0x15, 0x07, 0x17, 0x15, 0xc9, 0x01, + 0x37, 0xd9, 0xd9, 0x6d, 0x01, 0x37, 0xd9, 0xd9, 0x01, 0xd1, 0xb6, 0xfa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xf8, 0xb6, 0xfa, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, + 0x00, 0x01, 0x00, 0x52, 0x00, 0xb0, 0x04, 0x5a, 0x03, 0x00, 0x00, 0x05, + 0x00, 0x00, 0x13, 0x21, 0x11, 0x23, 0x11, 0x21, 0x52, 0x04, 0x08, 0x8f, + 0xfc, 0x87, 0x03, 0x00, 0xfd, 0xb0, 0x01, 0xc1, 0x00, 0x01, 0x00, 0x5e, + 0x01, 0xec, 0x02, 0x46, 0x02, 0x7f, 0x00, 0x03, 0x00, 0x00, 0x01, 0x15, + 0x21, 0x35, 0x02, 0x46, 0xfe, 0x18, 0x02, 0x7f, 0x93, 0x93, 0x00, 0x04, + 0xff, 0xe5, 0xff, 0xd3, 0x06, 0x02, 0x05, 0xf0, 0x00, 0x1a, 0x00, 0x25, + 0x00, 0x3d, 0x00, 0x55, 0x00, 0x00, 0x01, 0x16, 0x1f, 0x01, 0x16, 0x17, + 0x15, 0x23, 0x26, 0x3f, 0x01, 0x34, 0x27, 0x26, 0x23, 0x21, 0x11, 0x23, + 0x11, 0x21, 0x20, 0x17, 0x16, 0x15, 0x14, 0x07, 0x06, 0x25, 0x21, 0x32, + 0x37, 0x36, 0x35, 0x34, 0x27, 0x26, 0x23, 0x21, 0x13, 0x20, 0x17, 0x16, + 0x17, 0x16, 0x15, 0x10, 0x07, 0x06, 0x07, 0x06, 0x23, 0x22, 0x27, 0x26, + 0x27, 0x26, 0x35, 0x10, 0x37, 0x36, 0x37, 0x36, 0x17, 0x22, 0x07, 0x06, + 0x07, 0x06, 0x15, 0x14, 0x17, 0x16, 0x17, 0x16, 0x33, 0x32, 0x37, 0x36, + 0x37, 0x36, 0x35, 0x34, 0x27, 0x26, 0x27, 0x26, 0x03, 0xf6, 0x55, 0x07, + 0x01, 0x05, 0x29, 0xa2, 0x22, 0x04, 0x02, 0x45, 0x1a, 0x25, 0xfe, 0xee, + 0x8f, 0x01, 0xa6, 0x01, 0x07, 0x17, 0x02, 0x2b, 0x17, 0xfe, 0x0b, 0x01, + 0x08, 0x7f, 0x16, 0x05, 0x4d, 0x1f, 0x2e, 0xfe, 0xf8, 0xc7, 0x01, 0x04, + 0xd0, 0xbf, 0x4f, 0x2c, 0x9f, 0x92, 0xe8, 0x7b, 0x85, 0xf8, 0xcd, 0xbc, + 0x52, 0x31, 0x9c, 0x8e, 0xe0, 0x7e, 0x87, 0xde, 0xaf, 0xa4, 0x39, 0x19, + 0x88, 0x7e, 0xc0, 0x58, 0x5d, 0xe7, 0xb1, 0xa6, 0x37, 0x16, 0x8b, 0x80, + 0xc5, 0x58, 0x02, 0xe1, 0x37, 0x6c, 0x8d, 0x41, 0x1e, 0x33, 0x51, 0x4c, + 0x52, 0x6b, 0x18, 0x09, 0xfe, 0x85, 0x03, 0x8f, 0xd5, 0x15, 0x18, 0x5a, + 0x35, 0x1c, 0x1a, 0x59, 0x15, 0x1b, 0x66, 0x19, 0x0a, 0x01, 0xc3, 0x9c, + 0x8e, 0xdf, 0x7e, 0x86, 0xfe, 0xf6, 0xd1, 0xc0, 0x4c, 0x29, 0x99, 0x8c, + 0xdb, 0x83, 0x8b, 0x01, 0x04, 0xd0, 0xbf, 0x4f, 0x2d, 0x7f, 0x8d, 0x83, + 0xcb, 0x58, 0x5d, 0xdf, 0xb3, 0xa5, 0x3c, 0x1c, 0x8f, 0x86, 0xcf, 0x54, + 0x59, 0xe2, 0xb2, 0xa6, 0x3a, 0x1a, 0x00, 0x01, 0x00, 0x39, 0x05, 0x0c, + 0x02, 0x6a, 0x05, 0x9c, 0x00, 0x03, 0x00, 0x00, 0x01, 0x15, 0x21, 0x35, + 0x02, 0x6a, 0xfd, 0xcf, 0x05, 0x9c, 0x90, 0x90, 0x00, 0x02, 0x01, 0x35, + 0x03, 0x10, 0x03, 0xa2, 0x05, 0x7d, 0x00, 0x0e, 0x00, 0x1e, 0x00, 0x00, + 0x01, 0x32, 0x17, 0x16, 0x15, 0x14, 0x07, 0x06, 0x23, 0x22, 0x27, 0x26, + 0x27, 0x34, 0x36, 0x17, 0x22, 0x07, 0x06, 0x15, 0x14, 0x17, 0x16, 0x33, + 0x32, 0x37, 0x36, 0x35, 0x34, 0x27, 0x26, 0x02, 0x6d, 0x80, 0x5b, 0x5a, + 0x5e, 0x5b, 0x81, 0x7c, 0x5a, 0x5b, 0x02, 0xb7, 0x81, 0x59, 0x3c, 0x2e, + 0x44, 0x36, 0x44, 0x5f, 0x3a, 0x2c, 0x45, 0x35, 0x05, 0x7d, 0x5b, 0x5b, + 0x7f, 0x84, 0x5b, 0x59, 0x5a, 0x60, 0x7e, 0x80, 0xb5, 0x75, 0x45, 0x36, + 0x45, 0x59, 0x3c, 0x2e, 0x47, 0x35, 0x47, 0x5a, 0x39, 0x2d, 0x00, 0x02, + 0x00, 0x66, 0xff, 0xe9, 0x04, 0x46, 0x04, 0xfc, 0x00, 0x0b, 0x00, 0x0f, + 0x00, 0x00, 0x01, 0x15, 0x21, 0x11, 0x23, 0x11, 0x21, 0x35, 0x21, 0x11, + 0x33, 0x11, 0x01, 0x15, 0x21, 0x35, 0x04, 0x46, 0xfe, 0x58, 0x90, 0xfe, + 0x58, 0x01, 0xa8, 0x90, 0x01, 0xa8, 0xfc, 0x20, 0x03, 0x54, 0x8f, 0xfe, + 0x58, 0x01, 0xa8, 0x8f, 0x01, 0xa8, 0xfe, 0x58, 0xfd, 0x25, 0x90, 0x90, + 0x00, 0x01, 0x00, 0x27, 0x02, 0x46, 0x02, 0x9c, 0x05, 0xac, 0x00, 0x25, + 0x00, 0x00, 0x01, 0x22, 0x07, 0x06, 0x07, 0x23, 0x36, 0x37, 0x36, 0x33, + 0x32, 0x17, 0x16, 0x15, 0x14, 0x07, 0x06, 0x0f, 0x01, 0x06, 0x07, 0x06, + 0x07, 0x21, 0x15, 0x21, 0x36, 0x37, 0x36, 0x37, 0x36, 0x3f, 0x01, 0x36, + 0x35, 0x34, 0x27, 0x26, 0x01, 0x6d, 0x8b, 0x1e, 0x07, 0x03, 0x7f, 0x08, + 0xc6, 0x2e, 0x3a, 0x96, 0x55, 0x40, 0xaa, 0x0d, 0x0e, 0x81, 0x59, 0x21, + 0x10, 0x0b, 0x01, 0xd5, 0xfd, 0x91, 0x08, 0x35, 0x34, 0x8f, 0x02, 0x02, + 0x77, 0x79, 0x43, 0x2f, 0x05, 0x3f, 0x85, 0x1c, 0x29, 0xfe, 0x2e, 0x0b, + 0x5b, 0x44, 0x63, 0x9b, 0x5f, 0x07, 0x07, 0x42, 0x2f, 0x36, 0x1a, 0x25, + 0x76, 0x96, 0x4e, 0x4c, 0x4d, 0x01, 0x01, 0x3f, 0x41, 0x61, 0x4e, 0x2d, + 0x1e, 0x00, 0x00, 0x01, 0x00, 0x21, 0x02, 0x29, 0x02, 0x93, 0x05, 0xac, + 0x00, 0x30, 0x00, 0x00, 0x01, 0x22, 0x07, 0x06, 0x15, 0x23, 0x12, 0x37, + 0x36, 0x33, 0x32, 0x17, 0x16, 0x15, 0x14, 0x07, 0x16, 0x15, 0x14, 0x07, + 0x06, 0x23, 0x22, 0x27, 0x26, 0x35, 0x33, 0x16, 0x17, 0x16, 0x33, 0x32, + 0x37, 0x36, 0x35, 0x34, 0x27, 0x26, 0x27, 0x26, 0x23, 0x35, 0x32, 0x37, + 0x36, 0x35, 0x34, 0x27, 0x26, 0x01, 0x5a, 0x7e, 0x1d, 0x0b, 0x81, 0x06, + 0xf4, 0x16, 0x17, 0xa7, 0x4a, 0x2c, 0x75, 0x91, 0x6d, 0x53, 0x7d, 0xc8, + 0x49, 0x24, 0x7f, 0x07, 0x61, 0x22, 0x30, 0x7d, 0x2a, 0x11, 0x3f, 0x18, + 0x1f, 0x1f, 0x69, 0x99, 0x2b, 0x1e, 0x4d, 0x22, 0x05, 0x3f, 0x5d, 0x23, + 0x36, 0x01, 0x0b, 0x16, 0x02, 0x65, 0x3c, 0x55, 0x78, 0x36, 0x31, 0x9c, + 0x8d, 0x4b, 0x3a, 0x87, 0x41, 0x5b, 0x8b, 0x20, 0x0b, 0x56, 0x22, 0x2d, + 0x51, 0x29, 0x10, 0x06, 0x04, 0x68, 0x26, 0x1b, 0x3c, 0x5a, 0x22, 0x0f, + 0x00, 0x01, 0x00, 0xbc, 0x04, 0xbc, 0x02, 0x68, 0x05, 0xec, 0x00, 0x03, + 0x00, 0x00, 0x01, 0x33, 0x01, 0x23, 0x01, 0x81, 0xe7, 0xfe, 0xcf, 0x7b, + 0x05, 0xec, 0xfe, 0xd0, 0x00, 0x01, 0x00, 0x85, 0xfe, 0x3d, 0x04, 0x5a, + 0x04, 0x31, 0x00, 0x20, 0x00, 0x00, 0x25, 0x15, 0x06, 0x23, 0x22, 0x27, + 0x26, 0x27, 0x06, 0x23, 0x22, 0x27, 0x11, 0x23, 0x11, 0x33, 0x11, 0x14, + 0x17, 0x16, 0x33, 0x32, 0x37, 0x36, 0x35, 0x11, 0x33, 0x11, 0x14, 0x17, + 0x16, 0x33, 0x32, 0x04, 0x5a, 0x44, 0x31, 0x8f, 0x1a, 0x06, 0x01, 0x78, + 0xd6, 0x6f, 0x49, 0xaa, 0xaa, 0x5a, 0x36, 0x4b, 0x93, 0x50, 0x42, 0xaa, + 0x4f, 0x06, 0x07, 0x11, 0x64, 0x81, 0x12, 0x74, 0x18, 0x1e, 0xaa, 0x35, + 0xfe, 0x37, 0x05, 0xf4, 0xfd, 0x08, 0x79, 0x39, 0x21, 0x76, 0x61, 0x94, + 0x02, 0x60, 0xfc, 0x83, 0x4d, 0x06, 0x01, 0x00, 0x00, 0x01, 0x00, 0x62, + 0xfe, 0x96, 0x04, 0x2d, 0x05, 0xd5, 0x00, 0x13, 0x00, 0x00, 0x01, 0x26, + 0x27, 0x26, 0x35, 0x34, 0x37, 0x36, 0x37, 0x36, 0x33, 0x21, 0x15, 0x23, + 0x11, 0x23, 0x11, 0x23, 0x11, 0x23, 0x02, 0x0a, 0xd1, 0x75, 0x62, 0x75, + 0x6f, 0xa8, 0x1f, 0x20, 0x02, 0x00, 0x75, 0x83, 0xa8, 0x83, 0x02, 0x12, + 0x0b, 0x98, 0x7f, 0xb5, 0xc1, 0x8b, 0x84, 0x18, 0x04, 0x83, 0xf9, 0x44, + 0x06, 0xbc, 0xf9, 0x44, 0x00, 0x01, 0x00, 0xb2, 0x02, 0x6a, 0x01, 0xb0, + 0x03, 0x6a, 0x00, 0x03, 0x00, 0x00, 0x01, 0x11, 0x23, 0x11, 0x01, 0xb0, + 0xfe, 0x03, 0x6a, 0xff, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x50, + 0xfe, 0x4a, 0x02, 0x4c, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x13, 0x17, + 0x16, 0x33, 0x32, 0x37, 0x36, 0x35, 0x34, 0x27, 0x26, 0x23, 0x22, 0x07, + 0x27, 0x37, 0x33, 0x07, 0x36, 0x33, 0x32, 0x17, 0x16, 0x15, 0x14, 0x07, + 0x06, 0x23, 0x22, 0x27, 0x26, 0x27, 0x7b, 0x6e, 0x2e, 0x2d, 0x43, 0x1e, + 0x0d, 0x3c, 0x0f, 0x13, 0x1f, 0x21, 0x18, 0x56, 0x4e, 0x2f, 0x1a, 0x1f, + 0x7a, 0x1f, 0x09, 0x67, 0x3d, 0x58, 0x50, 0x58, 0x22, 0x36, 0xfe, 0xe1, + 0x32, 0x11, 0x2e, 0x15, 0x19, 0x3a, 0x0e, 0x04, 0x11, 0x0f, 0xbc, 0x73, + 0x04, 0x54, 0x18, 0x1d, 0x6f, 0x31, 0x1e, 0x21, 0x0d, 0x17, 0x00, 0x01, + 0x00, 0x7d, 0x02, 0x46, 0x01, 0xc7, 0x05, 0xac, 0x00, 0x0b, 0x00, 0x00, + 0x01, 0x23, 0x35, 0x37, 0x3e, 0x01, 0x37, 0x36, 0x37, 0x33, 0x11, 0x23, + 0x01, 0x48, 0xcb, 0x1f, 0x6c, 0x4a, 0x18, 0x03, 0x02, 0x58, 0x7f, 0x04, + 0xa4, 0x5e, 0x02, 0x0a, 0x38, 0x56, 0x07, 0x09, 0xfc, 0x9a, 0x00, 0x03, + 0x00, 0x52, 0x02, 0x6d, 0x02, 0x98, 0x05, 0xf0, 0x00, 0x03, 0x00, 0x13, + 0x00, 0x23, 0x00, 0x00, 0x01, 0x15, 0x21, 0x35, 0x01, 0x32, 0x17, 0x16, + 0x15, 0x14, 0x07, 0x06, 0x23, 0x22, 0x27, 0x26, 0x35, 0x34, 0x37, 0x36, + 0x17, 0x22, 0x07, 0x06, 0x15, 0x14, 0x17, 0x16, 0x33, 0x32, 0x37, 0x36, + 0x35, 0x34, 0x27, 0x26, 0x02, 0x83, 0xfd, 0xe5, 0x01, 0x0d, 0xbb, 0x45, + 0x23, 0x79, 0x46, 0x64, 0xb1, 0x49, 0x29, 0x82, 0x43, 0x5e, 0x68, 0x2c, + 0x18, 0x56, 0x25, 0x31, 0x65, 0x2d, 0x1a, 0x5b, 0x23, 0x02, 0xd5, 0x68, + 0x68, 0x03, 0x1b, 0xa1, 0x51, 0x73, 0xcf, 0x58, 0x33, 0x92, 0x54, 0x7a, + 0xde, 0x55, 0x2c, 0x6b, 0x68, 0x3a, 0x52, 0xa2, 0x3a, 0x19, 0x64, 0x3a, + 0x53, 0xaa, 0x38, 0x16, 0x00, 0x02, 0x00, 0xc9, 0x00, 0xd9, 0x03, 0x9c, + 0x03, 0x81, 0x00, 0x06, 0x00, 0x0d, 0x00, 0x00, 0x01, 0x15, 0x05, 0x35, + 0x37, 0x27, 0x35, 0x05, 0x15, 0x05, 0x35, 0x37, 0x27, 0x35, 0x02, 0x04, + 0xfe, 0xc5, 0xdd, 0xdd, 0x02, 0xd3, 0xfe, 0xc4, 0xdd, 0xdd, 0x02, 0x89, + 0xb6, 0xfa, 0xaa, 0xaa, 0xaa, 0xaa, 0xf8, 0xb6, 0xfa, 0xaa, 0xaa, 0xaa, + 0xaa, 0x00, 0x00, 0x04, 0x00, 0x7d, 0xff, 0xd7, 0x06, 0xcb, 0x05, 0xac, + 0x00, 0x0b, 0x00, 0x0f, 0x00, 0x1a, 0x00, 0x1d, 0x00, 0x00, 0x01, 0x23, + 0x35, 0x37, 0x3e, 0x01, 0x37, 0x36, 0x37, 0x33, 0x11, 0x23, 0x01, 0x33, + 0x01, 0x23, 0x25, 0x21, 0x35, 0x01, 0x33, 0x11, 0x33, 0x15, 0x23, 0x15, + 0x23, 0x19, 0x01, 0x01, 0x01, 0x48, 0xcb, 0x1f, 0x6c, 0x4a, 0x18, 0x03, + 0x02, 0x58, 0x7f, 0x03, 0xdd, 0x77, 0xfc, 0x62, 0x77, 0x04, 0x3c, 0xfe, + 0x7f, 0x01, 0xa1, 0x5f, 0x89, 0x89, 0x7f, 0xfe, 0xf7, 0x04, 0xa4, 0x5e, + 0x02, 0x0a, 0x38, 0x56, 0x07, 0x09, 0xfc, 0x9a, 0x03, 0x66, 0xfa, 0x2b, + 0xf6, 0x79, 0x02, 0x20, 0xfd, 0xd3, 0x6c, 0xcd, 0x01, 0x39, 0x01, 0x5d, + 0xfe, 0xa3, 0x00, 0x03, 0x00, 0x7d, 0xff, 0xd7, 0x06, 0xc1, 0x05, 0xac, + 0x00, 0x0b, 0x00, 0x0f, 0x00, 0x35, 0x00, 0x00, 0x01, 0x23, 0x35, 0x37, + 0x3e, 0x01, 0x37, 0x36, 0x37, 0x33, 0x11, 0x23, 0x01, 0x33, 0x01, 0x23, + 0x01, 0x22, 0x07, 0x06, 0x07, 0x23, 0x12, 0x37, 0x36, 0x33, 0x32, 0x17, + 0x16, 0x15, 0x14, 0x07, 0x06, 0x0f, 0x01, 0x06, 0x07, 0x06, 0x07, 0x21, + 0x15, 0x21, 0x36, 0x37, 0x36, 0x37, 0x36, 0x3f, 0x01, 0x36, 0x35, 0x34, + 0x27, 0x26, 0x01, 0x48, 0xcb, 0x1f, 0x6c, 0x4a, 0x18, 0x03, 0x02, 0x58, + 0x7f, 0x03, 0xac, 0x76, 0xfc, 0x63, 0x77, 0x04, 0x3b, 0x8f, 0x1c, 0x05, + 0x02, 0x7f, 0x07, 0xd3, 0x2a, 0x32, 0x96, 0x55, 0x40, 0xaa, 0x0d, 0x0e, + 0x81, 0x59, 0x21, 0x10, 0x0c, 0x01, 0xd5, 0xfd, 0x92, 0x08, 0x35, 0x34, + 0x8d, 0x03, 0x03, 0x77, 0x78, 0x43, 0x2e, 0x04, 0xa4, 0x5e, 0x02, 0x0a, + 0x38, 0x56, 0x07, 0x09, 0xfc, 0x9a, 0x03, 0x66, 0xfa, 0x2b, 0x03, 0x23, + 0x8e, 0x1a, 0x23, 0x01, 0x06, 0x29, 0x08, 0x5b, 0x44, 0x63, 0x9a, 0x60, + 0x07, 0x07, 0x41, 0x2f, 0x36, 0x1a, 0x25, 0x77, 0x97, 0x4d, 0x4d, 0x4b, + 0x01, 0x02, 0x3f, 0x40, 0x62, 0x4e, 0x2d, 0x1f, 0x00, 0x04, 0x00, 0x21, + 0xff, 0xd7, 0x06, 0xcb, 0x05, 0xac, 0x00, 0x30, 0x00, 0x34, 0x00, 0x3f, + 0x00, 0x42, 0x00, 0x00, 0x01, 0x22, 0x07, 0x06, 0x15, 0x23, 0x12, 0x37, + 0x36, 0x33, 0x32, 0x17, 0x16, 0x15, 0x14, 0x07, 0x16, 0x15, 0x14, 0x07, + 0x06, 0x23, 0x22, 0x27, 0x26, 0x35, 0x33, 0x16, 0x17, 0x16, 0x33, 0x32, + 0x37, 0x36, 0x35, 0x34, 0x27, 0x26, 0x27, 0x26, 0x23, 0x35, 0x32, 0x37, + 0x36, 0x35, 0x34, 0x27, 0x26, 0x25, 0x33, 0x01, 0x23, 0x25, 0x21, 0x35, + 0x01, 0x33, 0x11, 0x33, 0x15, 0x23, 0x15, 0x23, 0x19, 0x01, 0x01, 0x01, + 0x5a, 0x7e, 0x1d, 0x0b, 0x81, 0x06, 0xf4, 0x16, 0x17, 0xa7, 0x4a, 0x2c, + 0x75, 0x91, 0x6d, 0x53, 0x7d, 0xc8, 0x49, 0x24, 0x7f, 0x07, 0x61, 0x22, + 0x30, 0x7d, 0x2a, 0x11, 0x3f, 0x18, 0x1f, 0x1f, 0x69, 0x99, 0x2b, 0x1e, + 0x4d, 0x22, 0x03, 0xb2, 0x77, 0xfc, 0x62, 0x76, 0x04, 0x27, 0xfe, 0x7f, + 0x01, 0xa1, 0x5f, 0x89, 0x89, 0x7f, 0xfe, 0xf7, 0x05, 0x3f, 0x5d, 0x23, + 0x36, 0x01, 0x0b, 0x16, 0x02, 0x65, 0x3c, 0x55, 0x78, 0x36, 0x31, 0x9c, + 0x8d, 0x4b, 0x3a, 0x87, 0x41, 0x5b, 0x8b, 0x20, 0x0b, 0x56, 0x22, 0x2d, + 0x51, 0x29, 0x10, 0x06, 0x04, 0x68, 0x26, 0x1b, 0x3c, 0x5a, 0x22, 0x0f, + 0x6d, 0xfa, 0x2b, 0xf6, 0x79, 0x02, 0x20, 0xfd, 0xd3, 0x6c, 0xcd, 0x01, + 0x39, 0x01, 0x5d, 0xfe, 0xa3, 0x00, 0xff, 0xff, 0x00, 0xc5, 0xfe, 0x43, + 0x04, 0x39, 0x04, 0x31, 0x10, 0x0f, 0x00, 0x23, 0x04, 0xd7, 0x04, 0x31, + 0xc0, 0x00, 0xff, 0xff, 0x00, 0x23, 0x00, 0x00, 0x05, 0x39, 0x05, 0xd5, + 0x10, 0x27, 0x00, 0xc6, 0x01, 0x58, 0x01, 0x98, 0x10, 0x06, 0x00, 0x25, + 0x00, 0x00, 0xff, 0xff, 0x00, 0x23, 0x00, 0x00, 0x05, 0x39, 0x05, 0xd5, + 0x10, 0x27, 0x00, 0xc5, 0x01, 0x75, 0x01, 0x98, 0x10, 0x06, 0x00, 0x25, + 0x00, 0x00, 0xff, 0xff, 0x00, 0x23, 0x00, 0x00, 0x05, 0x39, 0x05, 0xd5, + 0x10, 0x27, 0x00, 0xc4, 0x01, 0x60, 0x01, 0x98, 0x10, 0x06, 0x00, 0x25, + 0x00, 0x00, 0xff, 0xff, 0x00, 0x23, 0x00, 0x00, 0x05, 0x39, 0x05, 0xd5, + 0x10, 0x27, 0x00, 0xc8, 0x01, 0x66, 0x01, 0x81, 0x10, 0x06, 0x00, 0x25, + 0x00, 0x00, 0xff, 0xff, 0x00, 0x23, 0x00, 0x00, 0x05, 0x39, 0x07, 0x3b, + 0x10, 0x27, 0x00, 0x6b, 0x01, 0x64, 0x01, 0x83, 0x10, 0x06, 0x00, 0x25, + 0x00, 0x00, 0xff, 0xff, 0x00, 0x23, 0x00, 0x00, 0x05, 0x39, 0x05, 0xd5, + 0x10, 0x27, 0x00, 0xc7, 0x01, 0x58, 0x01, 0x98, 0x10, 0x06, 0x00, 0x25, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x17, 0x00, 0x00, 0x07, 0x9a, 0x05, 0xd5, + 0x00, 0x0f, 0x00, 0x13, 0x00, 0x00, 0x01, 0x21, 0x03, 0x23, 0x01, 0x21, + 0x15, 0x21, 0x11, 0x21, 0x15, 0x21, 0x11, 0x21, 0x15, 0x21, 0x19, 0x01, + 0x23, 0x01, 0x03, 0xbe, 0xfd, 0xda, 0xaf, 0xd2, 0x02, 0x64, 0x04, 0xfa, + 0xfd, 0x08, 0x02, 0xd1, 0xfd, 0x2f, 0x03, 0x1d, 0xfc, 0x24, 0xcc, 0xfe, + 0xe5, 0x01, 0xb6, 0xfe, 0x4a, 0x05, 0xd5, 0xa8, 0xfe, 0x23, 0xa8, 0xfe, + 0x00, 0xa8, 0x02, 0x5e, 0x02, 0xcf, 0xfd, 0x31, 0x00, 0x01, 0x00, 0x62, + 0xfe, 0x4a, 0x05, 0x6a, 0x05, 0xee, 0x00, 0x46, 0x00, 0x00, 0x25, 0x32, + 0x37, 0x36, 0x37, 0x33, 0x02, 0x05, 0x06, 0x23, 0x07, 0x36, 0x33, 0x32, + 0x17, 0x16, 0x15, 0x14, 0x07, 0x06, 0x23, 0x22, 0x27, 0x26, 0x27, 0x37, + 0x17, 0x16, 0x33, 0x32, 0x37, 0x36, 0x35, 0x34, 0x27, 0x26, 0x23, 0x22, + 0x07, 0x27, 0x37, 0x26, 0x27, 0x26, 0x27, 0x26, 0x27, 0x26, 0x35, 0x34, + 0x37, 0x12, 0x25, 0x36, 0x33, 0x20, 0x13, 0x16, 0x17, 0x23, 0x26, 0x27, + 0x26, 0x23, 0x22, 0x07, 0x06, 0x11, 0x10, 0x17, 0x16, 0x03, 0x06, 0xdf, + 0x66, 0x3f, 0x1c, 0xc4, 0x3f, 0xfe, 0x31, 0x29, 0x2b, 0x1a, 0x1a, 0x1f, + 0x7a, 0x1f, 0x09, 0x65, 0x3e, 0x59, 0x53, 0x5d, 0x21, 0x2f, 0x2b, 0x68, + 0x32, 0x2f, 0x43, 0x1e, 0x0d, 0x3c, 0x0f, 0x13, 0x1f, 0x21, 0x16, 0x3f, + 0x9a, 0x4f, 0x21, 0x27, 0xb7, 0x49, 0x27, 0x65, 0x92, 0x01, 0x3a, 0x3a, + 0x3f, 0x01, 0xa2, 0x7c, 0x15, 0x0d, 0xc3, 0x2d, 0xa3, 0x50, 0x71, 0xe0, + 0x7e, 0x79, 0x91, 0x82, 0x77, 0x9d, 0x61, 0xac, 0xfd, 0xe0, 0x2c, 0x04, + 0x44, 0x04, 0x54, 0x18, 0x1d, 0x6d, 0x32, 0x1f, 0x24, 0x0c, 0x15, 0x52, + 0x30, 0x13, 0x2e, 0x15, 0x19, 0x3a, 0x0e, 0x04, 0x11, 0x0f, 0x8d, 0x16, + 0x28, 0x11, 0x1b, 0x84, 0xfc, 0x86, 0x98, 0xfc, 0xc5, 0x01, 0x1d, 0x2e, + 0x09, 0xfe, 0x9b, 0x3c, 0x47, 0xdd, 0x42, 0x21, 0xae, 0xa5, 0xfe, 0xe8, + 0xfe, 0xd6, 0xa6, 0x94, 0xff, 0xff, 0x00, 0xb8, 0x00, 0x00, 0x04, 0xe7, + 0x05, 0xd5, 0x10, 0x27, 0x00, 0xc6, 0x01, 0x7b, 0x01, 0x98, 0x10, 0x06, + 0x00, 0x29, 0x00, 0x00, 0xff, 0xff, 0x00, 0xb8, 0x00, 0x00, 0x04, 0xe7, + 0x05, 0xd5, 0x10, 0x27, 0x00, 0xc5, 0x01, 0x6d, 0x01, 0x98, 0x10, 0x06, + 0x00, 0x29, 0x00, 0x00, 0xff, 0xff, 0x00, 0xb8, 0x00, 0x00, 0x04, 0xe7, + 0x05, 0xd5, 0x10, 0x27, 0x00, 0xc4, 0x01, 0x73, 0x01, 0x96, 0x10, 0x06, + 0x00, 0x29, 0x00, 0x00, 0xff, 0xff, 0x00, 0xb8, 0x00, 0x00, 0x04, 0xe7, + 0x07, 0x3b, 0x10, 0x27, 0x00, 0x6b, 0x01, 0x71, 0x01, 0x83, 0x10, 0x06, + 0x00, 0x29, 0x00, 0x00, 0xff, 0xff, 0x00, 0xcd, 0x00, 0x00, 0x01, 0x8d, + 0x05, 0xd5, 0x10, 0x27, 0x00, 0xc6, 0xff, 0xd3, 0x01, 0x98, 0x10, 0x06, + 0x00, 0x2d, 0x00, 0x00, 0xff, 0xff, 0x00, 0xcd, 0x00, 0x00, 0x01, 0x8d, + 0x05, 0xd5, 0x10, 0x27, 0x00, 0xc5, 0xff, 0xd5, 0x01, 0x98, 0x10, 0x06, + 0x00, 0x2d, 0x00, 0x00, 0xff, 0xff, 0x00, 0xcd, 0x00, 0x00, 0x01, 0x8d, + 0x05, 0xd5, 0x10, 0x27, 0x00, 0xc4, 0xff, 0xd5, 0x01, 0x98, 0x10, 0x06, + 0x00, 0x2d, 0x00, 0x00, 0xff, 0xff, 0x00, 0x1c, 0x00, 0x00, 0x02, 0x3d, + 0x07, 0x3b, 0x10, 0x27, 0x00, 0x6b, 0xff, 0xdf, 0x01, 0x83, 0x10, 0x06, + 0x00, 0x2d, 0x00, 0x00, 0x00, 0x02, 0x00, 0x29, 0x00, 0x00, 0x05, 0x56, + 0x05, 0xd5, 0x00, 0x0e, 0x00, 0x1d, 0x00, 0x00, 0x13, 0x23, 0x35, 0x33, + 0x11, 0x21, 0x20, 0x17, 0x16, 0x11, 0x10, 0x07, 0x06, 0x29, 0x01, 0x13, + 0x11, 0x21, 0x20, 0x13, 0x36, 0x35, 0x10, 0x27, 0x26, 0x23, 0x21, 0x11, + 0x21, 0x15, 0xb6, 0x8d, 0x8d, 0x02, 0x42, 0x01, 0x19, 0xa2, 0xa3, 0xb0, + 0xa1, 0xfe, 0xf3, 0xfd, 0xbe, 0xbf, 0x01, 0x62, 0x01, 0x37, 0x61, 0x29, + 0xf2, 0x58, 0x77, 0xfe, 0x9e, 0x01, 0x5e, 0x02, 0xb6, 0x89, 0x02, 0x96, + 0xc6, 0xc7, 0xfe, 0xa4, 0xfe, 0x93, 0xc9, 0xb6, 0x02, 0xb6, 0xfd, 0xf2, + 0x01, 0x20, 0x7a, 0xaa, 0x01, 0xa0, 0x76, 0x2b, 0xfe, 0x12, 0x89, 0x00, + 0xff, 0xff, 0x00, 0x9c, 0x00, 0x00, 0x05, 0x2b, 0x05, 0xd5, 0x10, 0x27, + 0x00, 0xc8, 0x01, 0x98, 0x01, 0x81, 0x10, 0x06, 0x00, 0x32, 0x00, 0x00, + 0xff, 0xff, 0x00, 0x4e, 0xff, 0xd1, 0x05, 0xf0, 0x05, 0xee, 0x10, 0x27, + 0x00, 0xc6, 0x01, 0xcb, 0x01, 0x98, 0x10, 0x06, 0x00, 0x33, 0x00, 0x00, + 0xff, 0xff, 0x00, 0x4e, 0xff, 0xd1, 0x05, 0xf0, 0x05, 0xee, 0x10, 0x27, + 0x00, 0xc5, 0x01, 0xd5, 0x01, 0x98, 0x10, 0x06, 0x00, 0x33, 0x00, 0x00, + 0xff, 0xff, 0x00, 0x4e, 0xff, 0xd1, 0x05, 0xf0, 0x05, 0xee, 0x10, 0x27, + 0x00, 0xc4, 0x01, 0xd1, 0x01, 0x98, 0x10, 0x06, 0x00, 0x33, 0x00, 0x00, + 0xff, 0xff, 0x00, 0x4e, 0xff, 0xd1, 0x05, 0xf0, 0x05, 0xee, 0x10, 0x27, + 0x00, 0xc8, 0x01, 0xd1, 0x01, 0x81, 0x10, 0x06, 0x00, 0x33, 0x00, 0x00, + 0xff, 0xff, 0x00, 0x4e, 0xff, 0xd1, 0x05, 0xf0, 0x07, 0x3b, 0x10, 0x27, + 0x00, 0x6b, 0x01, 0xcf, 0x01, 0x83, 0x10, 0x06, 0x00, 0x33, 0x00, 0x00, + 0x00, 0x01, 0x00, 0xc3, 0x00, 0x46, 0x03, 0xe7, 0x03, 0x6a, 0x00, 0x0b, + 0x00, 0x00, 0x01, 0x17, 0x09, 0x01, 0x07, 0x09, 0x01, 0x27, 0x09, 0x01, + 0x37, 0x01, 0x03, 0x81, 0x64, 0xfe, 0xd5, 0x01, 0x2d, 0x66, 0xfe, 0xd3, + 0xfe, 0xd5, 0x66, 0x01, 0x2d, 0xfe, 0xd5, 0x64, 0x01, 0x2b, 0x03, 0x6a, + 0x66, 0xfe, 0xd5, 0xfe, 0xd3, 0x66, 0x01, 0x2d, 0xfe, 0xd5, 0x64, 0x01, + 0x2d, 0x01, 0x2b, 0x64, 0xfe, 0xd7, 0x00, 0x03, 0x00, 0x3d, 0xff, 0xd1, + 0x05, 0xf4, 0x06, 0x0a, 0x00, 0x1b, 0x00, 0x26, 0x00, 0x31, 0x00, 0x00, + 0x3f, 0x01, 0x26, 0x11, 0x10, 0x37, 0x36, 0x25, 0x36, 0x33, 0x20, 0x17, + 0x37, 0x17, 0x07, 0x16, 0x13, 0x16, 0x15, 0x10, 0x07, 0x06, 0x05, 0x06, + 0x23, 0x20, 0x27, 0x07, 0x13, 0x01, 0x26, 0x23, 0x22, 0x07, 0x06, 0x03, + 0x06, 0x15, 0x14, 0x09, 0x01, 0x16, 0x33, 0x32, 0x37, 0x36, 0x13, 0x36, + 0x35, 0x34, 0x3d, 0xa6, 0x9b, 0xa8, 0x9e, 0x01, 0x05, 0x41, 0x45, 0x01, + 0x17, 0xc0, 0xb2, 0x52, 0xb7, 0x92, 0x16, 0x04, 0xa8, 0x9e, 0xfe, 0xfb, + 0x40, 0x45, 0xfe, 0xd9, 0xc7, 0x9e, 0xd7, 0x03, 0x13, 0x97, 0xc7, 0xe4, + 0x90, 0x94, 0x0a, 0x01, 0x03, 0xb8, 0xfc, 0xe8, 0x97, 0xdc, 0xe2, 0x91, + 0x93, 0x0b, 0x01, 0x27, 0xb6, 0xdb, 0x01, 0x29, 0x01, 0x3e, 0xd2, 0xc7, + 0x2b, 0x0b, 0xa6, 0xc2, 0x49, 0xc7, 0xb7, 0xfe, 0xf1, 0x2b, 0x2c, 0xfe, + 0xc2, 0xd2, 0xc6, 0x2b, 0x0b, 0xb8, 0xac, 0x01, 0x8b, 0x03, 0x5b, 0x83, + 0x9b, 0x9e, 0xfe, 0xf8, 0x12, 0x12, 0xd4, 0x02, 0x62, 0xfc, 0xa1, 0x97, + 0x9a, 0x9e, 0x01, 0x06, 0x13, 0x13, 0xea, 0x00, 0xff, 0xff, 0x00, 0xae, + 0xff, 0xd1, 0x05, 0x29, 0x05, 0xd5, 0x10, 0x27, 0x00, 0xc6, 0x01, 0x98, + 0x01, 0x98, 0x10, 0x06, 0x00, 0x39, 0x00, 0x00, 0xff, 0xff, 0x00, 0xae, + 0xff, 0xd1, 0x05, 0x29, 0x05, 0xd5, 0x10, 0x27, 0x00, 0xc5, 0x01, 0x98, + 0x01, 0x98, 0x10, 0x06, 0x00, 0x39, 0x00, 0x00, 0xff, 0xff, 0x00, 0xae, + 0xff, 0xd1, 0x05, 0x29, 0x05, 0xd5, 0x10, 0x27, 0x00, 0xc4, 0x01, 0x9e, + 0x01, 0x96, 0x10, 0x06, 0x00, 0x39, 0x00, 0x00, 0xff, 0xff, 0x00, 0xae, + 0xff, 0xd1, 0x05, 0x29, 0x07, 0x3b, 0x10, 0x27, 0x00, 0x6b, 0x01, 0x9e, + 0x01, 0x83, 0x10, 0x06, 0x00, 0x39, 0x00, 0x00, 0xff, 0xff, 0x00, 0x1b, + 0x00, 0x00, 0x05, 0x4a, 0x05, 0xd5, 0x10, 0x27, 0x00, 0xc5, 0x01, 0x6a, + 0x01, 0x98, 0x10, 0x06, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x02, 0x00, 0xba, + 0x00, 0x00, 0x04, 0xee, 0x05, 0xd5, 0x00, 0x0e, 0x00, 0x19, 0x00, 0x00, + 0x01, 0x11, 0x23, 0x11, 0x33, 0x15, 0x21, 0x32, 0x17, 0x16, 0x15, 0x14, + 0x07, 0x06, 0x23, 0x25, 0x21, 0x32, 0x37, 0x36, 0x35, 0x34, 0x27, 0x26, + 0x23, 0x21, 0x01, 0x79, 0xbf, 0xbf, 0x01, 0xaa, 0xf0, 0x7b, 0x60, 0x77, + 0x74, 0xb5, 0xfe, 0x2b, 0x01, 0x8d, 0xae, 0x47, 0x26, 0x77, 0x43, 0x61, + 0xfe, 0x73, 0x01, 0x83, 0xfe, 0x7d, 0x05, 0xd5, 0xf6, 0x90, 0x71, 0xb1, + 0xbd, 0x78, 0x75, 0xa8, 0x72, 0x3e, 0x56, 0x9e, 0x43, 0x25, 0x00, 0x01, + 0x00, 0x89, 0xff, 0xe1, 0x04, 0x91, 0x05, 0xd3, 0x00, 0x31, 0x00, 0x00, + 0x01, 0x20, 0x37, 0x36, 0x35, 0x34, 0x27, 0x26, 0x23, 0x22, 0x07, 0x06, + 0x15, 0x11, 0x23, 0x11, 0x34, 0x37, 0x36, 0x33, 0x20, 0x17, 0x16, 0x15, + 0x14, 0x07, 0x06, 0x07, 0x16, 0x17, 0x16, 0x15, 0x10, 0x07, 0x06, 0x23, + 0x22, 0x27, 0x35, 0x16, 0x33, 0x20, 0x37, 0x36, 0x35, 0x34, 0x27, 0x26, + 0x2b, 0x01, 0x02, 0x5a, 0x01, 0x0e, 0x29, 0x07, 0x71, 0x4e, 0x79, 0xd1, + 0x39, 0x19, 0xb4, 0x8b, 0x7d, 0xd1, 0x01, 0x00, 0x85, 0x65, 0x97, 0x03, + 0x0e, 0x71, 0x46, 0x36, 0xdf, 0x79, 0xac, 0x31, 0x3b, 0x2d, 0x2d, 0x01, + 0x23, 0x30, 0x09, 0xec, 0x32, 0x3e, 0x21, 0x03, 0x6a, 0xac, 0x1c, 0x20, + 0x7e, 0x3d, 0x2a, 0x87, 0x3c, 0x60, 0xfb, 0xec, 0x04, 0x42, 0xc2, 0x6d, + 0x62, 0x7e, 0x60, 0x93, 0xbe, 0x66, 0x02, 0x09, 0x1f, 0x7a, 0x5e, 0x5d, + 0xfe, 0xbf, 0x7b, 0x42, 0x0f, 0x99, 0x06, 0xda, 0x29, 0x30, 0xef, 0x27, + 0x09, 0x00, 0xff, 0xff, 0x00, 0x56, 0xff, 0xd1, 0x04, 0x48, 0x04, 0x50, + 0x10, 0x27, 0x00, 0xc6, 0x00, 0xec, 0x00, 0x00, 0x10, 0x06, 0x00, 0x45, + 0x00, 0x00, 0xff, 0xff, 0x00, 0x56, 0xff, 0xd1, 0x04, 0x48, 0x04, 0x50, + 0x10, 0x27, 0x00, 0xc5, 0x00, 0xec, 0xff, 0xfe, 0x10, 0x06, 0x00, 0x45, + 0x00, 0x00, 0xff, 0xff, 0x00, 0x56, 0xff, 0xd1, 0x04, 0x48, 0x04, 0x50, + 0x10, 0x27, 0x00, 0xc4, 0x00, 0xe5, 0x00, 0x00, 0x10, 0x06, 0x00, 0x45, + 0x00, 0x00, 0xff, 0xff, 0x00, 0x56, 0xff, 0xd1, 0x04, 0x48, 0x04, 0x50, + 0x10, 0x27, 0x00, 0xc8, 0x00, 0xe7, 0xff, 0xe3, 0x10, 0x06, 0x00, 0x45, + 0x00, 0x00, 0xff, 0xff, 0x00, 0x56, 0xff, 0xd1, 0x04, 0x48, 0x05, 0x9d, + 0x10, 0x27, 0x00, 0x6b, 0x00, 0xe5, 0xff, 0xe5, 0x10, 0x06, 0x00, 0x45, + 0x00, 0x00, 0xff, 0xff, 0x00, 0x56, 0xff, 0xd1, 0x04, 0x48, 0x04, 0x50, + 0x10, 0x27, 0x00, 0xc7, 0x00, 0xdd, 0x00, 0x00, 0x10, 0x06, 0x00, 0x45, + 0x00, 0x00, 0x00, 0x03, 0x00, 0x46, 0xff, 0xd1, 0x06, 0xc3, 0x04, 0x50, + 0x00, 0x3c, 0x00, 0x4d, 0x00, 0x56, 0x00, 0x00, 0x01, 0x16, 0x17, 0x16, + 0x33, 0x32, 0x37, 0x33, 0x06, 0x07, 0x06, 0x23, 0x22, 0x27, 0x26, 0x2f, + 0x01, 0x06, 0x07, 0x06, 0x23, 0x22, 0x27, 0x26, 0x35, 0x34, 0x37, 0x36, + 0x25, 0x36, 0x33, 0x36, 0x37, 0x36, 0x3d, 0x01, 0x34, 0x27, 0x26, 0x23, + 0x22, 0x07, 0x06, 0x07, 0x23, 0x12, 0x25, 0x36, 0x33, 0x20, 0x17, 0x36, + 0x37, 0x36, 0x33, 0x32, 0x17, 0x16, 0x17, 0x16, 0x15, 0x01, 0x32, 0x37, + 0x36, 0x37, 0x36, 0x3d, 0x01, 0x06, 0x07, 0x06, 0x07, 0x06, 0x15, 0x14, + 0x17, 0x16, 0x01, 0x21, 0x34, 0x27, 0x26, 0x23, 0x22, 0x07, 0x06, 0x03, + 0xac, 0x05, 0xa7, 0x41, 0x4e, 0xd1, 0x4a, 0xac, 0x26, 0x9f, 0x6e, 0x96, + 0xb7, 0x77, 0x24, 0x1a, 0x21, 0xa2, 0x97, 0x3d, 0x44, 0xb3, 0x5e, 0x47, + 0x98, 0x70, 0x01, 0x02, 0x05, 0x05, 0x7e, 0x20, 0x14, 0xa4, 0x23, 0x2a, + 0xb7, 0x31, 0x0d, 0x05, 0xac, 0x0a, 0x01, 0x20, 0x3a, 0x46, 0x01, 0x07, + 0x5f, 0x51, 0x96, 0x3c, 0x3f, 0xc0, 0x83, 0x48, 0x26, 0x2b, 0xfb, 0x02, + 0x9e, 0x6a, 0x36, 0x08, 0x01, 0x43, 0x9f, 0x94, 0x37, 0x67, 0x5b, 0x30, + 0x02, 0x2d, 0x02, 0x5a, 0x63, 0x4f, 0x75, 0x93, 0x56, 0x41, 0x01, 0xdf, + 0xfe, 0x52, 0x20, 0xd7, 0xcf, 0x62, 0x44, 0x65, 0x1f, 0x26, 0x37, 0xa8, + 0x29, 0x10, 0x6e, 0x53, 0x7c, 0xbc, 0x50, 0x3b, 0x17, 0x01, 0x0b, 0x27, + 0x18, 0x2e, 0x2d, 0x82, 0x19, 0x05, 0x73, 0x20, 0x2b, 0x01, 0x1e, 0x34, + 0x0a, 0xa8, 0x72, 0x27, 0x0f, 0x79, 0x44, 0x5e, 0x73, 0xe3, 0xfe, 0x87, + 0x6f, 0x38, 0x2d, 0x05, 0x03, 0xce, 0x1d, 0x17, 0x16, 0x18, 0x2e, 0x6e, + 0x69, 0x2c, 0x17, 0x02, 0x04, 0xa2, 0x5c, 0x4a, 0x72, 0x55, 0x00, 0x01, + 0x00, 0x3f, 0xfe, 0x4a, 0x03, 0xd1, 0x04, 0x50, 0x00, 0x3e, 0x00, 0x00, + 0x05, 0x24, 0x03, 0x26, 0x35, 0x10, 0x37, 0x36, 0x33, 0x32, 0x17, 0x16, + 0x17, 0x23, 0x26, 0x27, 0x26, 0x23, 0x22, 0x07, 0x06, 0x15, 0x14, 0x17, + 0x16, 0x33, 0x32, 0x13, 0x33, 0x06, 0x07, 0x06, 0x23, 0x07, 0x36, 0x33, + 0x32, 0x17, 0x16, 0x15, 0x14, 0x07, 0x06, 0x23, 0x22, 0x27, 0x26, 0x27, + 0x37, 0x17, 0x16, 0x33, 0x32, 0x37, 0x36, 0x35, 0x34, 0x27, 0x26, 0x23, + 0x22, 0x07, 0x27, 0x01, 0xcd, 0xfe, 0xf2, 0x59, 0x27, 0x8b, 0x82, 0xd1, + 0xf3, 0x6d, 0x3d, 0x0b, 0xac, 0x18, 0x83, 0x2c, 0x37, 0xa5, 0x4e, 0x36, + 0x7a, 0x49, 0x6a, 0xda, 0x2c, 0xac, 0x0c, 0x8b, 0x72, 0xab, 0x1b, 0x1d, + 0x1c, 0x77, 0x21, 0x0a, 0x67, 0x3d, 0x58, 0x4f, 0x53, 0x24, 0x3a, 0x2b, + 0x69, 0x31, 0x2f, 0x42, 0x1f, 0x0e, 0x3d, 0x0f, 0x13, 0x20, 0x1f, 0x19, + 0x2b, 0x32, 0x01, 0x05, 0x70, 0x8a, 0x01, 0x14, 0xa1, 0x95, 0xa5, 0x5c, + 0x86, 0xa9, 0x30, 0x10, 0x9b, 0x6c, 0xa7, 0xf0, 0x69, 0x3e, 0x01, 0x04, + 0xd3, 0x71, 0x5c, 0x44, 0x04, 0x51, 0x19, 0x1f, 0x6f, 0x31, 0x1e, 0x1e, + 0x0c, 0x19, 0x54, 0x30, 0x13, 0x2e, 0x15, 0x19, 0x3a, 0x0e, 0x04, 0x11, + 0x0f, 0x00, 0xff, 0xff, 0x00, 0x52, 0xff, 0xd1, 0x04, 0x1b, 0x04, 0x50, + 0x10, 0x27, 0x00, 0xc6, 0x00, 0xf2, 0x00, 0x00, 0x10, 0x06, 0x00, 0x49, + 0x00, 0x00, 0xff, 0xff, 0x00, 0x52, 0xff, 0xd1, 0x04, 0x1b, 0x04, 0x50, + 0x10, 0x27, 0x00, 0xc5, 0x00, 0xf6, 0xff, 0xfe, 0x10, 0x06, 0x00, 0x49, + 0x00, 0x00, 0xff, 0xff, 0x00, 0x52, 0xff, 0xd1, 0x04, 0x1b, 0x04, 0x50, + 0x10, 0x27, 0x00, 0xc4, 0x00, 0xfc, 0x00, 0x02, 0x10, 0x06, 0x00, 0x49, + 0x00, 0x00, 0xff, 0xff, 0x00, 0x52, 0xff, 0xd1, 0x04, 0x1b, 0x05, 0x9d, + 0x10, 0x27, 0x00, 0x6b, 0x00, 0xf0, 0xff, 0xe5, 0x10, 0x06, 0x00, 0x49, + 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x26, 0x00, 0xc6, 0xcb, 0xfc, 0x10, 0x06, 0x00, 0xc3, 0x00, 0x00, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x26, + 0x00, 0xc5, 0xc9, 0xfe, 0x10, 0x06, 0x00, 0xc3, 0x00, 0x00, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x26, 0x00, 0xc4, + 0xc9, 0x00, 0x10, 0x06, 0x00, 0xc3, 0x00, 0x00, 0xff, 0xff, 0x00, 0x06, + 0x04, 0xca, 0x02, 0x27, 0x05, 0x9d, 0x10, 0x26, 0x00, 0x6b, 0xc9, 0xe5, + 0x10, 0x06, 0x00, 0xc3, 0x00, 0x00, 0x00, 0x02, 0x00, 0x4a, 0xff, 0xd1, + 0x04, 0x14, 0x05, 0xf2, 0x00, 0x24, 0x00, 0x34, 0x00, 0x00, 0x13, 0x10, + 0x37, 0x36, 0x33, 0x32, 0x17, 0x26, 0x27, 0x26, 0x27, 0x07, 0x27, 0x37, + 0x26, 0x27, 0x26, 0x27, 0x37, 0x16, 0x17, 0x16, 0x17, 0x37, 0x17, 0x07, + 0x16, 0x17, 0x16, 0x11, 0x10, 0x07, 0x06, 0x23, 0x20, 0x27, 0x26, 0x01, + 0x22, 0x07, 0x06, 0x15, 0x14, 0x17, 0x16, 0x33, 0x32, 0x37, 0x36, 0x35, + 0x34, 0x27, 0x26, 0x4a, 0xc7, 0x6d, 0x8a, 0x33, 0x4e, 0x48, 0x64, 0x0b, + 0x11, 0xc7, 0x4a, 0xae, 0x38, 0x64, 0x05, 0x07, 0x5a, 0x45, 0x5f, 0x19, + 0x27, 0xc6, 0x52, 0xb8, 0x99, 0x57, 0xd0, 0xb7, 0x77, 0xb7, 0xfe, 0xf3, + 0x7d, 0x5b, 0x01, 0xe5, 0x9f, 0x53, 0x41, 0x75, 0x4c, 0x72, 0x9d, 0x53, + 0x43, 0x7e, 0x4a, 0x02, 0x10, 0x01, 0x5d, 0x90, 0x4f, 0x1b, 0x4a, 0x54, + 0x09, 0x0f, 0x5c, 0x50, 0x52, 0x2b, 0x39, 0x03, 0x04, 0x5a, 0x1d, 0x3b, + 0x10, 0x19, 0x5c, 0x4c, 0x54, 0x75, 0x6a, 0xfb, 0xfe, 0xbf, 0xfe, 0xb1, + 0x92, 0x60, 0xc7, 0x91, 0x02, 0x89, 0x8a, 0x6d, 0xab, 0xea, 0x6e, 0x49, + 0x86, 0x6c, 0xa9, 0xfd, 0x6c, 0x3f, 0xff, 0xff, 0x00, 0x8f, 0x00, 0x00, + 0x03, 0xe5, 0x04, 0x50, 0x10, 0x27, 0x00, 0xc8, 0x00, 0xee, 0xff, 0xe3, + 0x10, 0x06, 0x00, 0x52, 0x00, 0x00, 0xff, 0xff, 0x00, 0x4a, 0xff, 0xd1, + 0x04, 0x14, 0x04, 0x50, 0x10, 0x27, 0x00, 0xc6, 0x00, 0xdf, 0x00, 0x02, + 0x10, 0x06, 0x00, 0x53, 0x00, 0x00, 0xff, 0xff, 0x00, 0x4a, 0xff, 0xd1, + 0x04, 0x14, 0x04, 0x50, 0x10, 0x27, 0x00, 0xc5, 0x00, 0xe1, 0x00, 0x00, + 0x10, 0x06, 0x00, 0x53, 0x00, 0x00, 0xff, 0xff, 0x00, 0x4a, 0xff, 0xd1, + 0x04, 0x14, 0x04, 0x50, 0x10, 0x27, 0x00, 0xc4, 0x00, 0xe1, 0x00, 0x02, + 0x10, 0x06, 0x00, 0x53, 0x00, 0x00, 0xff, 0xff, 0x00, 0x4a, 0xff, 0xd1, + 0x04, 0x14, 0x04, 0x50, 0x10, 0x27, 0x00, 0xc8, 0x00, 0xe1, 0xff, 0xe3, + 0x10, 0x06, 0x00, 0x53, 0x00, 0x00, 0xff, 0xff, 0x00, 0x4a, 0xff, 0xd1, + 0x04, 0x14, 0x05, 0x9d, 0x10, 0x27, 0x00, 0x6b, 0x00, 0xdf, 0xff, 0xe5, + 0x10, 0x06, 0x00, 0x53, 0x00, 0x00, 0x00, 0x03, 0x00, 0x66, 0x00, 0x00, + 0x04, 0x46, 0x03, 0xc7, 0x00, 0x03, 0x00, 0x07, 0x00, 0x0b, 0x00, 0x00, + 0x01, 0x15, 0x21, 0x35, 0x01, 0x15, 0x23, 0x35, 0x13, 0x15, 0x23, 0x35, + 0x04, 0x46, 0xfc, 0x20, 0x02, 0x5b, 0xd5, 0xd5, 0xd5, 0x02, 0x2b, 0x8f, + 0x8f, 0xfe, 0xaa, 0xd5, 0xd5, 0x02, 0xf2, 0xd5, 0xd5, 0x00, 0x00, 0x03, + 0x00, 0x25, 0xff, 0xc3, 0x04, 0x3b, 0x04, 0x50, 0x00, 0x17, 0x00, 0x20, + 0x00, 0x2b, 0x00, 0x00, 0x01, 0x07, 0x16, 0x15, 0x10, 0x07, 0x06, 0x23, + 0x22, 0x27, 0x07, 0x27, 0x37, 0x26, 0x35, 0x10, 0x37, 0x36, 0x33, 0x32, + 0x17, 0x16, 0x17, 0x37, 0x03, 0x01, 0x16, 0x33, 0x32, 0x37, 0x36, 0x35, + 0x34, 0x09, 0x01, 0x26, 0x27, 0x26, 0x23, 0x22, 0x07, 0x06, 0x15, 0x14, + 0x04, 0x3b, 0x81, 0x5a, 0xa1, 0x7c, 0xc6, 0xd2, 0x7c, 0x7d, 0x41, 0x87, + 0x62, 0xa1, 0x7d, 0xc7, 0xc6, 0x81, 0x07, 0x06, 0x77, 0xbd, 0xfe, 0x19, + 0x58, 0x81, 0xa3, 0x52, 0x3e, 0xfd, 0xc5, 0x01, 0xe9, 0x49, 0x79, 0x0f, + 0x10, 0x9f, 0x53, 0x41, 0x04, 0x17, 0x92, 0x94, 0xe1, 0xfe, 0xce, 0x98, + 0x75, 0x7f, 0x8d, 0x39, 0x97, 0x92, 0xeb, 0x01, 0x31, 0x98, 0x77, 0x78, + 0x07, 0x06, 0x85, 0xfe, 0xa8, 0xfd, 0xd9, 0x62, 0x8e, 0x6b, 0xa8, 0x89, + 0xfe, 0x88, 0x02, 0x27, 0x5c, 0x0c, 0x02, 0x8a, 0x6d, 0xab, 0x8c, 0x00, + 0xff, 0xff, 0x00, 0x85, 0xff, 0xd1, 0x03, 0xdb, 0x04, 0x31, 0x10, 0x27, + 0x00, 0xc6, 0x00, 0xdd, 0xff, 0xfe, 0x10, 0x06, 0x00, 0x59, 0x00, 0x00, + 0xff, 0xff, 0x00, 0x85, 0xff, 0xd1, 0x03, 0xdb, 0x04, 0x31, 0x10, 0x27, + 0x00, 0xc5, 0x00, 0xdd, 0x00, 0x00, 0x10, 0x06, 0x00, 0x59, 0x00, 0x00, + 0xff, 0xff, 0x00, 0x85, 0xff, 0xd1, 0x03, 0xdb, 0x04, 0x31, 0x10, 0x27, + 0x00, 0xc4, 0x00, 0xe3, 0x00, 0x02, 0x10, 0x06, 0x00, 0x59, 0x00, 0x00, + 0xff, 0xff, 0x00, 0x85, 0xff, 0xd1, 0x03, 0xdb, 0x05, 0x9d, 0x10, 0x27, + 0x00, 0x6b, 0x00, 0xe1, 0xff, 0xe5, 0x10, 0x06, 0x00, 0x59, 0x00, 0x00, + 0xff, 0xff, 0x00, 0x29, 0xfe, 0x42, 0x03, 0xd3, 0x04, 0x31, 0x10, 0x27, + 0x00, 0xc5, 0x00, 0xa6, 0xff, 0xfe, 0x10, 0x06, 0x00, 0x5d, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x6f, 0xfe, 0x42, 0x04, 0x2d, 0x05, 0xb6, 0x00, 0x14, + 0x00, 0x24, 0x00, 0x00, 0x13, 0x11, 0x33, 0x11, 0x36, 0x37, 0x36, 0x33, + 0x32, 0x17, 0x16, 0x11, 0x10, 0x07, 0x06, 0x23, 0x22, 0x27, 0x26, 0x27, + 0x11, 0x01, 0x22, 0x07, 0x06, 0x15, 0x14, 0x17, 0x16, 0x33, 0x32, 0x37, + 0x36, 0x35, 0x34, 0x27, 0x26, 0x6f, 0xaa, 0x59, 0x9f, 0x27, 0x2a, 0xd0, + 0x7c, 0x7f, 0x88, 0x7c, 0xc7, 0xa9, 0x72, 0x17, 0x17, 0x01, 0x2b, 0x91, + 0x53, 0x47, 0x6b, 0x4d, 0x73, 0x91, 0x57, 0x4f, 0x6d, 0x51, 0xfe, 0x42, + 0x07, 0x74, 0xfd, 0xf6, 0x7f, 0x1e, 0x07, 0x9d, 0xa0, 0xfe, 0xf3, 0xfe, + 0xf5, 0x9c, 0x8e, 0x6d, 0x17, 0x1c, 0xfd, 0xd1, 0x05, 0x6e, 0x81, 0x6f, + 0xb0, 0xdb, 0x72, 0x52, 0x7a, 0x70, 0xaf, 0xdc, 0x73, 0x57, 0xff, 0xff, + 0x00, 0x29, 0xfe, 0x42, 0x03, 0xd3, 0x05, 0x9d, 0x10, 0x27, 0x00, 0x6b, + 0x00, 0xb0, 0xff, 0xe5, 0x10, 0x06, 0x00, 0x5d, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x01, 0x9e, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x10, 0x00, 0x9c, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x0c, 0x00, 0xb7, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x4a, 0x00, 0xcc, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x12, 0x01, 0x3e, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x34, 0x01, 0x5c, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x10, 0x01, 0xad, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x8c, 0x01, 0xc8, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x48, 0x02, 0x9d, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x58, 0x03, 0x0c, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x00, 0x68, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x08, 0x00, 0xae, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x06, 0x00, 0xc5, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x25, 0x01, 0x18, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x09, 0x01, 0x52, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x1a, 0x01, 0x92, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x08, 0x01, 0xbf, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x46, 0x02, 0x56, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x24, 0x02, 0xe7, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x2c, 0x03, 0x66, 0x00, 0x03, + 0x00, 0x01, 0x04, 0x09, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x01, 0x04, 0x09, 0x00, 0x01, 0x00, 0x10, 0x00, 0x9c, 0x00, 0x03, + 0x00, 0x01, 0x04, 0x09, 0x00, 0x02, 0x00, 0x0c, 0x00, 0xb7, 0x00, 0x03, + 0x00, 0x01, 0x04, 0x09, 0x00, 0x03, 0x00, 0x4a, 0x00, 0xcc, 0x00, 0x03, + 0x00, 0x01, 0x04, 0x09, 0x00, 0x04, 0x00, 0x12, 0x01, 0x3e, 0x00, 0x03, + 0x00, 0x01, 0x04, 0x09, 0x00, 0x05, 0x00, 0x34, 0x01, 0x5c, 0x00, 0x03, + 0x00, 0x01, 0x04, 0x09, 0x00, 0x06, 0x00, 0x10, 0x01, 0xad, 0x00, 0x03, + 0x00, 0x01, 0x04, 0x09, 0x00, 0x0d, 0x00, 0x8c, 0x01, 0xc8, 0x00, 0x03, + 0x00, 0x01, 0x04, 0x09, 0x00, 0x0e, 0x00, 0x48, 0x02, 0x9d, 0x00, 0x03, + 0x00, 0x01, 0x04, 0x09, 0x00, 0x13, 0x00, 0x58, 0x03, 0x0c, 0x00, 0x03, + 0x00, 0x01, 0x04, 0x24, 0x00, 0x02, 0x00, 0x0e, 0x03, 0x93, 0x00, 0x03, + 0x00, 0x01, 0x04, 0x24, 0x00, 0x0d, 0x00, 0x86, 0x03, 0xa3, 0x00, 0x03, + 0x00, 0x01, 0x04, 0x24, 0x00, 0x0e, 0x00, 0x48, 0x04, 0x2b, 0x00, 0x03, + 0x00, 0x01, 0x04, 0x24, 0x00, 0x13, 0x00, 0x54, 0x04, 0x75, 0x00, 0x43, + 0x00, 0x6f, 0x00, 0x70, 0x00, 0x79, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x66, + 0x00, 0x74, 0x00, 0x20, 0x00, 0x32, 0x00, 0x30, 0x00, 0x30, 0x00, 0x32, + 0x00, 0x2c, 0x00, 0x20, 0x00, 0x32, 0x00, 0x30, 0x00, 0x30, 0x00, 0x33, + 0x00, 0x2c, 0x00, 0x20, 0x00, 0x32, 0x00, 0x30, 0x00, 0x30, 0x00, 0x35, + 0x00, 0x20, 0x00, 0x46, 0x00, 0x72, 0x00, 0x65, 0x00, 0x65, 0x00, 0x20, + 0x00, 0x53, 0x00, 0x6f, 0x00, 0x66, 0x00, 0x74, 0x00, 0x77, 0x00, 0x61, + 0x00, 0x72, 0x00, 0x65, 0x00, 0x20, 0x00, 0x46, 0x00, 0x6f, 0x00, 0x75, + 0x00, 0x6e, 0x00, 0x64, 0x00, 0x61, 0x00, 0x74, 0x00, 0x69, 0x00, 0x6f, + 0x00, 0x6e, 0x00, 0x2e, 0x00, 0x00, 0x43, 0x6f, 0x70, 0x79, 0x6c, 0x65, + 0x66, 0x74, 0x20, 0x32, 0x30, 0x30, 0x32, 0x2c, 0x20, 0x32, 0x30, 0x30, + 0x33, 0x2c, 0x20, 0x32, 0x30, 0x30, 0x35, 0x20, 0x46, 0x72, 0x65, 0x65, + 0x20, 0x53, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x20, 0x46, 0x6f, + 0x75, 0x6e, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x00, 0x00, 0x46, + 0x00, 0x72, 0x00, 0x65, 0x00, 0x65, 0x00, 0x53, 0x00, 0x61, 0x00, 0x6e, + 0x00, 0x73, 0x00, 0x00, 0x46, 0x72, 0x65, 0x65, 0x53, 0x61, 0x6e, 0x73, + 0x00, 0x00, 0x4d, 0x00, 0x65, 0x00, 0x64, 0x00, 0x69, 0x00, 0x75, 0x00, + 0x6d, 0x00, 0x00, 0x4d, 0x65, 0x64, 0x69, 0x75, 0x6d, 0x00, 0x00, 0x46, + 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x46, 0x00, 0x6f, 0x00, 0x72, + 0x00, 0x67, 0x00, 0x65, 0x00, 0x20, 0x00, 0x31, 0x00, 0x2e, 0x00, 0x30, + 0x00, 0x20, 0x00, 0x3a, 0x00, 0x20, 0x00, 0x46, 0x00, 0x72, 0x00, 0x65, + 0x00, 0x65, 0x00, 0x20, 0x00, 0x53, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x73, + 0x00, 0x20, 0x00, 0x3a, 0x00, 0x20, 0x00, 0x32, 0x00, 0x36, 0x00, 0x2d, + 0x00, 0x31, 0x00, 0x2d, 0x00, 0x32, 0x00, 0x30, 0x00, 0x30, 0x00, 0x36, + 0x00, 0x00, 0x46, 0x6f, 0x6e, 0x74, 0x46, 0x6f, 0x72, 0x67, 0x65, 0x20, + 0x31, 0x2e, 0x30, 0x20, 0x3a, 0x20, 0x46, 0x72, 0x65, 0x65, 0x20, 0x53, + 0x61, 0x6e, 0x73, 0x20, 0x3a, 0x20, 0x32, 0x36, 0x2d, 0x31, 0x2d, 0x32, + 0x30, 0x30, 0x36, 0x00, 0x00, 0x46, 0x00, 0x72, 0x00, 0x65, 0x00, 0x65, + 0x00, 0x20, 0x00, 0x53, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x73, 0x00, 0x00, + 0x46, 0x72, 0x65, 0x65, 0x20, 0x53, 0x61, 0x6e, 0x73, 0x00, 0x00, 0x56, + 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, + 0x00, 0x20, 0x00, 0x24, 0x00, 0x52, 0x00, 0x65, 0x00, 0x76, 0x00, 0x69, + 0x00, 0x73, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x3a, 0x00, 0x20, + 0x00, 0x31, 0x00, 0x2e, 0x00, 0x37, 0x00, 0x36, 0x00, 0x20, 0x00, 0x24, + 0x00, 0x20, 0x00, 0x00, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, + 0x24, 0x52, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x31, + 0x2e, 0x37, 0x36, 0x20, 0x24, 0x20, 0x00, 0x00, 0x46, 0x00, 0x72, 0x00, + 0x65, 0x00, 0x65, 0x00, 0x53, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x73, 0x00, + 0x00, 0x46, 0x72, 0x65, 0x65, 0x53, 0x61, 0x6e, 0x73, 0x00, 0x00, 0x54, + 0x00, 0x68, 0x00, 0x65, 0x00, 0x20, 0x00, 0x75, 0x00, 0x73, 0x00, 0x65, + 0x00, 0x20, 0x00, 0x6f, 0x00, 0x66, 0x00, 0x20, 0x00, 0x74, 0x00, 0x68, + 0x00, 0x69, 0x00, 0x73, 0x00, 0x20, 0x00, 0x66, 0x00, 0x6f, 0x00, 0x6e, + 0x00, 0x74, 0x00, 0x20, 0x00, 0x69, 0x00, 0x73, 0x00, 0x20, 0x00, 0x67, + 0x00, 0x72, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x65, 0x00, 0x64, + 0x00, 0x20, 0x00, 0x73, 0x00, 0x75, 0x00, 0x62, 0x00, 0x6a, 0x00, 0x65, + 0x00, 0x63, 0x00, 0x74, 0x00, 0x20, 0x00, 0x74, 0x00, 0x6f, 0x00, 0x20, + 0x00, 0x47, 0x00, 0x4e, 0x00, 0x55, 0x00, 0x20, 0x00, 0x47, 0x00, 0x65, + 0x00, 0x6e, 0x00, 0x65, 0x00, 0x72, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x20, + 0x00, 0x50, 0x00, 0x75, 0x00, 0x62, 0x00, 0x6c, 0x00, 0x69, 0x00, 0x63, + 0x00, 0x20, 0x00, 0x4c, 0x00, 0x69, 0x00, 0x63, 0x00, 0x65, 0x00, 0x6e, + 0x00, 0x73, 0x00, 0x65, 0x00, 0x2e, 0x00, 0x00, 0x54, 0x68, 0x65, 0x20, + 0x75, 0x73, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, + 0x66, 0x6f, 0x6e, 0x74, 0x20, 0x69, 0x73, 0x20, 0x67, 0x72, 0x61, 0x6e, + 0x74, 0x65, 0x64, 0x20, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x20, + 0x74, 0x6f, 0x20, 0x47, 0x4e, 0x55, 0x20, 0x47, 0x65, 0x6e, 0x65, 0x72, + 0x61, 0x6c, 0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20, 0x4c, 0x69, + 0x63, 0x65, 0x6e, 0x73, 0x65, 0x2e, 0x00, 0x00, 0x68, 0x00, 0x74, 0x00, + 0x74, 0x00, 0x70, 0x00, 0x3a, 0x00, 0x2f, 0x00, 0x2f, 0x00, 0x77, 0x00, + 0x77, 0x00, 0x77, 0x00, 0x2e, 0x00, 0x67, 0x00, 0x6e, 0x00, 0x75, 0x00, + 0x2e, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x67, 0x00, 0x2f, 0x00, 0x63, 0x00, + 0x6f, 0x00, 0x70, 0x00, 0x79, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x66, 0x00, + 0x74, 0x00, 0x2f, 0x00, 0x67, 0x00, 0x70, 0x00, 0x6c, 0x00, 0x2e, 0x00, + 0x68, 0x00, 0x74, 0x00, 0x6d, 0x00, 0x6c, 0x00, 0x00, 0x68, 0x74, 0x74, + 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x67, 0x6e, 0x75, 0x2e, + 0x6f, 0x72, 0x67, 0x2f, 0x63, 0x6f, 0x70, 0x79, 0x6c, 0x65, 0x66, 0x74, + 0x2f, 0x67, 0x70, 0x6c, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x00, 0x00, 0x54, + 0x00, 0x68, 0x00, 0x65, 0x00, 0x20, 0x00, 0x71, 0x00, 0x75, 0x00, 0x69, + 0x00, 0x63, 0x00, 0x6b, 0x00, 0x20, 0x00, 0x62, 0x00, 0x72, 0x00, 0x6f, + 0x00, 0x77, 0x00, 0x6e, 0x00, 0x20, 0x00, 0x66, 0x00, 0x6f, 0x00, 0x78, + 0x00, 0x20, 0x00, 0x6a, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x70, 0x00, 0x73, + 0x00, 0x20, 0x00, 0x6f, 0x00, 0x76, 0x00, 0x65, 0x00, 0x72, 0x00, 0x20, + 0x00, 0x74, 0x00, 0x68, 0x00, 0x65, 0x00, 0x20, 0x00, 0x6c, 0x00, 0x61, + 0x00, 0x7a, 0x00, 0x79, 0x00, 0x20, 0x00, 0x64, 0x00, 0x6f, 0x00, 0x67, + 0x00, 0x2e, 0x00, 0x00, 0x54, 0x68, 0x65, 0x20, 0x71, 0x75, 0x69, 0x63, + 0x6b, 0x20, 0x62, 0x72, 0x6f, 0x77, 0x6e, 0x20, 0x66, 0x6f, 0x78, 0x20, + 0x6a, 0x75, 0x6d, 0x70, 0x73, 0x20, 0x6f, 0x76, 0x65, 0x72, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x6c, 0x61, 0x7a, 0x79, 0x20, 0x64, 0x6f, 0x67, 0x2e, + 0x00, 0x00, 0x6e, 0x00, 0x61, 0x00, 0x76, 0x00, 0x61, 0x00, 0x64, 0x00, + 0x6e, 0x00, 0x6f, 0x00, 0x00, 0x00, 0x44, 0x00, 0x6f, 0x00, 0x76, 0x00, + 0x6f, 0x00, 0x6c, 0x00, 0x6a, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x61, 0x00, + 0x20, 0x00, 0x6a, 0x00, 0x65, 0x00, 0x20, 0x00, 0x75, 0x00, 0x70, 0x00, + 0x6f, 0x00, 0x72, 0x00, 0x61, 0x00, 0x62, 0x00, 0x61, 0x00, 0x20, 0x00, + 0x76, 0x00, 0x20, 0x00, 0x73, 0x00, 0x6b, 0x00, 0x6c, 0x00, 0x61, 0x00, + 0x64, 0x00, 0x75, 0x00, 0x20, 0x00, 0x7a, 0x00, 0x20, 0x00, 0x6c, 0x00, + 0x69, 0x00, 0x63, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x63, 0x00, 0x6f, 0x00, + 0x20, 0x00, 0x47, 0x00, 0x4e, 0x00, 0x55, 0x00, 0x20, 0x00, 0x47, 0x00, + 0x65, 0x00, 0x6e, 0x00, 0x65, 0x00, 0x72, 0x00, 0x61, 0x00, 0x6c, 0x00, + 0x20, 0x00, 0x50, 0x00, 0x75, 0x00, 0x62, 0x00, 0x6c, 0x00, 0x69, 0x00, + 0x63, 0x00, 0x20, 0x00, 0x4c, 0x00, 0x69, 0x00, 0x63, 0x00, 0x65, 0x00, + 0x6e, 0x00, 0x73, 0x00, 0x65, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x68, 0x00, + 0x74, 0x00, 0x74, 0x00, 0x70, 0x00, 0x3a, 0x00, 0x2f, 0x00, 0x2f, 0x00, + 0x77, 0x00, 0x77, 0x00, 0x77, 0x00, 0x2e, 0x00, 0x67, 0x00, 0x6e, 0x00, + 0x75, 0x00, 0x2e, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x67, 0x00, 0x2f, 0x00, + 0x63, 0x00, 0x6f, 0x00, 0x70, 0x00, 0x79, 0x00, 0x6c, 0x00, 0x65, 0x00, + 0x66, 0x00, 0x74, 0x00, 0x2f, 0x00, 0x67, 0x00, 0x70, 0x00, 0x6c, 0x00, + 0x2e, 0x00, 0x68, 0x00, 0x74, 0x00, 0x6d, 0x00, 0x6c, 0x00, 0x00, 0x01, + 0x60, 0x00, 0x65, 0x00, 0x72, 0x00, 0x69, 0x00, 0x66, 0x00, 0x20, 0x00, + 0x62, 0x00, 0x6f, 0x00, 0x20, 0x00, 0x7a, 0x00, 0x61, 0x00, 0x20, 0x00, + 0x76, 0x00, 0x61, 0x00, 0x6a, 0x00, 0x6f, 0x00, 0x20, 0x00, 0x73, 0x00, + 0x70, 0x00, 0x65, 0x00, 0x74, 0x00, 0x20, 0x00, 0x6b, 0x00, 0x75, 0x00, + 0x68, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x20, 0x00, 0x64, 0x00, 0x6f, 0x00, + 0x6d, 0x00, 0x61, 0x01, 0x0d, 0x00, 0x65, 0x00, 0x20, 0x01, 0x7e, 0x00, + 0x67, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x63, 0x00, 0x65, 0x00, 0x2e, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xfe, 0xcb, 0x00, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xc9, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x01, 0x02, 0x00, 0x03, + 0x00, 0x04, 0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, 0x08, 0x00, 0x09, + 0x00, 0x0a, 0x00, 0x0b, 0x00, 0x0c, 0x00, 0x0d, 0x00, 0x0e, 0x00, 0x0f, + 0x00, 0x10, 0x00, 0x11, 0x00, 0x12, 0x00, 0x13, 0x00, 0x14, 0x00, 0x15, + 0x00, 0x16, 0x00, 0x17, 0x00, 0x18, 0x00, 0x19, 0x00, 0x1a, 0x00, 0x1b, + 0x00, 0x1c, 0x00, 0x1d, 0x00, 0x1e, 0x00, 0x1f, 0x00, 0x20, 0x00, 0x21, + 0x00, 0x22, 0x00, 0x23, 0x00, 0x24, 0x00, 0x25, 0x00, 0x26, 0x00, 0x27, + 0x00, 0x28, 0x00, 0x29, 0x00, 0x2a, 0x00, 0x2b, 0x00, 0x2c, 0x00, 0x2d, + 0x00, 0x2e, 0x00, 0x2f, 0x00, 0x30, 0x00, 0x31, 0x00, 0x32, 0x00, 0x33, + 0x00, 0x34, 0x00, 0x35, 0x00, 0x36, 0x00, 0x37, 0x00, 0x38, 0x00, 0x39, + 0x00, 0x3a, 0x00, 0x3b, 0x00, 0x3c, 0x00, 0x3d, 0x00, 0x3e, 0x00, 0x3f, + 0x00, 0x40, 0x00, 0x41, 0x00, 0x42, 0x00, 0x43, 0x00, 0x44, 0x00, 0x45, + 0x00, 0x46, 0x00, 0x47, 0x00, 0x48, 0x00, 0x49, 0x00, 0x4a, 0x00, 0x4b, + 0x00, 0x4c, 0x00, 0x4d, 0x00, 0x4e, 0x00, 0x4f, 0x00, 0x50, 0x00, 0x51, + 0x00, 0x52, 0x00, 0x53, 0x00, 0x54, 0x00, 0x55, 0x00, 0x56, 0x00, 0x57, + 0x00, 0x58, 0x00, 0x59, 0x00, 0x5a, 0x00, 0x5b, 0x00, 0x5c, 0x00, 0x5d, + 0x00, 0x5e, 0x00, 0x5f, 0x00, 0x60, 0x00, 0x61, 0x00, 0xac, 0x00, 0xa3, + 0x00, 0x84, 0x00, 0x85, 0x00, 0xbd, 0x00, 0x96, 0x00, 0xe8, 0x00, 0x86, + 0x00, 0x8e, 0x00, 0x8b, 0x00, 0x9d, 0x00, 0xa9, 0x00, 0xa4, 0x01, 0x03, + 0x00, 0x8a, 0x00, 0xda, 0x00, 0x83, 0x00, 0x93, 0x00, 0xf2, 0x00, 0xf3, + 0x00, 0x8d, 0x00, 0x97, 0x00, 0x88, 0x00, 0xc3, 0x00, 0xde, 0x00, 0xf1, + 0x00, 0x9e, 0x00, 0xaa, 0x00, 0xf5, 0x00, 0xf4, 0x00, 0xf6, 0x00, 0xa2, + 0x00, 0xad, 0x00, 0xc9, 0x00, 0xc7, 0x00, 0xae, 0x00, 0x62, 0x00, 0x63, + 0x00, 0x90, 0x00, 0x64, 0x00, 0xcb, 0x00, 0x65, 0x00, 0xc8, 0x00, 0xca, + 0x00, 0xcf, 0x00, 0xcc, 0x00, 0xcd, 0x00, 0xce, 0x00, 0xe9, 0x00, 0x66, + 0x00, 0xd3, 0x00, 0xd0, 0x00, 0xd1, 0x00, 0xaf, 0x00, 0x67, 0x00, 0xf0, + 0x00, 0x91, 0x00, 0xd6, 0x00, 0xd4, 0x00, 0xd5, 0x00, 0x68, 0x00, 0xeb, + 0x00, 0xed, 0x00, 0x89, 0x00, 0x6a, 0x00, 0x69, 0x00, 0x6b, 0x00, 0x6d, + 0x00, 0x6c, 0x00, 0x6e, 0x00, 0xa0, 0x00, 0x6f, 0x00, 0x71, 0x00, 0x70, + 0x00, 0x72, 0x00, 0x73, 0x00, 0x75, 0x00, 0x74, 0x00, 0x76, 0x00, 0x77, + 0x00, 0xea, 0x00, 0x78, 0x00, 0x7a, 0x00, 0x79, 0x00, 0x7b, 0x00, 0x7d, + 0x00, 0x7c, 0x00, 0xb8, 0x00, 0xa1, 0x00, 0x7f, 0x00, 0x7e, 0x00, 0x80, + 0x00, 0x81, 0x00, 0xec, 0x00, 0xee, 0x00, 0xba, 0x00, 0xd7, 0x00, 0xd8, + 0x01, 0x04, 0x01, 0x05, 0x00, 0xdd, 0x00, 0xd9, 0x06, 0x67, 0x6c, 0x79, + 0x70, 0x68, 0x33, 0x0a, 0x73, 0x6f, 0x66, 0x74, 0x68, 0x79, 0x70, 0x68, + 0x65, 0x6e, 0x07, 0x75, 0x6e, 0x69, 0x30, 0x32, 0x43, 0x41, 0x07, 0x75, + 0x6e, 0x69, 0x30, 0x32, 0x43, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0xff, 0xff, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, + 0x00, 0x22, 0x00, 0x00, 0x00, 0x02, 0x00, 0x03, 0x00, 0x00, 0x00, 0x6a, + 0x00, 0x01, 0x00, 0x6b, 0x00, 0x6b, 0x00, 0x03, 0x00, 0x6c, 0x00, 0x02, + 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x8e, 0x00, 0x9c, 0x00, 0x08, + 0x44, 0x46, 0x4c, 0x54, 0x00, 0x32, 0x61, 0x72, 0x6d, 0x6e, 0x00, 0x3c, + 0x62, 0x65, 0x6e, 0x67, 0x00, 0x46, 0x64, 0x65, 0x76, 0x61, 0x00, 0x50, + 0x67, 0x75, 0x6a, 0x72, 0x00, 0x5a, 0x67, 0x75, 0x72, 0x75, 0x00, 0x64, + 0x68, 0x65, 0x62, 0x72, 0x00, 0x6e, 0x6c, 0x61, 0x74, 0x6e, 0x00, 0x78, + 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, + 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, + 0x63, 0x63, 0x6d, 0x70, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x06, 0x00, 0x0e, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x46, 0x00, 0x02, + 0x00, 0x12, 0x00, 0x1a, 0x00, 0x22, 0x00, 0x22, 0x00, 0x03, 0x00, 0x00, + 0x00, 0x2c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x4d, 0x00, 0x4e, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, + 0x00, 0x4d, 0x00, 0x4e, 0x00, 0x01, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x06, 0x00, 0x76, 0x00, 0x01, 0x00, 0x01, 0x00, 0x4d, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x90, 0x00, 0xaa, 0x00, 0x08, + 0x44, 0x46, 0x4c, 0x54, 0x00, 0x32, 0x61, 0x72, 0x6d, 0x6e, 0x00, 0x3e, + 0x62, 0x65, 0x6e, 0x67, 0x00, 0x48, 0x64, 0x65, 0x76, 0x61, 0x00, 0x52, + 0x67, 0x75, 0x6a, 0x72, 0x00, 0x5c, 0x67, 0x75, 0x72, 0x75, 0x00, 0x66, + 0x68, 0x65, 0x62, 0x72, 0x00, 0x70, 0x6c, 0x61, 0x74, 0x6e, 0x00, 0x7a, + 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, + 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x02, 0x6b, 0x65, 0x72, 0x6e, 0x00, 0x0e, 0x6b, 0x65, 0x72, 0x6e, + 0x00, 0x14, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x06, 0x00, 0x0e, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x8e, + 0x00, 0x01, 0x00, 0x7a, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x12, + 0x00, 0x20, 0x00, 0x46, 0x00, 0x54, 0x00, 0x03, 0xff, 0xff, 0xff, 0x33, + 0xff, 0xff, 0xff, 0xac, 0xff, 0xff, 0xff, 0x9a, 0x00, 0x09, 0x00, 0x25, + 0xff, 0xf2, 0x00, 0x38, 0xff, 0x5c, 0x00, 0x3a, 0xff, 0xa2, 0x00, 0x3b, + 0xff, 0xd9, 0x00, 0x3d, 0xff, 0x44, 0x00, 0x84, 0xff, 0xf2, 0x00, 0x87, + 0xff, 0xf2, 0x00, 0x88, 0xff, 0xf2, 0x00, 0x89, 0xff, 0xe9, 0x00, 0x03, + 0xff, 0xff, 0xff, 0x31, 0xff, 0xff, 0xff, 0xac, 0xff, 0xff, 0xff, 0x98, + 0x00, 0x09, 0x00, 0x25, 0xff, 0x9a, 0x00, 0x38, 0xfe, 0xfe, 0x00, 0x3a, + 0xff, 0x42, 0x00, 0x3b, 0xff, 0x79, 0x00, 0x3d, 0xfe, 0xf0, 0x00, 0x84, + 0xff, 0x9a, 0x00, 0x87, 0xff, 0x9a, 0x00, 0x88, 0xff, 0x9a, 0x00, 0x89, + 0xff, 0x91, 0x00, 0x01, 0x00, 0x04, 0x00, 0x10, 0x00, 0x11, 0x00, 0x12, + 0x00, 0x7e, 0x00, 0x01, 0x0e, 0x92, 0x00, 0x04, 0x00, 0x00, 0x00, 0x48, + 0x00, 0x9a, 0x01, 0x34, 0x01, 0x7a, 0x01, 0xa4, 0x01, 0xda, 0x02, 0x50, + 0x02, 0x82, 0x02, 0x94, 0x02, 0xe6, 0x03, 0x5c, 0x03, 0xae, 0x03, 0xd8, + 0x04, 0x2e, 0x04, 0xa4, 0x04, 0xce, 0x05, 0x8c, 0x05, 0xc2, 0x06, 0x5c, + 0x06, 0xee, 0x07, 0x18, 0x07, 0xaa, 0x07, 0xb4, 0x07, 0xca, 0x07, 0xd8, + 0x07, 0xe2, 0x07, 0xfc, 0x08, 0x42, 0x08, 0x5c, 0x08, 0x66, 0x08, 0x70, + 0x08, 0xae, 0x08, 0xb4, 0x08, 0xc6, 0x08, 0xe0, 0x08, 0xfe, 0x09, 0x08, + 0x09, 0x12, 0x09, 0xc0, 0x09, 0xca, 0x0a, 0x08, 0x0a, 0x0e, 0x0a, 0x78, + 0x0a, 0xde, 0x0a, 0xf8, 0x0b, 0x62, 0x0b, 0x90, 0x0c, 0x02, 0x0c, 0x30, + 0x0c, 0x5e, 0x0c, 0xd0, 0x0d, 0x46, 0x0d, 0x4c, 0x0d, 0x5a, 0x0d, 0x70, + 0x0d, 0x7e, 0x0d, 0x8c, 0x0d, 0xa6, 0x0d, 0xac, 0x0d, 0xb2, 0x0d, 0xd0, + 0x0d, 0xd6, 0x0d, 0xf8, 0x0e, 0x06, 0x0e, 0x14, 0x0e, 0x22, 0x0e, 0x30, + 0x0e, 0x3e, 0x0e, 0x4c, 0x0e, 0x5a, 0x0e, 0x68, 0x0e, 0x76, 0x0e, 0x7c, + 0x00, 0x26, 0xff, 0xff, 0xff, 0xae, 0xff, 0xff, 0xff, 0x8d, 0xff, 0xff, + 0xff, 0x7b, 0xff, 0xff, 0xff, 0xe9, 0xff, 0xff, 0xff, 0xb6, 0x00, 0x10, + 0x00, 0x0a, 0x00, 0x11, 0xff, 0xfa, 0x00, 0x12, 0x00, 0x0a, 0x00, 0x27, + 0xff, 0xb6, 0x00, 0x2b, 0xff, 0xb8, 0x00, 0x33, 0xff, 0xbc, 0x00, 0x35, + 0xff, 0xbe, 0x00, 0x38, 0xff, 0x42, 0x00, 0x39, 0xff, 0xb4, 0x00, 0x3a, + 0xff, 0x66, 0x00, 0x3b, 0xff, 0x98, 0x00, 0x3d, 0xff, 0x35, 0x00, 0x45, + 0xff, 0xf8, 0x00, 0x46, 0x00, 0x08, 0x00, 0x47, 0xff, 0xe9, 0x00, 0x48, + 0xff, 0xf0, 0x00, 0x49, 0xff, 0xdf, 0x00, 0x4b, 0xff, 0xec, 0x00, 0x53, + 0xff, 0xe5, 0x00, 0x55, 0xff, 0xf0, 0x00, 0x58, 0xff, 0xdf, 0x00, 0x59, + 0xff, 0xe7, 0x00, 0x5a, 0xff, 0xc1, 0x00, 0x5b, 0xff, 0xd5, 0x00, 0x5d, + 0xff, 0xba, 0x00, 0x6e, 0xff, 0xa6, 0x00, 0x8a, 0xff, 0xb6, 0x00, 0x99, + 0xff, 0xbc, 0x00, 0x9c, 0xff, 0xb4, 0x00, 0x9d, 0xff, 0xb4, 0x00, 0x9e, + 0xff, 0xb4, 0x00, 0x9f, 0xff, 0xb4, 0x00, 0xaa, 0xff, 0xec, 0x00, 0x11, + 0xff, 0xff, 0xff, 0xf6, 0x00, 0x25, 0xff, 0xd5, 0x00, 0x33, 0xff, 0xf2, + 0x00, 0x3a, 0xff, 0xac, 0x00, 0x3b, 0xff, 0xcd, 0x00, 0x3d, 0xff, 0xa6, + 0x00, 0x84, 0xff, 0xd5, 0x00, 0x85, 0xff, 0xd5, 0x00, 0x86, 0xff, 0xd5, + 0x00, 0x87, 0xff, 0xd5, 0x00, 0x88, 0xff, 0xd5, 0x00, 0x89, 0xff, 0xd5, + 0x00, 0x95, 0xff, 0xf2, 0x00, 0x96, 0xff, 0xf2, 0x00, 0x97, 0xff, 0xf2, + 0x00, 0x99, 0xff, 0xf2, 0x00, 0x9b, 0xff, 0xfe, 0x00, 0x0a, 0x00, 0x25, + 0xff, 0xbe, 0x00, 0x2c, 0xff, 0xe7, 0x00, 0x2f, 0xff, 0xec, 0x00, 0x33, + 0xff, 0xf0, 0x00, 0x84, 0xff, 0xbe, 0x00, 0x87, 0xff, 0xbe, 0x00, 0x88, + 0xff, 0xbe, 0x00, 0x89, 0xff, 0xbc, 0x00, 0x96, 0xff, 0xf0, 0x00, 0x99, + 0xff, 0xf0, 0x00, 0x0d, 0x00, 0x25, 0xff, 0xaa, 0x00, 0x2e, 0xff, 0xf6, + 0x00, 0x38, 0xff, 0xa4, 0x00, 0x3a, 0xff, 0x98, 0x00, 0x3b, 0xff, 0xc5, + 0x00, 0x3c, 0xff, 0x93, 0x00, 0x3d, 0xff, 0x7f, 0x00, 0x83, 0xff, 0xaa, + 0x00, 0x84, 0xff, 0xaa, 0x00, 0x85, 0xff, 0xaa, 0x00, 0x86, 0xff, 0xaa, + 0x00, 0x87, 0xff, 0xaa, 0x00, 0x88, 0xff, 0xaa, 0x00, 0x1d, 0xff, 0xff, + 0xff, 0xd1, 0x00, 0x10, 0xff, 0x23, 0x00, 0x11, 0xff, 0xe3, 0x00, 0x12, + 0xff, 0x23, 0x00, 0x25, 0xff, 0x73, 0x00, 0x2e, 0xff, 0x98, 0x00, 0x33, + 0xff, 0xd3, 0x00, 0x45, 0xff, 0xbc, 0x00, 0x49, 0xff, 0xcf, 0x00, 0x4d, + 0xff, 0xec, 0x00, 0x4e, 0xff, 0xe7, 0x00, 0x53, 0xff, 0xd5, 0x00, 0x56, + 0xff, 0xb8, 0x00, 0x59, 0xff, 0xbc, 0x00, 0x83, 0xff, 0x73, 0x00, 0x84, + 0xff, 0x73, 0x00, 0x85, 0xff, 0x73, 0x00, 0x86, 0xff, 0x73, 0x00, 0x87, + 0xff, 0x73, 0x00, 0x88, 0xff, 0x73, 0x00, 0x99, 0xff, 0xd3, 0x00, 0xa4, + 0xff, 0xbc, 0x00, 0xa7, 0xff, 0xbc, 0x00, 0xa8, 0xff, 0xbc, 0x00, 0xa9, + 0xff, 0xc5, 0x00, 0xac, 0xff, 0xcf, 0x00, 0xb6, 0xff, 0xd5, 0x00, 0xb9, + 0xff, 0xd5, 0x00, 0xbb, 0xff, 0xd5, 0x00, 0x0c, 0x00, 0x25, 0xff, 0xf4, + 0x00, 0x38, 0xff, 0xa6, 0x00, 0x3a, 0xff, 0x9a, 0x00, 0x3b, 0xff, 0xc7, + 0x00, 0x3d, 0xff, 0x81, 0x00, 0x83, 0xff, 0xf4, 0x00, 0x84, 0xff, 0xf4, + 0x00, 0x85, 0xff, 0xf4, 0x00, 0x86, 0xff, 0xf4, 0x00, 0x87, 0xff, 0xf4, + 0x00, 0x88, 0xff, 0xf4, 0x00, 0x89, 0xff, 0xfa, 0x00, 0x04, 0x00, 0x25, + 0xff, 0xbe, 0x00, 0x87, 0xff, 0xbe, 0x00, 0x88, 0xff, 0xbe, 0x00, 0x89, + 0xff, 0xc1, 0x00, 0x14, 0xff, 0xff, 0xff, 0xa4, 0x00, 0x11, 0xff, 0xa0, + 0x00, 0x27, 0xff, 0x98, 0x00, 0x2b, 0xff, 0x98, 0x00, 0x33, 0xff, 0x9e, + 0x00, 0x37, 0xff, 0xb2, 0x00, 0x38, 0x00, 0x29, 0x00, 0x45, 0xff, 0xe9, + 0x00, 0x49, 0xff, 0xbe, 0x00, 0x53, 0xff, 0xc5, 0x00, 0x59, 0xff, 0xd9, + 0x00, 0x5d, 0xff, 0x81, 0x00, 0x96, 0xff, 0x9e, 0x00, 0x99, 0xff, 0x9e, + 0x00, 0xa7, 0xff, 0xe9, 0x00, 0xa8, 0xff, 0xe9, 0x00, 0xa9, 0xff, 0xf2, + 0x00, 0xb6, 0xff, 0xc5, 0x00, 0xb9, 0xff, 0xc5, 0x00, 0xbf, 0xff, 0xd9, + 0x00, 0x1d, 0xff, 0xff, 0xfe, 0xdf, 0xff, 0xff, 0xfe, 0xcf, 0xff, 0xff, + 0xff, 0xd9, 0xff, 0xff, 0xff, 0xac, 0x00, 0x11, 0xff, 0x00, 0x00, 0x25, + 0x00, 0x23, 0x00, 0x27, 0xff, 0xac, 0x00, 0x2b, 0xff, 0xaa, 0x00, 0x33, + 0xff, 0xac, 0x00, 0x37, 0xff, 0xd9, 0x00, 0x38, 0xff, 0x29, 0x00, 0x39, + 0xff, 0xb8, 0x00, 0x3a, 0xff, 0x29, 0x00, 0x3b, 0xff, 0x75, 0x00, 0x3d, + 0xff, 0x08, 0x00, 0x59, 0xff, 0xf2, 0x00, 0x5d, 0xff, 0x8d, 0x00, 0x84, + 0x00, 0x23, 0x00, 0x87, 0x00, 0x23, 0x00, 0x88, 0x00, 0x23, 0x00, 0x89, + 0x00, 0x29, 0x00, 0x8a, 0xff, 0xb4, 0x00, 0x95, 0xff, 0xac, 0x00, 0x96, + 0xff, 0xac, 0x00, 0x97, 0xff, 0xac, 0x00, 0x98, 0xff, 0xac, 0x00, 0x99, + 0xff, 0xac, 0x00, 0x9f, 0xff, 0xb8, 0x00, 0xbf, 0xff, 0xf2, 0x00, 0x14, + 0xff, 0xff, 0xff, 0xfa, 0x00, 0x10, 0xff, 0xf2, 0x00, 0x12, 0xff, 0xf2, + 0x00, 0x25, 0xff, 0xee, 0x00, 0x27, 0xff, 0xfa, 0x00, 0x2b, 0xff, 0xfc, + 0x00, 0x45, 0xff, 0xf6, 0x00, 0x53, 0x00, 0x04, 0x00, 0x84, 0xff, 0xee, + 0x00, 0x87, 0xff, 0xee, 0x00, 0x88, 0xff, 0xee, 0x00, 0x89, 0xff, 0xf4, + 0x00, 0x8a, 0xff, 0xfa, 0x00, 0xa4, 0xff, 0xf6, 0x00, 0xa7, 0xff, 0xf6, + 0x00, 0xa8, 0xff, 0xf6, 0x00, 0xa9, 0xff, 0xfc, 0x00, 0xb6, 0x00, 0x04, + 0x00, 0xb9, 0x00, 0x04, 0x00, 0xbb, 0x00, 0x08, 0x00, 0x0a, 0x00, 0x25, + 0xff, 0xb8, 0x00, 0x38, 0xff, 0xaa, 0x00, 0x3a, 0xff, 0xa4, 0x00, 0x3b, + 0xff, 0xd1, 0x00, 0x3c, 0xff, 0xa2, 0x00, 0x3d, 0xff, 0x87, 0x00, 0x84, + 0xff, 0xb8, 0x00, 0x87, 0xff, 0xb8, 0x00, 0x88, 0xff, 0xb8, 0x00, 0x89, + 0xff, 0xb0, 0x00, 0x15, 0xff, 0xff, 0xff, 0xc7, 0x00, 0x10, 0xfe, 0xec, + 0x00, 0x11, 0xff, 0xae, 0x00, 0x12, 0xfe, 0xec, 0x00, 0x25, 0xff, 0x60, + 0x00, 0x2e, 0xff, 0x60, 0x00, 0x45, 0xff, 0xc7, 0x00, 0x49, 0xff, 0xc1, + 0x00, 0x53, 0xff, 0xc9, 0x00, 0x84, 0xff, 0x60, 0x00, 0x87, 0xff, 0x60, + 0x00, 0x88, 0xff, 0x60, 0x00, 0x89, 0xff, 0x50, 0x00, 0xa4, 0xff, 0xc7, + 0x00, 0xa7, 0xff, 0xc7, 0x00, 0xa8, 0xff, 0xc7, 0x00, 0xa9, 0xff, 0xcf, + 0x00, 0xac, 0xff, 0xc1, 0x00, 0xb6, 0xff, 0xc9, 0x00, 0xb9, 0xff, 0xc9, + 0x00, 0xbb, 0xff, 0xc9, 0x00, 0x1d, 0xff, 0xff, 0xff, 0xe9, 0xff, 0xff, + 0xff, 0xe9, 0x00, 0x11, 0xff, 0xfc, 0x00, 0x27, 0xff, 0xdf, 0x00, 0x2b, + 0xff, 0xe1, 0x00, 0x33, 0xff, 0xe5, 0x00, 0x38, 0xff, 0xd1, 0x00, 0x39, + 0xff, 0xdd, 0x00, 0x3a, 0xff, 0xb0, 0x00, 0x3b, 0xff, 0xc9, 0x00, 0x3d, + 0xff, 0xa8, 0x00, 0x45, 0xff, 0xe1, 0x00, 0x49, 0xff, 0xe7, 0x00, 0x53, + 0xff, 0xee, 0x00, 0x59, 0xff, 0xee, 0x00, 0x5d, 0xff, 0xf0, 0x00, 0x8a, + 0xff, 0xdf, 0x00, 0x96, 0xff, 0xe5, 0x00, 0x99, 0xff, 0xe5, 0x00, 0x9f, + 0xff, 0xdd, 0x00, 0xa4, 0xff, 0xe1, 0x00, 0xa7, 0xff, 0xe1, 0x00, 0xa8, + 0xff, 0xe1, 0x00, 0xa9, 0xff, 0xe7, 0x00, 0xac, 0xff, 0xe7, 0x00, 0xb6, + 0xff, 0xee, 0x00, 0xb9, 0xff, 0xee, 0x00, 0xbd, 0xff, 0xee, 0x00, 0xbf, + 0xff, 0xee, 0x00, 0x0a, 0x00, 0x25, 0xff, 0xd3, 0x00, 0x38, 0xff, 0xc7, + 0x00, 0x3a, 0xff, 0xaa, 0x00, 0x3b, 0xff, 0xc7, 0x00, 0x3d, 0xff, 0x9e, + 0x00, 0x58, 0xff, 0xfa, 0x00, 0x84, 0xff, 0xd3, 0x00, 0x87, 0xff, 0xd3, + 0x00, 0x88, 0xff, 0xd3, 0x00, 0x89, 0xff, 0xd3, 0x00, 0x2f, 0xff, 0xff, + 0xff, 0x10, 0xff, 0xff, 0xff, 0x85, 0xff, 0xff, 0xff, 0xcf, 0xff, 0xff, + 0xff, 0xb8, 0x00, 0x10, 0xff, 0x33, 0x00, 0x11, 0xff, 0x62, 0x00, 0x12, + 0xff, 0x33, 0x00, 0x1e, 0xfe, 0xf0, 0x00, 0x1f, 0xfe, 0xf8, 0x00, 0x25, + 0xff, 0x3d, 0x00, 0x27, 0xff, 0xa6, 0x00, 0x2b, 0xff, 0xa4, 0x00, 0x2e, + 0xff, 0x33, 0x00, 0x33, 0xff, 0xaa, 0x00, 0x37, 0xff, 0xcf, 0x00, 0x3a, + 0x00, 0x19, 0x00, 0x3b, 0x00, 0x21, 0x00, 0x3d, 0x00, 0x29, 0x00, 0x45, + 0xff, 0x33, 0x00, 0x47, 0xff, 0x48, 0x00, 0x49, 0xff, 0x3d, 0x00, 0x4b, + 0xff, 0x4a, 0x00, 0x4d, 0xff, 0xfa, 0x00, 0x4e, 0xff, 0xf6, 0x00, 0x53, + 0xff, 0x44, 0x00, 0x56, 0xff, 0x44, 0x00, 0x57, 0xff, 0x44, 0x00, 0x59, + 0xff, 0x46, 0x00, 0x5a, 0xff, 0x3d, 0x00, 0x5b, 0xff, 0x42, 0x00, 0x5d, + 0xff, 0x33, 0x00, 0x6e, 0xff, 0x08, 0x00, 0x83, 0xff, 0x3d, 0x00, 0x84, + 0xff, 0x3d, 0x00, 0x85, 0xff, 0x3d, 0x00, 0x86, 0xff, 0x3d, 0x00, 0x87, + 0xff, 0x3d, 0x00, 0x88, 0xff, 0x3d, 0x00, 0x89, 0xff, 0x39, 0x00, 0x95, + 0xff, 0xaa, 0x00, 0x96, 0xff, 0xaa, 0x00, 0x97, 0xff, 0xaa, 0x00, 0x98, + 0xff, 0xaa, 0x00, 0x99, 0xff, 0xaa, 0x00, 0x9b, 0xff, 0xac, 0x00, 0xa9, + 0xff, 0x39, 0x00, 0xbb, 0xff, 0x4e, 0x00, 0x0d, 0x00, 0x10, 0xff, 0xc9, + 0x00, 0x12, 0xff, 0xcd, 0x00, 0x25, 0xff, 0xb6, 0x00, 0x51, 0xff, 0xf8, + 0x00, 0x52, 0xff, 0xf8, 0x00, 0x54, 0x00, 0x06, 0x00, 0x56, 0xff, 0xf8, + 0x00, 0x84, 0xff, 0xb6, 0x00, 0x85, 0xff, 0xb6, 0x00, 0x86, 0xff, 0xb6, + 0x00, 0x87, 0xff, 0xb6, 0x00, 0x88, 0xff, 0xb6, 0x00, 0x89, 0xff, 0xb0, + 0x00, 0x26, 0xff, 0xff, 0xff, 0x5c, 0xff, 0xff, 0xff, 0xb8, 0xff, 0xff, + 0xff, 0xa8, 0x00, 0x10, 0xff, 0x4a, 0x00, 0x11, 0xff, 0xb2, 0x00, 0x12, + 0xff, 0x4a, 0x00, 0x1e, 0xff, 0x79, 0x00, 0x1f, 0xff, 0x79, 0x00, 0x25, + 0xff, 0x6f, 0x00, 0x27, 0xff, 0xa8, 0x00, 0x2b, 0xff, 0xaa, 0x00, 0x33, + 0xff, 0xae, 0x00, 0x37, 0xff, 0xb8, 0x00, 0x38, 0x00, 0x1f, 0x00, 0x45, + 0xff, 0x87, 0x00, 0x49, 0xff, 0x8b, 0x00, 0x4b, 0xff, 0x9a, 0x00, 0x4d, + 0xff, 0xf6, 0x00, 0x53, 0xff, 0x91, 0x00, 0x56, 0xff, 0xaa, 0x00, 0x59, + 0xff, 0xac, 0x00, 0x5d, 0xff, 0xd7, 0x00, 0x6e, 0xff, 0x56, 0x00, 0x83, + 0xff, 0x6f, 0x00, 0x84, 0xff, 0x6f, 0x00, 0x85, 0xff, 0x6f, 0x00, 0x86, + 0xff, 0x6f, 0x00, 0x87, 0xff, 0x6f, 0x00, 0x88, 0xff, 0x6f, 0x00, 0x89, + 0xff, 0x60, 0x00, 0x95, 0xff, 0xae, 0x00, 0x96, 0xff, 0xae, 0x00, 0x97, + 0xff, 0xae, 0x00, 0x98, 0xff, 0xae, 0x00, 0x99, 0xff, 0xae, 0x00, 0x9b, + 0xff, 0xbc, 0x00, 0xa9, 0xff, 0x8f, 0x00, 0xbb, 0xff, 0x9a, 0x00, 0x24, + 0xff, 0xff, 0xff, 0x91, 0x00, 0x10, 0xff, 0x8d, 0x00, 0x11, 0xff, 0xe5, + 0x00, 0x12, 0xff, 0x8d, 0x00, 0x1e, 0xff, 0x96, 0x00, 0x1f, 0xff, 0x93, + 0x00, 0x25, 0xff, 0x9a, 0x00, 0x27, 0xff, 0xd1, 0x00, 0x2b, 0xff, 0xd3, + 0x00, 0x33, 0xff, 0xd7, 0x00, 0x37, 0xff, 0xcf, 0x00, 0x38, 0x00, 0x27, + 0x00, 0x45, 0xff, 0xb2, 0x00, 0x49, 0xff, 0xbe, 0x00, 0x4b, 0xff, 0xcd, + 0x00, 0x4d, 0xff, 0xfe, 0x00, 0x53, 0xff, 0xc5, 0x00, 0x56, 0xff, 0xc7, + 0x00, 0x59, 0xff, 0xc7, 0x00, 0x5d, 0xff, 0xf4, 0x00, 0x6e, 0xff, 0x89, + 0x00, 0x83, 0xff, 0x9a, 0x00, 0x84, 0xff, 0x9a, 0x00, 0x85, 0xff, 0x9a, + 0x00, 0x86, 0xff, 0x9a, 0x00, 0x87, 0xff, 0x9a, 0x00, 0x88, 0xff, 0x9a, + 0x00, 0x89, 0xff, 0x8d, 0x00, 0x95, 0xff, 0xd7, 0x00, 0x96, 0xff, 0xd7, + 0x00, 0x97, 0xff, 0xd7, 0x00, 0x98, 0xff, 0xd7, 0x00, 0x99, 0xff, 0xd7, + 0x00, 0x9b, 0xff, 0xe5, 0x00, 0xa9, 0xff, 0xba, 0x00, 0xbb, 0xff, 0xcd, + 0x00, 0x0a, 0x00, 0x11, 0xff, 0x98, 0x00, 0x27, 0xff, 0x9e, 0x00, 0x33, + 0xff, 0xa4, 0x00, 0x35, 0xff, 0xa6, 0x00, 0x45, 0xff, 0xe1, 0x00, 0x49, + 0xff, 0xb6, 0x00, 0x53, 0xff, 0xbc, 0x00, 0x59, 0xff, 0xcf, 0x00, 0x5d, + 0xff, 0x83, 0x00, 0x99, 0xff, 0xa4, 0x00, 0x24, 0xff, 0xff, 0xff, 0x0c, + 0x00, 0x10, 0xff, 0x1d, 0x00, 0x11, 0xff, 0x54, 0x00, 0x12, 0xff, 0x1d, + 0x00, 0x1e, 0xff, 0x4e, 0x00, 0x1f, 0xff, 0x4c, 0x00, 0x25, 0xff, 0x3b, + 0x00, 0x27, 0xff, 0x89, 0x00, 0x2b, 0xff, 0x89, 0x00, 0x33, 0xff, 0x8d, + 0x00, 0x37, 0xff, 0xac, 0x00, 0x38, 0x00, 0x2f, 0x00, 0x45, 0xff, 0x4c, + 0x00, 0x49, 0xff, 0x4a, 0x00, 0x4b, 0xff, 0x56, 0x00, 0x4d, 0x00, 0x06, + 0x00, 0x53, 0xff, 0x50, 0x00, 0x54, 0xff, 0x91, 0x00, 0x59, 0xff, 0x7f, + 0x00, 0x5a, 0xff, 0xb6, 0x00, 0x6e, 0xff, 0x04, 0x00, 0x83, 0xff, 0x3b, + 0x00, 0x84, 0xff, 0x3b, 0x00, 0x85, 0xff, 0x3b, 0x00, 0x86, 0xff, 0x3b, + 0x00, 0x87, 0xff, 0x3b, 0x00, 0x88, 0xff, 0x3b, 0x00, 0x89, 0xff, 0x2d, + 0x00, 0x95, 0xff, 0x8d, 0x00, 0x96, 0xff, 0x8d, 0x00, 0x97, 0xff, 0x8d, + 0x00, 0x98, 0xff, 0x8d, 0x00, 0x99, 0xff, 0x8d, 0x00, 0x9b, 0xff, 0x91, + 0x00, 0xa9, 0xff, 0x54, 0x00, 0xbb, 0xff, 0x58, 0x00, 0x02, 0x00, 0x5a, + 0xff, 0xbc, 0x00, 0x5d, 0xff, 0xb2, 0x00, 0x05, 0xff, 0xff, 0xff, 0xd1, + 0x00, 0x4e, 0xff, 0xf8, 0x00, 0x5a, 0xff, 0xd5, 0x00, 0x5b, 0xff, 0xe5, + 0x00, 0x5d, 0xff, 0xcb, 0x00, 0x03, 0x00, 0x5a, 0xff, 0xe9, 0x00, 0x5b, + 0xff, 0xfa, 0x00, 0x5d, 0xff, 0xe1, 0x00, 0x02, 0x00, 0x4c, 0x00, 0x02, + 0x00, 0x4f, 0x00, 0x0e, 0x00, 0x06, 0xff, 0xff, 0xff, 0xdb, 0x00, 0x58, + 0xff, 0xec, 0x00, 0x5a, 0xff, 0xe1, 0x00, 0x5b, 0xff, 0xee, 0x00, 0x5c, + 0xff, 0xc9, 0x00, 0x5d, 0xff, 0xd9, 0x00, 0x11, 0xff, 0xff, 0xff, 0xe7, + 0x00, 0x45, 0xff, 0xee, 0x00, 0x49, 0xff, 0xe1, 0x00, 0x4a, 0x00, 0x2d, + 0x00, 0x4d, 0xff, 0xfc, 0x00, 0x4e, 0xff, 0xf8, 0x00, 0x50, 0xff, 0xfa, + 0x00, 0x53, 0xff, 0xec, 0x00, 0x58, 0x00, 0x31, 0x00, 0xa4, 0xff, 0xee, + 0x00, 0xa7, 0xff, 0xee, 0x00, 0xa8, 0xff, 0xee, 0x00, 0xa9, 0xff, 0xf6, + 0x00, 0xac, 0xff, 0xe1, 0x00, 0xb6, 0xff, 0xec, 0x00, 0xb9, 0xff, 0xec, + 0x00, 0xbb, 0xff, 0xee, 0x00, 0x06, 0x00, 0x45, 0xff, 0xf6, 0x00, 0xa7, + 0xff, 0xf6, 0x00, 0xa8, 0xff, 0xf6, 0x00, 0xa9, 0xff, 0xfe, 0x00, 0xb6, + 0x00, 0x06, 0x00, 0xb9, 0x00, 0x06, 0x00, 0x02, 0xff, 0xff, 0xff, 0xe1, + 0x00, 0x5d, 0xff, 0xdb, 0x00, 0x02, 0x00, 0x38, 0xff, 0xf2, 0x00, 0x4e, + 0xff, 0xfa, 0x00, 0x0f, 0x00, 0x11, 0xff, 0xac, 0x00, 0x45, 0xff, 0xfc, + 0x00, 0x49, 0xff, 0xd5, 0x00, 0x4b, 0xff, 0xdf, 0x00, 0x53, 0xff, 0xd9, + 0x00, 0x57, 0xff, 0xfa, 0x00, 0x59, 0xff, 0xe9, 0x00, 0xa4, 0xff, 0xfc, + 0x00, 0xa7, 0xff, 0xfc, 0x00, 0xa8, 0xff, 0xfc, 0x00, 0xa9, 0x00, 0x04, + 0x00, 0xac, 0xff, 0xd5, 0x00, 0xb6, 0xff, 0xd9, 0x00, 0xb9, 0xff, 0xd9, + 0x00, 0xbf, 0xff, 0xf4, 0x00, 0x01, 0x00, 0x5d, 0xff, 0xf6, 0x00, 0x04, + 0x00, 0x54, 0x00, 0x0a, 0x00, 0x5a, 0xff, 0xe5, 0x00, 0x5b, 0xff, 0xf2, + 0x00, 0x5d, 0xff, 0xdb, 0x00, 0x06, 0xff, 0xff, 0xff, 0xe3, 0x00, 0x38, + 0xff, 0x3b, 0x00, 0x54, 0x00, 0x0a, 0x00, 0x5a, 0xff, 0xe5, 0x00, 0x5b, + 0xff, 0xf2, 0x00, 0x5d, 0xff, 0xdb, 0x00, 0x07, 0xff, 0xff, 0xff, 0xd5, + 0x00, 0x38, 0xff, 0x35, 0x00, 0x58, 0xff, 0xec, 0x00, 0x5a, 0xff, 0xdb, + 0x00, 0x5b, 0xff, 0xec, 0x00, 0x5c, 0xff, 0xc9, 0x00, 0x5d, 0xff, 0xd3, + 0x00, 0x02, 0x00, 0x58, 0xff, 0xf8, 0x00, 0x5d, 0xff, 0xdf, 0x00, 0x02, + 0x00, 0x47, 0x00, 0x10, 0x00, 0x59, 0x00, 0x08, 0x00, 0x2b, 0xff, 0xff, + 0x00, 0x02, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xf4, 0x00, 0x10, + 0xff, 0x73, 0x00, 0x11, 0xff, 0xa0, 0x00, 0x12, 0xff, 0x73, 0x00, 0x1e, + 0xff, 0xd3, 0x00, 0x1f, 0xff, 0xd3, 0x00, 0x45, 0xff, 0xf6, 0x00, 0x47, + 0xff, 0xf4, 0x00, 0x48, 0xff, 0xfe, 0x00, 0x49, 0xff, 0xe9, 0x00, 0x4a, + 0x00, 0x35, 0x00, 0x4b, 0xff, 0xf8, 0x00, 0x4d, 0x00, 0x02, 0x00, 0x4f, + 0x00, 0x0c, 0x00, 0x50, 0x00, 0x02, 0x00, 0x53, 0xff, 0xf4, 0x00, 0x54, + 0x00, 0x10, 0x00, 0x55, 0xff, 0xfa, 0x00, 0x57, 0x00, 0x08, 0x00, 0x58, + 0x00, 0x39, 0x00, 0x59, 0x00, 0x04, 0x00, 0x5a, 0x00, 0x3b, 0x00, 0x5b, + 0x00, 0x3f, 0x00, 0x5c, 0x00, 0x29, 0x00, 0x5d, 0x00, 0x31, 0x00, 0x5e, + 0x00, 0x12, 0x00, 0xa3, 0xff, 0xf6, 0x00, 0xa4, 0xff, 0xf6, 0x00, 0xa5, + 0xff, 0xf6, 0x00, 0xa7, 0xff, 0xf6, 0x00, 0xa8, 0xff, 0xf6, 0x00, 0xa9, + 0xff, 0xfe, 0x00, 0xaa, 0xff, 0xee, 0x00, 0xab, 0xff, 0xe9, 0x00, 0xac, + 0xff, 0xe9, 0x00, 0xad, 0xff, 0xe9, 0x00, 0xb5, 0xff, 0xf4, 0x00, 0xb6, + 0xff, 0xf4, 0x00, 0xb7, 0xff, 0xf4, 0x00, 0xb9, 0xff, 0xf4, 0x00, 0xbb, + 0xff, 0xf4, 0x00, 0x02, 0xff, 0xff, 0xff, 0xd3, 0x00, 0x58, 0xff, 0xfa, + 0x00, 0x0f, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x1e, 0xff, 0xc7, 0x00, 0x1f, + 0xff, 0xc7, 0x00, 0x37, 0xff, 0xf0, 0x00, 0x45, 0xff, 0xfe, 0x00, 0x49, + 0xff, 0xe3, 0x00, 0x4c, 0xff, 0xfa, 0x00, 0x53, 0xff, 0xe7, 0x00, 0xa4, + 0xff, 0xfe, 0x00, 0xa7, 0xff, 0xfe, 0x00, 0xa8, 0xff, 0xfe, 0x00, 0xa9, + 0x00, 0x04, 0x00, 0xac, 0xff, 0xe3, 0x00, 0xb6, 0xff, 0xe7, 0x00, 0xb9, + 0xff, 0xe7, 0x00, 0x01, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x1a, 0xff, 0xff, + 0xff, 0xdf, 0x00, 0x10, 0xff, 0x73, 0x00, 0x11, 0xff, 0xe7, 0x00, 0x12, + 0xff, 0x73, 0x00, 0x1e, 0xff, 0xd1, 0x00, 0x1f, 0xff, 0xd1, 0x00, 0x45, + 0xff, 0xdb, 0x00, 0x47, 0xff, 0xdf, 0x00, 0x49, 0xff, 0xd5, 0x00, 0x4b, + 0xff, 0xe3, 0x00, 0x53, 0xff, 0xdd, 0x00, 0x57, 0xff, 0xee, 0x00, 0xa3, + 0xff, 0xdb, 0x00, 0xa4, 0xff, 0xdb, 0x00, 0xa5, 0xff, 0xdb, 0x00, 0xa6, + 0xff, 0xdb, 0x00, 0xa7, 0xff, 0xdb, 0x00, 0xa8, 0xff, 0xdb, 0x00, 0xa9, + 0xff, 0xe3, 0x00, 0xab, 0xff, 0xd5, 0x00, 0xac, 0xff, 0xd5, 0x00, 0xad, + 0xff, 0xd5, 0x00, 0xb5, 0xff, 0xdd, 0x00, 0xb6, 0xff, 0xdd, 0x00, 0xb9, + 0xff, 0xdd, 0x00, 0xbb, 0xff, 0xdd, 0x00, 0x19, 0x00, 0x10, 0xff, 0x9a, + 0x00, 0x11, 0xff, 0xfe, 0x00, 0x12, 0xff, 0x9a, 0x00, 0x1e, 0xff, 0xd1, + 0x00, 0x1f, 0xff, 0xd1, 0x00, 0x45, 0xff, 0xe1, 0x00, 0x47, 0xff, 0xf2, + 0x00, 0x49, 0xff, 0xe7, 0x00, 0x4b, 0xff, 0xf4, 0x00, 0x53, 0xff, 0xee, + 0x00, 0x57, 0xff, 0xf6, 0x00, 0xa3, 0xff, 0xe1, 0x00, 0xa4, 0xff, 0xe1, + 0x00, 0xa5, 0xff, 0xe1, 0x00, 0xa6, 0xff, 0xe1, 0x00, 0xa7, 0xff, 0xe1, + 0x00, 0xa8, 0xff, 0xe1, 0x00, 0xa9, 0xff, 0xe9, 0x00, 0xab, 0xff, 0xe7, + 0x00, 0xac, 0xff, 0xe7, 0x00, 0xad, 0xff, 0xe7, 0x00, 0xb5, 0xff, 0xee, + 0x00, 0xb6, 0xff, 0xee, 0x00, 0xb9, 0xff, 0xee, 0x00, 0xbb, 0xff, 0xf4, + 0x00, 0x06, 0x00, 0x45, 0xff, 0xdd, 0x00, 0x47, 0xff, 0xd1, 0x00, 0x49, + 0xff, 0xc7, 0x00, 0x53, 0xff, 0xcd, 0x00, 0x55, 0xff, 0xd7, 0x00, 0xac, + 0xff, 0xc7, 0x00, 0x1a, 0x00, 0x10, 0xff, 0x71, 0x00, 0x11, 0xff, 0xe3, + 0x00, 0x12, 0xff, 0x71, 0x00, 0x1e, 0xff, 0xc9, 0x00, 0x1f, 0xff, 0xc9, + 0x00, 0x45, 0xff, 0xd3, 0x00, 0x47, 0xff, 0xd9, 0x00, 0x49, 0xff, 0xcf, + 0x00, 0x4b, 0xff, 0xdd, 0x00, 0x50, 0xff, 0xf8, 0x00, 0x53, 0xff, 0xd7, + 0x00, 0x57, 0xff, 0xe7, 0x00, 0xa3, 0xff, 0xd3, 0x00, 0xa4, 0xff, 0xd3, + 0x00, 0xa5, 0xff, 0xd3, 0x00, 0xa6, 0xff, 0xd3, 0x00, 0xa7, 0xff, 0xd3, + 0x00, 0xa8, 0xff, 0xd3, 0x00, 0xa9, 0xff, 0xdb, 0x00, 0xab, 0xff, 0xcf, + 0x00, 0xac, 0xff, 0xcf, 0x00, 0xad, 0xff, 0xcf, 0x00, 0xb5, 0xff, 0xd7, + 0x00, 0xb6, 0xff, 0xd7, 0x00, 0xb9, 0xff, 0xd7, 0x00, 0xbb, 0xff, 0xd9, + 0x00, 0x0b, 0x00, 0x10, 0x00, 0x0a, 0x00, 0x12, 0x00, 0x0a, 0x00, 0x27, + 0xff, 0xb6, 0x00, 0x2b, 0xff, 0xb8, 0x00, 0x33, 0xff, 0xbc, 0x00, 0x35, + 0xff, 0xbe, 0x00, 0x38, 0xff, 0x42, 0x00, 0x39, 0xff, 0xb4, 0x00, 0x3a, + 0xff, 0x66, 0x00, 0x3b, 0xff, 0x98, 0x00, 0x3d, 0xff, 0x35, 0x00, 0x1c, + 0xff, 0xff, 0xff, 0xae, 0xff, 0xff, 0xff, 0x7b, 0x00, 0x10, 0x00, 0x0a, + 0x00, 0x11, 0xff, 0xfa, 0x00, 0x12, 0x00, 0x0a, 0x00, 0x27, 0xff, 0xb6, + 0x00, 0x2b, 0xff, 0xb8, 0x00, 0x33, 0xff, 0xbc, 0x00, 0x35, 0xff, 0xbe, + 0x00, 0x38, 0xff, 0x42, 0x00, 0x39, 0xff, 0xb4, 0x00, 0x3a, 0xff, 0x66, + 0x00, 0x3b, 0xff, 0x98, 0x00, 0x3d, 0xff, 0x35, 0x00, 0x45, 0xff, 0xf8, + 0x00, 0x46, 0x00, 0x08, 0x00, 0x47, 0xff, 0xe9, 0x00, 0x48, 0xff, 0xf0, + 0x00, 0x49, 0xff, 0xdf, 0x00, 0x4b, 0xff, 0xec, 0x00, 0x53, 0xff, 0xe5, + 0x00, 0x55, 0xff, 0xf0, 0x00, 0x58, 0xff, 0xdf, 0x00, 0x59, 0xff, 0xe7, + 0x00, 0x5a, 0xff, 0xc1, 0x00, 0x5b, 0xff, 0xd5, 0x00, 0x5d, 0xff, 0xba, + 0x00, 0x6e, 0xff, 0xa6, 0x00, 0x0b, 0x00, 0x10, 0x00, 0x0a, 0x00, 0x12, + 0x00, 0x0a, 0x00, 0x27, 0xff, 0xb6, 0x00, 0x2b, 0xff, 0xb8, 0x00, 0x33, + 0xff, 0xbc, 0x00, 0x35, 0xff, 0xbe, 0x00, 0x38, 0xff, 0x42, 0x00, 0x39, + 0xff, 0xb4, 0x00, 0x3a, 0xff, 0x66, 0x00, 0x3b, 0xff, 0x98, 0x00, 0x3d, + 0xff, 0x35, 0x00, 0x0b, 0x00, 0x10, 0x00, 0x0a, 0x00, 0x12, 0x00, 0x0a, + 0x00, 0x27, 0xff, 0xb6, 0x00, 0x2b, 0xff, 0xb8, 0x00, 0x33, 0xff, 0xbc, + 0x00, 0x35, 0xff, 0xbe, 0x00, 0x38, 0xff, 0x42, 0x00, 0x39, 0xff, 0xb4, + 0x00, 0x3a, 0xff, 0x66, 0x00, 0x3b, 0xff, 0x98, 0x00, 0x3d, 0xff, 0x35, + 0x00, 0x1c, 0xff, 0xff, 0xff, 0xae, 0xff, 0xff, 0xff, 0x8d, 0xff, 0xff, + 0xff, 0x7b, 0x00, 0x10, 0x00, 0x0a, 0x00, 0x11, 0xff, 0xfa, 0x00, 0x12, + 0x00, 0x0a, 0x00, 0x27, 0xff, 0xb6, 0x00, 0x2b, 0xff, 0xb8, 0x00, 0x33, + 0xff, 0xbc, 0x00, 0x35, 0xff, 0xbe, 0x00, 0x38, 0xff, 0x42, 0x00, 0x39, + 0xff, 0xb4, 0x00, 0x3a, 0xff, 0x66, 0x00, 0x3b, 0xff, 0x98, 0x00, 0x3d, + 0xff, 0x35, 0x00, 0x45, 0xff, 0xf8, 0x00, 0x46, 0x00, 0x08, 0x00, 0x47, + 0xff, 0xe9, 0x00, 0x48, 0xff, 0xf0, 0x00, 0x4b, 0xff, 0xec, 0x00, 0x53, + 0xff, 0xe5, 0x00, 0x55, 0xff, 0xf0, 0x00, 0x58, 0xff, 0xdf, 0x00, 0x59, + 0xff, 0xe7, 0x00, 0x5a, 0xff, 0xc1, 0x00, 0x5b, 0xff, 0xd5, 0x00, 0x5d, + 0xff, 0xba, 0x00, 0x6e, 0xff, 0xa6, 0x00, 0x1d, 0xff, 0xff, 0xff, 0xae, + 0xff, 0xff, 0xff, 0x8d, 0xff, 0xff, 0xff, 0x7b, 0x00, 0x10, 0x00, 0x0a, + 0x00, 0x11, 0xff, 0xfa, 0x00, 0x12, 0x00, 0x0a, 0x00, 0x27, 0xff, 0xb6, + 0x00, 0x2b, 0xff, 0xb8, 0x00, 0x33, 0xff, 0xbc, 0x00, 0x35, 0xff, 0xbe, + 0x00, 0x38, 0xff, 0x42, 0x00, 0x39, 0xff, 0xb4, 0x00, 0x3a, 0xff, 0x66, + 0x00, 0x3b, 0xff, 0x98, 0x00, 0x3d, 0xff, 0x35, 0x00, 0x45, 0xff, 0xf8, + 0x00, 0x46, 0x00, 0x08, 0x00, 0x47, 0xff, 0xe9, 0x00, 0x48, 0xff, 0xf0, + 0x00, 0x49, 0xff, 0xdf, 0x00, 0x4b, 0xff, 0xec, 0x00, 0x53, 0xff, 0xe5, + 0x00, 0x55, 0xff, 0xf0, 0x00, 0x58, 0xff, 0xdf, 0x00, 0x59, 0xff, 0xe7, + 0x00, 0x5a, 0xff, 0xc1, 0x00, 0x5b, 0xff, 0xd5, 0x00, 0x5d, 0xff, 0xba, + 0x00, 0x6e, 0xff, 0xa6, 0x00, 0x01, 0x00, 0x25, 0xff, 0xc1, 0x00, 0x03, + 0x00, 0x38, 0xff, 0xaa, 0x00, 0x3a, 0xff, 0xa4, 0x00, 0x3d, 0xff, 0x87, + 0x00, 0x05, 0x00, 0x25, 0xff, 0xb8, 0x00, 0x38, 0xff, 0xaa, 0x00, 0x3a, + 0xff, 0xa4, 0x00, 0x3b, 0xff, 0xd1, 0x00, 0x3d, 0xff, 0x87, 0x00, 0x03, + 0x00, 0x38, 0xff, 0xaa, 0x00, 0x3a, 0xff, 0xa4, 0x00, 0x3d, 0xff, 0x87, + 0x00, 0x03, 0x00, 0x38, 0xff, 0xaa, 0x00, 0x3a, 0xff, 0xa4, 0x00, 0x3d, + 0xff, 0x87, 0x00, 0x06, 0x00, 0x25, 0xff, 0xb8, 0x00, 0x38, 0xff, 0xaa, + 0x00, 0x3a, 0xff, 0xa4, 0x00, 0x3b, 0xff, 0xd1, 0x00, 0x3c, 0xff, 0xa2, + 0x00, 0x3d, 0xff, 0x87, 0x00, 0x01, 0x00, 0x25, 0xff, 0xbc, 0x00, 0x01, + 0x00, 0x25, 0xff, 0xb6, 0x00, 0x07, 0x00, 0x10, 0xff, 0xc9, 0x00, 0x12, + 0xff, 0xcd, 0x00, 0x25, 0xff, 0xb6, 0x00, 0x51, 0xff, 0xf8, 0x00, 0x52, + 0xff, 0xf8, 0x00, 0x54, 0x00, 0x06, 0x00, 0x56, 0xff, 0xf8, 0x00, 0x01, + 0x00, 0x25, 0xff, 0xb6, 0x00, 0x08, 0x00, 0x10, 0xff, 0xc9, 0x00, 0x12, + 0xff, 0xcd, 0x00, 0x25, 0xff, 0xb6, 0x00, 0x46, 0x00, 0x06, 0x00, 0x51, + 0xff, 0xf8, 0x00, 0x52, 0xff, 0xf8, 0x00, 0x54, 0x00, 0x06, 0x00, 0x56, + 0xff, 0xf8, 0x00, 0x03, 0x00, 0x5a, 0xff, 0xd5, 0x00, 0x5b, 0xff, 0xe5, + 0x00, 0x5d, 0xff, 0xcb, 0x00, 0x03, 0x00, 0x5a, 0xff, 0xd5, 0x00, 0x5b, + 0xff, 0xe5, 0x00, 0x5d, 0xff, 0xcb, 0x00, 0x03, 0x00, 0x5a, 0xff, 0xd5, + 0x00, 0x5b, 0xff, 0xe5, 0x00, 0x5d, 0xff, 0xcb, 0x00, 0x03, 0x00, 0x5a, + 0xff, 0xd5, 0x00, 0x5b, 0xff, 0xe5, 0x00, 0x5d, 0xff, 0xcb, 0x00, 0x03, + 0x00, 0x5a, 0xff, 0xdf, 0x00, 0x5b, 0xff, 0xec, 0x00, 0x5d, 0xff, 0xd7, + 0x00, 0x03, 0x00, 0x5a, 0xff, 0xe1, 0x00, 0x5b, 0xff, 0xee, 0x00, 0x5d, + 0xff, 0xd9, 0x00, 0x03, 0x00, 0x5a, 0xff, 0xe1, 0x00, 0x5b, 0xff, 0xee, + 0x00, 0x5d, 0xff, 0xd9, 0x00, 0x03, 0x00, 0x5a, 0xff, 0xdb, 0x00, 0x5b, + 0xff, 0xec, 0x00, 0x5d, 0xff, 0xd3, 0x00, 0x03, 0x00, 0x5a, 0xff, 0xdb, + 0x00, 0x5b, 0xff, 0xec, 0x00, 0x5d, 0xff, 0xd3, 0x00, 0x01, 0x00, 0x58, + 0xff, 0xec, 0x00, 0x05, 0x00, 0x58, 0xff, 0xec, 0x00, 0x5a, 0xff, 0xdb, + 0x00, 0x5b, 0xff, 0xec, 0x00, 0x5c, 0xff, 0xc9, 0x00, 0x5d, 0xff, 0xd3, + 0x00, 0x02, 0x00, 0x11, 0x00, 0x25, 0x00, 0x28, 0x00, 0x00, 0x00, 0x2a, + 0x00, 0x2b, 0x00, 0x04, 0x00, 0x2e, 0x00, 0x30, 0x00, 0x06, 0x00, 0x32, + 0x00, 0x34, 0x00, 0x09, 0x00, 0x36, 0x00, 0x3e, 0x00, 0x0c, 0x00, 0x45, + 0x00, 0x47, 0x00, 0x15, 0x00, 0x49, 0x00, 0x4d, 0x00, 0x18, 0x00, 0x4f, + 0x00, 0x5d, 0x00, 0x1d, 0x00, 0x83, 0x00, 0x88, 0x00, 0x2c, 0x00, 0x8a, + 0x00, 0x8a, 0x00, 0x32, 0x00, 0x95, 0x00, 0x99, 0x00, 0x33, 0x00, 0x9b, + 0x00, 0x9f, 0x00, 0x38, 0x00, 0xa3, 0x00, 0xa4, 0x00, 0x3d, 0x00, 0xa7, + 0x00, 0xa9, 0x00, 0x3f, 0x00, 0xac, 0x00, 0xad, 0x00, 0x42, 0x00, 0xb5, + 0x00, 0xb7, 0x00, 0x44, 0x00, 0xb9, 0x00, 0xb9, 0x00, 0x47, 0x00, 0x00 +}; +unsigned int FreeSans_ttf_len = 22932; + +#if 0 +void writeLogo(const char *dir) +{ + QCString fileName=(QCString)dir+"/doxygen.png"; + QFile f(fileName); + if (f.open(IO_WriteOnly)) + f.writeBlock((char *)doxygen_png_data,doxygen_png_len); + else + { + fprintf(stderr,"warning: Cannot open file %s for writing\n",fileName.data()); + } + f.close(); +} + +void writeSearchButton(const char *dir) +{ + QCString fileName=(QCString)dir+"/search.png"; + QFile f(fileName); + if (f.open(IO_WriteOnly)) + f.writeBlock((char *)search_png,search_png_len); + else + { + fprintf(stderr,"warning: Cannot open file %s for writing\n",fileName.data()); + } + f.close(); +} +#endif + +void writeDoxFont(const char *dir) +{ + QCString fileName=(QCString)dir+"/FreeSans.ttf"; + QFile f(fileName); + if (f.open(IO_WriteOnly)) + f.writeBlock((char *)FreeSans_ttf,FreeSans_ttf_len); + else + { + fprintf(stderr,"error: Cannot open file %s for writing\n",fileName.data()); + } + f.close(); +} + +void removeDoxFont(const char *dir) +{ + QDir d(dir); + d.remove("FreeSans.ttf"); +} diff --git a/trunk/src/logos.h b/trunk/src/logos.h new file mode 100644 index 0000000..3050819 --- /dev/null +++ b/trunk/src/logos.h @@ -0,0 +1,27 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#ifndef LOGOS_H +#define LOGOS_H + +extern void writeLogo(const char *dir); +//extern void writeNullImage(const char *dir); +extern void writeSearchButton(const char *dir); +extern void writeDoxFont(const char *dir); +extern void removeDoxFont(const char *dir); + +#endif diff --git a/trunk/src/main.cpp b/trunk/src/main.cpp new file mode 100644 index 0000000..dd1ea1e --- /dev/null +++ b/trunk/src/main.cpp @@ -0,0 +1,41 @@ +/****************************************************************************** + * + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#include "doxygen.h" + +/*! \file + * \brief main entry point for doxygen + * + * This file contains main() + */ + +/*! Default main. The idea of separating this from the rest of doxygen, + * is to make it possible to write your own main, with a different + * generateOutput() function for instance. + */ +int main(int argc,char **argv) +{ + initDoxygen(); + readConfiguration(argc,argv); + checkConfiguration(); + adjustConfiguration(); + parseInput(); + generateOutput(); + return 0; +} + diff --git a/trunk/src/mandocvisitor.cpp b/trunk/src/mandocvisitor.cpp new file mode 100644 index 0000000..06fe9df --- /dev/null +++ b/trunk/src/mandocvisitor.cpp @@ -0,0 +1,1010 @@ +/****************************************************************************** + * + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#include "mandocvisitor.h" +#include "docparser.h" +#include "language.h" +#include "doxygen.h" +#include "outputgen.h" +#include "code.h" +#include "dot.h" +#include "util.h" +#include "message.h" +#include +#include "parserintf.h" + +ManDocVisitor::ManDocVisitor(FTextStream &t,CodeOutputInterface &ci, + const char *langExt) + : DocVisitor(DocVisitor_Man), m_t(t), m_ci(ci), m_insidePre(FALSE), m_hide(FALSE), m_firstCol(TRUE), + m_indent(0), m_langExt(langExt) +{ +} + + //-------------------------------------- + // visitor functions for leaf nodes + //-------------------------------------- + +void ManDocVisitor::visit(DocWord *w) +{ + if (m_hide) return; + filter(w->word()); + m_firstCol=FALSE; +} + +void ManDocVisitor::visit(DocLinkedWord *w) +{ + if (m_hide) return; + m_t << "\\fB"; + filter(w->word()); + m_t << "\\fP"; + m_firstCol=FALSE; +} + +void ManDocVisitor::visit(DocWhiteSpace *w) +{ + if (m_hide) return; + if (m_insidePre) + { + m_t << w->chars(); + m_firstCol=w->chars().at(w->chars().length()-1)=='\n'; + } + else + { + m_t << " "; + m_firstCol=FALSE; + } +} + +void ManDocVisitor::visit(DocSymbol *s) +{ + if (m_hide) return; + switch(s->symbol()) + { + case DocSymbol::BSlash: m_t << "\\\\"; break; + case DocSymbol::At: m_t << "@"; break; + case DocSymbol::Less: m_t << "<"; break; + case DocSymbol::Greater: m_t << ">"; break; + case DocSymbol::Amp: m_t << "&"; break; + case DocSymbol::Dollar: m_t << "$"; break; + case DocSymbol::Hash: m_t << "#"; break; + case DocSymbol::DoubleColon: m_t << "::"; break; + case DocSymbol::Percent: m_t << "%"; break; + case DocSymbol::Copy: m_t << "(C)"; break; + case DocSymbol::Tm: m_t << "(TM)"; break; + case DocSymbol::Reg: m_t << "(R)"; break; + case DocSymbol::Apos: m_t << "'"; break; + case DocSymbol::Quot: m_t << "\""; break; + case DocSymbol::Lsquo: m_t << "`"; break; + case DocSymbol::Rsquo: m_t << "'"; break; + case DocSymbol::Ldquo: m_t << "``"; break; + case DocSymbol::Rdquo: m_t << "''"; break; + case DocSymbol::Ndash: m_t << "--"; break; + case DocSymbol::Mdash: m_t << "---"; break; + case DocSymbol::Uml: m_t << s->letter() << "\\*(4"; break; + case DocSymbol::Acute: m_t << s->letter() << "\\*(`"; break; + case DocSymbol::Grave: m_t << s->letter() << "\\*:"; break; + case DocSymbol::Circ: m_t << s->letter() << "\\*^"; break; + case DocSymbol::Slash: m_t << s->letter(); break; /* todo: implement this */ + case DocSymbol::Tilde: m_t << s->letter() << "\\*~"; break; + case DocSymbol::Szlig: m_t << "s\\*:"; break; + case DocSymbol::Cedil: m_t << s->letter() << "\\*,"; break; + case DocSymbol::Ring: m_t << s->letter() << "\\*o"; break; + case DocSymbol::Nbsp: m_t << " "; break; + default: + err("error: unknown symbol found\n"); + } + m_firstCol=FALSE; +} + +void ManDocVisitor::visit(DocURL *u) +{ + if (m_hide) return; + m_t << u->url(); + m_firstCol=FALSE; +} + +void ManDocVisitor::visit(DocLineBreak *) +{ + if (m_hide) return; + m_t << endl << ".br" << endl; + m_firstCol=TRUE; +} + +void ManDocVisitor::visit(DocHorRuler *) +{ + if (m_hide) return; + if (!m_firstCol) m_t << endl; + m_t << ".PP" << endl; + m_firstCol=TRUE; +} + +void ManDocVisitor::visit(DocStyleChange *s) +{ + if (m_hide) return; + switch (s->style()) + { + case DocStyleChange::Bold: + if (s->enable()) m_t << "\\fB"; else m_t << "\\fP"; + m_firstCol=FALSE; + break; + case DocStyleChange::Italic: + if (s->enable()) m_t << "\\fI"; else m_t << "\\fP"; + m_firstCol=FALSE; + break; + case DocStyleChange::Code: + if (s->enable()) m_t << "\\fC"; else m_t << "\\fP"; + m_firstCol=FALSE; + break; + case DocStyleChange::Subscript: + if (s->enable()) m_t << "\\*<"; else m_t << "\\*> "; + m_firstCol=FALSE; + break; + case DocStyleChange::Superscript: + if (s->enable()) m_t << "\\*{"; else m_t << "\\*} "; + m_firstCol=FALSE; + break; + case DocStyleChange::Center: + /* not supported */ + break; + case DocStyleChange::Small: + /* not supported */ + break; + case DocStyleChange::Preformatted: + if (s->enable()) + { + if (!m_firstCol) m_t << endl; + m_t << ".PP" << endl; + m_t << ".nf" << endl; + m_insidePre=TRUE; + } + else + { + m_insidePre=FALSE; + if (!m_firstCol) m_t << endl; + m_t << ".fi" << endl; + m_t << ".PP" << endl; + m_firstCol=TRUE; + } + break; + case DocStyleChange::Div: /* HTML only */ break; + case DocStyleChange::Span: /* HTML only */ break; + } +} + +void ManDocVisitor::visit(DocVerbatim *s) +{ + if (m_hide) return; + switch(s->type()) + { + case DocVerbatim::Code: // fall though + if (!m_firstCol) m_t << endl; + m_t << ".PP" << endl; + m_t << ".nf" << endl; + Doxygen::parserManager->getParser(0/*TODO*/) + ->parseCode(m_ci,s->context(),s->text(), + s->isExample(),s->exampleFile()); + if (!m_firstCol) m_t << endl; + m_t << ".fi" << endl; + m_t << ".PP" << endl; + m_firstCol=TRUE; + break; + case DocVerbatim::Verbatim: + if (!m_firstCol) m_t << endl; + m_t << ".PP" << endl; + m_t << ".nf" << endl; + m_t << s->text(); + if (!m_firstCol) m_t << endl; + m_t << ".fi" << endl; + m_t << ".PP" << endl; + m_firstCol=TRUE; + break; + case DocVerbatim::ManOnly: + m_t << s->text(); + break; + case DocVerbatim::HtmlOnly: + case DocVerbatim::XmlOnly: + case DocVerbatim::LatexOnly: + case DocVerbatim::Dot: + case DocVerbatim::Msc: + /* nothing */ + break; + } +} + +void ManDocVisitor::visit(DocAnchor *) +{ + /* no support for anchors in man pages */ +} + +void ManDocVisitor::visit(DocInclude *inc) +{ + if (m_hide) return; + switch(inc->type()) + { + case DocInclude::IncWithLines: + { + if (!m_firstCol) m_t << endl; + m_t << ".PP" << endl; + m_t << ".nf" << endl; + QFileInfo cfi( inc->file() ); + FileDef fd( cfi.dirPath(), cfi.fileName() ); + Doxygen::parserManager->getParser(inc->extension()) + ->parseCode(m_ci,inc->context(), + inc->text(), + inc->isExample(), + inc->exampleFile(), &fd); + if (!m_firstCol) m_t << endl; + m_t << ".fi" << endl; + m_t << ".PP" << endl; + m_firstCol=TRUE; + } + break; + case DocInclude::Include: + if (!m_firstCol) m_t << endl; + m_t << ".PP" << endl; + m_t << ".nf" << endl; + Doxygen::parserManager->getParser(inc->extension()) + ->parseCode(m_ci,inc->context(), + inc->text(),inc->isExample(), + inc->exampleFile()); + if (!m_firstCol) m_t << endl; + m_t << ".fi" << endl; + m_t << ".PP" << endl; + m_firstCol=TRUE; + break; + case DocInclude::DontInclude: + break; + case DocInclude::HtmlInclude: + break; + case DocInclude::VerbInclude: + if (!m_firstCol) m_t << endl; + m_t << ".PP" << endl; + m_t << ".nf" << endl; + m_t << inc->text(); + if (!m_firstCol) m_t << endl; + m_t << ".fi" << endl; + m_t << ".PP" << endl; + m_firstCol=TRUE; + break; + case DocInclude::Snippet: + if (!m_firstCol) m_t << endl; + m_t << ".PP" << endl; + m_t << ".nf" << endl; + Doxygen::parserManager->getParser(inc->extension()) + ->parseCode(m_ci, + inc->context(), + extractBlock(inc->text(),inc->blockId()), + inc->isExample(), + inc->exampleFile() + ); + if (!m_firstCol) m_t << endl; + m_t << ".fi" << endl; + m_t << ".PP" << endl; + m_firstCol=TRUE; + break; + } +} + +void ManDocVisitor::visit(DocIncOperator *op) +{ + //printf("DocIncOperator: type=%d first=%d, last=%d text=`%s'\n", + // op->type(),op->isFirst(),op->isLast(),op->text().data()); + if (op->isFirst()) + { + if (!m_hide) + { + if (!m_firstCol) m_t << endl; + m_t << ".PP" << endl; + m_t << ".nf" << endl; + } + pushEnabled(); + m_hide = TRUE; + } + if (op->type()!=DocIncOperator::Skip) + { + popEnabled(); + if (!m_hide) + { + Doxygen::parserManager->getParser(0/*TODO*/) + ->parseCode(m_ci,op->context(),op->text(), + op->isExample(),op->exampleFile()); + } + pushEnabled(); + m_hide=TRUE; + } + if (op->isLast()) + { + popEnabled(); + if (!m_hide) + { + if (!m_firstCol) m_t << endl; + m_t << ".fi" << endl; + m_t << ".PP" << endl; + m_firstCol=TRUE; + } + } + else + { + if (!m_hide) m_t << endl; + } +} + +void ManDocVisitor::visit(DocFormula *f) +{ + if (m_hide) return; + m_t << f->text(); +} + +void ManDocVisitor::visit(DocIndexEntry *) +{ +} + +void ManDocVisitor::visit(DocSimpleSectSep *) +{ +} + +void ManDocVisitor::visit(DocCite *cite) +{ + if (m_hide) return; + m_t << "\\fB"; + if (cite->file().isEmpty()) m_t << "["; + filter(cite->text()); + if (cite->file().isEmpty()) m_t << "]"; + m_t << "\\fP"; +} + + +//-------------------------------------- +// visitor functions for compound nodes +//-------------------------------------- + +void ManDocVisitor::visitPre(DocAutoList *) +{ + if (m_hide) return; + m_indent+=2; +} + +void ManDocVisitor::visitPost(DocAutoList *) +{ + if (m_hide) return; + m_indent-=2; + m_t << ".PP" << endl; +} + +void ManDocVisitor::visitPre(DocAutoListItem *li) +{ + if (m_hide) return; + QCString ws; + ws.fill(' ',m_indent-2); + if (!m_firstCol) m_t << endl; + m_t << ".IP \"" << ws; + if (((DocAutoList *)li->parent())->isEnumList()) + { + m_t << li->itemNumber() << ".\" " << m_indent+2; + } + else // bullet list + { + m_t << "\\(bu\" " << m_indent; + } + m_t << endl; + m_firstCol=TRUE; +} + +void ManDocVisitor::visitPost(DocAutoListItem *) +{ + if (m_hide) return; + m_t << endl; + m_firstCol=TRUE; +} + +void ManDocVisitor::visitPre(DocPara *) +{ +} + +void ManDocVisitor::visitPost(DocPara *p) +{ + if (m_hide) return; + if (!p->isLast() && // omit

    for last paragraph + !(p->parent() && // and for parameter sections + p->parent()->kind()==DocNode::Kind_ParamSect + ) + ) + { + if (!m_firstCol) m_t << endl; + m_t << ".PP" << endl; + m_firstCol=TRUE; + } +} + +void ManDocVisitor::visitPre(DocRoot *) +{ +} + +void ManDocVisitor::visitPost(DocRoot *) +{ +} + +void ManDocVisitor::visitPre(DocSimpleSect *s) +{ + if (m_hide) return; + if (!m_firstCol) + { + m_t << endl; + m_t << ".PP" << endl; + } + m_t << "\\fB"; + switch(s->type()) + { + case DocSimpleSect::See: + m_t << theTranslator->trSeeAlso(); break; + case DocSimpleSect::Return: + m_t << theTranslator->trReturns(); break; + case DocSimpleSect::Author: + m_t << theTranslator->trAuthor(TRUE,TRUE); break; + case DocSimpleSect::Authors: + m_t << theTranslator->trAuthor(TRUE,FALSE); break; + case DocSimpleSect::Version: + m_t << theTranslator->trVersion(); break; + case DocSimpleSect::Since: + m_t << theTranslator->trSince(); break; + case DocSimpleSect::Date: + m_t << theTranslator->trDate(); break; + case DocSimpleSect::Note: + m_t << theTranslator->trNote(); break; + case DocSimpleSect::Warning: + m_t << theTranslator->trWarning(); break; + case DocSimpleSect::Pre: + m_t << theTranslator->trPrecondition(); break; + case DocSimpleSect::Post: + m_t << theTranslator->trPostcondition(); break; + case DocSimpleSect::Copyright: + m_t << theTranslator->trCopyright(); break; + case DocSimpleSect::Invar: + m_t << theTranslator->trInvariant(); break; + case DocSimpleSect::Remark: + m_t << theTranslator->trRemarks(); break; + case DocSimpleSect::Attention: + m_t << theTranslator->trAttention(); break; + case DocSimpleSect::User: break; + case DocSimpleSect::Rcs: break; + case DocSimpleSect::Unknown: break; + } + + // special case 1: user defined title + if (s->type()!=DocSimpleSect::User && s->type()!=DocSimpleSect::Rcs) + { + m_t << ":\\fP" << endl; + m_t << ".RS 4" << endl; + } +} + +void ManDocVisitor::visitPost(DocSimpleSect *) +{ + if (m_hide) return; + if (!m_firstCol) m_t << endl; + m_t << ".RE" << endl; + m_t << ".PP" << endl; + m_firstCol=TRUE; +} + +void ManDocVisitor::visitPre(DocTitle *) +{ +} + +void ManDocVisitor::visitPost(DocTitle *) +{ + if (m_hide) return; + m_t << "\\fP" << endl; + m_t << ".RS 4" << endl; +} + +void ManDocVisitor::visitPre(DocSimpleList *) +{ + if (m_hide) return; + m_indent+=2; + if (!m_firstCol) m_t << endl; + m_t << ".PD 0" << endl; +} + +void ManDocVisitor::visitPost(DocSimpleList *) +{ + if (m_hide) return; + m_indent-=2; + m_t << ".PP" << endl; +} + +void ManDocVisitor::visitPre(DocSimpleListItem *) +{ + if (m_hide) return; + QCString ws; + ws.fill(' ',m_indent-2); + if (!m_firstCol) m_t << endl; + m_t << ".IP \"" << ws << "\\(bu\" " << m_indent << endl; + m_firstCol=TRUE; +} + +void ManDocVisitor::visitPost(DocSimpleListItem *) +{ + if (m_hide) return; + m_t << endl; + m_firstCol=TRUE; +} + +void ManDocVisitor::visitPre(DocSection *s) +{ + if (m_hide) return; + if (!m_firstCol) m_t << endl; + if (s->level()==1) m_t << ".SH"; else m_t << ".SS"; + m_t << " \""; + filter(s->title()); + m_t << "\"" << endl; + if (s->level()==1) m_t << ".PP" << endl; + m_firstCol=TRUE; +} + +void ManDocVisitor::visitPost(DocSection *) +{ +} + +void ManDocVisitor::visitPre(DocHtmlList *) +{ + if (m_hide) return; + m_indent+=2; + if (!m_firstCol) m_t << endl; + m_t << ".PD 0" << endl; +} + +void ManDocVisitor::visitPost(DocHtmlList *) +{ + if (m_hide) return; + m_indent-=2; + if (!m_firstCol) m_t << endl; + m_t << ".PP" << endl; +} + +void ManDocVisitor::visitPre(DocHtmlListItem *li) +{ + if (m_hide) return; + QCString ws; + ws.fill(' ',m_indent-2); + if (!m_firstCol) m_t << endl; + m_t << ".IP \"" << ws; + if (((DocHtmlList *)li->parent())->type()==DocHtmlList::Ordered) + { + m_t << li->itemNumber() << ".\" " << m_indent+2; + } + else // bullet list + { + m_t << "\\(bu\" " << m_indent; + } + m_t << endl; + m_firstCol=TRUE; +} + +void ManDocVisitor::visitPost(DocHtmlListItem *) +{ + if (m_hide) return; + m_t << endl; + m_firstCol=TRUE; +} + +//void ManDocVisitor::visitPre(DocHtmlPre *) +//{ +// if (!m_firstCol) m_t << endl; +// m_t << ".PP" << endl; +// m_t << ".nf" << endl; +// m_insidePre=TRUE; +//} +// +//void ManDocVisitor::visitPost(DocHtmlPre *) +//{ +// m_insidePre=FALSE; +// if (!m_firstCol) m_t << endl; +// m_t << ".fi" << endl; +// m_t << ".PP" << endl; +// m_firstCol=TRUE; +//} + +void ManDocVisitor::visitPre(DocHtmlDescList *) +{ +} + +void ManDocVisitor::visitPost(DocHtmlDescList *) +{ + if (m_hide) return; + if (!m_firstCol) m_t << endl; + m_t << ".PP" << endl; + m_firstCol=TRUE; +} + +void ManDocVisitor::visitPre(DocHtmlDescTitle *) +{ + if (m_hide) return; + if (!m_firstCol) m_t << endl; + m_t << ".IP \"\\fB"; + m_firstCol=FALSE; +} + +void ManDocVisitor::visitPost(DocHtmlDescTitle *) +{ + if (m_hide) return; + m_t << "\\fP\" 1c" << endl; + m_firstCol=TRUE; +} + +void ManDocVisitor::visitPre(DocHtmlDescData *) +{ +} + +void ManDocVisitor::visitPost(DocHtmlDescData *) +{ +} + +void ManDocVisitor::visitPre(DocHtmlTable *) +{ +} + +void ManDocVisitor::visitPost(DocHtmlTable *) +{ +} + +void ManDocVisitor::visitPre(DocHtmlCaption *) +{ +} + +void ManDocVisitor::visitPost(DocHtmlCaption *) +{ +} + +void ManDocVisitor::visitPre(DocHtmlRow *) +{ +} + +void ManDocVisitor::visitPost(DocHtmlRow *) +{ +} + +void ManDocVisitor::visitPre(DocHtmlCell *) +{ +} + +void ManDocVisitor::visitPost(DocHtmlCell *) +{ +} + +void ManDocVisitor::visitPre(DocInternal *) +{ + if (m_hide) return; + //if (!m_firstCol) m_t << endl; + //m_t << ".PP" << endl; + //m_t << "\\fB" << theTranslator->trForInternalUseOnly() << "\\fP" << endl; + //m_t << ".RS 4" << endl; +} + +void ManDocVisitor::visitPost(DocInternal *) +{ + if (m_hide) return; + //if (!m_firstCol) m_t << endl; + //m_t << ".RE" << endl; + //m_t << ".PP" << endl; + //m_firstCol=TRUE; +} + +void ManDocVisitor::visitPre(DocHRef *) +{ + if (m_hide) return; + m_t << "\\fC"; +} + +void ManDocVisitor::visitPost(DocHRef *) +{ + if (m_hide) return; + m_t << "\\fP"; +} + +void ManDocVisitor::visitPre(DocHtmlHeader *header) +{ + if (m_hide) return; + if (!m_firstCol) m_t << endl; + if (header->level()==1) m_t << ".SH"; else m_t << ".SS"; + m_t << " \""; +} + +void ManDocVisitor::visitPost(DocHtmlHeader *header) +{ + if (m_hide) return; + m_t << "\"" << endl; + if (header->level()==1) m_t << ".PP" << endl; + m_firstCol=TRUE; +} + +void ManDocVisitor::visitPre(DocImage *) +{ +} + +void ManDocVisitor::visitPost(DocImage *) +{ +} + +void ManDocVisitor::visitPre(DocDotFile *) +{ +} + +void ManDocVisitor::visitPost(DocDotFile *) +{ +} +void ManDocVisitor::visitPre(DocMscFile *) +{ +} + +void ManDocVisitor::visitPost(DocMscFile *) +{ +} + + +void ManDocVisitor::visitPre(DocLink *) +{ + if (m_hide) return; + m_t << "\\fB"; +} + +void ManDocVisitor::visitPost(DocLink *) +{ + if (m_hide) return; + m_t << "\\fP"; +} + +void ManDocVisitor::visitPre(DocRef *ref) +{ + if (m_hide) return; + m_t << "\\fB"; + if (!ref->hasLinkText()) filter(ref->targetTitle()); +} + +void ManDocVisitor::visitPost(DocRef *) +{ + if (m_hide) return; + m_t << "\\fP"; +} + +void ManDocVisitor::visitPre(DocSecRefItem *) +{ + if (m_hide) return; + QCString ws; + ws.fill(' ',m_indent-2); + if (!m_firstCol) m_t << endl; + m_t << ".IP \"" << ws << "\\(bu\" " << m_indent << endl; + m_firstCol=TRUE; +} + +void ManDocVisitor::visitPost(DocSecRefItem *) +{ + if (m_hide) return; + m_t << endl; + m_firstCol=TRUE; +} + +void ManDocVisitor::visitPre(DocSecRefList *) +{ + if (m_hide) return; + m_indent+=2; +} + +void ManDocVisitor::visitPost(DocSecRefList *) +{ + if (m_hide) return; + m_indent-=2; + if (!m_firstCol) m_t << endl; + m_t << ".PP" << endl; +} + +//void ManDocVisitor::visitPre(DocLanguage *l) +//{ +// QString langId = Config_getEnum("OUTPUT_LANGUAGE"); +// if (l->id().lower()!=langId.lower()) +// { +// pushEnabled(); +// m_hide = TRUE; +// } +//} +// +//void ManDocVisitor::visitPost(DocLanguage *l) +//{ +// QString langId = Config_getEnum("OUTPUT_LANGUAGE"); +// if (l->id().lower()!=langId.lower()) +// { +// popEnabled(); +// } +//} + +void ManDocVisitor::visitPre(DocParamSect *s) +{ + if (m_hide) return; + if (!m_firstCol) + { + m_t << endl; + m_t << ".PP" << endl; + } + m_t << "\\fB"; + switch(s->type()) + { + case DocParamSect::Param: + m_t << theTranslator->trParameters(); break; + case DocParamSect::RetVal: + m_t << theTranslator->trReturnValues(); break; + case DocParamSect::Exception: + m_t << theTranslator->trExceptions(); break; + case DocParamSect::TemplateParam: + /* TODO: add this + m_t << theTranslator->trTemplateParam(); break; + */ + m_t << "Template Parameters"; break; + default: + ASSERT(0); + } + m_t << ":\\fP" << endl; + m_t << ".RS 4" << endl; +} + +void ManDocVisitor::visitPost(DocParamSect *) +{ + if (m_hide) return; + if (!m_firstCol) m_t << endl; + m_t << ".RE" << endl; + m_t << ".PP" << endl; + m_firstCol=TRUE; +} + +void ManDocVisitor::visitPre(DocParamList *pl) +{ + if (m_hide) return; + m_t << "\\fI"; + //QStrListIterator li(pl->parameters()); + //const char *s; + QListIterator li(pl->parameters()); + DocNode *param; + bool first=TRUE; + for (li.toFirst();(param=li.current());++li) + { + if (!first) m_t << ","; else first=FALSE; + if (param->kind()==DocNode::Kind_Word) + { + visit((DocWord*)param); + } + else if (param->kind()==DocNode::Kind_LinkedWord) + { + visit((DocLinkedWord*)param); + } + } + m_t << "\\fP "; +} + +void ManDocVisitor::visitPost(DocParamList *pl) +{ + if (m_hide) return; + if (!pl->isLast()) + { + if (!m_firstCol) m_t << endl; + m_t << ".br" << endl; + } +} + +void ManDocVisitor::visitPre(DocXRefItem *x) +{ + if (m_hide) return; + if (!m_firstCol) + { + m_t << endl; + m_t << ".PP" << endl; + } + m_t << "\\fB"; + filter(x->title()); + m_t << "\\fP" << endl; + m_t << ".RS 4" << endl; +} + +void ManDocVisitor::visitPost(DocXRefItem *) +{ + if (m_hide) return; + if (!m_firstCol) m_t << endl; + m_t << ".RE" << endl; + m_t << ".PP" << endl; + m_firstCol=TRUE; +} + +void ManDocVisitor::visitPre(DocInternalRef *) +{ + if (m_hide) return; + m_t << "\\fB"; +} + +void ManDocVisitor::visitPost(DocInternalRef *) +{ + if (m_hide) return; + m_t << "\\fP"; +} + +void ManDocVisitor::visitPre(DocCopy *) +{ +} + +void ManDocVisitor::visitPost(DocCopy *) +{ +} + +void ManDocVisitor::visitPre(DocText *) +{ +} + +void ManDocVisitor::visitPost(DocText *) +{ +} + +void ManDocVisitor::visitPre(DocHtmlBlockQuote *) +{ + if (m_hide) return; + if (!m_firstCol) + { + m_t << endl; + m_t << ".PP" << endl; + } + m_t << ".RS 4" << endl; // TODO: add support for nested block quotes +} + +void ManDocVisitor::visitPost(DocHtmlBlockQuote *) +{ + if (m_hide) return; + if (!m_firstCol) m_t << endl; + m_t << ".RE" << endl; + m_t << ".PP" << endl; + m_firstCol=TRUE; +} + + +void ManDocVisitor::filter(const char *str) +{ + if (str) + { + const char *p=str; + char c=0; + while ((c=*p++)) + { + switch(c) + { + case '.': m_t << "\\&."; break; // see bug652277 + case '\\': m_t << "\\\\"; break; + case '"': c = '\''; // fall through + default: m_t << c; break; + } + } + } +} + +void ManDocVisitor::pushEnabled() +{ + m_enabled.push(new bool(m_hide)); +} + +void ManDocVisitor::popEnabled() +{ + bool *v=m_enabled.pop(); + ASSERT(v!=0); + m_hide = *v; + delete v; +} + diff --git a/trunk/src/mandocvisitor.h b/trunk/src/mandocvisitor.h new file mode 100644 index 0000000..acd0663 --- /dev/null +++ b/trunk/src/mandocvisitor.h @@ -0,0 +1,160 @@ +/****************************************************************************** + * + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#ifndef _MANDOCVISITOR_H +#define _MANDOCVISITOR_H + +#include "docvisitor.h" +#include +#include + +class FTextStream; +class CodeOutputInterface; + +/*! @brief Concrete visitor implementation for LaTeX output. */ +class ManDocVisitor : public DocVisitor +{ + public: + ManDocVisitor(FTextStream &t,CodeOutputInterface &ci,const char *langExt); + + //-------------------------------------- + // visitor functions for leaf nodes + //-------------------------------------- + + void visit(DocWord *); + void visit(DocLinkedWord *); + void visit(DocWhiteSpace *); + void visit(DocSymbol *); + void visit(DocURL *); + void visit(DocLineBreak *); + void visit(DocHorRuler *); + void visit(DocStyleChange *); + void visit(DocVerbatim *); + void visit(DocAnchor *); + void visit(DocInclude *); + void visit(DocIncOperator *); + void visit(DocFormula *); + void visit(DocIndexEntry *); + void visit(DocSimpleSectSep *); + void visit(DocCite *); + + //-------------------------------------- + // visitor functions for compound nodes + //-------------------------------------- + + void visitPre(DocAutoList *); + void visitPost(DocAutoList *); + void visitPre(DocAutoListItem *); + void visitPost(DocAutoListItem *); + void visitPre(DocPara *); + void visitPost(DocPara *); + void visitPre(DocRoot *); + void visitPost(DocRoot *); + void visitPre(DocSimpleSect *); + void visitPost(DocSimpleSect *); + void visitPre(DocTitle *); + void visitPost(DocTitle *); + void visitPre(DocSimpleList *); + void visitPost(DocSimpleList *); + void visitPre(DocSimpleListItem *); + void visitPost(DocSimpleListItem *); + void visitPre(DocSection *s); + void visitPost(DocSection *); + void visitPre(DocHtmlList *s); + void visitPost(DocHtmlList *s); + void visitPre(DocHtmlListItem *); + void visitPost(DocHtmlListItem *); + //void visitPre(DocHtmlPre *); + //void visitPost(DocHtmlPre *); + void visitPre(DocHtmlDescList *); + void visitPost(DocHtmlDescList *); + void visitPre(DocHtmlDescTitle *); + void visitPost(DocHtmlDescTitle *); + void visitPre(DocHtmlDescData *); + void visitPost(DocHtmlDescData *); + void visitPre(DocHtmlTable *t); + void visitPost(DocHtmlTable *t); + void visitPre(DocHtmlCaption *); + void visitPost(DocHtmlCaption *); + void visitPre(DocHtmlRow *); + void visitPost(DocHtmlRow *) ; + void visitPre(DocHtmlCell *); + void visitPost(DocHtmlCell *); + void visitPre(DocInternal *); + void visitPost(DocInternal *); + void visitPre(DocHRef *); + void visitPost(DocHRef *); + void visitPre(DocHtmlHeader *); + void visitPost(DocHtmlHeader *) ; + void visitPre(DocImage *); + void visitPost(DocImage *); + void visitPre(DocDotFile *); + void visitPost(DocDotFile *); + void visitPre(DocMscFile *); + void visitPost(DocMscFile *); + void visitPre(DocLink *lnk); + void visitPost(DocLink *); + void visitPre(DocRef *ref); + void visitPost(DocRef *); + void visitPre(DocSecRefItem *); + void visitPost(DocSecRefItem *); + void visitPre(DocSecRefList *); + void visitPost(DocSecRefList *); + //void visitPre(DocLanguage *); + //void visitPost(DocLanguage *); + void visitPre(DocParamSect *); + void visitPost(DocParamSect *); + void visitPre(DocParamList *); + void visitPost(DocParamList *); + void visitPre(DocXRefItem *); + void visitPost(DocXRefItem *); + void visitPre(DocInternalRef *); + void visitPost(DocInternalRef *); + void visitPre(DocCopy *); + void visitPost(DocCopy *); + void visitPre(DocText *); + void visitPost(DocText *); + void visitPre(DocHtmlBlockQuote *); + void visitPost(DocHtmlBlockQuote *); + + private: + + //-------------------------------------- + // helper functions + //-------------------------------------- + + void filter(const char *str); + + void pushEnabled(); + void popEnabled(); + + //-------------------------------------- + // state variables + //-------------------------------------- + + FTextStream &m_t; + CodeOutputInterface &m_ci; + bool m_insidePre; + bool m_hide; + bool m_firstCol; + int m_indent; + QStack m_enabled; + QCString m_langExt; +}; + +#endif diff --git a/trunk/src/mangen.cpp b/trunk/src/mangen.cpp new file mode 100644 index 0000000..fb2898c --- /dev/null +++ b/trunk/src/mangen.cpp @@ -0,0 +1,787 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +/* http://www.cubic.org/source/archive/fileform/txt/man/ has some + nice introductions to groff and man pages. */ + +#include + +#include "qtbc.h" +#include +#include "message.h" +#include "mangen.h" +#include "config.h" +#include "util.h" +#include "doxygen.h" +#include +#include "docparser.h" +#include "mandocvisitor.h" +#include "language.h" + +static QCString getExtension() +{ + QCString ext = Config_getString("MAN_EXTENSION"); + if( ext.length() >= 2 && + ext.data()[0] == '.') + { + ext = ext.mid(1, ext.length()-1); + } + else + { + ext = "3"; + } + return ext; +} + +ManGenerator::ManGenerator() : OutputGenerator() +{ + dir=Config_getString("MAN_OUTPUT")+"/man" + getExtension(); + firstCol=TRUE; + paragraph=FALSE; + col=0; + upperCase=FALSE; + insideTabbing=FALSE; + inHeader=FALSE; +} + +ManGenerator::~ManGenerator() +{ +} + +//void ManGenerator::append(const OutputGenerator *g) +//{ +// QCString r=g->getContents(); +// if (upperCase) +// t << r.upper(); +// else +// t << r; +// if (!r.isEmpty()) +// firstCol = r.at(r.length()-1)=='\n'; +// else +// firstCol = ((ManGenerator *)g)->firstCol; +// col+=((ManGenerator *)g)->col; +// inHeader=((ManGenerator *)g)->inHeader; +// paragraph=FALSE; +//} + +void ManGenerator::init() +{ + QCString ext = getExtension(); + QCString &manOutput = Config_getString("MAN_OUTPUT"); + + QDir d(manOutput); + if (!d.exists() && !d.mkdir(manOutput)) + { + err("Could not create output directory %s\n",manOutput.data()); + exit(1); + } + d.setPath(manOutput+"/man"+ext); + if (!d.exists() && !d.mkdir(manOutput+"/man"+ext)) + { + err("Could not create output directory %s/man%s\n",manOutput.data(),ext.data()); + exit(1); + } + createSubDirs(d); +} + +static QCString buildFileName(const char *name) +{ + QCString fileName; + if (name==0) return "noname"; + + const char *p=name; + char c; + while ((c=*p++)) + { + switch (c) + { + case ':': + fileName+="_"; + if (*p==':') p++; + break; + case '<': + case '>': + case '&': + case '*': + case '!': + case '^': + case '~': + case '%': + case '+': + case '/': + fileName+="_"; + break; + default: + fileName+=c; + } + } + + QCString &manExtension = Config_getString("MAN_EXTENSION"); + if (convertToQCString(fileName.right(2))!=manExtension) + { + fileName+=manExtension; + } + + return fileName; +} + +void ManGenerator::startFile(const char *,const char *manName,const char *) +{ + startPlainFile( buildFileName( manName ) ); + firstCol=TRUE; +} + +void ManGenerator::endFile() +{ + t << endl; + endPlainFile(); +} + +void ManGenerator::endTitleHead(const char *,const char *name) +{ + t << ".TH \"" << name << "\" " << getExtension() << " \"" + << dateToString(FALSE) << "\" \""; + if (!Config_getString("PROJECT_NUMBER").isEmpty()) + t << "Version " << Config_getString("PROJECT_NUMBER") << "\" \""; + if (Config_getString("PROJECT_NAME").isEmpty()) + t << "Doxygen"; + else + t << Config_getString("PROJECT_NAME"); + t << "\" \\\" -*- nroff -*-" << endl; + t << ".ad l" << endl; + t << ".nh" << endl; + t << ".SH NAME" << endl; + t << name << " \\- "; + firstCol=FALSE; + inHeader=TRUE; +} + +void ManGenerator::newParagraph() +{ + if (!paragraph) + { + if (!firstCol) t << endl; + t << ".PP" << endl; + firstCol=TRUE; + } + paragraph=TRUE; +} + +void ManGenerator::startParagraph() +{ + if (!paragraph) + { + if (!firstCol) t << endl; + t << ".PP" << endl; + firstCol=TRUE; + } + paragraph=TRUE; +} + +void ManGenerator::endParagraph() +{ +} + +void ManGenerator::writeString(const char *text) +{ + docify(text); +} + +void ManGenerator::startIndexItem(const char *,const char *) +{ +} + +void ManGenerator::endIndexItem(const char *,const char *) +{ +} + +void ManGenerator::writeStartAnnoItem(const char *,const char *, + const char *,const char *) +{ +} + +void ManGenerator::writeObjectLink(const char *,const char *, + const char *, const char *name) +{ + startBold(); docify(name); endBold(); +} + +void ManGenerator::writeCodeLink(const char *,const char *, + const char *, const char *name, + const char *) +{ + docify(name); +} + +void ManGenerator::startHtmlLink(const char *) +{ +} + +void ManGenerator::endHtmlLink() +{ +} + +//void ManGenerator::writeMailLink(const char *url) +//{ +// docify(url); +//} + +void ManGenerator::startGroupHeader(int) +{ + if (!firstCol) t << endl; + t << ".SH \""; + upperCase=TRUE; + firstCol=FALSE; +} + +void ManGenerator::endGroupHeader(int) +{ + t << "\"\n.PP " << endl; + firstCol=TRUE; + paragraph=TRUE; + upperCase=FALSE; +} + +void ManGenerator::startMemberHeader(const char *) +{ + if (!firstCol) t << endl; + t << ".SS \""; +} + +void ManGenerator::endMemberHeader() +{ + t << "\"\n"; + firstCol=TRUE; + paragraph=FALSE; +} + +void ManGenerator::docify(const char *str) +{ + if (str) + { + const char *p=str; + char c=0; + while ((c=*p++)) + { + switch(c) + { + case '.': t << "\\&."; break; // see bug652277 + case '\\': t << "\\\\"; col++; break; + case '\n': t << "\n"; col=0; break; + case '\"': c = '\''; // no break! + default: t << c; col++; break; + } + } + firstCol=(c=='\n'); + //printf("%s",str);fflush(stdout); + } + paragraph=FALSE; +} + +void ManGenerator::codify(const char *str) +{ + //static char spaces[]=" "; + if (str) + { + const char *p=str; + char c; + int spacesToNextTabStop; + while (*p) + { + c=*p++; + switch(c) + { + case '.': t << "\\&."; break; // see bug652277 + case '\t': spacesToNextTabStop = + Config_getInt("TAB_SIZE") - (col%Config_getInt("TAB_SIZE")); + t << Doxygen::spaces.left(spacesToNextTabStop); + col+=spacesToNextTabStop; + break; + case '\n': t << "\n"; firstCol=TRUE; col=0; break; + case '\\': t << "\\"; col++; break; + case '\"': c = '\''; // no break! + default: t << c; firstCol=FALSE; col++; break; + } + } + //printf("%s",str);fflush(stdout); + } + paragraph=FALSE; +} + +void ManGenerator::writeChar(char c) +{ + firstCol=(c=='\n'); + if (firstCol) col=0; else col++; + switch (c) + { + case '\\': t << "\\\\"; break; + case '\"': c = '\''; // no break! + default: t << c; break; + } + //printf("%c",c);fflush(stdout); + paragraph=FALSE; +} + +void ManGenerator::startDescList(SectionTypes) +{ + if (!firstCol) + { t << endl << ".PP" << endl; + firstCol=TRUE; paragraph=TRUE; + col=0; + } + paragraph=FALSE; + startBold(); +} + +void ManGenerator::startTitle() +{ + if (!firstCol) t << endl; + t << ".SH \""; + firstCol=FALSE; + paragraph=FALSE; +} + +void ManGenerator::endTitle() +{ + t << "\""; +} + +void ManGenerator::startItemListItem() +{ + if (!firstCol) t << endl; + t << ".TP" << endl; + firstCol=TRUE; + paragraph=FALSE; + col=0; +} + +void ManGenerator::endItemListItem() +{ +} + +void ManGenerator::startCodeFragment() +{ + newParagraph(); + t << ".nf" << endl; + firstCol=TRUE; + paragraph=FALSE; +} + +void ManGenerator::endCodeFragment() +{ + if (!firstCol) t << endl; + t << ".fi" << endl; + firstCol=TRUE; + paragraph=FALSE; + col=0; +} + +void ManGenerator::startMemberDoc(const char *,const char *,const char *,const char *,bool) +{ + if (!firstCol) t << endl; + t << ".SS \""; + firstCol=FALSE; + paragraph=FALSE; +} + +void ManGenerator::startDoxyAnchor(const char *,const char *manName, + const char *, const char *name, + const char *) +{ + // something to be done? + if( !Config_getBool("MAN_LINKS") ) + { + return; // no + } + + // the name of the link file is derived from the name of the anchor: + // - truncate after an (optional) :: + QCString baseName = name; + int i=baseName.findRev("::"); + if (i!=-1) baseName=baseName.right(baseName.length()-i-2); + + //printf("Converting man link '%s'->'%s'->'%s'\n", + // name,baseName.data(),buildFileName(baseName).data()); + + // - remove dangerous characters and append suffix, then add dir prefix + QCString fileName=dir+"/"+buildFileName( baseName ); + QFile linkfile( fileName ); + // - only create file if it doesn't exist already + if ( !linkfile.open( IO_ReadOnly ) ) + { + if ( linkfile.open( IO_WriteOnly ) ) + { + FTextStream linkstream; + linkstream.setDevice(&linkfile); + //linkstream.setEncoding(QTextStream::UnicodeUTF8); + linkstream << ".so man" << getExtension() << "/" << buildFileName( manName ) << endl; + } + } + linkfile.close(); +} + +void ManGenerator::endMemberDoc(bool) +{ + t << "\"\n"; +} + +void ManGenerator::startSubsection() +{ + if (!firstCol) t << endl; + t << ".SS \""; + firstCol=FALSE; + paragraph=FALSE; +} + +void ManGenerator::endSubsection() +{ + t << "\""; +} + + +void ManGenerator::startSubsubsection() +{ + if (!firstCol) t << endl; + t << "\n.SS \""; + firstCol=FALSE; + paragraph=FALSE; +} + +void ManGenerator::endSubsubsection() +{ + t << "\""; +} + +void ManGenerator::writeSynopsis() +{ + if (!firstCol) t << endl; + t << ".SH SYNOPSIS\n.br\n.PP\n"; + firstCol=TRUE; + paragraph=FALSE; +} + +void ManGenerator::startDescItem() +{ + if (!firstCol) t << endl; + t << ".IP \""; + firstCol=FALSE; +} + +//void ManGenerator::endDescTitle() +//{ +// endBold(); +// paragraph=TRUE; +//} + +void ManGenerator::startDescForItem() +{ + if (!firstCol) t << endl; + if (!paragraph) t << ".in -1c" << endl; + t << ".in +1c" << endl; + firstCol=TRUE; + paragraph=FALSE; + col=0; +} + +void ManGenerator::endDescForItem() +{ +} + +void ManGenerator::endDescItem() +{ + t << "\" 1c" << endl; + firstCol=TRUE; +} + +void ManGenerator::startAnonTypeScope(int indentLevel) +{ + if (indentLevel==0) + { + insideTabbing=TRUE; + } +} + +void ManGenerator::endAnonTypeScope(int indentLevel) +{ + if (indentLevel==0) + { + insideTabbing=FALSE; + } +} + + +void ManGenerator::startMemberItem(const char *,int) +{ + if (firstCol && !insideTabbing) t << ".in +1c\n"; + t << "\n.ti -1c\n.RI \""; + firstCol=FALSE; +} + +void ManGenerator::endMemberItem() +{ + t << "\"\n.br"; +} + +void ManGenerator::startMemberList() +{ + if (!insideTabbing) + { + t << "\n.in +1c"; firstCol=FALSE; + } +} + +void ManGenerator::endMemberList() +{ + if (!insideTabbing) + { + t << "\n.in -1c"; firstCol=FALSE; + } +} + +void ManGenerator::startMemberGroupHeader(bool) +{ + t << "\n.PP\n.RI \"\\fB"; +} + +void ManGenerator::endMemberGroupHeader() +{ + t << "\\fP\"\n.br\n"; + firstCol=TRUE; +} + +void ManGenerator::startMemberGroupDocs() +{ +} + +void ManGenerator::endMemberGroupDocs() +{ + t << "\n.PP"; +} + +void ManGenerator::startMemberGroup() +{ + t << "\n.in +1c"; +} + +void ManGenerator::endMemberGroup(bool) +{ + t << "\n.in -1c"; + firstCol=FALSE; +} + +void ManGenerator::startSection(const char *,const char *,SectionInfo::SectionType type) +{ + if( !inHeader ) + { + switch(type) + { + case SectionInfo::Page: startGroupHeader(FALSE); break; + case SectionInfo::Section: startGroupHeader(FALSE); break; + case SectionInfo::Subsection: startMemberHeader(0); break; + case SectionInfo::Subsubsection: startMemberHeader(0); break; + case SectionInfo::Paragraph: startMemberHeader(0); break; + default: ASSERT(0); break; + } + } +} + +void ManGenerator::endSection(const char *,SectionInfo::SectionType type) +{ + if( !inHeader ) + { + switch(type) + { + case SectionInfo::Page: endGroupHeader(0); break; + case SectionInfo::Section: endGroupHeader(0); break; + case SectionInfo::Subsection: endMemberHeader(); break; + case SectionInfo::Subsubsection: endMemberHeader(); break; + case SectionInfo::Paragraph: endMemberHeader(); break; + default: ASSERT(0); break; + } + } + else + { + t << "\n"; + firstCol=TRUE; + paragraph=FALSE; + inHeader=FALSE; + } +} + +void ManGenerator::startSimpleSect(SectionTypes,const char *, + const char *,const char *title) +{ + if (!firstCol) + { t << endl << ".PP" << endl; + firstCol=TRUE; paragraph=TRUE; + col=0; + } + paragraph=FALSE; + startBold(); + docify(title); + endBold(); + paragraph=TRUE; +} + +void ManGenerator::endSimpleSect() +{ +} + +void ManGenerator::startParamList(ParamListTypes,const char *title) +{ + if (!firstCol) + { t << endl << ".PP" << endl; + firstCol=TRUE; paragraph=TRUE; + col=0; + } + paragraph=FALSE; + startBold(); + docify(title); + endBold(); + paragraph=TRUE; +} + +void ManGenerator::endParamList() +{ +} + +void ManGenerator::printDoc(DocNode *n,const char *langExt) +{ + ManDocVisitor *visitor = new ManDocVisitor(t,*this,langExt); + n->accept(visitor); + delete visitor; + firstCol=FALSE; + paragraph = FALSE; +} + +void ManGenerator::startConstraintList(const char *header) +{ + if (!firstCol) + { t << endl << ".PP" << endl; + firstCol=TRUE; paragraph=TRUE; + col=0; + } + paragraph=FALSE; + startBold(); + docify(header); + endBold(); + paragraph=TRUE; +} + +void ManGenerator::startConstraintParam() +{ + startItemListItem(); + startEmphasis(); +} + +void ManGenerator::endConstraintParam() +{ + endEmphasis(); + endItemListItem(); + t << " : "; +} + +void ManGenerator::startConstraintType() +{ + startEmphasis(); +} + +void ManGenerator::endConstraintType() +{ + endEmphasis(); +} + +void ManGenerator::startConstraintDocs() +{ +} + +void ManGenerator::endConstraintDocs() +{ + t << endl; firstCol=TRUE; +} + +void ManGenerator::endConstraintList() +{ +} + + +void ManGenerator::startInlineHeader() +{ + if (!firstCol) + { + t << endl << ".PP" << endl << ".in -1c" << endl; + } + t << ".RI \"\\fB"; +} + +void ManGenerator::endInlineHeader() +{ + t << "\\fP\"" << endl << ".in +1c" << endl; + firstCol = FALSE; +} + +void ManGenerator::startMemberDocSimple() +{ + if (!firstCol) + { + t << endl << ".PP" << endl; + } + t << "\\fB"; + docify(theTranslator->trCompoundMembers()); + t << ":\\fP" << endl; + t << ".RS 4" << endl; +} + +void ManGenerator::endMemberDocSimple() +{ + if (!firstCol) t << endl; + t << ".RE" << endl; + t << ".PP" << endl; + firstCol=TRUE; +} + +void ManGenerator::startInlineMemberType() +{ +} + +void ManGenerator::endInlineMemberType() +{ + t << " "; +} + +void ManGenerator::startInlineMemberName() +{ + t << "\\fI"; +} + +void ManGenerator::endInlineMemberName() +{ + t << "\\fP "; +} + +void ManGenerator::startInlineMemberDoc() +{ +} + +void ManGenerator::endInlineMemberDoc() +{ + if (!firstCol) t << endl; + t << ".br" << endl; + t << ".PP" << endl; + firstCol=TRUE; +} + diff --git a/trunk/src/mangen.h b/trunk/src/mangen.h new file mode 100644 index 0000000..5c8a863 --- /dev/null +++ b/trunk/src/mangen.h @@ -0,0 +1,262 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#ifndef MANGEN_H +#define MANGEN_H + +#include "outputgen.h" + +class QFile; + +class ManGenerator : public OutputGenerator +{ + public: + ManGenerator(); + ~ManGenerator(); + + //OutputGenerator *copy() { return new ManGenerator; } + //OutputGenerator *clone() { return new ManGenerator(*this); } + //void append(const OutputGenerator *o); + void enable() + { if (genStack->top()) active=*genStack->top(); else active=TRUE; } + void disable() { active=FALSE; } + void enableIf(OutputType o) { if (o==Man) enable(); } + void disableIf(OutputType o) { if (o==Man) disable(); } + void disableIfNot(OutputType o) { if (o!=Man) disable(); } + bool isEnabled(OutputType o) { return (o==Man && active); } + OutputGenerator *get(OutputType o) { return (o==Man) ? this : 0; } + + void printDoc(DocNode *,const char *); + + static void init(); + void startFile(const char *name,const char *manName,const char *title); + void writeSearchInfo() {} + void writeFooter() {} + void endFile(); + void clearBuffer(); + + void startIndexSection(IndexSections) {} + void endIndexSection(IndexSections) {} + void writePageLink(const char *,bool) {} + void startProjectNumber() {} + void endProjectNumber() {} + void writeStyleInfo(int) {} + void startTitleHead(const char *) {} + void endTitleHead(const char *,const char *); + void startTitle(); + void endTitle(); + + void newParagraph(); + void startParagraph(); + void endParagraph(); + void writeString(const char *text); + void startIndexListItem() {} + void endIndexListItem() {} + void startIndexList() {} + void endIndexList() { newParagraph(); } + void startIndexKey() {} + void endIndexKey() {} + void startIndexValue(bool) {} + void endIndexValue(const char *,bool) {} + void startItemList() {} + void endItemList() { newParagraph(); } + void startIndexItem(const char *ref,const char *file); + void endIndexItem(const char *ref,const char *file); + void docify(const char *text); + void codify(const char *text); + void writeObjectLink(const char *ref,const char *file, + const char *anchor,const char *name); + void writeCodeLink(const char *ref,const char *file, + const char *anchor,const char *name, + const char *tooltip); + void startTextLink(const char *,const char *) {} + void endTextLink() {} + void startHtmlLink(const char *url); + void endHtmlLink(); + void startTypewriter() { t << "\\fC"; firstCol=FALSE; } + void endTypewriter() { t << "\\fP"; firstCol=FALSE; } + void startGroupHeader(int); + void endGroupHeader(int); + void startMemberSections() {} + void endMemberSections() {} + void startHeaderSection() {} + void endHeaderSection() {} + void startMemberHeader(const char *); + void endMemberHeader(); + void insertMemberAlign(bool) {} + void startMemberSubtitle() {} + void endMemberSubtitle() {} + //void writeListItem(); + void startItemListItem(); + void endItemListItem(); + void startMemberDocList() {} + void endMemberDocList() {} + void startMemberList(); + void endMemberList(); + void startInlineHeader(); + void endInlineHeader(); + void startAnonTypeScope(int); + void endAnonTypeScope(int); + void startMemberItem(const char *,int); + void endMemberItem(); + void startMemberTemplateParams() {} + void endMemberTemplateParams(const char *) {} + + void startMemberGroupHeader(bool); + void endMemberGroupHeader(); + void startMemberGroupDocs(); + void endMemberGroupDocs(); + void startMemberGroup(); + void endMemberGroup(bool); + + void writeRuler() {} + void writeAnchor(const char *,const char *) {} + void startCodeFragment(); + void endCodeFragment(); + void writeLineNumber(const char *,const char *,const char *,int l) { t << l << " "; } + void startCodeLine() {} + void endCodeLine() { codify("\n"); col=0; } + void startEmphasis() { t << "\\fI"; firstCol=FALSE; } + void endEmphasis() { t << "\\fP"; firstCol=FALSE; } + void startBold() { t << "\\fB"; firstCol=FALSE; } + void endBold() { t << "\\fP"; firstCol=FALSE; } + void startDescription() {} + void endDescription() {} + void startDescItem(); + void endDescItem(); + void lineBreak(const char *) { t << "\n.br" << endl; } + void writeChar(char c); + void startMemberDoc(const char *,const char *,const char *,const char *,bool); + void endMemberDoc(bool); + void startDoxyAnchor(const char *,const char *,const char *,const char *,const char *); + void endDoxyAnchor(const char *,const char *) {} + void startCodeAnchor(const char *) {} + void endCodeAnchor() {} + void writeLatexSpacing() {} + void writeStartAnnoItem(const char *type,const char *file, + const char *path,const char *name); + void writeEndAnnoItem(const char *) { t << endl; firstCol=TRUE; } + void startSubsection(); + void endSubsection(); + void startSubsubsection(); + void endSubsubsection(); + void startCenter() {} + void endCenter() {} + void startSmall() {} + void endSmall() {} + void startMemberDescription(const char *) { t << "\n.RI \"\\fI"; firstCol=FALSE; } + void endMemberDescription() { t << "\\fP\""; firstCol=FALSE; } + void startDescList(SectionTypes); + void endDescList() {} + void startSimpleSect(SectionTypes,const char *,const char *,const char *); + void endSimpleSect(); + void startParamList(ParamListTypes,const char *title); + void endParamList(); + //void writeDescItem(); + void startDescForItem(); + void endDescForItem(); + void startSection(const char *,const char *,SectionInfo::SectionType); + void endSection(const char *,SectionInfo::SectionType); + void addIndexItem(const char *,const char *) {} + void startIndent() {} + void endIndent() {} + void writeSynopsis(); + void startClassDiagram() {} + void endClassDiagram(const ClassDiagram &,const char *,const char *) {} + void startPageRef() {} + void endPageRef(const char *,const char *) {} + void startQuickIndices() {} + void endQuickIndices() {} + void writeSplitBar(const char *) {} + void writeLogo() {} + void writeQuickLinks(bool,HighlightedItem,const char *) {} + void startContents() {} + void endContents() {} + void writeNonBreakableSpace(int n) { int i; for (i=0;i +#include +#include +#include +#include + +#include "markdown.h" +#include "growbuf.h" +#include "debug.h" +#include "util.h" +#include "doxygen.h" +#include "commentscan.h" +#include "entry.h" + +//----------- + +// is character at position i in data part of an identifier? +#define isIdChar(i) \ + ((data[i]>='a' && data[i]<='z') || \ + (data[i]>='A' && data[i]<='Z') || \ + (data[i]>='0' && data[i]<='9')) \ + +// is character at position i in data allowed before an emphasis section +#define isOpenEmphChar(i) \ + (data[i]=='\n' || data[i]==' ' || data[i]=='\'' || data[i]=='<' || \ + data[i]=='{' || data[i]=='(' || data[i]=='[' || data[i]==',' || \ + data[i]==':' || data[i]==';') + +// is character at position i in data an escape that prevents ending an emphasis section +// so for example *bla (*.txt) is cool* +#define ignoreCloseEmphChar(i) \ + (data[i]=='(' || data[i]=='{' || data[i]=='[' || data[i]=='<' || \ + data[i]=='=' || data[i]=='+' || data[i]=='-' || data[i]=='\\' || \ + data[i]=='@') + +//---------- + +struct LinkRef +{ + LinkRef(const QCString &l,const QCString &t) : link(l), title(t) {} + QCString link; + QCString title; +}; + +typedef int (*action_t)(GrowBuf &out,const char *data,int offset,int size); + +enum Alignment { AlignNone, AlignLeft, AlignCenter, AlignRight }; + + +//---------- + +static QDict g_linkRefs(257); +static action_t g_actions[256]; +static Entry *g_current; +static QCString g_fileName; +//static QDict g_htmlBlockTags(17); + +//---------- + +const int codeBlockIndent = 4; + +static void processInline(GrowBuf &out,const char *data,int size); + +// escape characters that have a special meaning later on. +static QCString escapeSpecialChars(const QCString &s) +{ + if (s.isEmpty()) return ""; + GrowBuf growBuf; + const char *p=s; + char c; + while ((c=*p++)) + { + switch (c) + { + case '<': growBuf.addStr("\\<"); break; + case '>': growBuf.addStr("\\>"); break; + case '\\': growBuf.addStr("\\\\"); break; + case '@': growBuf.addStr("\\@"); break; + default: growBuf.addChar(c); break; + } + } + growBuf.addChar(0); + return growBuf.get(); +} + +static void convertStringFragment(QCString &result,const char *data,int size) +{ + if (size<0) size=0; + result.resize(size+1); + memcpy(result.data(),data,size); + result.at(size)='\0'; +} + +/** helper function to convert presence of left and/or right alignment markers + * to a alignment value + */ +static Alignment markersToAlignment(bool leftMarker,bool rightMarker) +{ + //printf("markerToAlignment(%d,%d)\n",leftMarker,rightMarker); + if (leftMarker && rightMarker) + { + return AlignCenter; + } + else if (leftMarker) + { + return AlignLeft; + } + else if (rightMarker) + { + return AlignRight; + } + else + { + return AlignNone; + } +} + + +// Check if data contains a block command. If so returned the command +// that ends the block. If not an empty string is returned. +// Note When offset>0 character position -1 will be inspected. +// +// Checks for and skip the following block commands: +// {@code .. { .. } .. } +// \dot .. \enddot +// \code .. \endcode +// \msc .. \endmsc +// \f$..\f$ +// \f[..\f] +// \f{..\f} +// \verbatim..\endverbatim +// \latexonly..\endlatexonly +// \htmlonly..\endhtmlonly +// \xmlonly..\endxmlonly +// \rtfonly..\endrtfonly +// \manonly..\endmanonly +static QCString isBlockCommand(const char *data,int offset,int size) +{ + bool openBracket = offset>0 && data[-1]=='{'; + bool isEscaped = offset>0 && (data[-1]=='\\' || data[-1]=='@'); + if (isEscaped) return QCString(); + + int end=1; + while (end='a' && data[end]<='z')) end++; + if (end==1) return QCString(); + QCString blockName; + convertStringFragment(blockName,data+1,end-1); + if (blockName=="code" && openBracket) + { + return "}"; + } + else if (blockName=="dot" || + blockName=="code" || + blockName=="msc" || + blockName=="verbatim" || + blockName=="latexonly" || + blockName=="htmlonly" || + blockName=="xmlonly" || + blockName=="rtfonly" || + blockName=="manonly" + ) + { + return "end"+blockName; + } + else if (blockName=="f" && end0 && ignoreCloseEmphChar(i-1)) + { + i++; + continue; + } + else if (data[i] == c) + { + if (i=size || data[i]=='\n') return 0; // empty line -> paragraph + } + else // should not get here! + { + i++; + } + + } + return 0; +} + +/** process single emphasis */ +static int processEmphasis1(GrowBuf &out, const char *data, int size, char c) +{ + int i = 0, len; + + /* skipping one symbol if coming from emph3 */ + if (size>1 && data[0]==c && data[1]==c) { i=1; } + + while (i=size) return 0; + + if (i+1"); + processInline(out,data,i); + out.addStr(""); + return i+1; + } + } + return 0; +} + +/** process double emphasis */ +static int processEmphasis2(GrowBuf &out, const char *data, int size, char c) +{ + int i = 0, len; + + while (i"); + processInline(out,data,i); + out.addStr(""); + return i + 2; + } + i++; + } + return 0; +} + +/** Parsing single emphase. + * Finds the first closing tag, and delegates to the other emph + */ +static int processEmphasis3(GrowBuf &out, const char *data, int size, char c) +{ + int i = 0, len; + + while (i"); + processInline(out,data,i); + out.addStr(""); + return i+3; + } + else if (i+10 && data[-1]=='\\') return 0; // escaped < + + // find the end of the html tag + int i=1; + int l=0; + // compute length of the tag name + while (i tag + { + bool insideStr=FALSE; + while (i') + { // found tag, copy from start to end of tag + out.addStr(data,i+6); + //printf("found

    ..
    [%d..%d]\n",0,i+6); + return i+6; + } + } + else if (insideStr && c=='"') + { + if (data[i-1]!='\\') insideStr=FALSE; + } + else if (c=='"') + { + insideStr=TRUE; + } + i++; + } + } + else // some other html tag + { + if (l>0 && i') // + { + //printf("Found htmlTag={%s}\n",QCString(data).left(i+2).data()); + out.addStr(data,i+2); + return i+2; + } + else if (data[i]=='>') // + { + //printf("Found htmlTag={%s}\n",QCString(data).left(i+1).data()); + out.addStr(data,i+1); + return i+1; + } + else if (data[i]==' ') // ') // found end of tag + { + //printf("Found htmlTag={%s}\n",QCString(data).left(i+1).data()); + out.addStr(data,i+1); + return i+1; + } + i++; + } + } + } + } + //printf("Not a valid html tag\n"); + return 0; +} + +static int processEmphasis(GrowBuf &out,const char *data,int offset,int size) +{ + if ((offset>0 && !isOpenEmphChar(-1)) || // invalid char before * or _ + (size>1 && data[0]!=data[1] && !isIdChar(1)) || // invalid char after * or _ + (size>2 && data[0]==data[1] && !isIdChar(2))) // invalid char after ** or __ + { + return 0; + } + +#if 0 + if (offset>0 && size>1 && (isIdChar(-1) || data[-1]==data[0])) + { + if (isIdChar(1) || data[-1]==data[0]) + { + // avoid processing interal * and _ as cmd_id, or 4*10 as emphasis, + // also x**2,y*2 should not be processed + return 0; + } + else if (size>2 && data[0]==data[1] && isIdChar(2)) + { + // avoid processing interal ** and __ such as cmd__id__bla, + // or 4**10,5**10 as emphasis + return 0; + } + } +#endif + char c = data[0]; + int ret; + if (size>2 && data[1]!=c) // _bla or *bla + { + // whitespace cannot follow an opening emphasis + if (data[1]==' ' || data[1]=='\n' || + (ret = processEmphasis1(out, data+1, size-1, c)) == 0) + { + return 0; + } + return ret+1; + } + if (size>3 && data[1]==c && data[2]!=c) // __bla or **bla + { + if (data[2]==' ' || data[2]=='\n' || + (ret = processEmphasis2(out, data+2, size-2, c)) == 0) + { + return 0; + } + return ret+2; + } + if (size>4 && data[1]==c && data[2]==c && data[3]!=c) // ___bla or ***bla + { + if (data[3]==' ' || data[3]=='\n' || + (ret = processEmphasis3(out, data+3, size-3, c)) == 0) + { + return 0; + } + return ret+3; + } + return 0; +} + +static int processLink(GrowBuf &out,const char *data,int,int size) +{ + QCString content; + QCString link; + QCString title; + int contentStart,contentEnd,linkStart,titleStart,titleEnd; + bool isImageLink = FALSE; + bool isToc = FALSE; + int i=1; + if (data[0]=='!') + { + isImageLink = TRUE; + if (size<2 || data[1]!='[') + { + return 0; + } + i++; + } + contentStart=i; + int level=1; + int nl=0; + // find the matching ] + while (i1) return 0; // only allow one newline in the content + } + i++; + } + if (i>=size) return 0; // premature end of comment -> no link + contentEnd=i; + convertStringFragment(content,data+contentStart,contentEnd-contentStart); + //printf("processLink: content={%s}\n",content.data()); + if (!isImageLink && content.isEmpty()) return 0; // no link text + i++; // skip over ] + + // skip whitespace + while (i1) return 0; + } + i++; + } + if (i>=size || data[i]=='\n') return 0; + convertStringFragment(link,data+linkStart,i-linkStart); + link = link.stripWhiteSpace(); + //printf("processLink: link={%s}\n",link.data()); + if (link.isEmpty()) return 0; + if (link.at(link.length()-1)=='>') link=link.left(link.length()-1); + + // optional title + if (data[i]=='\'' || data[i]=='"') + { + char c = data[i]; + i++; + titleStart=i; + nl=0; + while (i1) return 0; + nl++; + } + i++; + } + if (i>=size) + { + return 0; + } + titleEnd = i-1; + // search back for closing marker + while (titleEnd>titleStart && data[titleEnd]==' ') titleEnd--; + if (data[titleEnd]==c) // found it + { + convertStringFragment(title,data+titleStart,titleEnd-titleStart); + //printf("processLink: title={%s}\n",title.data()); + } + else + { + return 0; + } + } + i++; + } + else if (i1) return 0; + } + i++; + } + if (i>=size) return 0; + // extract link + convertStringFragment(link,data+linkStart,i-linkStart); + //printf("processLink: link={%s}\n",link.data()); + link = link.stripWhiteSpace(); + if (link.isEmpty()) // shortcut link + { + link=content; + } + // lookup reference + LinkRef *lr = g_linkRefs.find(link.lower()); + if (lr) // found it + { + link = lr->link; + title = lr->title; + //printf("processLink: ref: link={%s} title={%s}\n",link.data(),title.data()); + } + else // reference not found! + { + //printf("processLink: ref {%s} do not exist\n",link.lower().data()); + return 0; + } + i++; + } + else if (ilink; + title = lr->title; + explicitTitle=TRUE; + i=contentEnd; + } + else if (content=="TOC") + { + isToc=TRUE; + i=contentEnd; + } + else + { + return 0; + } + i++; + } + else + { + return 0; + } + static QRegExp re("^[@\\]ref "); + if (isToc) // special case for [TOC] + { + if (g_current) g_current->stat=TRUE; + } + else if (isImageLink) + { + if (link.find("@ref ")!=-1 || link.find("\\ref ")!=-1) + // assume doxygen symbol link + { + out.addStr("@image html "); + out.addStr(link.mid(5)); + if (!explicitTitle && !content.isEmpty()) + { + out.addStr(" \""); + out.addStr(content); + out.addStr("\""); + } + else if ((content.isEmpty() || explicitTitle) && !title.isEmpty()) + { + out.addStr(" \""); + out.addStr(title); + out.addStr("\""); + } + } + else + { + out.addStr("\"");"); + } + } + else + { + if (link.find("@ref ")!=-1 || link.find("\\ref ")!=-1) + // assume doxygen symbol link + { + out.addStr(link); + out.addStr(" \""); + if (explicitTitle && !title.isEmpty()) + { + out.addStr(title); + } + else + { + out.addStr(content); + } + out.addStr("\""); + } + else if (link.find('/')!=-1 || link.find('.')!=-1 || link.find('#')!=-1) + { // file/url link + out.addStr(""); + out.addStr(content.simplifyWhiteSpace()); + out.addStr(""); + } + else // avoid link to e.g. F[x](y) + { + //printf("no link for '%s'\n",link.data()); + return 0; + } + } + return i; +} + +/** '`' parsing a code span (assuming codespan != 0) */ +static int processCodeSpan(GrowBuf &out, const char *data, int /*offset*/, int size) +{ + int end, nb = 0, i, f_begin, f_end; + + /* counting the number of backticks in the delimiter */ + while (nb= size) + { + return 0; // no matching delimiter + } + if (nl==2) // too many newlines inside the span + { + return 0; + } + + // trimming outside whitespaces + f_begin = nb; + while (f_begin < end && data[f_begin]==' ') + { + f_begin++; + } + f_end = end - nb; + while (f_end > nb && data[f_end-1]==' ') + { + f_end--; + } + + if (nb==1) // check for closing ' followed by space within f_begin..f_end + { + i=f_begin; + while (i"); + //out.addStr(convertToHtml(codeFragment,TRUE)); + out.addStr(escapeSpecialChars(codeFragment)); + out.addStr(""); + } + return end; +} + + +static int processSpecialCommand(GrowBuf &out, const char *data, int offset, int size) +{ + int i=1; + QCString endBlockName = isBlockCommand(data,offset,size); + if (!endBlockName.isEmpty()) + { + int l = endBlockName.length(); + while (i1 && data[0]=='\\') + { + char c=data[1]; + if (c=='[' || c==']' || c=='*' || c=='+' || c=='-' || + c=='!' || c=='(' || c==')' || c=='.' || c=='`' || c=='_') + { + out.addStr(&data[1],1); + return 2; + } + } + return 0; +} + +static void processInline(GrowBuf &out,const char *data,int size) +{ + int i=0, end=0; + action_t action = 0; + while (i=size) break; + i=end; + end = action(out,data+i,i,size-i); + if (!end) + { + end=i+1; + } + else + { + i+=end; + end=i; + } + } +} + +/** returns whether the line is a setext-style hdr underline */ +static int isHeaderline(const char *data, int size) +{ + int i = 0; + while (i=size || data[i]=='\n') ? 1 : 0; + } + // test of level 2 header + if (data[i]=='-') + { + while (i=size || data[i]=='\n') ? 2 : 0; + } + return 0; +} + +/** returns TRUE if this line starts a block quote */ +static bool isBlockQuote(const char *data,int size,int indent) +{ + int i = 0; + while (i's and skip spaces + int level=0; + while (i' || data[i]==' ')) + { + if (data[i]=='>') level++; + i++; + } + // last characters should be a space or newline, + // so a line starting with >= does not match + return level>0 && i code block + { + return FALSE; + } + //return i' && i=size || data[i]!='[') return 0; + i++; + int refIdStart=i; + while (i=size || data[i]!=']') return 0; + convertStringFragment(refid,data+refIdStart,i-refIdStart); + if (refid.isEmpty()) return 0; + //printf(" isLinkRef: found refid='%s'\n",refid.data()); + i++; + if (i>=size || data[i]!=':') return 0; + i++; + + // format: whitespace* \n? whitespace* ( | url) + while (i=size) return 0; + + if (i') i++; + if (linkStart==linkEnd) return 0; // empty link + convertStringFragment(link,data+linkStart,linkEnd-linkStart); + //printf(" isLinkRef: found link='%s'\n",link.data()); + if (link=="@ref" || link=="\\ref") + { + int argStart=i; + while (i=size) + { + //printf("end of isLinkRef while looking for title! i=%d\n",i); + return i; // end of buffer while looking for the optional title + } + + char c = data[i]; + if (c=='\'' || c=='"' || c=='(') // optional title present? + { + //printf(" start of title found! char='%c'\n",c); + i++; + if (c=='(') c=')'; // replace c by end character + int titleStart=i; + // search for end of the line + while (ititleStart && data[end]!=c) end--; + if (end>titleStart) + { + convertStringFragment(title,data+titleStart,end-titleStart); + } + //printf(" title found: '%s'\n",title.data()); + } + while (i=size) return i; // end of buffer while ref id was found + else if (data[i]=='\n') return i+1; // end of line while ref id was found + else if (eol) return eol; // no optional title found + return 0; // invalid link ref +} + +static int isHRuler(const char *data,int size) +{ + int i=0; + if (size>0 && data[size-1]=='\n') size--; // ignore newline character + while (i=size) return 0; // empty line + char c=data[i]; + if (c!='*' && c!='-' && c!='_') + { + return 0; // not a hrule character + } + int n=0; + while (i=3; // at least 3 characters needed for a hruler +} + +static QCString extractTitleId(QCString &title) +{ + //static QRegExp r1("^[a-z_A-Z][a-z_A-Z0-9\\-]*:"); + static QRegExp r2("\\{#[a-z_A-Z][a-z_A-Z0-9\\-]*\\}$"); + int l=0; + int i = r2.match(title,0,&l); + if (i!=-1) // found {#id} style id + { + QCString id = title.mid(i+2,l-3); + title = title.left(i)+title.mid(i+l); + //printf("found id='%s' title='%s'\n",id.data(),title.data()); + return id; + } + //i = r1.match(title,0,&l); + //if (i!=-1) // found id: style id + //{ + // QCString id = title.mid(i,l-1); + // title = title.left(i)+title.mid(i+l); + // //printf("found id='%s' title='%s'\n",id.data(),title.data()); + // return id; + //} + //printf("no id found in title '%s'\n",title.data()); + return ""; +} + + +static int isAtxHeader(const char *data,int size, + QCString &header,QCString &id) +{ + int i = 0, end; + int level = 0, blanks=0; + + // find start of header text and determine heading level + while (i=size || data[i]!='#') + { + return 0; + } + while (ii && (data[end-1]=='#' || data[end-1]==' ')) end--; + + // store result + convertStringFragment(header,data+i,end-i); + id = extractTitleId(header); + if (!id.isEmpty()) // strip #'s between title and id + { + i=header.length()-1; + while (i>=0 && (header.at(i)=='#' || header.at(i)==' ')) i--; + header=header.left(i+1); + } + + return level; +} + +static int isEmptyLine(const char *data,int size) +{ + int i=0; + while (i')) + +// compute the indent from the start of the input, excluding list markers +// such as -, -#, *, +, 1., and
  • +static int computeIndentExcludingListMarkers(const char *data,int size) +{ + int i=0; + int indent=0; + bool isDigit=FALSE; + bool isLi=FALSE; + bool listMarkerSkipped=FALSE; + while (i0 && data[i-1]=='-') || // -# item + (isDigit=(data[i]>='1' && data[i]<='9')) || // ordered list marker? + (isLi=(i tag + ) + ) + ) + ) + { + if (isDigit) // skip over ordered list marker '10. ' + { + int j=i+1; + while (j='0' && data[j]<='9') || data[j]=='.')) + { + if (data[j]=='.') // should be end of the list marker + { + if (j + indent+=3; + listMarkerSkipped=TRUE; + } + else if (data[i]=='-' && i%d\n",QCString(data).left(size).data(),indent); + return indent; +} + +static bool isFencedCodeBlock(const char *data,int size,int refIndent, + QCString &lang,int &start,int &end,int &offset) +{ + // rules: at least 3 ~~~, end of the block same amount of ~~~'s, otherwise + // return FALSE + int i=0; + int indent=0; + int startTildes=0; + while (i=refIndent+4) return FALSE; // part of code block + while (iisCodeBlock: line is not indented enough %d<4\n",indent0); + return FALSE; + } + + i=offset; + int nl=0; + int nl_pos[3]; + // search back 3 lines and remember the start of lines -1 and -2 + while (i>0 && nl<3) + { + if (data[i-offset-1]=='\n') nl_pos[nl++]=i-offset; + i--; + } + + // if there are only 2 preceding lines, then line -2 starts at -offset + if (i==0 && nl==2) nl_pos[nl++]=-offset; + //printf(" nl=%d\n",nl); + + if (nl==3) // we have at least 2 preceding lines + { + //printf(" positions: nl_pos=[%d,%d,%d] line[-2]='%s' line[-1]='%s'\n", + // nl_pos[0],nl_pos[1],nl_pos[2], + // QCString(data+nl_pos[1]).left(nl_pos[0]-nl_pos[1]-1).data(), + // QCString(data+nl_pos[2]).left(nl_pos[1]-nl_pos[2]-1).data()); + + // check that line -1 is empty + if (!isEmptyLine(data+nl_pos[1],nl_pos[0]-nl_pos[1]-1)) + { + return FALSE; + } + + // determine the indent of line -2 + indent=computeIndentExcludingListMarkers(data+nl_pos[2],nl_pos[1]-nl_pos[2]); + + //printf(">isCodeBlock local_indent %d>=%d+4=%d\n", + // indent0,indent2,indent0>=indent2+4); + // if the difference is >4 spaces -> code block + return indent0>=indent+codeBlockIndent; + } + else // not enough lines to determine the relative indent, use global indent + { + // check that line -1 is empty + if (nl==1 && !isEmptyLine(data-offset,offset-1)) + { + return FALSE; + } + //printf(">isCodeBlock global indent %d>=%d+4=%d\n", + // indent0,indent,indent0>=indent+4); + return indent0>=indent+codeBlockIndent; + } +} + +/** Finds the location of the table's contains in the string \a data. + * Only one line will be inspected. + * @param[in] data pointer to the string buffer. + * @param[in] size the size of the buffer. + * @param[out] start offset of the first character of the table content + * @param[out] end offset of the last character of the table content + * @param[out] columns number of table columns found + * @returns The offset until the next line in the buffer. + */ +int findTableColumns(const char *data,int size,int &start,int &end,int &columns) +{ + int i=0; + int eol; + // find start character of the table line + while (i0 && data[i]==' ') i--; + if (i>0 && data[i]=='|') i--; // trailing | does not count + end = i; + + // count columns between start and end + columns=1; + if (end>start) + { + i=start; + while (i<=end) + { + if (data[i]=='|' && (i==0 || data[i-1]!='\\')) columns++; + i++; + } + } + //printf("findTableColumns(start=%d,end=%d,columns=%d) eol=%d\n", + // start,end,columns,eol); + return eol; +} + +/** Returns TRUE iff data points to the start of a table block */ +static bool isTableBlock(const char *data,int size) +{ + int cc0,start,end; + + // the first line should have at least two columns separated by '|' + int i = findTableColumns(data,size,start,end,cc0); + if (i>=size || cc0<2) + { + //printf("isTableBlock: no |'s in the header\n"); + return FALSE; + } + + int cc1; + int ret = findTableColumns(data+i,size-i,start,end,cc1); + int j=i+start; + // separator line should consist of |, - and : and spaces only + while (j<=end+i) + { + if (data[j]!=':' && data[j]!='-' && data[j]!='|' && data[j]!=' ') + { + //printf("isTableBlock: invalid character '%c'\n",data[j]); + return FALSE; // invalid characters in table separator + } + j++; + } + if (cc1!=cc0) // number of columns should be same as previous line + { + return FALSE; + } + + i+=ret; // goto next line + int cc2; + ret = findTableColumns(data+i,size-i,start,end,cc2); + + //printf("isTableBlock: %d\n",cc1==cc2); + return cc1==cc2; +} + +static int writeTableBlock(GrowBuf &out,const char *data,int size) +{ + int i=0,j,k; + int columns,start,end,cc; + + i = findTableColumns(data,size,start,end,columns); + + out.addStr(""); + + // write table header, in range [start..end] + out.addStr(""); + + int headerStart = start; + int headerEnd = end; + + // read cell alignments + int ret = findTableColumns(data+i,size-i,start,end,cc); + k=0; + Alignment *columnAlignment = new Alignment[columns]; + + bool leftMarker=FALSE,rightMarker=FALSE; + bool startFound=FALSE; + j=start+i; + while (j<=end+i) + { + if (!startFound) + { + if (data[j]==':') { leftMarker=TRUE; startFound=TRUE; } + if (data[j]=='-') startFound=TRUE; + //printf(" data[%d]=%c startFound=%d\n",j,data[j],startFound); + } + if (data[j]=='-') rightMarker=FALSE; + else if (data[j]==':') rightMarker=TRUE; + if (j<=end+i && (data[j]=='|' && (j==0 || data[j-1]!='\\'))) + { + if (k"); + while (m<=headerEnd && (data[m]!='|' || (m>0 && data[m-1]=='\\'))) + { + out.addChar(data[m++]); + } + m++; + } + + // write table cells + while (i"); + j=start+i; + int columnStart=j; + k=0; + while (j<=end+i) + { + if (j==columnStart) + { + out.addStr(""); + } + if (j<=end+i && (data[j]=='|' && (j==0 || data[j-1]!='\\'))) + { + columnStart=j+1; + k++; + } + else + { + out.addChar(data[j]); + } + j++; + } + out.addChar('\n'); + + // proceed to next line + i+=ret; + } + + out.addStr("
    \n"); + + delete[] columnAlignment; + return i; +} + + +void writeOneLineHeaderOrRuler(GrowBuf &out,const char *data,int size) +{ + int level; + QCString header; + QCString id; + if (isHRuler(data,size)) + { + out.addStr("
    \n"); + } + else if ((level=isAtxHeader(data,size,header,id))) + { + QCString hTag; + if (level<5 && !id.isEmpty()) + { + SectionInfo::SectionType type = SectionInfo::Anchor; + switch(level) + { + case 1: out.addStr("@section "); + type=SectionInfo::Section; + break; + case 2: out.addStr("@subsection "); + type=SectionInfo::Subsection; + break; + case 3: out.addStr("@subsubsection "); + type=SectionInfo::Subsubsection; + break; + default: out.addStr("@paragraph "); + type=SectionInfo::Paragraph; + break; + } + out.addStr(id); + out.addStr(" "); + out.addStr(header); + SectionInfo *si = new SectionInfo(g_fileName,id,header,type,level); + if (g_current) + { + g_current->anchors->append(si); + } + Doxygen::sectionDict.append(header,si); + } + else + { + if (!id.isEmpty()) + { + out.addStr("\\anchor "+id+"\n"); + } + hTag.sprintf("h%d",level); + out.addStr("<"+hTag+">"); + out.addStr(header); + out.addStr("\n"); + } + } + else // nothing interesting -> just output the line + { + out.addStr(data,size); + } +} + +static int writeBlockQuote(GrowBuf &out,const char *data,int size) +{ + int l; + int i=0; + int curLevel=0; + int end=0; + while (i')) + { + if (data[j]=='>') { level++; indent=j+1; } + else if (j>0 && data[j-1]=='>') indent=j+1; + j++; + } + if (j>0 && data[j-1]=='>') // disqualify last > if not followed by space + { + indent--; + j--; + } + if (level>curLevel) // quote level increased => add start markers + { + for (l=curLevel;l\n"); + } + } + else if (level add end markers + { + for (l=level;l\n"); + } + } + curLevel=level; + if (level==0) break; // end of quote block + // copy line without quotation marks + out.addStr(data+indent,end-indent); + // proceed with next line + i=end; + } + // end of comment within blockquote => add end markers + for (l=0;l\n"); + } + return i; +} + +static int writeCodeBlock(GrowBuf &out,const char *data,int size,int refIndent) +{ + int i=0,end; + //printf("writeCodeBlock: data={%s}\n",QCString(data).left(size).data()); + out.addStr("@verbatim\n"); + while (i=refIndent+codeBlockIndent) // enough indent to contine the code block + { + // add code line minus the indent + out.addStr(data+i+refIndent+codeBlockIndent,end-i-refIndent-codeBlockIndent); + i=end; + } + else // end of code block + { + break; + } + } + out.addStr("@endverbatim\n"); + //printf("i=%d\n",i); + return i; +} + +// start searching for the end of the line start at offset \a i +// keeping track of possible blocks that need to to skipped. +static void findEndOfLine(GrowBuf &out,const char *data,int size, + int &pi,int&i,int &end) +{ + // find end of the line + int nb=0; + end=i+1; + while (end') //
     tag
    +      {
    +        if (pi!=-1) // output previous line if available
    +        {
    +          out.addStr(data+pi,i-pi);
    +        }
    +        // output part until 
    +        out.addStr(data+i,end-1-i); 
    +        // output part until 
    + i = end-1 + processHtmlTag(out,data+end-1,end-1,size-end+1); + pi=-1; + end = i+1; + break; + } + else + { + end++; + } + } + else if (nb==0 && data[end-1]=='`') + { + while (end0 && data[end-1]=='`') + { + int enb=0; + while (endcodeBlockIndent && isCodeBlock(data,0,end,blockIndent)) + { + i=writeCodeBlock(out,data,size,blockIndent); + end=i+1; + pi=-1; + } + + // process each line + while (i0) + { + //printf("Found header at %d-%d\n",i,end); + while (pianchors->append(si); + } + Doxygen::sectionDict.append(header,si); + } + else + { + out.addStr(level==1?"

    ":"

    "); + out.addStr(header); + out.addStr(level==1?"

    \n":"\n"); + } + } + else + { + out.addStr("
    \n"); + } + pi=-1; + i=end; + end=i+1; + continue; + } + else if ((ref=isLinkRef(data+pi,size-pi,id,link,title))) + { + //printf("found link ref: id='%s' link='%s' title='%s'\n", + // id.data(),link.data(),title.data()); + g_linkRefs.insert(id.lower(),new LinkRef(link,title)); + i=ref+pi; + pi=-1; + end=i+1; + } + else if (isFencedCodeBlock(data+pi,size-pi,indent,lang,blockStart,blockEnd,blockOffset)) + { + //printf("Found FencedCodeBlock lang='%s' start=%d end=%d code={%s}\n", + // lang.data(),blockStart,blockEnd,QCString(data+pi+blockStart).left(blockEnd-blockStart).data()); + if (!lang.isEmpty() && lang.at(0)=='.') lang=lang.mid(1); + if (lang.isEmpty()) out.addStr("@verbatim"); else out.addStr("@code"); + if (!lang.isEmpty()) + { + out.addStr("{"+lang+"}"); + } + out.addStr(data+pi+blockStart,blockEnd-blockStart); + out.addStr("\n"); + if (lang.isEmpty()) out.addStr("@endverbatim"); else out.addStr("@endcode"); + i=pi+blockOffset; + pi=-1; + end=i+1; + continue; + } + else if (isCodeBlock(data+i,i,end-i,blockIndent)) + { + // skip previous line (it is empty anyway) + i+=writeCodeBlock(out,data+i,size-i,blockIndent); + pi=-1; + end=i+1; + continue; + } + else if (isTableBlock(data+pi,size-pi)) + { + i=pi+writeTableBlock(out,data+pi,size-pi); + pi=-1; + end=i+1; + continue; + } + else + { + writeOneLineHeaderOrRuler(out,data+pi,i-pi); + } + } + pi=i; + i=end; + } + //printf("last line %d size=%d\n",i,size); + if (pi!=-1 && pi=size) return ""; + int end1=i+1; + while (end10) + { + docs=docs.mid(end1); + } + id = extractTitleId(title); + //printf("extractPageTitle(title='%s' docs='%s' id='%s')\n",title.data(),docs.data(),id.data()); + return title; +} + +static QCString detab(const QCString &s,int &refIndent) +{ + static int tabSize = Config_getInt("TAB_SIZE"); + GrowBuf out; + int size = s.length(); + const char *data = s.data(); + int i=0; + int col=0; + const int maxIndent=1000000; // value representing infinity + int minIndent=maxIndent; + while (i update minIndent + out.addChar(c); + if (collang = SrcLangExt_Markdown; + QCString docs = fileBuf; + QCString id; + QCString title=extractPageTitle(docs,id).stripWhiteSpace(); + QCString baseName = substitute(QFileInfo(fileName).baseName().utf8()," ","_"); + if (id.isEmpty()) id = "md_"+baseName; + if (title.isEmpty()) title = baseName; + if (id=="mainpage" || id=="index") + { + docs.prepend("@mainpage "+title+"\n"); + } + else + { + docs.prepend("@page "+id+" "+title+"\n"); + } + int lineNr=1; + int position=0; + + // even without markdown support enabled, we still + // parse markdown files as such + bool markdownEnabled = Doxygen::markdownSupport; + Doxygen::markdownSupport = TRUE; + + bool needsEntry; + Protection prot; + while (parseCommentBlock( + this, + current, + docs, + fileName, + lineNr, + FALSE, // isBrief + FALSE, // javadoc autobrief + FALSE, // inBodyDocs + prot, // protection + position, + needsEntry)) + { + if (needsEntry) + { + QCString docFile = current->docFile; + root->addSubEntry(current); + current = new Entry; + current->lang = SrcLangExt_Markdown; + current->docFile = docFile; + current->docLine = lineNr; + } + } + if (needsEntry) + { + root->addSubEntry(current); + } + + // restore setting + Doxygen::markdownSupport = markdownEnabled; +} + +void MarkdownFileParser::parseCode(CodeOutputInterface &codeOutIntf, + const char *scopeName, + const QCString &input, + bool isExampleBlock, + const char *exampleName, + FileDef *fileDef, + int startLine, + int endLine, + bool inlineFragment, + MemberDef *memberDef, + bool showLineNumbers + ) +{ + ParserInterface *pIntf = Doxygen::parserManager->getParser("*.cpp"); + if (pIntf!=this) + { + pIntf->parseCode( + codeOutIntf,scopeName,input,isExampleBlock,exampleName, + fileDef,startLine,endLine,inlineFragment,memberDef,showLineNumbers); + } +} + +void MarkdownFileParser::resetCodeParserState() +{ + ParserInterface *pIntf = Doxygen::parserManager->getParser("*.cpp"); + if (pIntf!=this) + { + pIntf->resetCodeParserState(); + } +} + +void MarkdownFileParser::parsePrototype(const char *text) +{ + ParserInterface *pIntf = Doxygen::parserManager->getParser("*.cpp"); + if (pIntf!=this) + { + pIntf->parsePrototype(text); + } +} + diff --git a/trunk/src/markdown.h b/trunk/src/markdown.h new file mode 100644 index 0000000..bff1100 --- /dev/null +++ b/trunk/src/markdown.h @@ -0,0 +1,54 @@ +/****************************************************************************** + * + * Copyright (C) 1997-2012 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. + * + */ + +#ifndef MARKDOWN_H +#define MARKDOWN_H + +#include +#include "parserintf.h" + +class Entry; + +/** processes string \a s and converts markdown into doxygen/html commands. */ +QCString processMarkdown(const QCString &fileName,Entry *e,const QCString &s); + +class MarkdownFileParser : public ParserInterface +{ + public: + virtual ~MarkdownFileParser() {} + void parseInput(const char *fileName, + const char *fileBuf, + Entry *root); + bool needsPreprocessing(const QCString &) { return FALSE; } + void parseCode(CodeOutputInterface &codeOutIntf, + const char *scopeName, + const QCString &input, + bool isExampleBlock, + const char *exampleName=0, + FileDef *fileDef=0, + int startLine=-1, + int endLine=-1, + bool inlineFragment=FALSE, + MemberDef *memberDef=0, + bool showLineNumbers=TRUE + ); + void resetCodeParserState(); + void parsePrototype(const char *text); +}; + + + + +#endif diff --git a/trunk/src/marshal.cpp b/trunk/src/marshal.cpp new file mode 100644 index 0000000..3ef97b8 --- /dev/null +++ b/trunk/src/marshal.cpp @@ -0,0 +1,830 @@ +#include +#include + +#include "sortdict.h" +#include "marshal.h" +#include "entry.h" +#include "section.h" +#include "memberlist.h" +#include "definition.h" +#include "groupdef.h" +#include "example.h" +#include "arguments.h" + +#define HEADER ('D'<<24)+('O'<<16)+('X'<<8)+'!' + +void marshalInt(StorageIntf *s,int v) +{ + uchar b[4]; + b[0]=((uint)v)>>24; + b[1]=(((uint)v)>>16)&0xff; + b[2]=(((uint)v)>>8)&0xff; + b[3]=v&0xff; + s->write((const char *)b,4); +} + +void marshalUInt(StorageIntf *s,uint v) +{ + uchar b[4]; + b[0]=v>>24; + b[1]=(v>>16)&0xff; + b[2]=(v>>8)&0xff; + b[3]=v&0xff; + s->write((const char *)b,4); +} + +void marshalBool(StorageIntf *s,bool b) +{ + char c = b; + s->write(&c,sizeof(char)); +} + +void marshalQCString(StorageIntf *s,const QCString &str) +{ + uint l=str.length(); + marshalUInt(s,l); + if (l>0) s->write(str.data(),l); +} + +void marshalQGString(StorageIntf *s,const QGString &str) +{ + uint l=str.length(); + marshalUInt(s,l); + if (l>0) s->write(str.data(),l); +} + +void marshalArgumentList(StorageIntf *s,ArgumentList *argList) +{ + if (argList==0) + { + marshalUInt(s,NULL_LIST); // null pointer representation + } + else + { + marshalUInt(s,argList->count()); + if (argList->count()>0) + { + ArgumentListIterator ali(*argList); + Argument *a; + for (ali.toFirst();(a=ali.current());++ali) + { + marshalQCString(s,a->attrib); + marshalQCString(s,a->type); + marshalQCString(s,a->canType); + marshalQCString(s,a->name); + marshalQCString(s,a->array); + marshalQCString(s,a->defval); + marshalQCString(s,a->docs); + } + } + marshalBool(s,argList->constSpecifier); + marshalBool(s,argList->volatileSpecifier); + marshalBool(s,argList->pureSpecifier); + } +} + +void marshalArgumentLists(StorageIntf *s,QList *argLists) +{ + if (argLists==0) + { + marshalUInt(s,NULL_LIST); // null pointer representation + } + else + { + marshalUInt(s,argLists->count()); + QListIterator ali(*argLists); + ArgumentList *al; + for (ali.toFirst();(al=ali.current());++ali) + { + marshalArgumentList(s,al); + } + } +} + +void marshalBaseInfoList(StorageIntf *s, QList *baseList) +{ + if (baseList==0) + { + marshalUInt(s,NULL_LIST); // null pointer representation + } + else + { + marshalUInt(s,baseList->count()); + QListIterator bli(*baseList); + BaseInfo *bi; + for (bli.toFirst();(bi=bli.current());++bli) + { + marshalQCString(s,bi->name); + marshalInt(s,(int)bi->prot); + marshalInt(s,(int)bi->virt); + } + } +} + +void marshalGroupingList(StorageIntf *s, QList *groups) +{ + if (groups==0) + { + marshalUInt(s,NULL_LIST); // null pointer representation + } + else + { + marshalUInt(s,groups->count()); + QListIterator gli(*groups); + Grouping *g; + for (gli.toFirst();(g=gli.current());++gli) + { + marshalQCString(s,g->groupname); + marshalInt(s,(int)g->pri); + } + } +} + +void marshalSectionInfoList(StorageIntf *s, QList *anchors) +{ + if (anchors==0) + { + marshalUInt(s,NULL_LIST); // null pointer representation + } + else + { + marshalUInt(s,anchors->count()); + QListIterator sli(*anchors); + SectionInfo *si; + for (sli.toFirst();(si=sli.current());++sli) + { + marshalQCString(s,si->label); + marshalQCString(s,si->title); + marshalQCString(s,si->ref); + marshalInt(s,(int)si->type); + marshalQCString(s,si->fileName); + marshalInt(s,si->level); + } + } +} + +void marshalItemInfoList(StorageIntf *s, QList *sli) +{ + if (sli==0) + { + marshalUInt(s,NULL_LIST); // null pointer representation + } + else + { + marshalUInt(s,sli->count()); + QListIterator liii(*sli); + ListItemInfo *lii; + for (liii.toFirst();(lii=liii.current());++liii) + { + marshalQCString(s,lii->type); + marshalInt(s,lii->itemId); + } + } +} + +void marshalObjPointer(StorageIntf *s,void *obj) +{ + char *b = (char *)&obj; + s->write(b,sizeof(void *)); +} + +void marshalSectionDict(StorageIntf *s,SectionDict *sections) +{ + if (sections==0) + { + marshalUInt(s,NULL_LIST); // null pointer representation + } + else + { + marshalUInt(s,sections->count()); + SDict::IteratorDict sli(*sections); + SectionInfo *si; + for (sli.toFirst();(si=sli.current());++sli) + { + marshalQCString(s,sli.currentKey()); + marshalObjPointer(s,si); + } + } +} + +void marshalMemberSDict(StorageIntf *s,MemberSDict *memberSDict) +{ + if (memberSDict==0) + { + marshalUInt(s,NULL_LIST); // null pointer representation + } + else + { + marshalUInt(s,memberSDict->count()); + //printf(" marshalMemberSDict: items=%d\n",memberSDict->count()); + SDict::IteratorDict mdi(*memberSDict); + MemberDef *md; + int count=0; + for (mdi.toFirst();(md=mdi.current());++mdi) + { + //printf(" marshalMemberSDict: %d: key=%s value=%p\n",count,mdi.currentKey().data(),md); + marshalQCString(s,mdi.currentKey()); + marshalObjPointer(s,md); + count++; + } + assert(count==memberSDict->count()); + } +} + +void marshalDocInfo(StorageIntf *s,DocInfo *docInfo) +{ + if (docInfo==0) + { + marshalUInt(s,NULL_LIST); // null pointer representation + } + else + { + marshalUInt(s,1); + marshalQCString(s,docInfo->doc); + marshalInt(s,docInfo->line); + marshalQCString(s,docInfo->file); + } +} + +void marshalBriefInfo(StorageIntf *s,BriefInfo *briefInfo) +{ + if (briefInfo==0) + { + marshalUInt(s,NULL_LIST); // null pointer representation + } + else + { + marshalUInt(s,1); + marshalQCString(s,briefInfo->doc); + marshalQCString(s,briefInfo->tooltip); + marshalInt(s,briefInfo->line); + marshalQCString(s,briefInfo->file); + } +} + +void marshalBodyInfo(StorageIntf *s,BodyInfo *bodyInfo) +{ + if (bodyInfo==0) + { + marshalUInt(s,NULL_LIST); // null pointer representation + } + else + { + marshalUInt(s,1); + marshalInt(s,bodyInfo->startLine); + marshalInt(s,bodyInfo->endLine); + marshalObjPointer(s,bodyInfo->fileDef); + } +} + +void marshalGroupList(StorageIntf *s,GroupList *groupList) +{ + if (groupList==0) + { + marshalUInt(s,NULL_LIST); // null pointer representation + } + else + { + marshalUInt(s,groupList->count()); + QListIterator gli(*groupList); + GroupDef *gd=0; + for (gli.toFirst();(gd=gli.current());++gli) + { + marshalObjPointer(s,gd); + } + } +} + +void marshalMemberList(StorageIntf *s,MemberList *ml) +{ + if (ml==0) + { + marshalUInt(s,NULL_LIST); // null pointer representation + } + else + { + marshalUInt(s,ml->count()); + MemberListIterator mli(*ml); + MemberDef *md; + uint count=0; + for (mli.toFirst();(md=mli.current());++mli) + { + marshalObjPointer(s,md); + count++; + } + assert(count==ml->count()); + + ml->marshal(s); + } +} + +void marshalExampleSDict(StorageIntf *s,ExampleSDict *ed) +{ + if (ed==0) + { + marshalUInt(s,NULL_LIST); // null pointer representation + } + else + { + marshalUInt(s,ed->count()); + //printf(" marshalMemberSDict: items=%d\n",memberSDict->count()); + SDict::IteratorDict edi(*ed); + Example *e; + for (edi.toFirst();(e=edi.current());++edi) + { + //printf(" marshalMemberSDict: %d: key=%s value=%p\n",count,mdi.currentKey().data(),md); + marshalQCString(s,edi.currentKey()); + marshalQCString(s,e->anchor); + marshalQCString(s,e->name); + marshalQCString(s,e->file); + } + } +} + +void marshalMemberLists(StorageIntf *s,SDict *mls) +{ + if (mls==0) + { + marshalUInt(s,NULL_LIST); // null pointer representation + } + else + { + marshalUInt(s,mls->count()); + //printf(" marshalMemberSDict: items=%d\n",memberSDict->count()); + SDict::IteratorDict mli(*mls); + MemberList *ml; + for (mli.toFirst();(ml=mli.current());++mli) + { + //printf(" marshalMemberSDict: %d: key=%s value=%p\n",count,mdi.currentKey().data(),md); + marshalQCString(s,mli.currentKey()); + marshalObjPointer(s,ml); // assume we are not owner of the list + } + } +} + +void marshalEntry(StorageIntf *s,Entry *e) +{ + marshalUInt(s,HEADER); + marshalQCString(s,e->name); + marshalQCString(s,e->type); + marshalInt(s,e->section); + marshalInt(s,(int)e->protection); + marshalInt(s,(int)e->mtype); + marshalInt(s,e->spec); + marshalInt(s,e->initLines); + marshalBool(s,e->stat); + marshalBool(s,e->explicitExternal); + marshalBool(s,e->proto); + marshalBool(s,e->subGrouping); + marshalBool(s,e->callGraph); + marshalBool(s,e->callerGraph); + marshalInt(s,(int)e->virt); + marshalQCString(s,e->args); + marshalQCString(s,e->bitfields); + marshalArgumentList(s,e->argList); + marshalArgumentLists(s,e->tArgLists); + marshalQGString(s,e->program); + marshalQGString(s,e->initializer); + marshalQCString(s,e->includeFile); + marshalQCString(s,e->includeName); + marshalQCString(s,e->doc); + marshalInt(s,e->docLine); + marshalQCString(s,e->docFile); + marshalQCString(s,e->brief); + marshalInt(s,e->briefLine); + marshalQCString(s,e->briefFile); + marshalQCString(s,e->inbodyDocs); + marshalInt(s,e->inbodyLine); + marshalQCString(s,e->inbodyFile); + marshalQCString(s,e->relates); + marshalInt(s,e->relatesType); + marshalQCString(s,e->read); + marshalQCString(s,e->write); + marshalQCString(s,e->inside); + marshalQCString(s,e->exception); + marshalArgumentList(s,e->typeConstr); + marshalInt(s,e->bodyLine); + marshalInt(s,e->endBodyLine); + marshalInt(s,e->mGrpId); + marshalBaseInfoList(s,e->extends); + marshalGroupingList(s,e->groups); + marshalSectionInfoList(s,e->anchors); + marshalQCString(s,e->fileName); + marshalInt(s,e->startLine); + marshalItemInfoList(s,e->sli); + marshalInt(s,(int)e->lang); + marshalBool(s,e->hidden); + marshalBool(s,e->artificial); + marshalInt(s,(int)e->groupDocType); +} + +void marshalEntryTree(StorageIntf *s,Entry *e) +{ + marshalEntry(s,e); + marshalUInt(s,e->children()->count()); + QListIterator eli(*e->children()); + Entry *child; + for (eli.toFirst();(child=eli.current());++eli) + { + marshalEntryTree(s,child); + } +} + +//------------------------------------------------------------------ + +int unmarshalInt(StorageIntf *s) +{ + uchar b[4]; + s->read((char *)b,4); + int result=(int)((((uint)b[0])<<24)+((uint)b[1]<<16)+((uint)b[2]<<8)+(uint)b[3]); + //printf("unmarshalInt: %x %x %x %x: %x offset=%llx\n",b[0],b[1],b[2],b[3],result,f.pos()); + return result; +} + +uint unmarshalUInt(StorageIntf *s) +{ + uchar b[4]; + s->read((char *)b,4); + uint result=(((uint)b[0])<<24)+((uint)b[1]<<16)+((uint)b[2]<<8)+(uint)b[3]; + //printf("unmarshalUInt: %x %x %x %x: %x offset=%llx\n",b[0],b[1],b[2],b[3],result,f.pos()); + return result; +} + +bool unmarshalBool(StorageIntf *s) +{ + char result; + s->read(&result,sizeof(result)); + //printf("unmarshalBool: %x offset=%llx\n",result,f.pos()); + return result; +} + +QCString unmarshalQCString(StorageIntf *s) +{ + uint len = unmarshalUInt(s); + //printf("unmarshalQCString: len=%d offset=%llx\n",len,f.pos()); + QCString result(len+1); + result.at(len)='\0'; + if (len>0) + { + s->read(result.data(),len); + } + //printf("unmarshalQCString: result=%s\n",result.data()); + return result; +} + +QGString unmarshalQGString(StorageIntf *s) +{ + uint len = unmarshalUInt(s); + //printf("unmarshalQCString: len=%d offset=%llx\n",len,f.pos()); + QGString result(len+1); + result.at(len)='\0'; + if (len>0) + { + s->read(result.data(),len); + } + //printf("unmarshalQCString: result=%s\n",result.data()); + return result; +} + +ArgumentList *unmarshalArgumentList(StorageIntf *s) +{ + uint i; + uint count = unmarshalUInt(s); + if (count==NULL_LIST) return 0; // null list + ArgumentList *result = new ArgumentList; + assert(count<1000000); + //printf("unmarshalArgumentList: %d\n",count); + for (i=0;iattrib = unmarshalQCString(s); + a->type = unmarshalQCString(s); + a->canType = unmarshalQCString(s); + a->name = unmarshalQCString(s); + a->array = unmarshalQCString(s); + a->defval = unmarshalQCString(s); + a->docs = unmarshalQCString(s); + result->append(a); + } + result->constSpecifier = unmarshalBool(s); + result->volatileSpecifier = unmarshalBool(s); + result->pureSpecifier = unmarshalBool(s); + return result; +} + +QList *unmarshalArgumentLists(StorageIntf *s) +{ + uint i; + uint count = unmarshalUInt(s); + if (count==NULL_LIST) return 0; // null list + QList *result = new QList; + result->setAutoDelete(TRUE); + assert(count<1000000); + //printf("unmarshalArgumentLists: %d\n",count); + for (i=0;iappend(unmarshalArgumentList(s)); + } + return result; +} + +QList *unmarshalBaseInfoList(StorageIntf *s) +{ + uint i; + uint count = unmarshalUInt(s); + if (count==NULL_LIST) return 0; // null list + QList *result = new QList; + result->setAutoDelete(TRUE); + assert(count<1000000); + for (i=0;iappend(new BaseInfo(name,prot,virt)); + } + return result; +} + +QList *unmarshalGroupingList(StorageIntf *s) +{ + uint i; + uint count = unmarshalUInt(s); + if (count==NULL_LIST) return 0; // null list + QList *result = new QList; + result->setAutoDelete(TRUE); + assert(count<1000000); + for (i=0;iappend(new Grouping(name,prio)); + } + return result; +} + +QList *unmarshalSectionInfoList(StorageIntf *s) +{ + uint i; + uint count = unmarshalUInt(s); + if (count==NULL_LIST) return 0; // null list + QList *result = new QList; + result->setAutoDelete(TRUE); + assert(count<1000000); + for (i=0;iappend(new SectionInfo(fileName,label,title,type,level,ref)); + } + return result; +} + +QList *unmarshalItemInfoList(StorageIntf *s) +{ + uint i; + uint count = unmarshalUInt(s); + if (count==NULL_LIST) return 0; // null list + QList *result = new QList; + result->setAutoDelete(TRUE); + assert(count<1000000); + for (i=0;itype = unmarshalQCString(s); + lii->itemId = unmarshalInt(s); + result->append(lii); + } + return result; +} + +void *unmarshalObjPointer(StorageIntf *s) +{ + void *result; + s->read((char *)&result,sizeof(void*)); + return result; +} + +SectionDict *unmarshalSectionDict(StorageIntf *s) +{ + uint i; + uint count = unmarshalUInt(s); + //printf("unmarshalSectionDict count=%d\n",count); + if (count==NULL_LIST) return 0; // null list + SectionDict *result = new SectionDict(17); + assert(count<1000000); + for (i=0;ilabel.data()); + result->append(key,si); + } + return result; +} + +MemberSDict *unmarshalMemberSDict(StorageIntf *s) +{ + uint i; + uint count = unmarshalUInt(s); + //printf("--- unmarshalMemberSDict count=%d\n",count); + if (count==NULL_LIST) + { + //printf("--- end unmarshalMemberSDict\n"); + return 0; // null list + } + MemberSDict *result = new MemberSDict; + assert(count<1000000); + //printf("Reading %d key-value pairs\n",count); + for (i=0;iappend(key,md); + } + + //printf("--- end unmarshalMemberSDict\n"); + return result; +} + +DocInfo *unmarshalDocInfo(StorageIntf *s) +{ + uint count = unmarshalUInt(s); + if (count==NULL_LIST) return 0; + DocInfo *result = new DocInfo; + result->doc = unmarshalQCString(s); + result->line = unmarshalInt(s); + result->file = unmarshalQCString(s); + return result; +} + +BriefInfo *unmarshalBriefInfo(StorageIntf *s) +{ + uint count = unmarshalUInt(s); + if (count==NULL_LIST) return 0; + BriefInfo *result = new BriefInfo; + result->doc = unmarshalQCString(s); + result->tooltip = unmarshalQCString(s); + result->line = unmarshalInt(s); + result->file = unmarshalQCString(s); + return result; +} + +BodyInfo *unmarshalBodyInfo(StorageIntf *s) +{ + uint count = unmarshalUInt(s); + if (count==NULL_LIST) return 0; + BodyInfo *result = new BodyInfo; + result->startLine = unmarshalInt(s); + result->endLine = unmarshalInt(s); + result->fileDef = (FileDef*)unmarshalObjPointer(s); + return result; +} + +GroupList *unmarshalGroupList(StorageIntf *s) +{ + uint i; + uint count = unmarshalUInt(s); + if (count==NULL_LIST) return 0; // null list + assert(count<1000000); + GroupList *result = new GroupList; + for (i=0;iappend(gd); + } + return result; +} + +MemberList *unmarshalMemberList(StorageIntf *s) +{ + uint i; + uint count = unmarshalUInt(s); + if (count==NULL_LIST) return 0; + MemberList *result = new MemberList; + assert(count<1000000); + for (i=0;iappend(md); + } + result->unmarshal(s); + return result; +} + +ExampleSDict *unmarshalExampleSDict(StorageIntf *s) +{ + uint i; + uint count = unmarshalUInt(s); + if (count==NULL_LIST) return 0; + ExampleSDict *result = new ExampleSDict; + assert(count<1000000); + for (i=0;ianchor = unmarshalQCString(s); + e->name = unmarshalQCString(s); + e->file = unmarshalQCString(s); + result->inSort(key,e); + } + return result; +} + +SDict *unmarshalMemberLists(StorageIntf *s) +{ + uint i; + uint count = unmarshalUInt(s); + if (count==NULL_LIST) return 0; + SDict *result = new SDict(7); + assert(count<1000000); + for (i=0;iappend(key,ml); + } + return result; +} + +Entry * unmarshalEntry(StorageIntf *s) +{ + Entry *e = new Entry; + uint header=unmarshalUInt(s); + ASSERT(header==HEADER); + e->name = unmarshalQCString(s); + e->type = unmarshalQCString(s); + e->section = unmarshalInt(s); + e->protection = (Protection)unmarshalInt(s); + e->mtype = (MethodTypes)unmarshalInt(s); + e->spec = unmarshalInt(s); + e->initLines = unmarshalInt(s); + e->stat = unmarshalBool(s); + e->explicitExternal = unmarshalBool(s); + e->proto = unmarshalBool(s); + e->subGrouping = unmarshalBool(s); + e->callGraph = unmarshalBool(s); + e->callerGraph = unmarshalBool(s); + e->virt = (Specifier)unmarshalInt(s); + e->args = unmarshalQCString(s); + e->bitfields = unmarshalQCString(s); + delete e->argList; + e->argList = unmarshalArgumentList(s); + e->tArgLists = unmarshalArgumentLists(s); + e->program = unmarshalQGString(s); + e->initializer = unmarshalQGString(s); + e->includeFile = unmarshalQCString(s); + e->includeName = unmarshalQCString(s); + e->doc = unmarshalQCString(s); + e->docLine = unmarshalInt(s); + e->docFile = unmarshalQCString(s); + e->brief = unmarshalQCString(s); + e->briefLine = unmarshalInt(s); + e->briefFile = unmarshalQCString(s); + e->inbodyDocs = unmarshalQCString(s); + e->inbodyLine = unmarshalInt(s); + e->inbodyFile = unmarshalQCString(s); + e->relates = unmarshalQCString(s); + e->relatesType = (RelatesType)unmarshalInt(s); + e->read = unmarshalQCString(s); + e->write = unmarshalQCString(s); + e->inside = unmarshalQCString(s); + e->exception = unmarshalQCString(s); + e->typeConstr = unmarshalArgumentList(s); + e->bodyLine = unmarshalInt(s); + e->endBodyLine = unmarshalInt(s); + e->mGrpId = unmarshalInt(s); + delete e->extends; + e->extends = unmarshalBaseInfoList(s); + delete e->groups; + e->groups = unmarshalGroupingList(s); + delete e->anchors; + e->anchors = unmarshalSectionInfoList(s); + e->fileName = unmarshalQCString(s); + e->startLine = unmarshalInt(s); + e->sli = unmarshalItemInfoList(s); + e->lang = (SrcLangExt)unmarshalInt(s); + e->hidden = unmarshalBool(s); + e->artificial = unmarshalBool(s); + e->groupDocType = (Entry::GroupDocType)unmarshalInt(s); + return e; +} + +Entry * unmarshalEntryTree(StorageIntf *s) +{ + Entry *e = unmarshalEntry(s); + uint count = unmarshalUInt(s); + uint i; + for (i=0;iaddSubEntry(unmarshalEntryTree(s)); + } + return e; +} diff --git a/trunk/src/marshal.h b/trunk/src/marshal.h new file mode 100644 index 0000000..0360dca --- /dev/null +++ b/trunk/src/marshal.h @@ -0,0 +1,95 @@ +/****************************************************************************** + * + * Copyright (C) 1997-2012 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. + * + */ + +#ifndef MARSHAL_H +#define MARSHAL_H + +#include +#include +#include "sortdict.h" +#include "store.h" + +class ArgumentList; +struct BaseInfo; +struct Grouping; +struct SectionInfo; +struct ListItemInfo; +class QCString; +class QGString; +class SectionDict; +class MemberSDict; +class GroupList; +struct BodyInfo; +struct DocInfo; +struct BriefInfo; +class MemberList; +class ExampleSDict; +class Entry; + +#define NULL_LIST 0xffffffff + +//----- marshaling function: datatype -> byte stream -------------------- + +void marshalInt(StorageIntf *s,int v); +void marshalUInt(StorageIntf *s,uint v); +void marshalBool(StorageIntf *s,bool b); +void marshalQCString(StorageIntf *s,const QCString &str); +void marshalQGString(StorageIntf *s,const QGString &str); +void marshalArgumentList(StorageIntf *s,ArgumentList *argList); +void marshalArgumentLists(StorageIntf *s,QList *argLists); +void marshalBaseInfoList(StorageIntf *s, QList *baseList); +void marshalGroupingList(StorageIntf *s, QList *groups); +void marshalSectionInfoList(StorageIntf *s, QList *anchors); +void marshalItemInfoList(StorageIntf *s, QList *sli); +void marshalObjPointer(StorageIntf *s,void *obj); +void marshalSectionDict(StorageIntf *s,SectionDict *sections); +void marshalMemberSDict(StorageIntf *s,MemberSDict *memberSDict); +void marshalDocInfo(StorageIntf *s,DocInfo *docInfo); +void marshalBriefInfo(StorageIntf *s,BriefInfo *briefInfo); +void marshalBodyInfo(StorageIntf *s,BodyInfo *bodyInfo); +void marshalGroupList(StorageIntf *s,GroupList *groupList); +void marshalMemberList(StorageIntf *s,MemberList *ml); +void marshalExampleSDict(StorageIntf *s,ExampleSDict *ed); +void marshalMemberLists(StorageIntf *s,SDict *mls); +void marshalEntry(StorageIntf *s,Entry *e); +void marshalEntryTree(StorageIntf *s,Entry *e); + +//----- unmarshaling function: byte stream -> datatype ------------------ + +int unmarshalInt(StorageIntf *s); +uint unmarshalUInt(StorageIntf *s); +bool unmarshalBool(StorageIntf *s); +QCString unmarshalQCString(StorageIntf *s); +QGString unmarshalQGString(StorageIntf *s); +ArgumentList * unmarshalArgumentList(StorageIntf *s); +QList *unmarshalArgumentLists(StorageIntf *s); +QList * unmarshalBaseInfoList(StorageIntf *s); +QList * unmarshalGroupingList(StorageIntf *s); +QList * unmarshalSectionInfoList(StorageIntf *s); +QList *unmarshalItemInfoList(StorageIntf *s); +void * unmarshalObjPointer(StorageIntf *s); +SectionDict * unmarshalSectionDict(StorageIntf *s); +MemberSDict * unmarshalMemberSDict(StorageIntf *s); +DocInfo * unmarshalDocInfo(StorageIntf *s); +BriefInfo * unmarshalBriefInfo(StorageIntf *s); +BodyInfo * unmarshalBodyInfo(StorageIntf *s); +GroupList * unmarshalGroupList(StorageIntf *s); +MemberList * unmarshalMemberList(StorageIntf *s); +ExampleSDict * unmarshalExampleSDict(StorageIntf *s); +SDict * unmarshalMemberLists(StorageIntf *s); +Entry * unmarshalEntry(StorageIntf *s); +Entry * unmarshalEntryTree(StorageIntf *s); + +#endif diff --git a/trunk/src/memberdef.cpp b/trunk/src/memberdef.cpp new file mode 100644 index 0000000..8ea32e0 --- /dev/null +++ b/trunk/src/memberdef.cpp @@ -0,0 +1,4507 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#include +#include +#include +#include +#include "md5.h" +#include "memberdef.h" +#include "membername.h" +#include "doxygen.h" +#include "util.h" +#include "code.h" +#include "message.h" +#include "htmlhelp.h" +#include "language.h" +#include "outputlist.h" +#include "example.h" +#include "membergroup.h" +#include "groupdef.h" +#include "defargs.h" +#include "docparser.h" +#include "dot.h" +#include "searchindex.h" +#include "parserintf.h" +#include "marshal.h" +#include "objcache.h" +#include "vhdlscanner.h" +#include "vhdldocgen.h" +#include "arguments.h" + +#define START_MARKER 0x4D454D5B // MEM[ +#define END_MARKER 0x4D454D5D // MEM] + +#if defined(_OS_WIN32_) +#define snprintf _snprintf +#endif + +// Put this macro at the start of any method of MemberDef that can directly +// or indirectly access other MemberDefs. It prevents that the content +// pointed to by m_impl gets flushed to disk in the middle of the method call! +#define KEEP_RESIDENT_DURING_CALL makeResident();LockingPtr lock(this,this) + +//----------------------------------------------------------------------------- + +int MemberDef::s_indentLevel = 0; + +//----------------------------------------------------------------------------- + +static QCString addTemplateNames(const QCString &s,const QCString &n,const QCString &t) +{ + QCString result; + QCString clRealName=n; + int p=0,i; + if ((i=clRealName.find('<'))!=-1) + { + clRealName=clRealName.left(i); // strip template specialization + } + if ((i=clRealName.findRev("::"))!=-1) + { + clRealName=clRealName.right(clRealName.length()-i-2); + } + while ((i=s.find(clRealName,p))!=-1) + { + result+=s.mid(p,i-p); + uint j=clRealName.length()+i; + if (s.length()==j || (s.at(j)!='<' && !isId(s.at(j)))) + { // add template names + //printf("Adding %s+%s\n",clRealName.data(),t.data()); + result+=clRealName+t; + } + else + { // template names already present + //printf("Adding %s\n",clRealName.data()); + result+=clRealName; + } + p=i+clRealName.length(); + } + result+=s.right(s.length()-p); + //printf("addTemplateNames(%s,%s,%s)=%s\n",s.data(),n.data(),t.data(),result.data()); + return result; +} + +static bool writeDefArgumentList(OutputList &ol,ClassDef *cd, + const QCString & /*scopeName*/,MemberDef *md) +{ + LockingPtr defArgList=(md->isDocsForDefinition()) ? + md->argumentList() : md->declArgumentList(); + //printf("writeDefArgumentList `%s' isDocsForDefinition()=%d\n",md->name().data(),md->isDocsForDefinition()); + if (defArgList==0 || md->isProperty()) + { + return FALSE; // member has no function like argument list + } + if (!md->isDefine()) ol.docify(" "); + + // simple argument list for tcl + if (md->getLanguage()==SrcLangExt_Tcl) + { + Argument *a=defArgList->first(); + ol.startParameterName(FALSE); + while (a) + { + if (a->defval.isEmpty()) + { + ol.docify(a->name+" "); + } + else + { + ol.docify("?"+a->name+"? "); + } + a=defArgList->next(); + } + ol.endParameterName(FALSE,FALSE,FALSE); + ol.endMemberDocName(); + return TRUE; + } + + //printf("writeDefArgList(%d)\n",defArgList->count()); + ol.pushGeneratorState(); + //ol.disableAllBut(OutputGenerator::Html); + bool htmlOn = ol.isEnabled(OutputGenerator::Html); + bool latexOn = ol.isEnabled(OutputGenerator::Latex); + { + // html and latex + if (htmlOn) ol.enable(OutputGenerator::Html); + if (latexOn) ol.enable(OutputGenerator::Latex); + + ol.endMemberDocName(); + ol.startParameterList(!md->isObjCMethod()); + } + ol.enableAll(); + ol.disable(OutputGenerator::Html); + ol.disable(OutputGenerator::Latex); + { + // other formats + if (!md->isObjCMethod()) ol.docify("("); // start argument list + ol.endMemberDocName(); + } + ol.popGeneratorState(); + //printf("===> name=%s isDefine=%d\n",md->name().data(),md->isDefine()); + + Argument *a=defArgList->first(); + QCString cName; + if (cd) + { + cName=cd->name(); + int il=cName.find('<'); + int ir=cName.findRev('>'); + if (il!=-1 && ir!=-1 && ir>il) + { + cName=cName.mid(il,ir-il+1); + //printf("1. cName=%s\n",cName.data()); + } + else if (cd->templateArguments()) + { + cName=tempArgListToString(cd->templateArguments()); + //printf("2. cName=%s\n",cName.data()); + } + else // no template specifier + { + cName.resize(0); + } + } + //printf("~~~ %s cName=%s\n",md->name().data(),cName.data()); + + bool first=TRUE; + bool paramTypeStarted=FALSE; + bool isDefine = md->isDefine(); + while (a) + { + if (isDefine || first) + { + ol.startParameterType(first,0); + paramTypeStarted=TRUE; + if (isDefine) + { + ol.endParameterType(); + ol.startParameterName(TRUE); + } + } + QRegExp re(")("),res("(.*\\*"); + int vp=a->type.find(re); + int wp=a->type.find(res); + + // use the following to put the function pointer type before the name + bool hasFuncPtrType=FALSE; + + if (!a->attrib.isEmpty() && !md->isObjCMethod()) // argument has an IDL attribute + { + ol.docify(a->attrib+" "); + } + if (hasFuncPtrType) // argument type is a function pointer + { + //printf("a->type=`%s' a->name=`%s'\n",a->type.data(),a->name.data()); + QCString n=a->type.left(vp); + if (hasFuncPtrType) n=a->type.left(wp); + if (md->isObjCMethod()) { n.prepend("("); n.append(")"); } + if (!cName.isEmpty()) n=addTemplateNames(n,cd->name(),cName); + linkifyText(TextGeneratorOLImpl(ol),cd,md->getBodyDef(),md->name(),n); + } + else // non-function pointer type + { + QCString n=a->type; + if (md->isObjCMethod()) { n.prepend("("); n.append(")"); } + if (a->type!="...") + { + if (!cName.isEmpty()) n=addTemplateNames(n,cd->name(),cName); + linkifyText(TextGeneratorOLImpl(ol),cd,md->getBodyDef(),md->name(),n); + } + } + if (!isDefine) + { + if (paramTypeStarted) + { + ol.endParameterType(); + paramTypeStarted=FALSE; + } + ol.startParameterName(defArgList->count()<2); + } + if (hasFuncPtrType) + { + ol.docify(a->type.mid(wp,vp-wp)); + } + if (!a->name.isEmpty() || (a->name.isEmpty() && a->type=="...")) // argument has a name + { + //if (!hasFuncPtrType) + //{ + // ol.docify(" "); + //} + ol.disable(OutputGenerator::Man); + ol.disable(OutputGenerator::Latex); + ol.startEmphasis(); + ol.enable(OutputGenerator::Man); + if (latexOn) ol.enable(OutputGenerator::Latex); + if (a->name.isEmpty()) ol.docify(a->type); else ol.docify(a->name); + ol.disable(OutputGenerator::Man); + ol.disable(OutputGenerator::Latex); + ol.endEmphasis(); + ol.enable(OutputGenerator::Man); + if (latexOn) ol.enable(OutputGenerator::Latex); + } + if (!a->array.isEmpty()) + { + ol.docify(a->array); + } + if (hasFuncPtrType) // write the part of the argument type + // that comes after the name + { + linkifyText(TextGeneratorOLImpl(ol),cd,md->getBodyDef(), + md->name(),a->type.right(a->type.length()-vp)); + } + if (!a->defval.isEmpty()) // write the default value + { + QCString n=a->defval; + if (!cName.isEmpty()) n=addTemplateNames(n,cd->name(),cName); + ol.docify(" = "); + + ol.startTypewriter(); + linkifyText(TextGeneratorOLImpl(ol),cd,md->getBodyDef(),md->name(),n,FALSE,TRUE,TRUE); + ol.endTypewriter(); + + } + a=defArgList->next(); + if (a) + { + if (!md->isObjCMethod()) ol.docify(", "); // there are more arguments + if (!isDefine) + { + QCString key; + if (md->isObjCMethod() && a->attrib.length()>=2) + { + //printf("Found parameter keyword %s\n",a->attrib.data()); + // strip [ and ] + key=a->attrib.mid(1,a->attrib.length()-2); + if (key!=",") key+=":"; // for normal keywords add colon + } + ol.endParameterName(FALSE,FALSE,!md->isObjCMethod()); + if (paramTypeStarted) + { + ol.endParameterType(); + } + ol.startParameterType(FALSE,key); + paramTypeStarted=TRUE; + } + else // isDefine + { + ol.endParameterName(FALSE,FALSE,TRUE); + } + } + first=FALSE; + } + ol.pushGeneratorState(); + ol.disable(OutputGenerator::Html); + ol.disable(OutputGenerator::Latex); + if (!md->isObjCMethod()) ol.docify(")"); // end argument list + ol.enableAll(); + if (htmlOn) ol.enable(OutputGenerator::Html); + if (latexOn) ol.enable(OutputGenerator::Latex); + if (first) ol.startParameterName(defArgList->count()<2); + ol.endParameterName(TRUE,defArgList->count()<2,!md->isObjCMethod()); + ol.popGeneratorState(); + if (md->extraTypeChars()) + { + ol.docify(md->extraTypeChars()); + } + if (defArgList->constSpecifier) + { + ol.docify(" const"); + } + if (defArgList->volatileSpecifier) + { + ol.docify(" volatile"); + } + return TRUE; +} + +static void writeTemplatePrefix(OutputList &ol,ArgumentList *al) +{ + ol.docify("template<"); + Argument *a=al->first(); + while (a) + { + ol.docify(a->type); + ol.docify(" "); + ol.docify(a->name); + if (a->defval.length()!=0) + { + ol.docify(" = "); + ol.docify(a->defval); + } + a=al->next(); + if (a) ol.docify(", "); + } + ol.docify("> "); +} + +QCString extractDirection(QCString &docs) +{ + QRegExp re("\\[[^\\]]+\\]"); // [...] + int l=0; + if (re.match(docs,0,&l)==0) + { + int inPos = docs.find("in", 1,FALSE); + int outPos = docs.find("out",1,FALSE); + bool input = inPos!=-1 && inPos *defTmpArgLists; // lists of template argument lists + // (for template functions in nested template classes) + + ClassDef *cachedAnonymousType; // if the member has an anonymous compound + // as its type then this is computed by + // getClassDefOfAnonymousType() and + // cached here. + SDict *classSectionSDict; // not accessible + + MemberDef *groupAlias; // Member containing the definition + int grpId; // group id + MemberGroup *memberGroup; // group's member definition + GroupDef *group; // group in which this member is in + Grouping::GroupPri_t grouppri; // priority of this definition + QCString groupFileName; // file where this grouping was defined + int groupStartLine; // line " " " " " + MemberDef *groupMember; + + bool isTypedefValCached; + ClassDef *cachedTypedefValue; + QCString cachedTypedefTemplSpec; + QCString cachedResolvedType; + + // inbody documentation + //int inbodyLine; + //QCString inbodyFile; + //QCString inbodyDocs; + + // documentation inheritance + MemberDef *docProvider; + + // to store the output file base from tag files + QCString explicitOutputFileBase; + + // objective-c + bool implOnly; // function found in implementation but not + // in the interface + bool hasDocumentedParams; + bool hasDocumentedReturnType; + bool isDMember; + Relationship related; // relationship of this to the class + bool stat; // is it a static function? + bool proto; // is it a prototype; + bool docEnumValues; // is an enum with documented enum values. + bool annScope; // member is part of an annoymous scope + bool annUsed; + bool hasCallGraph; + bool hasCallerGraph; + bool explExt; // member was explicitly declared external + bool tspec; // member is a template specialization + bool groupHasDocs; // true if the entry that caused the grouping was documented + bool docsForDefinition; // TRUE => documentation block is put before + // definition. + // FALSE => block is put before declaration. + ClassDef *category; +}; + +MemberDefImpl::MemberDefImpl() : + enumFields(0), + redefinedBy(0), + exampleSDict(0), + defArgList(0), + declArgList(0), + tArgList(0), + typeConstraints(0), + defTmpArgLists(0), + classSectionSDict(0), + category(0) +{ +} + +MemberDefImpl::~MemberDefImpl() +{ + delete redefinedBy; + delete exampleSDict; + delete enumFields; + delete defArgList; + delete tArgList; + delete typeConstraints; + delete defTmpArgLists; + delete classSectionSDict; + delete declArgList; +} + +void MemberDefImpl::init(Definition *def, + const char *t,const char *a,const char *e, + Protection p,Specifier v,bool s,Relationship r, + MemberDef::MemberType mt,const ArgumentList *tal, + const ArgumentList *al + ) +{ + classDef=0; + fileDef=0; + redefines=0; + relatedAlso=0; + redefinedBy=0; + nspace=0; + memDef=0; + memDec=0; + group=0; + grpId=-1; + exampleSDict=0; + enumFields=0; + enumScope=0; + defTmpArgLists=0; + hasCallGraph = FALSE; + hasCallerGraph = FALSE; + initLines=0; + type=t; + if (mt==MemberDef::Typedef) type.stripPrefix("typedef "); + // type.stripPrefix("struct "); + // type.stripPrefix("class " ); + // type.stripPrefix("union " ); + type=removeRedundantWhiteSpace(type); + args=a; + args=removeRedundantWhiteSpace(args); + if (type.isEmpty()) decl=def->name()+args; else decl=type+" "+def->name()+args; + + memberGroup=0; + virt=v; + prot=p; + related=r; + stat=s; + mtype=mt; + exception=e; + proto=FALSE; + annScope=FALSE; + memSpec=0; + annMemb=0; + annUsed=FALSE; + annEnumType=0; + groupAlias=0; + explExt=FALSE; + tspec=FALSE; + cachedAnonymousType=0; + maxInitLines=Config_getInt("MAX_INITIALIZER_LINES"); + userInitLines=-1; + docEnumValues=FALSE; + // copy function template arguments (if any) + if (tal) + { + tArgList = new ArgumentList; + tArgList->setAutoDelete(TRUE); + ArgumentListIterator ali(*tal); + Argument *a; + for (;(a=ali.current());++ali) + { + tArgList->append(new Argument(*a)); + } + } + else + { + tArgList=0; + } + //printf("new member al=%p\n",al); + // copy function definition arguments (if any) + if (al) + { + defArgList = new ArgumentList; + defArgList->setAutoDelete(TRUE); + ArgumentListIterator ali(*al); + Argument *a; + for (;(a=ali.current());++ali) + { + //printf("copy argument %s (doc=%s)\n",a->name.data(),a->docs.data()); + defArgList->append(new Argument(*a)); + } + defArgList->constSpecifier = al->constSpecifier; + defArgList->volatileSpecifier = al->volatileSpecifier; + defArgList->pureSpecifier = al->pureSpecifier; + //printf("defArgList(%p)->constSpecifier=%d\n",defArgList,defArgList->constSpecifier); + } + else + { + defArgList=0; + } + // convert function declaration arguments (if any) + if (!args.isEmpty()) + { + declArgList = new ArgumentList; + stringToArgumentList(args,declArgList,&extraTypeChars); + //printf("setDeclArgList %s to %s const=%d\n",args.data(), + // argListToString(declArgList).data(),declArgList->constSpecifier); + } + else + { + declArgList = 0; + } + templateMaster = 0; + classSectionSDict = 0; + docsForDefinition = TRUE; + isTypedefValCached = FALSE; + cachedTypedefValue = 0; + //inbodyLine = -1; + implOnly=FALSE; + groupMember = 0; + hasDocumentedParams = FALSE; + hasDocumentedReturnType = FALSE; + docProvider = 0; + isDMember = def->getDefFileName().right(2).lower()==".d"; +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- + +/*! Creates a new member definition. + * + * \param df File containing the definition of this member. + * \param dl Line at which the member definition was found. + * \param t A string representing the type of the member. + * \param na A string representing the name of the member. + * \param a A string representing the arguments of the member. + * \param e A string representing the throw clause of the members. + * \param p The protection context of the member, possible values are: + * \c Public, \c Protected, \c Private. + * \param v The degree of `virtualness' of the member, possible values are: + * \c Normal, \c Virtual, \c Pure. + * \param s A boolean that is true iff the member is static. + * \param r The relationship between the class and the member. + * \param mt The kind of member. See #MemberDef::MemberType for a list of + * all types. + * \param tal The template arguments of this member. + * \param al The arguments of this member. This is a structured form of + * the string past as argument \a a. + */ + +MemberDef::MemberDef(const char *df,int dl, + const char *t,const char *na,const char *a,const char *e, + Protection p,Specifier v,bool s,Relationship r,MemberType mt, + const ArgumentList *tal,const ArgumentList *al + ) : Definition(df,dl,removeRedundantWhiteSpace(na)) +{ + //printf("MemberDef::MemberDef(%s)\n",na); + m_storagePos=-1; + m_cacheHandle=-1; + m_impl = new MemberDefImpl; + m_impl->init(this,t,a,e,p,v,s,r,mt,tal,al); + m_flushPending = FALSE; + m_isLinkableCached = 0; + m_isConstructorCached = 0; + m_isDestructorCached = 0; +} + +void MemberDef::moveTo(Definition *scope) +{ + setOuterScope(scope); + if (scope->definitionType()==Definition::TypeClass) + { + m_impl->classDef = (ClassDef*)scope; + } + else if (scope->definitionType()==Definition::TypeFile) + { + m_impl->fileDef = (FileDef*)scope; + } + else if (scope->definitionType()==Definition::TypeNamespace) + { + m_impl->nspace = (NamespaceDef*)scope; + } + m_isLinkableCached = 0; + m_isConstructorCached = 0; +} + + +/*! Destroys the member definition. */ +MemberDef::~MemberDef() +{ + delete m_impl; + //printf("%p: ~MemberDef()\n",this); + m_impl=0; + if (m_cacheHandle!=-1) + { + Doxygen::symbolCache->del(m_cacheHandle); + m_cacheHandle=-1; + } +} + +void MemberDef::setReimplements(MemberDef *md) +{ + makeResident(); + //if (redefines==0) redefines = new MemberList; + //if (redefines->find(md)==-1) redefines->inSort(md); + + m_impl->redefines = md; +} + +void MemberDef::insertReimplementedBy(MemberDef *md) +{ + makeResident(); + if (m_impl->templateMaster) + { + m_impl->templateMaster->insertReimplementedBy(md); + } + if (m_impl->redefinedBy==0) m_impl->redefinedBy = new MemberList(MemberList::redefinedBy); + if (m_impl->redefinedBy->findRef(md)==-1) + { + m_impl->redefinedBy->inSort(md); + } +} + +MemberDef *MemberDef::reimplements() const +{ + makeResident(); + return m_impl->redefines; +} + +LockingPtr MemberDef::reimplementedBy() const +{ + makeResident(); + return LockingPtr(this,m_impl->redefinedBy); +} + +void MemberDef::insertEnumField(MemberDef *md) +{ + makeResident(); + if (m_impl->enumFields==0) m_impl->enumFields=new MemberList(MemberList::enumFields); + m_impl->enumFields->append(md); +} + +bool MemberDef::addExample(const char *anchor,const char *nameStr, + const char *file) +{ + makeResident(); + //printf("%s::addExample(%s,%s,%s)\n",name().data(),anchor,nameStr,file); + if (m_impl->exampleSDict==0) m_impl->exampleSDict = new ExampleSDict; + if (m_impl->exampleSDict->find(nameStr)==0) + { + //printf("Add reference to example %s to member %s\n",nameStr,name.data()); + Example *e=new Example; + e->anchor=anchor; + e->name=nameStr; + e->file=file; + m_impl->exampleSDict->inSort(nameStr,e); + return TRUE; + } + return FALSE; +} + +bool MemberDef::hasExamples() +{ + makeResident(); + if (m_impl->exampleSDict==0) + return FALSE; + else + return m_impl->exampleSDict->count()>0; +} + +QCString MemberDef::getOutputFileBase() const +{ + makeResident(); + static bool separateMemberPages = Config_getBool("SEPARATE_MEMBER_PAGES"); + QCString baseName; + //printf("Member: %s: templateMaster=%p group=%p classDef=%p nspace=%p fileDef=%p\n", + // name().data(),m_impl->templateMaster,m_impl->group,m_impl->classDef, + // m_impl->nspace,m_impl->fileDef); + if (!m_impl->explicitOutputFileBase.isEmpty()) + { + return m_impl->explicitOutputFileBase; + } + else if (m_impl->templateMaster) + { + return m_impl->templateMaster->getOutputFileBase(); + } + else if (m_impl->group) + { + baseName=m_impl->group->getOutputFileBase(); + } + else if (m_impl->classDef) + { + baseName=m_impl->classDef->getOutputFileBase(); + } + else if (m_impl->nspace) + { + baseName=m_impl->nspace->getOutputFileBase(); + } + else if (m_impl->fileDef) + { + baseName=m_impl->fileDef->getOutputFileBase(); + } + + if (baseName.isEmpty()) + { + warn(getDefFileName(),getDefLine(), + "warning: Internal inconsistency: member %s does not belong to any" + " container!",qPrint(name()) + ); + return "dummy"; + } + else if (separateMemberPages) + { + if (getEnumScope()) // enum value, which is part of enum's documentation + { + baseName+="_"+getEnumScope()->anchor(); + } + else + { + baseName+="_"+anchor(); + } + } + return baseName; +} + +QCString MemberDef::getReference() const +{ + makeResident(); + QCString ref = Definition::getReference(); + if (!ref.isEmpty()) + { + return ref; + } + if (m_impl->templateMaster) + { + return m_impl->templateMaster->getReference(); + } + else if (m_impl->group) + { + return m_impl->group->getReference(); + } + else if (m_impl->classDef) + { + return m_impl->classDef->getReference(); + } + else if (m_impl->nspace) + { + return m_impl->nspace->getReference(); + } + else if (m_impl->fileDef) + { + return m_impl->fileDef->getReference(); + } + return ""; +} + +QCString MemberDef::anchor() const +{ + KEEP_RESIDENT_DURING_CALL; + QCString result=m_impl->anc; + if (m_impl->groupAlias) return m_impl->groupAlias->anchor(); + if (m_impl->templateMaster) return m_impl->templateMaster->anchor(); + if (m_impl->enumScope && m_impl->enumScope!=this) // avoid recursion for C#'s public enum E { E, F } + { + result.prepend(m_impl->enumScope->anchor()); + } + if (m_impl->group) + { + if (m_impl->groupMember) + { + result=m_impl->groupMember->anchor(); + } + else if (getReference().isEmpty()) + { + result.prepend("g"); + } + } + return result; +} + +void MemberDef::_computeLinkableInProject() +{ + KEEP_RESIDENT_DURING_CALL; + static bool extractStatic = Config_getBool("EXTRACT_STATIC"); + m_isLinkableCached = 2; // linkable + //printf("MemberDef::isLinkableInProject(name=%s)\n",name().data()); + if (isHidden()) + { + //printf("is hidden\n"); + m_isLinkableCached = 1; + return; + } + if (m_impl->templateMaster) + { + //printf("has template master\n"); + m_isLinkableCached = m_impl->templateMaster->isLinkableInProject() ? 2 : 1; + } + if (name().isEmpty() || name().at(0)=='@') + { + //printf("name invalid\n"); + m_isLinkableCached = 1; // not a valid or a dummy name + return; + } + if (!hasDocumentation() && !isReference()) + { + //printf("no docs or reference\n"); + m_isLinkableCached = 1; // no documentation + return; + } + if (m_impl->group && !m_impl->group->isLinkableInProject()) + { + //printf("group but group not linkable!\n"); + m_isLinkableCached = 1; // group but group not linkable + return; + } + if (!m_impl->group && m_impl->classDef && !m_impl->classDef->isLinkableInProject()) + { + //printf("in a class but class not linkable!\n"); + m_isLinkableCached = 1; // in class but class not linkable + return; + } + if (!m_impl->group && m_impl->nspace && !m_impl->related && !m_impl->nspace->isLinkableInProject()) + { + //printf("in a namespace but namespace not linkable!\n"); + m_isLinkableCached = 1; // in namespace but namespace not linkable + return; + } + if (!m_impl->group && !m_impl->nspace && + !m_impl->related && !m_impl->classDef && + m_impl->fileDef && !m_impl->fileDef->isLinkableInProject()) + { + //printf("in a file but file not linkable!\n"); + m_isLinkableCached = 1; // in file (and not in namespace) but file not linkable + return; + } + if (!protectionLevelVisible(m_impl->prot) && m_impl->mtype!=Friend) + { + //printf("private and invisible!\n"); + m_isLinkableCached = 1; // hidden due to protection + return; + } + if (m_impl->stat && m_impl->classDef==0 && !extractStatic) + { + //printf("static and invisible!\n"); + m_isLinkableCached = 1; // hidden due to staticness + return; + } + //printf("linkable!\n"); + return; // linkable! +} + +void MemberDef::setDocumentation(const char *d,const char *docFile,int docLine,bool stripWhiteSpace) +{ + makeResident(); + Definition::setDocumentation(d,docFile,docLine,stripWhiteSpace); + m_isLinkableCached = 0; +} + +void MemberDef::setBriefDescription(const char *b,const char *briefFile,int briefLine) +{ + makeResident(); + Definition::setBriefDescription(b,briefFile,briefLine); + m_isLinkableCached = 0; +} + +void MemberDef::setInbodyDocumentation(const char *d,const char *inbodyFile,int inbodyLine) +{ + makeResident(); + Definition::setInbodyDocumentation(d,inbodyFile,inbodyLine); + m_isLinkableCached = 0; +} + +void MemberDef::setHidden(bool b) +{ + makeResident(); + Definition::setHidden(b); + m_isLinkableCached = 0; +} + +bool MemberDef::isLinkableInProject() const +{ + if (m_isLinkableCached==0) + { + MemberDef *that = (MemberDef*)this; + that->_computeLinkableInProject(); + } + ASSERT(m_isLinkableCached>0); + return m_isLinkableCached==2; +} + +bool MemberDef::isLinkable() const +{ + makeResident(); + if (m_impl->templateMaster) + { + return m_impl->templateMaster->isLinkable(); + } + else + { + return isLinkableInProject() || isReference(); + } +} + + +void MemberDef::setDefinitionTemplateParameterLists(QList *lists) +{ + if (lists) + { + makeResident(); + if (m_impl->defTmpArgLists) delete m_impl->defTmpArgLists; + m_impl->defTmpArgLists = copyArgumentLists(lists); + } +} + +void MemberDef::writeLink(OutputList &ol,ClassDef *,NamespaceDef *, + FileDef *fd,GroupDef *gd,bool onlyText) +{ + KEEP_RESIDENT_DURING_CALL; + SrcLangExt lang = getLanguage(); + //static bool optimizeOutputJava = Config_getBool("OPTIMIZE_OUTPUT_JAVA"); + static bool hideScopeNames = Config_getBool("HIDE_SCOPE_NAMES"); + QCString sep = getLanguageSpecificSeparator(lang,TRUE); + QCString n = name(); + if (!hideScopeNames) + { + if (m_impl->classDef && gd && !isRelated()) + { + n.prepend(m_impl->classDef->displayName()+sep); + } + else if (m_impl->nspace && (gd || fd)) + { + n.prepend(m_impl->nspace->displayName()+sep); + } + } + + if (isObjCMethod()) + { + if (isStatic()) ol.docify("+ "); else ol.docify("- "); + } + if (!onlyText && isLinkable()) // write link + { + if (m_impl->mtype==EnumValue && getGroupDef()==0 && // enum value is not grouped + getEnumScope() && getEnumScope()->getGroupDef()) // but its container is + { + GroupDef *enumValGroup = getEnumScope()->getGroupDef(); + ol.writeObjectLink(enumValGroup->getReference(), + enumValGroup->getOutputFileBase(), + anchor(),n); + } + else + { + ol.writeObjectLink(getReference(),getOutputFileBase(),anchor(),n); + } + } + else // write only text + { + ol.startBold(); + ol.docify(n); + ol.endBold(); + } +} + +/*! If this member has an anonymous class/struct/union as its type, then + * this method will return the ClassDef that describes this return type. + */ +ClassDef *MemberDef::getClassDefOfAnonymousType() +{ + // split KEEP_RESIDENT_DURING_CALL for performance + makeResident(); + if (m_impl->cachedAnonymousType) return m_impl->cachedAnonymousType; + LockingPtr lock(this,this); // since this memberDef can access + // other memberDefs prevent it from + // being flushed to disk halfway + + QCString cname; + if (getClassDef()!=0) + { + cname=getClassDef()->name().copy(); + } + else if (getNamespaceDef()!=0) + { + cname=getNamespaceDef()->name().copy(); + } + QCString ltype(m_impl->type); + // strip `static' keyword from ltype + //if (ltype.left(7)=="static ") ltype=ltype.right(ltype.length()-7); + // strip `friend' keyword from ltype + ltype.stripPrefix("friend "); + static QRegExp r("@[0-9]+"); + int l,i=r.match(ltype,0,&l); + //printf("ltype=`%s' i=%d\n",ltype.data(),i); + // search for the last anonymous scope in the member type + ClassDef *annoClassDef=0; + if (i!=-1) // found anonymous scope in type + { + int il=i-1,ir=i+l; + // extract anonymous scope + while (il>=0 && (isId(ltype.at(il)) || ltype.at(il)==':' || ltype.at(il)=='@')) il--; + if (il>0) il++; else if (il<0) il=0; + while (ir<(int)ltype.length() && (isId(ltype.at(ir)) || ltype.at(ir)==':' || ltype.at(ir)=='@')) ir++; + + QCString annName = ltype.mid(il,ir-il); + + // if inside a class or namespace try to prepend the scope name + if (!cname.isEmpty() && annName.left(cname.length()+2)!=cname+"::") + { + QCString ts=stripAnonymousNamespaceScope(cname+"::"+annName); + //printf("Member::writeDeclaration: Trying %s\n",ts.data()); + annoClassDef=getClass(ts); + } + // if not found yet, try without scope name + if (annoClassDef==0) + { + QCString ts=stripAnonymousNamespaceScope(annName); + //printf("Member::writeDeclaration: Trying %s\n",ts.data()); + annoClassDef=getClass(ts); + } + } + m_impl->cachedAnonymousType = annoClassDef; + return annoClassDef; +} + +/*! This methods returns TRUE iff the brief section (also known as + * declaration section) is visible in the documentation. + */ +bool MemberDef::isBriefSectionVisible() const +{ + static bool extractStatic = Config_getBool("EXTRACT_STATIC"); + static bool hideUndocMembers = Config_getBool("HIDE_UNDOC_MEMBERS"); + static bool briefMemberDesc = Config_getBool("BRIEF_MEMBER_DESC"); + static bool repeatBrief = Config_getBool("REPEAT_BRIEF"); + static bool hideFriendCompounds = Config_getBool("HIDE_FRIEND_COMPOUNDS"); + + //printf("Member %s grpId=%d docs=%s file=%s args=%s\n", + // name().data(), + // 0,"", //grpId,grpId==-1?"":Doxygen::memberDocDict[grpId]->data(), + // "", //getFileDef()->name().data(), + // argsString()); + + KEEP_RESIDENT_DURING_CALL; + + MemberGroupInfo *info = Doxygen::memGrpInfoDict[m_impl->grpId]; + //printf("name=%s m_impl->grpId=%d info=%p\n",name().data(),m_impl->grpId,info); + //QCString *pMemGrp = Doxygen::memberDocDict[grpId]; + bool hasDocs = hasDocumentation() || + // part of a documented member group + (m_impl->grpId!=-1 && info && !(info->doc.isEmpty() && info->header.isEmpty())); + + // only include static members with file/namespace scope if + // explicitly enabled in the config file + bool visibleIfStatic = !(getClassDef()==0 && + isStatic() && + !extractStatic + ); + + // only include members is the are documented or + // HIDE_UNDOC_MEMBERS is NO in the config file + bool visibleIfDocumented = (!hideUndocMembers || + hasDocs || + isDocumentedFriendClass() + ); + + // hide members with no detailed description and brief descriptions + // explicitly disabled. + bool visibleIfEnabled = !(hideUndocMembers && + documentation().isEmpty() && + !briefMemberDesc && + !repeatBrief + ); + + // Hide friend (class|struct|union) declarations if HIDE_FRIEND_COMPOUNDS is true + bool visibleIfFriendCompound = !(hideFriendCompounds && + isFriend() && + (m_impl->type=="friend class" || + m_impl->type=="friend struct" || + m_impl->type=="friend union" + ) + ); + + // only include members that are non-private unless EXTRACT_PRIVATE is + // set to YES or the member is part of a group + bool visibleIfPrivate = (protectionLevelVisible(protection()) || + m_impl->mtype==Friend + ); + + // hide member if it overrides a member in a superclass and has no + // documentation of its own + //bool visibleIfDocVirtual = !reimplements() || + // !Config_getBool("INHERIT_DOCS") || + // hasDocs; + + // true if this member is a constructor or destructor + bool cOrDTor = isConstructor() || isDestructor(); + + // hide default constructors or destructors (no args) without + // documentation + bool visibleIfNotDefaultCDTor = !(cOrDTor && + m_impl->defArgList && + (m_impl->defArgList->isEmpty() || + m_impl->defArgList->first()->type == "void" + ) && + !hasDocs + ); + + + //printf("visibleIfStatic=%d visibleIfDocumented=%d visibleIfEnabled=%d " + // "visibleIfPrivate=%d visibltIfNotDefaultCDTor=%d " + // "visibleIfFriendCompound=%d !annScope=%d\n", + // visibleIfStatic,visibleIfDocumented, + // visibleIfEnabled,visibleIfPrivate,visibleIfNotDefaultCDTor, + // visibleIfFriendCompound,!m_impl->annScope); + + bool visible = visibleIfStatic && visibleIfDocumented && + visibleIfEnabled && visibleIfPrivate && + /*visibleIfDocVirtual &&*/ visibleIfNotDefaultCDTor && + visibleIfFriendCompound && + !m_impl->annScope && !isHidden(); + //printf("MemberDef::isBriefSectionVisible() %d\n",visible); + return visible; +} + + +void MemberDef::writeDeclaration(OutputList &ol, + ClassDef *cd,NamespaceDef *nd,FileDef *fd,GroupDef *gd, + bool inGroup + ) +{ + //printf("%s MemberDef::writeDeclaration() inGroup=%d\n",name().data(),inGroup); + + // hide enum value, since they appear already as part of the enum, unless they + // are explicitly grouped. + KEEP_RESIDENT_DURING_CALL; + if (!inGroup && m_impl->mtype==EnumValue) return; + + // hide members whose brief section should not be visible + //if (!isBriefSectionVisible()) return; + + Definition *d=0; + ASSERT (cd!=0 || nd!=0 || fd!=0 || gd!=0); // member should belong to something + if (cd) d=cd; else if (nd) d=nd; else if (fd) d=fd; else d=gd; + + // write tag file information of this member + if (!Config_getString("GENERATE_TAGFILE").isEmpty() && !isReference()) + { + Doxygen::tagFile << " mtype) + { + case Define: Doxygen::tagFile << "define"; break; + case EnumValue: Doxygen::tagFile << "enumvalue"; break; + case Property: Doxygen::tagFile << "property"; break; + case Event: Doxygen::tagFile << "event"; break; + case Variable: Doxygen::tagFile << "variable"; break; + case Typedef: Doxygen::tagFile << "typedef"; break; + case Enumeration: Doxygen::tagFile << "enumeration"; break; + case Function: Doxygen::tagFile << "function"; break; + case Signal: Doxygen::tagFile << "signal"; break; + //case Prototype: Doxygen::tagFile << "prototype"; break; + case Friend: Doxygen::tagFile << "friend"; break; + case DCOP: Doxygen::tagFile << "dcop"; break; + case Slot: Doxygen::tagFile << "slot"; break; + } + if (m_impl->prot!=Public) + { + Doxygen::tagFile << "\" protection=\""; + if (m_impl->prot==Protected) Doxygen::tagFile << "protected"; + else if (m_impl->prot==Package) Doxygen::tagFile << "package"; + else /* Private */ Doxygen::tagFile << "private"; + } + if (m_impl->virt!=Normal) + { + Doxygen::tagFile << "\" virtualness=\""; + if (m_impl->virt==Virtual) Doxygen::tagFile << "virtual"; + else /* Pure */ Doxygen::tagFile << "pure"; + } + if (isStatic()) + { + Doxygen::tagFile << "\" static=\"yes"; + } + Doxygen::tagFile << "\">" << endl; + Doxygen::tagFile << " " << convertToXML(typeString()) << "" << endl; + Doxygen::tagFile << " " << convertToXML(name()) << "" << endl; + Doxygen::tagFile << " " << convertToXML(getOutputFileBase()+Doxygen::htmlFileExtension) << "" << endl; + Doxygen::tagFile << " " << convertToXML(anchor()) << "" << endl; + Doxygen::tagFile << " " << convertToXML(argsString()) << "" << endl; + writeDocAnchorsToTagFile(); + Doxygen::tagFile << " " << endl; + } + + // write search index info + if (Doxygen::searchIndex && isLinkableInProject()) + { + Doxygen::searchIndex->setCurrentDoc(qualifiedName(),getOutputFileBase(),anchor()); + Doxygen::searchIndex->addWord(localName(),TRUE); + Doxygen::searchIndex->addWord(qualifiedName(),FALSE); + } + + QCString cname = d->name(); + QCString cdname = d->displayName(); + QCString cfname = getOutputFileBase(); + //QCString osname = cname; + // in case of class members that are put in a group the name of the outerscope + // differs from the cname. + //if (getOuterScope()) osname=getOuterScope()->name(); + + //HtmlHelp *htmlHelp=0; + //bool hasHtmlHelp = Config_getBool("GENERATE_HTML") && Config_getBool("GENERATE_HTMLHELP"); + //if (hasHtmlHelp) htmlHelp = HtmlHelp::getInstance(); + + // search for the last anonymous scope in the member type + ClassDef *annoClassDef=getClassDefOfAnonymousType(); + + // start a new member declaration + bool isAnonymous = annoClassDef || m_impl->annMemb || m_impl->annEnumType; + ///printf("startMemberItem for %s\n",name().data()); + ol.startMemberItem( anchor(), isAnonymous ? 1 : m_impl->tArgList ? 3 : 0); + + // If there is no detailed description we need to write the anchor here. + bool detailsVisible = isDetailedSectionLinkable(); + if (!detailsVisible && !m_impl->annMemb) + { + QCString doxyName=name().copy(); + if (!cname.isEmpty()) + { + doxyName.prepend(cdname+getLanguageSpecificSeparator(getLanguage())); + } + QCString doxyArgs=argsString(); + ol.startDoxyAnchor(cfname,cname,anchor(),doxyName,doxyArgs); + + ol.pushGeneratorState(); + ol.disable(OutputGenerator::Man); + ol.disable(OutputGenerator::Latex); + ol.docify("\n"); + ol.popGeneratorState(); + } + + if (annoClassDef || m_impl->annMemb) + { + int j; + for (j=0;jtArgList) + { + if (!isAnonymous) ol.startMemberTemplateParams(); + writeTemplatePrefix(ol,m_impl->tArgList); + if (!isAnonymous) ol.endMemberTemplateParams(anchor()); + } + + // *** write type + QCString ltype(m_impl->type); + if (m_impl->mtype==Typedef) ltype.prepend("typedef "); + // strip `friend' keyword from ltype + ltype.stripPrefix("friend "); + static QRegExp r("@[0-9]+"); + + bool endAnonScopeNeeded=FALSE; + int l,i=r.match(ltype,0,&l); + if (i!=-1) // member has an anonymous type + { + //printf("annoClassDef=%p annMemb=%p scopeName=`%s' anonymous=`%s'\n", + // annoClassDef,annMemb,cname.data(),ltype.mid(i,l).data()); + + if (annoClassDef) // type is an anonymous compound + { + int ir=i+l; + //printf("<<<<<<<<<<<<<<\n"); + ol.startAnonTypeScope(s_indentLevel++); + annoClassDef->writeDeclaration(ol,m_impl->annMemb,inGroup); + //printf(">>>>>>>>>>>>>> startMemberItem(2)\n"); + ol.startMemberItem(anchor(),2); + int j; + for (j=0;j< s_indentLevel-1;j++) + { + ol.writeNonBreakableSpace(3); + } + QCString varName=ltype.right(ltype.length()-ir).stripWhiteSpace(); + //printf(">>>>>> indDepth=%d ltype=`%s' varName=`%s'\n",indDepth,ltype.data(),varName.data()); + ol.docify("}"); + if (varName.isEmpty() && (name().isEmpty() || name().at(0)=='@')) + { + ol.docify(";"); + } + endAnonScopeNeeded=TRUE; + } + else + { + if (getAnonymousEnumType()) // type is an anonymous enum + { + linkifyText(TextGeneratorOLImpl(ol), // out + d, // scope + getBodyDef(), // fileScope + name(), // + ltype.left(i), // text + TRUE // autoBreak + ); + getAnonymousEnumType()->writeEnumDeclaration(ol,cd,nd,fd,gd); + //ol+=*getAnonymousEnumType()->enumDecl(); + linkifyText(TextGeneratorOLImpl(ol),d,m_impl->fileDef,name(),ltype.right(ltype.length()-i-l),TRUE); + } + else + { + ltype = ltype.left(i) + " { ... } " + removeAnonymousScopes(ltype.right(ltype.length()-i-l)); + linkifyText(TextGeneratorOLImpl(ol), // out + d, // scope + getBodyDef(), // fileScope + name(), // + ltype, // text + TRUE // autoBreak + ); + } + } + } + else if (ltype=="@") // rename type from enum values + { + ltype=""; + } + else + { + if (isObjCMethod()) + { + ltype.prepend("("); + ltype.append(")"); + } + linkifyText(TextGeneratorOLImpl(ol), // out + d, // scope + getBodyDef(), // fileScope + name(), // + ltype, // text + TRUE // autoBreak + ); + } + bool htmlOn = ol.isEnabled(OutputGenerator::Html); + if (htmlOn && Config_getBool("HTML_ALIGN_MEMBERS") && !ltype.isEmpty()) + { + ol.disable(OutputGenerator::Html); + } + if (!ltype.isEmpty()) ol.docify(" "); + if (htmlOn) + { + ol.enable(OutputGenerator::Html); + } + + if (m_impl->annMemb) + { + ol.pushGeneratorState(); + ol.disableAllBut(OutputGenerator::Html); + ol.writeNonBreakableSpace(3); + ol.popGeneratorState(); + } + else + { + ol.insertMemberAlign(m_impl->tArgList!=0); + } + + // *** write name + if (!name().isEmpty() && name().at(0)!='@') // hide anonymous stuff + { + //printf("Member name=`%s gd=%p md->groupDef=%p inGroup=%d isLinkable()=%d\n",name().data(),gd,getGroupDef(),inGroup,isLinkable()); + if (!(name().isEmpty() || name().at(0)=='@') && // name valid + (hasDocumentation() || isReference()) && // has docs + !(m_impl->prot==Private && !Config_getBool("EXTRACT_PRIVATE") && m_impl->mtype!=Friend) && // hidden due to protection + !(isStatic() && m_impl->classDef==0 && !Config_getBool("EXTRACT_STATIC")) // hidden due to static-ness + ) + { + if (m_impl->annMemb) + { + //printf("anchor=%s ann_anchor=%s\n",anchor(),annMemb->anchor()); + m_impl->annMemb->writeLink(ol, + m_impl->annMemb->getClassDef(), + m_impl->annMemb->getNamespaceDef(), + m_impl->annMemb->getFileDef(), + m_impl->annMemb->getGroupDef() + ); + m_impl->annMemb->setAnonymousUsed(); + setAnonymousUsed(); + } + else + { + //printf("writeLink %s->%d\n",name.data(),hasDocumentation()); + ClassDef *rcd = cd; + if (isReference() && m_impl->classDef) rcd = m_impl->classDef; + writeLink(ol,rcd,nd,fd,gd); + } + } + 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 (m_impl->annMemb) + { + m_impl->annMemb->setAnonymousUsed(); + setAnonymousUsed(); + } + ClassDef *rcd = cd; + if (isReference() && m_impl->classDef) rcd = m_impl->classDef; + writeLink(ol,rcd,nd,fd,gd,TRUE); + } + } + + // add to index + if (isEnumerate() && name().at(0)=='@') + { + // don't add to index + } + else // index member + { + //static bool separateMemPages = Config_getBool("SEPARATE_MEMBER_PAGES"); + //QCString cfname = getOutputFileBase(); + //QCString cfiname = d->getOutputFileBase(); + //Doxygen::indexList.addIndexItem( + // cname, // level1 + // name(), // level2 + // separateMemPages ? cfname : cfiname, // contRef + // cfname, // memRef + // anchor(), // anchor + // this); // memberdef + Doxygen::indexList.addIndexItem(d,this); + } + + // *** write arguments + if (argsString() && !isObjCMethod()) + { + if (!isDefine()) ol.writeString(" "); + linkifyText(TextGeneratorOLImpl(ol), // out + d, // scope + getBodyDef(), // fileScope + name(), // + argsString(), // text + m_impl->annMemb, // autoBreak + TRUE, // external + FALSE, // keepSpaces + s_indentLevel + ); + } + + // *** write exceptions + if (excpString()) + { + ol.writeString(" "); + ol.docify(excpString()); + } + + // *** write bitfields + if (!m_impl->bitfields.isEmpty()) // add bitfields + { + linkifyText(TextGeneratorOLImpl(ol),d,getBodyDef(),name(),m_impl->bitfields.simplifyWhiteSpace()); + } + else if (hasOneLineInitializer() + //!init.isEmpty() && initLines==0 && // one line initializer + //((maxInitLines>0 && userInitLines==-1) || userInitLines>0) // enabled by default or explicitly + ) // add initializer + { + if (!isDefine()) + { + ol.writeString(" = "); + linkifyText(TextGeneratorOLImpl(ol),d,getBodyDef(),name(),m_impl->initializer.simplifyWhiteSpace()); + } + else + { + ol.writeNonBreakableSpace(3); + linkifyText(TextGeneratorOLImpl(ol),d,getBodyDef(),name(),m_impl->initializer); + } + } + + if (isObjCMethod() && isImplementation()) + { + ol.startTypewriter(); + ol.docify(" [implementation]"); + ol.endTypewriter(); + } + + if (isProperty() && (isSettable() || isGettable())) + { + ol.writeLatexSpacing(); + ol.startTypewriter(); + ol.docify(" ["); + QStrList sl; + if (isGettable()) sl.append("get"); + if (isSettable()) sl.append("set"); + const char *s=sl.first(); + while (s) + { + ol.docify(s); + s=sl.next(); + if (s) ol.docify(", "); + } + ol.docify("]"); + ol.endTypewriter(); + } + + if (isEvent() && (isAddable() || isRemovable() || isRaisable())) + { + ol.writeLatexSpacing(); + ol.startTypewriter(); + ol.docify(" ["); + QStrList sl; + if (isAddable()) sl.append("add"); + if (isRemovable()) sl.append("remove"); + if (isRaisable()) sl.append("raise"); + const char *s=sl.first(); + while (s) + { + ol.docify(s); + s=sl.next(); + if (s) ol.docify(", "); + } + ol.docify("]"); + ol.endTypewriter(); + } + + if (!detailsVisible && !m_impl->annMemb) + { + ol.endDoxyAnchor(cfname,anchor()); + } + + //printf("endMember %s annoClassDef=%p annEnumType=%p\n", + // name().data(),annoClassDef,annEnumType); + ol.endMemberItem(); + if (endAnonScopeNeeded) + { + ol.endAnonTypeScope(--s_indentLevel); + } + + // write brief description + if (!briefDescription().isEmpty() && + Config_getBool("BRIEF_MEMBER_DESC") + /* && !annMemb */ + ) + { + ol.startMemberDescription(anchor()); + ol.parseDoc(briefFile(),briefLine(), + getOuterScope()?getOuterScope():d,this,briefDescription(), + TRUE,FALSE,0,TRUE,FALSE); + if (detailsVisible) + { + ol.pushGeneratorState(); + ol.disableAllBut(OutputGenerator::Html); + //ol.endEmphasis(); + ol.docify(" "); + if (m_impl->group!=0 && gd==0) // forward link to the group + { + ol.startTextLink(getOutputFileBase(),anchor()); + } + else // local link + { + ol.startTextLink(0,anchor()); + } + ol.endTextLink(); + //ol.startEmphasis(); + ol.popGeneratorState(); + } + // for RTF we need to add an extra empty paragraph + ol.pushGeneratorState(); + ol.disableAllBut(OutputGenerator::RTF); + ol.startParagraph(); + ol.endParagraph(); + ol.popGeneratorState(); + ol.endMemberDescription(); + } + warnIfUndocumented(); +} + +bool MemberDef::isDetailedSectionLinkable() const +{ + static bool extractAll = Config_getBool("EXTRACT_ALL"); + static bool alwaysDetailedSec = Config_getBool("ALWAYS_DETAILED_SEC"); + static bool repeatBrief = Config_getBool("REPEAT_BRIEF"); + static bool briefMemberDesc = Config_getBool("BRIEF_MEMBER_DESC"); + static bool hideUndocMembers = Config_getBool("HIDE_UNDOC_MEMBERS"); + static bool extractStatic = Config_getBool("EXTRACT_STATIC"); + + KEEP_RESIDENT_DURING_CALL; + + // the member has details documentation for any of the following reasons + bool docFilter = + // treat everything as documented + extractAll || + // has detailed docs + !documentation().isEmpty() || + // has inbody docs + !inbodyDocumentation().isEmpty() || + // is an enum with values that are documented + (m_impl->mtype==Enumeration && m_impl->docEnumValues) || + // is documented enum value + (m_impl->mtype==EnumValue && !briefDescription().isEmpty()) || + // has brief description that is part of the detailed description + (!briefDescription().isEmpty() && // has brief docs + (alwaysDetailedSec && // they are visible in + (repeatBrief || // detailed section or + !briefMemberDesc // they are explicitly not + ) // shown in brief section + ) + ) || + // has a multi-line initialization block + //(initLines>0 && initLinesdefArgList!=0 && m_impl->defArgList->hasDocumentation()) || + // has user comments + Doxygen::userComments + ; + + // this is not a global static or global statics should be extracted + bool staticFilter = getClassDef()!=0 || !isStatic() || extractStatic; + + // only include members that are non-private unless EXTRACT_PRIVATE is + // set to YES or the member is part of a group + bool privateFilter = protectionLevelVisible(protection()) || m_impl->mtype==Friend; + + // member is part of an anonymous scope that is the type of + // another member in the list. + // + //bool inAnonymousScope = !briefDescription().isEmpty() && annUsed; + + // hide friend (class|struct|union) member if HIDE_FRIEND_COMPOUNDS + // is true + bool friendCompoundFilter = !(Config_getBool("HIDE_FRIEND_COMPOUNDS") && + isFriend() && + (m_impl->type=="friend class" || + m_impl->type=="friend struct" || + m_impl->type=="friend union" + ) + ); + + + bool result = ((docFilter && staticFilter && privateFilter && friendCompoundFilter && !isHidden())); + //printf("%s::isDetailedSectionLinkable: %d\n",name().data(),result); + return result; +} + +bool MemberDef::isDetailedSectionVisible(bool inGroup,bool inFile) const +{ + static bool separateMemPages = Config_getBool("SEPARATE_MEMBER_PAGES"); + static bool inlineSimpleStructs = Config_getBool("INLINE_SIMPLE_STRUCTS"); + static bool hideUndocMembers = Config_getBool("HIDE_UNDOC_MEMBERS"); + bool groupFilter = getGroupDef()==0 || inGroup || separateMemPages; + bool fileFilter = getNamespaceDef()==0 || !inFile; + bool simpleFilter = !hideUndocMembers && inlineSimpleStructs && + getClassDef()!=0 && getClassDef()->isSimple(); + + bool visible = isDetailedSectionLinkable() && groupFilter && fileFilter && + !isReference(); + bool result = visible || simpleFilter; + //printf("%s::isDetailedSectionVisble: %d groupFilter=%d fileFilter=%d\n", + // name().data(),result,groupFilter,fileFilter); + return result; +} + +/*! Writes the "detailed documentation" section of this member to + * all active output formats. + */ +void MemberDef::writeDocumentation(MemberList *ml,OutputList &ol, + const char *scName, + Definition *container, + bool inGroup, + bool showEnumValues, + bool showInline + ) +{ + // if this member is in a group find the real scope name. + bool hasParameterList = FALSE; + bool inFile = container->definitionType()==Definition::TypeFile; + bool hasDocs = isDetailedSectionVisible(inGroup,inFile); + + //printf("MemberDef::writeDocumentation(): name=`%s' hasDocs=`%d' containerType=%d inGroup=%d\n", + // name().data(),hasDocs,container->definitionType(),inGroup); + + if ( !hasDocs ) return; + if (isEnumValue() && !showEnumValues) return; + + KEEP_RESIDENT_DURING_CALL; + + SrcLangExt lang = getLanguage(); + //printf("member=%s lang=%d\n",name().data(),lang); + bool optVhdl = lang==SrcLangExt_VHDL; + QCString sep = getLanguageSpecificSeparator(lang,TRUE); + + QCString scopeName = scName; + QCString memAnchor = anchor(); + QCString ciname = container->name(); + if (container->definitionType()==TypeGroup) + { + if (getClassDef()) scopeName=getClassDef()->displayName(); + else if (getNamespaceDef()) scopeName=getNamespaceDef()->displayName(); + else if (getFileDef()) scopeName=getFileDef()->displayName(); + ciname = ((GroupDef *)container)->groupTitle(); + } + else if (container->definitionType()==TypeFile && getNamespaceDef()) + { // member is in a namespace, but is written as part of the file documentation + // as well, so we need to make sure its label is unique. + memAnchor.prepend("file_"); + } + + QCString cname = container->name(); + QCString cfname = getOutputFileBase(); + QCString cfiname = container->getOutputFileBase(); + + // get member name + QCString doxyName=name(); + // prepend scope if there is any. TODO: make this optional for C only docs + if (!scopeName.isEmpty()) + { + doxyName.prepend(scopeName+sep); + } + QCString doxyArgs=argsString(); + + QCString ldef = definition(); + QCString title = name(); + //printf("member `%s' def=`%s'\n",name().data(),ldef.data()); + if (isEnumerate()) + { + if (title.at(0)=='@') + { + ldef = title = "anonymous enum"; + } + else + { + ldef.prepend("enum "); + } + } + else if (isEnumValue()) + { + if (ldef.at(0)=='@') + { + ldef=ldef.mid(2); + } + } + int i=0,l; + static QRegExp r("@[0-9]+"); + + //---------------------------------------- + + ol.pushGeneratorState(); + + + if ((isVariable() || isTypedef()) && (i=r.match(ldef,0,&l))!=-1) + { + // find enum type and insert it in the definition + MemberListIterator vmli(*ml); + MemberDef *vmd; + bool found=FALSE; + for ( ; (vmd=vmli.current()) && !found ; ++vmli) + { + if (vmd->isEnumerate() && ldef.mid(i,l)==vmd->name()) + { + ol.startDoxyAnchor(cfname,cname,memAnchor,doxyName,doxyArgs); + ol.startMemberDoc(ciname,name(),memAnchor,name(),showInline); + linkifyText(TextGeneratorOLImpl(ol),container,getBodyDef(),name(),ldef.left(i)); + vmd->writeEnumDeclaration(ol,getClassDef(),getNamespaceDef(),getFileDef(),getGroupDef()); + linkifyText(TextGeneratorOLImpl(ol),container,getBodyDef(),name(),ldef.right(ldef.length()-i-l)); + + found=TRUE; + } + } + if (!found) // anonymous compound + { + //printf("Anonymous compound `%s'\n",cname.data()); + ol.startDoxyAnchor(cfname,cname,memAnchor,doxyName,doxyArgs); + ol.startMemberDoc(ciname,name(),memAnchor,name(),showInline); + // search for the last anonymous compound name in the definition + int si=ldef.find(' '),pi,ei=i+l; + if (si==-1) si=0; + while ((pi=r.match(ldef,i+l,&l))!=-1) + { + i=pi; + ei=i+l; + } + // first si characters of ldef contain compound type name + ol.startMemberDocName(isObjCMethod()); + ol.docify(ldef.left(si)); + ol.docify(" { ... } "); + // last ei characters of ldef contain pointer/reference specifiers + int ni=ldef.find("::",si); + if (ni>=ei) ei=ni+2; + linkifyText(TextGeneratorOLImpl(ol),container,getBodyDef(),name(),ldef.right(ldef.length()-ei)); + } + } + else // not an enum value + { + ol.startDoxyAnchor(cfname,cname,memAnchor,doxyName,doxyArgs); + ol.startMemberDoc(ciname,name(),memAnchor,title,showInline); + + ClassDef *cd=getClassDef(); + if (!Config_getBool("HIDE_SCOPE_NAMES")) + { + bool first=TRUE; + if (m_impl->defTmpArgLists) + // definition has explicit template parameter declarations + { + QListIterator ali(*m_impl->defTmpArgLists); + ArgumentList *tal; + for (ali.toFirst();(tal=ali.current());++ali) + { + if (tal->count()>0) + { + if (!first) ol.docify(" "); + ol.startMemberDocPrefixItem(); + writeTemplatePrefix(ol,tal); + ol.endMemberDocPrefixItem(); + } + } + } + else // definition gets it template parameters from its class + // (since no definition was found) + { + if (cd && !isTemplateSpecialization()) + { + QList tempParamLists; + cd->getTemplateParameterLists(tempParamLists); + //printf("#tempParamLists=%d\n",tempParamLists.count()); + QListIterator ali(tempParamLists); + ArgumentList *tal; + for (ali.toFirst();(tal=ali.current());++ali) + { + if (tal->count()>0) + { + if (!first) ol.docify(" "); + ol.startMemberDocPrefixItem(); + writeTemplatePrefix(ol,tal); + ol.endMemberDocPrefixItem(); + } + } + } + if (m_impl->tArgList) // function template prefix + { + ol.startMemberDocPrefixItem(); + writeTemplatePrefix(ol,m_impl->tArgList); + ol.endMemberDocPrefixItem(); + } + } + } + + ol.startMemberDocName(isObjCMethod()); + if (cd && cd->isObjectiveC()) + { + // strip scope name + int ep = ldef.find("::"); + if (ep!=-1) + { + int sp=ldef.findRev(' ',ep); + if (sp!=-1) + { + ldef=ldef.left(sp+1)+ldef.mid(ep+2); + } + } + // strip keywords + int dp = ldef.find(':'); + if (dp!=-1) + { + ldef=ldef.left(dp+1); + } + int l=ldef.length(); + //printf("start >%s<\n",ldef.data()); + int i=l-1; + while (i>=0 && (isId(ldef.at(i)) || ldef.at(i)==':')) i--; + while (i>=0 && isspace((uchar)ldef.at(i))) i--; + if (i>0) + { + // insert braches around the type + QCString tmp("("+ldef.left(i+1)+")"+ldef.mid(i+1)); + ldef=tmp; + } + //printf("end >%s< i=%d\n",ldef.data(),i); + if (isStatic()) ldef.prepend("+ "); else ldef.prepend("- "); + } + + if (optVhdl) + { + VhdlDocGen::writeVHDLTypeDocumentation(this,container,ol); + } + else + { + linkifyText(TextGeneratorOLImpl(ol),container,getBodyDef(),name(),substitute(ldef,"::",sep)); + hasParameterList=writeDefArgumentList(ol,cd,scopeName,this); + } + + if (hasOneLineInitializer()) // add initializer + { + if (!isDefine()) + { + ol.docify(" = "); + linkifyText(TextGeneratorOLImpl(ol),container,getBodyDef(),name(),m_impl->initializer.simplifyWhiteSpace()); + } + else + { + ol.writeNonBreakableSpace(3); + linkifyText(TextGeneratorOLImpl(ol),container,getBodyDef(),name(),m_impl->initializer); + } + } + if (excpString()) // add exception list + { + ol.docify(" "); + linkifyText(TextGeneratorOLImpl(ol),container,getBodyDef(),name(),excpString()); + } + } + + Specifier lvirt=virtualness(); + + if ((!isObjCMethod() || isOptional() || isRequired()) && + (protection()!=Public || lvirt!=Normal || + isFriend() || isRelated() || + (isInline() && Config_getBool("INLINE_INFO")) || + isSignal() || isSlot() || + isStatic() || + (m_impl->classDef && m_impl->classDef!=container && container->definitionType()==TypeClass) || + (m_impl->memSpec & ~Entry::Inline)!=0 + ) + ) + { + // write the member specifier list + ol.writeLatexSpacing(); + ol.startTypewriter(); + ol.docify(" ["); + QStrList sl; + if (optVhdl) + { + sl.append(VhdlDocGen::trTypeString(getMemberSpecifiers())); + } + else + { + if (isFriend()) sl.append("friend"); + else if (isRelated()) sl.append("related"); + else + { + if (Config_getBool("INLINE_INFO") && isInline()) sl.append("inline"); + if (isExplicit()) sl.append("explicit"); + if (isMutable()) sl.append("mutable"); + if (isStatic()) sl.append("static"); + if (isGettable()) sl.append("get"); + if (isSettable()) sl.append("set"); + if (isAddable()) sl.append("add"); + if (isRemovable()) sl.append("remove"); + if (isRaisable()) sl.append("raise"); + if (isReadable()) sl.append("read"); + if (isWritable()) sl.append("write"); + if (isFinal()) sl.append("final"); + if (isAbstract()) sl.append("abstract"); + if (isOverride()) sl.append("override"); + if (isInitonly()) sl.append("initonly"); + if (isSealed()) sl.append("sealed"); + if (isNew()) sl.append("new"); + if (isOptional()) sl.append("optional"); + if (isRequired()) sl.append("required"); + if (isAssign()) sl.append("assign"); + else if (isCopy()) sl.append("copy"); + else if (isRetain()) sl.append("retain"); + + if (!isObjCMethod()) + { + if (protection()==Protected) sl.append("protected"); + else if (protection()==Private) sl.append("private"); + else if (protection()==Package) sl.append("package"); + + if (lvirt==Virtual) sl.append("virtual"); + else if (lvirt==Pure) sl.append("pure virtual"); + if (isSignal()) sl.append("signal"); + if (isSlot()) sl.append("slot"); + } + } + if (m_impl->classDef && + container->definitionType()==TypeClass && + m_impl->classDef!=container && + !isRelated() + ) + { + sl.append("inherited"); + } + } + const char *s=sl.first(); + while (s) + { + ol.docify(s); + s=sl.next(); + if (s) ol.docify(", "); + } + ol.docify("]"); + ol.endTypewriter(); + } + else if (isObjCMethod() && isImplementation()) + { + ol.writeLatexSpacing(); + ol.startTypewriter(); + ol.docify(" [implementation]"); + ol.endTypewriter(); + } + if (hasParameterList) + { + ol.endParameterList(); + ol.endMemberDoc(TRUE); + } + else + { + ol.endMemberDocName(); + ol.endMemberDoc(FALSE); + } + ol.endDoxyAnchor(cfname,memAnchor); + ol.startIndent(); + + // FIXME:PARA + //ol.pushGeneratorState(); + //ol.disable(OutputGenerator::RTF); + //ol.newParagraph(); + //ol.popGeneratorState(); + + /* write multi-line initializer (if any) */ + if (hasMultiLineInitializer() + //initLines>0 && ((initLinesmtype==Define) + ol.parseText(theTranslator->trDefineValue()); + else + ol.parseText(theTranslator->trInitialValue()); + ol.endBold(); + ParserInterface *pIntf = Doxygen::parserManager->getParser(getDefFileExtension()); + pIntf->resetCodeParserState(); + ol.startCodeFragment(); + pIntf->parseCode(ol,scopeName,m_impl->initializer,FALSE,0,getFileDef(), + -1,-1,TRUE,this,FALSE); + ol.endCodeFragment(); + } + + QCString brief = briefDescription(); + QCString detailed = documentation(); + LockingPtr docArgList = LockingPtr(this,m_impl->defArgList); + if (m_impl->templateMaster) + { + brief = m_impl->templateMaster->briefDescription(); + detailed = m_impl->templateMaster->documentation(); + docArgList = m_impl->templateMaster->argumentList(); + } + + /* write brief description */ + if (!brief.isEmpty() && + (Config_getBool("REPEAT_BRIEF") || + !Config_getBool("BRIEF_MEMBER_DESC") + ) + ) + { + ol.startParagraph(); + ol.parseDoc(briefFile(),briefLine(), + getOuterScope()?getOuterScope():container,this, + brief,FALSE,FALSE,0,TRUE,FALSE); + ol.endParagraph(); + } + + /* write detailed description */ + if (!detailed.isEmpty() || + !inbodyDocumentation().isEmpty()) + { + // write vhdl inline code with or without option INLINE_SOURCE + if (optVhdl && VhdlDocGen::isMisc(this)) + { + VhdlDocGen::writeSource(this,ol,cname); + return; + } + else + { + ol.parseDoc(docFile(),docLine(),getOuterScope()?getOuterScope():container,this,detailed+"\n",TRUE,FALSE); + } + + if (!inbodyDocumentation().isEmpty()) + { + ol.parseDoc(inbodyFile(),inbodyLine(), + getOuterScope()?getOuterScope():container,this, + inbodyDocumentation()+"\n",TRUE,FALSE); + } + } + else if (!brief.isEmpty() && (Config_getBool("REPEAT_BRIEF") || + !Config_getBool("BRIEF_MEMBER_DESC"))) + { + if (!inbodyDocumentation().isEmpty()) + { + ol.parseDoc(inbodyFile(),inbodyLine(),getOuterScope()?getOuterScope():container,this,inbodyDocumentation()+"\n",TRUE,FALSE); + } + } + + + //printf("***** defArgList=%p name=%s docs=%s hasDocs=%d\n", + // defArgList, + // defArgList?defArgList->hasDocumentation():-1); + if (docArgList!=0 && docArgList->hasDocumentation()) + { + QCString paramDocs; + ArgumentListIterator ali(*docArgList); + Argument *a; + // convert the parameter documentation into a list of @param commands + for (ali.toFirst();(a=ali.current());++ali) + { + if (a->hasDocumentation()) + { + QCString direction = extractDirection(a->docs); + paramDocs+="@param"+direction+" "+a->name+" "+a->docs; + } + } + // feed the result to the documentation parser + ol.parseDoc( + docFile(),docLine(), + getOuterScope()?getOuterScope():container, + this, // memberDef + paramDocs, // docStr + TRUE, // indexWords + FALSE // isExample + ); + + } + + // For enum, we also write the documented enum values + if (isEnumerate()) + { + bool first=TRUE; + LockingPtr fmdl=enumFieldList(); + //printf("** %s: enum values=%d\n",name().data(),fmdl!=0 ? fmdl->count() : 0); + if (fmdl!=0) + { + MemberDef *fmd=fmdl->first(); + while (fmd) + { + //printf("Enum %p: isLinkable()=%d\n",fmd,fmd->isLinkable()); + if (fmd->isLinkable()) + { + if (first) + { + ol.startSimpleSect(BaseOutputDocInterface::EnumValues,0,0,theTranslator->trEnumerationValues()+": "); + ol.startDescForItem(); + ol.startDescTable(); + } + + ol.addIndexItem(fmd->name(),ciname); + ol.addIndexItem(ciname,fmd->name()); + + //Doxygen::indexList.addIndexItem( + // ciname, // level1 + // fmd->name(), // level2 + // separateMemPages ? cfname : cfiname, // contRef + // cfname, // memRef + // fmd->anchor(), // anchor + // fmd); // memberdef + Doxygen::indexList.addIndexItem(container,fmd); + + //ol.writeListItem(); + ol.startDescTableTitle(); // this enables emphasis! + ol.startDoxyAnchor(cfname,cname,fmd->anchor(),fmd->name(),fmd->argsString()); + first=FALSE; + //ol.startEmphasis(); + ol.docify(fmd->name()); + //ol.endEmphasis(); + ol.disableAllBut(OutputGenerator::Man); + ol.writeString(" "); + ol.enableAll(); + ol.endDoxyAnchor(cfname,fmd->anchor()); + ol.endDescTableTitle(); + //ol.newParagraph(); + ol.startDescTableData(); + + if (!fmd->briefDescription().isEmpty()) + { + ol.parseDoc(fmd->briefFile(),fmd->briefLine(),getOuterScope()?getOuterScope():container,fmd,fmd->briefDescription(),TRUE,FALSE); + } + // FIXME:PARA + //if (!fmd->briefDescription().isEmpty() && + // !fmd->documentation().isEmpty()) + //{ + // ol.newParagraph(); + //} + if (!fmd->documentation().isEmpty()) + { + ol.parseDoc(fmd->docFile(),fmd->docLine(),getOuterScope()?getOuterScope():container,fmd,fmd->documentation()+"\n",TRUE,FALSE); + } + ol.endDescTableData(); + } + fmd=fmdl->next(); + } + } + if (!first) + { + //ol.endItemList(); + ol.endDescTable(); + ol.endDescForItem(); + ol.endSimpleSect(); + ol.writeChar('\n'); + } + } + + MemberDef *bmd=reimplements(); + ClassDef *bcd=0; + if (bmd && (bcd=bmd->getClassDef())) + { + // write class that contains a member that is reimplemented by this one + if (bcd->isLinkable()) + { + ol.startParagraph(); + QCString reimplFromLine; + if (bmd->virtualness()!=Pure && bcd->compoundType()!=ClassDef::Interface) + { + reimplFromLine = theTranslator->trReimplementedFromList(1); + } + else + { + reimplFromLine = theTranslator->trImplementedFromList(1); + } + int markerPos = reimplFromLine.find("@0"); + if (markerPos!=-1) // should always pass this. + { + ol.parseText(reimplFromLine.left(markerPos)); //text left from marker + if (bmd->isLinkable()) // replace marker with link + { + //Definition *bd=bmd->group; + //if (bd==0) bd=bcd; + ol.writeObjectLink(bmd->getReference(),bmd->getOutputFileBase(), + bmd->anchor(),bcd->displayName()); + + //ol.writeObjectLink(bcd->getReference(),bcd->getOutputFileBase(), + // bmd->anchor(),bcd->name()); + if ( bmd->isLinkableInProject() ) + { + writePageRef(ol,bmd->getOutputFileBase(),bmd->anchor()); + } + } + else + { + ol.writeObjectLink(bcd->getReference(),bcd->getOutputFileBase(), + 0,bcd->displayName()); + if (bcd->isLinkableInProject()/* && !Config_getBool("PDF_HYPERLINKS")*/ ) + { + writePageRef(ol,bcd->getOutputFileBase(),bcd->anchor()); + } + } + ol.parseText(reimplFromLine.right( + reimplFromLine.length()-markerPos-2)); // text right from marker + + } + else + { + err("error: translation error: no marker in trReimplementsFromList()\n"); + } + ol.endParagraph(); + } + + //ol.writeString("."); + } + + LockingPtr bml=reimplementedBy(); + if (bml!=0) + { + MemberListIterator mli(*bml); + MemberDef *bmd=0; + uint count=0; + ClassDef *bcd=0; + for (mli.toFirst();(bmd=mli.current()) && (bcd=bmd->getClassDef());++mli) + { + // count the members that directly inherit from md and for + // which the member and class are visible in the docs. + if ( bmd->isLinkable() && bcd->isLinkable() ) + { + count++; + } + } + if (count>0) + { + mli.toFirst(); + // write the list of classes that overwrite this member + ol.startParagraph(); + + QCString reimplInLine; + if (m_impl->virt==Pure || (m_impl->classDef && m_impl->classDef->compoundType()==ClassDef::Interface)) + { + reimplInLine = theTranslator->trImplementedInList(count); + } + else + { + reimplInLine = theTranslator->trReimplementedInList(count); + } + static QRegExp marker("@[0-9]+"); + int index=0,newIndex,matchLen; + // now replace all markers in reimplInLine with links to the classes + while ((newIndex=marker.match(reimplInLine,index,&matchLen))!=-1) + { + ol.parseText(reimplInLine.mid(index,newIndex-index)); + bool ok; + uint entryIndex = reimplInLine.mid(newIndex+1,matchLen-1).toUInt(&ok); + //bmd=bml->at(entryIndex); + + count=0; + // find the entryIndex-th documented entry in the inheritance list. + for (mli.toLast();(bmd=mli.current()) && (bcd=bmd->getClassDef());--mli) + { + if ( bmd->isLinkable() && bcd->isLinkable()) + { + if (count==entryIndex) break; + count++; + } + } + + if (ok && bcd && bmd) // write link for marker + { + //ol.writeObjectLink(bcd->getReference(),bcd->getOutputFileBase(), + // bmd->anchor(),bcd->name()); + ol.writeObjectLink(bmd->getReference(),bmd->getOutputFileBase(), + bmd->anchor(),bcd->displayName()); + + if (bmd->isLinkableInProject() ) + { + writePageRef(ol,bmd->getOutputFileBase(),bmd->anchor()); + } + } + ++mli; + index=newIndex+matchLen; + } + ol.parseText(reimplInLine.right(reimplInLine.length()-index)); + ol.endParagraph(); + } + } + + // write the list of examples that use this member + if (hasExamples()) + { + ol.startSimpleSect(BaseOutputDocInterface::Examples,0,0,theTranslator->trExamples()+": "); + ol.startDescForItem(); + writeExample(ol,m_impl->exampleSDict); + ol.endDescForItem(); + ol.endSimpleSect(); + } + + if (m_impl->typeConstraints) + { + writeTypeConstraints(ol,this,m_impl->typeConstraints); + } + + // write reference to the source + writeSourceDef(ol,cname); + writeSourceRefs(ol,cname); + writeSourceReffedBy(ol,cname); + writeInlineCode(ol,cname); + + // write call graph + if ((m_impl->hasCallGraph || Config_getBool("CALL_GRAPH")) + && (isFunction() || isSlot() || isSignal()) && Config_getBool("HAVE_DOT") + ) + { + DotCallGraph callGraph(this,FALSE); + if (!callGraph.isTrivial() && !callGraph.isTooBig()) + { + msg("Generating call graph for function %s\n",qPrint(qualifiedName())); + ol.disable(OutputGenerator::Man); + ol.startParagraph(); + ol.startCallGraph(); + ol.parseText(theTranslator->trCallGraph()); + ol.endCallGraph(callGraph); + ol.endParagraph(); + ol.enableAll(); + } + } + if ((m_impl->hasCallerGraph || Config_getBool("CALLER_GRAPH")) + && (isFunction() || isSlot() || isSignal()) && Config_getBool("HAVE_DOT") + ) + { + DotCallGraph callerGraph(this, TRUE); + if (!callerGraph.isTrivial() && !callerGraph.isTooBig()) + { + msg("Generating caller graph for function %s\n",qPrint(qualifiedName())); + ol.disable(OutputGenerator::Man); + ol.startParagraph(); + ol.startCallGraph(); + ol.parseText(theTranslator->trCallerGraph()); + ol.endCallGraph(callerGraph); + ol.endParagraph(); + ol.enableAll(); + } + } + + if (Doxygen::userComments) + { + ol.pushGeneratorState(); + ol.disableAllBut(OutputGenerator::Html); + QCString cmd = ""; + ol.writeString(cmd); + ol.popGeneratorState(); + } + + ol.endIndent(); + + // enable LaTeX again + //if (Config_getBool("EXTRACT_ALL") && !hasDocs) ol.enable(OutputGenerator::Latex); + ol.popGeneratorState(); + + //------------------------------------------------ + + if (!Config_getBool("EXTRACT_ALL") && + Config_getBool("WARN_IF_UNDOCUMENTED") && + Config_getBool("WARN_NO_PARAMDOC") && + !Doxygen::suppressDocWarnings) + { + if (!hasDocumentedParams()) + { + warn_doc_error(docFile(),docLine(), + "warning: parameters of member %s are not (all) documented", + qPrint(qualifiedName())); + } + if (!hasDocumentedReturnType() && isFunction() && hasDocumentation()) + { + warn_doc_error(docFile(),docLine(), + "warning: return type of member %s is not documented", + qPrint(qualifiedName())); + } + } +} + +// strip scope and field name from the type +// example: "struct N::S.v.c" will become "struct v" +static QCString simplifyTypeForTable(const QCString &s) +{ + QCString ts=removeAnonymousScopes(s); + if (ts.right(2)=="::") ts = ts.left(ts.length()-2); + static QRegExp re("[A-Z_a-z0-9]+::"); + int i,l; + while ((i=re.match(ts,0,&l))!=-1) + { + ts=ts.left(i)+ts.mid(i+l); + } + i=ts.findRev('.'); + if (i!=-1) ts = ts.left(i); + i=ts.findRev('.'); + if (i!=-1) ts = ts.right(ts.length()-i-1); + //printf("simplifyTypeForTable(%s)->%s\n",s.data(),ts.data()); + return ts; +} + +void MemberDef::writeMemberDocSimple(OutputList &ol, Definition *container) +{ + KEEP_RESIDENT_DURING_CALL; + + Definition *scope = getOuterScope(); + QCString doxyName = name(); + QCString doxyArgs = argsString(); + QCString memAnchor = anchor(); + QCString cfname = getOutputFileBase(); + QCString cname; + if (scope) cname = scope->name(); + if (doxyName.at(0)=='@') + { + doxyName="__unnamed__"; + } + + ol.startInlineMemberType(); + ol.startDoxyAnchor(cfname,cname,memAnchor,doxyName,doxyArgs); + + QCString ts = simplifyTypeForTable(m_impl->type); + + linkifyText(TextGeneratorOLImpl(ol), // out + scope, // scope + getBodyDef(), // fileScope + doxyName, // + ts, // text + TRUE // autoBreak + ); + ol.endDoxyAnchor(cfname,memAnchor); + ol.endInlineMemberType(); + + ol.startInlineMemberName(); + ol.docify(doxyName); + if (!m_impl->bitfields.isEmpty()) // add bitfields + { + linkifyText(TextGeneratorOLImpl(ol),getOuterScope(),getBodyDef(),name(),m_impl->bitfields.simplifyWhiteSpace()); + } + ol.endInlineMemberName(); + + ol.startInlineMemberDoc(); + + QCString brief = briefDescription(); + QCString detailed = documentation(); + + /* write brief description */ + if (!brief.isEmpty() && + (Config_getBool("REPEAT_BRIEF") || + !Config_getBool("BRIEF_MEMBER_DESC") + ) + ) + { + ol.parseDoc(briefFile(),briefLine(), + getOuterScope()?getOuterScope():container,this, + brief,FALSE,FALSE,0,TRUE,FALSE); + } + + /* write detailed description */ + if (!detailed.isEmpty()) + { + ol.parseDoc(docFile(),docLine(), + getOuterScope()?getOuterScope():container,this, + detailed+"\n",FALSE,FALSE,0,TRUE,FALSE); + + } + + ol.endInlineMemberDoc(); +} + +QCString MemberDef::memberTypeName() const +{ + makeResident(); + switch (m_impl->mtype) + { + case Define: return "define"; + case Function: return "function"; + case Variable: return "variable"; + case Typedef: return "typedef"; + case Enumeration: return "enumeration"; + case EnumValue: return "enumvalue"; + case Signal: return "signal"; + case Slot: return "slot"; + case Friend: return "friend"; + case DCOP: return "dcop"; + case Property: return "property"; + case Event: return "event"; + default: return "unknown"; + } +} + +void MemberDef::warnIfUndocumented() +{ + makeResident(); + if (m_impl->memberGroup) return; + ClassDef *cd = getClassDef(); + NamespaceDef *nd = getNamespaceDef(); + FileDef *fd = getFileDef(); + GroupDef *gd = getGroupDef(); + Definition *d=0; + const char *t=0; + if (cd) + t="class", d=cd; + else if (nd) + t="namespace", d=nd; + else if (gd) + t="group", d=gd; + else + t="file", d=fd; + static bool extractAll = Config_getBool("EXTRACT_ALL"); + + //printf("warnIfUndoc: d->isLinkable()=%d isLinkable()=%d " + // "isDocumentedFriendClass()=%d name()=%s prot=%d\n", + // d->isLinkable(),isLinkable(),isDocumentedFriendClass(), + // name().data(),prot); + if ((!hasUserDocumentation() && !extractAll) && + !isFriendClass() && + name().find('@')==-1 && d->name().find('@')==-1 && + protectionLevelVisible(m_impl->prot) + ) + { + warn_undoc(getDefFileName(),getDefLine(),"warning: Member %s%s (%s) of %s %s is not documented.", + qPrint(name()),qPrint(argsString()),qPrint(memberTypeName()),t,qPrint(d->name())); + } +} + + + +bool MemberDef::isFriendClass() const +{ + makeResident(); + return (isFriend() && + (m_impl->type=="friend class" || m_impl->type=="friend struct" || + m_impl->type=="friend union")); +} + +bool MemberDef::isDocumentedFriendClass() const +{ + makeResident(); + ClassDef *fcd=0; + QCString baseName=name(); + int i=baseName.find('<'); + if (i!=-1) baseName=baseName.left(i); + return (isFriendClass() && + (fcd=getClass(baseName)) && fcd->isLinkable()); +} + +bool MemberDef::hasDocumentation() const +{ + makeResident(); + return Definition::hasDocumentation() || + (m_impl->mtype==Enumeration && m_impl->docEnumValues) || // has enum values + (m_impl->defArgList!=0 && m_impl->defArgList->hasDocumentation()); // has doc arguments +} + +#if 0 +bool MemberDef::hasUserDocumentation() const +{ + bool hasDocs = Definition::hasUserDocumentation(); + return hasDocs; +} +#endif + + +void MemberDef::setMemberGroup(MemberGroup *grp) +{ + makeResident(); + m_impl->memberGroup = grp; +} + +bool MemberDef::visibleMemberGroup(bool hideNoHeader) +{ + makeResident(); + return m_impl->memberGroup!=0 && + (!hideNoHeader || m_impl->memberGroup->header()!="[NOHEADER]"); +} + +QCString MemberDef::getScopeString() const +{ + makeResident(); + QCString result; + if (getClassDef()) result=getClassDef()->displayName(); + else if (getNamespaceDef()) result=getNamespaceDef()->displayName(); + return result; +} + +#if 0 +static QCString escapeAnchor(const QCString &anchor) +{ + QCString result; + int l = anchor.length(),i; + for (i=0;i='a' && c<='z') || (c>='A' && c<='Z')) + { + result+=c; + } + else + { + static char hexStr[]="0123456789ABCDEF"; + char escChar[]={ '_', 0, 0, 0 }; + escChar[1]=hexStr[c>>4]; + escChar[2]=hexStr[c&0xf]; + result+=escChar; + } + } + return result; +} +#endif + +void MemberDef::setAnchor(const char *a) +{ + makeResident(); + //anc=a; + a=a; + QCString memAnchor = name(); + if (!m_impl->args.isEmpty()) memAnchor+=m_impl->args; + + memAnchor.prepend(definition()); // actually the method name is now included + // twice, which is silly, but we keep it this way for backward + // compatibility. + + // include number of template arguments as well, + // to distinguish between two template + // specializations that only differ in the template parameters. + if (m_impl->tArgList) + { + char buf[20]; + snprintf(buf,20,"%d:",m_impl->tArgList->count()); + buf[19]='\0'; + memAnchor.prepend(buf); + } + + // convert to md5 hash + uchar md5_sig[16]; + QCString sigStr(33); + MD5Buffer((const unsigned char *)memAnchor.data(),memAnchor.length(),md5_sig); + //printf("memAnchor=%s\n",memAnchor.data()); + MD5SigToString(md5_sig,sigStr.data(),33); + m_impl->anc = "a"+sigStr; +} + +void MemberDef::setGroupDef(GroupDef *gd,Grouping::GroupPri_t pri, + const QCString &fileName,int startLine, + bool hasDocs,MemberDef *member) +{ + //printf("%s MemberDef::setGroupDef(%s)\n",name().data(),gd->name().data()); + makeResident(); + m_impl->group=gd; + m_impl->grouppri=pri; + m_impl->groupFileName=fileName; + m_impl->groupStartLine=startLine; + m_impl->groupHasDocs=hasDocs; + m_impl->groupMember=member; + m_isLinkableCached = 0; +} + +void MemberDef::setEnumScope(MemberDef *md) +{ + makeResident(); + m_impl->enumScope=md; + if (md->getGroupDef()) + { + m_impl->group=md->getGroupDef(); + m_impl->grouppri=md->getGroupPri(); + m_impl->groupFileName=md->getGroupFileName(); + m_impl->groupStartLine=md->getGroupStartLine(); + m_impl->groupHasDocs=md->getGroupHasDocs(); + m_isLinkableCached = 0; + } +} + +void MemberDef::setMemberClass(ClassDef *cd) +{ + makeResident(); + m_impl->classDef=cd; + m_isLinkableCached = 0; + m_isConstructorCached = 0; + setOuterScope(cd); +} + +void MemberDef::setNamespace(NamespaceDef *nd) +{ + makeResident(); + m_impl->nspace=nd; + setOuterScope(nd); +} + +MemberDef *MemberDef::createTemplateInstanceMember( + ArgumentList *formalArgs,ArgumentList *actualArgs) +{ + KEEP_RESIDENT_DURING_CALL; + //printf(" Member %s %s %s\n",typeString(),name().data(),argsString()); + ArgumentList *actualArgList = 0; + if (m_impl->defArgList) + { + actualArgList = new ArgumentList; + ArgumentListIterator ali(*m_impl->defArgList); + Argument *arg; + for (;(arg=ali.current());++ali) + { + Argument *actArg = new Argument(*arg); + actArg->type = substituteTemplateArgumentsInString(actArg->type,formalArgs,actualArgs); + actualArgList->append(actArg); + } + actualArgList->constSpecifier = m_impl->defArgList->constSpecifier; + actualArgList->volatileSpecifier = m_impl->defArgList->volatileSpecifier; + actualArgList->pureSpecifier = m_impl->defArgList->pureSpecifier; + } + + QCString methodName=name(); + if (methodName.left(9)=="operator ") // conversion operator + { + methodName=substituteTemplateArgumentsInString(methodName,formalArgs,actualArgs); + } + + MemberDef *imd = new MemberDef( + getDefFileName(),getDefLine(), + substituteTemplateArgumentsInString(m_impl->type,formalArgs,actualArgs), + methodName, + substituteTemplateArgumentsInString(m_impl->args,formalArgs,actualArgs), + m_impl->exception, m_impl->prot, + m_impl->virt, m_impl->stat, m_impl->related, m_impl->mtype, 0, 0 + ); + imd->setArgumentList(actualArgList); + imd->setDefinition(substituteTemplateArgumentsInString(m_impl->def,formalArgs,actualArgs)); + imd->setBodyDef(getBodyDef()); + imd->setBodySegment(getStartBodyLine(),getEndBodyLine()); + //imd->setBodyMember(this); + + // TODO: init other member variables (if needed). + // TODO: reimplemented info + return imd; +} + +bool MemberDef::hasOneLineInitializer() const +{ + makeResident(); + //printf("%s: init=%s, initLines=%d maxInitLines=%d userInitLines=%d\n", + // name().data(),m_impl->initializer.data(),m_impl->initLines, + // m_impl->maxInitLines,m_impl->userInitLines); + return !m_impl->initializer.isEmpty() && m_impl->initLines==0 && // one line initializer + ((m_impl->maxInitLines>0 && m_impl->userInitLines==-1) || m_impl->userInitLines>0); // enabled by default or explicitly +} + +bool MemberDef::hasMultiLineInitializer() const +{ + makeResident(); + //printf("initLines=%d userInitLines=%d maxInitLines=%d\n", + // initLines,userInitLines,maxInitLines); + return m_impl->initLines>0 && + ((m_impl->initLinesmaxInitLines && m_impl->userInitLines==-1) // implicitly enabled + || m_impl->initLinesuserInitLines // explicitly enabled + ); +} + +void MemberDef::setInitializer(const char *initializer) +{ + makeResident(); + m_impl->initializer=initializer; + int p=m_impl->initializer.length()-1; + while (p>=0 && isspace((uchar)m_impl->initializer.at(p))) p--; + m_impl->initializer=m_impl->initializer.left(p+1); + m_impl->initLines=m_impl->initializer.contains('\n'); +} + +void MemberDef::addListReference(Definition *) +{ + KEEP_RESIDENT_DURING_CALL; + static bool optimizeOutputForC = Config_getBool("OPTIMIZE_OUTPUT_FOR_C"); + //static bool hideScopeNames = Config_getBool("HIDE_SCOPE_NAMES"); + //static bool optimizeOutputJava = Config_getBool("OPTIMIZE_OUTPUT_JAVA"); + //static bool fortranOpt = Config_getBool("OPTIMIZE_FOR_FORTRAN"); + SrcLangExt lang = getLanguage(); + visited=TRUE; + if (!isLinkableInProject()) return; + QCString memLabel; + if (optimizeOutputForC) + { + memLabel=theTranslator->trGlobal(TRUE,TRUE); + } + else if (lang==SrcLangExt_Fortran) + { + memLabel=theTranslator->trSubprogram(TRUE,TRUE); + } + else + { + memLabel=theTranslator->trMember(TRUE,TRUE); + } + QCString memName = name(); + Definition *pd=getOuterScope(); + QCString pdName = pd->definitionType()==Definition::TypeClass ? + ((ClassDef*)pd)->displayName() : pd->name(); + QCString sep = getLanguageSpecificSeparator(lang,TRUE); + QCString memArgs; + if (!isRelated() + /* && commented out as a result of bug 597016 + ( + (!hideScopeNames && // there is a scope + pd && pd!=Doxygen::globalScope) // and we can show it + || + (pd=getClassDef()) // it's a class so we + // show the scope anyway + ) + */ + ) + { + if (isObjCMethod()) + { + memName = "[" + pd->name() + " " + name() + "]"; + } + else + { + if (pd!=Doxygen::globalScope) memName.prepend(pdName+sep); + memArgs = argsString(); + } + } + LockingPtr< QList > xrefItems = xrefListItems(); + if (xrefItems!=0) + { + addRefItem(xrefItems.pointer(), + qualifiedName()+argsString(), // argsString is needed for overloaded functions (see bug 609624) + memLabel, + getOutputFileBase()+"#"+anchor(),memName,memArgs); + } +} + +MemberList *MemberDef::getSectionList(Definition *d) const +{ + makeResident(); + char key[20]; + sprintf(key,"%p",d); + return (d!=0 && m_impl->classSectionSDict) ? m_impl->classSectionSDict->find(key) : 0; +} + +void MemberDef::setSectionList(Definition *d, MemberList *sl) +{ + makeResident(); + //printf("MemberDef::setSectionList(%p,%p) name=%s\n",d,sl,name().data()); + char key[20]; + sprintf(key,"%p",d); + if (m_impl->classSectionSDict==0) + { + m_impl->classSectionSDict = new SDict(7); + } + m_impl->classSectionSDict->append(key,sl); +} + +Specifier MemberDef::virtualness(int count) const +{ + KEEP_RESIDENT_DURING_CALL; + if (count>25) + { + warn(getDefFileName(),getDefLine(), + "warning: Internal inconsistency: recursion detected in overload relation for member %s!" + ,qPrint(name()) + ); + return Normal; + } + makeResident(); + Specifier v = m_impl->virt; + MemberDef *rmd = reimplements(); + while (rmd && v==Normal) + { + v = rmd->virtualness(count+1)==Normal ? Normal : Virtual; + rmd = rmd->reimplements(); + } + return v; +} + +void MemberDef::_computeIsConstructor() +{ + KEEP_RESIDENT_DURING_CALL; + m_isConstructorCached=1; // FALSE + if (m_impl->classDef) + { + if (m_impl->isDMember) // for D + { + m_isConstructorCached = name()=="this" ? 2 : 1; + return; + } + else if (getLanguage()==SrcLangExt_PHP) // for PHP + { + m_isConstructorCached = name()=="__construct" ? 2 : 1; + return; + } + else if (name()=="__init__" && + getLanguage()==SrcLangExt_Python) // for Python + { + m_isConstructorCached = 2; // TRUE + return; + } + else if (getLanguage()==SrcLangExt_Tcl) // for Tcl + { + m_isConstructorCached = name()=="constructor" ? 2 : 1; + return; + } + else // for other languages + { + QCString locName = m_impl->classDef->localName(); + int i=locName.find('<'); + if (i==-1) // not a template class + { + m_isConstructorCached = name()==locName ? 2 : 1; + } + else + { + m_isConstructorCached = name()==locName.left(i) ? 2 : 1; + } + return; + } + } +} + +bool MemberDef::isConstructor() const +{ + if (m_isConstructorCached==0) + { + MemberDef *that = (MemberDef*)this; + that->_computeIsConstructor(); + } + ASSERT(m_isConstructorCached>0); + return m_isConstructorCached==2; + +} + +void MemberDef::_computeIsDestructor() +{ + KEEP_RESIDENT_DURING_CALL; + bool isDestructor; + if (m_impl->isDMember) // for D + { + isDestructor = name()=="~this"; + } + else if (getLanguage()==SrcLangExt_PHP) // for PHP + { + isDestructor = name()=="__destruct"; + } + else if (getLanguage()==SrcLangExt_Tcl) // for Tcl + { + isDestructor = name()=="destructor"; + } + else if (name()=="__del__" && + getLanguage()==SrcLangExt_Python) // for Python + { + isDestructor=TRUE; + } + else // other languages + { + isDestructor = + (name().find('~')!=-1 || name().find('!')!=-1) // The ! is for C++/CLI + && name().find("operator")==-1; + } + m_isDestructorCached = isDestructor ? 2 : 1; +} + +bool MemberDef::isDestructor() const +{ + if (m_isDestructorCached==0) + { + MemberDef *that=(MemberDef*)this; + that->_computeIsDestructor(); + } + ASSERT(m_isDestructorCached>0); + return m_isDestructorCached==2; +} + +void MemberDef::writeEnumDeclaration(OutputList &typeDecl, + ClassDef *cd,NamespaceDef *nd,FileDef *fd,GroupDef *gd) +{ + KEEP_RESIDENT_DURING_CALL; + + int enumMemCount=0; + + QList *fmdl=m_impl->enumFields; + uint numVisibleEnumValues=0; + if (fmdl) + { + MemberDef *fmd=fmdl->first(); + while (fmd) + { + if (fmd->isBriefSectionVisible()) numVisibleEnumValues++; + fmd=fmdl->next(); + } + } + if (numVisibleEnumValues==0 && !isBriefSectionVisible()) + { + return; + } + + QCString n = name(); + int i=n.findRev("::"); + if (i!=-1) n=n.right(n.length()-i-2); // strip scope (TODO: is this needed?) + if (n[0]!='@') // not an anonymous enum + { + if (isLinkableInProject() || hasDocumentedEnumValues()) + { + if (!Config_getString("GENERATE_TAGFILE").isEmpty() && !isReference()) + { + Doxygen::tagFile << " " << endl; + Doxygen::tagFile << " " << convertToXML(name()) << "" << endl; + Doxygen::tagFile << " " << convertToXML(getOutputFileBase()+Doxygen::htmlFileExtension) << "" << endl; + Doxygen::tagFile << " " << convertToXML(anchor()) << "" << endl; + Doxygen::tagFile << " " << convertToXML(argsString()) << "" << endl; + Doxygen::tagFile << " " << endl; + } + writeLink(typeDecl,cd,nd,fd,gd); + } + else + { + typeDecl.startBold(); + typeDecl.docify(n); + typeDecl.endBold(); + } + typeDecl.writeChar(' '); + } + + uint enumValuesPerLine = (uint)Config_getInt("ENUM_VALUES_PER_LINE"); + if (numVisibleEnumValues>0 && enumValuesPerLine>0) + { + typeDecl.docify("{ "); + if (fmdl) + { + MemberDef *fmd=fmdl->first(); + bool fmdVisible = fmd->isBriefSectionVisible(); + while (fmd) + { + 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.enable(OutputGenerator::Latex); + typeDecl.lineBreak(); + typeDecl.disable(OutputGenerator::Latex); + typeDecl.writeString("  "); + typeDecl.popGeneratorState(); + } + + if (fmd->hasDocumentation()) // enum value has docs + { + if (!Config_getString("GENERATE_TAGFILE").isEmpty() && !fmd->isReference()) + { + Doxygen::tagFile << " " << endl; + Doxygen::tagFile << " " << convertToXML(fmd->name()) << "" << endl; + Doxygen::tagFile << " " << convertToXML(getOutputFileBase()+Doxygen::htmlFileExtension) << "" << endl; + Doxygen::tagFile << " " << convertToXML(fmd->anchor()) << "" << endl; + Doxygen::tagFile << " " << convertToXML(fmd->argsString()) << "" << endl; + Doxygen::tagFile << " " << endl; + } + fmd->writeLink(typeDecl,cd,nd,fd,gd); + } + else // no docs for this enum value + { + typeDecl.startBold(); + typeDecl.docify(fmd->name()); + typeDecl.endBold(); + } + if (fmd->hasOneLineInitializer()) // enum value has initializer + { + typeDecl.writeString(" = "); + typeDecl.parseText(fmd->initializer()); + } + } + + bool prevVisible = fmdVisible; + fmd=fmdl->next(); + if (fmd && (fmdVisible=fmd->isBriefSectionVisible())) + { + typeDecl.writeString(", "); + } + if (prevVisible) + { + typeDecl.disable(OutputGenerator::Man); + typeDecl.writeString("\n"); // to prevent too long lines in LaTeX + typeDecl.enable(OutputGenerator::Man); + enumMemCount++; + } + } + if (numVisibleEnumValues>enumValuesPerLine) + { + typeDecl.pushGeneratorState(); + typeDecl.disableAllBut(OutputGenerator::Html); + typeDecl.lineBreak(); + typeDecl.popGeneratorState(); + } + } + typeDecl.docify(" }"); + } +} + +void MemberDef::setArgumentList(ArgumentList *al) +{ + makeResident(); + if (m_impl->defArgList) delete m_impl->defArgList; + m_impl->defArgList = al; +} + +void MemberDef::setDeclArgumentList(ArgumentList *al) +{ + makeResident(); + if (m_impl->declArgList) delete m_impl->declArgList; + m_impl->declArgList = al; +} + +void MemberDef::setTypeConstraints(ArgumentList *al) +{ + if (al==0) return; + makeResident(); + if (m_impl->typeConstraints) delete m_impl->typeConstraints; + m_impl->typeConstraints = new ArgumentList; + m_impl->typeConstraints->setAutoDelete(TRUE); + ArgumentListIterator ali(*al); + Argument *a; + for (;(a=ali.current());++ali) + { + m_impl->typeConstraints->append(new Argument(*a)); + } +} + +void MemberDef::setType(const char *t) +{ + makeResident(); + m_impl->type = t; +} + +void MemberDef::findSectionsInDocumentation() +{ + makeResident(); + docFindSections(documentation(),this,0,docFile()); +} + +void MemberDef::enableCallGraph(bool e) +{ + makeResident(); + m_impl->hasCallGraph=e; + if (e) Doxygen::parseSourcesNeeded = TRUE; +} + +void MemberDef::enableCallerGraph(bool e) +{ + makeResident(); + m_impl->hasCallerGraph=e; + if (e) Doxygen::parseSourcesNeeded = TRUE; +} + +#if 0 +bool MemberDef::protectionVisible() const +{ + makeResident(); + return m_impl->prot==Public || + (m_impl->prot==Private && Config_getBool("EXTRACT_PRIVATE")) || + (m_impl->prot==Protected && Config_getBool("EXTRACT_PROTECTED")) || + (m_impl->prot==Package && Config_getBool("EXTRACT_PACKAGE")); +} +#endif + +#if 0 +void MemberDef::setInbodyDocumentation(const char *docs, + const char *docFile,int docLine) +{ + makeResident(); + m_impl->inbodyDocs = docs; + m_impl->inbodyDocs = m_impl->inbodyDocs.stripWhiteSpace(); + m_impl->inbodyLine = docLine; + m_impl->inbodyFile = docFile; +} +#endif + +bool MemberDef::isObjCMethod() const +{ + makeResident(); + if (m_impl->classDef && m_impl->classDef->isObjectiveC() && isFunction()) return TRUE; + return FALSE; +} + +bool MemberDef::isObjCProperty() const +{ + makeResident(); + if (m_impl->classDef && m_impl->classDef->isObjectiveC() && isProperty()) return TRUE; + return FALSE; +} + +QCString MemberDef::qualifiedName() const +{ + makeResident(); + if (isObjCMethod()) + { + QCString qm; + if (isStatic()) qm="+"; else qm="-"; + qm+="["; + qm+=m_impl->classDef->name()+" "; + qm+=name(); + qm+="]"; + return qm; + } + else + { + return Definition::qualifiedName(); + } +} + +void MemberDef::setTagInfo(TagInfo *ti) +{ + if (ti) + { + makeResident(); + //printf("%s: Setting tag name=%s anchor=%s\n",name().data(),ti->tagName.data(),ti->anchor.data()); + m_impl->anc=ti->anchor; + setReference(ti->tagName); + m_impl->explicitOutputFileBase = stripExtension(ti->fileName); + } +} + +QCString MemberDef::objCMethodName(bool localLink,bool showStatic) const +{ + makeResident(); + QCString qm; + if (showStatic) + { + if (isStatic()) qm="+ "; else qm="- "; + } + qm+=name(); + if (!localLink) // link to method of same class + { + qm+=" ("; + qm+=m_impl->classDef->name(); + qm+=")"; + } + return qm; +} + +const char *MemberDef::declaration() const +{ + makeResident(); + return m_impl->decl; +} + +const char *MemberDef::definition() const +{ + makeResident(); + return m_impl->def; +} + +const char *MemberDef::extraTypeChars() const +{ + makeResident(); + return m_impl->extraTypeChars; +} + +const char *MemberDef::typeString() const +{ + makeResident(); + return m_impl->type; +} + +const char *MemberDef::argsString() const +{ + makeResident(); + return m_impl->args; +} + +const char *MemberDef::excpString() const +{ + makeResident(); + return m_impl->exception; +} + +const char *MemberDef::bitfieldString() const +{ + makeResident(); + return m_impl->bitfields; +} + +const QCString &MemberDef::initializer() const +{ + makeResident(); + return m_impl->initializer; +} + +int MemberDef::initializerLines() const +{ + makeResident(); + return m_impl->initLines; +} + +int MemberDef::getMemberSpecifiers() const +{ + makeResident(); + return m_impl->memSpec; +} + +ClassDef *MemberDef::getClassDef() const +{ + makeResident(); + return m_impl->classDef; +} + +FileDef *MemberDef::getFileDef() const +{ + makeResident(); + return m_impl->fileDef; +} + +NamespaceDef* MemberDef::getNamespaceDef() const +{ + makeResident(); + return m_impl->nspace; +} + +const char *MemberDef::getReadAccessor() const +{ + makeResident(); + return m_impl->read; +} + +const char *MemberDef::getWriteAccessor() const +{ + makeResident(); + return m_impl->write; +} + +GroupDef *MemberDef::getGroupDef() const +{ + makeResident(); + return m_impl->group; +} + +Grouping::GroupPri_t MemberDef::getGroupPri() const +{ + makeResident(); + return m_impl->grouppri; +} + +const char *MemberDef::getGroupFileName() const +{ + makeResident(); + return m_impl->groupFileName; +} + +int MemberDef::getGroupStartLine() const +{ + makeResident(); + return m_impl->groupStartLine; +} + +bool MemberDef::getGroupHasDocs() const +{ + makeResident(); + return m_impl->groupHasDocs; +} + +Protection MemberDef::protection() const +{ + makeResident(); + return m_impl->prot; +} + +MemberDef::MemberType MemberDef::memberType() const +{ + makeResident(); + return m_impl->mtype; +} + +bool MemberDef::isSignal() const +{ + makeResident(); + return m_impl->mtype==Signal; +} + +bool MemberDef::isSlot() const +{ + makeResident(); + return m_impl->mtype==Slot; +} + +bool MemberDef::isVariable() const +{ + makeResident(); + return m_impl->mtype==Variable; +} + +bool MemberDef::isEnumerate() const +{ + makeResident(); + return m_impl->mtype==Enumeration; +} + +bool MemberDef::isEnumValue() const +{ + makeResident(); + return m_impl->mtype==EnumValue; +} + +bool MemberDef::isTypedef() const +{ + makeResident(); + return m_impl->mtype==Typedef; +} + +bool MemberDef::isFunction() const +{ + makeResident(); + return m_impl->mtype==Function; +} + +bool MemberDef::isFunctionPtr() const +{ + makeResident(); + return m_impl->mtype==Variable && QCString(argsString()).find(")(")!=-1; +} + +bool MemberDef::isDefine() const +{ + makeResident(); + return m_impl->mtype==Define; +} + +bool MemberDef::isFriend() const +{ + makeResident(); + return m_impl->mtype==Friend; +} + +bool MemberDef::isDCOP() const +{ + makeResident(); + return m_impl->mtype==DCOP; +} + +bool MemberDef::isProperty() const +{ + makeResident(); + return m_impl->mtype==Property; +} + +bool MemberDef::isEvent() const +{ + makeResident(); + return m_impl->mtype==Event; +} + +bool MemberDef::isRelated() const +{ + makeResident(); + return m_impl->related == Related; +} + +bool MemberDef::isForeign() const +{ + makeResident(); + return m_impl->related == Foreign; +} + +bool MemberDef::isStatic() const +{ + makeResident(); + return m_impl->stat; +} + +bool MemberDef::isInline() const +{ + makeResident(); + return (m_impl->memSpec&Entry::Inline)!=0; +} + +bool MemberDef::isExplicit() const +{ + makeResident(); + return (m_impl->memSpec&Entry::Explicit)!=0; +} + +bool MemberDef::isMutable() const +{ + makeResident(); + return (m_impl->memSpec&Entry::Mutable)!=0; +} + +bool MemberDef::isGettable() const +{ + makeResident(); + return (m_impl->memSpec&Entry::Gettable)!=0; +} + +bool MemberDef::isSettable() const +{ + makeResident(); + return (m_impl->memSpec&Entry::Settable)!=0; +} + +bool MemberDef::isAddable() const +{ + makeResident(); + return (m_impl->memSpec&Entry::Addable)!=0; +} + +bool MemberDef::isRemovable() const +{ + makeResident(); + return (m_impl->memSpec&Entry::Removable)!=0; +} + +bool MemberDef::isRaisable() const +{ + makeResident(); + return (m_impl->memSpec&Entry::Raisable)!=0; +} + +bool MemberDef::isReadable() const +{ + makeResident(); + return (m_impl->memSpec&Entry::Readable)!=0; +} + +bool MemberDef::isWritable() const +{ + makeResident(); + return (m_impl->memSpec&Entry::Writable)!=0; +} + +bool MemberDef::isFinal() const +{ + makeResident(); + return (m_impl->memSpec&Entry::Final)!=0; +} + +bool MemberDef::isNew() const +{ + makeResident(); + return (m_impl->memSpec&Entry::New)!=0; +} + +bool MemberDef::isSealed() const +{ + makeResident(); + return (m_impl->memSpec&Entry::Sealed)!=0; +} + +bool MemberDef::isOverride() const +{ + makeResident(); + return (m_impl->memSpec&Entry::Override)!=0; +} + +bool MemberDef::isInitonly() const +{ + makeResident(); + return (m_impl->memSpec&Entry::Initonly)!=0; +} + +bool MemberDef::isAbstract() const +{ + makeResident(); + return (m_impl->memSpec&Entry::Abstract)!=0; +} + +bool MemberDef::isOptional() const +{ + makeResident(); + return (m_impl->memSpec&Entry::Optional)!=0; +} + +bool MemberDef::isRequired() const +{ + makeResident(); + return (m_impl->memSpec&Entry::Required)!=0; +} + +bool MemberDef::isNonAtomic() const +{ + makeResident(); + return (m_impl->memSpec&Entry::NonAtomic)!=0; +} + +bool MemberDef::isCopy() const +{ + makeResident(); + return (m_impl->memSpec&Entry::Copy)!=0; +} + +bool MemberDef::isAssign() const +{ + makeResident(); + return (m_impl->memSpec&Entry::Assign)!=0; +} + +bool MemberDef::isRetain() const +{ + makeResident(); + return (m_impl->memSpec&Entry::Retain)!=0; +} + + +bool MemberDef::isImplementation() const +{ + makeResident(); + return m_impl->implOnly; +} + +bool MemberDef::isExternal() const +{ + makeResident(); + return m_impl->explExt; +} + +bool MemberDef::isTemplateSpecialization() const +{ + makeResident(); + return m_impl->tspec; +} + +bool MemberDef::hasDocumentedParams() const +{ + makeResident(); + return m_impl->hasDocumentedParams; +} + +bool MemberDef::hasDocumentedReturnType() const +{ + makeResident(); + return m_impl->hasDocumentedReturnType; +} + +ClassDef *MemberDef::relatedAlso() const +{ + makeResident(); + return m_impl->relatedAlso; +} + +bool MemberDef::hasDocumentedEnumValues() const +{ + makeResident(); + return m_impl->docEnumValues; +} + +MemberDef *MemberDef::getAnonymousEnumType() const +{ + makeResident(); + return m_impl->annEnumType; +} + +bool MemberDef::isDocsForDefinition() const +{ + makeResident(); + return m_impl->docsForDefinition; +} + +MemberDef *MemberDef::getEnumScope() const +{ + makeResident(); + return m_impl->enumScope; +} + +LockingPtr MemberDef::enumFieldList() const +{ + makeResident(); + return LockingPtr(this,m_impl->enumFields); +} + +LockingPtr MemberDef::getExamples() const +{ + makeResident(); + return LockingPtr(this,m_impl->exampleSDict); +} + +bool MemberDef::isPrototype() const +{ + makeResident(); + return m_impl->proto; +} + +LockingPtr MemberDef::argumentList() const +{ + makeResident(); + return LockingPtr(this,m_impl->defArgList); +} + +LockingPtr MemberDef::declArgumentList() const +{ + makeResident(); + return LockingPtr(this,m_impl->declArgList); +} + +LockingPtr MemberDef::templateArguments() const +{ + makeResident(); + return LockingPtr(this,m_impl->tArgList); +} + +LockingPtr< QList > MemberDef::definitionTemplateParameterLists() const +{ + makeResident(); + return LockingPtr< QList >(this,m_impl->defTmpArgLists); +} + +int MemberDef::getMemberGroupId() const +{ + makeResident(); + return m_impl->grpId; +} + +MemberGroup *MemberDef::getMemberGroup() const +{ + makeResident(); + return m_impl->memberGroup; +} + +bool MemberDef::fromAnonymousScope() const +{ + makeResident(); + return m_impl->annScope; +} + +bool MemberDef::anonymousDeclShown() const +{ + makeResident(); + return m_impl->annUsed; +} + +void MemberDef::setAnonymousUsed() +{ + makeResident(); + m_impl->annUsed = TRUE; +} + +bool MemberDef::hasCallGraph() const +{ + makeResident(); + return m_impl->hasCallGraph; +} + +bool MemberDef::hasCallerGraph() const +{ + makeResident(); + return m_impl->hasCallerGraph; +} + +MemberDef *MemberDef::templateMaster() const +{ + makeResident(); + return m_impl->templateMaster; +} + +bool MemberDef::isTypedefValCached() const +{ + makeResident(); + return m_impl->isTypedefValCached; +} + +ClassDef *MemberDef::getCachedTypedefVal() const +{ + makeResident(); + return m_impl->cachedTypedefValue; +} + +QCString MemberDef::getCachedTypedefTemplSpec() const +{ + makeResident(); + return m_impl->cachedTypedefTemplSpec; +} + +QCString MemberDef::getCachedResolvedTypedef() const +{ + makeResident(); + //printf("MemberDef::getCachedResolvedTypedef()=%s m_impl=%p\n",m_impl->cachedResolvedType.data(),m_impl); + return m_impl->cachedResolvedType; +} + +MemberDef *MemberDef::memberDefinition() const +{ + makeResident(); + return m_impl->memDef; +} + +MemberDef *MemberDef::memberDeclaration() const +{ + makeResident(); + return m_impl->memDec; +} + +MemberDef *MemberDef::inheritsDocsFrom() const +{ + makeResident(); + return m_impl->docProvider; +} + +MemberDef *MemberDef::getGroupAlias() const +{ + makeResident(); + return m_impl->groupAlias; +} + +void MemberDef::setMemberType(MemberType t) +{ + makeResident(); + m_impl->mtype=t; + m_isLinkableCached = 0; +} + +void MemberDef::setDefinition(const char *d) +{ + makeResident(); + m_impl->def=d; +} + +void MemberDef::setFileDef(FileDef *fd) +{ + makeResident(); + m_impl->fileDef=fd; + m_isLinkableCached = 0; + m_isConstructorCached = 0; + m_isDestructorCached = 0; +} + +void MemberDef::setProtection(Protection p) +{ + makeResident(); + m_impl->prot=p; + m_isLinkableCached = 0; +} + +void MemberDef::setMemberSpecifiers(int s) +{ + makeResident(); + m_impl->memSpec=s; +} + +void MemberDef::mergeMemberSpecifiers(int s) +{ + makeResident(); + m_impl->memSpec|=s; +} + +void MemberDef::setBitfields(const char *s) +{ + makeResident(); + m_impl->bitfields = s; +} + +void MemberDef::setMaxInitLines(int lines) +{ + if (lines!=-1) + { + makeResident(); + m_impl->userInitLines=lines; + } +} + +void MemberDef::setExplicitExternal(bool b) +{ + makeResident(); + m_impl->explExt=b; +} + +void MemberDef::setReadAccessor(const char *r) +{ + makeResident(); + m_impl->read=r; +} + +void MemberDef::setWriteAccessor(const char *w) +{ + makeResident(); + m_impl->write=w; +} + +void MemberDef::setTemplateSpecialization(bool b) +{ + makeResident(); + m_impl->tspec=b; +} + +void MemberDef::makeRelated() +{ + makeResident(); + m_impl->related = Related; + m_isLinkableCached = 0; +} + +void MemberDef::makeForeign() +{ + makeResident(); + m_impl->related = Foreign; + m_isLinkableCached = 0; +} + +void MemberDef::setHasDocumentedParams(bool b) +{ + makeResident(); + m_impl->hasDocumentedParams = b; +} + +void MemberDef::setHasDocumentedReturnType(bool b) +{ + makeResident(); + m_impl->hasDocumentedReturnType = b; +} + +void MemberDef::setInheritsDocsFrom(MemberDef *md) +{ + makeResident(); + m_impl->docProvider = md; +} + +void MemberDef::setArgsString(const char *as) +{ + makeResident(); + m_impl->args = as; +} + +void MemberDef::setRelatedAlso(ClassDef *cd) +{ + makeResident(); + m_impl->relatedAlso=cd; +} + +void MemberDef::setEnumClassScope(ClassDef *cd) +{ + makeResident(); + m_impl->classDef = cd; + m_isLinkableCached = 0; + m_isConstructorCached = 0; +} + +void MemberDef::setDocumentedEnumValues(bool value) +{ + makeResident(); + m_impl->docEnumValues=value; +} + +void MemberDef::setAnonymousEnumType(MemberDef *md) +{ + makeResident(); + m_impl->annEnumType = md; +} + +void MemberDef::setPrototype(bool p) +{ + makeResident(); + m_impl->proto=p; +} + +void MemberDef::setMemberGroupId(int id) +{ + makeResident(); + m_impl->grpId=id; +} + +void MemberDef::makeImplementationDetail() +{ + makeResident(); + m_impl->implOnly=TRUE; +} + +void MemberDef::setFromAnonymousScope(bool b) +{ + makeResident(); + m_impl->annScope=b; +} + +void MemberDef::setFromAnonymousMember(MemberDef *m) +{ + makeResident(); + m_impl->annMemb=m; +} + +void MemberDef::setTemplateMaster(MemberDef *mt) +{ + makeResident(); + m_impl->templateMaster=mt; + m_isLinkableCached = 0; +} + +void MemberDef::setDocsForDefinition(bool b) +{ + makeResident(); + m_impl->docsForDefinition = b; +} + +void MemberDef::setGroupAlias(MemberDef *md) +{ + makeResident(); + m_impl->groupAlias = md; +} + +void MemberDef::invalidateTypedefValCache() +{ + makeResident(); + m_impl->isTypedefValCached=FALSE; +} + +void MemberDef::setMemberDefinition(MemberDef *md) +{ + makeResident(); + m_impl->memDef=md; +} + +void MemberDef::setMemberDeclaration(MemberDef *md) +{ + makeResident(); + m_impl->memDec=md; +} + +ClassDef *MemberDef::category() const +{ + makeResident(); + return m_impl->category; +} + +void MemberDef::setCategory(ClassDef *def) +{ + makeResident(); + m_impl->category = def; +} + + +void MemberDef::cacheTypedefVal(ClassDef*val, const QCString & templSpec, const QCString &resolvedType) +{ + makeResident(); + m_impl->isTypedefValCached=TRUE; + m_impl->cachedTypedefValue=val; + m_impl->cachedTypedefTemplSpec=templSpec; + m_impl->cachedResolvedType=resolvedType; + //printf("MemberDef::cacheTypedefVal=%s m_impl=%p\n",m_impl->cachedResolvedType.data(),m_impl); +} + +void MemberDef::copyArgumentNames(MemberDef *bmd) +{ + makeResident(); + { + LockingPtr arguments = bmd->argumentList(); + if (m_impl->defArgList && arguments!=0) + { + ArgumentListIterator aliDst(*m_impl->defArgList); + ArgumentListIterator aliSrc(*arguments); + Argument *argDst, *argSrc; + for (;(argDst=aliDst.current()) && (argSrc=aliSrc.current());++aliDst,++aliSrc) + { + argDst->name = argSrc->name; + } + } + } + { + LockingPtr arguments = bmd->declArgumentList(); + if (m_impl->declArgList && arguments!=0) + { + ArgumentListIterator aliDst(*m_impl->declArgList); + ArgumentListIterator aliSrc(*arguments); + Argument *argDst, *argSrc; + for (;(argDst=aliDst.current()) && (argSrc=aliSrc.current());++aliDst,++aliSrc) + { + argDst->name = argSrc->name; + } + } + } +} + +static void invalidateCachedTypesInArgumentList(ArgumentList *al) +{ + if (al) + { + ArgumentListIterator ali(*al); + Argument *a; + for (ali.toFirst();(a=ali.current());++ali) + { + a->canType.resize(0); + } + } +} + +void MemberDef::invalidateCachedArgumentTypes() +{ + makeResident(); + invalidateCachedTypesInArgumentList(m_impl->defArgList); + invalidateCachedTypesInArgumentList(m_impl->declArgList); +} + + +//----------------------------------------------------------------- + +void MemberDef::flushToDisk() const +{ + if (isLocked()) return; + MemberDef *that = (MemberDef*)this; + that->m_storagePos = Doxygen::symbolStorage->alloc(); + //printf("%p: MemberDef::flushToDisk() m_impl=%p\n",this,m_impl); + // write the definition base class member variables to disk + Definition::flushToDisk(); + + //printf("%p: flushing specific part\n",this); + + // write the memberdef member variables to disk + marshalUInt(Doxygen::symbolStorage,START_MARKER); + marshalObjPointer (Doxygen::symbolStorage,m_impl->classDef); + marshalObjPointer (Doxygen::symbolStorage,m_impl->fileDef); + marshalObjPointer (Doxygen::symbolStorage,m_impl->nspace); + marshalObjPointer (Doxygen::symbolStorage,m_impl->enumScope); + marshalObjPointer (Doxygen::symbolStorage,m_impl->annEnumType); + marshalMemberList (Doxygen::symbolStorage,m_impl->enumFields); + marshalObjPointer (Doxygen::symbolStorage,m_impl->redefines); + marshalMemberList (Doxygen::symbolStorage,m_impl->redefinedBy); + marshalObjPointer (Doxygen::symbolStorage,m_impl->memDef); + marshalObjPointer (Doxygen::symbolStorage,m_impl->memDec); + marshalObjPointer (Doxygen::symbolStorage,m_impl->relatedAlso); + marshalExampleSDict (Doxygen::symbolStorage,m_impl->exampleSDict); + marshalQCString (Doxygen::symbolStorage,m_impl->type); + marshalQCString (Doxygen::symbolStorage,m_impl->args); + marshalQCString (Doxygen::symbolStorage,m_impl->def); + marshalQCString (Doxygen::symbolStorage,m_impl->anc); + marshalInt (Doxygen::symbolStorage,(int)m_impl->virt); + marshalInt (Doxygen::symbolStorage,(int)m_impl->prot); + marshalQCString (Doxygen::symbolStorage,m_impl->decl); + marshalQCString (Doxygen::symbolStorage,m_impl->bitfields); + marshalQCString (Doxygen::symbolStorage,m_impl->read); + marshalQCString (Doxygen::symbolStorage,m_impl->write); + marshalQCString (Doxygen::symbolStorage,m_impl->exception); + marshalQCString (Doxygen::symbolStorage,m_impl->initializer); + marshalQCString (Doxygen::symbolStorage,m_impl->extraTypeChars); + marshalInt (Doxygen::symbolStorage,m_impl->initLines); + marshalInt (Doxygen::symbolStorage,m_impl->memSpec); + marshalInt (Doxygen::symbolStorage,(int)m_impl->mtype); + marshalInt (Doxygen::symbolStorage,m_impl->maxInitLines); + marshalInt (Doxygen::symbolStorage,m_impl->userInitLines); + marshalObjPointer (Doxygen::symbolStorage,m_impl->annMemb); + marshalArgumentList (Doxygen::symbolStorage,m_impl->defArgList); + marshalArgumentList (Doxygen::symbolStorage,m_impl->declArgList); + marshalArgumentList (Doxygen::symbolStorage,m_impl->tArgList); + marshalArgumentList (Doxygen::symbolStorage,m_impl->typeConstraints); + marshalObjPointer (Doxygen::symbolStorage,m_impl->templateMaster); + marshalArgumentLists(Doxygen::symbolStorage,m_impl->defTmpArgLists); + marshalObjPointer (Doxygen::symbolStorage,m_impl->cachedAnonymousType); + marshalMemberLists (Doxygen::symbolStorage,m_impl->classSectionSDict); + marshalObjPointer (Doxygen::symbolStorage,m_impl->groupAlias); + marshalInt (Doxygen::symbolStorage,m_impl->grpId); + marshalObjPointer (Doxygen::symbolStorage,m_impl->memberGroup); + marshalObjPointer (Doxygen::symbolStorage,m_impl->group); + marshalInt (Doxygen::symbolStorage,(int)m_impl->grouppri); + marshalQCString (Doxygen::symbolStorage,m_impl->groupFileName); + marshalInt (Doxygen::symbolStorage,m_impl->groupStartLine); + marshalObjPointer (Doxygen::symbolStorage,m_impl->groupMember); + marshalBool (Doxygen::symbolStorage,m_impl->isTypedefValCached); + marshalObjPointer (Doxygen::symbolStorage,m_impl->cachedTypedefValue); + marshalQCString (Doxygen::symbolStorage,m_impl->cachedTypedefTemplSpec); + marshalQCString (Doxygen::symbolStorage,m_impl->cachedResolvedType); + marshalObjPointer (Doxygen::symbolStorage,m_impl->docProvider); + marshalQCString (Doxygen::symbolStorage,m_impl->explicitOutputFileBase); + marshalBool (Doxygen::symbolStorage,m_impl->implOnly); + marshalBool (Doxygen::symbolStorage,m_impl->hasDocumentedParams); + marshalBool (Doxygen::symbolStorage,m_impl->hasDocumentedReturnType); + marshalBool (Doxygen::symbolStorage,m_impl->isDMember); + marshalInt (Doxygen::symbolStorage,(int)m_impl->related); + marshalBool (Doxygen::symbolStorage,m_impl->stat); + marshalBool (Doxygen::symbolStorage,m_impl->proto); + marshalBool (Doxygen::symbolStorage,m_impl->docEnumValues); + marshalBool (Doxygen::symbolStorage,m_impl->annScope); + marshalBool (Doxygen::symbolStorage,m_impl->annUsed); + marshalBool (Doxygen::symbolStorage,m_impl->hasCallGraph); + marshalBool (Doxygen::symbolStorage,m_impl->hasCallerGraph); + marshalBool (Doxygen::symbolStorage,m_impl->explExt); + marshalBool (Doxygen::symbolStorage,m_impl->tspec); + marshalBool (Doxygen::symbolStorage,m_impl->groupHasDocs); + marshalBool (Doxygen::symbolStorage,m_impl->docsForDefinition); + marshalObjPointer (Doxygen::symbolStorage,m_impl->category); + marshalUInt(Doxygen::symbolStorage,END_MARKER); + + // function doesn't modify the object conceptually but compiler doesn't know this. + delete that->m_impl; + that->m_impl=0; + that->m_flushPending=FALSE; +} + +void MemberDef::loadFromDisk() const +{ + MemberDef *that = (MemberDef *)this; + if (isLocked()) + { + //printf("%p: loadFromDisk() locked: so still in memory\n",this); + assert(m_impl!=0); + return; + } + assert(m_impl==0); + + Doxygen::symbolStorage->seek(m_storagePos); + Definition::loadFromDisk(); + + //printf("%p: loading specific part\n",this); + + that->m_impl = new MemberDefImpl; + //printf("%p: MemberDef::loadFromDisk(): m_impl=%p\n",this,m_impl); + + uint marker = unmarshalUInt(Doxygen::symbolStorage); + assert(marker==START_MARKER); + m_impl->classDef = (ClassDef*)unmarshalObjPointer (Doxygen::symbolStorage); + m_impl->fileDef = (FileDef*)unmarshalObjPointer (Doxygen::symbolStorage); + m_impl->nspace = (NamespaceDef*)unmarshalObjPointer (Doxygen::symbolStorage); + m_impl->enumScope = (MemberDef*)unmarshalObjPointer (Doxygen::symbolStorage); + m_impl->annEnumType = (MemberDef*)unmarshalObjPointer (Doxygen::symbolStorage); + m_impl->enumFields = unmarshalMemberList (Doxygen::symbolStorage); + m_impl->redefines = (MemberDef*)unmarshalObjPointer (Doxygen::symbolStorage); + m_impl->redefinedBy = unmarshalMemberList (Doxygen::symbolStorage); + m_impl->memDef = (MemberDef*)unmarshalObjPointer (Doxygen::symbolStorage); + m_impl->memDec = (MemberDef*)unmarshalObjPointer (Doxygen::symbolStorage); + m_impl->relatedAlso = (ClassDef*)unmarshalObjPointer (Doxygen::symbolStorage); + m_impl->exampleSDict = unmarshalExampleSDict (Doxygen::symbolStorage); + m_impl->type = unmarshalQCString (Doxygen::symbolStorage); + m_impl->args = unmarshalQCString (Doxygen::symbolStorage); + m_impl->def = unmarshalQCString (Doxygen::symbolStorage); + m_impl->anc = unmarshalQCString (Doxygen::symbolStorage); + m_impl->virt = (Specifier)unmarshalInt (Doxygen::symbolStorage); + m_impl->prot = (Protection)unmarshalInt(Doxygen::symbolStorage); + m_impl->decl = unmarshalQCString (Doxygen::symbolStorage); + m_impl->bitfields = unmarshalQCString (Doxygen::symbolStorage); + m_impl->read = unmarshalQCString (Doxygen::symbolStorage); + m_impl->write = unmarshalQCString (Doxygen::symbolStorage); + m_impl->exception = unmarshalQCString (Doxygen::symbolStorage); + m_impl->initializer = unmarshalQCString (Doxygen::symbolStorage); + m_impl->extraTypeChars = unmarshalQCString (Doxygen::symbolStorage); + m_impl->initLines = unmarshalInt (Doxygen::symbolStorage); + m_impl->memSpec = unmarshalInt (Doxygen::symbolStorage); + m_impl->mtype = (MemberDef::MemberType)unmarshalInt (Doxygen::symbolStorage); + m_impl->maxInitLines = unmarshalInt (Doxygen::symbolStorage); + m_impl->userInitLines = unmarshalInt (Doxygen::symbolStorage); + m_impl->annMemb = (MemberDef*)unmarshalObjPointer (Doxygen::symbolStorage); + m_impl->defArgList = unmarshalArgumentList (Doxygen::symbolStorage); + m_impl->declArgList = unmarshalArgumentList (Doxygen::symbolStorage); + m_impl->tArgList = unmarshalArgumentList (Doxygen::symbolStorage); + m_impl->typeConstraints = unmarshalArgumentList (Doxygen::symbolStorage); + m_impl->templateMaster = (MemberDef*)unmarshalObjPointer (Doxygen::symbolStorage); + m_impl->defTmpArgLists = unmarshalArgumentLists(Doxygen::symbolStorage); + m_impl->cachedAnonymousType = (ClassDef*)unmarshalObjPointer (Doxygen::symbolStorage); + m_impl->classSectionSDict = unmarshalMemberLists (Doxygen::symbolStorage); + m_impl->groupAlias = (MemberDef*)unmarshalObjPointer (Doxygen::symbolStorage); + m_impl->grpId = unmarshalInt (Doxygen::symbolStorage); + m_impl->memberGroup = (MemberGroup*)unmarshalObjPointer (Doxygen::symbolStorage); + m_impl->group = (GroupDef*)unmarshalObjPointer (Doxygen::symbolStorage); + m_impl->grouppri = (Grouping::GroupPri_t)unmarshalInt (Doxygen::symbolStorage); + m_impl->groupFileName = unmarshalQCString (Doxygen::symbolStorage); + m_impl->groupStartLine = unmarshalInt (Doxygen::symbolStorage); + m_impl->groupMember = (MemberDef*)unmarshalObjPointer (Doxygen::symbolStorage); + m_impl->isTypedefValCached = unmarshalBool (Doxygen::symbolStorage); + m_impl->cachedTypedefValue = (ClassDef*)unmarshalObjPointer (Doxygen::symbolStorage); + m_impl->cachedTypedefTemplSpec = unmarshalQCString (Doxygen::symbolStorage); + m_impl->cachedResolvedType = unmarshalQCString (Doxygen::symbolStorage); + m_impl->docProvider = (MemberDef*)unmarshalObjPointer (Doxygen::symbolStorage); + m_impl->explicitOutputFileBase = unmarshalQCString (Doxygen::symbolStorage); + m_impl->implOnly = unmarshalBool (Doxygen::symbolStorage); + m_impl->hasDocumentedParams = unmarshalBool (Doxygen::symbolStorage); + m_impl->hasDocumentedReturnType = unmarshalBool (Doxygen::symbolStorage); + m_impl->isDMember = unmarshalBool (Doxygen::symbolStorage); + m_impl->related = (Relationship)unmarshalInt(Doxygen::symbolStorage); + m_impl->stat = unmarshalBool (Doxygen::symbolStorage); + m_impl->proto = unmarshalBool (Doxygen::symbolStorage); + m_impl->docEnumValues = unmarshalBool (Doxygen::symbolStorage); + m_impl->annScope = unmarshalBool (Doxygen::symbolStorage); + m_impl->annUsed = unmarshalBool (Doxygen::symbolStorage); + m_impl->hasCallGraph = unmarshalBool (Doxygen::symbolStorage); + m_impl->hasCallerGraph = unmarshalBool (Doxygen::symbolStorage); + m_impl->explExt = unmarshalBool (Doxygen::symbolStorage); + m_impl->tspec = unmarshalBool (Doxygen::symbolStorage); + m_impl->groupHasDocs = unmarshalBool (Doxygen::symbolStorage); + m_impl->docsForDefinition = unmarshalBool (Doxygen::symbolStorage); + m_impl->category = (ClassDef*)unmarshalObjPointer (Doxygen::symbolStorage); + marker = unmarshalUInt(Doxygen::symbolStorage); + assert(marker==END_MARKER); + + //printf("%p: MemberDef::loadFromDisk(): sorting\n",this); +} + +void MemberDef::makeResident() const +{ + if (Doxygen::symbolCache==0) return; + if (m_cacheHandle==-1) // not yet in cache + { + MemberDef *victim = 0; + MemberDef *that = (MemberDef*)this; // fake method constness + that->m_cacheHandle = Doxygen::symbolCache->add(that,(void **)&victim); + //printf("adding %s to cache, handle=%d\n",m_impl->name.data(),that->m_cacheHandle); + if (victim) // cache was full, victim was the least recently used item and has to go + { + //printf("%p: makeResident(): cache full %p::saveToDisk(): m_impl=%p\n",this,victim,victim->m_impl); + victim->m_cacheHandle=-1; // invalidate cache handle + victim->saveToDisk(); // store the item on disk + } + else // cache not yet full + { + //printf("Adding %s to cache, handle=%d\n",m_impl->name.data(),m_cacheHandle); + } + if (m_storagePos!=-1) // already been written to disk + { + if (isLocked()) // locked in memory + { + assert(m_impl!=0); + that->m_flushPending=FALSE; // no need to flush anymore + } + else // not locked in memory + { + assert(m_impl==0); + loadFromDisk(); + } + } + } + else // already cached, make this object the most recently used. + { + assert(m_impl!=0); + //printf("Touching symbol %s\n",m_impl->name.data()); + Doxygen::symbolCache->use(m_cacheHandle); + } +} + +void MemberDef::saveToDisk() const +{ + assert(m_impl!=0); + MemberDef *that = (MemberDef *)this; + //printf("%p: saveToDisk(): m_impl=%p\n",this,m_impl); + if (isLocked()) // cannot flush the item as it is locked + { + that->m_flushPending=TRUE; // flush when unlocked + } + else // ready to flush the item to disk + { + //printf("Adding %s to cache, handle=%d by replacing %s\n", + // m_impl->name.data(),m_cacheHandle,victim->m_impl->name.data()); + if (m_storagePos!=-1) + // if victim was stored on disk already and is not locked + { + // free the storage space occupied by the old store item + Doxygen::symbolStorage->release(m_storagePos); // free up space for others + } + // write a the new (possibly modified) instance to disk + flushToDisk(); + // end to write sequence (unless nothing was written due to the lock) + Doxygen::symbolStorage->end(); + } +} + +void MemberDef::lock() const +{ +} + +void MemberDef::unlock() const +{ + if (m_flushPending && !isLocked()) + { + //printf("%p: flush after unlock\n",this); + // write a the new (possibly modified) instance to disk + flushToDisk(); + // end to write sequence (unless nothing was written due to the lock) + Doxygen::symbolStorage->end(); + } +} + diff --git a/trunk/src/memberdef.h b/trunk/src/memberdef.h new file mode 100644 index 0000000..2e85d47 --- /dev/null +++ b/trunk/src/memberdef.h @@ -0,0 +1,399 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#ifndef MEMBERDEF_H +#define MEMBERDEF_H + +#include "qtbc.h" +#include +#include +#include + +#include "types.h" +#include "definition.h" +#include "sortdict.h" + +class ClassDef; +class NamespaceDef; +class GroupDef; +class FileDef; +class MemberList; +class MemberGroup; +class ExampleSDict; +class OutputList; +class GroupDef; +class QTextStream; +class ArgumentList; +class MemberDefImpl; + +struct SourceReference +{ + FileDef *fd; + QCString anchor; +}; + +class MemberDef : public Definition +{ + public: + + enum MemberType { + Define, + Function, + Variable, + Typedef, + Enumeration, + EnumValue, + Signal, + Slot, + Friend, + DCOP, + Property, + Event + }; + + MemberDef(const char *defFileName,int defLine, + const char *type,const char *name,const char *args, + const char *excp,Protection prot,Specifier virt,bool stat, + Relationship related,MemberType t,const ArgumentList *tal, + const ArgumentList *al); + ~MemberDef(); + DefType definitionType() const { return TypeMember; } + // move this member into a different scope + void moveTo(Definition *); + + //----------------------------------------------------------------------------------- + // ---- getters ----- + //----------------------------------------------------------------------------------- + + // link id + QCString getOutputFileBase() const; + QCString getReference() const; + QCString anchor() const; + + const char *declaration() const; + const char *definition() const; + const char *typeString() const; + const char *argsString() const; + const char *excpString() const; + const char *bitfieldString() const; + const char *extraTypeChars() const; + const QCString &initializer() const; + int initializerLines() const; + int getMemberSpecifiers() const; + MemberList *getSectionList(Definition *d) const; + + // scope query members + ClassDef *getClassDef() const; + FileDef *getFileDef() const; + NamespaceDef* getNamespaceDef() const; + + // grabbing the property read/write accessor names + const char *getReadAccessor() const; + const char *getWriteAccessor() const; + + // querying the grouping definition + GroupDef *getGroupDef() const; + Grouping::GroupPri_t getGroupPri() const; + const char *getGroupFileName() const; + int getGroupStartLine() const; + bool getGroupHasDocs() const; + QCString qualifiedName() const; + QCString objCMethodName(bool localLink,bool showStatic) const; + + // direct kind info + Protection protection() const; + Specifier virtualness(int count=0) const; + MemberType memberType() const; + QCString memberTypeName() const; + + // getter methods + bool isSignal() const; + bool isSlot() const; + bool isVariable() const; + bool isEnumerate() const; + bool isEnumValue() const; + bool isTypedef() const; + bool isFunction() const; + bool isFunctionPtr() const; + bool isDefine() const; + bool isFriend() const; + bool isDCOP() const; + bool isProperty() const; + bool isEvent() const; + bool isRelated() const; + bool isForeign() const; + bool isStatic() const; + bool isInline() const; + bool isExplicit() const; + bool isMutable() const; + bool isGettable() const; + bool isSettable() const; + bool isReadable() const; + bool isWritable() const; + bool isAddable() const; + bool isRemovable() const; + bool isRaisable() const; + bool isFinal() const; + bool isAbstract() const; + bool isOverride() const; + bool isInitonly() const; + bool isOptional() const; + bool isRequired() const; + bool isNonAtomic() const; + bool isCopy() const; + bool isAssign() const; + bool isRetain() const; + bool isNew() const; + bool isSealed() const; + bool isImplementation() const; + bool isExternal() const; + bool isTemplateSpecialization() const; + bool hasDocumentedParams() const; + bool hasDocumentedReturnType() const; + bool isObjCMethod() const; + bool isObjCProperty() const; + bool isConstructor() const; + bool isDestructor() const; + bool hasOneLineInitializer() const; + bool hasMultiLineInitializer() const; + bool protectionVisible() const; + + // output info + bool isLinkableInProject() const; + bool isLinkable() const; + bool hasDocumentation() const; // overrides hasDocumentation in definition.h + //bool hasUserDocumentation() const; // overrides hasUserDocumentation + bool isBriefSectionVisible() const; + bool isDetailedSectionVisible(bool inGroup,bool inFile) const; + bool isDetailedSectionLinkable() const; + bool isFriendClass() const; + bool isDocumentedFriendClass() const; + + MemberDef *reimplements() const; + LockingPtr reimplementedBy() const; + + //int inbodyLine() const; + //QCString inbodyFile() const; + //const QCString &inbodyDocumentation() const; + + ClassDef *relatedAlso() const; + + bool hasDocumentedEnumValues() const; + MemberDef *getAnonymousEnumType() const; + bool isDocsForDefinition() const; + MemberDef *getEnumScope() const; + LockingPtr enumFieldList() const; + + bool hasExamples(); + LockingPtr getExamples() const; + bool isPrototype() const; + + // argument related members + LockingPtr argumentList() const; + LockingPtr declArgumentList() const; + LockingPtr templateArguments() const; + LockingPtr< QList > definitionTemplateParameterLists() const; + + // member group related members + int getMemberGroupId() const; + MemberGroup *getMemberGroup() const; + + bool fromAnonymousScope() const; + bool anonymousDeclShown() const; + + // callgraph related members + bool hasCallGraph() const; + bool hasCallerGraph() const; + bool visibleMemberGroup(bool hideNoHeader); + + MemberDef *templateMaster() const; + QCString getScopeString() const; + ClassDef *getClassDefOfAnonymousType(); + + // cached typedef functions + bool isTypedefValCached() const; + ClassDef *getCachedTypedefVal() const; + QCString getCachedTypedefTemplSpec() const; + QCString getCachedResolvedTypedef() const; + + MemberDef *memberDefinition() const; + MemberDef *memberDeclaration() const; + MemberDef *inheritsDocsFrom() const; + MemberDef *getGroupAlias() const; + + ClassDef *category() const; + + QCString displayName() const { return Definition::name(); } + + //----------------------------------------------------------------------------------- + // ---- setters ----- + //----------------------------------------------------------------------------------- + + // set functions + void setMemberType(MemberType t); + void setDefinition(const char *d); + void setFileDef(FileDef *fd); + void setAnchor(const char *a); + void setProtection(Protection p); + void setMemberSpecifiers(int s); + void mergeMemberSpecifiers(int s); + void setInitializer(const char *i); + void setBitfields(const char *s); + void setMaxInitLines(int lines); + void setMemberClass(ClassDef *cd); + void setSectionList(Definition *d,MemberList *sl); + void setGroupDef(GroupDef *gd,Grouping::GroupPri_t pri, + const QCString &fileName,int startLine,bool hasDocs, + MemberDef *member=0); + void setExplicitExternal(bool b); + void setReadAccessor(const char *r); + void setWriteAccessor(const char *w); + void setTemplateSpecialization(bool b); + + void makeRelated(); + void makeForeign(); + void setHasDocumentedParams(bool b); + void setHasDocumentedReturnType(bool b); + void setInheritsDocsFrom(MemberDef *md); + void setTagInfo(TagInfo *i); + void setArgsString(const char *as); + + // relation to other members + void setReimplements(MemberDef *md); + void insertReimplementedBy(MemberDef *md); + + // in-body documentation + //void setInbodyDocumentation(const char *docs,const char *file,int line); + + void setRelatedAlso(ClassDef *cd); + + // enumeration specific members + void insertEnumField(MemberDef *md); + void setEnumScope(MemberDef *md); + void setEnumClassScope(ClassDef *cd); + void setDocumentedEnumValues(bool value); + void setAnonymousEnumType(MemberDef *md); + + // example related members + bool addExample(const char *anchor,const char *name,const char *file); + + // prototype related members + void setPrototype(bool p); + + // argument related members + void setArgumentList(ArgumentList *al); + void setDeclArgumentList(ArgumentList *al); + void setDefinitionTemplateParameterLists(QList *lists); + void setTypeConstraints(ArgumentList *al); + void setType(const char *t); + + // namespace related members + void setNamespace(NamespaceDef *nd); + + // member group related members + void setMemberGroup(MemberGroup *grp); + void setMemberGroupId(int id); + void makeImplementationDetail(); + + // anonymous scope members + void setFromAnonymousScope(bool b); + void setFromAnonymousMember(MemberDef *m); + + void enableCallGraph(bool e); + void enableCallerGraph(bool e); + + void setTemplateMaster(MemberDef *mt); + void addListReference(Definition *d); + void setDocsForDefinition(bool b); + void setGroupAlias(MemberDef *md); + + void cacheTypedefVal(ClassDef *val,const QCString &templSpec,const QCString &resolvedType); + void invalidateTypedefValCache(); + + void invalidateCachedArgumentTypes(); + + // declaration <-> definition relation + void setMemberDefinition(MemberDef *md); + void setMemberDeclaration(MemberDef *md); + + void setAnonymousUsed(); + void copyArgumentNames(MemberDef *bmd); + + void setCategory(ClassDef *); + + void setDocumentation(const char *d,const char *docFile,int docLine,bool stripWhiteSpace=TRUE); + void setBriefDescription(const char *b,const char *briefFile,int briefLine); + void setInbodyDocumentation(const char *d,const char *inbodyFile,int inbodyLine); + + void setHidden(bool b); + + //----------------------------------------------------------------------------------- + // --- actions ---- + //----------------------------------------------------------------------------------- + + // output generation + void writeDeclaration(OutputList &ol, + ClassDef *cd,NamespaceDef *nd,FileDef *fd,GroupDef *gd, + bool inGroup); + void writeDocumentation(MemberList *ml,OutputList &ol, + const char *scopeName,Definition *container, + bool inGroup,bool showEnumValues=FALSE,bool + showInline=FALSE); + void writeMemberDocSimple(OutputList &ol,Definition *container); + void warnIfUndocumented(); + + MemberDef *createTemplateInstanceMember(ArgumentList *formalArgs, + ArgumentList *actualArgs); + + void writeEnumDeclaration(OutputList &typeDecl, + ClassDef *cd,NamespaceDef *nd,FileDef *fd,GroupDef *gd); + + void findSectionsInDocumentation(); + + bool visited; + + protected: + void flushToDisk() const; + void loadFromDisk() const; + private: + void lock() const; + void unlock() const; + void saveToDisk() const; + void makeResident() const; + void _computeLinkableInProject(); + void _computeIsConstructor(); + void _computeIsDestructor(); + + static int s_indentLevel; + // disable copying of member defs + MemberDef(const MemberDef &); + MemberDef &operator=(const MemberDef &); + + void writeLink(OutputList &ol, + ClassDef *cd,NamespaceDef *nd,FileDef *fd,GroupDef *gd, + bool onlyText=FALSE); + + MemberDefImpl *m_impl; + int m_cacheHandle; + off_t m_storagePos; // location where the item is stored in file (if impl==0) + bool m_flushPending; + uchar m_isLinkableCached; // 0 = not cached, 1=FALSE, 2=TRUE + uchar m_isConstructorCached; // 0 = not cached, 1=FALSE, 2=TRUE + uchar m_isDestructorCached; // 0 = not cached, 1=FALSE, 2=TRUE +}; + +#endif diff --git a/trunk/src/membergroup.cpp b/trunk/src/membergroup.cpp new file mode 100644 index 0000000..6f9cbe7 --- /dev/null +++ b/trunk/src/membergroup.cpp @@ -0,0 +1,365 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#include "qtbc.h" +#include "membergroup.h" +#include "memberlist.h" +#include "outputlist.h" +#include "util.h" +#include "classdef.h" +#include "namespacedef.h" +#include "filedef.h" +#include "language.h" +#include "groupdef.h" +#include "doxygen.h" +#include "docparser.h" +#include "marshal.h" +#include "entry.h" +#include "md5.h" + +//static QCString idToName(int id) +//{ +// QCString result; +// result.sprintf("mgroup_%d",id); +// return result; +//} + +MemberGroup::MemberGroup() +{ +} + +MemberGroup::MemberGroup(Definition *parent, + int id,const char *hdr,const char *d,const char *docFile) +{ + //printf("New member group id=%d header=%s desc=%s\n",id,hdr,d); + memberList = new MemberList(MemberList::memberGroup); + grpId = id; + grpHeader = hdr; + doc = d; + scope = 0; + inSameSection = TRUE; + inDeclSection = 0; + m_numDecMembers = -1; + m_numDocMembers = -1; + m_parent = parent; + m_docFile = docFile; + m_xrefListItems = 0; + //printf("Member group docs=`%s'\n",doc.data()); +} + +MemberGroup::~MemberGroup() +{ + delete memberList; +} + +void MemberGroup::insertMember(MemberDef *md) +{ + //printf("MemberGroup::insertMember m_parent=%s memberList=%p count=%d" + // " member section list: %p: md=%p:%s\n", + // m_parent ? m_parent->name().data() : "", + // memberList->first() ? memberList->first()->getSectionList(m_parent) : 0, + // memberList->count(), + // md->getSectionList(m_parent), + // md,md->name().data()); + + MemberDef *firstMd = memberList->first(); + if (inSameSection && memberList->count()>0 && + firstMd->getSectionList(m_parent)!=md->getSectionList(m_parent)) + { + inSameSection=FALSE; + } + else if (inDeclSection==0) + { + inDeclSection = md->getSectionList(m_parent); + //printf("inDeclSection=%p type=%d\n",inDeclSection,inDeclSection->listType()); + } + memberList->append(md); + + // copy the group of the first member in the memberGroup + GroupDef *gd; + if (firstMd && (gd=firstMd->getGroupDef())) + { + md->setGroupDef(gd, firstMd->getGroupPri(), + firstMd->getGroupFileName(), firstMd->getGroupStartLine(), + firstMd->getGroupHasDocs()); + gd->insertMember(md); + } +} + + +void MemberGroup::setAnchors(ClassDef *context) +{ + ::setAnchors(context,'z',memberList,grpId); +} + +void MemberGroup::writeDeclarations(OutputList &ol, + ClassDef *cd,NamespaceDef *nd,FileDef *fd,GroupDef *gd, + bool showInline) +{ + //printf("MemberGroup::writeDeclarations() %s\n",grpHeader.data()); + QCString ldoc = doc; + if (!ldoc.isEmpty()) ldoc.prepend(""); + memberList->writeDeclarations(ol,cd,nd,fd,gd,grpHeader,ldoc,FALSE,showInline); +} + +void MemberGroup::writePlainDeclarations(OutputList &ol, + ClassDef *cd,NamespaceDef *nd,FileDef *fd,GroupDef *gd + ) +{ + //printf("MemberGroup::writePlainDeclarations() memberList->count()=%d\n",memberList->count()); + memberList->writePlainDeclarations(ol,cd,nd,fd,gd); +} + +void MemberGroup::writeDocumentation(OutputList &ol,const char *scopeName, + Definition *container,bool showEnumValues,bool showInline) +{ + memberList->writeDocumentation(ol,scopeName,container,0,showEnumValues,showInline); +} + +void MemberGroup::writeDocumentationPage(OutputList &ol,const char *scopeName, + Definition *container) +{ + memberList->writeDocumentationPage(ol,scopeName,container); +} + +/*! Add this group as a subsection of the declaration section, instead + * of rendering it in its own section + */ +void MemberGroup::addToDeclarationSection() +{ + if (inDeclSection) + { + //printf("Adding group %p to list %p (type=%d)\n",this, + // inDeclSection,inDeclSection->listType()); + inDeclSection->addMemberGroup(this); + } +} + +int MemberGroup::countDecMembers(GroupDef *gd) +{ + if (m_numDecMembers==-1) /* number of member not cached */ + { + memberList->countDecMembers(gd); + m_numDecMembers = memberList->numDecMembers(); + } + return m_numDecMembers; +} + +int MemberGroup::countDocMembers() +{ + if (m_numDocMembers==-1) + { + memberList->countDocMembers(); + m_numDocMembers = memberList->numDocMembers(); + } + return m_numDocMembers; +} + +void MemberGroup::distributeMemberGroupDocumentation() +{ + //printf("MemberGroup::distributeMemberGroupDocumentation() %s\n",grpHeader.data()); + MemberDef *md=memberList->first(); + while (md) + { + //printf("checking md=%s\n",md->name().data()); + // find the first member of the group with documentation + if (!md->documentation().isEmpty() || + !md->briefDescription().isEmpty() || + !md->inbodyDocumentation().isEmpty() + ) + { + //printf("found it!\n"); + break; + } + md=memberList->next(); + } + if (md) // distribute docs of md to other members of the list + { + //printf("Member %s has documentation!\n",md->name().data()); + MemberDef *omd=memberList->first(); + while (omd) + { + if (md!=omd && omd->documentation().isEmpty() && + omd->briefDescription().isEmpty() && + omd->inbodyDocumentation().isEmpty() + ) + { + //printf("Copying documentation to member %s\n",omd->name().data()); + omd->setBriefDescription(md->briefDescription(),md->briefFile(),md->briefLine()); + omd->setDocumentation(md->documentation(),md->docFile(),md->docLine()); + omd->setInbodyDocumentation(md->inbodyDocumentation(),md->inbodyFile(),md->inbodyLine()); + } + omd=memberList->next(); + } + } +} + +int MemberGroup::varCount() const +{ + return memberList->varCount(); +} + +int MemberGroup::funcCount() const +{ + return memberList->funcCount(); +} + +int MemberGroup::enumCount() const +{ + return memberList->enumCount(); +} + +int MemberGroup::enumValueCount() const +{ + return memberList->enumValueCount(); +} + +int MemberGroup::typedefCount() const +{ + return memberList->typedefCount(); +} + +int MemberGroup::protoCount() const +{ + return memberList->protoCount(); +} + +int MemberGroup::defineCount() const +{ + return memberList->defineCount(); +} + +int MemberGroup::friendCount() const +{ + return memberList->friendCount(); +} + +int MemberGroup::numDecMembers() const +{ + return memberList->numDecMembers(); +} + +int MemberGroup::numDocMembers() const +{ + return memberList->numDocMembers(); +} + +void MemberGroup::setInGroup(bool b) +{ + memberList->setInGroup(b); +} + +QCString MemberGroup::anchor() const +{ + uchar md5_sig[16]; + QCString sigStr(33); + QCString locHeader = grpHeader; + if (locHeader.isEmpty()) locHeader="[NOHEADER]"; + MD5Buffer((const unsigned char *)locHeader.data(),locHeader.length(),md5_sig); + MD5SigToString(md5_sig,sigStr.data(),33); + return "amgrp"+sigStr; +} + +void MemberGroup::addListReferences(Definition *def) +{ + memberList->addListReferences(def); + if (m_xrefListItems && def) + { + QCString name = def->getOutputFileBase()+"#"+anchor(); + addRefItem(m_xrefListItems, + name, + theTranslator->trGroup(TRUE,TRUE), + name, + grpHeader,0); + } +} + +void MemberGroup::findSectionsInDocumentation() +{ + docFindSections(doc,0,this,m_docFile); + memberList->findSectionsInDocumentation(); +} + +void MemberGroup::marshal(StorageIntf *s) +{ + marshalMemberList(s,memberList); + marshalObjPointer(s,inDeclSection); // reference only + marshalInt(s,grpId); + marshalQCString(s,grpHeader); + marshalQCString(s,fileName); + marshalObjPointer(s,scope); + marshalQCString(s,doc); + marshalBool(s,inSameSection); + marshalInt(s,m_numDecMembers); + marshalInt(s,m_numDocMembers); + marshalObjPointer(s,m_parent); + marshalQCString(s,m_docFile); + marshalItemInfoList (Doxygen::symbolStorage,m_xrefListItems); +} + +void MemberGroup::unmarshal(StorageIntf *s) +{ + memberList = unmarshalMemberList(s); + inDeclSection = (MemberList *)unmarshalObjPointer(s); + grpId = unmarshalInt(s); + grpHeader = unmarshalQCString(s); + fileName = unmarshalQCString(s); + scope = (Definition *)unmarshalObjPointer(s); + doc = unmarshalQCString(s); + inSameSection = unmarshalBool(s); + m_numDecMembers = unmarshalInt(s); + m_numDocMembers = unmarshalInt(s); + m_parent = (Definition *)unmarshalObjPointer(s); + m_docFile = unmarshalQCString(s); + m_xrefListItems = unmarshalItemInfoList (Doxygen::symbolStorage); +} + +void MemberGroup::setRefItems(const QList *sli) +{ + if (sli) + { + // deep copy the list + if (m_xrefListItems==0) + { + m_xrefListItems=new QList; + m_xrefListItems->setAutoDelete(TRUE); + } + QListIterator slii(*sli); + ListItemInfo *lii; + for (slii.toFirst();(lii=slii.current());++slii) + { + m_xrefListItems->append(new ListItemInfo(*lii)); + } + } +} +//-------------------------------------------------------------------------- + +void MemberGroupInfo::setRefItems(const QList *sli) +{ + if (!sli) return; + if (m_sli==0) + { + m_sli = new QList; + m_sli->setAutoDelete(TRUE); + } + QListIterator slii(*sli); + ListItemInfo *ili; + for (slii.toFirst();(ili=slii.current());++slii) + { + m_sli->append(new ListItemInfo(*ili)); + } +} diff --git a/trunk/src/membergroup.h b/trunk/src/membergroup.h new file mode 100644 index 0000000..12d1383 --- /dev/null +++ b/trunk/src/membergroup.h @@ -0,0 +1,153 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#ifndef MEMBERGROUP_H +#define MEMBERGROUP_H + +#include "qtbc.h" +#include +#include +#include "sortdict.h" + +#define DOX_NOGROUP -1 + +class MemberDef; +class ClassDef; +class NamespaceDef; +class FileDef; +class MemberList; +class GroupDef; +class OutputList; +class Definition; +class StorageIntf; +struct ListItemInfo; + +class MemberGroup +{ + public: + MemberGroup(); + MemberGroup(Definition *parent,int id,const char *header, + const char *docs,const char *docFile); + ~MemberGroup(); + QCString header() const { return grpHeader; } + int groupId() const { return grpId; } + void insertMember(MemberDef *md); + void setAnchors(ClassDef *); + void writePlainDeclarations(OutputList &ol, + ClassDef *cd,NamespaceDef *nd,FileDef *fd,GroupDef *gd); + void writeDeclarations(OutputList &ol, + ClassDef *cd,NamespaceDef *nd,FileDef *fd,GroupDef *gd, + bool showInline=FALSE); + + void writeDocumentation(OutputList &ol,const char *scopeName, + Definition *container,bool showEnumValues,bool showInline); + void writeDocumentationPage(OutputList &ol,const char *scopeName, + Definition *container); + QCString documentation() { return doc; } + bool allMembersInSameSection() { return inSameSection; } + void addToDeclarationSection(); + int countDecMembers(GroupDef *gd=0); + int countDocMembers(); + void distributeMemberGroupDocumentation(); + void findSectionsInDocumentation(); + int varCount() const; + int funcCount() const; + int enumCount() const; + int enumValueCount() const; + int typedefCount() const; + int protoCount() const; + int defineCount() const; + int friendCount() const; + int numDecMembers() const; + int numDocMembers() const; + void setInGroup(bool b); + void addListReferences(Definition *d); + void setRefItems(const QList *sli); + MemberList *members() const { return memberList; } + Definition *parent() const { return m_parent; } + QCString anchor() const; + + void marshal(StorageIntf *s); + void unmarshal(StorageIntf *s); + + private: + MemberList *memberList; // list of all members in the group + MemberList *inDeclSection; + int grpId; + QCString grpHeader; + QCString fileName; // base name of the generated file + Definition *scope; + QCString doc; + bool inSameSection; + int m_numDecMembers; + int m_numDocMembers; + Definition *m_parent; + QCString m_docFile; + QList *m_xrefListItems; +}; + +class MemberGroupList : public QList +{ +}; + +class MemberGroupListIterator : public QListIterator +{ + public: + MemberGroupListIterator(const MemberGroupList &l) : + QListIterator(l) {} +}; + +class MemberGroupSDict : public SIntDict +{ + public: + MemberGroupSDict(int size=17) : SIntDict(size) {} + ~MemberGroupSDict() {} + int compareItems(GCI item1,GCI item2) + { + return ((MemberGroup *)item1)->groupId() - ((MemberGroup*)item2)->groupId(); + } +}; + + +struct MemberGroupInfo +{ + MemberGroupInfo() : m_sli(0) {} + ~MemberGroupInfo() { delete m_sli; m_sli=0; } + void setRefItems(const QList *sli); + QCString header; + QCString doc; + QCString docFile; + QCString compoundName; + QList *m_sli; +}; + +//class MemberGroupDict : public QIntDict +//{ +// public: +// MemberGroupDict(int size) : QIntDict(size) {} +// ~MemberGroupDict() {} +//}; + +//class MemberGroupDictIterator : public QIntDictIterator +//{ +// public: +// MemberGroupDictIterator(const MemberGroupDict &d) : +// QIntDictIterator(d) {} +// ~MemberGroupDictIterator() {} +//}; + +#endif diff --git a/trunk/src/memberlist.cpp b/trunk/src/memberlist.cpp new file mode 100644 index 0000000..8cfad19 --- /dev/null +++ b/trunk/src/memberlist.cpp @@ -0,0 +1,831 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#include + +#include "memberlist.h" +#include "classdef.h" +#include "message.h" +#include "util.h" +#include "language.h" +#include "doxygen.h" +#include "outputlist.h" +#include "groupdef.h" +#include "marshal.h" +#include "vhdldocgen.h" + +MemberList::MemberList() +{ +} + +MemberList::MemberList(ListType lt) : m_listType(lt) +{ + memberGroupList=0; + m_numDecMembers=-1; // special value indicating that value needs to be computed + m_numDocMembers=-1; // special value indicating that value needs to be computed + m_inGroup=FALSE; + m_inFile=FALSE; + m_needsSorting=FALSE; +} + +MemberList::~MemberList() +{ + delete memberGroupList; +} + +int MemberList::compareItems(GCI item1, GCI item2) +{ + static bool sortConstructorsFirst = Config_getBool("SORT_MEMBERS_CTORS_1ST"); + MemberDef *c1=(MemberDef *)item1; + MemberDef *c2=(MemberDef *)item2; + if (sortConstructorsFirst) { + int ord1 = c1->isConstructor() ? 2 : (c1->isDestructor() ? 1 : 0); + int ord2 = c2->isConstructor() ? 2 : (c2->isDestructor() ? 1 : 0); + if (ord1 > ord2) + return -1; + else if (ord2 > ord1) + return 1; + } + int cmp = stricmp(c1->name(),c2->name()); + return cmp!=0 ? cmp : c1->getDefLine()-c2->getDefLine(); +} + +/*! Count the number of members in this list that are visible in + * the declaration part of a compound's documentation page. + */ +void MemberList::countDecMembers(bool countEnumValues,GroupDef *gd) +{ + if (m_numDecMembers!=-1) return; + + //printf("----- countDecMembers count=%d ----\n",count()); + m_varCnt=m_funcCnt=m_enumCnt=m_enumValCnt=0; + m_typeCnt=m_protoCnt=m_defCnt=m_friendCnt=0; + m_numDecMembers=0; + QListIterator mli(*this); + MemberDef *md; + for (mli.toFirst();(md=mli.current());++mli) + { + //printf("MemberList::countDecMembers(md=%s,%d)\n",md->name().data(),md->isBriefSectionVisible()); + if (md->isBriefSectionVisible()) + { + switch(md->memberType()) + { + case MemberDef::Variable: // fall through + case MemberDef::Event: // fall through + case MemberDef::Property: m_varCnt++,m_numDecMembers++; + break; + case MemberDef::Function: // fall through + case MemberDef::Signal: // fall through + case MemberDef::DCOP: // fall through + case MemberDef::Slot: if (!md->isRelated() || md->getClassDef()) + m_funcCnt++,m_numDecMembers++; + break; + case MemberDef::Enumeration: m_enumCnt++,m_numDecMembers++; break; + case MemberDef::EnumValue: if (countEnumValues) + m_enumValCnt++,m_numDecMembers++; + break; + case MemberDef::Typedef: m_typeCnt++,m_numDecMembers++; break; + //case MemberDef::Prototype: m_protoCnt++,m_numDecMembers++; break; + case MemberDef::Define: if (Config_getBool("EXTRACT_ALL") || + md->argsString() || + !md->initializer().isEmpty() || + md->hasDocumentation() + ) m_defCnt++,m_numDecMembers++; + break; + case MemberDef::Friend: m_friendCnt++,m_numDecMembers++; + break; + default: + err("Error: Unknown member type found for member `%s'\n!",md->name().data()); + } + } + } + if (memberGroupList) + { + MemberGroupListIterator mgli(*memberGroupList); + MemberGroup *mg; + for (;(mg=mgli.current());++mgli) + { + mg->countDecMembers(gd); + m_varCnt+=mg->varCount(); + m_funcCnt+=mg->funcCount(); + m_enumCnt+=mg->enumCount(); + m_enumValCnt+=mg->enumValueCount(); + m_typeCnt+=mg->typedefCount(); + m_protoCnt+=mg->protoCount(); + m_defCnt+=mg->defineCount(); + m_friendCnt+=mg->friendCount(); + m_numDecMembers+=mg->numDecMembers(); + } + } + //printf("----- end countDecMembers ----\n"); + + //printf("MemberList::countDecMembers()=%d\n",m_numDecMembers); +} + +void MemberList::countDocMembers(bool countEnumValues) +{ + if (m_numDocMembers!=-1) return; // used cached value + m_numDocMembers=0; + QListIterator mli(*this); + MemberDef *md; + for (mli.toFirst();(md=mli.current());++mli) + { + if (md->isDetailedSectionVisible(m_inGroup,m_inFile)) + { + // do not count enum values, since they do not produce entries of their own + if (countEnumValues || md->memberType()!=MemberDef::EnumValue) + m_numDocMembers++; + } + } + if (memberGroupList) + { + MemberGroupListIterator mgli(*memberGroupList); + MemberGroup *mg; + for (;(mg=mgli.current());++mgli) + { + mg->countDocMembers(); + m_numDocMembers+=mg->numDocMembers(); + } + } + //printf("MemberList::countDocMembers()=%d memberGroupList=%p\n",m_numDocMembers,memberGroupList); +} + +bool MemberList::insert(uint index,const MemberDef *md) +{ + return QList::insert(index,md); +} + +void MemberList::inSort(const MemberDef *md) +{ + QList::inSort(md); +} + +void MemberList::append(const MemberDef *md) +{ + QList::append(md); +} + +MemberListIterator::MemberListIterator(const QList &l) : + QListIterator(l) +{ +} + +bool MemberList::declVisible() const +{ + MemberListIterator mli(*this); + MemberDef *md; + for ( ; (md=mli.current()); ++mli ) + { + if (md->isBriefSectionVisible()) + { + switch (md->memberType()) + { + case MemberDef::Define: // fall through + case MemberDef::Typedef: // fall through + case MemberDef::Variable: // fall through + case MemberDef::Function: // fall through + case MemberDef::Signal: // fall through + case MemberDef::Slot: // fall through + case MemberDef::DCOP: // fall through + case MemberDef::Property: // fall through + case MemberDef::Event: + return TRUE; + case MemberDef::Enumeration: + { + int enumVars=0; + MemberListIterator vmli(*this); + MemberDef *vmd; + QCString name(md->name()); + int i=name.findRev("::"); + if (i!=-1) name=name.right(name.length()-i-2); // strip scope (TODO: is this needed?) + if (name[0]=='@') // anonymous enum => append variables + { + for ( ; (vmd=vmli.current()) ; ++vmli) + { + QCString vtype=vmd->typeString(); + if ((vtype.find(name))!=-1) + { + enumVars++; + } + } + } + // if this is an anonymous enum and there are variables of this + // enum type (i.e. enumVars>0), then we do not show the enum here. + if (enumVars==0) // show enum here + { + return TRUE; + } + } + break; + case MemberDef::Friend: + return TRUE; + case MemberDef::EnumValue: + { + if (m_inGroup) + { + return TRUE; + } + } + break; + } + } + } + return FALSE; +} + +void MemberList::writePlainDeclarations(OutputList &ol, + ClassDef *cd,NamespaceDef *nd,FileDef *fd,GroupDef *gd + ) +{ + //printf("----- writePlainDeclaration() ----\n"); + countDecMembers(); + if (numDecMembers()==0) + { + //printf(" --> no members!\n"); + return; // no members in this list + } + //printf(" --> writePlainDeclaration() numDecMembers()=%d\n", + // numDecMembers()); + + ol.pushGeneratorState(); + + bool first=TRUE; + MemberDef *md; + MemberListIterator mli(*this); + for ( ; (md=mli.current()); ++mli ) + { + //printf(">>> Member `%s' type=%d visible=%d\n", + // md->name().data(),md->memberType(),md->isBriefSectionVisible()); + if (md->isBriefSectionVisible()) + { + switch(md->memberType()) + { + case MemberDef::Define: // fall through + //case MemberDef::Prototype: // fall through + case MemberDef::Typedef: // fall through + case MemberDef::Variable: // fall through + case MemberDef::Function: // fall through + case MemberDef::Signal: // fall through + case MemberDef::Slot: // fall through + case MemberDef::DCOP: // fall through + case MemberDef::Property: // fall through + case MemberDef::Event: + { + if (first) ol.startMemberList(),first=FALSE; + md->writeDeclaration(ol,cd,nd,fd,gd,m_inGroup); + break; + } + case MemberDef::Enumeration: + { + int enumVars=0; + MemberListIterator vmli(*this); + MemberDef *vmd; + QCString name(md->name()); + int i=name.findRev("::"); + if (i!=-1) name=name.right(name.length()-i-2); // strip scope (TODO: is this needed?) + if (name[0]=='@') // anonymous enum => append variables + { + for ( ; (vmd=vmli.current()) ; ++vmli) + { + QCString vtype=vmd->typeString(); + if ((vtype.find(name))!=-1) + { + enumVars++; + vmd->setAnonymousEnumType(md); + } + } + } + // if this is an anonymous enum and there are variables of this + // enum type (i.e. enumVars>0), then we do not show the enum here. + if (enumVars==0) // show enum here + { + //printf("Enum!!\n"); + if (first) + { + ol.startMemberList(); + first=FALSE; + } + ol.startMemberItem(md->anchor(),0); + ol.writeString("enum "); + ol.insertMemberAlign(); + md->writeEnumDeclaration(ol,cd,nd,fd,gd); + ol.endMemberItem(); + if (!md->briefDescription().isEmpty() && Config_getBool("BRIEF_MEMBER_DESC")) + { + ol.startMemberDescription(md->anchor()); + ol.parseDoc( + md->briefFile(),md->briefLine(), + cd,md, + md->briefDescription(), + TRUE,FALSE,0,TRUE,FALSE + ); + if (md->isDetailedSectionLinkable()) + { + ol.disableAllBut(OutputGenerator::Html); + ol.docify(" "); + ol.startTextLink(md->getOutputFileBase(), + md->anchor()); + ol.parseText(theTranslator->trMore()); + ol.endTextLink(); + ol.enableAll(); + } + ol.endMemberDescription(); + } + } + md->warnIfUndocumented(); + break; + } + case MemberDef::Friend: + { + if (first) + { + ol.startMemberList(); + first=FALSE; + } + md->writeDeclaration(ol,cd,nd,fd,gd,m_inGroup); + break; + } + case MemberDef::EnumValue: + { + if (m_inGroup) + { + //printf("EnumValue!\n"); + if (first) ol.startMemberList(),first=FALSE; + md->writeDeclaration(ol,cd,nd,fd,gd,m_inGroup); + } + } + break; + } + } + } + + // handle members that are inside anonymous compounds and for which + // no variables of the anonymous compound type exist. + if (cd) + { + MemberListIterator mli(*this); + for ( ; (md=mli.current()) ; ++mli ) + { + if (md->fromAnonymousScope() && !md->anonymousDeclShown()) + { + md->setFromAnonymousScope(FALSE); + //printf("anonymous compound members\n"); + if (md->isBriefSectionVisible()) + { + if (first) + { + ol.startMemberList(); + first=FALSE; + } + md->writeDeclaration(ol,cd,nd,fd,gd,m_inGroup); + } + md->setFromAnonymousScope(TRUE); + } + } + } + + if (!first) + { + ol.endMemberList(); + } + + ol.popGeneratorState(); + //printf("----- end writePlainDeclaration() ----\n"); +} + +void MemberList::writeDeclarations(OutputList &ol, + ClassDef *cd,NamespaceDef *nd,FileDef *fd,GroupDef *gd, + const char *title,const char *subtitle, bool showEnumValues, + bool showInline) +{ + //printf("----- writeDeclaration() this=%p ----\n",this); + static bool optimizeVhdl = Config_getBool("OPTIMIZE_OUTPUT_VHDL"); + + countDecMembers(showEnumValues,gd); // count members shown in this section + Definition *ctx = cd; + if (ctx==0 && nd) ctx = nd; + if (ctx==0 && gd) ctx = gd; + if (ctx==0 && fd) ctx = fd; + + if (numDecMembers()==0) return; + //printf("%p: MemberList::writeDeclaration(title=`%s',subtitle=`%s')=%d\n", + // this,title,subtitle,numDecMembers()); + if (title) + { + if (showInline) + { + ol.startInlineHeader(); + } + else + { + ol.startMemberHeader(listTypeAsString()); + } + ol.parseText(title); + if (showInline) + { + ol.endInlineHeader(); + } + else + { + ol.endMemberHeader(); + } + } + if (subtitle) + { + QCString st=subtitle; + st = st.stripWhiteSpace(); + if (!st.isEmpty()) + { + ol.startMemberSubtitle(); + ol.parseDoc("[generated]",-1,ctx,0,subtitle,FALSE,FALSE,0,FALSE,FALSE); + ol.endMemberSubtitle(); + } + } + + // TODO: Two things need to be worked out for proper VHDL output: + // 1. Signals and types under the group need to be + // formatted to associate them with the group somehow + // indentation, or at the very least, extra space after + // the group is done + // 2. This might need to be repeated below for memberGroupLists + if (optimizeVhdl) // use specific declarations function + { + VhdlDocGen::writeVhdlDeclarations(this,ol,0,cd,0,0); + } + else + { + writePlainDeclarations(ol,cd,nd,fd,gd); + } + + //printf("memberGroupList=%p\n",memberGroupList); + if (memberGroupList) + { + MemberGroupListIterator mgli(*memberGroupList); + MemberGroup *mg; + while ((mg=mgli.current())) + { + bool hasHeader=!mg->header().isEmpty() && mg->header()!="[NOHEADER]"; + //printf("mg->header=%s hasHeader=%d\n",mg->header().data(),hasHeader); + ol.startMemberGroupHeader(hasHeader); + if (hasHeader) + { + ol.parseText(mg->header()); + } + ol.endMemberGroupHeader(); + if (!mg->documentation().isEmpty()) + { + //printf("Member group has docs!\n"); + ol.startMemberGroupDocs(); + ol.parseDoc("[generated]",-1,ctx,0,mg->documentation()+"\n",FALSE,FALSE); + ol.endMemberGroupDocs(); + } + ol.startMemberGroup(); + //printf("--- mg->writePlainDeclarations ---\n"); + mg->writePlainDeclarations(ol,cd,nd,fd,gd); + ol.endMemberGroup(hasHeader); + ++mgli; + } + } + //printf("----- end writeDeclaration() ----\n"); + +} + +void MemberList::writeDocumentation(OutputList &ol, + const char *scopeName, Definition *container, + const char *title,bool showEnumValues,bool showInline) +{ + //printf("MemberList::writeDocumentation()\n"); + + countDocMembers(showEnumValues); + if (numDocMembers()==0) return; + + if (title) + { + ol.writeRuler(); + ol.startGroupHeader(showInline ? 2 : 0); + ol.parseText(title); + ol.endGroupHeader(showInline ? 2 : 0); + } + ol.startMemberDocList(); + + MemberListIterator mli(*this); + MemberDef *md; + for ( ; (md=mli.current()) ; ++mli) + { + md->writeDocumentation(this,ol,scopeName,container, + m_inGroup,showEnumValues,showInline); + } + if (memberGroupList) + { + //printf("MemberList::writeDocumentation() -- member groups\n"); + MemberGroupListIterator mgli(*memberGroupList); + MemberGroup *mg; + for (;(mg=mgli.current());++mgli) + { + mg->writeDocumentation(ol,scopeName,container,showEnumValues,showInline); + } + } + ol.endMemberDocList(); +} + +// members in a table +void MemberList::writeSimpleDocumentation(OutputList &ol, + Definition *container) +{ + countDocMembers(FALSE); + //printf("MemberList count=%d\n",numDocMembers()); + if (numDocMembers()==0) return; + + ol.startMemberDocSimple(); + MemberListIterator mli(*this); + MemberDef *md; + for ( ; (md=mli.current()) ; ++mli) + { + md->writeMemberDocSimple(ol,container); + } + ol.endMemberDocSimple(); +} + +// separate member pages +void MemberList::writeDocumentationPage(OutputList &ol, + const char *scopeName, Definition *container) +{ + static bool generateTreeView = Config_getBool("GENERATE_TREEVIEW"); + MemberListIterator mli(*this); + MemberDef *md; + for ( ; (md=mli.current()) ; ++mli) + { + QCString diskName=md->getOutputFileBase(); + QCString title=md->qualifiedName(); + startFile(ol,diskName,md->name(),title,HLI_None,!generateTreeView, + container->getOutputFileBase()); + if (!generateTreeView) + { + container->writeNavigationPath(ol); + ol.endQuickIndices(); + } + ol.startContents(); + + + if (generateTreeView) + { + md->writeDocumentation(this,ol,scopeName,container,m_inGroup); + ol.endContents(); + endFileWithNavPath(container,ol); + } + else + { + ol.writeString("\n" + " \n" + " \n"); + ol.writeString(" \n"); + ol.writeString(" \n"); + ol.writeString("
    \n"); + + container->writeQuickMemberLinks(ol,md); + + ol.writeString(" \n"); + + md->writeDocumentation(this,ol,scopeName,container,m_inGroup); + + ol.writeString("
    \n"); + + endFile(ol); + } + } + if (memberGroupList) + { + //printf("MemberList::writeDocumentation() -- member groups\n"); + MemberGroupListIterator mgli(*memberGroupList); + MemberGroup *mg; + for (;(mg=mgli.current());++mgli) + { + mg->writeDocumentationPage(ol,scopeName,container); + } + } +} + +void MemberList::addMemberGroup(MemberGroup *mg) +{ + if (memberGroupList==0) + { + memberGroupList=new MemberGroupList; + } + //printf("addMemberGroup: this=%p mg=%p\n",this,mg); + memberGroupList->append(mg); +} + +void MemberList::addListReferences(Definition *def) +{ + MemberListIterator mli(*this); + MemberDef *md; + for ( ; (md=mli.current()) ; ++mli) + { + if (md->getGroupDef()==0 || def->definitionType()==Definition::TypeGroup) + { + md->addListReference(def); + LockingPtr enumFields = md->enumFieldList(); + if (md->memberType()==MemberDef::Enumeration && enumFields!=0) + { + //printf(" Adding enum values!\n"); + MemberListIterator vmli(*enumFields); + MemberDef *vmd; + for ( ; (vmd=vmli.current()) ; ++vmli) + { + //printf(" adding %s\n",vmd->name().data()); + vmd->addListReference(def); + } + } + } + } + if (memberGroupList) + { + MemberGroupListIterator mgli(*memberGroupList); + MemberGroup *mg; + for (;(mg=mgli.current());++mgli) + { + mg->addListReferences(def); + } + } +} + +void MemberList::findSectionsInDocumentation() +{ + MemberListIterator mli(*this); + MemberDef *md; + for ( ; (md=mli.current()) ; ++mli) + { + md->findSectionsInDocumentation(); + } + if (memberGroupList) + { + MemberGroupListIterator mgli(*memberGroupList); + MemberGroup *mg; + for (;(mg=mgli.current());++mgli) + { + mg->findSectionsInDocumentation(); + } + } +} + +void MemberList::marshal(StorageIntf *s) +{ + marshalInt(s,(int)m_listType); + marshalInt(s,m_varCnt); + marshalInt(s,m_funcCnt); + marshalInt(s,m_enumCnt); + marshalInt(s,m_enumValCnt); + marshalInt(s,m_typeCnt); + marshalInt(s,m_protoCnt); + marshalInt(s,m_defCnt); + marshalInt(s,m_friendCnt); + marshalInt(s,m_numDecMembers); + marshalInt(s,m_numDocMembers); + marshalBool(s,m_inGroup); + marshalBool(s,m_inFile); + marshalBool(s,m_needsSorting); + if (memberGroupList==0) + { + marshalUInt(s,NULL_LIST); // null pointer representation + } + else + { + marshalUInt(s,memberGroupList->count()); + QListIterator mgi(*memberGroupList); + MemberGroup *mg=0; + for (mgi.toFirst();(mg=mgi.current());++mgi) + { + mg->marshal(s); + } + } +} + +void MemberList::unmarshal(StorageIntf *s) +{ + m_listType = (MemberList::ListType)unmarshalInt(s); + m_varCnt = unmarshalInt(s); + m_funcCnt = unmarshalInt(s); + m_enumCnt = unmarshalInt(s); + m_enumValCnt = unmarshalInt(s); + m_typeCnt = unmarshalInt(s); + m_protoCnt = unmarshalInt(s); + m_defCnt = unmarshalInt(s); + m_friendCnt = unmarshalInt(s); + m_numDecMembers = unmarshalInt(s); + m_numDocMembers = unmarshalInt(s); + m_inGroup = unmarshalBool(s); + m_inFile = unmarshalBool(s); + m_needsSorting = unmarshalBool(s); + uint i,count = unmarshalUInt(s); + if (count==NULL_LIST) // empty list + { + memberGroupList = 0; + } + else // add member groups + { + memberGroupList = new MemberGroupList; + for (i=0;iunmarshal(s); + memberGroupList->append(mg); + } + } +} + +QCString MemberList::listTypeAsString() const +{ + switch(m_listType) + { + case pubMethods: return "pub-methods"; + case proMethods: return "pro-methods"; + case pacMethods: return "pac-methods"; + case priMethods: return "pri-methods"; + case pubStaticMethods: return "pub-static-methods"; + case proStaticMethods: return "pro-static-methods"; + case pacStaticMethods: return "pac-static-methods"; + case priStaticMethods: return "pri-static-methods"; + case pubSlots: return "pub-slots"; + case proSlots: return "pro-slots"; + case priSlots: return "pri-slots"; + case pubAttribs: return "pub-attribs"; + case proAttribs: return "pro-attribs"; + case pacAttribs: return "pac-attribs"; + case priAttribs: return "pri-attribs"; + case pubStaticAttribs: return "pub-static-attribs"; + case proStaticAttribs: return "pro-static-attribs"; + case pacStaticAttribs: return "pac-static-attribs"; + case priStaticAttribs: return "pri-static-attribs"; + case pubTypes: return "pub-types"; + case proTypes: return "pro-types"; + case pacTypes: return "pac-types"; + case priTypes: return "pri-types"; + case related: return "related"; + case signals: return "signals"; + case friends: return "friends"; + case dcopMethods: return "dcop-methods"; + case properties: return "properties"; + case events: return "events"; + case decDefineMembers: return "define-members"; + case decProtoMembers: return "proto-members"; + case decTypedefMembers: return "typedef-members"; + case decEnumMembers: return "enum-members"; + case decFuncMembers: return "func-members"; + case decVarMembers: return "var-members"; + case decEnumValMembers: return "enumval-members"; + case decPubSlotMembers: return "pub-slot-members"; + case decProSlotMembers: return "pro-slot-members"; + case decPriSlotMembers: return "pri-slot-members"; + case decSignalMembers: return "signal-members"; + case decEventMembers: return "event-members"; + case decFriendMembers: return "friend-members"; + case decPropMembers: return "prop-members"; + case enumFields: return "enum-fields"; + case memberGroup: return "member-group"; + default: break; + } + return ""; +} + +void MemberList::setNeedsSorting(bool b) +{ + m_needsSorting = b; +} + +//-------------------------------------------------------------------------- + +int MemberSDict::compareItems(GCI item1, GCI item2) +{ + // NOTE: this function can be triggered from unmarshalMemberSDict + // so it may not result in called to MemberDef::makeResident(). + // As a result, the data returned by MemberDef::name() and + // MemberDef::getDefLine() will always be kept in memory. + MemberDef *c1=(MemberDef *)item1; + MemberDef *c2=(MemberDef *)item2; + //printf("MemberSDict::compareItems(%s,%s)\n",c1->name().data(),c2->name().data()); + int cmp = stricmp(c1->name(),c2->name()); + if (cmp) + { + return cmp; + } + else + { + return c1->getDefLine()-c2->getDefLine(); + } +} + + diff --git a/trunk/src/memberlist.h b/trunk/src/memberlist.h new file mode 100644 index 0000000..e832ad5 --- /dev/null +++ b/trunk/src/memberlist.h @@ -0,0 +1,202 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#ifndef MEMBERLIST_H +#define MEMBERLIST_H + +#include +#include "memberdef.h" +#include "sortdict.h" + +class GroupDef; +class MemberGroup; +class MemberGroupList; +class StorageIntf; + +class MemberList : public QList +{ + public: + enum ListType + { + privateLists = 0x0800, + detailedLists = 0x1000, + declarationLists = 0x2000, + documentationLists = 0x4000, + + pubMethods = 0, + proMethods = 1, + pacMethods = 2, + priMethods = 3 + privateLists, + pubStaticMethods = 4, + proStaticMethods = 5, + pacStaticMethods = 6, + priStaticMethods = 7 + privateLists, + pubSlots = 8, + proSlots = 9, + priSlots = 10 + privateLists, + pubAttribs = 11, + proAttribs = 12, + pacAttribs = 13, + priAttribs = 14 + privateLists, + pubStaticAttribs = 15, + proStaticAttribs = 16, + pacStaticAttribs = 17, + priStaticAttribs = 18 + privateLists, + pubTypes = 19, + proTypes = 20, + pacTypes = 21, + priTypes = 22 + privateLists, + related = 23, + signals = 24, + friends = 25, + dcopMethods = 26, + properties = 27, + events = 28, + + typedefMembers = 29 + detailedLists, + enumMembers = 30 + detailedLists, + enumValMembers = 31 + detailedLists, + functionMembers = 32 + detailedLists, + relatedMembers = 33 + detailedLists, + variableMembers = 34 + detailedLists, + propertyMembers = 35 + detailedLists, + eventMembers = 36 + detailedLists, + constructors = 37 + detailedLists, + + allMembersList = 38, + + decDefineMembers = 39 + declarationLists, + decProtoMembers = 40 + declarationLists, + decTypedefMembers = 41 + declarationLists, + decEnumMembers = 42 + declarationLists, + decFuncMembers = 43 + declarationLists, + decVarMembers = 44 + declarationLists, + decEnumValMembers = 45 + declarationLists, + decPubSlotMembers = 46 + declarationLists, + decProSlotMembers = 47 + declarationLists, + decPriSlotMembers = 48 + declarationLists, + decSignalMembers = 49 + declarationLists, + decEventMembers = 50 + declarationLists, + decFriendMembers = 51 + declarationLists, + decPropMembers = 52 + declarationLists, + + docDefineMembers = 53 + documentationLists, + docProtoMembers = 54 + documentationLists, + docTypedefMembers = 55 + documentationLists, + docEnumMembers = 56 + documentationLists, + docFuncMembers = 57 + documentationLists, + docVarMembers = 58 + documentationLists, + docEnumValMembers = 59 + documentationLists, + docPubSlotMembers = 60 + documentationLists, + docProSlotMembers = 61 + documentationLists, + docPriSlotMembers = 62 + documentationLists, + docSignalMembers = 63 + documentationLists, + docEventMembers = 64 + documentationLists, + docFriendMembers = 65 + documentationLists, + docPropMembers = 66 + documentationLists, + + redefinedBy = 67, + enumFields = 68, + memberGroup = 69 + }; + + MemberList(); + MemberList(ListType lt); + ~MemberList(); + ListType listType() const { return m_listType; } + QCString listTypeAsString() const; + bool insert(uint index,const MemberDef *md); + void inSort(const MemberDef *md); + void append(const MemberDef *md); + int compareItems(GCI item1,GCI item2); + int varCount() const { ASSERT(m_numDecMembers!=-1); return m_varCnt; } + int funcCount() const { ASSERT(m_numDecMembers!=-1); return m_funcCnt; } + int enumCount() const { ASSERT(m_numDecMembers!=-1); return m_enumCnt; } + int enumValueCount() const { ASSERT(m_numDecMembers!=-1); return m_enumValCnt; } + int typedefCount() const { ASSERT(m_numDecMembers!=-1); return m_typeCnt; } + int protoCount() const { ASSERT(m_numDecMembers!=-1); return m_protoCnt; } + int defineCount() const { ASSERT(m_numDecMembers!=-1); return m_defCnt; } + int friendCount() const { ASSERT(m_numDecMembers!=-1); return m_friendCnt; } + int numDecMembers() const { ASSERT(m_numDecMembers!=-1); return m_numDecMembers; } + int numDocMembers() const { ASSERT(m_numDocMembers!=-1); return m_numDocMembers; } + bool needsSorting() const { return m_needsSorting; } + void countDecMembers(bool countEnumValues=FALSE,GroupDef *gd=0); + void countDocMembers(bool countEnumValues=FALSE); + void writePlainDeclarations(OutputList &ol, + ClassDef *cd,NamespaceDef *nd,FileDef *fd,GroupDef *gd); + void writeDeclarations(OutputList &ol, + ClassDef *cd,NamespaceDef *nd,FileDef *fd,GroupDef *gd, + const char *title,const char *subtitle,bool showEnumValues=FALSE,bool showInline=FALSE); + void writeDocumentation(OutputList &ol,const char *scopeName, + Definition *container,const char *title,bool showEnumValues=FALSE,bool showInline=FALSE); + void writeSimpleDocumentation(OutputList &ol,Definition *container); + void writeDocumentationPage(OutputList &ol, + const char *scopeName, Definition *container); + bool declVisible() const; + void addMemberGroup(MemberGroup *mg); + void setInGroup(bool inGroup) { m_inGroup=inGroup; } + void setInFile(bool inFile) { m_inFile=inFile; } + void addListReferences(Definition *def); + void findSectionsInDocumentation(); + void setNeedsSorting(bool b); + MemberGroupList *getMemberGroupList() const { return memberGroupList; } + + void marshal(StorageIntf *s); + void unmarshal(StorageIntf *s); + + private: + int m_varCnt; + int m_funcCnt; + int m_enumCnt; + int m_enumValCnt; + int m_typeCnt; + int m_protoCnt; + int m_defCnt; + int m_friendCnt; + int m_numDecMembers; // number of members in the brief part of the memberlist + int m_numDocMembers; // number of members in the detailed part of the memberlist + MemberGroupList *memberGroupList; + bool m_inGroup; // is this list part of a group definition + bool m_inFile; // is this list part of a file definition + ListType m_listType; + bool m_needsSorting; +}; + +class MemberListIterator : public QListIterator +{ + public: + MemberListIterator(const QList &list); + virtual ~MemberListIterator() {} +}; + +class MemberDict : public QDict +{ + public: + MemberDict(int size) : QDict(size) {} + virtual ~MemberDict() {} +}; + +class MemberSDict : public SDict +{ + public: + MemberSDict(int size=17) : SDict(size) {} + virtual ~MemberSDict() {} + int compareItems(GCI item1,GCI item2); +}; + + +#endif diff --git a/trunk/src/membername.cpp b/trunk/src/membername.cpp new file mode 100644 index 0000000..506313e --- /dev/null +++ b/trunk/src/membername.cpp @@ -0,0 +1,83 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#include "membername.h" +#include "classdef.h" +#include "util.h" +#include "filedef.h" + +MemberName::MemberName(const char *n) : QList() +{ + name=n; + setAutoDelete(TRUE); +} + +MemberName::~MemberName() +{ +} + +int MemberName::compareItems(GCI item1, GCI item2) +{ + MemberDef *m1=(MemberDef *)item1; + MemberDef *m2=(MemberDef *)item2; + ClassDef *c1=m1->getClassDef(); + ClassDef *c2=m2->getClassDef(); + FileDef *f1=m1->getFileDef(); + FileDef *f2=m2->getFileDef(); + if (c1 && c2) + return strcmp(c1->name(),c2->name()); + else if (f1 && f2) + return strcmp(f1->name(),f2->name()); + else + return 0; +} + +MemberNameInfo::MemberNameInfo(const char *n) : QList() +{ + name=n; + setAutoDelete(TRUE); +} + +int MemberNameInfo::compareItems(GCI item1, GCI item2) +{ + MemberInfo *m1=(MemberInfo *)item1; + MemberInfo *m2=(MemberInfo *)item2; + ClassDef *c1=m1->memberDef->getClassDef(); + ClassDef *c2=m2->memberDef->getClassDef(); + FileDef *f1=m1->memberDef->getFileDef(); + FileDef *f2=m2->memberDef->getFileDef(); + if (c1 && c2) + return strcmp(c1->name(),c2->name()); + else if (f1 && f2) + return strcmp(f1->name(),f2->name()); + else + return 0; +} +MemberNameIterator::MemberNameIterator(const MemberName &mnlist) : + QListIterator(mnlist) +{ +} + +int MemberNameSDict::compareItems(GCI item1, GCI item2) +{ + MemberName *n1=(MemberName *)item1; + MemberName *n2=(MemberName *)item2; + return stricmp(n1->memberName()+getPrefixIndex(n1->memberName()), + n2->memberName()+getPrefixIndex(n2->memberName()) + ); +} + diff --git a/trunk/src/membername.h b/trunk/src/membername.h new file mode 100644 index 0000000..e5fbaa3 --- /dev/null +++ b/trunk/src/membername.h @@ -0,0 +1,98 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#ifndef MEMBERNAME_H +#define MEMBERNAME_H + +#include +#include "memberdef.h" +#include "sortdict.h" + +class MemberName : public QList +{ + public: + MemberName(const char *name); + ~MemberName(); + const char *memberName() const { return name; } + + int compareItems(GCI item1,GCI item2); + private: + QCString name; +}; + +class MemberNameIterator : public QListIterator +{ + public: + MemberNameIterator( const MemberName &list); +}; + +class MemberNameSDict : public SDict +{ + public: + MemberNameSDict(int size) : SDict(size) {} + ~MemberNameSDict() {} + + int compareItems(GCI item1,GCI item2); +}; + +struct MemberInfo +{ + MemberInfo(MemberDef *md,Protection p,Specifier v,bool inh) : + memberDef(md), prot(p), virt(v), inherited(inh), ambigClass(0) {} + ~MemberInfo() {} + MemberDef *memberDef; + Protection prot; + Specifier virt; + bool inherited; + QCString scopePath; + QCString ambiguityResolutionScope; + ClassDef *ambigClass; +}; + +class MemberNameInfo : public QList +{ + public: + MemberNameInfo(const char *name); + ~MemberNameInfo() {} + const char *memberName() const { return name; } + int compareItems(GCI item1,GCI item2); + private: + QCString name; +}; + +class MemberNameInfoIterator : public QListIterator +{ + public: + MemberNameInfoIterator(const MemberNameInfo &mnii) + : QListIterator(mnii) {} +}; + + +class MemberNameInfoSDict : public SDict +{ + public: + MemberNameInfoSDict(int size) : SDict(size) {} + ~MemberNameInfoSDict() {} + int compareItems(GCI item1,GCI item2) + { return stricmp( + ((MemberNameInfo *)item1)->memberName(), + ((MemberNameInfo *)item2)->memberName() + ); + } +}; + +#endif diff --git a/trunk/src/message.cpp b/trunk/src/message.cpp new file mode 100644 index 0000000..5a452cc --- /dev/null +++ b/trunk/src/message.cpp @@ -0,0 +1,196 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#include +#include +#include +#include "config.h" +#include "util.h" +#include "debug.h" +#include "doxygen.h" +#include "portable.h" + +static QCString outputFormat; +//static int warnFormatOrder; // 1 = $file,$line,$text +// // 2 = $text,$line,$file +// // 3 = $line,$text,$file +// // 4 = $file,$text,$line +// // 5 = $text,$file,$line +// // 6 = $line,$file,$text + +static FILE *warnFile = stderr; + +void initWarningFormat() +{ +// int filePos = Config_getString("WARN_FORMAT").find("$file"); +// int linePos = Config_getString("WARN_FORMAT").find("$line"); +// int textPos = Config_getString("WARN_FORMAT").find("$text"); +// +// // sort items on position (there are 6 cases) +// warnFormatOrder = 1; +// if (filePos>linePos && filePos>textPos) +// { +// if (linePos>textPos) // $text,$line,$file +// { +// warnFormatOrder = 2; +// } +// else // $line,$text,$file +// { +// warnFormatOrder = 3; +// } +// } +// else if (filePostextPos) // $file,$text,$line +// { +// warnFormatOrder = 4; +// } +// } +// else if (filePostextPos) // $text,$file,$line +// { +// warnFormatOrder = 5; +// } +// else // $line,$file,$text +// { +// warnFormatOrder = 6; +// } +// outputFormat = +// substitute( +// substitute( +// substitute( +// Config_getString("WARN_FORMAT"), +// "$file","%s" +// ), +// "$text","%s" +// ), +// "$line","%d" +// )+'\n'; + + // replace(QRegExp("\\$file"),"%s"). + // replace(QRegExp("\\$text"),"%s"). + // replace(QRegExp("\\$line"),"%d")+ + // '\n'; + + outputFormat = Config_getString("WARN_FORMAT"); + + if (!Config_getString("WARN_LOGFILE").isEmpty()) + { + warnFile = portable_fopen(Config_getString("WARN_LOGFILE"),"w"); + } + if (!warnFile) // point it to something valid, because warn() relies on it + { + warnFile = stderr; + } +} + + +void msg(const char *fmt, ...) +{ + if (!Config_getBool("QUIET")) + { + if (Debug::isFlagSet(Debug::Time)) + { + printf("%.3f sec: ",((double)Doxygen::runningTime.elapsed())/1000.0); + } + va_list args; + va_start(args, fmt); + vfprintf(stdout, fmt, args); + va_end(args); + } +} + +static void format_warn(const char *file,int line,const char *text) +{ + QCString fileSubst = file==0 ? "" : file; + QCString lineSubst; lineSubst.setNum(line); + QCString textSubst = text; + QCString versionSubst; + if (file) // get version from file name + { + bool ambig; + FileDef *fd=findFileDef(Doxygen::inputNameDict,file,ambig); + if (fd) + { + versionSubst = fd->getVersion(); + } + } + // substitute markers by actual values + QCString msgText = + substitute( + substitute( + substitute( + substitute( + outputFormat, + "$file",fileSubst + ), + "$text",textSubst + ), + "$line",lineSubst + ), + "$version",versionSubst + )+'\n'; + + // print resulting message + fwrite(msgText.data(),1,msgText.length(),warnFile); +} + +static void do_warn(const char *tag, const char *file, int line, const char *fmt, va_list args) +{ + if (!Config_getBool(tag)) return; // warning type disabled + char text[4096]; + vsnprintf(text, 4096, fmt, args); + text[4095]='\0'; + format_warn(file,line,text); +} + +void warn(const char *file,int line,const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + do_warn("WARNINGS", file, line, fmt, args); + va_end(args); +} + +void warn_simple(const char *file,int line,const char *text) +{ + if (!Config_getBool("WARNINGS")) return; // warning type disabled + format_warn(file,line,text); +} + +void warn_undoc(const char *file,int line,const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + do_warn("WARN_IF_UNDOCUMENTED", file, line, fmt, args); + va_end(args); +} + +void warn_doc_error(const char *file,int line,const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + do_warn("WARN_IF_DOC_ERROR", file, line, fmt, args); + va_end(args); +} + +void err(const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + vfprintf(warnFile, fmt, args); + va_end(args); +} diff --git a/trunk/src/message.h b/trunk/src/message.h new file mode 100644 index 0000000..46b736c --- /dev/null +++ b/trunk/src/message.h @@ -0,0 +1,31 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#ifndef MESSAGE_H +#define MESSAGE_H + +#include + +extern void msg(const char *fmt, ...); +extern void warn(const char *file,int line,const char *fmt, ...); +extern void warn_simple(const char *file,int line,const char *text); +extern void warn_undoc(const char *file,int line,const char *fmt, ...); +extern void warn_doc_error(const char *file,int line,const char *fmt, ...); +extern void err(const char *fmt, ...); +void initWarningFormat(); + +#endif diff --git a/trunk/src/msc.cpp b/trunk/src/msc.cpp new file mode 100644 index 0000000..51875ba --- /dev/null +++ b/trunk/src/msc.cpp @@ -0,0 +1,198 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#include "msc.h" +#include "portable.h" +#include "config.h" +#include "message.h" +#include "docparser.h" +#include "doxygen.h" + +#include + +static const int maxCmdLine = 40960; + +static bool convertMapFile(QTextStream &t,const char *mapName,const QCString relPath, + const QCString &context) +{ + QFile f(mapName); + if (!f.open(IO_ReadOnly)) + { + err("error: failed to open map file %s for inclusion in the docs!\n" + "If you installed Graphviz/dot after a previous failing run, \n" + "try deleting the output directory and rerun doxygen.\n",mapName); + return FALSE; + } + const int maxLineLen=1024; + char buf[maxLineLen]; + char url[maxLineLen]; + char ref[maxLineLen]; + int x1,y1,x2,y2; + while (!f.atEnd()) + { + bool isRef = FALSE; + int numBytes = f.readLine(buf,maxLineLen); + buf[numBytes-1]='\0'; + //printf("ReadLine `%s'\n",buf); + if (strncmp(buf,"rect",4)==0) + { + // obtain the url and the coordinates in the order used by graphviz-1.5 + sscanf(buf,"rect %s %d,%d %d,%d",url,&x1,&y1,&x2,&y2); + + if ( strcmp(url,"\\ref") == 0 ) + { + isRef = TRUE; + sscanf(buf,"rect %s %s %d,%d %d,%d",ref,url,&x1,&y1,&x2,&y2); + } + + // sanity checks + if (y2ref(),TRUE); + if (!df->file().isEmpty()) t << df->file() << Doxygen::htmlFileExtension; + if (!df->anchor().isEmpty()) t << "#" << df->anchor(); + } + else + { + t << url; + } + t << "\" shape=\"rect\" coords=\"" + << x1 << "," << y1 << "," << x2 << "," << y2 << "\"" + << " alt=\"\"/>" << endl; + } + } + + return TRUE; +} + +void writeMscGraphFromFile(const char *inFile,const char *outDir, + const char *outFile,MscOutputFormat format) +{ + QCString absOutFile = outDir; + absOutFile+=portable_pathSeparator(); + absOutFile+=outFile; + + // chdir to the output dir, so dot can find the font file. + QCString oldDir = convertToQCString(QDir::currentDirPath()); + // go to the html output directory (i.e. path) + QDir::setCurrent(outDir); + //printf("Going to dir %s\n",QDir::currentDirPath().data()); + QCString mscExe = Config_getString("MSCGEN_PATH")+"mscgen"+portable_commandExtension(); + QCString mscArgs; + QCString extension; + if (format==MSC_BITMAP) + { + mscArgs+="-T png"; + extension=".png"; + } + else if (format==MSC_EPS) + { + mscArgs+="-T eps"; + extension=".eps"; + } + mscArgs+=" -i \""; + mscArgs+=inFile; + + mscArgs+="\" -o \""; + mscArgs+=outFile; + mscArgs+=extension+"\""; + int exitCode; +// printf("*** running: %s %s outDir:%s %s\n",mscExe.data(),mscArgs.data(),outDir,outFile); + portable_sysTimerStart(); + if ((exitCode=portable_system(mscExe,mscArgs,FALSE))!=0) + { + portable_sysTimerStop(); + goto error; + } + portable_sysTimerStop(); + if ( (format==MSC_EPS) && (Config_getBool("USE_PDFLATEX")) ) + { + QCString epstopdfArgs(maxCmdLine); + epstopdfArgs.sprintf("\"%s.eps\" --outfile=\"%s.pdf\"", + outFile,outFile); + portable_sysTimerStart(); + if (portable_system("epstopdf",epstopdfArgs)!=0) + { + err("error: Problems running epstopdf. Check your TeX installation!\n"); + } + portable_sysTimerStop(); + } + +error: + QDir::setCurrent(oldDir); +} + +QCString getMscImageMapFromFile(const QCString& inFile, const QCString& outDir, + const QCString& relPath,const QCString& context) +{ + QCString outFile = inFile + ".map"; + + + //printf("*** running:getMscImageMapFromFile \n"); + // chdir to the output dir, so dot can find the font file. + QCString oldDir = convertToQCString(QDir::currentDirPath()); + // go to the html output directory (i.e. path) + QDir::setCurrent(outDir); + //printf("Going to dir %s\n",QDir::currentDirPath().data()); + + QCString mscExe = Config_getString("MSCGEN_PATH")+"mscgen"+portable_commandExtension(); + QCString mscArgs = "-T ismap -i \""; + mscArgs+=inFile; + QFileInfo fi(inFile); + mscArgs+="\" -o \""; + mscArgs+=outFile + "\""; + + int exitCode; + portable_sysTimerStart(); + if ((exitCode=portable_system(mscExe,mscArgs,FALSE))!=0) + { + portable_sysTimerStop(); + QDir::setCurrent(oldDir); + return ""; + } + portable_sysTimerStop(); + + QString result; + QTextOStream tmpout(&result); + convertMapFile(tmpout, outFile, relPath, context); + QDir().remove(outFile); + + QDir::setCurrent(oldDir); + return result.data(); +} + +void writeMscImageMapFromFile(FTextStream &t,const QCString &inFile, + const QCString &outDir, + const QCString &relPath, + const QCString &baseName, + const QCString &context) +{ + QCString mapName = baseName+".map"; + QCString mapFile = inFile+".map"; + t << "\""" << endl; + QCString imap = getMscImageMapFromFile(inFile,outDir,relPath,context); + t << "" << imap << "" << endl; +} + diff --git a/trunk/src/msc.h b/trunk/src/msc.h new file mode 100644 index 0000000..f1fc78b --- /dev/null +++ b/trunk/src/msc.h @@ -0,0 +1,38 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#ifndef _MSC_H +#define _MSC_H + +#include "qtbc.h" + +class FTextStream; + +enum MscOutputFormat { MSC_BITMAP , MSC_EPS }; + +void writeMscGraphFromFile(const char *inFile,const char *outDir, + const char *outFile,MscOutputFormat format); + +QCString getMscImageMapFromFile(const QCString& inFile, const QCString& outDir, + const QCString& relPath,const QCString& context); + +void writeMscImageMapFromFile(FTextStream &t,const QCString &inFile, + const QCString &outDir, const QCString &relPath, + const QCString &baseName, const QCString &context); + +#endif + diff --git a/trunk/src/namespacedef.cpp b/trunk/src/namespacedef.cpp new file mode 100644 index 0000000..4d53a12 --- /dev/null +++ b/trunk/src/namespacedef.cpp @@ -0,0 +1,992 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#include "qtbc.h" +#include "namespacedef.h" +#include "outputlist.h" +#include "util.h" +#include "language.h" +#include "classdef.h" +#include "classlist.h" +#include "memberlist.h" +#include "doxygen.h" +#include "message.h" +#include "docparser.h" +#include "searchindex.h" +#include "vhdldocgen.h" +#include "layout.h" + +//------------------------------------------------------------------ + +NamespaceDef::NamespaceDef(const char *df,int dl, + const char *name,const char *lref, + const char *fName) : + Definition(df,dl,name) +{ + if (fName) + { + fileName = stripExtension(fName); + } + else + { + fileName="namespace"; + fileName+=name; + } + classSDict = new ClassSDict(17); + namespaceSDict = new NamespaceSDict(17); + m_innerCompounds = new SDict(17); + usingDirList = 0; + usingDeclList = 0; + m_allMembersDict = 0; + setReference(lref); + memberGroupSDict = new MemberGroupSDict; + memberGroupSDict->setAutoDelete(TRUE); + visited=FALSE; + m_subGrouping=Config_getBool("SUBGROUPING"); +} + +NamespaceDef::~NamespaceDef() +{ + delete classSDict; + delete namespaceSDict; + delete m_innerCompounds; + delete usingDirList; + delete usingDeclList; + delete memberGroupSDict; +} + +void NamespaceDef::distributeMemberGroupDocumentation() +{ + MemberGroupSDict::Iterator mgli(*memberGroupSDict); + MemberGroup *mg; + for (;(mg=mgli.current());++mgli) + { + mg->distributeMemberGroupDocumentation(); + } +} + +void NamespaceDef::findSectionsInDocumentation() +{ + docFindSections(documentation(),this,0,docFile()); + MemberGroupSDict::Iterator mgli(*memberGroupSDict); + MemberGroup *mg; + for (;(mg=mgli.current());++mgli) + { + mg->findSectionsInDocumentation(); + } + QListIterator mli(m_memberLists); + MemberList *ml; + for (mli.toFirst();(ml=mli.current());++mli) + { + if (ml->listType()&MemberList::declarationLists) + { + ml->findSectionsInDocumentation(); + } + } +} + +void NamespaceDef::insertUsedFile(const char *f) +{ + if (files.find(f)==-1) + { + if (Config_getBool("SORT_MEMBER_DOCS")) + files.inSort(f); + else + files.append(f); + } +} + +void NamespaceDef::addInnerCompound(Definition *d) +{ + m_innerCompounds->append(d->localName(),d); + if (d->definitionType()==Definition::TypeNamespace) + { + insertNamespace((NamespaceDef *)d); + } + else if (d->definitionType()==Definition::TypeClass) + { + insertClass((ClassDef *)d); + } +} + +void NamespaceDef::insertClass(ClassDef *cd) +{ + if (classSDict->find(cd->name())==0) + { + if (Config_getBool("SORT_BRIEF_DOCS")) + classSDict->inSort(cd->name(),cd); + else + classSDict->append(cd->name(),cd); + } +} + +void NamespaceDef::insertNamespace(NamespaceDef *nd) +{ + if (namespaceSDict->find(nd->name())==0) + { + if (Config_getBool("SORT_MEMBER_DOCS")) + namespaceSDict->inSort(nd->name(),nd); + else + namespaceSDict->append(nd->name(),nd); + } +} + + +void NamespaceDef::addMembersToMemberGroup() +{ + QListIterator mli(m_memberLists); + MemberList *ml; + for (mli.toFirst();(ml=mli.current());++mli) + { + if (ml->listType()&MemberList::declarationLists) + { + ::addMembersToMemberGroup(ml,&memberGroupSDict,this); + } + } + + // add members inside sections to their groups + if (memberGroupSDict) + { + MemberGroupSDict::Iterator mgli(*memberGroupSDict); + MemberGroup *mg; + for (;(mg=mgli.current());++mgli) + { + if (mg->allMembersInSameSection() && m_subGrouping) + { + //printf("----> addToDeclarationSection(%s)\n",mg->header().data()); + mg->addToDeclarationSection(); + } + } + } +} + +void NamespaceDef::insertMember(MemberDef *md) +{ + if (md->isHidden()) return; + MemberList *allMemberList = getMemberList(MemberList::allMembersList); + if (allMemberList==0) + { + allMemberList = new MemberList(MemberList::allMembersList); + m_memberLists.append(allMemberList); + } + allMemberList->append(md); + if (m_allMembersDict==0) + { + m_allMembersDict = new MemberSDict; + } + //printf("%s::m_allMembersDict->append(%s)\n",name().data(),md->localName().data()); + m_allMembersDict->append(md->localName(),md); + //::addNamespaceMemberNameToIndex(md); + //static bool sortBriefDocs=Config_getBool("SORT_BRIEF_DOCS"); + switch(md->memberType()) + { + case MemberDef::Variable: + addMemberToList(MemberList::decVarMembers,md); + addMemberToList(MemberList::docVarMembers,md); + break; + case MemberDef::Function: + addMemberToList(MemberList::decFuncMembers,md); + addMemberToList(MemberList::docFuncMembers,md); + break; + case MemberDef::Typedef: + addMemberToList(MemberList::decTypedefMembers,md); + addMemberToList(MemberList::docTypedefMembers,md); + break; + case MemberDef::Enumeration: + addMemberToList(MemberList::decEnumMembers,md); + addMemberToList(MemberList::docEnumMembers,md); + break; + case MemberDef::EnumValue: + break; + case MemberDef::Define: + addMemberToList(MemberList::decDefineMembers,md); + addMemberToList(MemberList::docDefineMembers,md); + break; + default: + err("NamespaceDef::insertMembers(): " + "member `%s' with class scope `%s' inserted in namespace scope `%s'!\n", + md->name().data(), + md->getClassDef() ? md->getClassDef()->name().data() : "", + name().data()); + } +} + +void NamespaceDef::computeAnchors() +{ + MemberList *allMemberList = getMemberList(MemberList::allMembersList); + if (allMemberList) setAnchors(0,'a',allMemberList); +} + +void NamespaceDef::writeDetailedDescription(OutputList &ol,const QCString &title) +{ + if ((!briefDescription().isEmpty() && Config_getBool("REPEAT_BRIEF")) || + !documentation().isEmpty() + ) + { + ol.writeRuler(); + ol.pushGeneratorState(); + ol.disableAllBut(OutputGenerator::Html); + ol.writeAnchor(0,"details"); + ol.popGeneratorState(); + ol.startGroupHeader(); + ol.parseText(title); + ol.endGroupHeader(); + + ol.startTextBlock(); + if (!briefDescription().isEmpty() && Config_getBool("REPEAT_BRIEF")) + { + ol.parseDoc(briefFile(),briefLine(),this,0,briefDescription(),FALSE,FALSE); + } + if (!briefDescription().isEmpty() && Config_getBool("REPEAT_BRIEF") && + !documentation().isEmpty()) + { + ol.pushGeneratorState(); + ol.disable(OutputGenerator::Man); + ol.disable(OutputGenerator::RTF); + //ol.newParagraph(); // FIXME:PARA + ol.enableAll(); + ol.disableAllBut(OutputGenerator::Man); + ol.writeString("\n\n"); + ol.popGeneratorState(); + } + if (!documentation().isEmpty()) + { + ol.parseDoc(docFile(),docLine(),this,0,documentation()+"\n",TRUE,FALSE); + } + ol.endTextBlock(); + } +} + +void NamespaceDef::writeBriefDescription(OutputList &ol) +{ + if (!briefDescription().isEmpty() && Config_getBool("BRIEF_MEMBER_DESC")) + { + ol.startParagraph(); + ol.parseDoc(briefFile(),briefLine(),this,0, + briefDescription(),TRUE,FALSE,0,TRUE,FALSE); + ol.pushGeneratorState(); + ol.disable(OutputGenerator::RTF); + ol.writeString(" \n"); + ol.enable(OutputGenerator::RTF); + + if (Config_getBool("REPEAT_BRIEF") || + !documentation().isEmpty() + ) + { + ol.disableAllBut(OutputGenerator::Html); + ol.startTextLink(0,"details"); + ol.parseText(theTranslator->trMore()); + ol.endTextLink(); + } + ol.popGeneratorState(); + ol.endParagraph(); + + // FIXME:PARA + //ol.pushGeneratorState(); + //ol.disable(OutputGenerator::RTF); + //ol.newParagraph(); + //ol.popGeneratorState(); + } + ol.writeSynopsis(); +} + +void NamespaceDef::startMemberDeclarations(OutputList &ol) +{ + ol.startMemberSections(); +} + +void NamespaceDef::endMemberDeclarations(OutputList &ol) +{ + ol.endMemberSections(); +} + +void NamespaceDef::startMemberDocumentation(OutputList &ol) +{ + if (Config_getBool("SEPARATE_MEMBER_PAGES")) + { + ol.disable(OutputGenerator::Html); + Doxygen::suppressDocWarnings = TRUE; + } +} + +void NamespaceDef::endMemberDocumentation(OutputList &ol) +{ + if (Config_getBool("SEPARATE_MEMBER_PAGES")) + { + ol.enable(OutputGenerator::Html); + Doxygen::suppressDocWarnings = FALSE; + } +} + +void NamespaceDef::writeClassDeclarations(OutputList &ol,const QCString &title) +{ + if (classSDict) classSDict->writeDeclaration(ol,0,title,TRUE); +} + +void NamespaceDef::writeInlineClasses(OutputList &ol) +{ + if (classSDict) classSDict->writeDocumentation(ol,this); +} + +void NamespaceDef::writeNamespaceDeclarations(OutputList &ol,const QCString &title) +{ + if (namespaceSDict) namespaceSDict->writeDeclaration(ol,title,TRUE); +} + +void NamespaceDef::writeMemberGroups(OutputList &ol) +{ + /* write user defined member groups */ + if (memberGroupSDict) + { + memberGroupSDict->sort(); + MemberGroupSDict::Iterator mgli(*memberGroupSDict); + MemberGroup *mg; + for (;(mg=mgli.current());++mgli) + { + if ((!mg->allMembersInSameSection() || !m_subGrouping) + && mg->header()!="[NOHEADER]") + { + mg->writeDeclarations(ol,0,this,0,0); + } + } + } +} + +void NamespaceDef::writeAuthorSection(OutputList &ol) +{ + // write Author section (Man only) + ol.pushGeneratorState(); + ol.disableAllBut(OutputGenerator::Man); + ol.startGroupHeader(); + ol.parseText(theTranslator->trAuthor(TRUE,TRUE)); + ol.endGroupHeader(); + ol.parseText(theTranslator->trGeneratedAutomatically(Config_getString("PROJECT_NAME"))); + ol.popGeneratorState(); +} + +void NamespaceDef::writeSummaryLinks(OutputList &ol) +{ + ol.pushGeneratorState(); + ol.disableAllBut(OutputGenerator::Html); + QListIterator eli( + LayoutDocManager::instance().docEntries(LayoutDocManager::Namespace)); + LayoutDocEntry *lde; + bool first=TRUE; + for (eli.toFirst();(lde=eli.current());++eli) + { + if ((lde->kind()==LayoutDocEntry::NamespaceClasses && classSDict && classSDict->declVisible()) || + (lde->kind()==LayoutDocEntry::NamespaceNestedNamespaces && namespaceSDict && namespaceSDict->declVisible()) + ) + { + LayoutDocEntrySection *ls = (LayoutDocEntrySection*)lde; + QCString label = lde->kind()==LayoutDocEntry::NamespaceClasses ? "nested-classes" : "namespaces"; + writeSummaryLink(ol,label,ls->title,first); + } + else if (lde->kind()== LayoutDocEntry::MemberDecl) + { + LayoutDocEntryMemberDecl *lmd = (LayoutDocEntryMemberDecl*)lde; + MemberList * ml = getMemberList(lmd->type); + if (ml && ml->declVisible()) + { + writeSummaryLink(ol,ml->listTypeAsString(),lmd->title,first); + } + } + } + if (!first) + { + ol.writeString(" \n"); + } + ol.popGeneratorState(); +} + +void NamespaceDef::writeDocumentation(OutputList &ol) +{ + static bool generateTreeView = Config_getBool("GENERATE_TREEVIEW"); + //static bool outputJava = Config_getBool("OPTIMIZE_OUTPUT_JAVA"); + //static bool fortranOpt = Config_getBool("OPTIMIZE_FOR_FORTRAN"); + SrcLangExt lang = getLanguage(); + + QCString pageTitle; + if (lang==SrcLangExt_Java || lang==SrcLangExt_CSharp) + { + pageTitle = theTranslator->trPackage(displayName()); + } + else if (lang==SrcLangExt_Fortran) + { + pageTitle = theTranslator->trModuleReference(displayName()); + } + else + { + pageTitle = theTranslator->trNamespaceReference(displayName()); + } + startFile(ol,getOutputFileBase(),name(),pageTitle,HLI_NamespaceVisible,!generateTreeView); + + if (!generateTreeView) + { + if (getOuterScope()!=Doxygen::globalScope) + { + writeNavigationPath(ol); + } + ol.endQuickIndices(); + } + + startTitle(ol,getOutputFileBase(),this); + ol.parseText(pageTitle); + addGroupListToTitle(ol,this); + endTitle(ol,getOutputFileBase(),displayName()); + ol.startContents(); + + if (Doxygen::searchIndex) + { + Doxygen::searchIndex->setCurrentDoc(pageTitle,getOutputFileBase()); + Doxygen::searchIndex->addWord(localName(),TRUE); + } + + bool generateTagFile = !Config_getString("GENERATE_TAGFILE").isEmpty(); + if (generateTagFile) + { + Doxygen::tagFile << " " << endl; + Doxygen::tagFile << " " << convertToXML(name()) << "" << endl; + Doxygen::tagFile << " " << convertToXML(getOutputFileBase()) << Doxygen::htmlFileExtension << "" << endl; + } + + Doxygen::indexList.addIndexItem(this,0); + + //---------------------------------------- start flexible part ------------------------------- + + QListIterator eli( + LayoutDocManager::instance().docEntries(LayoutDocManager::Namespace)); + LayoutDocEntry *lde; + for (eli.toFirst();(lde=eli.current());++eli) + { + switch (lde->kind()) + { + case LayoutDocEntry::BriefDesc: + writeBriefDescription(ol); + break; + case LayoutDocEntry::MemberDeclStart: + startMemberDeclarations(ol); + break; + case LayoutDocEntry::NamespaceClasses: + { + LayoutDocEntrySection *ls = (LayoutDocEntrySection*)lde; + writeClassDeclarations(ol,ls->title); + } + break; + case LayoutDocEntry::NamespaceNestedNamespaces: + { + LayoutDocEntrySection *ls = (LayoutDocEntrySection*)lde; + writeNamespaceDeclarations(ol,ls->title); + } + break; + case LayoutDocEntry::MemberGroups: + writeMemberGroups(ol); + break; + case LayoutDocEntry::MemberDecl: + { + LayoutDocEntryMemberDecl *lmd = (LayoutDocEntryMemberDecl*)lde; + writeMemberDeclarations(ol,lmd->type,lmd->title); + } + break; + case LayoutDocEntry::MemberDeclEnd: + endMemberDeclarations(ol); + break; + case LayoutDocEntry::DetailedDesc: + { + LayoutDocEntrySection *ls = (LayoutDocEntrySection*)lde; + writeDetailedDescription(ol,ls->title); + } + break; + case LayoutDocEntry::MemberDefStart: + startMemberDocumentation(ol); + break; + case LayoutDocEntry::NamespaceInlineClasses: + writeInlineClasses(ol); + break; + case LayoutDocEntry::MemberDef: + { + LayoutDocEntryMemberDef *lmd = (LayoutDocEntryMemberDef*)lde; + writeMemberDocumentation(ol,lmd->type,lmd->title); + } + break; + case LayoutDocEntry::MemberDefEnd: + endMemberDocumentation(ol); + break; + case LayoutDocEntry::AuthorSection: + writeAuthorSection(ol); + break; + case LayoutDocEntry::ClassIncludes: + case LayoutDocEntry::ClassInheritanceGraph: + case LayoutDocEntry::ClassNestedClasses: + case LayoutDocEntry::ClassCollaborationGraph: + case LayoutDocEntry::ClassAllMembersLink: + case LayoutDocEntry::ClassUsedFiles: + case LayoutDocEntry::ClassInlineClasses: + case LayoutDocEntry::FileClasses: + case LayoutDocEntry::FileNamespaces: + case LayoutDocEntry::FileIncludes: + case LayoutDocEntry::FileIncludeGraph: + case LayoutDocEntry::FileIncludedByGraph: + case LayoutDocEntry::FileSourceLink: + case LayoutDocEntry::FileInlineClasses: + case LayoutDocEntry::GroupClasses: + case LayoutDocEntry::GroupInlineClasses: + case LayoutDocEntry::GroupNamespaces: + case LayoutDocEntry::GroupDirs: + case LayoutDocEntry::GroupNestedGroups: + case LayoutDocEntry::GroupFiles: + case LayoutDocEntry::GroupGraph: + case LayoutDocEntry::GroupPageDocs: + case LayoutDocEntry::DirSubDirs: + case LayoutDocEntry::DirFiles: + case LayoutDocEntry::DirGraph: + err("Internal inconsistency: member %d should not be part of " + "LayoutDocManager::Namespace entry list\n",lde->kind()); + break; + } + } + + //---------------------------------------- end flexible part ------------------------------- + + ol.endContents(); + + endFileWithNavPath(this,ol); + + if (generateTagFile) + { + writeDocAnchorsToTagFile(); + Doxygen::tagFile << " " << endl; + } + + if (Config_getBool("SEPARATE_MEMBER_PAGES")) + { + MemberList *allMemberList = getMemberList(MemberList::allMembersList); + if (allMemberList) allMemberList->sort(); + writeMemberPages(ol); + } +} + +void NamespaceDef::writeMemberPages(OutputList &ol) +{ + ol.pushGeneratorState(); + ol.disableAllBut(OutputGenerator::Html); + + QListIterator mli(m_memberLists); + MemberList *ml; + for (mli.toFirst();(ml=mli.current());++mli) + { + if (ml->listType()&MemberList::documentationLists) + { + ml->writeDocumentationPage(ol,displayName(),this); + } + } + ol.popGeneratorState(); +} + +void NamespaceDef::writeQuickMemberLinks(OutputList &ol,MemberDef *currentMd) const +{ + static bool createSubDirs=Config_getBool("CREATE_SUBDIRS"); + + ol.writeString("
    \n"); + ol.writeString(" \n"); + + MemberList *allMemberList = getMemberList(MemberList::allMembersList); + if (allMemberList) + { + MemberListIterator mli(*allMemberList); + MemberDef *md; + for (mli.toFirst();(md=mli.current());++mli) + { + if (md->getNamespaceDef()==this && md->isLinkable()) + { + ol.writeString(" \n"); + } + } + } + + ol.writeString("
    "); + if (md->isLinkableInProject()) + { + if (md==currentMd) // selected item => highlight + { + ol.writeString("getOutputFileBase()+Doxygen::htmlFileExtension+"#"+md->anchor()); + ol.writeString("\">"); + ol.writeString(convertToHtml(md->localName())); + ol.writeString(""); + } + ol.writeString("
    \n"); + ol.writeString("
    \n"); +} + +int NamespaceDef::countMembers() +{ + MemberList *allMemberList = getMemberList(MemberList::allMembersList); + if (allMemberList) allMemberList->countDocMembers(); + return (allMemberList ? allMemberList->numDocMembers() : 0)+classSDict->count(); +} + +void NamespaceDef::addUsingDirective(NamespaceDef *nd) +{ + if (usingDirList==0) + { + usingDirList = new NamespaceSDict; + } + if (usingDirList->find(nd->qualifiedName())==0) + { + usingDirList->append(nd->qualifiedName(),nd); + } + //printf("%p: NamespaceDef::addUsingDirective: %s:%d\n",this,name().data(),usingDirList->count()); +} + +NamespaceSDict *NamespaceDef::getUsedNamespaces() const +{ + //printf("%p: NamespaceDef::getUsedNamespace: %s:%d\n",this,name().data(),usingDirList?usingDirList->count():0); + return usingDirList; +} + +void NamespaceDef::addUsingDeclaration(Definition *d) +{ + if (usingDeclList==0) + { + usingDeclList = new SDict(17); + } + if (usingDeclList->find(d->qualifiedName())==0) + { + usingDeclList->append(d->qualifiedName(),d); + } +} + +QCString NamespaceDef::getOutputFileBase() const +{ + if (isReference()) + { + return fileName; + } + else + { + return convertNameToFile(fileName); + } +} + +Definition *NamespaceDef::findInnerCompound(const char *n) +{ + if (n==0) return 0; + Definition *d = m_innerCompounds->find(n); + if (d==0) + { + if (usingDirList) + { + d = usingDirList->find(n); + } + if (d==0 && usingDeclList) + { + d = usingDeclList->find(n); + } + } + return d; +} + +void NamespaceDef::addListReferences() +{ + //bool fortranOpt = Config_getBool("OPTIMIZE_FOR_FORTRAN"); + { + LockingPtr< QList > xrefItems = xrefListItems(); + addRefItem(xrefItems.pointer(), + qualifiedName(), + getLanguage()==SrcLangExt_Fortran ? + theTranslator->trModule(TRUE,TRUE) : + theTranslator->trNamespace(TRUE,TRUE), + getOutputFileBase(),displayName(), + 0 + ); + } + MemberGroupSDict::Iterator mgli(*memberGroupSDict); + MemberGroup *mg; + for (;(mg=mgli.current());++mgli) + { + mg->addListReferences(this); + } + QListIterator mli(m_memberLists); + MemberList *ml; + for (mli.toFirst();(ml=mli.current());++mli) + { + if (ml->listType()&MemberList::documentationLists) + { + ml->addListReferences(this); + } + } +} + +QCString NamespaceDef::displayName() const +{ + QCString result=name(); + SrcLangExt lang = getLanguage(); + QCString sep = getLanguageSpecificSeparator(lang); + if (sep!="::") + { + result = substitute(result,"::",sep); + } + //printf("NamespaceDef::displayName() %s->%s lang=%d\n",name().data(),result.data(),lang); + return result; +} + +void NamespaceDef::combineUsingRelations() +{ + if (visited) return; // already done + visited=TRUE; + if (usingDirList) + { + NamespaceSDict::Iterator nli(*usingDirList); + NamespaceDef *nd; + for (nli.toFirst();(nd=nli.current());++nli) + { + nd->combineUsingRelations(); + } + for (nli.toFirst();(nd=nli.current());++nli) + { + // add used namespaces of namespace nd to this namespace + if (nd->getUsedNamespaces()) + { + NamespaceSDict::Iterator unli(*nd->getUsedNamespaces()); + NamespaceDef *und; + for (unli.toFirst();(und=unli.current());++unli) + { + //printf("Adding namespace %s to the using list of %s\n",und->qualifiedName().data(),qualifiedName().data()); + addUsingDirective(und); + } + } + // add used classes of namespace nd to this namespace + if (nd->getUsedClasses()) + { + SDict::Iterator cli(*nd->getUsedClasses()); + Definition *ucd; + for (cli.toFirst();(ucd=cli.current());++cli) + { + //printf("Adding class %s to the using list of %s\n",cd->qualifiedName().data(),qualifiedName().data()); + addUsingDeclaration(ucd); + } + } + } + } +} + +bool NamespaceSDict::declVisible() const +{ + SDict::Iterator ni(*this); + NamespaceDef *nd; + for (ni.toFirst();(nd=ni.current());++ni) + { + if (nd->isLinkable()) + { + return TRUE; + } + } + return FALSE; +} + +void NamespaceSDict::writeDeclaration(OutputList &ol,const char *title,bool localName) +{ + + + if (count()==0) return; // no namespaces in the list + + if (Config_getBool("OPTIMIZE_OUTPUT_VHDL")) return; + + + SDict::Iterator ni(*this); + NamespaceDef *nd; + bool found=FALSE; + for (ni.toFirst();(nd=ni.current()) && !found;++ni) + { + if (nd->isLinkable()) found=TRUE; + } + if (!found) return; // no linkable namespaces in the list + + // write list of namespaces + ol.startMemberHeader("namespaces"); + //bool javaOpt = Config_getBool("OPTIMIZE_OUTPUT_JAVA"); + //bool fortranOpt = Config_getBool("OPTIMIZE_FOR_FORTRAN"); + ol.parseText(title); + ol.endMemberHeader(); + ol.startMemberList(); + for (ni.toFirst();(nd=ni.current());++ni) + { + if (nd->isLinkable()) + { + SrcLangExt lang = nd->getLanguage(); + ol.startMemberItem(nd->getOutputFileBase(),0); + if (lang==SrcLangExt_Java || lang==SrcLangExt_CSharp) + { + ol.docify("package "); + } + else if (lang==SrcLangExt_Fortran) + { + ol.docify("module "); + } + else + { + ol.docify("namespace "); + } + ol.insertMemberAlign(); + QCString name; + if (localName) + { + name = nd->localName(); + } + else + { + name = nd->displayName(); + } + ol.writeObjectLink(nd->getReference(),nd->getOutputFileBase(),0,name); + if (!Config_getString("GENERATE_TAGFILE").isEmpty() && !nd->isReference()) + { + Doxygen::tagFile << " " << convertToXML(nd->name()) << "" << endl; + } + ol.endMemberItem(); + if (!nd->briefDescription().isEmpty() && Config_getBool("BRIEF_MEMBER_DESC")) + { + ol.startMemberDescription(nd->getOutputFileBase()); + ol.parseDoc(nd->briefFile(),nd->briefLine(),nd,0,nd->briefDescription(),FALSE,FALSE,0,TRUE); + ol.endMemberDescription(); + } + } + } + ol.endMemberList(); +} + +MemberList *NamespaceDef::createMemberList(MemberList::ListType lt) +{ + m_memberLists.setAutoDelete(TRUE); + QListIterator mli(m_memberLists); + MemberList *ml; + for (mli.toFirst();(ml=mli.current());++mli) + { + if (ml->listType()==lt) + { + return ml; + } + } + // not found, create a new member list + ml = new MemberList(lt); + m_memberLists.append(ml); + return ml; +} + +void NamespaceDef::addMemberToList(MemberList::ListType lt,MemberDef *md) +{ + static bool sortBriefDocs = Config_getBool("SORT_BRIEF_DOCS"); + static bool sortMemberDocs = Config_getBool("SORT_MEMBER_DOCS"); + MemberList *ml = createMemberList(lt); + ml->setNeedsSorting( + ((ml->listType()&MemberList::declarationLists) && sortBriefDocs) || + ((ml->listType()&MemberList::documentationLists) && sortMemberDocs)); + ml->append(md); + +#if 0 + if (ml->needsSorting()) + ml->inSort(md); + else + ml->append(md); +#endif + + if (ml->listType()&MemberList::declarationLists) md->setSectionList(this,ml); +} + +void NamespaceDef::sortMemberLists() +{ + MemberList *ml = m_memberLists.first(); + while (ml) + { + if (ml->needsSorting()) { ml->sort(); ml->setNeedsSorting(FALSE); } + ml = m_memberLists.next(); + } +} + + + +MemberList *NamespaceDef::getMemberList(MemberList::ListType lt) const +{ + NamespaceDef *that = (NamespaceDef*)this; + MemberList *ml = that->m_memberLists.first(); + while (ml) + { + if (ml->listType()==lt) + { + return ml; + } + ml = that->m_memberLists.next(); + } + return 0; +} + +void NamespaceDef::writeMemberDeclarations(OutputList &ol,MemberList::ListType lt,const QCString &title) +{ + MemberList * ml = getMemberList(lt); + if (ml) ml->writeDeclarations(ol,0,this,0,0,title,0); +} + +void NamespaceDef::writeMemberDocumentation(OutputList &ol,MemberList::ListType lt,const QCString &title) +{ + MemberList * ml = getMemberList(lt); + if (ml) ml->writeDocumentation(ol,displayName(),this,title); +} + + +bool NamespaceDef::isLinkableInProject() const +{ + int i = name().findRev("::"); + if (i==-1) i=0; else i+=2; + static bool extractAnonNs = Config_getBool("EXTRACT_ANON_NSPACES"); + static bool showNamespaces = Config_getBool("SHOW_NAMESPACES"); + if (extractAnonNs && // extract anonymous ns + name().mid(i,20)=="anonymous_namespace{" && // correct prefix + showNamespaces) // not disabled by config + { + return TRUE; + } + return !name().isEmpty() && name().at(i)!='@' && // not anonymous + (hasDocumentation() || getLanguage()==SrcLangExt_CSharp) && // documented + !isReference() && // not an external reference + !isHidden() && // not hidden + !isArtificial() && // or artificial + showNamespaces; // not disabled by config +} + +bool NamespaceDef::isLinkable() const +{ + return isLinkableInProject() || isReference(); +} + +MemberDef * NamespaceDef::getMemberByName(const QCString &n) const +{ + MemberDef *md = 0; + if (m_allMembersDict && !n.isEmpty()) + { + md = m_allMembersDict->find(n); + //printf("%s::m_allMembersDict->find(%s)=%p\n",name().data(),n.data(),md); + } + return md; +} + diff --git a/trunk/src/namespacedef.h b/trunk/src/namespacedef.h new file mode 100644 index 0000000..f1db108 --- /dev/null +++ b/trunk/src/namespacedef.h @@ -0,0 +1,168 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#ifndef NAMESPACEDEF_H +#define NAMESPACEDEF_H + +#include "qtbc.h" +#include +#include +#include "sortdict.h" +#include "definition.h" +#include "memberlist.h" + +class ClassDef; +class ClassList; +class OutputList; +class ClassSDict; +class MemberDef; +class NamespaceList; +class MemberGroupSDict; +class NamespaceSDict; + +class NamespaceDef : public Definition +{ + public: + NamespaceDef(const char *defFileName,int defLine, + const char *name,const char *ref=0, + const char *refFile=0); + ~NamespaceDef(); + DefType definitionType() const { return TypeNamespace; } + QCString getOutputFileBase() const; + QCString anchor() const { return QCString(); } + void insertUsedFile(const char *fname); + + void writeDocumentation(OutputList &ol); + void writeMemberPages(OutputList &ol); + void writeQuickMemberLinks(OutputList &ol,MemberDef *currentMd) const; + + void insertClass(ClassDef *cd); + void insertNamespace(NamespaceDef *nd); + void insertMember(MemberDef *md); + + void computeAnchors(); + int countMembers(); + void addUsingDirective(NamespaceDef *nd); + NamespaceSDict *getUsedNamespaces() const; + void addUsingDeclaration(Definition *def); + SDict *getUsedClasses() const { return usingDeclList; } + void combineUsingRelations(); + QCString displayName() const; + + bool isLinkableInProject() const; + bool isLinkable() const; + void addMembersToMemberGroup(); + void distributeMemberGroupDocumentation(); + void findSectionsInDocumentation(); + void sortMemberLists(); + + virtual Definition *findInnerCompound(const char *name); + void addInnerCompound(Definition *d); + void addListReferences(); + + MemberList *getMemberList(MemberList::ListType lt) const; + const QList &getMemberLists() const { return m_memberLists; } + MemberDef *getMemberByName(const QCString &) const; + + /*! Returns the user defined member groups */ + MemberGroupSDict *getMemberGroupSDict() const { return memberGroupSDict; } + + /*! Returns the classes contained in this namespace */ + ClassSDict *getClassSDict() const { return classSDict; } + + /*! Returns the namespaces contained in this namespace */ + NamespaceSDict *getNamespaceSDict() const { return namespaceSDict; } + + bool visited; + + private: + MemberList *createMemberList(MemberList::ListType lt); + void addMemberToList(MemberList::ListType lt,MemberDef *md); + void writeMemberDeclarations(OutputList &ol,MemberList::ListType lt,const QCString &title); + void writeMemberDocumentation(OutputList &ol,MemberList::ListType lt,const QCString &title); + void writeDetailedDescription(OutputList &ol,const QCString &title); + void writeBriefDescription(OutputList &ol); + void startMemberDeclarations(OutputList &ol); + void endMemberDeclarations(OutputList &ol); + void writeClassDeclarations(OutputList &ol,const QCString &title); + void writeInlineClasses(OutputList &ol); + void writeNamespaceDeclarations(OutputList &ol,const QCString &title); + void writeMemberGroups(OutputList &ol); + void writeAuthorSection(OutputList &ol); + void startMemberDocumentation(OutputList &ol); + void endMemberDocumentation(OutputList &ol); + void writeSummaryLinks(OutputList &ol); + + QCString fileName; + QStrList files; + + NamespaceSDict *usingDirList; + SDict *usingDeclList; + SDict *m_innerCompounds; + + MemberSDict *m_allMembersDict; + QList m_memberLists; + MemberGroupSDict *memberGroupSDict; + ClassSDict *classSDict; + NamespaceSDict *namespaceSDict; + bool m_subGrouping; +}; + +class NamespaceList : public QList +{ + public: + ~NamespaceList() {} + int compareItems(GCI item1,GCI item2) + { + return stricmp(((NamespaceDef *)item1)->name(), + ((NamespaceDef *)item2)->name() + ); + } +}; + +class NamespaceListIterator : public QListIterator +{ + public: + NamespaceListIterator(const NamespaceList &l) : + QListIterator(l) {} +}; + +class NamespaceDict : public QDict +{ + public: + NamespaceDict(int size) : QDict(size) {} + ~NamespaceDict() {} +}; + +class NamespaceSDict : public SDict +{ + public: + NamespaceSDict(int size=17) : SDict(size) {} + ~NamespaceSDict() {} + int compareItems(GCI item1,GCI item2) + { + return stricmp(((NamespaceDef *)item1)->name(), + ((NamespaceDef *)item2)->name() + ); + } + void writeDeclaration(OutputList &ol,const char *title,bool localName=FALSE); + bool declVisible() const; +}; + + + +#endif diff --git a/trunk/src/navtree.css b/trunk/src/navtree.css new file mode 100644 index 0000000..2166b6f --- /dev/null +++ b/trunk/src/navtree.css @@ -0,0 +1,127 @@ +#nav-tree .children_ul { + margin:0; + padding:4px; +} + +#nav-tree ul { + list-style:none outside none; + margin:0px; + padding:0px; +} + +#nav-tree li { + white-space:nowrap; + margin:0px; + padding:0px; +} + +#nav-tree .plus { + margin:0px; +} + +#nav-tree .selected { + background-image: url('tab_a.png'); + background-repeat:repeat-x; + color: #fff; + text-shadow: 0px 1px 1px rgba(0, 0, 0, 1.0); +} + +#nav-tree img { + margin:0px; + padding:0px; + border:0px; + vertical-align: middle; +} + +#nav-tree a { + text-decoration:none; + padding:0px; + margin:0px; + outline:none; +} + +#nav-tree .label { + margin:0px; + padding:0px; +} + +#nav-tree .label a { + padding:2px; +} + +#nav-tree .selected a { + text-decoration:none; + padding:2px; + margin:0px; + color:#fff; +} + +#nav-tree .children_ul { + margin:0px; + padding:0px; +} + +#nav-tree .item { + margin:0px; + padding:0px; +} + +#nav-tree { + padding: 0px 0px; + background-color: #FAFAFF; + font-size:14px; + overflow:auto; +} + +#doc-content { + overflow:auto; + display:block; + padding:0px; + margin:0px; +} + +#side-nav { + padding:0 6px 0 0; + margin: 0px; + display:block; + position: absolute; + left: 0px; + width: 300px; +} + +.ui-resizable .ui-resizable-handle { + display:block; +} + +.ui-resizable-e { + background:url("ftv2splitbar.png") repeat scroll right center transparent; + cursor:e-resize; + height:100%; + right:0; + top:0; + width:6px; +} + +.ui-resizable-handle { + display:none; + font-size:0.1px; + position:absolute; + z-index:1; +} + +#nav-tree-contents { + margin: 6px 0px 0px 0px; +} + +#nav-tree { + background-image:url('nav_h.png'); + background-repeat:repeat-x; + background-color: ##FA; +} + +@media print +{ + #nav-tree { display: none; } + div.ui-resizable-handle { display: none; position: relative; } +} + diff --git a/trunk/src/navtree.js b/trunk/src/navtree.js new file mode 100644 index 0000000..cff8c10 --- /dev/null +++ b/trunk/src/navtree.js @@ -0,0 +1,355 @@ +function getData(varName) +{ + var i = varName.lastIndexOf('/'); + var n = i>=0 ? varName.substring(i+1) : varName; + return eval(n); +} + +function stripPath(uri) +{ + return uri.substring(uri.lastIndexOf('/')+1); +} + +function getScript(scriptName,func,show) +{ + var head = document.getElementsByTagName("head")[0]; + var script = document.createElement('script'); + script.id = scriptName; + script.type = 'text/javascript'; + script.onload = func; + script.src = scriptName+'.js'; + script.onreadystatechange = function() { + if (script.readyState=='complete' || script.readyState=='loaded') { + func(); if (show) showRoot(); + } + }; + head.appendChild(script); +} + +function createIndent(o,domNode,node,level) +{ + if (node.parentNode && node.parentNode.parentNode) { + createIndent(o,domNode,node.parentNode,level+1); + } + var imgNode = document.createElement("img"); + imgNode.width = 16; + imgNode.height = 22; + if (level==0 && node.childrenData) { + node.plus_img = imgNode; + node.expandToggle = document.createElement("a"); + node.expandToggle.href = "javascript:void(0)"; + node.expandToggle.onclick = function() { + if (node.expanded) { + $(node.getChildrenUL()).slideUp("fast"); + if (node.isLast) { + node.plus_img.src = node.relpath+"ftv2plastnode.png"; + } else { + node.plus_img.src = node.relpath+"ftv2pnode.png"; + } + node.expanded = false; + } else { + expandNode(o, node, false, false); + } + } + node.expandToggle.appendChild(imgNode); + domNode.appendChild(node.expandToggle); + } else { + domNode.appendChild(imgNode); + } + if (level==0) { + if (node.isLast) { + if (node.childrenData) { + imgNode.src = node.relpath+"ftv2plastnode.png"; + } else { + imgNode.src = node.relpath+"ftv2lastnode.png"; + domNode.appendChild(imgNode); + } + } else { + if (node.childrenData) { + imgNode.src = node.relpath+"ftv2pnode.png"; + } else { + imgNode.src = node.relpath+"ftv2node.png"; + domNode.appendChild(imgNode); + } + } + } else { + if (node.isLast) { + imgNode.src = node.relpath+"ftv2blank.png"; + } else { + imgNode.src = node.relpath+"ftv2vertline.png"; + } + } + imgNode.border = "0"; +} + +function newNode(o, po, text, link, childrenData, lastNode) +{ + var node = new Object(); + node.children = Array(); + node.childrenData = childrenData; + node.depth = po.depth + 1; + node.relpath = po.relpath; + node.isLast = lastNode; + + node.li = document.createElement("li"); + po.getChildrenUL().appendChild(node.li); + node.parentNode = po; + + node.itemDiv = document.createElement("div"); + node.itemDiv.className = "item"; + + node.labelSpan = document.createElement("span"); + node.labelSpan.className = "label"; + + createIndent(o,node.itemDiv,node,0); + node.itemDiv.appendChild(node.labelSpan); + node.li.appendChild(node.itemDiv); + + var a = document.createElement("a"); + node.labelSpan.appendChild(a); + node.label = document.createTextNode(text); + node.expanded = false; + a.appendChild(node.label); + if (link) { + var url; + if (link.substring(0,1)=='^') { + url = link.substring(1); + link = url; + } else { + url = node.relpath+link; + } + a.className = stripPath(link.replace('#',':')); + if (link.indexOf('#')!=-1) { + var aname = '#'+link.split('#')[1]; + var srcPage = stripPath($(location).attr('pathname')); + var targetPage = stripPath(link.split('#')[0]); + a.href = srcPage!=targetPage ? url : '#'; + a.onclick = function(){ + if (!$(a).parent().parent().hasClass('selected')) + { + $('.item').removeClass('selected'); + $('.item').removeAttr('id'); + $(a).parent().parent().addClass('selected'); + $(a).parent().parent().attr('id','selected'); + } + var pos, anchor = $(aname), docContent = $('#doc-content'); + if (anchor.parent().attr('class')=='memItemLeft') { + pos = anchor.parent().position().top; + } else { + pos = anchor.position().top; + } + var dist = Math.abs(Math.min( + pos-docContent.offset().top, + docContent[0].scrollHeight- + docContent.height()-docContent.scrollTop())); + docContent.animate({ + scrollTop: pos + docContent.scrollTop() - docContent.offset().top + },Math.max(50,Math.min(500,dist)),function(){ + window.location.replace(aname); + }); + }; + } else { + a.href = url; + } + } else { + if (childrenData != null) + { + a.className = "nolink"; + a.href = "javascript:void(0)"; + a.onclick = node.expandToggle.onclick; + } + } + + node.childrenUL = null; + node.getChildrenUL = function() { + if (!node.childrenUL) { + node.childrenUL = document.createElement("ul"); + node.childrenUL.className = "children_ul"; + node.childrenUL.style.display = "none"; + node.li.appendChild(node.childrenUL); + } + return node.childrenUL; + }; + + return node; +} + +function showRoot() +{ + var headerHeight = $("#top").height(); + var footerHeight = $("#nav-path").height(); + var windowHeight = $(window).height() - headerHeight - footerHeight; + (function (){ // retry until we can scroll to the selected item + try { + navtree.scrollTo('#selected',0,{offset:-windowHeight/2}); + } catch (err) { + setTimeout(arguments.callee, 0); + } + })(); +} + +function expandNode(o, node, imm, showRoot) +{ + if (node.childrenData && !node.expanded) { + if (typeof(node.childrenData)==='string') { + var varName = node.childrenData; + getScript(node.relpath+varName,function(){ + node.childrenData = getData(varName); + expandNode(o, node, imm, showRoot); + }, showRoot); + } else { + if (!node.childrenVisited) { + getNode(o, node); + } if (imm) { + $(node.getChildrenUL()).show(); + } else { + $(node.getChildrenUL()).slideDown("fast"); + } + if (node.isLast) { + node.plus_img.src = node.relpath+"ftv2mlastnode.png"; + } else { + node.plus_img.src = node.relpath+"ftv2mnode.png"; + } + node.expanded = true; + } + } +} + +function highlightAnchor() +{ + var anchor = $($(location).attr('hash')); + if (anchor.parent().attr('class')=='memItemLeft'){ + var rows = $('.memberdecls tr[class$=\""'+ + window.location.hash.substring(1)+'"\"]').children(); + rows.effect('highlight',{},1500); + } else if (anchor.parent().is(":header")) { + anchor.parent().effect('highlight',{},1500); + } else { + var targetDiv = anchor.next(); + $(targetDiv).children('.memproto,.memdoc').effect("highlight",{},1500); + } +} + +function showNode(o, node, index) +{ + if (node.childrenData /*&& !node.expanded*/) { + if (typeof(node.childrenData)==='string') { + var varName = node.childrenData; + getScript(node.relpath+varName,function(){ + node.childrenData = getData(varName); + showNode(o,node,index); + },true); + } else { + if (!node.childrenVisited) { + getNode(o, node); + } + $(node.getChildrenUL()).show(); + if (node.isLast) { + node.plus_img.src = node.relpath+"ftv2mlastnode.png"; + } else { + node.plus_img.src = node.relpath+"ftv2mnode.png"; + } + node.expanded = true; + var n = node.children[o.breadcrumbs[index]]; + if (index+11){ + var a; + if ($(location).attr('hash')){ + var clslink=stripPath($(location).attr('pathname'))+':'+ + $(location).attr('hash').substring(1); + a=$('.item a[class$=\""'+clslink+'"\"]'); + } + if (a==null || !$(a).parent().parent().hasClass('selected')){ + $('.item').removeClass('selected'); + $('.item').removeAttr('id'); + } + var link=stripPath($(location).attr('pathname')); + navTo(o,link,$(location).attr('hash'),relpath); + } + }) + + $(window).load(showRoot); +} + diff --git a/trunk/src/navtree_css.h b/trunk/src/navtree_css.h new file mode 100644 index 0000000..82955e2 --- /dev/null +++ b/trunk/src/navtree_css.h @@ -0,0 +1,127 @@ +"#nav-tree .children_ul {\n" +" margin:0;\n" +" padding:4px;\n" +"}\n" +"\n" +"#nav-tree ul {\n" +" list-style:none outside none;\n" +" margin:0px;\n" +" padding:0px;\n" +"}\n" +"\n" +"#nav-tree li {\n" +" white-space:nowrap;\n" +" margin:0px;\n" +" padding:0px;\n" +"}\n" +"\n" +"#nav-tree .plus {\n" +" margin:0px;\n" +"}\n" +"\n" +"#nav-tree .selected {\n" +" background-image: url('tab_a.png');\n" +" background-repeat:repeat-x;\n" +" color: #fff;\n" +" text-shadow: 0px 1px 1px rgba(0, 0, 0, 1.0);\n" +"}\n" +"\n" +"#nav-tree img {\n" +" margin:0px;\n" +" padding:0px;\n" +" border:0px;\n" +" vertical-align: middle;\n" +"}\n" +"\n" +"#nav-tree a {\n" +" text-decoration:none;\n" +" padding:0px;\n" +" margin:0px;\n" +" outline:none;\n" +"}\n" +"\n" +"#nav-tree .label {\n" +" margin:0px;\n" +" padding:0px;\n" +"}\n" +"\n" +"#nav-tree .label a {\n" +" padding:2px;\n" +"}\n" +"\n" +"#nav-tree .selected a {\n" +" text-decoration:none;\n" +" padding:2px;\n" +" margin:0px;\n" +" color:#fff;\n" +"}\n" +"\n" +"#nav-tree .children_ul {\n" +" margin:0px;\n" +" padding:0px;\n" +"}\n" +"\n" +"#nav-tree .item {\n" +" margin:0px;\n" +" padding:0px;\n" +"}\n" +"\n" +"#nav-tree {\n" +" padding: 0px 0px;\n" +" background-color: #FAFAFF; \n" +" font-size:14px;\n" +" overflow:auto;\n" +"}\n" +"\n" +"#doc-content {\n" +" overflow:auto;\n" +" display:block;\n" +" padding:0px;\n" +" margin:0px;\n" +"}\n" +"\n" +"#side-nav {\n" +" padding:0 6px 0 0;\n" +" margin: 0px;\n" +" display:block;\n" +" position: absolute;\n" +" left: 0px;\n" +" width: 300px;\n" +"}\n" +"\n" +".ui-resizable .ui-resizable-handle {\n" +" display:block;\n" +"}\n" +"\n" +".ui-resizable-e {\n" +" background:url(\"ftv2splitbar.png\") repeat scroll right center transparent;\n" +" cursor:e-resize;\n" +" height:100%;\n" +" right:0;\n" +" top:0;\n" +" width:6px;\n" +"}\n" +"\n" +".ui-resizable-handle {\n" +" display:none;\n" +" font-size:0.1px;\n" +" position:absolute;\n" +" z-index:1;\n" +"}\n" +"\n" +"#nav-tree-contents {\n" +" margin: 6px 0px 0px 0px;\n" +"}\n" +"\n" +"#nav-tree {\n" +" background-image:url('nav_h.png');\n" +" background-repeat:repeat-x;\n" +" background-color: ##FA;\n" +"}\n" +"\n" +"@media print\n" +"{\n" +" #nav-tree { display: none; }\n" +" div.ui-resizable-handle { display: none; position: relative; }\n" +"}\n" +"\n" diff --git a/trunk/src/navtree_js.h b/trunk/src/navtree_js.h new file mode 100644 index 0000000..3eccef6 --- /dev/null +++ b/trunk/src/navtree_js.h @@ -0,0 +1,355 @@ +"function getData(varName)\n" +"{\n" +" var i = varName.lastIndexOf('/');\n" +" var n = i>=0 ? varName.substring(i+1) : varName;\n" +" return eval(n);\n" +"}\n" +"\n" +"function stripPath(uri)\n" +"{\n" +" return uri.substring(uri.lastIndexOf('/')+1);\n" +"}\n" +"\n" +"function getScript(scriptName,func,show)\n" +"{\n" +" var head = document.getElementsByTagName(\"head\")[0]; \n" +" var script = document.createElement('script');\n" +" script.id = scriptName;\n" +" script.type = 'text/javascript';\n" +" script.onload = func; \n" +" script.src = scriptName+'.js'; \n" +" script.onreadystatechange = function() {\n" +" if (script.readyState=='complete' || script.readyState=='loaded') { \n" +" func(); if (show) showRoot(); \n" +" }\n" +" };\n" +" head.appendChild(script); \n" +"}\n" +"\n" +"function createIndent(o,domNode,node,level)\n" +"{\n" +" if (node.parentNode && node.parentNode.parentNode) {\n" +" createIndent(o,domNode,node.parentNode,level+1);\n" +" }\n" +" var imgNode = document.createElement(\"img\");\n" +" imgNode.width = 16;\n" +" imgNode.height = 22;\n" +" if (level==0 && node.childrenData) {\n" +" node.plus_img = imgNode;\n" +" node.expandToggle = document.createElement(\"a\");\n" +" node.expandToggle.href = \"javascript:void(0)\";\n" +" node.expandToggle.onclick = function() {\n" +" if (node.expanded) {\n" +" $(node.getChildrenUL()).slideUp(\"fast\");\n" +" if (node.isLast) {\n" +" node.plus_img.src = node.relpath+\"ftv2plastnode.png\";\n" +" } else {\n" +" node.plus_img.src = node.relpath+\"ftv2pnode.png\";\n" +" }\n" +" node.expanded = false;\n" +" } else {\n" +" expandNode(o, node, false, false);\n" +" }\n" +" }\n" +" node.expandToggle.appendChild(imgNode);\n" +" domNode.appendChild(node.expandToggle);\n" +" } else {\n" +" domNode.appendChild(imgNode);\n" +" }\n" +" if (level==0) {\n" +" if (node.isLast) {\n" +" if (node.childrenData) {\n" +" imgNode.src = node.relpath+\"ftv2plastnode.png\";\n" +" } else {\n" +" imgNode.src = node.relpath+\"ftv2lastnode.png\";\n" +" domNode.appendChild(imgNode);\n" +" }\n" +" } else {\n" +" if (node.childrenData) {\n" +" imgNode.src = node.relpath+\"ftv2pnode.png\";\n" +" } else {\n" +" imgNode.src = node.relpath+\"ftv2node.png\";\n" +" domNode.appendChild(imgNode);\n" +" }\n" +" }\n" +" } else {\n" +" if (node.isLast) {\n" +" imgNode.src = node.relpath+\"ftv2blank.png\";\n" +" } else {\n" +" imgNode.src = node.relpath+\"ftv2vertline.png\";\n" +" }\n" +" }\n" +" imgNode.border = \"0\";\n" +"}\n" +"\n" +"function newNode(o, po, text, link, childrenData, lastNode)\n" +"{\n" +" var node = new Object();\n" +" node.children = Array();\n" +" node.childrenData = childrenData;\n" +" node.depth = po.depth + 1;\n" +" node.relpath = po.relpath;\n" +" node.isLast = lastNode;\n" +"\n" +" node.li = document.createElement(\"li\");\n" +" po.getChildrenUL().appendChild(node.li);\n" +" node.parentNode = po;\n" +"\n" +" node.itemDiv = document.createElement(\"div\");\n" +" node.itemDiv.className = \"item\";\n" +"\n" +" node.labelSpan = document.createElement(\"span\");\n" +" node.labelSpan.className = \"label\";\n" +"\n" +" createIndent(o,node.itemDiv,node,0);\n" +" node.itemDiv.appendChild(node.labelSpan);\n" +" node.li.appendChild(node.itemDiv);\n" +"\n" +" var a = document.createElement(\"a\");\n" +" node.labelSpan.appendChild(a);\n" +" node.label = document.createTextNode(text);\n" +" node.expanded = false;\n" +" a.appendChild(node.label);\n" +" if (link) {\n" +" var url;\n" +" if (link.substring(0,1)=='^') {\n" +" url = link.substring(1);\n" +" link = url;\n" +" } else {\n" +" url = node.relpath+link;\n" +" }\n" +" a.className = stripPath(link.replace('#',':'));\n" +" if (link.indexOf('#')!=-1) {\n" +" var aname = '#'+link.split('#')[1];\n" +" var srcPage = stripPath($(location).attr('pathname'));\n" +" var targetPage = stripPath(link.split('#')[0]);\n" +" a.href = srcPage!=targetPage ? url : '#';\n" +" a.onclick = function(){\n" +" if (!$(a).parent().parent().hasClass('selected'))\n" +" {\n" +" $('.item').removeClass('selected');\n" +" $('.item').removeAttr('id');\n" +" $(a).parent().parent().addClass('selected');\n" +" $(a).parent().parent().attr('id','selected');\n" +" }\n" +" var pos, anchor = $(aname), docContent = $('#doc-content');\n" +" if (anchor.parent().attr('class')=='memItemLeft') {\n" +" pos = anchor.parent().position().top;\n" +" } else {\n" +" pos = anchor.position().top;\n" +" }\n" +" var dist = Math.abs(Math.min(\n" +" pos-docContent.offset().top,\n" +" docContent[0].scrollHeight-\n" +" docContent.height()-docContent.scrollTop()));\n" +" docContent.animate({\n" +" scrollTop: pos + docContent.scrollTop() - docContent.offset().top\n" +" },Math.max(50,Math.min(500,dist)),function(){\n" +" window.location.replace(aname);\n" +" });\n" +" };\n" +" } else {\n" +" a.href = url;\n" +" }\n" +" } else {\n" +" if (childrenData != null) \n" +" {\n" +" a.className = \"nolink\";\n" +" a.href = \"javascript:void(0)\";\n" +" a.onclick = node.expandToggle.onclick;\n" +" }\n" +" }\n" +"\n" +" node.childrenUL = null;\n" +" node.getChildrenUL = function() {\n" +" if (!node.childrenUL) {\n" +" node.childrenUL = document.createElement(\"ul\");\n" +" node.childrenUL.className = \"children_ul\";\n" +" node.childrenUL.style.display = \"none\";\n" +" node.li.appendChild(node.childrenUL);\n" +" }\n" +" return node.childrenUL;\n" +" };\n" +"\n" +" return node;\n" +"}\n" +"\n" +"function showRoot()\n" +"{\n" +" var headerHeight = $(\"#top\").height();\n" +" var footerHeight = $(\"#nav-path\").height();\n" +" var windowHeight = $(window).height() - headerHeight - footerHeight;\n" +" (function (){ // retry until we can scroll to the selected item\n" +" try {\n" +" navtree.scrollTo('#selected',0,{offset:-windowHeight/2});\n" +" } catch (err) {\n" +" setTimeout(arguments.callee, 0);\n" +" }\n" +" })();\n" +"}\n" +"\n" +"function expandNode(o, node, imm, showRoot)\n" +"{\n" +" if (node.childrenData && !node.expanded) {\n" +" if (typeof(node.childrenData)==='string') {\n" +" var varName = node.childrenData;\n" +" getScript(node.relpath+varName,function(){\n" +" node.childrenData = getData(varName);\n" +" expandNode(o, node, imm, showRoot);\n" +" }, showRoot);\n" +" } else {\n" +" if (!node.childrenVisited) {\n" +" getNode(o, node);\n" +" } if (imm) {\n" +" $(node.getChildrenUL()).show();\n" +" } else {\n" +" $(node.getChildrenUL()).slideDown(\"fast\");\n" +" }\n" +" if (node.isLast) {\n" +" node.plus_img.src = node.relpath+\"ftv2mlastnode.png\";\n" +" } else {\n" +" node.plus_img.src = node.relpath+\"ftv2mnode.png\";\n" +" }\n" +" node.expanded = true;\n" +" }\n" +" }\n" +"}\n" +"\n" +"function highlightAnchor()\n" +"{\n" +" var anchor = $($(location).attr('hash'));\n" +" if (anchor.parent().attr('class')=='memItemLeft'){\n" +" var rows = $('.memberdecls tr[class$=\\\"\"'+\n" +" window.location.hash.substring(1)+'\"\\\"]').children();\n" +" rows.effect('highlight',{},1500);\n" +" } else if (anchor.parent().is(\":header\")) {\n" +" anchor.parent().effect('highlight',{},1500);\n" +" } else {\n" +" var targetDiv = anchor.next();\n" +" $(targetDiv).children('.memproto,.memdoc').effect(\"highlight\",{},1500);\n" +" }\n" +"}\n" +"\n" +"function showNode(o, node, index)\n" +"{\n" +" if (node.childrenData /*&& !node.expanded*/) {\n" +" if (typeof(node.childrenData)==='string') {\n" +" var varName = node.childrenData;\n" +" getScript(node.relpath+varName,function(){\n" +" node.childrenData = getData(varName);\n" +" showNode(o,node,index);\n" +" },true);\n" +" } else {\n" +" if (!node.childrenVisited) {\n" +" getNode(o, node);\n" +" }\n" +" $(node.getChildrenUL()).show();\n" +" if (node.isLast) {\n" +" node.plus_img.src = node.relpath+\"ftv2mlastnode.png\";\n" +" } else {\n" +" node.plus_img.src = node.relpath+\"ftv2mnode.png\";\n" +" }\n" +" node.expanded = true;\n" +" var n = node.children[o.breadcrumbs[index]];\n" +" if (index+11){\n" +" var a;\n" +" if ($(location).attr('hash')){\n" +" var clslink=stripPath($(location).attr('pathname'))+':'+\n" +" $(location).attr('hash').substring(1);\n" +" a=$('.item a[class$=\\\"\"'+clslink+'\"\\\"]');\n" +" }\n" +" if (a==null || !$(a).parent().parent().hasClass('selected')){\n" +" $('.item').removeClass('selected');\n" +" $('.item').removeAttr('id');\n" +" }\n" +" var link=stripPath($(location).attr('pathname'));\n" +" navTo(o,link,$(location).attr('hash'),relpath);\n" +" }\n" +" })\n" +"\n" +" $(window).load(showRoot);\n" +"}\n" +"\n" diff --git a/trunk/src/objcache.cpp b/trunk/src/objcache.cpp new file mode 100644 index 0000000..a08d649 --- /dev/null +++ b/trunk/src/objcache.cpp @@ -0,0 +1,326 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#include +#include +#include +#include "objcache.h" + +//---------------------------------------------------------------------- + +ObjCache::ObjCache(unsigned int logSize) + : m_head(-1), m_tail(-1), //m_numEntries(0), + m_size(1<index); + moveToFront(hnode->index); + m_hits++; + } + else // object not in the cache. + { + void *lruObj=0; + if (m_freeCacheNodes!=-1) // cache not full -> add element to the cache + { + // remove element from free list + int index = m_freeCacheNodes; + m_freeCacheNodes = m_cache[index].next; + + // add to head of the list + if (m_tail==-1) + { + m_tail = index; + } + m_cache[index].prev = -1; + m_cache[index].next = m_head; + if (m_head!=-1) + { + m_cache[m_head].prev = index; + } + m_head = index; + m_count++; + } + else // cache full -> replace element in the cache + { + //printf("Cache full!\n"); + lruObj = m_cache[m_tail].obj; + hashRemove(lruObj); + moveToFront(m_tail); // m_tail indexes the emptied element, which becomes m_head + } + //printf("numEntries=%d size=%d\n",m_numEntries,m_size); + m_cache[m_head].obj = obj; + hnode = hashInsert(obj); + hnode->index = m_head; + *victim = lruObj; + m_misses++; + } + return m_head; +} + +void ObjCache::del(int index) +{ + assert(index!=-1); + assert(m_cache[index].obj!=0); + hashRemove(m_cache[index].obj); + moveToFront(index); + m_head = m_cache[index].next; + if (m_head==-1) + m_tail=-1; + else + m_cache[m_head].prev=-1; + m_cache[index].obj=0; + m_cache[index].prev=-1; + m_cache[index].next = m_freeCacheNodes; + m_freeCacheNodes = index; + m_count--; +} + +#ifdef CACHE_DEBUG +#define cache_debug_printf printf +void ObjCache::printLRU() +{ + cache_debug_printf("MRU->LRU: "); + int index = m_head; + while (index!=-1) + { + cache_debug_printf("%d=%p ",index,m_cache[index].obj); + index = m_cache[index].next; + } + cache_debug_printf("\n"); + + cache_debug_printf("LRU->MRU: "); + index = m_tail; + while (index!=-1) + { + cache_debug_printf("%d=%p ",index,m_cache[index].obj); + index = m_cache[index].prev; + } + cache_debug_printf("\n"); +} +#endif + +#ifdef CACHE_STATS +#define cache_stats_printf printf +void ObjCache::printStats() +{ + cache_stats_printf("ObjCache: hits=%d misses=%d hit ratio=%f\n",m_hits,m_misses,m_hits*100.0/(m_hits+m_misses)); +} +#endif + +void ObjCache::moveToFront(int index) +{ + int prev,next; + if (m_head!=index) + { + next = m_cache[index].next; + prev = m_cache[index].prev; + + // de-chain node at index + m_cache[prev].next = next; + if (next!=-1) m_cache[next].prev = prev; else m_tail = prev; + + // add to head + m_cache[index].prev = -1; + m_cache[index].next = m_head; + m_cache[m_head].prev = index; + m_head = index; + } +} + +unsigned int ObjCache::hash(void *addr) +{ + static bool isPtr64 = sizeof(addr)==8; + if (isPtr64) + { + uint64 key = (uint64)addr; + // Thomas Wang's 64 bit Mix Function + key += ~(key << 32); + key ^= (key >> 22); + key += ~(key << 13); + key ^= (key >> 8); + key += (key << 3); + key ^= (key >> 15); + key += ~(key << 27); + key ^= (key >> 31); + return key & (m_size-1); + } + else + { + // Thomas Wang's 32 bit Mix Function + unsigned long key = (unsigned long)addr; + key += ~(key << 15); + key ^= (key >> 10); + key += (key << 3); + key ^= (key >> 6); + key += ~(key << 11); + key ^= (key >> 16); + return key & (m_size-1); + } +} + +ObjCache::HashNode *ObjCache::hashFind(void *obj) +{ + HashNode *node = 0; + int index = m_hash[hash(obj)].head; + //printf("hashFind: obj=%p index=%d\n",obj,index); + while (index!=-1 && + m_hash[index].obj!=obj + ) // search for right object in the list + { + index = m_hash[index].nextHash; + } + // found the obj at index, so it is in the cache! + if (index!=-1) + { + node = &m_hash[index]; + } + return node; +} + +ObjCache::HashNode *ObjCache::hashInsert(void *obj) +{ + int index = hash(obj); + //printf("Inserting %p index=%d\n",obj,index); + + // remove element from empty list + int newElement = m_freeHashNodes; + assert(newElement!=-1); + m_freeHashNodes = m_hash[m_freeHashNodes].nextHash; + + if (m_hash[index].head!=-1) // hash collision -> goto end of the list + { + index = m_hash[index].head; + while (m_hash[index].nextHash!=-1) + { + index = m_hash[index].nextHash; + } + // add to end of the list + m_hash[index].nextHash = newElement; + } + else // first element in the hash list + { + m_hash[index].head = newElement; + } + // add to the end of the list + m_hash[newElement].nextHash = -1; + m_hash[newElement].obj = obj; + return &m_hash[newElement]; +} + +void ObjCache::hashRemove(void *obj) +{ + int index = hash(obj); + + // find element + int curIndex = m_hash[index].head; + int prevIndex=-1; + while (m_hash[curIndex].obj!=obj) + { + prevIndex = curIndex; + curIndex = m_hash[curIndex].nextHash; + } + + if (prevIndex==-1) // remove from start + { + m_hash[index].head = m_hash[curIndex].nextHash; + } + else // remove in the middle + { + m_hash[prevIndex].nextHash = m_hash[curIndex].nextHash; + } + + // add curIndex element to empty list + m_hash[curIndex].nextHash = m_freeHashNodes; + m_hash[curIndex].index = -1; + m_hash[curIndex].obj = 0; + m_freeHashNodes = curIndex; +} + +#ifdef CACHE_TEST +int main() +{ + int i; + struct obj + { + obj() : handle(-1) {} + int handle; + }; + obj *objs = new obj[100]; + ObjCache c(3); + for (i=0;i<32;i++) + { + int objId=(i%3)+(i>>2)*4; + printf("------- use(%d=%p)--------\n",objId,&objs[objId]); +#ifdef CACHE_DEBUG + c.printLRU(); +#endif + obj *victim=0; + if (objs[objId].handle==-1) + { + objs[objId].handle = c.add(&objs[objId],(void**)&victim); + if (victim) victim->handle=-1; + } + else + { + c.use(objs[objId].handle); + } + printf("i=%d objId=%d using %p victim=%p\n",i,objId,&objs[objId],victim); + } + for (i=0;i<100;i++) + { + if (objs[i].handle!=-1) + { + printf("------ del objId=%d handle=%d ------\n",i,objs[i].handle); + c.del(objs[i].handle); + objs[i].handle=-1; +#ifdef CACHE_DEBUG + c.printLRU(); +#endif + } + } + c.printStats(); + return 0; +} +#endif diff --git a/trunk/src/objcache.h b/trunk/src/objcache.h new file mode 100644 index 0000000..71e7178 --- /dev/null +++ b/trunk/src/objcache.h @@ -0,0 +1,127 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#ifndef OBJCACHE_H +#define OBJCACHE_H + +//#define CACHE_TEST +//#define CACHE_DEBUG +#define CACHE_STATS + +/** @brief Cache for objects. + * + * This cache is used to decide which objects should remain in + * memory. It uses a least recently used policy (LRU) to decide + * which object should make room for a new object when the cache + * is full. An object should be added using add(), and then use() + * should be called when the object is used. + */ +class ObjCache +{ + private: + struct CacheNode + { + CacheNode() : next(-1), prev(-1), obj(0) {} + int next; + int prev; + void *obj; + }; + struct HashNode + { + HashNode() : head(-1), nextHash(-1), index(-1), obj(0) {} + int head; + int nextHash; + int index; + void *obj; + }; + + public: + /*! Creates the cache. The number of elements in the cache is 2 to + * the power of \a logSize. + */ + ObjCache(unsigned int logSize); + + /*! Deletes the cache and free all internal data-structures used. */ + ~ObjCache(); + + /*! Adds \a obj to the cache. When victim is not null, this object is + * removed from the cache to make room for \a obj. + * Returns a handle to the object, which can be used by the use() + * function, each time the object is used. + */ + int add(void *obj,void **victim); + + /*! Indicates that this object is used. This will move the object + * to the front of the internal LRU list to make sure it is removed last. + * The parameter \a handle is returned when called add(). + */ + void use(int handle) + { + if (handle==m_lastHandle) return; + m_lastHandle = handle; + m_hits++; + moveToFront(handle); + } + + /*! Removes the item identified by \a handle from the cache. + * @see add() + */ + void del(int handle); + + /*! Debug function. Prints the LRU list */ + void printLRU(); + /*! Print miss/hits statistics */ + void printStats(); + + /*! total size of the cache */ + int size() const { return m_size; } + + /*! number of elements in the cache */ + int count() const { return m_count; } + + int hits() const + { + return m_hits; + } + int misses() const + { + return m_misses; + } + + + private: + void moveToFront(int index); + unsigned int hash(void *addr); + HashNode *hashFind(void *obj); + HashNode *hashInsert(void *obj); + void hashRemove(void *obj); + + CacheNode *m_cache; + HashNode *m_hash; + int m_head; + int m_tail; + int m_size; + int m_count; + int m_freeHashNodes; + int m_freeCacheNodes; + int m_lastHandle; + int m_misses; + int m_hits; +}; + +#endif // OBJCACHE_H + diff --git a/trunk/src/outputgen.cpp b/trunk/src/outputgen.cpp new file mode 100644 index 0000000..74ba116 --- /dev/null +++ b/trunk/src/outputgen.cpp @@ -0,0 +1,82 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#include + +#include "qtbc.h" +#include "outputgen.h" +#include "message.h" +#include "portable.h" + +OutputGenerator::OutputGenerator() +{ + //printf("OutputGenerator::OutputGenerator()\n"); + file=0; + active=TRUE; + genStack = new QStack; + genStack->setAutoDelete(TRUE); +} + +OutputGenerator::~OutputGenerator() +{ + //printf("OutputGenerator::~OutputGenerator()\n"); + delete file; + delete genStack; +} + +void OutputGenerator::startPlainFile(const char *name) +{ + //printf("startPlainFile(%s)\n",name); + fileName=dir+"/"+name; + file = new QFile(fileName); + if (!file) + { + err("Could not create file object for %s\n",fileName.data()); + exit(1); + } + if (!file->open(IO_WriteOnly)) + { + err("Could not open file %s for writing\n",fileName.data()); + exit(1); + } + t.setDevice(file); +} + +void OutputGenerator::endPlainFile() +{ + t.unsetDevice(); + delete file; + file=0; + fileName.resize(0); +} + +void OutputGenerator::pushGeneratorState() +{ + genStack->push(new bool(isEnabled())); + //printf("%p:pushGeneratorState(%d) enabled=%d\n",this,genStack->count(),isEnabled()); +} + +void OutputGenerator::popGeneratorState() +{ + //printf("%p:popGeneratorState(%d) enabled=%d\n",this,genStack->count(),isEnabled()); + bool *lb = genStack->pop(); + ASSERT(lb!=0); + if (lb==0) return; // for some robustness against superfluous \endhtmlonly commands. + if (*lb) enable(); else disable(); + delete lb; +} + diff --git a/trunk/src/outputgen.h b/trunk/src/outputgen.h new file mode 100644 index 0000000..58d1384 --- /dev/null +++ b/trunk/src/outputgen.h @@ -0,0 +1,494 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#ifndef OUTPUTGEN_H +#define OUTPUTGEN_H + +#include "qtbc.h" +#include "ftextstream.h" +#include +#include +#include +#include "index.h" +#include "section.h" + +class ClassDiagram; +class DotClassGraph; +class DotInclDepGraph; +class DotCallGraph; +class DotDirDeps; +class DotGfxHierarchyTable; +class DotGroupCollaboration; +class DocNode; +class MemberDef; +class GroupDef; +class Definition; + +/*! \brief Output interface for code parser. + */ +class CodeOutputInterface +{ + public: + virtual ~CodeOutputInterface() {} + /*! Writes an ASCII string to the output. This function should keep + * spaces visible, should break lines at a newline and should convert + * tabs to the right number of spaces. + */ + virtual void codify(const char *s) = 0; + + /*! Writes a link to an object in a code fragment. + * \param ref If this is non-zero, the object is to be found in + * an external documentation file. + * \param file The file in which the object is located. + * \param anchor The anchor uniquely identifying the object within + * the file. + * \param name The text to display as a placeholder for the link. + * \param tooltip The tooltip to display when the mouse is on the link. + */ + virtual void writeCodeLink(const char *ref,const char *file, + const char *anchor,const char *name, + const char *tooltip) = 0; + + virtual void writeLineNumber(const char *ref,const char *file, + const char *anchor,int lineNumber) = 0; + virtual void startCodeLine() = 0; + virtual void endCodeLine() = 0; + virtual void startCodeAnchor(const char *label) = 0; + virtual void endCodeAnchor() = 0; + virtual void startFontClass(const char *) = 0; + virtual void endFontClass() = 0; + virtual void writeCodeAnchor(const char *name) = 0; + virtual void linkableSymbol(int line,const char *symName, + Definition *symDef,Definition *context) = 0; +}; + +/*! \brief Base Interface used for generating output outside of the + * comment blocks. + * + * This abstract class is used by output generation functions + * to generate the output for a specific format, + * or a list of formats (see OutputList). This interface + * contains functions that generate fragments of the output. + */ +class BaseOutputDocInterface : public CodeOutputInterface +{ + public: + virtual ~BaseOutputDocInterface() {} + enum ParamListTypes { Param, RetVal, Exception }; + enum SectionTypes { /*See, Return, Author, Version, + Since, Date, Bug, Note, + Warning, Par, Deprecated, Pre, + Post, Invar, Remark, Attention, + Todo, Test, RCS, */ EnumValues, + Examples + }; + + virtual void parseDoc(const char *,int, const char *,MemberDef *, + const QCString &,bool) {} + virtual void parseText(const QCString &) {} + + /*! Start of a bullet list: e.g. \c \ in html. startItemListItem() is + * Used for the bullet items. + */ + virtual void startItemList() = 0; + + /*! Writes a list item for a bullet or enumerated + * list: e.g. \c \ in html + */ + virtual void startItemListItem() = 0; + + /*! Writes a list item for a bullet or enumerated + * list: e.g. \c \ in html + */ + virtual void endItemListItem() = 0; + + /*! Ends a bullet list: e.g. \c \ in html */ + virtual void endItemList() = 0; + + /*! Writes an ASCII string to the output. Converts characters that have + * A special meaning, like \c & in html. + */ + virtual void docify(const char *s) = 0; + + /*! Writes a single ASCII character to the output. Converts characters + * that have a special meaning. + */ + virtual void writeChar(char c) = 0; + + /*! Writes an ASCII string to the output, \e without converting + * special characters. + */ + virtual void writeString(const char *text) = 0; + + /*! Starts a new paragraph */ + //virtual void newParagraph() = 0; + + /*! Starts a new paragraph */ + virtual void startParagraph() = 0; + /*! Ends a paragraph */ + virtual void endParagraph() = 0; + + /*! Writes a link to an object in the documentation. + * \param ref If this is non-zero, the object is to be found in + * an external documentation file. + * \param file The file in which the object is located. + * \param anchor The anchor uniquely identifying the object within + * the file. + * \param name The text to display as a placeholder for the link. + */ + virtual void writeObjectLink(const char *ref,const char *file, + const char *anchor, const char *name) = 0; + + + /*! Starts a (link to an) URL found in the documentation. + * \param url The URL to link to. + */ + virtual void startHtmlLink(const char *url) = 0; + + /*! Ends a link started by startHtmlLink(). + */ + virtual void endHtmlLink() = 0; + + + /*! Changes the text font to bold face. The bold section ends with + * endBold() + */ + virtual void startBold() = 0; + + /*! End a section of text displayed in bold face. */ + virtual void endBold() = 0; + + /*! Changes the text font to fixed size. The section ends with + * endTypewriter() + */ + virtual void startTypewriter() = 0; + + /*! End a section of text displayed in typewriter style. */ + virtual void endTypewriter() = 0; + + /*! Changes the text font to italic. The italic section ends with + * endEmphasis() + */ + virtual void startEmphasis() = 0; + + /*! Ends a section of text displayed in italic. */ + virtual void endEmphasis() = 0; + + /*! Starts a source code fragment. The fragment will be + * fed to the code parser (see code.h) for syntax highlighting + * and cross-referencing. The fragment ends by a call to + * endCodeFragment() + */ + virtual void startCodeFragment() = 0; + + /*! Ends a source code fragment + */ + virtual void endCodeFragment() = 0; + + + + + /*! Writes a horizontal ruler to the output */ + virtual void writeRuler() = 0; + + /*! Starts a description list: e.g. \c \ in HTML + * Items are surrounded by startDescItem() and endDescItem() + */ + virtual void startDescription() = 0; + + /*! Ends a description list: e.g. \c \ in HTML */ + virtual void endDescription() = 0; + + /*! Starts an item of a description list: e.g. \c \ in HTML. */ + virtual void startDescItem() = 0; + + virtual void startDescForItem() = 0; + virtual void endDescForItem() = 0; + + /*! Ends an item of a description list and starts the + * description itself: e.g. \c \ in HTML. + */ + virtual void endDescItem() = 0; + + virtual void startCenter() = 0; + virtual void endCenter() = 0; + virtual void startSmall() = 0; + virtual void endSmall() = 0; + + virtual void startSimpleSect(SectionTypes t,const char *file, + const char *anchor,const char *title) = 0; + virtual void endSimpleSect() = 0; + virtual void startParamList(ParamListTypes t,const char *title) = 0; + virtual void endParamList() = 0; + + //virtual void writeDescItem() = 0; + virtual void startTitle() = 0; + virtual void endTitle() = 0; + + virtual void writeAnchor(const char *fileName,const char *name) = 0; + virtual void startSection(const char *,const char *,SectionInfo::SectionType) = 0; + virtual void endSection(const char *,SectionInfo::SectionType) = 0; + + virtual void lineBreak(const char *style) = 0; + virtual void addIndexItem(const char *s1,const char *s2) = 0; + + virtual void writeNonBreakableSpace(int) = 0; + virtual void startDescTable() = 0; + virtual void endDescTable() = 0; + virtual void startDescTableTitle() = 0; + virtual void endDescTableTitle() = 0; + virtual void startDescTableData() = 0; + virtual void endDescTableData() = 0; + virtual void startTextLink(const char *file,const char *anchor) = 0; + virtual void endTextLink() = 0; + virtual void startPageRef() = 0; + virtual void endPageRef(const char *,const char *) = 0; + virtual void startSubsection() = 0; + virtual void endSubsection() = 0; + virtual void startSubsubsection() = 0; + virtual void endSubsubsection() = 0; +}; + +/*! \brief Abstract output generator. + * + * Subclass this class to add support for a new output format + */ +class OutputGenerator : public BaseOutputDocInterface +{ + public: + enum OutputType { Html, Latex, Man, RTF, XML, DEF, Perl }; + + OutputGenerator(); + virtual ~OutputGenerator(); + + /////////////////////////////////////////////////////////////// + // generic generator methods + /////////////////////////////////////////////////////////////// + virtual void enable() = 0; + virtual void disable() = 0; + virtual void enableIf(OutputType o) = 0; + virtual void disableIf(OutputType o) = 0; + virtual void disableIfNot(OutputType o) = 0; + virtual bool isEnabled(OutputType o) = 0; + virtual OutputGenerator *get(OutputType o) = 0; + void startPlainFile(const char *name); + void endPlainFile(); + //QCString getContents() const; + bool isEnabled() const { return active; } + void pushGeneratorState(); + void popGeneratorState(); + //void setEncoding(const QCString &enc) { encoding = enc; } + //virtual void postProcess(QByteArray &) { } + + virtual void printDoc(DocNode *,const char *langExt) = 0; + + /////////////////////////////////////////////////////////////// + // structural output interface + /////////////////////////////////////////////////////////////// + virtual void startFile(const char *name,const char *manName, + const char *title) = 0; + virtual void writeSearchInfo() = 0; + virtual void writeFooter() = 0; + virtual void endFile() = 0; + virtual void startIndexSection(IndexSections) = 0; + virtual void endIndexSection(IndexSections) = 0; + virtual void writePageLink(const char *,bool) = 0; + virtual void startProjectNumber() = 0; + virtual void endProjectNumber() = 0; + virtual void writeStyleInfo(int part) = 0; + virtual void startTitleHead(const char *) = 0; + virtual void endTitleHead(const char *fileName,const char *name) = 0; + virtual void startIndexListItem() = 0; + virtual void endIndexListItem() = 0; + virtual void startIndexList() = 0; + virtual void endIndexList() = 0; + virtual void startIndexKey() = 0; + virtual void endIndexKey() = 0; + virtual void startIndexValue(bool) = 0; + virtual void endIndexValue(const char *,bool) = 0; + virtual void startIndexItem(const char *ref,const char *file) = 0; + virtual void endIndexItem(const char *ref,const char *file) = 0; + virtual void startGroupHeader(int) = 0; + virtual void endGroupHeader(int) = 0; + virtual void startMemberSections() = 0; + virtual void endMemberSections() = 0; + virtual void startHeaderSection() = 0; + virtual void endHeaderSection() = 0; + virtual void startMemberHeader(const char *anchor) = 0; + virtual void endMemberHeader() = 0; + virtual void startMemberSubtitle() = 0; + virtual void endMemberSubtitle() = 0; + virtual void startMemberDocList() = 0; + virtual void endMemberDocList() = 0; + virtual void startMemberList() = 0; + virtual void endMemberList() = 0; + virtual void startInlineHeader() = 0; + virtual void endInlineHeader() = 0; + virtual void startAnonTypeScope(int) = 0; + virtual void endAnonTypeScope(int) = 0; + virtual void startMemberItem(const char *,int) = 0; + virtual void endMemberItem() = 0; + virtual void startMemberTemplateParams() = 0; + virtual void endMemberTemplateParams(const char *) = 0; + virtual void startMemberGroupHeader(bool) = 0; + virtual void endMemberGroupHeader() = 0; + virtual void startMemberGroupDocs() = 0; + virtual void endMemberGroupDocs() = 0; + virtual void startMemberGroup() = 0; + virtual void endMemberGroup(bool) = 0; + virtual void insertMemberAlign(bool) = 0; + virtual void startMemberDoc(const char *,const char *, + const char *,const char *,bool) = 0; + virtual void endMemberDoc(bool) = 0; + virtual void startDoxyAnchor(const char *fName,const char *manName, + const char *anchor,const char *name, + const char *args) = 0; + virtual void endDoxyAnchor(const char *fileName,const char *anchor) = 0; + virtual void writeLatexSpacing() = 0; + virtual void writeStartAnnoItem(const char *type,const char *file, + const char *path,const char *name) = 0; + virtual void writeEndAnnoItem(const char *name) = 0; + virtual void startMemberDescription(const char *anchor) = 0; + virtual void endMemberDescription() = 0; + virtual void startIndent() = 0; + virtual void endIndent() = 0; + virtual void writeSynopsis() = 0; + virtual void startClassDiagram() = 0; + virtual void endClassDiagram(const ClassDiagram &,const char *,const char *) = 0; + virtual void startDotGraph() = 0; + virtual void endDotGraph(const DotClassGraph &g) = 0; + virtual void startInclDepGraph() = 0; + virtual void endInclDepGraph(const DotInclDepGraph &g) = 0; + virtual void startGroupCollaboration() = 0; + virtual void endGroupCollaboration(const DotGroupCollaboration &g) = 0; + virtual void startCallGraph() = 0; + virtual void endCallGraph(const DotCallGraph &g) = 0; + virtual void startDirDepGraph() = 0; + virtual void endDirDepGraph(const DotDirDeps &g) = 0; + virtual void writeGraphicalHierarchy(const DotGfxHierarchyTable &g) = 0; + virtual void startQuickIndices() = 0; + virtual void endQuickIndices() = 0; + virtual void writeSplitBar(const char *) = 0; + virtual void writeLogo() = 0; + virtual void writeQuickLinks(bool compact,HighlightedItem hli,const char *file) = 0; + virtual void startContents() = 0; + virtual void endContents() = 0; + virtual void startTextBlock(bool) = 0; + virtual void endTextBlock(bool) = 0; + virtual void lastIndexPage() = 0; + virtual void startMemberDocPrefixItem() = 0; + virtual void endMemberDocPrefixItem() = 0; + virtual void startMemberDocName(bool) = 0; + virtual void endMemberDocName() = 0; + virtual void startParameterType(bool,const char *key) = 0; + virtual void endParameterType() = 0; + virtual void startParameterName(bool) = 0; + virtual void endParameterName(bool,bool,bool) = 0; + virtual void startParameterList(bool) = 0; + virtual void endParameterList() = 0; + + virtual void startConstraintList(const char *) = 0; + virtual void startConstraintParam() = 0; + virtual void endConstraintParam() = 0; + virtual void startConstraintType() = 0; + virtual void endConstraintType() = 0; + virtual void startConstraintDocs() = 0; + virtual void endConstraintDocs() = 0; + virtual void endConstraintList() = 0; + + virtual void startMemberDocSimple() = 0; + virtual void endMemberDocSimple() = 0; + virtual void startInlineMemberType() = 0; + virtual void endInlineMemberType() = 0; + virtual void startInlineMemberName() = 0; + virtual void endInlineMemberName() = 0; + virtual void startInlineMemberDoc() = 0; + virtual void endInlineMemberDoc() = 0; + + protected: + FTextStream t; + QFile *file; + QCString fileName; + QCString dir; + bool active; + QStack *genStack; + + private: + OutputGenerator(const OutputGenerator &o); + OutputGenerator &operator=(const OutputGenerator &o); +}; + +/*! \brief Interface used for generating documentation. + * + * This abstract class is used by several functions + * to generate the output for a specific format. + * This interface contains some state saving and changing + * functions for dealing with format specific output. + */ +class OutputDocInterface : public BaseOutputDocInterface +{ + public: + virtual ~OutputDocInterface() {} + + /*! Create a new output generator. This can later by appended + * to the current one using append(). + */ + //virtual OutputDocInterface *clone() = 0; + + /*! Disables all output formats except format \a o + * (useful for OutputList only) + */ + virtual void disableAllBut(OutputGenerator::OutputType o) = 0; + + /*! Enables all output formats as far as they have been enabled in + * the config file. (useful for OutputList only) + */ + virtual void enableAll() = 0; + + /*! Disables all output formats (useful for OutputList only) */ + virtual void disableAll()= 0; + + /*! Disables a specific output format (useful for OutputList only) */ + virtual void disable(OutputGenerator::OutputType o) = 0; + + /*! Enables a specific output format (useful for OutputList only) */ + virtual void enable(OutputGenerator::OutputType o) = 0; + + /*! Check whether a specific output format is currenly enabled + * (useful for OutputList only) + */ + virtual bool isEnabled(OutputGenerator::OutputType o) = 0; + + /*! Appends the output generated by generator \a g to this + * generator. + */ + //virtual void append(const OutputDocInterface *g) = 0; + + /*! Pushes the state of the current generator (or list of + * generators) on a stack. + */ + virtual void pushGeneratorState() = 0; + + /*! Pops the state of the current generator (or list of + * generators) on a stack. Should be preceded by a call + * the pushGeneratorState(). + */ + virtual void popGeneratorState() = 0; +}; + + +#endif diff --git a/trunk/src/outputlist.cpp b/trunk/src/outputlist.cpp new file mode 100644 index 0000000..cb1bba1 --- /dev/null +++ b/trunk/src/outputlist.cpp @@ -0,0 +1,316 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +/*! \file + * This class represents a list of output generators that work in "parallel". + * The class only knows about the abstract base class OutputGenerators. + * All output is produced by calling a method of this class, which forwards + * the call to all output generators. + */ + +#include "outputlist.h" +#include "outputgen.h" +#include "config.h" +#include "message.h" +#include "definition.h" + +#include "docparser.h" + +OutputList::OutputList(bool) +{ + //printf("OutputList::OutputList()\n"); + outputs = new QList; + outputs->setAutoDelete(TRUE); +} + +OutputList::~OutputList() +{ + //printf("OutputList::~OutputList()\n"); + delete outputs; +} + +void OutputList::add(const OutputGenerator *og) +{ + if (og) outputs->append(og); +} + +void OutputList::disableAllBut(OutputGenerator::OutputType o) +{ + OutputGenerator *og=outputs->first(); + while (og) + { + og->disableIfNot(o); + og=outputs->next(); + } +} + +void OutputList::enableAll() +{ + OutputGenerator *og=outputs->first(); + while (og) + { + og->enable(); + og=outputs->next(); + } +} + +void OutputList::disableAll() +{ + OutputGenerator *og=outputs->first(); + while (og) + { + og->disable(); + og=outputs->next(); + } +} + +void OutputList::disable(OutputGenerator::OutputType o) +{ + OutputGenerator *og=outputs->first(); + while (og) + { + og->disableIf(o); + og=outputs->next(); + } +} + +void OutputList::enable(OutputGenerator::OutputType o) +{ + OutputGenerator *og=outputs->first(); + while (og) + { + og->enableIf(o); + og=outputs->next(); + } +} + +bool OutputList::isEnabled(OutputGenerator::OutputType o) +{ + bool result=FALSE; + OutputGenerator *og=outputs->first(); + while (og) + { + result=result || og->isEnabled(o); + og=outputs->next(); + } + return result; +} + +void OutputList::pushGeneratorState() +{ + OutputGenerator *og=outputs->first(); + while (og) + { + og->pushGeneratorState(); + og=outputs->next(); + } +} + +void OutputList::popGeneratorState() +{ + OutputGenerator *og=outputs->first(); + while (og) + { + og->popGeneratorState(); + og=outputs->next(); + } +} + +void OutputList::parseDoc(const char *fileName,int startLine, + Definition *ctx,MemberDef * md, + const QCString &docStr,bool indexWords, + bool isExample,const char *exampleName, + bool singleLine,bool linkFromIndex) +{ + int count=0; + if (docStr.isEmpty()) return; + + OutputGenerator *og=outputs->first(); + while (og) + { + if (og->isEnabled()) count++; + og=outputs->next(); + } + if (count==0) return; // no output formats enabled. + + DocNode *root=0; + if (docStr.at(docStr.length()-1)=='\n') + { + root = validatingParseDoc(fileName,startLine, + ctx,md,docStr,indexWords,isExample,exampleName, + singleLine,linkFromIndex); + } + else + { + root = validatingParseDoc(fileName,startLine, + ctx,md,docStr+"\n",indexWords,isExample,exampleName, + singleLine,linkFromIndex); + } + + og=outputs->first(); + while (og) + { + //printf("og->printDoc(extension=%s)\n", + // ctx?ctx->getDefFileExtension().data():""); + if (og->isEnabled()) og->printDoc(root,ctx?ctx->getDefFileExtension():QCString("")); + og=outputs->next(); + } + + delete root; +} + +void OutputList::parseText(const QCString &textStr) +{ + int count=0; + OutputGenerator *og=outputs->first(); + while (og) + { + if (og->isEnabled()) count++; + og=outputs->next(); + } + if (count==0) return; // no output formats enabled. + + DocNode *root = validatingParseText(textStr); + + og=outputs->first(); + while (og) + { + if (og->isEnabled()) og->printDoc(root,0); + og=outputs->next(); + } + + delete root; +} + + +//-------------------------------------------------------------------------- +// Create some overloaded definitions of the forall function. +// Using template functions here would have made it a little less +// portable (I guess). + +// zero arguments +void OutputList::forall(void (OutputGenerator::*func)()) +{ + OutputGenerator *og=outputs->first(); + while (og) + { + if (og->isEnabled()) (og->*func)(); + og=outputs->next(); + } +} + +// one argument +#define FORALL1(a1,p1) \ +void OutputList::forall(void (OutputGenerator::*func)(a1),a1) \ +{ \ + OutputGenerator *og=outputs->first(); \ + while (og) \ + { \ + if (og->isEnabled()) (og->*func)(p1); \ + og=outputs->next(); \ + } \ +} + +// two arguments +#define FORALL2(a1,a2,p1,p2) \ +void OutputList::forall(void (OutputGenerator::*func)(a1,a2),a1,a2) \ +{ \ + OutputGenerator *og=outputs->first(); \ + while (og) \ + { \ + if (og->isEnabled()) (og->*func)(p1,p2); \ + og=outputs->next(); \ + } \ +} + +// three arguments +#define FORALL3(a1,a2,a3,p1,p2,p3) \ +void OutputList::forall(void (OutputGenerator::*func)(a1,a2,a3),a1,a2,a3) \ +{ \ + OutputGenerator *og=outputs->first(); \ + while (og) \ + { \ + if (og->isEnabled()) (og->*func)(p1,p2,p3); \ + og=outputs->next(); \ + } \ +} + +// four arguments +#define FORALL4(a1,a2,a3,a4,p1,p2,p3,p4) \ +void OutputList::forall(void (OutputGenerator::*func)(a1,a2,a3,a4),a1,a2,a3,a4) \ +{ \ + OutputGenerator *og=outputs->first(); \ + while (og) \ + { \ + if (og->isEnabled()) (og->*func)(p1,p2,p3,p4); \ + og=outputs->next(); \ + } \ +} + +// five arguments +#define FORALL5(a1,a2,a3,a4,a5,p1,p2,p3,p4,p5) \ +void OutputList::forall(void (OutputGenerator::*func)(a1,a2,a3,a4,a5),a1,a2,a3,a4,a5) \ +{ \ + OutputGenerator *og=outputs->first(); \ + while (og) \ + { \ + if (og->isEnabled()) (og->*func)(p1,p2,p3,p4,p5); \ + og=outputs->next(); \ + } \ +} + +// now instantiate only the ones we need. + +FORALL1(const char *a1,a1) +FORALL1(char a1,a1) +FORALL1(int a1,a1) +FORALL1(const DotClassGraph &a1,a1) +FORALL1(const DotInclDepGraph &a1,a1) +FORALL1(const DotCallGraph &a1,a1) +FORALL1(const DotDirDeps &a1,a1) +FORALL1(const DotGfxHierarchyTable &a1,a1) +FORALL1(const DotGroupCollaboration &a1,a1) +FORALL1(SectionTypes a1,a1) +#if defined(HAS_BOOL_TYPE) || defined(Q_HAS_BOOL_TYPE) +FORALL1(bool a1,a1) +FORALL2(bool a1,int a2,a1,a2) +FORALL2(bool a1,bool a2,a1,a2) +FORALL2(const char *a1,bool a2,a1,a2) +FORALL4(const char *a1,const char *a2,const char *a3,bool a4,a1,a2,a3,a4) +#endif +FORALL2(int a1,bool a2,a1,a2) +FORALL2(bool a1,const char *a2,a1,a2) +FORALL2(ParamListTypes a1,const char *a2,a1,a2) +FORALL1(IndexSections a1,a1) +FORALL2(const char *a1,const char *a2,a1,a2) +FORALL2(const char *a1,int a2,a1,a2) +FORALL2(const char *a1,SectionInfo::SectionType a2,a1,a2) +FORALL3(bool a1,HighlightedItem a2,const char *a3,a1,a2,a3) +FORALL3(bool a1,bool a2,bool a3,a1,a2,a3) +FORALL3(const ClassDiagram &a1,const char *a2,const char *a3,a1,a2,a3) +FORALL3(const char *a1,const char *a2,const char *a3,a1,a2,a3) +FORALL3(const char *a1,const char *a2,bool a3,a1,a2,a3) +FORALL3(const char *a1,const char *a2,SectionInfo::SectionType a3,a1,a2,a3) +FORALL3(uchar a1,uchar a2,uchar a3,a1,a2,a3) +FORALL4(SectionTypes a1,const char *a2,const char *a3,const char *a4,a1,a2,a3,a4) +FORALL4(const char *a1,const char *a2,const char *a3,const char *a4,a1,a2,a3,a4) +FORALL4(const char *a1,const char *a2,const char *a3,int a4,a1,a2,a3,a4) +FORALL5(const char *a1,const char *a2,const char *a3,const char *a4,const char *a5,a1,a2,a3,a4,a5) +FORALL5(const char *a1,const char *a2,const char *a3,const char *a4,bool a5,a1,a2,a3,a4,a5) + + +//-------------------------------------------------------------------------- diff --git a/trunk/src/outputlist.h b/trunk/src/outputlist.h new file mode 100644 index 0000000..1b5b8ec --- /dev/null +++ b/trunk/src/outputlist.h @@ -0,0 +1,518 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#ifndef OUTPUTLIST_H +#define OUTPUTLIST_H + +#include "qtbc.h" +#include +#include "index.h" // for IndexSections +#include "outputgen.h" + +#define FORALLPROTO1(arg1) \ + void forall(void (OutputGenerator::*func)(arg1),arg1) +#define FORALLPROTO2(arg1,arg2) \ + void forall(void (OutputGenerator::*func)(arg1,arg2),arg1,arg2) +#define FORALLPROTO3(arg1,arg2,arg3) \ + void forall(void (OutputGenerator::*func)(arg1,arg2,arg3),arg1,arg2,arg3) +#define FORALLPROTO4(arg1,arg2,arg3,arg4) \ + void forall(void (OutputGenerator::*func)(arg1,arg2,arg3,arg4),arg1,arg2,arg3,arg4) +#define FORALLPROTO5(arg1,arg2,arg3,arg4,arg5) \ + void forall(void (OutputGenerator::*func)(arg1,arg2,arg3,arg4,arg5),arg1,arg2,arg3,arg4,arg5) + +class ClassDiagram; +class DotClassGraph; +class DotDirDeps; +class DotInclDepGraph; +class DotGfxHierarchyTable; +class SectionDict; +class DotGroupCollaboration; + +class OutputList : public OutputDocInterface +{ + public: + OutputList(bool); + virtual ~OutputList(); + + void add(const OutputGenerator *); + + void disableAllBut(OutputGenerator::OutputType o); + void enableAll(); + void disableAll(); + void disable(OutputGenerator::OutputType o); + void enable(OutputGenerator::OutputType o); + bool isEnabled(OutputGenerator::OutputType o); + void pushGeneratorState(); + void popGeneratorState(); + + + ////////////////////////////////////////////////// + // OutputDocInterface implementation + ////////////////////////////////////////////////// + + void parseDoc(const char *fileName,int startLine, + Definition *ctx,MemberDef *md,const QCString &docStr, + bool indexWords,bool isExample,const char *exampleName=0, + bool singleLine=FALSE,bool linkFromIndex=FALSE); + void parseText(const QCString &textStr); + + + void startIndexSection(IndexSections is) + { forall(&OutputGenerator::startIndexSection,is); } + void endIndexSection(IndexSections is) + { forall(&OutputGenerator::endIndexSection,is); } + void writePageLink(const char *name,bool first) + { forall(&OutputGenerator::writePageLink,name,first); } + void startProjectNumber() + { forall(&OutputGenerator::startProjectNumber); } + void endProjectNumber() + { forall(&OutputGenerator::endProjectNumber); } + void writeStyleInfo(int part) + { forall(&OutputGenerator::writeStyleInfo,part); } + void startFile(const char *name,const char *manName,const char *title) + { forall(&OutputGenerator::startFile,name,manName,title); } + void writeSearchInfo() + { forall(&OutputGenerator::writeSearchInfo); } + void writeFooter() + { forall(&OutputGenerator::writeFooter); } + void endFile() + { forall(&OutputGenerator::endFile); } + void startTitleHead(const char *fileName) + { forall(&OutputGenerator::startTitleHead,fileName); } + void endTitleHead(const char *fileName,const char *name) + { forall(&OutputGenerator::endTitleHead,fileName,name); } + void startTitle() + { forall(&OutputGenerator::startTitle); } + void endTitle() + { forall(&OutputGenerator::endTitle); } + //void newParagraph() + //{ forall(&OutputGenerator::newParagraph); } + void startParagraph() + { forall(&OutputGenerator::startParagraph); } + void endParagraph() + { forall(&OutputGenerator::endParagraph); } + void writeString(const char *text) + { forall(&OutputGenerator::writeString,text); } + void startIndexListItem() + { forall(&OutputGenerator::startIndexListItem); } + void endIndexListItem() + { forall(&OutputGenerator::endIndexListItem); } + void startIndexList() + { forall(&OutputGenerator::startIndexList); } + void endIndexList() + { forall(&OutputGenerator::endIndexList); } + void startIndexKey() + { forall(&OutputGenerator::startIndexKey); } + void endIndexKey() + { forall(&OutputGenerator::endIndexKey); } + void startIndexValue(bool b) + { forall(&OutputGenerator::startIndexValue,b); } + void endIndexValue(const char *name,bool b) + { forall(&OutputGenerator::endIndexValue,name,b); } + void startItemList() + { forall(&OutputGenerator::startItemList); } + void endItemList() + { forall(&OutputGenerator::endItemList); } + void startIndexItem(const char *ref,const char *file) + { forall(&OutputGenerator::startIndexItem,ref,file); } + void endIndexItem(const char *ref,const char *file) + { forall(&OutputGenerator::endIndexItem,ref,file); } + void docify(const char *s) + { forall(&OutputGenerator::docify,s); } + void codify(const char *s) + { forall(&OutputGenerator::codify,s); } + void writeObjectLink(const char *ref,const char *file, + const char *anchor, const char *name) + { forall(&OutputGenerator::writeObjectLink,ref,file,anchor,name); } + void writeCodeLink(const char *ref,const char *file, + const char *anchor,const char *name, + const char *tooltip) + { forall(&OutputGenerator::writeCodeLink,ref,file,anchor,name,tooltip); } + void startTextLink(const char *file,const char *anchor) + { forall(&OutputGenerator::startTextLink,file,anchor); } + void endTextLink() + { forall(&OutputGenerator::endTextLink); } + void startHtmlLink(const char *url) + { forall(&OutputGenerator::startHtmlLink,url); } + void endHtmlLink() + { forall(&OutputGenerator::endHtmlLink); } + void writeStartAnnoItem(const char *type,const char *file, + const char *path,const char *name) + { forall(&OutputGenerator::writeStartAnnoItem,type,file,path,name); } + void writeEndAnnoItem(const char *name) + { forall(&OutputGenerator::writeEndAnnoItem,name); } + void startTypewriter() + { forall(&OutputGenerator::startTypewriter); } + void endTypewriter() + { forall(&OutputGenerator::endTypewriter); } + void startGroupHeader(int extraLevels=0) + { forall(&OutputGenerator::startGroupHeader,extraLevels); } + void endGroupHeader(int extraLevels=0) + { forall(&OutputGenerator::endGroupHeader,extraLevels); } + //void writeListItem() + //{ forall(&OutputGenerator::writeListItem); } + void startItemListItem() + { forall(&OutputGenerator::startItemListItem); } + void endItemListItem() + { forall(&OutputGenerator::endItemListItem); } + void startMemberSections() + { forall(&OutputGenerator::startMemberSections); } + void endMemberSections() + { forall(&OutputGenerator::endMemberSections); } + void startHeaderSection() + { forall(&OutputGenerator::startHeaderSection); } + void endHeaderSection() + { forall(&OutputGenerator::endHeaderSection); } + void startMemberHeader(const char *anchor) + { forall(&OutputGenerator::startMemberHeader,anchor); } + void endMemberHeader() + { forall(&OutputGenerator::endMemberHeader); } + void startMemberSubtitle() + { forall(&OutputGenerator::startMemberSubtitle); } + void endMemberSubtitle() + { forall(&OutputGenerator::endMemberSubtitle); } + void startMemberDocList() + { forall(&OutputGenerator::startMemberDocList); } + void endMemberDocList() + { forall(&OutputGenerator::endMemberDocList); } + void startMemberList() + { forall(&OutputGenerator::startMemberList); } + void endMemberList() + { forall(&OutputGenerator::endMemberList); } + void startInlineHeader() + { forall(&OutputGenerator::startInlineHeader); } + void endInlineHeader() + { forall(&OutputGenerator::endInlineHeader); } + void startAnonTypeScope(int i1) + { forall(&OutputGenerator::startAnonTypeScope,i1); } + void endAnonTypeScope(int i1) + { forall(&OutputGenerator::endAnonTypeScope,i1); } + void startMemberItem(const char *anchor,int i1) + { forall(&OutputGenerator::startMemberItem,anchor,i1); } + void endMemberItem() + { forall(&OutputGenerator::endMemberItem); } + void startMemberTemplateParams() + { forall(&OutputGenerator::startMemberTemplateParams); } + void endMemberTemplateParams(const char *anchor) + { forall(&OutputGenerator::endMemberTemplateParams,anchor); } + void startMemberGroupHeader(bool b) + { forall(&OutputGenerator::startMemberGroupHeader,b); } + void endMemberGroupHeader() + { forall(&OutputGenerator::endMemberGroupHeader); } + void startMemberGroupDocs() + { forall(&OutputGenerator::startMemberGroupDocs); } + void endMemberGroupDocs() + { forall(&OutputGenerator::endMemberGroupDocs); } + void startMemberGroup() + { forall(&OutputGenerator::startMemberGroup); } + void endMemberGroup(bool last) + { forall(&OutputGenerator::endMemberGroup,last); } + void insertMemberAlign(bool templ=FALSE) + { forall(&OutputGenerator::insertMemberAlign,templ); } + void writeRuler() + { forall(&OutputGenerator::writeRuler); } + void writeAnchor(const char *fileName,const char *name) + { forall(&OutputGenerator::writeAnchor,fileName,name); } + void startCodeFragment() + { forall(&OutputGenerator::startCodeFragment); } + void endCodeFragment() + { forall(&OutputGenerator::endCodeFragment); } + void startCodeLine() + { forall(&OutputGenerator::startCodeLine); } + void endCodeLine() + { forall(&OutputGenerator::endCodeLine); } + void writeLineNumber(const char *ref,const char *file,const char *anchor, + int lineNumber) + { forall(&OutputGenerator::writeLineNumber,ref,file,anchor,lineNumber); } + void startEmphasis() + { forall(&OutputGenerator::startEmphasis); } + void endEmphasis() + { forall(&OutputGenerator::endEmphasis); } + void writeChar(char c) + { forall(&OutputGenerator::writeChar,c); } + void startMemberDoc(const char *clName,const char *memName, + const char *anchor,const char *title,bool showInline) + { forall(&OutputGenerator::startMemberDoc,clName,memName,anchor,title,showInline); } + void endMemberDoc(bool hasArgs) + { forall(&OutputGenerator::endMemberDoc,hasArgs); } + void startDoxyAnchor(const char *fName,const char *manName, + const char *anchor, const char *name, + const char *args) + { forall(&OutputGenerator::startDoxyAnchor,fName,manName,anchor,name,args); } + void endDoxyAnchor(const char *fn,const char *anchor) + { forall(&OutputGenerator::endDoxyAnchor,fn,anchor); } + void startCodeAnchor(const char *label) + { forall(&OutputGenerator::startCodeAnchor,label); } + void endCodeAnchor() + { forall(&OutputGenerator::endCodeAnchor); } + void writeLatexSpacing() + { forall(&OutputGenerator::writeLatexSpacing); } + void startDescription() + { forall(&OutputGenerator::startDescription); } + void endDescription() + { forall(&OutputGenerator::endDescription); } + void startDescItem() + { forall(&OutputGenerator::startDescItem); } + void endDescItem() + { forall(&OutputGenerator::endDescItem); } + void startDescForItem() + { forall(&OutputGenerator::startDescForItem); } + void endDescForItem() + { forall(&OutputGenerator::endDescForItem); } + void startSubsection() + { forall(&OutputGenerator::startSubsection); } + void endSubsection() + { forall(&OutputGenerator::endSubsection); } + void startSubsubsection() + { forall(&OutputGenerator::startSubsubsection); } + void endSubsubsection() + { forall(&OutputGenerator::endSubsubsection); } + void startCenter() + { forall(&OutputGenerator::startCenter); } + void endCenter() + { forall(&OutputGenerator::endCenter); } + void startSmall() + { forall(&OutputGenerator::startSmall); } + void endSmall() + { forall(&OutputGenerator::endSmall); } + void lineBreak(const char *style=0) + { forall(&OutputGenerator::lineBreak,style); } + void startBold() + { forall(&OutputGenerator::startBold); } + void endBold() + { forall(&OutputGenerator::endBold); } + void startMemberDescription(const char *anchor) + { forall(&OutputGenerator::startMemberDescription,anchor); } + void endMemberDescription() + { forall(&OutputGenerator::endMemberDescription); } + void startSimpleSect(SectionTypes t,const char *file,const char *anchor, + const char *title) + { forall(&OutputGenerator::startSimpleSect,t,file,anchor,title); } + void endSimpleSect() + { forall(&OutputGenerator::endSimpleSect); } + void startParamList(ParamListTypes t,const char *title) + { forall(&OutputGenerator::startParamList,t,title); } + void endParamList() + { forall(&OutputGenerator::endParamList); } + //void writeDescItem() + //{ forall(&OutputGenerator::writeDescItem); } + void startIndent() + { forall(&OutputGenerator::startIndent); } + void endIndent() + { forall(&OutputGenerator::endIndent); } + void startSection(const char *lab,const char *title,SectionInfo::SectionType t) + { forall(&OutputGenerator::startSection,lab,title,t); } + void endSection(const char *lab,SectionInfo::SectionType t) + { forall(&OutputGenerator::endSection,lab,t); } + void addIndexItem(const char *s1,const char *s2) + { forall(&OutputGenerator::addIndexItem,s1,s2); } + void writeSynopsis() + { forall(&OutputGenerator::writeSynopsis); } + void startClassDiagram() + { forall(&OutputGenerator::startClassDiagram); } + void endClassDiagram(const ClassDiagram &d,const char *f,const char *n) + { forall(&OutputGenerator::endClassDiagram,d,f,n); } + void startPageRef() + { forall(&OutputGenerator::startPageRef); } + void endPageRef(const char *c,const char *a) + { forall(&OutputGenerator::endPageRef,c,a); } + void startQuickIndices() + { forall(&OutputGenerator::startQuickIndices); } + void endQuickIndices() + { forall(&OutputGenerator::endQuickIndices); } + void writeSplitBar(const char *name) + { forall(&OutputGenerator::writeSplitBar,name); } + void writeLogo() + { forall(&OutputGenerator::writeLogo); } + void writeQuickLinks(bool compact,HighlightedItem hli,const char *file) + { forall(&OutputGenerator::writeQuickLinks,compact,hli,file); } + void startContents() + { forall(&OutputGenerator::startContents); } + void endContents() + { forall(&OutputGenerator::endContents); } + void writeNonBreakableSpace(int num) + { forall(&OutputGenerator::writeNonBreakableSpace,num); } + void startDescTable() + { forall(&OutputGenerator::startDescTable); } + void endDescTable() + { forall(&OutputGenerator::endDescTable); } + void startDescTableTitle() + { forall(&OutputGenerator::startDescTableTitle); } + void endDescTableTitle() + { forall(&OutputGenerator::endDescTableTitle); } + void startDescTableData() + { forall(&OutputGenerator::startDescTableData); } + void endDescTableData() + { forall(&OutputGenerator::endDescTableData); } + void startDotGraph() + { forall(&OutputGenerator::startDotGraph); } + void endDotGraph(const DotClassGraph &g) + { forall(&OutputGenerator::endDotGraph,g); } + void startInclDepGraph() + { forall(&OutputGenerator::startInclDepGraph); } + void endInclDepGraph(const DotInclDepGraph &g) + { forall(&OutputGenerator::endInclDepGraph,g); } + void startCallGraph() + { forall(&OutputGenerator::startCallGraph); } + void endCallGraph(const DotCallGraph &g) + { forall(&OutputGenerator::endCallGraph,g); } + void startDirDepGraph() + { forall(&OutputGenerator::startDirDepGraph); } + void endDirDepGraph(const DotDirDeps &g) + { forall(&OutputGenerator::endDirDepGraph,g); } + void startGroupCollaboration() + { forall(&OutputGenerator::startGroupCollaboration); } + void endGroupCollaboration(const DotGroupCollaboration &g) + { forall(&OutputGenerator::endGroupCollaboration,g); } + void writeGraphicalHierarchy(const DotGfxHierarchyTable &g) + { forall(&OutputGenerator::writeGraphicalHierarchy,g); } + void startTextBlock(bool dense=FALSE) + { forall(&OutputGenerator::startTextBlock,dense); } + void endTextBlock(bool paraBreak=FALSE) + { forall(&OutputGenerator::endTextBlock,paraBreak); } + void lastIndexPage() + { forall(&OutputGenerator::lastIndexPage); } + void startMemberDocPrefixItem() + { forall(&OutputGenerator::startMemberDocPrefixItem); } + void endMemberDocPrefixItem() + { forall(&OutputGenerator::endMemberDocPrefixItem); } + void startMemberDocName(bool align) + { forall(&OutputGenerator::startMemberDocName,align); } + void endMemberDocName() + { forall(&OutputGenerator::endMemberDocName); } + void startParameterType(bool first,const char *key) + { forall(&OutputGenerator::startParameterType,first,key); } + void endParameterType() + { forall(&OutputGenerator::endParameterType); } + void startParameterName(bool one) + { forall(&OutputGenerator::startParameterName,one); } + void endParameterName(bool last,bool one,bool bracket) + { forall(&OutputGenerator::endParameterName,last,one,bracket); } + void startParameterList(bool openBracket) + { forall(&OutputGenerator::startParameterList,openBracket); } + void endParameterList() + { forall(&OutputGenerator::endParameterList); } + + void startConstraintList(const char *header) + { forall(&OutputGenerator::startConstraintList,header); } + void startConstraintParam() + { forall(&OutputGenerator::startConstraintParam); } + void endConstraintParam() + { forall(&OutputGenerator::endConstraintParam); } + void startConstraintType() + { forall(&OutputGenerator::startConstraintType); } + void endConstraintType() + { forall(&OutputGenerator::endConstraintType); } + void startConstraintDocs() + { forall(&OutputGenerator::startConstraintDocs); } + void endConstraintDocs() + { forall(&OutputGenerator::endConstraintDocs); } + void endConstraintList() + { forall(&OutputGenerator::endConstraintList); } + + void startMemberDocSimple() + { forall(&OutputGenerator::startMemberDocSimple); } + void endMemberDocSimple() + { forall(&OutputGenerator::endMemberDocSimple); } + void startInlineMemberType() + { forall(&OutputGenerator::startInlineMemberType); } + void endInlineMemberType() + { forall(&OutputGenerator::endInlineMemberType); } + void startInlineMemberName() + { forall(&OutputGenerator::startInlineMemberName); } + void endInlineMemberName() + { forall(&OutputGenerator::endInlineMemberName); } + void startInlineMemberDoc() + { forall(&OutputGenerator::startInlineMemberDoc); } + void endInlineMemberDoc() + { forall(&OutputGenerator::endInlineMemberDoc); } + + void startFontClass(const char *c) + { forall(&OutputGenerator::startFontClass,c); } + void endFontClass() + { forall(&OutputGenerator::endFontClass); } + void writeCodeAnchor(const char *name) + { forall(&OutputGenerator::writeCodeAnchor,name); } + void startPlainFile(const char *name) + { + OutputGenerator *og=outputs->first(); + while (og) + { + if (og->isEnabled()) (og->startPlainFile)(name); + og=outputs->next(); + } + } + void endPlainFile() + { + OutputGenerator *og=outputs->first(); + while (og) + { + if (og->isEnabled()) (og->endPlainFile)(); + og=outputs->next(); + } + } + void linkableSymbol(int,const char *,Definition *,Definition *) {} + + + + private: + void debug(); + void clear(); + + void forall(void (OutputGenerator::*func)()); + FORALLPROTO1(const char *); + FORALLPROTO1(char); + FORALLPROTO1(IndexSections); + FORALLPROTO1(int); + FORALLPROTO1(const DotClassGraph &); + FORALLPROTO1(const DotInclDepGraph &); + FORALLPROTO1(const DotCallGraph &); + FORALLPROTO1(const DotGroupCollaboration &); + FORALLPROTO1(const DotDirDeps &); + FORALLPROTO1(const DotGfxHierarchyTable &); + FORALLPROTO1(SectionTypes); +#if defined(HAS_BOOL_TYPE) || defined(Q_HAS_BOOL_TYPE) + FORALLPROTO1(bool); + FORALLPROTO2(bool,int); + FORALLPROTO2(bool,bool); + FORALLPROTO2(const char *,bool); + FORALLPROTO4(const char *,const char *,const char *,int); +#endif + FORALLPROTO2(int,bool); + FORALLPROTO2(bool,const char *); + FORALLPROTO2(ParamListTypes,const char *); + FORALLPROTO2(const char *,const char *); + FORALLPROTO2(const char *,int); + FORALLPROTO2(const char *,SectionInfo::SectionType); + FORALLPROTO3(bool,HighlightedItem,const char *); + FORALLPROTO3(bool,bool,bool); + FORALLPROTO3(const char *,const char *,bool); + FORALLPROTO3(const char *,const char *,SectionInfo::SectionType); + FORALLPROTO3(uchar,uchar,uchar); + FORALLPROTO3(const char *,const char *,const char *); + FORALLPROTO3(const ClassDiagram &,const char *,const char *); + FORALLPROTO4(SectionTypes,const char *,const char *,const char *); + FORALLPROTO4(const char *,const char *,const char *,const char *); + FORALLPROTO4(const char *,const char *,const char *,bool); + FORALLPROTO5(const char *,const char *,const char *,const char *,const char *); + FORALLPROTO5(const char *,const char *,const char *,const char *,bool); + + OutputList(const OutputList &ol); + QList *outputs; +}; + +#endif diff --git a/trunk/src/pagedef.cpp b/trunk/src/pagedef.cpp new file mode 100644 index 0000000..7d7ac01 --- /dev/null +++ b/trunk/src/pagedef.cpp @@ -0,0 +1,283 @@ +#include "pagedef.h" +#include "groupdef.h" +#include "docparser.h" +#include "config.h" +#include "util.h" +#include "outputlist.h" +#include "doxygen.h" +#include "language.h" +#include + + +PageDef::PageDef(const char *f,int l,const char *n, + const char *d,const char *t) + : Definition(f,l,n), m_title(t) +{ + setDocumentation(d,f,l); + m_subPageDict = new PageSDict(7); + m_pageScope = 0; + m_nestingLevel = 0; + m_showToc = FALSE; +} + +PageDef::~PageDef() +{ + delete m_subPageDict; +} + +void PageDef::findSectionsInDocumentation() +{ + docFindSections(documentation(),this,0,docFile()); +} + +GroupDef *PageDef::getGroupDef() const +{ + LockingPtr groups = partOfGroups(); + return groups!=0 ? groups->getFirst() : 0; +} + +QCString PageDef::getOutputFileBase() const +{ + if (getGroupDef()) + return getGroupDef()->getOutputFileBase(); + else + return m_fileName; +} + +void PageDef::addInnerCompound(Definition *def) +{ + if (def->definitionType()==Definition::TypePage) + { + PageDef *pd = (PageDef*)def; + m_subPageDict->append(pd->name(),pd); + def->setOuterScope(this); + if (this==Doxygen::mainPage) + { + pd->setNestingLevel(m_nestingLevel); + } + else + { + pd->setNestingLevel(m_nestingLevel+1); + } + } +} + +bool PageDef::hasParentPage() const +{ + return getOuterScope() && + getOuterScope()->definitionType()==Definition::TypePage; +} + +void PageDef::writeDocumentation(OutputList &ol) +{ + static bool generateTreeView = Config_getBool("GENERATE_TREEVIEW"); + + //outputList->disable(OutputGenerator::Man); + QCString pageName; + pageName=escapeCharsInString(name(),FALSE,TRUE); + + //printf("PageDef::writeDocumentation: %s\n",getOutputFileBase().data()); + + ol.pushGeneratorState(); + //1.{ + + if (m_nestingLevel>0 + //&& // a sub page + //(Doxygen::mainPage==0 || getOuterScope()!=Doxygen::mainPage) // and not a subpage of the mainpage + ) + { + // do not generate sub page output for RTF and LaTeX, as these are + // part of their parent page + ol.disableAll(); + ol.enable(OutputGenerator::Man); + ol.enable(OutputGenerator::Html); + } + + startFile(ol,getOutputFileBase(),pageName,title(),HLI_Pages,!generateTreeView); + + if (!generateTreeView) + { + if (getOuterScope()!=Doxygen::globalScope && !Config_getBool("DISABLE_INDEX")) + { + getOuterScope()->writeNavigationPath(ol); + } + ol.endQuickIndices(); + } + SectionInfo *si=Doxygen::sectionDict.find(name()); + + // save old generator state and write title only to Man generator + ol.pushGeneratorState(); + //2.{ + ol.disableAllBut(OutputGenerator::Man); + ol.startTitleHead(pageName); + ol.endTitleHead(pageName, pageName); + if (si) + { + ol.parseDoc(docFile(),docLine(),this,0,si->title,TRUE,FALSE,0,TRUE,FALSE); + ol.endSection(si->label,si->type); + } + ol.popGeneratorState(); + //2.} + + // for Latex the section is already generated as a chapter in the index! + ol.pushGeneratorState(); + //2.{ + ol.disable(OutputGenerator::Latex); + ol.disable(OutputGenerator::RTF); + ol.disable(OutputGenerator::Man); + if (!title().isEmpty() && !name().isEmpty() && si!=0) + { + //ol.startSection(si->label,si->title,si->type); + startTitle(ol,getOutputFileBase(),this); + ol.parseDoc(docFile(),docLine(),this,0,si->title,TRUE,FALSE,0,TRUE,FALSE); + //stringToSearchIndex(getOutputFileBase(), + // theTranslator->trPage(TRUE,TRUE)+" "+si->title, + // si->title); + //ol.endSection(si->label,si->type); + endTitle(ol,getOutputFileBase(),name()); + } + ol.startContents(); + ol.popGeneratorState(); + //2.} + + if (m_showToc && hasSections()) + { + writeToc(ol); + } + + writePageDocumentation(ol); + + if (generateTreeView && getOuterScope()!=Doxygen::globalScope && !Config_getBool("DISABLE_INDEX")) + { + ol.endContents(); + endFileWithNavPath(getOuterScope(),ol); + } + else + { + endFile(ol); + } + + ol.popGeneratorState(); + //1.} + + if (!Config_getString("GENERATE_TAGFILE").isEmpty()) + { + bool found=FALSE; + QDictIterator rli(*Doxygen::xrefLists); + RefList *rl; + for (rli.toFirst();(rl=rli.current());++rli) + { + if (rl->listName()==name()) + { + found=TRUE; + break; + } + } + if (!found) // not one of the generated related pages + { + Doxygen::tagFile << " " << endl; + Doxygen::tagFile << " " << name() << "" << endl; + Doxygen::tagFile << " " << convertToXML(title()) << "" << endl; + Doxygen::tagFile << " " << getOutputFileBase() << "" << endl; + writeDocAnchorsToTagFile(); + Doxygen::tagFile << " " << endl; + } + } + + Doxygen::indexList.addIndexItem(this,0,filterTitle(title())); +} + +void PageDef::writePageDocumentation(OutputList &ol) +{ + + bool markdownEnabled = Doxygen::markdownSupport; + if (getLanguage()==SrcLangExt_Markdown) + { + Doxygen::markdownSupport = TRUE; + } + + ol.startTextBlock(); + ol.parseDoc( + docFile(), // fileName + docLine(), // startLine + this, // context + 0, // memberdef + documentation()+inbodyDocumentation(), // docStr + TRUE, // index words + FALSE // not an example + ); + ol.endTextBlock(); + + Doxygen::markdownSupport = markdownEnabled; + + if (hasSubPages()) + { + // for printed documentation we write subpages as section's of the + // parent page. + ol.pushGeneratorState(); + ol.disableAll(); + ol.enable(OutputGenerator::Latex); + ol.enable(OutputGenerator::RTF); + + PageSDict::Iterator pdi(*m_subPageDict); + PageDef *subPage=pdi.toFirst(); + for (pdi.toFirst();(subPage=pdi.current());++pdi) + { + SectionInfo::SectionType sectionType = SectionInfo::Paragraph; + switch (m_nestingLevel) + { + case 0: sectionType = SectionInfo::Page; break; + case 1: sectionType = SectionInfo::Section; break; + case 2: sectionType = SectionInfo::Subsection; break; + case 3: sectionType = SectionInfo::Subsubsection; break; + default: sectionType = SectionInfo::Paragraph; break; + } + QCString title = subPage->title(); + if (title.isEmpty()) title = subPage->name(); + ol.startSection(subPage->name(),title,sectionType); + ol.parseText(title); + ol.endSection(subPage->name(),sectionType); + Doxygen::subpageNestingLevel++; + subPage->writePageDocumentation(ol); + Doxygen::subpageNestingLevel--; + } + + ol.popGeneratorState(); + } +} + +bool PageDef::visibleInIndex() const +{ + return // not part of a group + !getGroupDef() && + // not an externally defined page + (!isReference() || Config_getBool("ALLEXTERNALS")) && + // not a subpage + (getOuterScope()==0 || + getOuterScope()->definitionType()!=Definition::TypePage + ); +} + +bool PageDef::documentedPage() const +{ + return // not part of a group + !getGroupDef() && + // not an externally defined page + !isReference(); +} + +bool PageDef::hasSubPages() const +{ + return m_subPageDict->count()>0; +} + +void PageDef::setNestingLevel(int l) +{ + m_nestingLevel = l; +} + +void PageDef::setShowToc(bool b) +{ + m_showToc = b; +} + diff --git a/trunk/src/pagedef.h b/trunk/src/pagedef.h new file mode 100644 index 0000000..54aab2e --- /dev/null +++ b/trunk/src/pagedef.h @@ -0,0 +1,86 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#include "definition.h" +#include "sortdict.h" + +class PageSDict; +class OutputList; + +class PageDef : public Definition +{ + public: + PageDef(const char *f,int l,const char *n,const char *d,const char *t); + ~PageDef(); + + // setters + void setFileName(const char *name) { m_fileName = name; } + void setShowToc(bool b); + + // getters + DefType definitionType() const { return TypePage; } + bool isLinkableInProject() const + { + return /*hasDocumentation() &&*/ !isReference(); + } + bool isLinkable() const + { + return isLinkableInProject() || isReference(); + } + + // functions to get a uniform interface with Definitions + QCString getOutputFileBase() const; + QCString anchor() const { return QCString(); } + void findSectionsInDocumentation(); + QCString title() const { return m_title; } + GroupDef * getGroupDef() const; + PageSDict * getSubPages() const { return m_subPageDict; } + void addInnerCompound(Definition *d); + bool visibleInIndex() const; + bool documentedPage() const; + bool hasSubPages() const; + bool hasParentPage() const; + bool showToc() const { return m_showToc; } + void setPageScope(Definition *d){ m_pageScope = d; } + Definition *getPageScope() const { return m_pageScope; } + QCString displayName() const { return !m_title.isEmpty() ? m_title : Definition::name(); } + + void writeDocumentation(OutputList &ol); + + private: + void setNestingLevel(int l); + void writePageDocumentation(OutputList &ol); + QCString m_fileName; + QCString m_title; + GroupDef *m_inGroup; + PageSDict *m_subPageDict; // list of pages in the group + Definition *m_pageScope; + int m_nestingLevel; + bool m_showToc; +}; + +class PageSDict : public SDict +{ + public: + PageSDict(int size) : SDict(size) {} + virtual ~PageSDict() {} + int compareItems(GCI i1,GCI i2) + { + return stricmp(((PageDef *)i1)->name(),((PageDef *)i2)->name()); + } +}; + diff --git a/trunk/src/parserintf.h b/trunk/src/parserintf.h new file mode 100644 index 0000000..db22088 --- /dev/null +++ b/trunk/src/parserintf.h @@ -0,0 +1,171 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#ifndef PARSERINTF_H +#define PARSERINTF_H + +#include + +class Entry; +class FileDef; +class CodeOutputInterface; +class MemberDef; + +/** \brief Abstract interface for programming language parsers. + * + * By implementing the methods of this interface one can add + * a new language parser to doxygen. The parser can make use of the + * comment block parser to parse the contents of special comment blocks. + */ +class ParserInterface +{ + public: + virtual ~ParserInterface() {} + /** Parses a single input file with the goal to build an Entry tree. + * @param[in] fileName The full name of the file. + * @param[in] fileBuf The contents of the file (zero terminated). + * @param[in,out] root The root of the tree of Entry *nodes + * representing the information extracted from the file. + */ + virtual void parseInput(const char *fileName, + const char *fileBuf, + Entry *root) = 0; + + /** Returns TRUE if the language identified by \a extension needs + * the C preprocessor to be run before feed the result to the input + * parser. + * @see parseInput() + */ + virtual bool needsPreprocessing(const QCString &extension) = 0; + + /** Parses a source file or fragment with the goal to produce + * highlighted and cross-referenced output. + * @param[in] codeOutIntf Abstract interface for writing the result. + * @param[in] scopeName Name of scope to which the code belongs. + * @param[in] input Actual code in the form of a string + * @param[in] isExampleBlock TRUE iff the code is part of an example. + * @param[in] exampleName Name of the example. + * @param[in] fileDef File definition to which the code + * is associated. + * @param[in] startLine Starting line in case of a code fragment. + * @param[in] endLine Ending line of the code fragment. + * @param[in] inlineFragment Code fragment that is to be shown inline + * as part of the documentation. + * @param[in] memberDef Member definition to which the code + * is associated (non null in case of an inline fragment + * for a member). + * @param[in] showLineNumbers if set to TRUE and also fileDef is not 0, + * line numbers will be added to the source fragement + */ + virtual void parseCode(CodeOutputInterface &codeOutIntf, + const char *scopeName, + const QCString &input, + bool isExampleBlock, + const char *exampleName=0, + FileDef *fileDef=0, + int startLine=-1, + int endLine=-1, + bool inlineFragment=FALSE, + MemberDef *memberDef=0, + bool showLineNumbers=TRUE + ) = 0; + + /** Resets the state of the code parser. + * Since multiple code fragments can together form a single example, an + * explicit function is used to reset the code parser state. + * @see parseCode() + */ + virtual void resetCodeParserState() = 0; + + /** Callback function called by the comment block scanner. + * It provides a string \a text containing the prototype of a function + * or variable. The parser should parse this and store the information + * in the Entry node that corresponds with the node for which the + * comment block parser was invoked. + */ + virtual void parsePrototype(const char *text) = 0; + +}; + +//----------------------------------------------------------------------------- + +/** \brief Manages programming language parsers. + * + * This class manages the language parsers in the system. One can + * register parsers, and obtain a parser given a file extension. + */ +class ParserManager +{ + public: + /** Creates the parser manager object. + */ + ParserManager() + : m_defaultParser(0) { m_parsers.setAutoDelete(TRUE); } + + /** Registers an additional parser. + * @param[in] name A symbolic name of the parser, i.e. "c", + * "python", "fortran", "vhdl", ... + * @param[in] parser The parser that is to be used for the + * given name. + * @param[in] defParser Use this parser as the default parser, used + * for unregistered file extensions. + */ + void registerParser(const char *name,ParserInterface *parser,bool defParser=FALSE) + { + if (defParser && m_defaultParser==0) m_defaultParser=parser; + m_parsers.insert(name,parser); + } + + /** Registers a file \a extension with a parser with name \a parserName. + * Returns TRUE if the extension was successfully registered. + */ + bool registerExtension(const char *extension, const char *parserName) + { + if (parserName==0 || extension==0) return FALSE; + ParserInterface *intf = m_parsers.find(parserName); + if (intf==0) return FALSE; + if (m_extensions.find(extension)!=0) // extension already exists + { + m_extensions.remove(extension); // remove it + } + m_extensions.insert(extension,intf); // add new mapping + return TRUE; + } + + /** Gets the interface to the parser associated with given \a extension. + * If there is no parser explicitly registered for the supplied extension, + * the interface to the default parser will be returned. + */ + ParserInterface *getParser(const char *extension) + { + if (extension==0) return m_defaultParser; + QCString ext = QCString(extension).lower(); + ParserInterface *intf = m_extensions.find(ext); + if (intf==0 && ext.length()>4) + { + intf = m_extensions.find(ext.left(4)); + } + return intf ? intf : m_defaultParser; + } + + private: + QDict m_parsers; + QDict m_extensions; + ParserInterface *m_defaultParser; +}; + +#endif diff --git a/trunk/src/perlmodgen.cpp b/trunk/src/perlmodgen.cpp new file mode 100644 index 0000000..054cc56 --- /dev/null +++ b/trunk/src/perlmodgen.cpp @@ -0,0 +1,2930 @@ +/****************************************************************************** + * + * + * + * + * Copyright (C) 1997-2012 by Dimitri van Heesch. + * Authors: Dimitri van Heesch, Miguel Lobo. + * + * 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. + * + */ + +#include + +#include "perlmodgen.h" +#include "docparser.h" +#include "message.h" +#include "doxygen.h" +#include "pagedef.h" + +#include +#include +#include +#include +#include "ftextstream.h" +#include "arguments.h" + +#define PERLOUTPUT_MAX_INDENTATION 40 + +class PerlModOutputStream +{ +public: + + QCString m_s; + FTextStream *m_t; + + PerlModOutputStream(FTextStream *t = 0) : m_t(t) { } + + void add(char c); + void add(const char *s); + void add(QCString &s); + void add(int n); + void add(unsigned int n); +}; + +void PerlModOutputStream::add(char c) +{ + if (m_t != 0) + (*m_t) << c; + else + m_s += c; +} + +void PerlModOutputStream::add(const char *s) +{ + if (m_t != 0) + (*m_t) << s; + else + m_s += s; +} + +void PerlModOutputStream::add(QCString &s) +{ + if (m_t != 0) + (*m_t) << s; + else + m_s += s; +} + +void PerlModOutputStream::add(int n) +{ + if (m_t != 0) + (*m_t) << n; + else + m_s += n; +} + +void PerlModOutputStream::add(unsigned int n) +{ + if (m_t != 0) + (*m_t) << n; + else + m_s += n; +} + +class PerlModOutput +{ +public: + + bool m_pretty; + + inline PerlModOutput(bool pretty) + : m_pretty(pretty), m_stream(0), m_indentation(false), m_blockstart(true) + { + m_spaces[0] = 0; + } + + virtual ~PerlModOutput() { } + + inline void setPerlModOutputStream(PerlModOutputStream *os) { m_stream = os; } + + inline PerlModOutput &openSave() { iopenSave(); return *this; } + inline PerlModOutput &closeSave(QCString &s) { icloseSave(s); return *this; } + + inline PerlModOutput &continueBlock() + { + if (m_blockstart) + m_blockstart = false; + else + m_stream->add(','); + indent(); + return *this; + } + + inline PerlModOutput &add(char c) { m_stream->add(c); return *this; } + inline PerlModOutput &add(const char *s) { m_stream->add(s); return *this; } + inline PerlModOutput &add(QCString &s) { m_stream->add(s); return *this; } + inline PerlModOutput &add(int n) { m_stream->add(n); return *this; } + inline PerlModOutput &add(unsigned int n) { m_stream->add(n); return *this; } + + PerlModOutput &addQuoted(const char *s) { iaddQuoted(s); return *this; } + + inline PerlModOutput &indent() + { + if (m_pretty) { + m_stream->add('\n'); + m_stream->add(m_spaces); + } + return *this; + } + + inline PerlModOutput &open(char c, const char *s = 0) { iopen(c, s); return *this; } + inline PerlModOutput &close(char c = 0) { iclose(c); return *this; } + + inline PerlModOutput &addField(const char *s) { iaddField(s); return *this; } + inline PerlModOutput &addFieldQuotedChar(const char *field, char content) + { + iaddFieldQuotedChar(field, content); return *this; + } + inline PerlModOutput &addFieldQuotedString(const char *field, const char *content) + { + iaddFieldQuotedString(field, content); return *this; + } + inline PerlModOutput &addFieldBoolean(const char *field, bool content) + { + return addFieldQuotedString(field, content ? "yes" : "no"); + } + inline PerlModOutput &openList(const char *s = 0) { open('[', s); return *this; } + inline PerlModOutput &closeList() { close(']'); return *this; } + inline PerlModOutput &openHash(const char *s = 0 ) { open('{', s); return *this; } + inline PerlModOutput &closeHash() { close('}'); return *this; } + +protected: + + void iopenSave(); + void icloseSave(QCString &); + + void incIndent(); + void decIndent(); + + void iaddQuoted(const char *); + void iaddFieldQuotedChar(const char *, char); + void iaddFieldQuotedString(const char *, const char *); + void iaddField(const char *); + + void iopen(char, const char *); + void iclose(char); + +private: + + PerlModOutputStream *m_stream; + int m_indentation; + bool m_blockstart; + + QStack m_saved; + char m_spaces[PERLOUTPUT_MAX_INDENTATION * 2 + 2]; +}; + +void PerlModOutput::iopenSave() +{ + m_saved.push(m_stream); + m_stream = new PerlModOutputStream(); +} + +void PerlModOutput::icloseSave(QCString &s) +{ + s = m_stream->m_s; + delete m_stream; + m_stream = m_saved.pop(); +} + +void PerlModOutput::incIndent() +{ + if (m_indentation < PERLOUTPUT_MAX_INDENTATION) + { + char *s = &m_spaces[m_indentation * 2]; + *s++ = ' '; *s++ = ' '; *s = 0; + } + m_indentation++; +} + +void PerlModOutput::decIndent() +{ + m_indentation--; + if (m_indentation < PERLOUTPUT_MAX_INDENTATION) + m_spaces[m_indentation * 2] = 0; +} + +void PerlModOutput::iaddQuoted(const char *s) +{ + char c; + while ((c = *s++) != 0) { + if ((c == '\'') || (c == '\\')) + m_stream->add('\\'); + m_stream->add(c); + } +} + +void PerlModOutput::iaddField(const char *s) +{ + continueBlock(); + m_stream->add(s); + m_stream->add(m_pretty ? " => " : "=>"); +} + +void PerlModOutput::iaddFieldQuotedChar(const char *field, char content) +{ + iaddField(field); + m_stream->add('\''); + if ((content == '\'') || (content == '\\')) + m_stream->add('\\'); + m_stream->add(content); + m_stream->add('\''); +} + +void PerlModOutput::iaddFieldQuotedString(const char *field, const char *content) +{ + if (content == 0) + return; + iaddField(field); + m_stream->add('\''); + iaddQuoted(content); + m_stream->add('\''); +} + +void PerlModOutput::iopen(char c, const char *s) +{ + if (s != 0) + iaddField(s); + else + continueBlock(); + m_stream->add(c); + incIndent(); + m_blockstart = true; +} + +void PerlModOutput::iclose(char c) +{ + decIndent(); + indent(); + if (c != 0) + m_stream->add(c); + m_blockstart = false; +} + +/*! @brief Concrete visitor implementation for PerlMod output. */ +class PerlModDocVisitor : public DocVisitor +{ +public: + PerlModDocVisitor(PerlModOutput &); + virtual ~PerlModDocVisitor() { } + + void finish(); + + //-------------------------------------- + // visitor functions for leaf nodes + //-------------------------------------- + + void visit(DocWord *); + void visit(DocLinkedWord *); + void visit(DocWhiteSpace *); + void visit(DocSymbol *); + void visit(DocURL *); + void visit(DocLineBreak *); + void visit(DocHorRuler *); + void visit(DocStyleChange *); + void visit(DocVerbatim *); + void visit(DocAnchor *); + void visit(DocInclude *); + void visit(DocIncOperator *); + void visit(DocFormula *); + void visit(DocIndexEntry *); + void visit(DocSimpleSectSep *); + void visit(DocCite *); + + //-------------------------------------- + // visitor functions for compound nodes + //-------------------------------------- + + void visitPre(DocAutoList *); + void visitPost(DocAutoList *); + void visitPre(DocAutoListItem *); + void visitPost(DocAutoListItem *); + void visitPre(DocPara *) ; + void visitPost(DocPara *); + void visitPre(DocRoot *); + void visitPost(DocRoot *); + void visitPre(DocSimpleSect *); + void visitPost(DocSimpleSect *); + void visitPre(DocTitle *); + void visitPost(DocTitle *); + void visitPre(DocSimpleList *); + void visitPost(DocSimpleList *); + void visitPre(DocSimpleListItem *); + void visitPost(DocSimpleListItem *); + void visitPre(DocSection *); + void visitPost(DocSection *); + void visitPre(DocHtmlList *); + void visitPost(DocHtmlList *) ; + void visitPre(DocHtmlListItem *); + void visitPost(DocHtmlListItem *); + //void visitPre(DocHtmlPre *); + //void visitPost(DocHtmlPre *); + void visitPre(DocHtmlDescList *); + void visitPost(DocHtmlDescList *); + void visitPre(DocHtmlDescTitle *); + void visitPost(DocHtmlDescTitle *); + void visitPre(DocHtmlDescData *); + void visitPost(DocHtmlDescData *); + void visitPre(DocHtmlTable *); + void visitPost(DocHtmlTable *); + void visitPre(DocHtmlRow *); + void visitPost(DocHtmlRow *) ; + void visitPre(DocHtmlCell *); + void visitPost(DocHtmlCell *); + void visitPre(DocHtmlCaption *); + void visitPost(DocHtmlCaption *); + void visitPre(DocInternal *); + void visitPost(DocInternal *); + void visitPre(DocHRef *); + void visitPost(DocHRef *); + void visitPre(DocHtmlHeader *); + void visitPost(DocHtmlHeader *); + void visitPre(DocImage *); + void visitPost(DocImage *); + void visitPre(DocDotFile *); + void visitPost(DocDotFile *); + void visitPre(DocMscFile *); + void visitPost(DocMscFile *); + void visitPre(DocLink *); + void visitPost(DocLink *); + void visitPre(DocRef *); + void visitPost(DocRef *); + void visitPre(DocSecRefItem *); + void visitPost(DocSecRefItem *); + void visitPre(DocSecRefList *); + void visitPost(DocSecRefList *); + //void visitPre(DocLanguage *); + //void visitPost(DocLanguage *); + void visitPre(DocParamSect *); + void visitPost(DocParamSect *); + void visitPre(DocParamList *); + void visitPost(DocParamList *); + void visitPre(DocXRefItem *); + void visitPost(DocXRefItem *); + void visitPre(DocInternalRef *); + void visitPost(DocInternalRef *); + void visitPre(DocCopy *); + void visitPost(DocCopy *); + void visitPre(DocText *); + void visitPost(DocText *); + void visitPre(DocHtmlBlockQuote *); + void visitPost(DocHtmlBlockQuote *); + +private: + + //-------------------------------------- + // helper functions + //-------------------------------------- + + void addLink(const QCString &ref, const QCString &file, + const QCString &anchor); + + void enterText(); + void leaveText(); + + void openItem(const char *); + void closeItem(); + void singleItem(const char *); + void openSubBlock(const char * = 0); + void closeSubBlock(); + void openOther(); + void closeOther(); + + //-------------------------------------- + // state variables + //-------------------------------------- + + PerlModOutput &m_output; + bool m_textmode; + bool m_textblockstart; + QCString m_other; +}; + +PerlModDocVisitor::PerlModDocVisitor(PerlModOutput &output) + : DocVisitor(DocVisitor_Other), m_output(output), m_textmode(false) +{ + m_output.openList("doc"); +} + +void PerlModDocVisitor::finish() +{ + leaveText(); + m_output.closeList() + .add(m_other); +} + +void PerlModDocVisitor::addLink(const QCString &,const QCString &file,const QCString &anchor) +{ + QCString link = file; + if (!anchor.isEmpty()) + (link += "_1") += anchor; + m_output.addFieldQuotedString("link", link); +} + +void PerlModDocVisitor::openItem(const char *name) +{ + leaveText(); + m_output.openHash().addFieldQuotedString("type", name); +} + +void PerlModDocVisitor::closeItem() +{ + leaveText(); + m_output.closeHash(); +} + +void PerlModDocVisitor::enterText() +{ + if (m_textmode) + return; + openItem("text"); + m_output.addField("content").add('\''); + m_textmode = true; +} + +void PerlModDocVisitor::leaveText() +{ + if (!m_textmode) + return; + m_textmode = false; + m_output + .add('\'') + .closeHash(); +} + +void PerlModDocVisitor::singleItem(const char *name) +{ + openItem(name); + closeItem(); +} + +void PerlModDocVisitor::openSubBlock(const char *s) +{ + leaveText(); + m_output.openList(s); + m_textblockstart = true; +} + +void PerlModDocVisitor::closeSubBlock() +{ + leaveText(); + m_output.closeList(); +} + +void PerlModDocVisitor::openOther() +{ + // Using a secondary text stream will corrupt the perl file. Instead of + // printing doc => [ data => [] ], it will print doc => [] data => []. + /* + leaveText(); + m_output.openSave(); + */ +} + +void PerlModDocVisitor::closeOther() +{ + // Using a secondary text stream will corrupt the perl file. Instead of + // printing doc => [ data => [] ], it will print doc => [] data => []. + /* + QCString other; + leaveText(); + m_output.closeSave(other); + m_other += other; + */ +} + +void PerlModDocVisitor::visit(DocWord *w) +{ + enterText(); + m_output.addQuoted(w->word()); +} + +void PerlModDocVisitor::visit(DocLinkedWord *w) +{ + openItem("url"); + addLink(w->ref(), w->file(), w->anchor()); + m_output.addFieldQuotedString("content", w->word()); + closeItem(); +} + +void PerlModDocVisitor::visit(DocWhiteSpace *) +{ + enterText(); + m_output.add(' '); +} + +void PerlModDocVisitor::visit(DocSymbol *sy) +{ + char c = 0; + const char *s = 0; + const char *accent = 0; + const char *symbol = 0; + switch(sy->symbol()) + { + case DocSymbol::At: c = '@'; break; + case DocSymbol::Less: c = '<'; break; + case DocSymbol::Greater: c = '>'; break; + case DocSymbol::Amp: c = '&'; break; + case DocSymbol::Dollar: c = '$'; break; + case DocSymbol::Hash: c = '#'; break; + case DocSymbol::DoubleColon: s = "::"; break; + case DocSymbol::Percent: c = '%'; break; + case DocSymbol::Quot: c = '"'; break; + case DocSymbol::Lsquo: s = "\\\'"; break; + case DocSymbol::Rsquo: s = "\\\'"; break; + case DocSymbol::Ldquo: c = '"'; break; + case DocSymbol::Rdquo: c = '"'; break; + case DocSymbol::Ndash: c = '-'; break; + case DocSymbol::Mdash: s = "--"; break; + case DocSymbol::Nbsp: c = ' '; break; + case DocSymbol::Uml: accent = "umlaut"; break; + case DocSymbol::Acute: accent = "acute"; break; + case DocSymbol::Grave: accent = "grave"; break; + case DocSymbol::Circ: accent = "circ"; break; + case DocSymbol::Slash: accent = "slash"; break; + case DocSymbol::Tilde: accent = "tilde"; break; + case DocSymbol::Cedil: accent = "cedilla"; break; + case DocSymbol::Ring: accent = "ring"; break; + case DocSymbol::BSlash: s = "\\\\"; break; + case DocSymbol::Copy: symbol = "copyright"; break; + case DocSymbol::Tm: symbol = "trademark"; break; + case DocSymbol::Reg: symbol = "registered"; break; + case DocSymbol::Szlig: symbol = "szlig"; break; + case DocSymbol::Apos: s = "\\\'"; break; + case DocSymbol::Aelig: symbol = "aelig"; break; + case DocSymbol::AElig: symbol = "AElig"; break; + case DocSymbol::Unknown: err("error: unknown symbol found\n"); + break; + } + if (c != 0) + { + enterText(); + m_output.add(c); + } + else if (s != 0) + { + enterText(); + m_output.add(s); + } + else if (symbol != 0) + { + leaveText(); + openItem("symbol"); + m_output.addFieldQuotedString("symbol", symbol); + closeItem(); + } + else if (accent != 0) + { + leaveText(); + openItem("accent"); + m_output + .addFieldQuotedString("accent", accent) + .addFieldQuotedChar("letter", sy->letter()); + closeItem(); + } +} + +void PerlModDocVisitor::visit(DocURL *u) +{ + openItem("url"); + m_output.addFieldQuotedString("content", u->url()); + closeItem(); +} + +void PerlModDocVisitor::visit(DocLineBreak *) { singleItem("linebreak"); } +void PerlModDocVisitor::visit(DocHorRuler *) { singleItem("hruler"); } + +void PerlModDocVisitor::visit(DocStyleChange *s) +{ + const char *style = 0; + switch (s->style()) + { + case DocStyleChange::Bold: style = "bold"; break; + case DocStyleChange::Italic: style = "italic"; break; + case DocStyleChange::Code: style = "code"; break; + case DocStyleChange::Subscript: style = "subscript"; break; + case DocStyleChange::Superscript: style = "superscript"; break; + case DocStyleChange::Center: style = "center"; break; + case DocStyleChange::Small: style = "small"; break; + case DocStyleChange::Preformatted: style = "preformatted"; break; + case DocStyleChange::Div: style = "div"; break; + case DocStyleChange::Span: style = "span"; break; + + } + openItem("style"); + m_output.addFieldQuotedString("style", style) + .addFieldBoolean("enable", s->enable()); + closeItem(); +} + +void PerlModDocVisitor::visit(DocVerbatim *s) +{ + const char *type = 0; + switch(s->type()) + { + case DocVerbatim::Code: +#if 0 + m_output.add(""); + parseCode(m_ci,s->context(),s->text(),FALSE,0); + m_output.add(""); +#endif + return; + case DocVerbatim::Verbatim: type = "preformatted"; break; + case DocVerbatim::HtmlOnly: type = "htmlonly"; break; + case DocVerbatim::ManOnly: type = "manonly"; break; + case DocVerbatim::LatexOnly: type = "latexonly"; break; + case DocVerbatim::XmlOnly: type = "xmlonly"; break; + case DocVerbatim::Dot: type = "dot"; break; + case DocVerbatim::Msc: type = "msc"; break; + } + openItem(type); + m_output.addFieldQuotedString("content", s->text()); + closeItem(); +} + +void PerlModDocVisitor::visit(DocAnchor *anc) +{ + QCString anchor = anc->file() + "_1" + anc->anchor(); + openItem("anchor"); + m_output.addFieldQuotedString("id", anchor); + closeItem(); +} + +void PerlModDocVisitor::visit(DocInclude *inc) +{ + const char *type = 0; + switch(inc->type()) + { + case DocInclude::IncWithLines: + #if 0 + { + m_t << "
    ";
    +         QFileInfo cfi( inc->file() );
    +         FileDef fd( cfi.dirPath(), cfi.fileName() );
    +         parseCode(m_ci,inc->context(),inc->text().latin1(),inc->isExample(),inc->exampleFile(), &fd);
    +         m_t << "
    "; + } + break; + #endif + return; + case DocInclude::Include: +#if 0 + m_output.add(""); + parseCode(m_ci,inc->context(),inc->text(),FALSE,0); + m_output.add(""); +#endif + return; + case DocInclude::DontInclude: return; + case DocInclude::HtmlInclude: type = "htmlonly"; break; + case DocInclude::VerbInclude: type = "preformatted"; break; + case DocInclude::Snippet: return; + } + openItem(type); + m_output.addFieldQuotedString("content", inc->text()); + closeItem(); +} + +void PerlModDocVisitor::visit(DocIncOperator *) +{ +#if 0 + //printf("DocIncOperator: type=%d first=%d, last=%d text=`%s'\n", + // op->type(),op->isFirst(),op->isLast(),op->text().data()); + if (op->isFirst()) + { + m_output.add(""); + } + if (op->type()!=DocIncOperator::Skip) + { + parseCode(m_ci,op->context(),op->text(),FALSE,0); + } + if (op->isLast()) + { + m_output.add(""); + } + else + { + m_output.add('\n'); + } +#endif +} + +void PerlModDocVisitor::visit(DocFormula *f) +{ + openItem("formula"); + QCString id; + id += f->id(); + m_output.addFieldQuotedString("id", id).addFieldQuotedString("content", f->text()); + closeItem(); +} + +void PerlModDocVisitor::visit(DocIndexEntry *) +{ +#if 0 + m_output.add("" + ""); + m_output.addQuoted(ie->entry()); + m_output.add("" + "" + ""); +#endif +} + +void PerlModDocVisitor::visit(DocSimpleSectSep *) +{ +} + +void PerlModDocVisitor::visit(DocCite *cite) +{ + openItem("cite"); + m_output.addFieldQuotedString("text", cite->text()); + closeItem(); +} + + +//-------------------------------------- +// visitor functions for compound nodes +//-------------------------------------- + +void PerlModDocVisitor::visitPre(DocAutoList *l) +{ + openItem("list"); + m_output.addFieldQuotedString("style", l->isEnumList() ? "ordered" : "itemized"); + openSubBlock("content"); +} + +void PerlModDocVisitor::visitPost(DocAutoList *) +{ + closeSubBlock(); + closeItem(); +} + +void PerlModDocVisitor::visitPre(DocAutoListItem *) +{ + openSubBlock(); +} + +void PerlModDocVisitor::visitPost(DocAutoListItem *) +{ + closeSubBlock(); +} + +void PerlModDocVisitor::visitPre(DocPara *) +{ + if (m_textblockstart) + m_textblockstart = false; + else + singleItem("parbreak"); + /* + openItem("para"); + openSubBlock("content"); + */ +} + +void PerlModDocVisitor::visitPost(DocPara *) +{ + /* + closeSubBlock(); + closeItem(); + */ +} + +void PerlModDocVisitor::visitPre(DocRoot *) +{ +} + +void PerlModDocVisitor::visitPost(DocRoot *) +{ +} + +void PerlModDocVisitor::visitPre(DocSimpleSect *s) +{ + const char *type = 0; + switch (s->type()) + { + case DocSimpleSect::See: type = "see"; break; + case DocSimpleSect::Return: type = "return"; break; + case DocSimpleSect::Author: type = "author"; break; + case DocSimpleSect::Authors: type = "authors"; break; + case DocSimpleSect::Version: type = "version"; break; + case DocSimpleSect::Since: type = "since"; break; + case DocSimpleSect::Date: type = "date"; break; + case DocSimpleSect::Note: type = "note"; break; + case DocSimpleSect::Warning: type = "warning"; break; + case DocSimpleSect::Pre: type = "pre"; break; + case DocSimpleSect::Post: type = "post"; break; + case DocSimpleSect::Copyright: type = "copyright"; break; + case DocSimpleSect::Invar: type = "invariant"; break; + case DocSimpleSect::Remark: type = "remark"; break; + case DocSimpleSect::Attention: type = "attention"; break; + case DocSimpleSect::User: type = "par"; break; + case DocSimpleSect::Rcs: type = "rcs"; break; + case DocSimpleSect::Unknown: + err("error: unknown simple section found\n"); + break; + } + leaveText(); + m_output.openHash(); + openOther(); + openSubBlock(type); +} + +void PerlModDocVisitor::visitPost(DocSimpleSect *) +{ + closeSubBlock(); + closeOther(); + m_output.closeHash(); +} + +void PerlModDocVisitor::visitPre(DocTitle *) +{ + openItem("title"); + openSubBlock("content"); +} + +void PerlModDocVisitor::visitPost(DocTitle *) +{ + closeSubBlock(); + closeItem(); +} + +void PerlModDocVisitor::visitPre(DocSimpleList *) +{ + openItem("list"); + m_output.addFieldQuotedString("style", "itemized"); + openSubBlock("content"); +} + +void PerlModDocVisitor::visitPost(DocSimpleList *) +{ + closeSubBlock(); + closeItem(); +} + +void PerlModDocVisitor::visitPre(DocSimpleListItem *) { openSubBlock(); } +void PerlModDocVisitor::visitPost(DocSimpleListItem *) { closeSubBlock(); } + +void PerlModDocVisitor::visitPre(DocSection *s) +{ + QCString sect = QCString().sprintf("sect%d",s->level()); + openItem(sect); + openSubBlock("content"); +} + +void PerlModDocVisitor::visitPost(DocSection *) +{ + closeSubBlock(); + closeItem(); +} + +void PerlModDocVisitor::visitPre(DocHtmlList *l) +{ + openItem("list"); + m_output.addFieldQuotedString("style", (l->type() == DocHtmlList::Ordered) ? "ordered" : "itemized"); + openSubBlock("content"); +} + +void PerlModDocVisitor::visitPost(DocHtmlList *) +{ + closeSubBlock(); + closeItem(); +} + +void PerlModDocVisitor::visitPre(DocHtmlListItem *) { openSubBlock(); } +void PerlModDocVisitor::visitPost(DocHtmlListItem *) { closeSubBlock(); } + +//void PerlModDocVisitor::visitPre(DocHtmlPre *) +//{ +// openItem("preformatted"); +// openSubBlock("content"); +// //m_insidePre=TRUE; +//} + +//void PerlModDocVisitor::visitPost(DocHtmlPre *) +//{ +// //m_insidePre=FALSE; +// closeSubBlock(); +// closeItem(); +//} + +void PerlModDocVisitor::visitPre(DocHtmlDescList *) +{ +#if 0 + m_output.add("\n"); +#endif +} + +void PerlModDocVisitor::visitPost(DocHtmlDescList *) +{ +#if 0 + m_output.add("\n"); +#endif +} + +void PerlModDocVisitor::visitPre(DocHtmlDescTitle *) +{ +#if 0 + m_output.add(""); +#endif +} + +void PerlModDocVisitor::visitPost(DocHtmlDescTitle *) +{ +#if 0 + m_output.add("\n"); +#endif +} + +void PerlModDocVisitor::visitPre(DocHtmlDescData *) +{ +#if 0 + m_output.add(""); +#endif +} + +void PerlModDocVisitor::visitPost(DocHtmlDescData *) +{ +#if 0 + m_output.add("\n"); +#endif +} + +void PerlModDocVisitor::visitPre(DocHtmlTable *) +{ +#if 0 + m_output.add("numRows()); + m_output.add("\" cols=\""); m_output.add(t->numCols()); m_output.add("\">"); +#endif +} + +void PerlModDocVisitor::visitPost(DocHtmlTable *) +{ +#if 0 + m_output.add("
    \n"); +#endif +} + +void PerlModDocVisitor::visitPre(DocHtmlRow *) +{ +#if 0 + m_output.add("\n"); +#endif +} + +void PerlModDocVisitor::visitPost(DocHtmlRow *) +{ +#if 0 + m_output.add("\n"); +#endif +} + +void PerlModDocVisitor::visitPre(DocHtmlCell *) +{ +#if 0 + if (c->isHeading()) m_output.add(""); else m_output.add(""); +#endif +} + +void PerlModDocVisitor::visitPost(DocHtmlCell *) +{ +#if 0 + m_output.add(""); +#endif +} + +void PerlModDocVisitor::visitPre(DocHtmlCaption *) +{ +#if 0 + m_output.add(""); +#endif +} + +void PerlModDocVisitor::visitPost(DocHtmlCaption *) +{ +#if 0 + m_output.add("\n"); +#endif +} + +void PerlModDocVisitor::visitPre(DocInternal *) +{ +#if 0 + m_output.add(""); +#endif +} + +void PerlModDocVisitor::visitPost(DocInternal *) +{ +#if 0 + m_output.add(""); +#endif +} + +void PerlModDocVisitor::visitPre(DocHRef *) +{ +#if 0 + m_output.add("url()); m_output.add("\">"); +#endif +} + +void PerlModDocVisitor::visitPost(DocHRef *) +{ +#if 0 + m_output.add(""); +#endif +} + +void PerlModDocVisitor::visitPre(DocHtmlHeader *) +{ +#if 0 + m_output.add("level()); m_output.add(">"); +#endif +} + +void PerlModDocVisitor::visitPost(DocHtmlHeader *) +{ +#if 0 + m_output.add("level()); m_output.add(">\n"); +#endif +} + +void PerlModDocVisitor::visitPre(DocImage *) +{ +#if 0 + m_output.add("type()) + { + case DocImage::Html: m_output.add("html"); break; + case DocImage::Latex: m_output.add("latex"); break; + case DocImage::Rtf: m_output.add("rtf"); break; + } + m_output.add("\""); + + QCString baseName=img->name(); + int i; + if ((i=baseName.findRev('/'))!=-1 || (i=baseName.findRev('\\'))!=-1) + { + baseName=baseName.right(baseName.length()-i-1); + } + m_output.add(" name=\""); m_output.add(baseName); m_output.add("\""); + if (!img->width().isEmpty()) + { + m_output.add(" width=\""); + m_output.addQuoted(img->width()); + m_output.add("\""); + } + else if (!img->height().isEmpty()) + { + m_output.add(" height=\""); + m_output.addQuoted(img->height()); + m_output.add("\""); + } + m_output.add(">"); +#endif +} + +void PerlModDocVisitor::visitPost(DocImage *) +{ +#if 0 + m_output.add(""); +#endif +} + +void PerlModDocVisitor::visitPre(DocDotFile *) +{ +#if 0 + m_output.add("file()); m_output.add("\">"); +#endif +} + +void PerlModDocVisitor::visitPost(DocDotFile *) +{ +#if 0 + m_output.add(""); +#endif +} +void PerlModDocVisitor::visitPre(DocMscFile *) +{ +#if 0 + m_output.add("file()); m_output.add("\">"); +#endif +} + +void PerlModDocVisitor::visitPost(DocMscFile *) +{ +#if 0 + m_output.add(""); +#endif +} + + +void PerlModDocVisitor::visitPre(DocLink *lnk) +{ + openItem("link"); + addLink(lnk->ref(), lnk->file(), lnk->anchor()); +} + +void PerlModDocVisitor::visitPost(DocLink *) +{ + closeItem(); +} + +void PerlModDocVisitor::visitPre(DocRef *ref) +{ + openItem("ref"); + if (!ref->hasLinkText()) + m_output.addFieldQuotedString("text", ref->targetTitle()); + openSubBlock("content"); +} + +void PerlModDocVisitor::visitPost(DocRef *) +{ + closeSubBlock(); + closeItem(); +} + +void PerlModDocVisitor::visitPre(DocSecRefItem *) +{ +#if 0 + m_output.add("file()); m_output.add("_1"); m_output.add(ref->anchor()); m_output.add("\">"); +#endif +} + +void PerlModDocVisitor::visitPost(DocSecRefItem *) +{ +#if 0 + m_output.add(""); +#endif +} + +void PerlModDocVisitor::visitPre(DocSecRefList *) +{ +#if 0 + m_output.add(""); +#endif +} + +void PerlModDocVisitor::visitPost(DocSecRefList *) +{ +#if 0 + m_output.add(""); +#endif +} + +//void PerlModDocVisitor::visitPre(DocLanguage *l) +//{ +// openItem("language"); +// m_output.addFieldQuotedString("id", l->id()); +//} +// +//void PerlModDocVisitor::visitPost(DocLanguage *) +//{ +// closeItem(); +//} + +void PerlModDocVisitor::visitPre(DocParamSect *s) +{ + leaveText(); + const char *type = 0; + switch(s->type()) + { + case DocParamSect::Param: type = "params"; break; + case DocParamSect::RetVal: type = "retvals"; break; + case DocParamSect::Exception: type = "exceptions"; break; + case DocParamSect::TemplateParam: type = "templateparam"; break; + case DocParamSect::Unknown: + err("error: unknown parameter section found\n"); + break; + } + openOther(); + openSubBlock(type); +} + +void PerlModDocVisitor::visitPost(DocParamSect *) +{ + closeSubBlock(); + closeOther(); +} + +void PerlModDocVisitor::visitPre(DocParamList *pl) +{ + leaveText(); + m_output.openHash() + .openList("parameters"); + //QStrListIterator li(pl->parameters()); + //const char *s; + QListIterator li(pl->parameters()); + DocNode *param; + for (li.toFirst();(param=li.current());++li) + { + QCString s; + if (param->kind()==DocNode::Kind_Word) + { + s = ((DocWord*)param)->word(); + } + else if (param->kind()==DocNode::Kind_LinkedWord) + { + s = ((DocLinkedWord*)param)->word(); + } + m_output.openHash() + .addFieldQuotedString("name", s) + .closeHash(); + } + m_output.closeList() + .openList("doc"); +} + +void PerlModDocVisitor::visitPost(DocParamList *) +{ + leaveText(); + m_output.closeList() + .closeHash(); +} + +void PerlModDocVisitor::visitPre(DocXRefItem *) +{ +#if 0 + m_output.add("file()); m_output.add("_1"); m_output.add(x->anchor()); + m_output.add("\">"); + m_output.add(""); + m_output.addQuoted(x->title()); + m_output.add(""); + m_output.add(""); +#endif + openItem("xrefitem"); + openSubBlock("content"); +} + +void PerlModDocVisitor::visitPost(DocXRefItem *) +{ + closeSubBlock(); + closeItem(); +#if 0 + m_output.add(""); + m_output.add(""); +#endif +} + +void PerlModDocVisitor::visitPre(DocInternalRef *ref) +{ + openItem("ref"); + addLink(0,ref->file(),ref->anchor()); + openSubBlock("content"); +} + +void PerlModDocVisitor::visitPost(DocInternalRef *) +{ + closeSubBlock(); + closeItem(); +} + +void PerlModDocVisitor::visitPre(DocCopy *) +{ +} + +void PerlModDocVisitor::visitPost(DocCopy *) +{ +} + +void PerlModDocVisitor::visitPre(DocText *) +{ +} + +void PerlModDocVisitor::visitPost(DocText *) +{ +} + +void PerlModDocVisitor::visitPre(DocHtmlBlockQuote *) +{ + openItem("blockquote"); + openSubBlock("content"); +} + +void PerlModDocVisitor::visitPost(DocHtmlBlockQuote *) +{ + closeSubBlock(); + closeItem(); +} + +static void addTemplateArgumentList(ArgumentList *al,PerlModOutput &output,const char *) +{ + QCString indentStr; + if (!al) + return; + output.openList("template_parameters"); + ArgumentListIterator ali(*al); + Argument *a; + for (ali.toFirst();(a=ali.current());++ali) + { + output.openHash(); + if (!a->type.isEmpty()) + output.addFieldQuotedString("type", a->type); + if (!a->name.isEmpty()) + output.addFieldQuotedString("declaration_name", a->name) + .addFieldQuotedString("definition_name", a->name); + if (!a->defval.isEmpty()) + output.addFieldQuotedString("default", a->defval); + output.closeHash(); + } + output.closeList(); +} + +#if 0 +static void addMemberTemplateLists(MemberDef *md,PerlModOutput &output) +{ + ClassDef *cd = md->getClassDef(); + const char *cname = cd ? cd->name().data() : 0; + if (md->templateArguments()) // function template prefix + addTemplateArgumentList(md->templateArguments(),output,cname); +} +#endif + +static void addTemplateList(ClassDef *cd,PerlModOutput &output) +{ + addTemplateArgumentList(cd->templateArguments(),output,cd->name()); +} + +static void addPerlModDocBlock(PerlModOutput &output, + const char *name, + const QCString &fileName, + int lineNr, + Definition *scope, + MemberDef *md, + const QCString &text) +{ + QCString stext = text.stripWhiteSpace(); + if (stext.isEmpty()) + output.addField(name).add("{}"); + else { + DocNode *root = validatingParseDoc(fileName,lineNr,scope,md,stext,FALSE,0); + output.openHash(name); + PerlModDocVisitor *visitor = new PerlModDocVisitor(output); + root->accept(visitor); + visitor->finish(); + output.closeHash(); + delete visitor; + delete root; + } +} + +static const char *getProtectionName(Protection prot) +{ + switch (prot) + { + case Public: return "public"; + case Protected: return "protected"; + case Private: return "private"; + case Package: return "package"; + } + return 0; +} + +static const char *getVirtualnessName(Specifier virt) +{ + switch(virt) + { + case Normal: return "non_virtual"; + case Virtual: return "virtual"; + case Pure: return "pure_virtual"; + } + return 0; +} + +static QCString pathDoxyfile; +static QCString pathDoxyExec; + +void setPerlModDoxyfile(const QCString &qs) +{ + pathDoxyfile = qs; + pathDoxyExec = QDir::currentDirPath(); +} + +class PerlModGenerator +{ +public: + + PerlModOutput m_output; + + QCString pathDoxyStructurePM; + QCString pathDoxyDocsTex; + QCString pathDoxyFormatTex; + QCString pathDoxyLatexTex; + QCString pathDoxyLatexDVI; + QCString pathDoxyLatexPDF; + QCString pathDoxyStructureTex; + QCString pathDoxyDocsPM; + QCString pathDoxyLatexPL; + QCString pathDoxyLatexStructurePL; + QCString pathDoxyRules; + QCString pathMakefile; + + inline PerlModGenerator(bool pretty) : m_output(pretty) { } + + void generatePerlModForMember(MemberDef *md, Definition *); + void generatePerlModSection(Definition *d, MemberList *ml, + const char *name, const char *header=0); + void addListOfAllMembers(ClassDef *cd); + void generatePerlModForClass(ClassDef *cd); + void generatePerlModForNamespace(NamespaceDef *nd); + void generatePerlModForFile(FileDef *fd); + void generatePerlModForGroup(GroupDef *gd); + void generatePerlModForPage(PageDef *pi); + + bool createOutputFile(QFile &f, const char *s); + bool createOutputDir(QDir &perlModDir); + bool generateDoxyLatexTex(); + bool generateDoxyFormatTex(); + bool generateDoxyStructurePM(); + bool generateDoxyLatexPL(); + bool generateDoxyLatexStructurePL(); + bool generateDoxyRules(); + bool generateMakefile(); + bool generatePerlModOutput(); + + void generate(); +}; + +void PerlModGenerator::generatePerlModForMember(MemberDef *md,Definition *) +{ + // + declaration/definition arg lists + // + reimplements + // + reimplementedBy + // + exceptions + // + const/volatile specifiers + // - examples + // - source definition + // - source references + // - source referenced by + // - body code + // - template arguments + // (templateArguments(), definitionTemplateParameterLists()) + + QCString memType; + bool isFunc=FALSE; + switch (md->memberType()) + { + case MemberDef::Define: memType="define"; break; + case MemberDef::EnumValue: memType="enumvalue"; break; + case MemberDef::Property: memType="property"; break; + case MemberDef::Variable: memType="variable"; break; + case MemberDef::Typedef: memType="typedef"; break; + case MemberDef::Enumeration: memType="enum"; break; + case MemberDef::Function: memType="function"; isFunc=TRUE; break; + case MemberDef::Signal: memType="signal"; isFunc=TRUE; break; + //case MemberDef::Prototype: memType="prototype"; isFunc=TRUE; break; + case MemberDef::Friend: memType="friend"; isFunc=TRUE; break; + case MemberDef::DCOP: memType="dcop"; isFunc=TRUE; break; + case MemberDef::Slot: memType="slot"; isFunc=TRUE; break; + case MemberDef::Event: memType="event"; break; + } + + m_output.openHash() + .addFieldQuotedString("kind", memType) + .addFieldQuotedString("name", md->name()) + .addFieldQuotedString("virtualness", getVirtualnessName(md->virtualness())) + .addFieldQuotedString("protection", getProtectionName(md->protection())) + .addFieldBoolean("static", md->isStatic()); + + addPerlModDocBlock(m_output,"brief",md->getDefFileName(),md->getDefLine(),md->getOuterScope(),md,md->briefDescription()); + addPerlModDocBlock(m_output,"detailed",md->getDefFileName(),md->getDefLine(),md->getOuterScope(),md,md->documentation()); + if (md->memberType()!=MemberDef::Define && + md->memberType()!=MemberDef::Enumeration) + m_output.addFieldQuotedString("type", md->typeString()); + + LockingPtr al = md->argumentList(); + if (isFunc) //function + { + m_output.addFieldBoolean("const", al!=0 && al->constSpecifier) + .addFieldBoolean("volatile", al!=0 && al->volatileSpecifier); + + m_output.openList("parameters"); + LockingPtr declAl = md->declArgumentList(); + LockingPtr defAl = md->argumentList(); + if (declAl!=0 && declAl->count()>0) + { + ArgumentListIterator declAli(*declAl); + ArgumentListIterator defAli(*defAl); + Argument *a; + for (declAli.toFirst();(a=declAli.current());++declAli) + { + Argument *defArg = defAli.current(); + m_output.openHash(); + + if (!a->name.isEmpty()) + m_output.addFieldQuotedString("declaration_name", a->name); + + if (defArg && !defArg->name.isEmpty() && defArg->name!=a->name) + m_output.addFieldQuotedString("definition_name", defArg->name); + + if (!a->type.isEmpty()) + m_output.addFieldQuotedString("type", a->type); + + if (!a->array.isEmpty()) + m_output.addFieldQuotedString("array", a->array); + + if (!a->defval.isEmpty()) + m_output.addFieldQuotedString("default_value", a->defval); + + if (!a->attrib.isEmpty()) + m_output.addFieldQuotedString("attributes", a->attrib); + + m_output.closeHash(); + if (defArg) ++defAli; + } + } + m_output.closeList(); + } + else if (md->memberType()==MemberDef::Define && + md->argsString()!=0) // define + { + m_output.openList("parameters"); + ArgumentListIterator ali(*al); + Argument *a; + for (ali.toFirst();(a=ali.current());++ali) + { + m_output.openHash() + .addFieldQuotedString("name", a->type) + .closeHash(); + } + m_output.closeList(); + } + else if (md->argsString()!=0) + { + m_output.addFieldQuotedString("arguments", md->argsString()); + } + + if (!md->initializer().isEmpty()) + m_output.addFieldQuotedString("initializer", md->initializer()); + + if (md->excpString()) + m_output.addFieldQuotedString("exceptions", md->excpString()); + + if (md->memberType()==MemberDef::Enumeration) // enum + { + LockingPtr enumFields = md->enumFieldList(); + if (enumFields!=0) + { + m_output.openList("values"); + MemberListIterator emli(*enumFields); + MemberDef *emd; + for (emli.toFirst();(emd=emli.current());++emli) + { + m_output.openHash() + .addFieldQuotedString("name", emd->name()); + + if (!emd->initializer().isEmpty()) + m_output.addFieldQuotedString("initializer", emd->initializer()); + + addPerlModDocBlock(m_output,"brief",emd->getDefFileName(),emd->getDefLine(),emd->getOuterScope(),emd,emd->briefDescription()); + + addPerlModDocBlock(m_output,"detailed",emd->getDefFileName(),emd->getDefLine(),emd->getOuterScope(),emd,emd->documentation()); + + m_output.closeHash(); + } + m_output.closeList(); + } + } + + MemberDef *rmd = md->reimplements(); + if (rmd) + m_output.openHash("reimplements") + .addFieldQuotedString("name", rmd->name()) + .closeHash(); + + LockingPtr rbml = md->reimplementedBy(); + if (rbml!=0) + { + MemberListIterator mli(*rbml); + m_output.openList("reimplemented_by"); + for (mli.toFirst();(rmd=mli.current());++mli) + m_output.openHash() + .addFieldQuotedString("name", rmd->name()) + .closeHash(); + m_output.closeList(); + } + + m_output.closeHash(); +} + +void PerlModGenerator::generatePerlModSection(Definition *d, + MemberList *ml,const char *name,const char *header) +{ + if (ml==0) return; // empty list + + m_output.openHash(name); + + if (header) + m_output.addFieldQuotedString("header", header); + + m_output.openList("members"); + MemberListIterator mli(*ml); + MemberDef *md; + for (mli.toFirst();(md=mli.current());++mli) + { + generatePerlModForMember(md,d); + } + m_output.closeList() + .closeHash(); +} + +void PerlModGenerator::addListOfAllMembers(ClassDef *cd) +{ + m_output.openList("all_members"); + if (cd->memberNameInfoSDict()) + { + MemberNameInfoSDict::Iterator mnii(*cd->memberNameInfoSDict()); + MemberNameInfo *mni; + for (mnii.toFirst();(mni=mnii.current());++mnii) + { + MemberNameInfoIterator mii(*mni); + MemberInfo *mi; + for (mii.toFirst();(mi=mii.current());++mii) + { + MemberDef *md=mi->memberDef; + ClassDef *cd=md->getClassDef(); + Definition *d=md->getGroupDef(); + if (d==0) d = cd; + + m_output.openHash() + .addFieldQuotedString("name", md->name()) + .addFieldQuotedString("virtualness", getVirtualnessName(md->virtualness())) + .addFieldQuotedString("protection", getProtectionName(mi->prot)); + + if (!mi->ambiguityResolutionScope.isEmpty()) + m_output.addFieldQuotedString("ambiguity_scope", mi->ambiguityResolutionScope); + + m_output.addFieldQuotedString("scope", cd->name()) + .closeHash(); + } + } + } + m_output.closeList(); +} + +void PerlModGenerator::generatePerlModForClass(ClassDef *cd) +{ + // + brief description + // + detailed description + // + template argument list(s) + // - include file + // + member groups + // + inheritance diagram + // + list of direct super classes + // + list of direct sub classes + // + list of inner classes + // + collaboration diagram + // + list of all members + // + user defined member sections + // + standard member sections + // + detailed member documentation + // - examples using the class + + if (cd->isReference()) return; // skip external references. + if (cd->name().find('@')!=-1) return; // skip anonymous compounds. + if (cd->templateMaster()!=0) return; // skip generated template instances. + + m_output.openHash() + .addFieldQuotedString("name", cd->name()); + + if (cd->baseClasses()) + { + m_output.openList("base"); + BaseClassListIterator bcli(*cd->baseClasses()); + BaseClassDef *bcd; + for (bcli.toFirst();(bcd=bcli.current());++bcli) + m_output.openHash() + .addFieldQuotedString("name", bcd->classDef->displayName()) + .addFieldQuotedString("virtualness", getVirtualnessName(bcd->virt)) + .addFieldQuotedString("protection", getProtectionName(bcd->prot)) + .closeHash(); + m_output.closeList(); + } + + if (cd->subClasses()) + { + m_output.openList("derived"); + BaseClassListIterator bcli(*cd->subClasses()); + BaseClassDef *bcd; + for (bcli.toFirst();(bcd=bcli.current());++bcli) + m_output.openHash() + .addFieldQuotedString("name", bcd->classDef->displayName()) + .addFieldQuotedString("virtualness", getVirtualnessName(bcd->virt)) + .addFieldQuotedString("protection", getProtectionName(bcd->prot)) + .closeHash(); + m_output.closeList(); + } + + ClassSDict *cl = cd->getClassSDict(); + if (cl) + { + m_output.openList("inner"); + ClassSDict::Iterator cli(*cl); + ClassDef *cd; + for (cli.toFirst();(cd=cli.current());++cli) + m_output.openHash() + .addFieldQuotedString("name", cd->name()) + .closeHash(); + m_output.closeList(); + } + + IncludeInfo *ii=cd->includeInfo(); + if (ii) + { + QCString nm = ii->includeName; + if (nm.isEmpty() && ii->fileDef) nm = ii->fileDef->docName(); + if (!nm.isEmpty()) + { + m_output.openHash("includes"); +#if 0 + if (ii->fileDef && !ii->fileDef->isReference()) // TODO: support external references + t << " id=\"" << ii->fileDef->getOutputFileBase() << "\""; +#endif + m_output.addFieldBoolean("local", ii->local) + .addFieldQuotedString("name", nm) + .closeHash(); + } + } + + addTemplateList(cd,m_output); + addListOfAllMembers(cd); + if (cd->getMemberGroupSDict()) + { + MemberGroupSDict::Iterator mgli(*cd->getMemberGroupSDict()); + MemberGroup *mg; + for (;(mg=mgli.current());++mgli) + generatePerlModSection(cd,mg->members(),"user_defined",mg->header()); + } + + generatePerlModSection(cd,cd->getMemberList(MemberList::pubTypes),"public_typedefs"); + generatePerlModSection(cd,cd->getMemberList(MemberList::pubMethods),"public_methods"); + generatePerlModSection(cd,cd->getMemberList(MemberList::pubAttribs),"public_members"); + generatePerlModSection(cd,cd->getMemberList(MemberList::pubSlots),"public_slots"); + generatePerlModSection(cd,cd->getMemberList(MemberList::signals),"signals"); + generatePerlModSection(cd,cd->getMemberList(MemberList::dcopMethods),"dcop_methods"); + generatePerlModSection(cd,cd->getMemberList(MemberList::properties),"properties"); + generatePerlModSection(cd,cd->getMemberList(MemberList::pubStaticMethods),"public_static_methods"); + generatePerlModSection(cd,cd->getMemberList(MemberList::pubStaticAttribs),"public_static_members"); + generatePerlModSection(cd,cd->getMemberList(MemberList::proTypes),"protected_typedefs"); + generatePerlModSection(cd,cd->getMemberList(MemberList::proMethods),"protected_methods"); + generatePerlModSection(cd,cd->getMemberList(MemberList::proAttribs),"protected_members"); + generatePerlModSection(cd,cd->getMemberList(MemberList::proSlots),"protected_slots"); + generatePerlModSection(cd,cd->getMemberList(MemberList::proStaticMethods),"protected_static_methods"); + generatePerlModSection(cd,cd->getMemberList(MemberList::proStaticAttribs),"protected_static_members"); + generatePerlModSection(cd,cd->getMemberList(MemberList::priTypes),"private_typedefs"); + generatePerlModSection(cd,cd->getMemberList(MemberList::priMethods),"private_methods"); + generatePerlModSection(cd,cd->getMemberList(MemberList::priAttribs),"private_members"); + generatePerlModSection(cd,cd->getMemberList(MemberList::priSlots),"private_slots"); + generatePerlModSection(cd,cd->getMemberList(MemberList::priStaticMethods),"private_static_methods"); + generatePerlModSection(cd,cd->getMemberList(MemberList::priStaticAttribs),"private_static_members"); + generatePerlModSection(cd,cd->getMemberList(MemberList::friends),"friend_methods"); + generatePerlModSection(cd,cd->getMemberList(MemberList::related),"related_methods"); + + addPerlModDocBlock(m_output,"brief",cd->getDefFileName(),cd->getDefLine(),cd,0,cd->briefDescription()); + addPerlModDocBlock(m_output,"detailed",cd->getDefFileName(),cd->getDefLine(),cd,0,cd->documentation()); + +#if 0 + DotClassGraph inheritanceGraph(cd,DotClassGraph::Inheritance); + if (!inheritanceGraph.isTrivial()) + { + t << " " << endl; + inheritanceGraph.writePerlMod(t); + t << " " << endl; + } + DotClassGraph collaborationGraph(cd,DotClassGraph::Implementation); + if (!collaborationGraph.isTrivial()) + { + t << " " << endl; + collaborationGraph.writePerlMod(t); + t << " " << endl; + } + t << " getDefFileName() << "\" line=\"" + << cd->getDefLine() << "\""; + if (cd->getStartBodyLine()!=-1) + { + t << " bodystart=\"" << cd->getStartBodyLine() << "\" bodyend=\"" + << cd->getEndBodyLine() << "\""; + } + t << "/>" << endl; +#endif + + m_output.closeHash(); +} + +void PerlModGenerator::generatePerlModForNamespace(NamespaceDef *nd) +{ + // + contained class definitions + // + contained namespace definitions + // + member groups + // + normal members + // + brief desc + // + detailed desc + // + location + // - files containing (parts of) the namespace definition + + if (nd->isReference()) return; // skip external references + + m_output.openHash() + .addFieldQuotedString("name", nd->name()); + + ClassSDict *cl = nd->getClassSDict(); + if (cl) + { + m_output.openList("classes"); + ClassSDict::Iterator cli(*cl); + ClassDef *cd; + for (cli.toFirst();(cd=cli.current());++cli) + m_output.openHash() + .addFieldQuotedString("name", cd->name()) + .closeHash(); + m_output.closeList(); + } + + NamespaceSDict *nl = nd->getNamespaceSDict(); + if (nl) + { + m_output.openList("namespaces"); + NamespaceSDict::Iterator nli(*nl); + NamespaceDef *nd; + for (nli.toFirst();(nd=nli.current());++nli) + m_output.openHash() + .addFieldQuotedString("name", nd->name()) + .closeHash(); + m_output.closeList(); + } + + if (nd->getMemberGroupSDict()) + { + MemberGroupSDict::Iterator mgli(*nd->getMemberGroupSDict()); + MemberGroup *mg; + for (;(mg=mgli.current());++mgli) + generatePerlModSection(nd,mg->members(),"user-defined",mg->header()); + } + + generatePerlModSection(nd,nd->getMemberList(MemberList::decDefineMembers),"defines"); + generatePerlModSection(nd,nd->getMemberList(MemberList::decProtoMembers),"prototypes"); + generatePerlModSection(nd,nd->getMemberList(MemberList::decTypedefMembers),"typedefs"); + generatePerlModSection(nd,nd->getMemberList(MemberList::decEnumMembers),"enums"); + generatePerlModSection(nd,nd->getMemberList(MemberList::decFuncMembers),"functions"); + generatePerlModSection(nd,nd->getMemberList(MemberList::decVarMembers),"variables"); + + addPerlModDocBlock(m_output,"brief",nd->getDefFileName(),nd->getDefLine(),0,0,nd->briefDescription()); + addPerlModDocBlock(m_output,"detailed",nd->getDefFileName(),nd->getDefLine(),0,0,nd->documentation()); + + m_output.closeHash(); +} + +void PerlModGenerator::generatePerlModForFile(FileDef *fd) +{ + // + includes files + // + includedby files + // - include graph + // - included by graph + // - contained class definitions + // - contained namespace definitions + // - member groups + // + normal members + // + brief desc + // + detailed desc + // - source code + // - location + // - number of lines + + if (fd->isReference()) return; + + m_output.openHash() + .addFieldQuotedString("name", fd->name()); + + IncludeInfo *inc; + m_output.openList("includes"); + if (fd->includeFileList()) + { + QListIterator ili1(*fd->includeFileList()); + for (ili1.toFirst();(inc=ili1.current());++ili1) + { + m_output.openHash() + .addFieldQuotedString("name", inc->includeName); + if (inc->fileDef && !inc->fileDef->isReference()) + { + m_output.addFieldQuotedString("ref", inc->fileDef->getOutputFileBase()); + } + m_output.closeHash(); + } + } + m_output.closeList(); + + m_output.openList("included_by"); + if (fd->includedByFileList()) + { + QListIterator ili2(*fd->includedByFileList()); + for (ili2.toFirst();(inc=ili2.current());++ili2) + { + m_output.openHash() + .addFieldQuotedString("name", inc->includeName); + if (inc->fileDef && !inc->fileDef->isReference()) + { + m_output.addFieldQuotedString("ref", inc->fileDef->getOutputFileBase()); + } + m_output.closeHash(); + } + } + m_output.closeList(); + + generatePerlModSection(fd,fd->getMemberList(MemberList::decDefineMembers),"defines"); + generatePerlModSection(fd,fd->getMemberList(MemberList::decProtoMembers),"prototypes"); + generatePerlModSection(fd,fd->getMemberList(MemberList::decTypedefMembers),"typedefs"); + generatePerlModSection(fd,fd->getMemberList(MemberList::decEnumMembers),"enums"); + generatePerlModSection(fd,fd->getMemberList(MemberList::decFuncMembers),"functions"); + generatePerlModSection(fd,fd->getMemberList(MemberList::decVarMembers),"variables"); + + addPerlModDocBlock(m_output,"brief",fd->getDefFileName(),fd->getDefLine(),0,0,fd->briefDescription()); + addPerlModDocBlock(m_output,"detailed",fd->getDefFileName(),fd->getDefLine(),0,0,fd->documentation()); + + m_output.closeHash(); +} + +void PerlModGenerator::generatePerlModForGroup(GroupDef *gd) +{ + // + members + // + member groups + // + files + // + classes + // + namespaces + // - packages + // + pages + // + child groups + // - examples + // + brief description + // + detailed description + + if (gd->isReference()) return; // skip external references + + m_output.openHash() + .addFieldQuotedString("name", gd->name()) + .addFieldQuotedString("title", gd->groupTitle()); + + FileList *fl = gd->getFiles(); + if (fl) + { + m_output.openList("files"); + QListIterator fli(*fl); + FileDef *fd = fl->first(); + for (fli.toFirst();(fd=fli.current());++fli) + m_output.openHash() + .addFieldQuotedString("name", fd->name()) + .closeHash(); + m_output.closeList(); + } + + ClassSDict *cl = gd->getClasses(); + if (cl) + { + m_output.openList("classes"); + ClassSDict::Iterator cli(*cl); + ClassDef *cd; + for (cli.toFirst();(cd=cli.current());++cli) + m_output.openHash() + .addFieldQuotedString("name", cd->name()) + .closeHash(); + m_output.closeList(); + } + + NamespaceSDict *nl = gd->getNamespaces(); + if (nl) + { + m_output.openList("namespaces"); + NamespaceSDict::Iterator nli(*nl); + NamespaceDef *nd; + for (nli.toFirst();(nd=nli.current());++nli) + m_output.openHash() + .addFieldQuotedString("name", nd->name()) + .closeHash(); + m_output.closeList(); + } + + PageSDict *pl = gd->getPages(); + if (pl) + { + m_output.openList("pages"); + PageSDict::Iterator pli(*pl); + PageDef *pd; + for (pli.toFirst();(pd=pli.current());++pli) + m_output.openHash() + .addFieldQuotedString("title", pd->title()) + .closeHash(); + m_output.closeList(); + } + + GroupList *gl = gd->getSubGroups(); + if (gl) + { + m_output.openList("groups"); + GroupListIterator gli(*gl); + GroupDef *sgd; + for (gli.toFirst();(sgd=gli.current());++gli) + m_output.openHash() + .addFieldQuotedString("title", sgd->groupTitle()) + .closeHash(); + m_output.closeList(); + } + + if (gd->getMemberGroupSDict()) + { + MemberGroupSDict::Iterator mgli(*gd->getMemberGroupSDict()); + MemberGroup *mg; + for (;(mg=mgli.current());++mgli) + generatePerlModSection(gd,mg->members(),"user-defined",mg->header()); + } + + generatePerlModSection(gd,gd->getMemberList(MemberList::decDefineMembers),"defines"); + generatePerlModSection(gd,gd->getMemberList(MemberList::decProtoMembers),"prototypes"); + generatePerlModSection(gd,gd->getMemberList(MemberList::decTypedefMembers),"typedefs"); + generatePerlModSection(gd,gd->getMemberList(MemberList::decEnumMembers),"enums"); + generatePerlModSection(gd,gd->getMemberList(MemberList::decFuncMembers),"functions"); + generatePerlModSection(gd,gd->getMemberList(MemberList::decVarMembers),"variables"); + + addPerlModDocBlock(m_output,"brief",gd->getDefFileName(),gd->getDefLine(),0,0,gd->briefDescription()); + addPerlModDocBlock(m_output,"detailed",gd->getDefFileName(),gd->getDefLine(),0,0,gd->documentation()); + + m_output.closeHash(); +} + +void PerlModGenerator::generatePerlModForPage(PageDef *pd) +{ + // + name + // + title + // + documentation + + if (pd->isReference()) return; + + m_output.openHash() + .addFieldQuotedString("name", pd->name()); + + SectionInfo *si = Doxygen::sectionDict.find(pd->name()); + if (si) + m_output.addFieldQuotedString("title", si->title); + + addPerlModDocBlock(m_output,"detailed",pd->docFile(),pd->docLine(),0,0,pd->documentation()); + m_output.closeHash(); +} + +bool PerlModGenerator::generatePerlModOutput() +{ + QFile outputFile; + if (!createOutputFile(outputFile, pathDoxyDocsPM)) + return false; + + FTextStream outputTextStream(&outputFile); + PerlModOutputStream outputStream(&outputTextStream); + m_output.setPerlModOutputStream(&outputStream); + m_output.add("$doxydocs=").openHash(); + + m_output.openList("classes"); + ClassSDict::Iterator cli(*Doxygen::classSDict); + ClassDef *cd; + for (cli.toFirst();(cd=cli.current());++cli) + generatePerlModForClass(cd); + m_output.closeList(); + + m_output.openList("namespaces"); + NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict); + NamespaceDef *nd; + for (nli.toFirst();(nd=nli.current());++nli) + generatePerlModForNamespace(nd); + m_output.closeList(); + + m_output.openList("files"); + FileNameListIterator fnli(*Doxygen::inputNameList); + FileName *fn; + for (;(fn=fnli.current());++fnli) + { + FileNameIterator fni(*fn); + FileDef *fd; + for (;(fd=fni.current());++fni) + generatePerlModForFile(fd); + } + m_output.closeList(); + + m_output.openList("groups"); + GroupSDict::Iterator gli(*Doxygen::groupSDict); + GroupDef *gd; + for (;(gd=gli.current());++gli) + { + generatePerlModForGroup(gd); + } + m_output.closeList(); + + m_output.openList("pages"); + PageSDict::Iterator pdi(*Doxygen::pageSDict); + PageDef *pd=0; + for (pdi.toFirst();(pd=pdi.current());++pdi) + { + generatePerlModForPage(pd); + } + if (Doxygen::mainPage) + { + generatePerlModForPage(Doxygen::mainPage); + } + m_output.closeList(); + + m_output.closeHash().add(";\n1;\n"); + return true; +} + +bool PerlModGenerator::createOutputFile(QFile &f, const char *s) +{ + f.setName(s); + if (!f.open(IO_WriteOnly)) + { + err("Cannot open file %s for writing!\n", s); + return false; + } + return true; +} + +bool PerlModGenerator::createOutputDir(QDir &perlModDir) +{ + QCString outputDirectory = Config_getString("OUTPUT_DIRECTORY"); + if (outputDirectory.isEmpty()) + { + outputDirectory=QDir::currentDirPath(); + } + else + { + QDir dir(outputDirectory); + if (!dir.exists()) + { + dir.setPath(QDir::currentDirPath()); + if (!dir.mkdir(outputDirectory)) + { + err("error: tag OUTPUT_DIRECTORY: Output directory `%s' does not " + "exist and cannot be created\n",outputDirectory.data()); + exit(1); + } + else if (!Config_getBool("QUIET")) + { + err("notice: Output directory `%s' does not exist. " + "I have created it for you.\n", outputDirectory.data()); + } + dir.cd(outputDirectory); + } + outputDirectory=dir.absPath(); + } + + QDir dir(outputDirectory); + if (!dir.exists()) + { + dir.setPath(QDir::currentDirPath()); + if (!dir.mkdir(outputDirectory)) + { + err("Cannot create directory %s\n",outputDirectory.data()); + return false; + } + } + + perlModDir.setPath(outputDirectory+"/perlmod"); + if (!perlModDir.exists() && !perlModDir.mkdir(outputDirectory+"/perlmod")) + { + err("Could not create perlmod directory in %s\n",outputDirectory.data()); + return false; + } + return true; +} + +bool PerlModGenerator::generateDoxyStructurePM() +{ + QFile doxyModelPM; + if (!createOutputFile(doxyModelPM, pathDoxyStructurePM)) + return false; + + FTextStream doxyModelPMStream(&doxyModelPM); + doxyModelPMStream << + "sub memberlist($) {\n" + " my $prefix = $_[0];\n" + " return\n" + "\t[ \"hash\", $prefix . \"s\",\n" + "\t {\n" + "\t members =>\n" + "\t [ \"list\", $prefix . \"List\",\n" + "\t\t[ \"hash\", $prefix,\n" + "\t\t {\n" + "\t\t kind => [ \"string\", $prefix . \"Kind\" ],\n" + "\t\t name => [ \"string\", $prefix . \"Name\" ],\n" + "\t\t static => [ \"string\", $prefix . \"Static\" ],\n" + "\t\t virtualness => [ \"string\", $prefix . \"Virtualness\" ],\n" + "\t\t protection => [ \"string\", $prefix . \"Protection\" ],\n" + "\t\t type => [ \"string\", $prefix . \"Type\" ],\n" + "\t\t parameters =>\n" + "\t\t [ \"list\", $prefix . \"Params\",\n" + "\t\t\t[ \"hash\", $prefix . \"Param\",\n" + "\t\t\t {\n" + "\t\t\t declaration_name => [ \"string\", $prefix . \"ParamName\" ],\n" + "\t\t\t type => [ \"string\", $prefix . \"ParamType\" ],\n" + "\t\t\t },\n" + "\t\t\t],\n" + "\t\t ],\n" + "\t\t detailed =>\n" + "\t\t [ \"hash\", $prefix . \"Detailed\",\n" + "\t\t\t{\n" + "\t\t\t doc => [ \"doc\", $prefix . \"DetailedDoc\" ],\n" + "\t\t\t return => [ \"doc\", $prefix . \"Return\" ],\n" + "\t\t\t see => [ \"doc\", $prefix . \"See\" ],\n" + "\t\t\t params =>\n" + "\t\t\t [ \"list\", $prefix . \"PDBlocks\",\n" + "\t\t\t [ \"hash\", $prefix . \"PDBlock\",\n" + "\t\t\t\t{\n" + "\t\t\t\t parameters =>\n" + "\t\t\t\t [ \"list\", $prefix . \"PDParams\",\n" + "\t\t\t\t [ \"hash\", $prefix . \"PDParam\",\n" + "\t\t\t\t\t{\n" + "\t\t\t\t\t name => [ \"string\", $prefix . \"PDParamName\" ],\n" + "\t\t\t\t\t},\n" + "\t\t\t\t ],\n" + "\t\t\t\t ],\n" + "\t\t\t\t doc => [ \"doc\", $prefix . \"PDDoc\" ],\n" + "\t\t\t\t},\n" + "\t\t\t ],\n" + "\t\t\t ],\n" + "\t\t\t},\n" + "\t\t ],\n" + "\t\t },\n" + "\t\t],\n" + "\t ],\n" + "\t },\n" + "\t];\n" + "}\n" + "\n" + "$doxystructure =\n" + " [ \"hash\", \"Root\",\n" + " {\n" + "\tfiles =>\n" + "\t [ \"list\", \"Files\",\n" + "\t [ \"hash\", \"File\",\n" + "\t {\n" + "\t\tname => [ \"string\", \"FileName\" ],\n" + "\t\ttypedefs => memberlist(\"FileTypedef\"),\n" + "\t\tvariables => memberlist(\"FileVariable\"),\n" + "\t\tfunctions => memberlist(\"FileFunction\"),\n" + "\t\tdetailed =>\n" + "\t\t [ \"hash\", \"FileDetailed\",\n" + "\t\t {\n" + "\t\t doc => [ \"doc\", \"FileDetailedDoc\" ],\n" + "\t\t },\n" + "\t\t ],\n" + "\t },\n" + "\t ],\n" + "\t ],\n" + "\tpages =>\n" + "\t [ \"list\", \"Pages\",\n" + "\t [ \"hash\", \"Page\",\n" + "\t {\n" + "\t\tname => [ \"string\", \"PageName\" ],\n" + "\t\tdetailed =>\n" + "\t\t [ \"hash\", \"PageDetailed\",\n" + "\t\t {\n" + "\t\t doc => [ \"doc\", \"PageDetailedDoc\" ],\n" + "\t\t },\n" + "\t\t ],\n" + "\t },\n" + "\t ],\n" + "\t ],\n" + "\tclasses =>\n" + "\t [ \"list\", \"Classes\",\n" + "\t [ \"hash\", \"Class\",\n" + "\t {\n" + "\t\tname => [ \"string\", \"ClassName\" ],\n" + "\t\tpublic_typedefs => memberlist(\"ClassPublicTypedef\"),\n" + "\t\tpublic_methods => memberlist(\"ClassPublicMethod\"),\n" + "\t\tpublic_members => memberlist(\"ClassPublicMember\"),\n" + "\t\tprotected_typedefs => memberlist(\"ClassProtectedTypedef\"),\n" + "\t\tprotected_methods => memberlist(\"ClassProtectedMethod\"),\n" + "\t\tprotected_members => memberlist(\"ClassProtectedMember\"),\n" + "\t\tprivate_typedefs => memberlist(\"ClassPrivateTypedef\"),\n" + "\t\tprivate_methods => memberlist(\"ClassPrivateMethod\"),\n" + "\t\tprivate_members => memberlist(\"ClassPrivateMember\"),\n" + "\t\tdetailed =>\n" + "\t\t [ \"hash\", \"ClassDetailed\",\n" + "\t\t {\n" + "\t\t doc => [ \"doc\", \"ClassDetailedDoc\" ],\n" + "\t\t },\n" + "\t\t ],\n" + "\t },\n" + "\t ],\n" + "\t ],\n" + "\tgroups =>\n" + "\t [ \"list\", \"Groups\",\n" + "\t [ \"hash\", \"Group\",\n" + "\t {\n" + "\t\tname => [ \"string\", \"GroupName\" ],\n" + "\t\ttitle => [ \"string\", \"GroupTitle\" ],\n" + "\t\tfiles =>\n" + "\t\t [ \"list\", \"Files\",\n" + "\t\t [ \"hash\", \"File\",\n" + "\t\t {\n" + "\t\t name => [ \"string\", \"Filename\" ]\n" + "\t\t }\n" + "\t\t ],\n" + "\t\t ],\n" + "\t\tclasses =>\n" + "\t\t [ \"list\", \"Classes\",\n" + "\t\t [ \"hash\", \"Class\",\n" + "\t\t {\n" + "\t\t name => [ \"string\", \"Classname\" ]\n" + "\t\t }\n" + "\t\t ],\n" + "\t\t ],\n" + "\t\tnamespaces =>\n" + "\t\t [ \"list\", \"Namespaces\",\n" + "\t\t [ \"hash\", \"Namespace\",\n" + "\t\t {\n" + "\t\t name => [ \"string\", \"NamespaceName\" ]\n" + "\t\t }\n" + "\t\t ],\n" + "\t\t ],\n" + "\t\tpages =>\n" + "\t\t [ \"list\", \"Pages\",\n" + "\t\t [ \"hash\", \"Page\"," + "\t\t {\n" + "\t\t title => [ \"string\", \"PageName\" ]\n" + "\t\t }\n" + "\t\t ],\n" + "\t\t ],\n" + "\t\tgroups =>\n" + "\t\t [ \"list\", \"Groups\",\n" + "\t\t [ \"hash\", \"Group\",\n" + "\t\t {\n" + "\t\t title => [ \"string\", \"GroupName\" ]\n" + "\t\t }\n" + "\t\t ],\n" + "\t\t ],\n" + "\t\tfunctions => memberlist(\"GroupFunction\"),\n" + "\t\tdetailed =>\n" + "\t\t [ \"hash\", \"GroupDetailed\",\n" + "\t\t {\n" + "\t\t doc => [ \"doc\", \"GroupDetailedDoc\" ],\n" + "\t\t },\n" + "\t\t ],\n" + "\t }\n" + "\t ],\n" + "\t ],\n" + " },\n" + " ];\n" + "\n" + "1;\n"; + + return true; +} + +bool PerlModGenerator::generateDoxyRules() +{ + QFile doxyRules; + if (!createOutputFile(doxyRules, pathDoxyRules)) + return false; + + bool perlmodLatex = Config_getBool("PERLMOD_LATEX"); + QCString prefix = Config_getString("PERLMOD_MAKEVAR_PREFIX"); + + FTextStream doxyRulesStream(&doxyRules); + doxyRulesStream << + prefix << "DOXY_EXEC_PATH = " << pathDoxyExec << "\n" << + prefix << "DOXYFILE = " << pathDoxyfile << "\n" << + prefix << "DOXYDOCS_PM = " << pathDoxyDocsPM << "\n" << + prefix << "DOXYSTRUCTURE_PM = " << pathDoxyStructurePM << "\n" << + prefix << "DOXYRULES = " << pathDoxyRules << "\n"; + if (perlmodLatex) + doxyRulesStream << + prefix << "DOXYLATEX_PL = " << pathDoxyLatexPL << "\n" << + prefix << "DOXYLATEXSTRUCTURE_PL = " << pathDoxyLatexStructurePL << "\n" << + prefix << "DOXYSTRUCTURE_TEX = " << pathDoxyStructureTex << "\n" << + prefix << "DOXYDOCS_TEX = " << pathDoxyDocsTex << "\n" << + prefix << "DOXYFORMAT_TEX = " << pathDoxyFormatTex << "\n" << + prefix << "DOXYLATEX_TEX = " << pathDoxyLatexTex << "\n" << + prefix << "DOXYLATEX_DVI = " << pathDoxyLatexDVI << "\n" << + prefix << "DOXYLATEX_PDF = " << pathDoxyLatexPDF << "\n"; + + doxyRulesStream << + "\n" + ".PHONY: clean-perlmod\n" + "clean-perlmod::\n" + "\trm -f $(" << prefix << "DOXYSTRUCTURE_PM) \\\n" + "\t$(" << prefix << "DOXYDOCS_PM)"; + if (perlmodLatex) + doxyRulesStream << + " \\\n" + "\t$(" << prefix << "DOXYLATEX_PL) \\\n" + "\t$(" << prefix << "DOXYLATEXSTRUCTURE_PL) \\\n" + "\t$(" << prefix << "DOXYDOCS_TEX) \\\n" + "\t$(" << prefix << "DOXYSTRUCTURE_TEX) \\\n" + "\t$(" << prefix << "DOXYFORMAT_TEX) \\\n" + "\t$(" << prefix << "DOXYLATEX_TEX) \\\n" + "\t$(" << prefix << "DOXYLATEX_PDF) \\\n" + "\t$(" << prefix << "DOXYLATEX_DVI) \\\n" + "\t$(addprefix $(" << prefix << "DOXYLATEX_TEX:tex=),out aux log)"; + doxyRulesStream << "\n\n"; + + doxyRulesStream << + "$(" << prefix << "DOXYRULES) \\\n" + "$(" << prefix << "DOXYMAKEFILE) \\\n" + "$(" << prefix << "DOXYSTRUCTURE_PM) \\\n" + "$(" << prefix << "DOXYDOCS_PM)"; + if (perlmodLatex) { + doxyRulesStream << + " \\\n" + "$(" << prefix << "DOXYLATEX_PL) \\\n" + "$(" << prefix << "DOXYLATEXSTRUCTURE_PL) \\\n" + "$(" << prefix << "DOXYFORMAT_TEX) \\\n" + "$(" << prefix << "DOXYLATEX_TEX)"; + } + doxyRulesStream << + ": \\\n" + "\t$(" << prefix << "DOXYFILE)\n" + "\tcd $(" << prefix << "DOXY_EXEC_PATH) ; doxygen \"$<\"\n"; + + if (perlmodLatex) { + doxyRulesStream << + "\n" + "$(" << prefix << "DOXYDOCS_TEX): \\\n" + "$(" << prefix << "DOXYLATEX_PL) \\\n" + "$(" << prefix << "DOXYDOCS_PM)\n" + "\tperl -I\"$(\"$@\"\n" + "\n" + "$(" << prefix << "DOXYSTRUCTURE_TEX): \\\n" + "$(" << prefix << "DOXYLATEXSTRUCTURE_PL) \\\n" + "$(" << prefix << "DOXYSTRUCTURE_PM)\n" + "\tperl -I\"$(\"$@\"\n" + "\n" + "$(" << prefix << "DOXYLATEX_PDF) \\\n" + "$(" << prefix << "DOXYLATEX_DVI): \\\n" + "$(" << prefix << "DOXYLATEX_TEX) \\\n" + "$(" << prefix << "DOXYFORMAT_TEX) \\\n" + "$(" << prefix << "DOXYSTRUCTURE_TEX) \\\n" + "$(" << prefix << "DOXYDOCS_TEX)\n" + "\n" + "$(" << prefix << "DOXYLATEX_PDF): \\\n" + "$(" << prefix << "DOXYLATEX_TEX)\n" + "\tpdflatex -interaction=nonstopmode \"$<\"\n" + "\n" + "$(" << prefix << "DOXYLATEX_DVI): \\\n" + "$(" << prefix << "DOXYLATEX_TEX)\n" + "\tlatex -interaction=nonstopmode \"$<\"\n"; + } + + return true; +} + +bool PerlModGenerator::generateMakefile() +{ + QFile makefile; + if (!createOutputFile(makefile, pathMakefile)) + return false; + + bool perlmodLatex = Config_getBool("PERLMOD_LATEX"); + QCString prefix = Config_getString("PERLMOD_MAKEVAR_PREFIX"); + + FTextStream makefileStream(&makefile); + makefileStream << + ".PHONY: default clean" << (perlmodLatex ? " pdf" : "") << "\n" + "default: " << (perlmodLatex ? "pdf" : "clean") << "\n" + "\n" + "include " << pathDoxyRules << "\n" + "\n" + "clean: clean-perlmod\n"; + + if (perlmodLatex) { + makefileStream << + "pdf: $(" << prefix << "DOXYLATEX_PDF)\n" + "dvi: $(" << prefix << "DOXYLATEX_DVI)\n"; + } + + return true; +} + +bool PerlModGenerator::generateDoxyLatexStructurePL() +{ + QFile doxyLatexStructurePL; + if (!createOutputFile(doxyLatexStructurePL, pathDoxyLatexStructurePL)) + return false; + + FTextStream doxyLatexStructurePLStream(&doxyLatexStructurePL); + doxyLatexStructurePLStream << + "use DoxyStructure;\n" + "\n" + "sub process($) {\n" + "\tmy $node = $_[0];\n" + "\tmy ($type, $name) = @$node[0, 1];\n" + "\tmy $command;\n" + "\tif ($type eq \"string\") { $command = \"String\" }\n" + "\telsif ($type eq \"doc\") { $command = \"Doc\" }\n" + "\telsif ($type eq \"hash\") {\n" + "\t\t$command = \"Hash\";\n" + "\t\tfor my $subnode (values %{$$node[2]}) {\n" + "\t\t\tprocess($subnode);\n" + "\t\t}\n" + "\t}\n" + "\telsif ($type eq \"list\") {\n" + "\t\t$command = \"List\";\n" + "\t\tprocess($$node[2]);\n" + "\t}\n" + "\tprint \"\\\\\" . $command . \"Node{\" . $name . \"}%\\n\";\n" + "}\n" + "\n" + "process($doxystructure);\n"; + + return true; +} + +bool PerlModGenerator::generateDoxyLatexPL() +{ + QFile doxyLatexPL; + if (!createOutputFile(doxyLatexPL, pathDoxyLatexPL)) + return false; + + FTextStream doxyLatexPLStream(&doxyLatexPL); + doxyLatexPLStream << + "use DoxyStructure;\n" + "use DoxyDocs;\n" + "\n" + "sub latex_quote($) {\n" + "\tmy $text = $_[0];\n" + "\t$text =~ s/\\\\/\\\\textbackslash /g;\n" + "\t$text =~ s/\\|/\\\\textbar /g;\n" + "\t$text =~ s//\\\\textgreater /g;\n" + "\t$text =~ s/~/\\\\textasciitilde /g;\n" + "\t$text =~ s/\\^/\\\\textasciicircum /g;\n" + "\t$text =~ s/[\\$&%#_{}]/\\\\$&/g;\n" + "\tprint $text;\n" + "}\n" + "\n" + "sub generate_doc($) {\n" + "\tmy $doc = $_[0];\n" + "\tfor my $item (@$doc) {\n" + "\t\tmy $type = $$item{type};\n" + "\t\tif ($type eq \"text\") {\n" + "\t\t\tlatex_quote($$item{content});\n" + "\t\t} elsif ($type eq \"parbreak\") {\n" + "\t\t\tprint \"\\n\\n\";\n" + "\t\t} elsif ($type eq \"style\") {\n" + "\t\t\tmy $style = $$item{style};\n" + "\t\t\tif ($$item{enable} eq \"yes\") {\n" + "\t\t\t\tif ($style eq \"bold\") { print '\\bfseries'; }\n" + "\t\t\t\tif ($style eq \"italic\") { print '\\itshape'; }\n" + "\t\t\t\tif ($style eq \"code\") { print '\\ttfamily'; }\n" + "\t\t\t} else {\n" + "\t\t\t\tif ($style eq \"bold\") { print '\\mdseries'; }\n" + "\t\t\t\tif ($style eq \"italic\") { print '\\upshape'; }\n" + "\t\t\t\tif ($style eq \"code\") { print '\\rmfamily'; }\n" + "\t\t\t}\n" + "\t\t\tprint '{}';\n" + "\t\t} elsif ($type eq \"symbol\") {\n" + "\t\t\tmy $symbol = $$item{symbol};\n" + "\t\t\tif ($symbol eq \"copyright\") { print '\\copyright'; }\n" + "\t\t\telsif ($symbol eq \"szlig\") { print '\\ss'; }\n" + "\t\t\tprint '{}';\n" + "\t\t} elsif ($type eq \"accent\") {\n" + "\t\t\tmy ($accent) = $$item{accent};\n" + "\t\t\tif ($accent eq \"umlaut\") { print '\\\"'; }\n" + "\t\t\telsif ($accent eq \"acute\") { print '\\\\\\''; }\n" + "\t\t\telsif ($accent eq \"grave\") { print '\\`'; }\n" + "\t\t\telsif ($accent eq \"circ\") { print '\\^'; }\n" + "\t\t\telsif ($accent eq \"tilde\") { print '\\~'; }\n" + "\t\t\telsif ($accent eq \"cedilla\") { print '\\c'; }\n" + "\t\t\telsif ($accent eq \"ring\") { print '\\r'; }\n" + "\t\t\tprint \"{\" . $$item{letter} . \"}\"; \n" + "\t\t} elsif ($type eq \"list\") {\n" + "\t\t\tmy $env = ($$item{style} eq \"ordered\") ? \"enumerate\" : \"itemize\";\n" + "\t\t\tprint \"\\n\\\\begin{\" . $env .\"}\";\n" + "\t\t \tfor my $subitem (@{$$item{content}}) {\n" + "\t\t\t\tprint \"\\n\\\\item \";\n" + "\t\t\t\tgenerate_doc($subitem);\n" + "\t\t \t}\n" + "\t\t\tprint \"\\n\\\\end{\" . $env .\"}\";\n" + "\t\t} elsif ($type eq \"url\") {\n" + "\t\t\tlatex_quote($$item{content});\n" + "\t\t}\n" + "\t}\n" + "}\n" + "\n" + "sub generate($$) {\n" + "\tmy ($item, $node) = @_;\n" + "\tmy ($type, $name) = @$node[0, 1];\n" + "\tif ($type eq \"string\") {\n" + "\t\tprint \"\\\\\" . $name . \"{\";\n" + "\t\tlatex_quote($item);\n" + "\t\tprint \"}\";\n" + "\t} elsif ($type eq \"doc\") {\n" + "\t\tif (@$item) {\n" + "\t\t\tprint \"\\\\\" . $name . \"{\";\n" + "\t\t\tgenerate_doc($item);\n" + "\t\t\tprint \"}%\\n\";\n" + "\t\t} else {\n" + "#\t\t\tprint \"\\\\\" . $name . \"Empty%\\n\";\n" + "\t\t}\n" + "\t} elsif ($type eq \"hash\") {\n" + "\t\tmy ($key, $value);\n" + "\t\twhile (($key, $subnode) = each %{$$node[2]}) {\n" + "\t\t\tmy $subname = $$subnode[1];\n" + "\t\t\tprint \"\\\\Defcs{field\" . $subname . \"}{\";\n" + "\t\t\tif ($$item{$key}) {\n" + "\t\t\t\tgenerate($$item{$key}, $subnode);\n" + "\t\t\t} else {\n" + "#\t\t\t\t\tprint \"\\\\\" . $subname . \"Empty%\\n\";\n" + "\t\t\t}\n" + "\t\t\tprint \"}%\\n\";\n" + "\t\t}\n" + "\t\tprint \"\\\\\" . $name . \"%\\n\";\n" + "\t} elsif ($type eq \"list\") {\n" + "\t\tmy $index = 0;\n" + "\t\tif (@$item) {\n" + "\t\t\tprint \"\\\\\" . $name . \"{%\\n\";\n" + "\t\t\tfor my $subitem (@$item) {\n" + "\t\t\t\tif ($index) {\n" + "\t\t\t\t\tprint \"\\\\\" . $name . \"Sep%\\n\";\n" + "\t\t\t\t}\n" + "\t\t\t\tgenerate($subitem, $$node[2]);\n" + "\t\t\t\t$index++;\n" + "\t\t\t}\n" + "\t\t\tprint \"}%\\n\";\n" + "\t\t} else {\n" + "#\t\t\tprint \"\\\\\" . $name . \"Empty%\\n\";\n" + "\t\t}\n" + "\t}\n" + "}\n" + "\n" + "generate($doxydocs, $doxystructure);\n"; + + return true; +} + +bool PerlModGenerator::generateDoxyFormatTex() +{ + QFile doxyFormatTex; + if (!createOutputFile(doxyFormatTex, pathDoxyFormatTex)) + return false; + + FTextStream doxyFormatTexStream(&doxyFormatTex); + doxyFormatTexStream << + "\\def\\Defcs#1{\\long\\expandafter\\def\\csname#1\\endcsname}\n" + "\\Defcs{Empty}{}\n" + "\\def\\IfEmpty#1{\\expandafter\\ifx\\csname#1\\endcsname\\Empty}\n" + "\n" + "\\def\\StringNode#1{\\Defcs{#1}##1{##1}}\n" + "\\def\\DocNode#1{\\Defcs{#1}##1{##1}}\n" + "\\def\\ListNode#1{\\Defcs{#1}##1{##1}\\Defcs{#1Sep}{}}\n" + "\\def\\HashNode#1{\\Defcs{#1}{}}\n" + "\n" + "\\input{" << pathDoxyStructureTex << "}\n" + "\n" + "\\newbox\\BoxA\n" + "\\dimendef\\DimenA=151\\relax\n" + "\\dimendef\\DimenB=152\\relax\n" + "\\countdef\\ZoneDepth=151\\relax\n" + "\n" + "\\def\\Cs#1{\\csname#1\\endcsname}\n" + "\\def\\Letcs#1{\\expandafter\\let\\csname#1\\endcsname}\n" + "\\def\\Heading#1{\\vskip 4mm\\relax\\textbf{#1}}\n" + "\\def\\See#1{\\begin{flushleft}\\Heading{See also: }#1\\end{flushleft}}\n" + "\n" + "\\def\\Frame#1{\\vskip 3mm\\relax\\fbox{ \\vbox{\\hsize0.95\\hsize\\vskip 1mm\\relax\n" + "\\raggedright#1\\vskip 0.5mm\\relax} }}\n" + "\n" + "\\def\\Zone#1#2#3{%\n" + "\\Defcs{Test#1}{#2}%\n" + "\\Defcs{Emit#1}{#3}%\n" + "\\Defcs{#1}{%\n" + "\\advance\\ZoneDepth1\\relax\n" + "\\Letcs{Mode\\number\\ZoneDepth}0\\relax\n" + "\\Letcs{Present\\number\\ZoneDepth}0\\relax\n" + "\\Cs{Test#1}\n" + "\\expandafter\\if\\Cs{Present\\number\\ZoneDepth}1%\n" + "\\advance\\ZoneDepth-1\\relax\n" + "\\Letcs{Present\\number\\ZoneDepth}1\\relax\n" + "\\expandafter\\if\\Cs{Mode\\number\\ZoneDepth}1%\n" + "\\advance\\ZoneDepth1\\relax\n" + "\\Letcs{Mode\\number\\ZoneDepth}1\\relax\n" + "\\Cs{Emit#1}\n" + "\\advance\\ZoneDepth-1\\relax\\fi\n" + "\\advance\\ZoneDepth1\\relax\\fi\n" + "\\advance\\ZoneDepth-1\\relax}}\n" + "\n" + "\\def\\Member#1#2{%\n" + "\\Defcs{Test#1}{\\Cs{field#1Detailed}\n" + "\\IfEmpty{field#1DetailedDoc}\\else\\Letcs{Present#1}1\\fi}\n" + "\\Defcs{#1}{\\Letcs{Present#1}0\\relax\n" + "\\Cs{Test#1}\\if1\\Cs{Present#1}\\Letcs{Present\\number\\ZoneDepth}1\\relax\n" + "\\if1\\Cs{Mode\\number\\ZoneDepth}#2\\fi\\fi}}\n" + "\n" + "\\def\\TypedefMemberList#1#2{%\n" + "\\Defcs{#1DetailedDoc}##1{\\vskip 5.5mm\\relax##1}%\n" + "\\Defcs{#1Name}##1{\\textbf{##1}}%\n" + "\\Defcs{#1See}##1{\\See{##1}}%\n" + "%\n" + "\\Zone{#1s}{\\Cs{field#1List}}{\\subsubsection{#2}\\Cs{field#1List}}%\n" + "\\Member{#1}{\\Frame{typedef \\Cs{field#1Type} \\Cs{field#1Name}}%\n" + "\\Cs{field#1DetailedDoc}\\Cs{field#1See}\\vskip 5mm\\relax}}%\n" + "\n" + "\\def\\VariableMemberList#1#2{%\n" + "\\Defcs{#1DetailedDoc}##1{\\vskip 5.5mm\\relax##1}%\n" + "\\Defcs{#1Name}##1{\\textbf{##1}}%\n" + "\\Defcs{#1See}##1{\\See{##1}}%\n" + "%\n" + "\\Zone{#1s}{\\Cs{field#1List}}{\\subsubsection{#2}\\Cs{field#1List}}%\n" + "\\Member{#1}{\\Frame{\\Cs{field#1Type}{} \\Cs{field#1Name}}%\n" + "\\Cs{field#1DetailedDoc}\\Cs{field#1See}\\vskip 5mm\\relax}}%\n" + "\n" + "\\def\\FunctionMemberList#1#2{%\n" + "\\Defcs{#1PDParamName}##1{\\textit{##1}}%\n" + "\\Defcs{#1PDParam}{\\Cs{field#1PDParamName}}%\n" + "\\Defcs{#1PDParamsSep}{, }%\n" + "\\Defcs{#1PDBlocksSep}{\\vskip 2mm\\relax}%\n" + "%\n" + "\\Defcs{#1PDBlocks}##1{%\n" + "\\Heading{Parameters:}\\vskip 1.5mm\\relax\n" + "\\DimenA0pt\\relax\n" + "\\Defcs{#1PDBlock}{\\setbox\\BoxA\\hbox{\\Cs{field#1PDParams}}%\n" + "\\ifdim\\DimenA<\\wd\\BoxA\\DimenA\\wd\\BoxA\\fi}%\n" + "##1%\n" + "\\advance\\DimenA3mm\\relax\n" + "\\DimenB\\hsize\\advance\\DimenB-\\DimenA\\relax\n" + "\\Defcs{#1PDBlock}{\\hbox to\\hsize{\\vtop{\\hsize\\DimenA\\relax\n" + "\\Cs{field#1PDParams}}\\hfill\n" + "\\vtop{\\hsize\\DimenB\\relax\\Cs{field#1PDDoc}}}}%\n" + "##1}\n" + "\n" + "\\Defcs{#1ParamName}##1{\\textit{##1}}\n" + "\\Defcs{#1Param}{\\Cs{field#1ParamType}{} \\Cs{field#1ParamName}}\n" + "\\Defcs{#1ParamsSep}{, }\n" + "\n" + "\\Defcs{#1Name}##1{\\textbf{##1}}\n" + "\\Defcs{#1See}##1{\\See{##1}}\n" + "\\Defcs{#1Return}##1{\\Heading{Returns: }##1}\n" + "\\Defcs{field#1Title}{\\Frame{\\Cs{field#1Type}{} \\Cs{field#1Name}(\\Cs{field#1Params})}}%\n" + "%\n" + "\\Zone{#1s}{\\Cs{field#1List}}{\\subsubsection{#2}\\Cs{field#1List}}%\n" + "\\Member{#1}{%\n" + "\\Cs{field#1Title}\\vskip 6mm\\relax\\Cs{field#1DetailedDoc}\n" + "\\Cs{field#1Return}\\Cs{field#1PDBlocks}\\Cs{field#1See}\\vskip 5mm\\relax}}\n" + "\n" + "\\def\\FileDetailed{\\fieldFileDetailedDoc\\par}\n" + "\\def\\ClassDetailed{\\fieldClassDetailedDoc\\par}\n" + "\n" + "\\def\\FileSubzones{\\fieldFileTypedefs\\fieldFileVariables\\fieldFileFunctions}\n" + "\n" + "\\def\\ClassSubzones{%\n" + "\\fieldClassPublicTypedefs\\fieldClassPublicMembers\\fieldClassPublicMethods\n" + "\\fieldClassProtectedTypedefs\\fieldClassProtectedMembers\\fieldClassProtectedMethods\n" + "\\fieldClassPrivateTypedefs\\fieldClassPrivateMembers\\fieldClassPrivateMethods}\n" + "\n" + "\\Member{Page}{\\subsection{\\fieldPageName}\\fieldPageDetailedDoc}\n" + "\n" + "\\TypedefMemberList{FileTypedef}{Typedefs}\n" + "\\VariableMemberList{FileVariable}{Variables}\n" + "\\FunctionMemberList{FileFunction}{Functions}\n" + "\\Zone{File}{\\FileSubzones}{\\subsection{\\fieldFileName}\\fieldFileDetailed\\FileSubzones}\n" + "\n" + "\\TypedefMemberList{ClassPublicTypedef}{Public Typedefs}\n" + "\\TypedefMemberList{ClassProtectedTypedef}{Protected Typedefs}\n" + "\\TypedefMemberList{ClassPrivateTypedef}{Private Typedefs}\n" + "\\VariableMemberList{ClassPublicMember}{Public Members}\n" + "\\VariableMemberList{ClassProtectedMember}{Protected Members}\n" + "\\VariableMemberList{ClassPrivateMember}{Private Members}\n" + "\\FunctionMemberList{ClassPublicMethod}{Public Methods}\n" + "\\FunctionMemberList{ClassProtectedMethod}{Protected Methods}\n" + "\\FunctionMemberList{ClassPrivateMethod}{Private Methods}\n" + "\\Zone{Class}{\\ClassSubzones}{\\subsection{\\fieldClassName}\\fieldClassDetailed\\ClassSubzones}\n" + "\n" + "\\Zone{AllPages}{\\fieldPages}{\\section{Pages}\\fieldPages}\n" + "\\Zone{AllFiles}{\\fieldFiles}{\\section{Files}\\fieldFiles}\n" + "\\Zone{AllClasses}{\\fieldClasses}{\\section{Classes}\\fieldClasses}\n" + "\n" + "\\newlength{\\oldparskip}\n" + "\\newlength{\\oldparindent}\n" + "\\newlength{\\oldfboxrule}\n" + "\n" + "\\ZoneDepth0\\relax\n" + "\\Letcs{Mode0}1\\relax\n" + "\n" + "\\def\\EmitDoxyDocs{%\n" + "\\setlength{\\oldparskip}{\\parskip}\n" + "\\setlength{\\oldparindent}{\\parindent}\n" + "\\setlength{\\oldfboxrule}{\\fboxrule}\n" + "\\setlength{\\parskip}{0cm}\n" + "\\setlength{\\parindent}{0cm}\n" + "\\setlength{\\fboxrule}{1pt}\n" + "\\AllPages\\AllFiles\\AllClasses\n" + "\\setlength{\\parskip}{\\oldparskip}\n" + "\\setlength{\\parindent}{\\oldparindent}\n" + "\\setlength{\\fboxrule}{\\oldfboxrule}}\n"; + + return true; +} + +bool PerlModGenerator::generateDoxyLatexTex() +{ + QFile doxyLatexTex; + if (!createOutputFile(doxyLatexTex, pathDoxyLatexTex)) + return false; + + FTextStream doxyLatexTexStream(&doxyLatexTex); + doxyLatexTexStream << + "\\documentclass[a4paper,12pt]{article}\n" + "\\usepackage[latin1]{inputenc}\n" + "\\usepackage[none]{hyphenat}\n" + "\\usepackage[T1]{fontenc}\n" + "\\usepackage{hyperref}\n" + "\\usepackage{times}\n" + "\n" + "\\input{doxyformat}\n" + "\n" + "\\begin{document}\n" + "\\input{" << pathDoxyDocsTex << "}\n" + "\\sloppy\n" + "\\EmitDoxyDocs\n" + "\\end{document}\n"; + + return true; +} + +void PerlModGenerator::generate() +{ + // + classes + // + namespaces + // + files + // - packages + // + groups + // + related pages + // - examples + + QDir perlModDir; + if (!createOutputDir(perlModDir)) + return; + + bool perlmodLatex = Config_getBool("PERLMOD_LATEX"); + + pathDoxyDocsPM = perlModDir.absPath() + "/DoxyDocs.pm"; + pathDoxyStructurePM = perlModDir.absPath() + "/DoxyStructure.pm"; + pathMakefile = perlModDir.absPath() + "/Makefile"; + pathDoxyRules = perlModDir.absPath() + "/doxyrules.make"; + + if (perlmodLatex) { + pathDoxyStructureTex = perlModDir.absPath() + "/doxystructure.tex"; + pathDoxyFormatTex = perlModDir.absPath() + "/doxyformat.tex"; + pathDoxyLatexTex = perlModDir.absPath() + "/doxylatex.tex"; + pathDoxyLatexDVI = perlModDir.absPath() + "/doxylatex.dvi"; + pathDoxyLatexPDF = perlModDir.absPath() + "/doxylatex.pdf"; + pathDoxyDocsTex = perlModDir.absPath() + "/doxydocs.tex"; + pathDoxyLatexPL = perlModDir.absPath() + "/doxylatex.pl"; + pathDoxyLatexStructurePL = perlModDir.absPath() + "/doxylatex-structure.pl"; + } + + if (!(generatePerlModOutput() + && generateDoxyStructurePM() + && generateMakefile() + && generateDoxyRules())) + return; + + if (perlmodLatex) { + if (!(generateDoxyLatexStructurePL() + && generateDoxyLatexPL() + && generateDoxyLatexTex() + && generateDoxyFormatTex())) + return; + } +} + +void generatePerlMod() +{ + PerlModGenerator pmg(Config_getBool("PERLMOD_PRETTY")); + pmg.generate(); +} + +// Local Variables: +// c-basic-offset: 2 +// End: + +/* This elisp function for XEmacs makes Control-Z transform + the text in the region into a valid C string. + + (global-set-key '(control z) (lambda () (interactive) + (save-excursion + (if (< (mark) (point)) (exchange-point-and-mark)) + (let ((start (point)) (replacers + '(("\\\\" "\\\\\\\\") + ("\"" "\\\\\"") + ("\t" "\\\\t") + ("^.*$" "\"\\&\\\\n\"")))) + (while replacers + (while (re-search-forward (caar replacers) (mark) t) + (replace-match (cadar replacers) t)) + (goto-char start) + (setq replacers (cdr replacers))))))) +*/ diff --git a/trunk/src/perlmodgen.h b/trunk/src/perlmodgen.h new file mode 100644 index 0000000..4307d9b --- /dev/null +++ b/trunk/src/perlmodgen.h @@ -0,0 +1,23 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#ifndef PERLMODGEN_H +#define PERLMODGEN_H + +class QCString; + +extern void setPerlModDoxyfile(const QCString &); +extern void generatePerlMod(); + +#endif diff --git a/trunk/src/portable.cpp b/trunk/src/portable.cpp new file mode 100644 index 0000000..f2d1166 --- /dev/null +++ b/trunk/src/portable.cpp @@ -0,0 +1,410 @@ +#include +#include +#if defined(_WIN32) && !defined(__CYGWIN__) +#undef UNICODE +#define _WIN32_DCOM +#include +#else +#include +#include +#include +#include +#include +extern char **environ; +#endif + +#include +#include + +#if defined(_MSC_VER) || defined(__BORLANDC__) +#define popen _popen +#define pclose _pclose +#endif + +#include "portable.h" +#ifndef NODEBUG +#include "debug.h" +#endif +//#include "doxygen.h" + +static double g_sysElapsedTime; +static QTime g_time; + +int portable_system(const char *command,const char *args,bool commandHasConsole) +{ + + if (command==0) return 1; + + QCString fullCmd=command; + fullCmd=fullCmd.stripWhiteSpace(); + if (fullCmd.at(0)!='"' && fullCmd.find(' ')!=-1) + { + // add quotes around command as it contains spaces and is not quoted already + fullCmd="\""+fullCmd+"\""; + } + fullCmd += " "; + fullCmd += args; +#ifndef NODEBUG + Debug::print(Debug::ExtCmd,0,"Executing external command `%s`\n",fullCmd.data()); +#endif + +#if !defined(_WIN32) || defined(__CYGWIN__) + commandHasConsole=commandHasConsole; + /*! taken from the system() manpage on my Linux box */ + int pid,status=0; + +#ifdef _OS_SOLARIS // for Solaris we use vfork since it is more memory efficient + + // on Solaris fork() duplicates the memory usage + // so we use vfork instead + + // spawn shell + if ((pid=vfork())<0) + { + status=-1; + } + else if (pid==0) + { + execl("/bin/sh","sh","-c",fullCmd.data(),(char*)0); + _exit(127); + } + else + { + while (waitpid(pid,&status,0 )<0) + { + if (errno!=EINTR) + { + status=-1; + break; + } + } + } + return status; + +#else // Other Unices just use fork + + pid = fork(); + if (pid==-1) return -1; + if (pid==0) + { + const char * argv[4]; + argv[0] = "sh"; + argv[1] = "-c"; + argv[2] = fullCmd.data(); + argv[3] = 0; + execve("/bin/sh",(char * const *)argv,environ); + exit(127); + } + for (;;) + { + if (waitpid(pid,&status,0)==-1) + { + if (errno!=EINTR) return -1; + } + else + { + if (WIFEXITED(status)) + { + return WEXITSTATUS(status); + } + else + { + return status; + } + } + } +#endif // !_OS_SOLARIS + +#else // Win32 specific + if (commandHasConsole) + { + return system(fullCmd); + } + else + { + // Because ShellExecuteEx can delegate execution to Shell extensions + // (data sources, context menu handlers, verb implementations) that + // are activated using Component Object Model (COM), COM should be + // initialized before ShellExecuteEx is called. Some Shell extensions + // require the COM single-threaded apartment (STA) type. + // For that case COM is initialized as follows + CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); + + // gswin32 is a GUI api which will pop up a window and run + // asynchronously. To prevent both, we use ShellExecuteEx and + // WaitForSingleObject (thanks to Robert Golias for the code) + + SHELLEXECUTEINFO sInfo = { + sizeof(SHELLEXECUTEINFO), /* structure size */ + SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI, /* tell us the process + * handle so we can wait till it's done | + * do not display msg box if error + */ + NULL, /* window handle */ + NULL, /* action to perform: open */ + command, /* file to execute */ + args, /* argument list */ + NULL, /* use current working dir */ + SW_HIDE, /* minimize on start-up */ + 0, /* application instance handle */ + NULL, /* ignored: id list */ + NULL, /* ignored: class name */ + NULL, /* ignored: key class */ + 0, /* ignored: hot key */ + NULL, /* ignored: icon */ + NULL /* resulting application handle */ + }; + if (!ShellExecuteEx(&sInfo)) + { + return -1; + } + else if (sInfo.hProcess) /* executable was launched, wait for it to finish */ + { + WaitForSingleObject(sInfo.hProcess,INFINITE); + CloseHandle(sInfo.hProcess); + } + } + return 0; +#endif + +} + +uint portable_pid() +{ + uint pid; +#if !defined(_WIN32) || defined(__CYGWIN__) + pid = (uint)getpid(); +#else + pid = (uint)GetCurrentProcessId(); +#endif + return pid; +} + +static char **last_environ; + +void portable_setenv(const char *name,const char *value) +{ + if (value==0) value=""; +#if defined(_WIN32) && !defined(__CYGWIN__) + SetEnvironmentVariable(name,value); +#else + register char **ep = 0; + register size_t size; + const size_t namelen=strlen(name); + const size_t vallen=strlen(value) + 1; + + size = 0; + if (environ!=0) + { + for (ep = environ; *ep; ++ep) + { + if (!strncmp (*ep, name, namelen) && (*ep)[namelen] == '=') + break; + else + ++size; + } + } + + if (environ==0 || *ep==0) /* add new string */ + { + char **new_environ; + if (environ == last_environ && environ!=0) + { + // We allocated this space; we can extend it. + new_environ = (char **) realloc (last_environ, (size + 2) * sizeof (char *)); + } + else + { + new_environ = (char **) malloc ((size + 2) * sizeof (char *)); + } + + if (new_environ==0) // no more memory + { + return; + } + + new_environ[size] = (char *)malloc (namelen + 1 + vallen); + if (new_environ[size]==0) + { + free (new_environ); + return; + } + + if (environ != last_environ) + { + memcpy ((char *) new_environ, environ, size * sizeof (char *)); + } + + memcpy(new_environ[size], name, namelen); + new_environ[size][namelen] = '='; + memcpy(&new_environ[size][namelen + 1], value, vallen); + new_environ[size + 1] = 0; + last_environ = environ = new_environ; + } + else /* replace existing string */ + { + size_t len = strlen (*ep); + if (len + 1 < namelen + 1 + vallen) + { + /* The existing string is too short; malloc a new one. */ + char *newString = (char *)malloc(namelen + 1 + vallen); + if (newString==0) + { + return; + } + *ep = newString; + } + memcpy(*ep, name, namelen); + (*ep)[namelen] = '='; + memcpy(&(*ep)[namelen + 1], value, vallen); + } + +#endif +} + +void portable_unsetenv(const char *variable) +{ +#if defined(_WIN32) && !defined(__CYGWIN__) + SetEnvironmentVariable(variable,0); +#else + /* Some systems don't have unsetenv(), so we do it ourselves */ + size_t len; + char **ep; + + if (variable == NULL || *variable == '\0' || strchr (variable, '=') != NULL) + { + return; // not properly formatted + } + + len = strlen(variable); + + ep = environ; + while (*ep != NULL) + { + if (!strncmp(*ep, variable, len) && (*ep)[len]=='=') + { + /* Found it. Remove this pointer by moving later ones back. */ + char **dp = ep; + do dp[0] = dp[1]; while (*dp++); + /* Continue the loop in case NAME appears again. */ + } + else + { + ++ep; + } + } +#endif +} + +const char *portable_getenv(const char *variable) +{ + return getenv(variable); +} + +portable_off_t portable_fseek(FILE *f,portable_off_t offset, int whence) +{ +#if defined(_WIN32) && !defined(__CYGWIN__) + return _fseeki64(f,offset,whence); +#else + return fseeko(f,offset,whence); +#endif +} + +portable_off_t portable_ftell(FILE *f) +{ +#if defined(_WIN32) && !defined(__CYGWIN__) + return _ftelli64(f); +#else + return ftello(f); +#endif +} + +FILE *portable_fopen(const char *fileName,const char *mode) +{ +#if defined(_WIN32) && !defined(__CYGWIN__) + QString fn(fileName); + QString m(mode); + return _wfopen((wchar_t*)fn.ucs2(),(wchar_t*)m.ucs2()); +#else + return fopen(fileName,mode); +#endif +} + +char portable_pathSeparator() +{ +#if defined(_WIN32) && !defined(__CYGWIN__) + return '\\'; +#else + return '/'; +#endif +} + +char portable_pathListSeparator() +{ +#if defined(_WIN32) && !defined(__CYGWIN__) + return ';'; +#else + return ':'; +#endif +} + +const char *portable_ghostScriptCommand() +{ +#if defined(_WIN32) && !defined(__CYGWIN__) + return "gswin32c.exe"; +#else + return "gs"; +#endif +} + +const char *portable_commandExtension() +{ +#if defined(_WIN32) && !defined(__CYGWIN__) + return ".exe"; +#else + return ""; +#endif +} + +bool portable_fileSystemIsCaseSensitive() +{ +#if defined(_WIN32) || defined(macintosh) || defined(__MACOSX__) || defined(__APPLE__) + return FALSE; +#else + return TRUE; +#endif +} + +FILE * portable_popen(const char *name,const char *type) +{ + return popen(name,type); +} + +int portable_pclose(FILE *stream) +{ + return pclose(stream); +} + +void portable_sysTimerStart() +{ + g_time.start(); +} + +void portable_sysTimerStop() +{ + g_sysElapsedTime+=((double)g_time.elapsed())/1000.0; +} + +double portable_getSysElapsedTime() +{ + return g_sysElapsedTime; +} + +void portable_sleep(int ms) +{ +#if defined(_WIN32) && !defined(__CYGWIN__) + Sleep(ms); +#else + usleep(1000*ms); +#endif +} diff --git a/trunk/src/portable.h b/trunk/src/portable.h new file mode 100644 index 0000000..f698e32 --- /dev/null +++ b/trunk/src/portable.h @@ -0,0 +1,47 @@ +#ifndef PORTABLE_H +#define PORTABLE_H + +#include +#include +#include + +#if defined(_WIN32) +typedef __int64 portable_off_t; +#else +typedef off_t portable_off_t; +#endif + +/** @file + * @brief Portable versions of functions that are platform dependent. + */ + +int portable_system(const char *command,const char *args,bool commandHasConsole=TRUE); +uint portable_pid(); +const char * portable_getenv(const char *variable); +void portable_setenv(const char *variable,const char *value); +void portable_unsetenv(const char *variable); +portable_off_t portable_fseek(FILE *f,portable_off_t offset, int whence); +portable_off_t portable_ftell(FILE *f); +FILE * portable_fopen(const char *fileName,const char *mode); +char portable_pathSeparator(); +char portable_pathListSeparator(); +const char * portable_ghostScriptCommand(); +const char * portable_commandExtension(); +bool portable_fileSystemIsCaseSensitive(); +FILE * portable_popen(const char *name,const char *type); +int portable_pclose(FILE *stream); +void portable_sysTimerStart(); +void portable_sysTimerStop(); +double portable_getSysElapsedTime(); +void portable_sleep(int ms); + +extern "C" { + void * portable_iconv_open(const char* tocode, const char* fromcode); + size_t portable_iconv (void *cd, const char** inbuf, size_t *inbytesleft, + char* * outbuf, size_t *outbytesleft); + int portable_iconv_close (void *cd); +} + + +#endif + diff --git a/trunk/src/portable_c.c b/trunk/src/portable_c.c new file mode 100644 index 0000000..ab33639 --- /dev/null +++ b/trunk/src/portable_c.c @@ -0,0 +1,24 @@ +#include + +// These functions are implemented in a C file, because there are different +// versions of the iconv() prototype, some with a const pointer and some +// without. In C this is just a warning, but in C++ breaks the compilation. +// Looking at the LIBICONV_VERSION is not enough, since for MACOSX the +// const and non-const version exist with the same version of the file. + +void * portable_iconv_open(const char* tocode, const char* fromcode) +{ + return iconv_open(tocode,fromcode); +} + +size_t portable_iconv (void *cd, const char** inbuf, size_t *inbytesleft, + char** outbuf, size_t *outbytesleft) +{ + return iconv((iconv_t)cd,inbuf,inbytesleft,outbuf,outbytesleft); +} + +int portable_iconv_close (void *cd) +{ + return iconv_close((iconv_t)cd); +} + diff --git a/trunk/src/pre.h b/trunk/src/pre.h new file mode 100644 index 0000000..18c57c8 --- /dev/null +++ b/trunk/src/pre.h @@ -0,0 +1,33 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#ifndef PRE_H +#define PRE_H + +#include "qtbc.h" +#include +#include "define.h" + +class BufStr; + +void initPreprocessor(); +void cleanUpPreprocessor(); +void addSearchDir(const char *dir); +void preprocessFile(const char *fileName,BufStr &input,BufStr &output); +void preFreeScanner(); + +#endif diff --git a/trunk/src/pre.l b/trunk/src/pre.l new file mode 100644 index 0000000..d0acd41 --- /dev/null +++ b/trunk/src/pre.l @@ -0,0 +1,3051 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +%{ + +/* + * includes + */ + +#include +#include +#include +#include + +#include "qtbc.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pre.h" +#include "constexp.h" +#include "define.h" +#include "doxygen.h" +#include "message.h" +#include "util.h" +#include "defargs.h" +#include "debug.h" +#include "bufstr.h" +#include "portable.h" +#include "bufstr.h" +#include "arguments.h" +#include "entry.h" + +#define YY_NEVER_INTERACTIVE 1 + + +struct FileState +{ + FileState(int size) : fileBuf(size), + oldFileBuf(0), oldFileBufPos(0) {} + int lineNr; + BufStr fileBuf; + BufStr *oldFileBuf; + int oldFileBufPos; + YY_BUFFER_STATE bufState; + QCString fileName; +}; + +/** @brief Singleton that manages the defines available while + * proprocessing files. + */ +class DefineManager +{ + /** Local class used to hold the defines for a single file */ + class DefinesPerFile + { + public: + /** Creates an empty container for defines */ + DefinesPerFile() : m_defines(257), m_includedFiles(17) + { + m_defines.setAutoDelete(TRUE); + } + /** Destroys the object */ + virtual ~DefinesPerFile() + { + } + /** Adds a define in the context of a file. Will replace + * an existing define with the same name (redefinition) + * @param def The Define object to add. + */ + void addDefine(Define *def) + { + Define *d = m_defines.find(def->name); + if (d!=0) // redefine + { + m_defines.remove(d->name); + } + m_defines.insert(def->name,def); + } + /** Adds an include file for this file + * @param fileName The name of the include file + */ + void addInclude(const char *fileName) + { + m_includedFiles.insert(fileName,(void*)0x8); + } + void collectDefines(DefineDict *dict,QDict &includeStack); + private: + DefineDict m_defines; + QDict m_includedFiles; + }; + + public: + friend class DefinesPerFile; + /** Returns a reference to the singleton */ + static DefineManager &instance() + { + if (theInstance==0) theInstance = new DefineManager; + return *theInstance; + } + /** Deletes the singleton */ + static void deleteInstance() + { + delete theInstance; + theInstance = 0; + } + /** Starts a context in which defines are collected. + * Called at the start of a new file that is preprocessed. + * @param fileName the name of the file to process. + */ + void startContext(const char *fileName) + { + //printf("DefineManager::startContext()\n"); + m_contextDefines.clear(); + if (fileName==0) return; + DefinesPerFile *dpf = m_fileMap.find(fileName); + if (dpf==0) + { + //printf("New file!\n"); + dpf = new DefinesPerFile; + m_fileMap.insert(fileName,dpf); + } + } + /** Ends the context started with startContext() freeing any + * defines collected within in this context. + */ + void endContext() + { + //printf("DefineManager::endContext()\n"); + m_contextDefines.clear(); + } + /** Add an included file to the current context. + * If the file has been pre-processed already, all defines are added + * to the context. + * @param fileName The name of the include file to add to the context. + */ + void addFileToContext(const char *fileName) + { + if (fileName==0) return; + //printf("DefineManager::addFileToContext(%s)\n",fileName); + DefinesPerFile *dpf = m_fileMap.find(fileName); + if (dpf==0) + { + //printf("New file!\n"); + dpf = new DefinesPerFile; + m_fileMap.insert(fileName,dpf); + } + else + { + //printf("existing file!\n"); + QDict includeStack(17); + dpf->collectDefines(&m_contextDefines,includeStack); + } + } + + /** Add a define to the manager object. + * @param fileName The file in which the define was found + * @param def The Define object to add. + */ + void addDefine(const char *fileName,Define *def) + { + if (fileName==0) return; + //printf("DefineManager::addDefine(%s,%s)\n",fileName,def->name.data()); + Define *d = m_contextDefines.find(def->name); + if (d!=0) // redefine + { + m_contextDefines.remove(d->name); + } + m_contextDefines.insert(def->name,def); + + DefinesPerFile *dpf = m_fileMap.find(fileName); + if (dpf==0) + { + dpf = new DefinesPerFile; + } + dpf->addDefine(def); + } + + /** Add an include relation to the manager object. + * @param fromFileName file name in which the include was found. + * @param toFileName file name that is included. + */ + void addInclude(const char *fromFileName,const char *toFileName) + { + //printf("DefineManager::addInclude(%s,%s)\n",fromFileName,toFileName); + if (fromFileName==0 || toFileName==0) return; + DefinesPerFile *dpf = m_fileMap.find(fromFileName); + if (dpf==0) + { + dpf = new DefinesPerFile; + } + dpf->addInclude(toFileName); + } + /** Returns a Define object given its name or 0 if the Define does + * not exist. + */ + Define *isDefined(const char *name) const + { + return m_contextDefines.find(name); + } + /** Returns a reference to the defines found in the current context. */ + const DefineDict &defineContext() const + { + return m_contextDefines; + } + private: + static DefineManager *theInstance; + + /** Helper function to collect all define for a given file */ + void collectDefinesForFile(const char *fileName,DefineDict *dict) + { + if (fileName==0) return; + DefinesPerFile *dpf = m_fileMap.find(fileName); + if (dpf) + { + QDict includeStack(17); + dpf->collectDefines(dict,includeStack); + } + } + + /** Helper function to return the DefinesPerFile object for a given file name. */ + DefinesPerFile *find(const char *fileName) const + { + if (fileName==0) return 0; + return m_fileMap.find(fileName); + } + + /** Creates a new DefineManager object */ + DefineManager() : m_fileMap(1009), m_contextDefines(1009) + { + m_fileMap.setAutoDelete(TRUE); + } + + /** Destroys the object */ + virtual ~DefineManager() + { + } + + QDict m_fileMap; + DefineDict m_contextDefines; +}; + +/** Singleton instance */ +DefineManager *DefineManager::theInstance = 0; + +/** Collects all defines for a file and all files that the file includes. + * This function will recursively call itself for each file. + * @param dict The dictionary to fill with the defines. A redefine will + * replace a previous definition. + * @param includeStack The stack of includes, used to stop recursion in + * case there is a cyclic include dependency. + */ +void DefineManager::DefinesPerFile::collectDefines( + DefineDict *dict,QDict &includeStack) +{ + //printf("DefinesPerFile::collectDefines #defines=%d\n",m_defines.count()); + { + QDictIterator di(m_includedFiles); + for (di.toFirst();(di.current());++di) + { + QCString incFile = di.currentKey(); + DefinesPerFile *dpf = DefineManager::instance().find(incFile); + if (dpf && includeStack.find(incFile)==0) + { + //printf(" processing include %s\n",incFile.data()); + includeStack.insert(incFile,(void*)0x8); + dpf->collectDefines(dict,includeStack); + } + } + } + { + QDictIterator di(m_defines); + Define *def; + for (di.toFirst();(def=di.current());++di) + { + Define *d = dict->find(def->name); + if (d!=0) // redefine + { + dict->remove(d->name); + } + dict->insert(def->name,def); + //printf(" adding define %s\n",def->name.data()); + } + } +} + +/* ----------------------------------------------------------------- + * + * scanner's state + */ + +static int g_yyLineNr = 1; +static QCString g_yyFileName; +static FileDef *g_yyFileDef; +static FileDef *g_inputFileDef; +static int g_ifcount = 0; +static QStrList *g_pathList = 0; +static QStack g_includeStack; +static QDict *g_argDict; +static int g_defArgs = -1; +static QCString g_defName; +static QCString g_defText; +static QCString g_defLitText; +static QCString g_defArgsStr; +static QCString g_defExtraSpacing; +static bool g_defVarArgs; +static int g_level; +static int g_lastCContext; +static int g_lastCPPContext; +static QArray g_levelGuard; +static BufStr *g_inputBuf; +static int g_inputBufPos; +static BufStr *g_outputBuf; +static int g_roundCount; +static bool g_quoteArg; +static DefineDict *g_expandedDict; +static int g_findDefArgContext; +static bool g_expectGuard; +static QCString g_guardName; +static QCString g_lastGuardName; +static QCString g_incName; +static QCString g_guardExpr; +static int g_curlyCount; +static bool g_nospaces; // add extra spaces during macro expansion + +static bool g_macroExpansion; // from the configuration +static bool g_expandOnlyPredef; // from the configuration +static int g_commentCount; +static bool g_insideComment; +static bool g_isImported; +static QCString g_blockName; +static int g_condCtx; +static bool g_skip; +static QStack g_condStack; +static bool g_insideCS; // C# has simpler preprocessor +static bool g_isSource; + +static bool g_lexInit = FALSE; + +//DefineDict* getGlobalDefineDict() +//{ +// return g_globalDefineDict; +//} + +static void setFileName(const char *name) +{ + bool ambig; + QFileInfo fi(name); + g_yyFileName=convertToQCString(fi.absFilePath()); + g_yyFileDef=findFileDef(Doxygen::inputNameDict,g_yyFileName,ambig); + if (g_yyFileDef==0) // if this is not an input file check if it is an + // include file + { + g_yyFileDef=findFileDef(Doxygen::includeNameDict,g_yyFileName,ambig); + } + //printf("setFileName(%s) g_yyFileName=%s g_yyFileDef=%p\n", + // name,g_yyFileName.data(),g_yyFileDef); + if (g_yyFileDef && g_yyFileDef->isReference()) g_yyFileDef=0; + g_insideCS = getLanguageFromFileName(g_yyFileName)==SrcLangExt_CSharp; + g_isSource = guessSection(g_yyFileName); +} + +static void incrLevel() +{ + g_level++; + g_levelGuard.resize(g_level); + g_levelGuard[g_level-1]=FALSE; + //printf("%s line %d: incrLevel %d\n",g_yyFileName.data(),g_yyLineNr,g_level); +} + +static void decrLevel() +{ + //printf("%s line %d: decrLevel %d\n",g_yyFileName.data(),g_yyLineNr,g_level); + if (g_level > 0) + { + g_level--; + g_levelGuard.resize(g_level); + } + else + { + warn(g_yyFileName,g_yyLineNr,"warning: More #endif's than #if's found.\n"); + } +} + +static bool otherCaseDone() +{ + if (g_level==0) + { + warn(g_yyFileName,g_yyLineNr,"warning: Found an #else without a preceding #if.\n"); + return TRUE; + } + else + { + return g_levelGuard[g_level-1]; + } +} + +static void setCaseDone(bool value) +{ + g_levelGuard[g_level-1]=value; +} + +#if 0 +static bool macroIsAccessible(Define *def) +{ + //printf("macroIsAccessible(%s) input=%s def=%s\n", + // def->name.data(),g_inputFileDef?g_inputFileDef->name().data():"", + // def->fileDef ? def->fileDef->name().data() : ""); + if (def && def->isPredefined) // predefined macro -> globally accessible + { + //printf("%s: predefined macro %s\n",g_inputFileDef->name().data(),def->name.data()); + return TRUE; + } + if (def && def->fileDef==g_inputFileDef) + { + //printf("%s: macro %s defined in this file at line %d now at %d\n", + // g_inputFileDef->name().data(),def->name.data(),def->lineNr,g_yyLineNr); + return def->lineNr<=g_yyLineNr; + } + if (g_inputFileDef && def && def->fileDef) // check if g_inputFileDef actually includes def->fileDef + { + QDict includedFiles(257); + bool b = g_inputFileDef->includes(def->fileDef,&includedFiles); + //printf("%s: Checking for accessibility of define '%s' (defined in %s): result=%d\n", + // g_inputFileDef->name().data(),def->name.data(),def->fileDef->name().data(),b); + return b; + } + if (g_inputFileDef && def && !def->fileName.isEmpty()) + { + bool b = g_inputFileDef->includesByName(def->fileName); + //printf("%s: Checking for accessibility of define '%s' (defined in %s): result=%d\n", + // g_inputFileDef->name().data(),def->name.data(),def->fileName.data(),b); + return b; + } + //printf("not accessible!\n"); + return FALSE; +} + +static Define *isDefined(const char *name) +{ + Define *def=0; + if (name) + { + def=g_globalDefineDict->find(name); + if (def && def->undef) def=0; + if (def && !macroIsAccessible(def)) def=0; + } + //printf("isDefined(%s)=%p\n",name,def); + return def; +} +#endif + + +static QDict g_allIncludes(10009); + +static FileState *checkAndOpenFile(const QCString &fileName,bool &alreadyIncluded) +{ + alreadyIncluded = FALSE; + FileState *fs = 0; + //printf("checkAndOpenFile(%s)\n",fileName.data()); + QFileInfo fi(fileName); + if (fi.exists() && fi.isFile()) + { + static QStrList &exclPatterns = Config_getList("EXCLUDE_PATTERNS"); + if (patternMatch(fi,&exclPatterns)) return 0; + + QCString absName = convertToQCString(fi.absFilePath()); + + // global guard + if (g_curlyCount==0) // not #include inside { ... } + { + if (g_allIncludes.find(absName)!=0) + { + alreadyIncluded = TRUE; + //printf(" already included 1\n"); + return 0; // already done + } + g_allIncludes.insert(absName,(void *)0x8); + } + // check include stack for absName + + QStack tmpStack; + g_includeStack.setAutoDelete(FALSE); + while ((fs=g_includeStack.pop())) + { + if (fs->fileName==absName) alreadyIncluded=TRUE; + tmpStack.push(fs); + } + while ((fs=tmpStack.pop())) + { + g_includeStack.push(fs); + } + g_includeStack.setAutoDelete(TRUE); + + if (alreadyIncluded) + { + //printf(" already included 2\n"); + return 0; + } + //printf("#include %s\n",absName.data()); + + fs = new FileState(fi.size()+4096); + alreadyIncluded = FALSE; + if (!readInputFile(absName,fs->fileBuf)) + { // error + //printf(" error reading\n"); + delete fs; + fs=0; + } + else + { + fs->oldFileBuf = g_inputBuf; + fs->oldFileBufPos = g_inputBufPos; + } + } + return fs; +} + +static FileState *findFile(const char *fileName,bool localInclude,bool &alreadyIncluded) +{ + //printf("** findFile(%s,%d) g_yyFileName=%s\n",fileName,localInclude,g_yyFileName.data()); + if (localInclude && !g_yyFileName.isEmpty()) + { + QFileInfo fi(g_yyFileName); + if (fi.exists()) + { + QCString absName = QCString(fi.dirPath(TRUE).data())+"/"+fileName; + FileState *fs = checkAndOpenFile(absName,alreadyIncluded); + if (fs) + { + setFileName(absName); + g_yyLineNr=1; + return fs; + } + else if (alreadyIncluded) + { + return 0; + } + } + } + if (g_pathList==0) + { + return 0; + } + char *s=g_pathList->first(); + while (s) + { + QCString absName = (QCString)s+"/"+fileName; + //printf(" Looking for %s in %s\n",fileName,s); + FileState *fs = checkAndOpenFile(absName,alreadyIncluded); + if (fs) + { + setFileName(absName); + g_yyLineNr=1; + //printf(" -> found it\n"); + return fs; + } + else if (alreadyIncluded) + { + return 0; + } + + s=g_pathList->next(); + } + return 0; +} + +static QCString extractTrailingComment(const char *s) +{ + if (s==0) return ""; + int i=strlen(s)-1; + while (i>=0) + { + char c=s[i]; + switch (c) + { + case '/': + { + i--; + if (i>=0 && s[i]=='*') // end of a comment block + { + i--; + while (i>0 && !(s[i-1]=='/' && s[i]=='*')) i--; + if (i==0) + { + i++; + } + // only /*!< or /**< are treated as a comment for the macro name, + // otherwise the comment is treated as part of the macro definition + return ((s[i+1]=='*' || s[i+1]=='!') && s[i+2]=='<') ? &s[i-1] : ""; + } + else + { + return ""; + } + } + break; + // whitespace or line-continuation + case ' ': + case '\t': + case '\r': + case '\n': + case '\\': + break; + default: + return ""; + } + i--; + } + return ""; +} + +static int getNextChar(const QCString &expr,QCString *rest,uint &pos); +static int getCurrentChar(const QCString &expr,QCString *rest,uint pos); +static void unputChar(const QCString &expr,QCString *rest,uint &pos,char c); +static void expandExpression(QCString &expr,QCString *rest,int pos); + +static QCString stringize(const QCString &s) +{ + QCString result; + uint i=0; + bool inString=FALSE; + bool inChar=FALSE; + char c,pc; + while (i`%s'\n",s.data(),result.data()); + return result; +} + +/*! Execute all ## operators in expr. + * If the macro name before or after the operator contains a no-rescan + * marker (@-) then this is removed (before the concatenated macro name + * may be expanded again. + */ +static void processConcatOperators(QCString &expr) +{ + //printf("processConcatOperators: in=`%s'\n",expr.data()); + QRegExp r("[ \\t\\n]*##[ \\t\\n]*"); + int l,n,i=0; + if (expr.isEmpty()) return; + while ((n=r.match(expr,i,&l))!=-1) + { + //printf("Match: `%s'\n",expr.data()+i); + if (n+l+1<(int)expr.length() && expr.at(n+l)=='@' && expr.at(n+l+1)=='-') + { + // remove no-rescan marker after ID + l+=2; + } + //printf("found `%s'\n",expr.mid(n,l).data()); + // remove the ## operator and the surrounding whitespace + expr=expr.left(n)+expr.right(expr.length()-n-l); + int k=n-1; + while (k>=0 && isId(expr.at(k))) k--; + if (k>0 && expr.at(k)=='-' && expr.at(k-1)=='@') + { + // remove no-rescan marker before ID + expr=expr.left(k-1)+expr.right(expr.length()-k-1); + n-=2; + } + i=n; + } + //printf("processConcatOperators: out=`%s'\n",expr.data()); +} + +static void yyunput (int c,char *buf_ptr ); +static void returnCharToStream(char c) +{ + unput(c); +} + +static inline void addTillEndOfString(const QCString &expr,QCString *rest, + uint &pos,char term,QCString &arg) +{ + int cc; + while ((cc=getNextChar(expr,rest,pos))!=EOF) + { + if (cc=='\\') arg+=(char)cc,cc=getNextChar(expr,rest,pos); + else if (cc==term) return; + arg+=(char)cc; + } +} + +/*! replaces the function macro \a def whose argument list starts at + * \a pos in expression \a expr. + * Notice that this routine may scan beyond the \a expr string if needed. + * In that case the characters will be read from the input file. + * The replacement string will be returned in \a result and the + * length of the (unexpanded) argument list is stored in \a len. + */ +static bool replaceFunctionMacro(const QCString &expr,QCString *rest,int pos,int &len,const Define *def,QCString &result) +{ + //printf("replaceFunctionMacro(expr=%s,rest=%s,pos=%d,def=%s) level=%d\n",expr.data(),rest ? rest->data() : 0,pos,def->name.data(),g_level); + uint j=pos; + len=0; + result.resize(0); + int cc; + while ((cc=getCurrentChar(expr,rest,j))!=EOF && isspace(cc)) + { + len++; + getNextChar(expr,rest,j); + } + if (cc!='(') + { + unputChar(expr,rest,j,' '); + return FALSE; + } + getNextChar(expr,rest,j); // eat the `(' character + + QDict argTable; // list of arguments + argTable.setAutoDelete(TRUE); + QCString arg; + int argCount=0; + bool done=FALSE; + + // PHASE 1: read the macro arguments + if (def->nargs==0) + { + while ((cc=getNextChar(expr,rest,j))!=EOF) + { + char c = (char)cc; + if (c==')') break; + } + } + else + { + while (!done && (argCountnargs || def->varArgs) && + ((cc=getNextChar(expr,rest,j))!=EOF) + ) + { + char c=(char)cc; + if (c=='(') // argument is a function => search for matching ) + { + int level=1; + arg+=c; + //char term='\0'; + while ((cc=getNextChar(expr,rest,j))!=EOF) + { + char c=(char)cc; + //printf("processing %c: term=%c (%d)\n",c,term,term); + if (c=='\'' || c=='\"') // skip ('s and )'s inside strings + { + arg+=c; + addTillEndOfString(expr,rest,j,c,arg); + } + if (c==')') + { + level--; + arg+=c; + if (level==0) break; + } + else if (c=='(') + { + level++; + arg+=c; + } + else + arg+=c; + } + } + else if (c==')' || c==',') // last or next argument found + { + if (c==',' && argCount==def->nargs-1 && def->varArgs) + { + arg=arg.stripWhiteSpace(); + arg+=','; + } + else + { + QCString argKey; + argKey.sprintf("@%d",argCount++); // key name + arg=arg.stripWhiteSpace(); + // add argument to the lookup table + argTable.insert(argKey, new QCString(arg)); + arg.resize(0); + if (c==')') // end of the argument list + { + done=TRUE; + } + } + } + else if (c=='\"') // append literal strings + { + arg+=c; + bool found=FALSE; + while (!found && (cc=getNextChar(expr,rest,j))!=EOF) + { + found = cc=='"'; + if (cc=='\\') + { + c=(char)cc; + arg+=c; + if ((cc=getNextChar(expr,rest,j))==EOF) break; + } + c=(char)cc; + arg+=c; + } + } + else if (c=='\'') // append literal characters + { + arg+=c; + bool found=FALSE; + while (!found && (cc=getNextChar(expr,rest,j))!=EOF) + { + found = cc=='\''; + if (cc=='\\') + { + c=(char)cc; + arg+=c; + if ((cc=getNextChar(expr,rest,j))==EOF) break; + } + c=(char)cc; + arg+=c; + } + } + else // append other characters + { + arg+=c; + } + } + } + + // PHASE 2: apply the macro function + if (argCount==def->nargs || + (argCount>def->nargs && def->varArgs)) // matching parameters lists + { + uint k=0; + // substitution of all formal arguments + QCString resExpr; + const QCString d=def->definition.stripWhiteSpace(); + //printf("Macro definition: %s\n",d.data()); + bool inString=FALSE; + while (k copy it (is unescaped later) + { + k+=2; + resExpr+="@@"; // we unescape these later + } + else if (d.at(k+1)=='-') // no-rescan marker + { + k+=2; + resExpr+="@-"; + } + else // argument marker => read the argument number + { + QCString key="@"; + QCString *subst=0; + bool hash=FALSE; + int l=k-1; + // search for ## backward + if (l>=0 && d.at(l)=='"') l--; + while (l>=0 && d.at(l)==' ') l--; + if (l>0 && d.at(l)=='#' && d.at(l-1)=='#') hash=TRUE; + k++; + // scan the number + while (k='0' && d.at(k)<='9') key+=d.at(k++); + if (!hash) + { + // search for ## forward + l=k; + if (l<(int)d.length() && d.at(l)=='"') l++; + while (l<(int)d.length() && d.at(l)==' ') l++; + if (l<(int)d.length()-1 && d.at(l)=='#' && d.at(l+1)=='#') hash=TRUE; + } + //printf("request key %s result %s\n",key.data(),argTable[key]->data()); + if (key.length()>1 && (subst=argTable[key])) + { + QCString substArg=*subst; + //printf("substArg=`%s'\n",substArg.data()); + // only if no ## operator is before or after the argument + // marker we do macro expansion. + if (!hash) expandExpression(substArg,0,0); + if (inString) + { + //printf("`%s'=stringize(`%s')\n",stringize(*subst).data(),subst->data()); + + // if the marker is inside a string (because a # was put + // before the macro name) we must escape " and \ characters + resExpr+=stringize(substArg); + } + else + { + if (hash && substArg.isEmpty()) + { + resExpr+="@E"; // empty argument will be remove later on + } + else if (g_nospaces) + { + resExpr+=substArg; + } + else + { + resExpr+=" "+substArg+" "; + } + } + } + } + } + else // no marker, just copy + { + if (!inString && d.at(k)=='\"') + { + inString=TRUE; // entering a literal string + } + else if (inString && d.at(k)=='\"' && (d.at(k-1)!='\\' || d.at(k-2)=='\\')) + { + inString=FALSE; // leaving a literal string + } + resExpr+=d.at(k++); + } + } + len=j-pos; + result=resExpr; + //printf("result after substitution `%s' expr=`%s'\n", + // result.data(),expr.mid(pos,len).data()); + return TRUE; + } + return FALSE; +} + + +/*! returns the next identifier in string \a expr by starting at position \a p. + * The position of the identifier is returned (or -1 if nothing is found) + * and \a l is its length. Any quoted strings are skipping during the search. + */ +static int getNextId(const QCString &expr,int p,int *l) +{ + int n; + while (p<(int)expr.length()) + { + char c=expr.at(p++); + if (isdigit(c)) // skip number + { + while (p<(int)expr.length() && isId(expr.at(p))) p++; + } + else if (isalpha(c) || c=='_') // read id + { + n=p-1; + while (p<(int)expr.length() && isId(expr.at(p))) p++; + *l=p-n; + return n; + } + else if (c=='"') // skip string + { + char ppc=0,pc=c; + if (p<(int)expr.length()) c=expr.at(p); + while (p<(int)expr.length() && (c!='"' || (pc=='\\' && ppc!='\\'))) + // continue as long as no " is found, but ignoring \", but not \\" + { + ppc=pc; + pc=c; + c=expr.at(p); + p++; + } + if (p<(int)expr.length()) ++p; // skip closing quote + } + else if (c=='/') // skip C Comment + { + //printf("Found C comment at p=%d\n",p); + char pc=c; + if (p<(int)expr.length()) + { + c=expr.at(p); + if (c=='*') // Start of C comment + { + p++; + while (p<(int)expr.length() && !(pc=='*' && c=='/')) + { + pc=c; + c=expr.at(p++); + } + } + } + //printf("Found end of C comment at p=%d\n",p); + } + } + return -1; +} + +/*! preforms recursive macro expansion on the string \a expr + * starting at position \a pos. + * May read additional characters from the input while re-scanning! + * If \a expandAll is \c TRUE then all macros in the expression are + * expanded, otherwise only the first is expanded. + */ +static void expandExpression(QCString &expr,QCString *rest,int pos) +{ + //printf("expandExpression(%s,%s)\n",expr.data(),rest ? rest->data() : 0); + QCString macroName; + QCString expMacro; + bool definedTest=FALSE; + int i=pos,l,p,len; + while ((p=getNextId(expr,i,&l))!=-1) // search for an macro name + { + bool replaced=FALSE; + macroName=expr.mid(p,l); + //printf("macroName=%s\n",macroName.data()); + if (p<2 || !(expr.at(p-2)=='@' && expr.at(p-1)=='-')) // no-rescan marker? + { + if (g_expandedDict->find(macroName)==0) // expand macro + { + Define *def=DefineManager::instance().isDefined(macroName); + if (definedTest) // macro name was found after defined + { + if (def) expMacro = " 1 "; else expMacro = " 0 "; + replaced=TRUE; + len=l; + definedTest=FALSE; + } + else if (def && def->nargs==-1) // simple macro + { + // substitute the definition of the macro + //printf("macro `%s'->`%s'\n",macroName.data(),def->definition.data()); + if (g_nospaces) + { + expMacro=def->definition.stripWhiteSpace(); + } + else + { + expMacro=" "+def->definition.stripWhiteSpace()+" "; + } + //expMacro=def->definition.stripWhiteSpace(); + replaced=TRUE; + len=l; + //printf("simple macro expansion=`%s'->`%s'\n",macroName.data(),expMacro.data()); + } + else if (def && def->nargs>=0) // function macro + { + replaced=replaceFunctionMacro(expr,rest,p+l,len,def,expMacro); + len+=l; + } + else if (macroName=="defined") + { + //printf("found defined inside macro definition '%s'\n",expr.right(expr.length()-p).data()); + definedTest=TRUE; + } + + if (replaced) // expand the macro and rescan the expression + { + + //printf("replacing `%s'->`%s'\n",expr.mid(p,len).data(),expMacro.data()); + QCString resultExpr=expMacro; + QCString restExpr=expr.right(expr.length()-len-p); + processConcatOperators(resultExpr); + if (def && !def->nonRecursive) + { + g_expandedDict->insert(macroName,def); + expandExpression(resultExpr,&restExpr,0); + g_expandedDict->remove(macroName); + } + expr=expr.left(p)+resultExpr+restExpr; + i=p; + //printf("new expression: %s\n",expr.data()); + } + else // move to the next macro name + { + //printf("moving to the next macro old=%d new=%d\n",i,p+l); + i=p+l; + } + } + else // move to the next macro name + { + expr=expr.left(p)+"@-"+expr.right(expr.length()-p); + //printf("macro already expanded, moving to the next macro expr=%s\n",expr.data()); + i=p+l+2; + //i=p+l; + } + } + else // no re-scan marker found, skip the macro name + { + //printf("skipping marked macro\n"); + i=p+l; + } + } +} + +/*! replaces all occurrences of @@@@ in \a s by @@ + * and removes all occurrences of @@E. + * All identifiers found are replaced by 0L + */ +QCString removeIdsAndMarkers(const char *s) +{ + //printf("removeIdsAndMarkers(%s)\n",s); + const char *p=s; + char c; + bool inNum=FALSE; + QCString result; + if (p) + { + while ((c=*p)) + { + if (c=='@') // replace @@ with @ and remove @E + { + if (*(p+1)=='@') + { + result+=c; + } + else if (*(p+1)=='E') + { + // skip + } + p+=2; + } + else if (isdigit(c)) // number + { + result+=c; + p++; + inNum=TRUE; + } + else if (c=='d' && !inNum) // identifier starting with a `d' + { + if (strncmp(p,"defined ",8)==0 || strncmp(p,"defined(",8)==0) + // defined keyword + { + p+=7; // skip defined + } + else + { + result+="0L"; + p++; + while ((c=*p) && isId(c)) p++; + } + } + else if ((isalpha(c) || c=='_') && !inNum) // replace identifier with 0L + { + result+="0L"; + p++; + while ((c=*p) && isId(c)) p++; + if (*p=='(') // undefined function macro + { + p++; + int count=1; + while ((c=*p++)) + { + if (c=='(') count++; + else if (c==')') + { + count--; + if (count==0) break; + } + else if (c=='/') + { + char pc=c; + c=*++p; + if (c=='*') // start of C comment + { + while (*p && !(pc=='*' && c=='/')) // search end of comment + { + pc=c; + c=*++p; + } + p++; + } + } + } + } + } + else if (c=='/') // skip C comments + { + char pc=c; + c=*++p; + if (c=='*') // start of C comment + { + while (*p && !(pc=='*' && c=='/')) // search end of comment + { + pc=c; + c=*++p; + } + p++; + } + else // oops, not comment but division + { + result+=pc; + goto nextChar; + } + } + else + { +nextChar: + result+=c; + char lc=tolower(c); + if (!isId(lc) && lc!='.' /*&& lc!='-' && lc!='+'*/) inNum=FALSE; + p++; + } + } + } + //printf("removeIdsAndMarkers(%s)=%s\n",s,result.data()); + return result; +} + +/*! replaces all occurrences of @@ in \a s by @ + * \par assumption: + * \a s only contains pairs of @@'s + */ +QCString removeMarkers(const char *s) +{ + const char *p=s; + char c; + QCString result; + if (p) + { + while ((c=*p)) + { + switch(c) + { + case '@': // replace @@ with @ + { + if (*(p+1)=='@') + { + result+=c; + } + p+=2; + } + break; + case '/': // skip C comments + { + result+=c; + char pc=c; + c=*++p; + if (c=='*') // start of C comment + { + while (*p && !(pc=='*' && c=='/')) // search end of comment + { + if (*p=='@' && *(p+1)=='@') + result+=c,p++; + else + result+=c; + pc=c; + c=*++p; + } + if (*p) result+=c,p++; + } + } + break; + case '"': // skip string literals + { + result+=c; + char pc=c; + c=*++p; + while (*p && (c!='"' || pc=='\\')) // no end quote + { + result+=c; + c=*++p; + } + if (*p) result+=c,p++; + } + break; + case '\'': // skip char literals + { + result+=c; + char pc=c; + c=*++p; + while (*p && (c!='\'' || pc=='\\')) // no end quote + { + result+=c; + c=*++p; + } + if (*p) result+=c,p++; + } + break; + default: + { + result+=c; + p++; + } + break; + } + } + } + //printf("RemoveMarkers(%s)=%s\n",s,result.data()); + return result; +} + +/*! compute the value of the expression in string \a expr. + * If needed the function may read additional characters from the input. + */ + +bool computeExpression(const QCString &expr) +{ + QCString e=expr; + expandExpression(e,0,0); + //printf("after expansion `%s'\n",e.data()); + e = removeIdsAndMarkers(e); + if (e.isEmpty()) return FALSE; + //printf("parsing `%s'\n",e.data()); + return parseCppExpression(g_yyFileName,g_yyLineNr,e); +} + +/*! expands the macro definition in \a name + * If needed the function may read additional characters from the input + */ + +QCString expandMacro(const QCString &name) +{ + QCString n=name; + expandExpression(n,0,0); + n=removeMarkers(n); + //printf("expandMacro `%s'->`%s'\n",name.data(),n.data()); + return n; +} + +Define *newDefine() +{ + Define *def=new Define; + def->name = g_defName; + def->definition = g_defText.stripWhiteSpace(); + def->nargs = g_defArgs; + def->fileName = g_yyFileName; + def->fileDef = g_yyFileDef; + def->lineNr = g_yyLineNr; + def->varArgs = g_defVarArgs; + //printf("newDefine: %s %s file: %s\n",def->name.data(),def->definition.data(), + // def->fileDef ? def->fileDef->name().data() : def->fileName.data()); + //printf("newDefine: `%s'->`%s'\n",def->name.data(),def->definition.data()); + if (!def->name.isEmpty() && Doxygen::expandAsDefinedDict[def->name]) + { + def->isPredefined=TRUE; + } + return def; +} + +void addDefine() +{ + if (g_skip) return; // do not add this define as it is inside a + // conditional section (cond command) that is disabled. + if (!Doxygen::gatherDefines) return; + + //printf("addDefine %s %s\n",g_defName.data(),g_defArgsStr.data()); + //ArgumentList *al = new ArgumentList; + //stringToArgumentList(g_defArgsStr,al); + MemberDef *md=new MemberDef( + g_yyFileName,g_yyLineNr, + "#define",g_defName,g_defArgsStr,0, + Public,Normal,FALSE,Member,MemberDef::Define,0,0); + if (!g_defArgsStr.isEmpty()) + { + ArgumentList *argList = new ArgumentList; + //printf("addDefine() g_defName=`%s' g_defArgsStr=`%s'\n",g_defName.data(),g_defArgsStr.data()); + stringToArgumentList(g_defArgsStr,argList); + md->setArgumentList(argList); + } + //printf("Setting initializer for `%s' to `%s'\n",g_defName.data(),g_defText.data()); + int l=g_defLitText.find('\n'); + if (l>0 && g_defLitText.left(l).stripWhiteSpace()=="\\") + { + // strip first line if it only contains a slash + g_defLitText = g_defLitText.right(g_defLitText.length()-l-1); + } + else if (l>0) + { + // align the items on the first line with the items on the second line + int k=l+1; + const char *p=g_defLitText.data()+k; + char c; + while ((c=*p++) && (c==' ' || c=='\t')) k++; + g_defLitText=g_defLitText.mid(l+1,k-l-1)+g_defLitText.stripWhiteSpace(); + } + md->setInitializer(g_defLitText.stripWhiteSpace()); + + //printf("pre.l: md->setFileDef(%p)\n",g_inputFileDef); + md->setFileDef(g_inputFileDef); + md->setDefinition("#define "+g_defName); + + MemberName *mn=Doxygen::functionNameSDict->find(g_defName); + if (mn==0) + { + mn = new MemberName(g_defName); + Doxygen::functionNameSDict->append(g_defName,mn); + } + mn->append(md); + if (g_yyFileDef) + { + g_yyFileDef->insertMember(md); + } + + //Define *d; + //if ((d=defineDict[g_defName])==0) defineDict.insert(g_defName,newDefine()); +} + +static inline void outputChar(char c) +{ + if (g_includeStack.isEmpty() || g_curlyCount>0) g_outputBuf->addChar(c); +} + +static inline void outputArray(const char *a,int len) +{ + if (g_includeStack.isEmpty() || g_curlyCount>0) g_outputBuf->addArray(a,len); +} + +static void readIncludeFile(const QCString &inc) +{ + static bool searchIncludes = Config_getBool("SEARCH_INCLUDES"); + if (!searchIncludes) return; // do not read include files + uint i=0; + + // find the start of the include file name + while (i0 && inc.at(s-1)=='"'; + + // find the end of the include file name + while (is) // valid include file name found + { + // extract include path+name + QCString incFileName=inc.mid(s,i-s).stripWhiteSpace(); + + QCString dosExt = incFileName.right(4); + if (dosExt==".exe" || dosExt==".dll" || dosExt==".tlb") + { + // skip imported binary files (e.g. M$ type libraries) + return; + } + + QCString oldFileName = g_yyFileName; + FileDef *oldFileDef = g_yyFileDef; + int oldLineNr = g_yyLineNr; + //printf("Searching for `%s'\n",incFileName.data()); + + // absIncFileName avoids difficulties for incFileName starting with "../" (bug 641336) + QCString absIncFileName = incFileName; + { + static bool searchIncludes = Config_getBool("SEARCH_INCLUDES"); + QFileInfo fi(g_yyFileName); + if (fi.exists()) + { + QCString absName = QCString(fi.dirPath(TRUE).data())+"/"+incFileName; + QFileInfo fi2(absName); + if (fi2.exists()) + { + absIncFileName=fi2.absFilePath(); + } + else if (searchIncludes) // search in INCLUDE_PATH as well + { + QStrList &includePath = Config_getList("INCLUDE_PATH"); + char *s=includePath.first(); + while (s) + { + QFileInfo fi(s); + if (fi.exists() && fi.isDir()) + { + QCString absName = QCString(fi.absFilePath())+"/"+incFileName; + //printf("trying absName=%s\n",absName.data()); + QFileInfo fi2(absName); + if (fi2.exists()) + { + absIncFileName=fi2.absFilePath(); + break; + } + //printf( "absIncFileName = %s\n", absIncFileName.data() ); + } + s=includePath.next(); + } + } + //printf( "absIncFileName = %s\n", absIncFileName.data() ); + } + } + DefineManager::instance().addInclude(g_yyFileName,absIncFileName); + DefineManager::instance().addFileToContext(absIncFileName); + + // findFile will overwrite g_yyFileDef if found + FileState *fs; + bool alreadyIncluded = FALSE; + //printf("calling findFile(%s)\n",incFileName.data()); + if ((fs=findFile(incFileName,localInclude,alreadyIncluded))) // see if the include file can be found + { + //printf("Found include file!\n"); + if (Debug::isFlagSet(Debug::Preprocessor)) + { + for (i=0;iaddIncludeDependency(ambig ? 0 : incFd,incFileName,localInclude,g_isImported,FALSE); + // add included by dependency + if (g_yyFileDef) + { + //printf("Adding include dependency %s->%s\n",oldFileDef->name().data(),incFileName.data()); + g_yyFileDef->addIncludedByDependency(oldFileDef,oldFileDef->docName(),localInclude,g_isImported); + } + } + else if (g_inputFileDef) + { + g_inputFileDef->addIncludeDependency(0,absIncFileName,localInclude,g_isImported,TRUE); + } + fs->bufState = YY_CURRENT_BUFFER; + fs->lineNr = oldLineNr; + fs->fileName = oldFileName; + // push the state on the stack + g_includeStack.push(fs); + // set the scanner to the include file + + // Deal with file changes due to + // #include's within { .. } blocks + QCString lineStr(g_yyFileName.length()+20); + lineStr.sprintf("# 1 \"%s\" 1\n",g_yyFileName.data()); + outputArray(lineStr.data(),lineStr.length()); + + //fprintf(stderr,"Switching to include file %s\n",incFileName.data()); + g_expectGuard=TRUE; + g_inputBuf = &fs->fileBuf; + g_inputBufPos=0; + yy_switch_to_buffer(yy_create_buffer(0, YY_BUF_SIZE)); + } + else + { + //printf(" calling findFile(%s) alreadyInc=%d\n",incFileName.data(),alreadyIncluded); + if (oldFileDef) + { + bool ambig; + //QCString absPath = incFileName; + //if (QDir::isRelativePath(incFileName)) + //{ + // absPath = QDir::cleanDirPath(oldFileDef->getPath()+"/"+incFileName); + // //printf("%s + %s -> resolved path %s\n",oldFileDef->getPath().data(),incFileName.data(),absPath.data()); + //} + + // change to absolute name for bug 641336 + FileDef *fd = findFileDef(Doxygen::inputNameDict,absIncFileName,ambig); + //printf("%s::findFileDef(%s)=%p\n",oldFileDef->name().data(),incFileName.data(),fd); + // add include dependency to the file in which the #include was found + oldFileDef->addIncludeDependency(ambig ? 0 : fd,incFileName,localInclude,g_isImported,FALSE); + // add included by dependency + if (fd) + { + //printf("Adding include dependency (2) %s->%s ambig=%d\n",oldFileDef->name().data(),fd->name().data(),ambig); + fd->addIncludedByDependency(oldFileDef,oldFileDef->docName(),localInclude,g_isImported); + } + } + else if (g_inputFileDef) + { + g_inputFileDef->addIncludeDependency(0,absIncFileName,localInclude,g_isImported,TRUE); + } + if (Debug::isFlagSet(Debug::Preprocessor)) + { + if (alreadyIncluded) + { + Debug::print(Debug::Preprocessor,0,"#include %s: already included! skipping...\n",incFileName.data()); + } + else + { + Debug::print(Debug::Preprocessor,0,"#include %s: not found! skipping...\n",incFileName.data()); + } + //printf("error: include file %s not found\n",yytext); + } + if (g_curlyCount>0 && !alreadyIncluded) // failed to find #include inside { ... } + { + warn(g_yyFileName,g_yyLineNr,"Warning: include file %s not found, perhaps you forgot to add its directory to INCLUDE_PATH?",incFileName.data()); + } + } + } +} + +/* ----------------------------------------------------------------- */ + +static void startCondSection(const char *sectId) +{ + g_condStack.push(new bool(g_skip)); + if (Config_getList("ENABLED_SECTIONS").find(sectId)==-1) + { + g_skip=TRUE; + } +} + +static void endCondSection() +{ + if (g_condStack.isEmpty()) + { + g_skip=FALSE; + } + else + { + bool *ctx = g_condStack.pop(); + g_skip=*ctx; + } +} + +static void forceEndCondSection() +{ + while (!g_condStack.isEmpty()) + { + g_condStack.pop(); + } + g_skip=FALSE; +} + +static QCString escapeAt(const char *text) +{ + QCString result; + if (text) + { + char c; + const char *p=text; + while ((c=*p++)) + { + if (c=='@') result+="@@"; else result+=c; + } + } + return result; +} + +static char resolveTrigraph(char c) +{ + switch (c) + { + case '=': return '#'; + case '/': return '\\'; + case '\'': return '^'; + case '(': return '['; + case ')': return ']'; + case '!': return '|'; + case '<': return '{'; + case '>': return '}'; + case '-': return '~'; + } + return '?'; +} + +/* ----------------------------------------------------------------- */ + +#undef YY_INPUT +#define YY_INPUT(buf,result,max_size) result=yyread(buf,max_size); + +static int yyread(char *buf,int max_size) +{ + int bytesInBuf = g_inputBuf->curPos()-g_inputBufPos; + int bytesToCopy = QMIN(max_size,bytesInBuf); + memcpy(buf,g_inputBuf->data()+g_inputBufPos,bytesToCopy); + g_inputBufPos+=bytesToCopy; + return bytesToCopy; +} + +/* ----------------------------------------------------------------- */ + +%} + +ID [a-z_A-Z][a-z_A-Z0-9]* +B [ \t] +BN [ \t\r\n] +CHARLIT (("'"\\[0-7]{1,3}"'")|("'"\\."'")|("'"[^'\\\n]{1,4}"'")) + +%option noyywrap + +%x Start +%x Command +%x SkipCommand +%x SkipLine +%x SkipString +%x CopyLine +%x CopyString +%x Include +%x IncludeID +%x EndImport +%x DefName +%x DefineArg +%x DefineText +%x SkipCPPBlock +%x Ifdef +%x Ifndef +%x SkipCComment +%x CopyCComment +%x SkipVerbatim +%x SkipCPPComment +%x RemoveCComment +%x RemoveCPPComment +%x Guard +%x DefinedExpr1 +%x DefinedExpr2 +%x SkipDoubleQuote +%x SkipSingleQuote +%x UndefName +%x IgnoreLine +%x FindDefineArgs +%x ReadString +%x CondLine + +%% + +<*>\x06 +<*>\x00 +<*>\r +<*>"??"[=/'()!<>-] { // Trigraph + unput(resolveTrigraph(yytext[2])); + } +^{B}*"#" { BEGIN(Command); } +^{B}*/[^#] { + outputArray(yytext,yyleng); + BEGIN(CopyLine); + } +^{B}*[_A-Z][_A-Z0-9]*{B}*"("[^\)\n]*")"/{BN}{1,10}*[:{] { // constructors? + int i; + for (i=yyleng-1;i>=0;i--) + { + unput(yytext[i]); + } + BEGIN(CopyLine); + } +^{B}*[_A-Z][_A-Z0-9]*{B}*"("[^\(\)\n]*"("[^\)\n]*")"[^\)\n]*")"{B}*\n | // function list macro with one (...) argument, e.g. for K_GLOBAL_STATIC_WITH_ARGS +^{B}*[_A-Z][_A-Z0-9]*{B}*"("[^\)\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 && + name!="Q_PROPERTY" && + !( + (g_includeStack.isEmpty() || g_curlyCount>0) && + g_macroExpansion && + (def=DefineManager::instance().isDefined(name)) && + /*macroIsAccessible(def) &&*/ + (!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); + } + } +"extern"{BN}{0,80}"\"C\""*{BN}{0,80}"{" { + QCString text=yytext; + g_yyLineNr+=text.contains('\n'); + outputArray(yytext,yyleng); + } +"{" { // count brackets inside the main file + if (g_includeStack.isEmpty()) + { + g_curlyCount++; + } + outputChar(*yytext); + } +"}" { // count brackets inside the main file + if (g_includeStack.isEmpty() && g_curlyCount>0) + { + g_curlyCount--; + } + outputChar(*yytext); + } +"'"\\[0-7]{1,3}"'" { + outputArray(yytext,yyleng); + } +"'"\\."'" { + outputArray(yytext,yyleng); + } +"'"."'" { + outputArray(yytext,yyleng); + } +\" { + outputChar(*yytext); + BEGIN( CopyString ); + } +[^\"\\\r\n]+ { + outputArray(yytext,yyleng); + } +\\. { + outputArray(yytext,yyleng); + } +\" { + outputChar(*yytext); + BEGIN( CopyLine ); + } +{ID}/{BN}{0,80}"(" { + g_expectGuard = FALSE; + Define *def=0; + //def=g_globalDefineDict->find(yytext); + //def=DefineManager::instance().isDefined(yytext); + //printf("Search for define %s found=%d g_includeStack.isEmpty()=%d " + // "g_curlyCount=%d g_macroExpansion=%d g_expandOnlyPredef=%d " + // "isPreDefined=%d\n",yytext,def ? 1 : 0, + // g_includeStack.isEmpty(),g_curlyCount,g_macroExpansion,g_expandOnlyPredef, + // def ? def->isPredefined : -1 + // ); + if ((g_includeStack.isEmpty() || g_curlyCount>0) && + g_macroExpansion && + (def=DefineManager::instance().isDefined(yytext)) && + /*(def->isPredefined || macroIsAccessible(def)) && */ + (!g_expandOnlyPredef || def->isPredefined) + ) + { + //printf("Found it! #args=%d\n",def->nargs); + g_roundCount=0; + g_defArgsStr=yytext; + if (def->nargs==-1) // no function macro + { + QCString result = def->isPredefined ? def->definition : expandMacro(g_defArgsStr); + outputArray(result,result.length()); + } + else // zero or more arguments + { + g_findDefArgContext = CopyLine; + BEGIN(FindDefineArgs); + } + } + else + { + outputArray(yytext,yyleng); + } + } +{ID} { + Define *def=0; + if ((g_includeStack.isEmpty() || g_curlyCount>0) && + g_macroExpansion && + (def=DefineManager::instance().isDefined(yytext)) && + def->nargs==-1 && + /*(def->isPredefined || macroIsAccessible(def)) &&*/ + (!g_expandOnlyPredef || def->isPredefined) + ) + { + QCString result=def->isPredefined ? def->definition : expandMacro(yytext); + outputArray(result,result.length()); + } + else + { + outputArray(yytext,yyleng); + } + } +"\\"\r?/\n { // strip line continuation characters + } +. { + outputChar(*yytext); + } +\n { + outputChar('\n'); + BEGIN(Start); + g_yyLineNr++; + } +"(" { + g_defArgsStr+='('; + g_roundCount++; + } +")" { + g_defArgsStr+=')'; + g_roundCount--; + if (g_roundCount==0) + { + QCString result=expandMacro(g_defArgsStr); + //printf("g_defArgsStr=`%s'->`%s'\n",g_defArgsStr.data(),result.data()); + if (g_findDefArgContext==CopyLine) + { + outputArray(result,result.length()); + BEGIN(g_findDefArgContext); + } + else // g_findDefArgContext==IncludeID + { + readIncludeFile(result); + g_nospaces=FALSE; + BEGIN(Start); + } + } + } + /* +")"{B}*"(" { + g_defArgsStr+=yytext; + } + */ +{CHARLIT} { + g_defArgsStr+=yytext; + } +\" { + g_defArgsStr+=*yytext; + BEGIN(ReadString); + } +\n { + g_yyLineNr++; + outputChar('\n'); + } +"@" { + g_defArgsStr+="@@"; + } +. { + g_defArgsStr+=*yytext; + } +"\"" { + g_defArgsStr+=*yytext; + BEGIN(FindDefineArgs); + } +"//"|"/*" { + g_defArgsStr+=yytext; + } +\\. { + g_defArgsStr+=yytext; + } +. { + g_defArgsStr+=*yytext; + } +("include"|"import"){B}+/{ID} { + g_isImported = yytext[1]=='m'; + if (g_macroExpansion) + BEGIN(IncludeID); + } +("include"|"import"){B}*[<"] { + g_isImported = yytext[1]=='m'; + char c[2]; + c[0]=yytext[yyleng-1];c[1]='\0'; + g_incName=c; + BEGIN(Include); + } +("cmake")?"define"{B}+ { + //printf("!!!DefName\n"); + BEGIN(DefName); + } +"ifdef"/{B}*"(" { + incrLevel(); + g_guardExpr.resize(0); + BEGIN(DefinedExpr2); + } +"ifdef"/{B}+ { + //printf("Pre.l: ifdef\n"); + incrLevel(); + g_guardExpr.resize(0); + BEGIN(DefinedExpr1); + } +"ifndef"/{B}*"(" { + incrLevel(); + g_guardExpr="! "; + BEGIN(DefinedExpr2); + } +"ifndef"/{B}+ { + incrLevel(); + g_guardExpr="! "; + BEGIN(DefinedExpr1); + } +"if"/[ \t(!] { + incrLevel(); + g_guardExpr.resize(0); + BEGIN(Guard); + } +("elif"|"else"{B}*"if")/[ \t(!] { + if (!otherCaseDone()) + { + g_guardExpr.resize(0); + BEGIN(Guard); + } + else + { + g_ifcount=0; + BEGIN(SkipCPPBlock); + } + } +"else"/[^a-z_A-Z0-9] { + //printf("else g_levelGuard[%d]=%d\n",g_level-1,g_levelGuard[g_level-1]); + if (otherCaseDone()) + { + g_ifcount=0; + BEGIN(SkipCPPBlock); + } + else + { + setCaseDone(TRUE); + //g_levelGuard[g_level-1]=TRUE; + } + } +"undef"{B}+ { + BEGIN(UndefName); + } +("elif"|"else"{B}*"if")/[ \t(!] { + if (!otherCaseDone()) + { + g_guardExpr.resize(0); + BEGIN(Guard); + } + } +"endif"/[^a-z_A-Z0-9] { + //printf("Pre.l: #endif\n"); + decrLevel(); + } +\n { + outputChar('\n'); + BEGIN(Start); + g_yyLineNr++; + } +"pragma"{B}+"once" { + g_expectGuard = FALSE; + } +{ID} { // unknown directive + BEGIN(IgnoreLine); + } +\\[\r]?\n { + outputChar('\n'); + g_yyLineNr++; + } +. +. +{ID} { + Define *def; + if ((def=DefineManager::instance().isDefined(yytext)) + /*&& !def->isPredefined*/ + && !def->nonRecursive + ) + { + //printf("undefining %s\n",yytext); + def->undef=TRUE; + } + BEGIN(Start); + } +\\[\r]?\n { + outputChar('\n'); + g_guardExpr+=' '; + g_yyLineNr++; + } +"defined"/{B}*"(" { + BEGIN(DefinedExpr2); + } +"defined"/{B}+ { + BEGIN(DefinedExpr1); + } +{ID} { g_guardExpr+=yytext; } +. { g_guardExpr+=*yytext; } +\n { + unput(*yytext); + //printf("Guard: `%s'\n", + // g_guardExpr.data()); + bool guard=computeExpression(g_guardExpr); + setCaseDone(guard); + //printf("if g_levelGuard[%d]=%d\n",g_level-1,g_levelGuard[g_level-1]); + if (guard) + { + BEGIN(Start); + } + else + { + g_ifcount=0; + BEGIN(SkipCPPBlock); + } + } +\\\n { g_yyLineNr++; outputChar('\n'); } +{ID} { + if (DefineManager::instance().isDefined(yytext) || g_guardName==yytext) + g_guardExpr+=" 1L "; + else + g_guardExpr+=" 0L "; + g_lastGuardName=yytext; + BEGIN(Guard); + } +{ID} { + if (DefineManager::instance().isDefined(yytext) || g_guardName==yytext) + g_guardExpr+=" 1L "; + else + g_guardExpr+=" 0L "; + g_lastGuardName=yytext; + } +\n { // should not happen, handle anyway + g_yyLineNr++; + g_ifcount=0; + BEGIN(SkipCPPBlock); + } +")" { + BEGIN(Guard); + } +. +^{B}*"#" { BEGIN(SkipCommand); } +^{B}*/[^#] { BEGIN(SkipLine); } +\n { g_yyLineNr++; outputChar('\n'); } +. +"if"(("n")?("def"))?/[ \t(!] { + incrLevel(); + g_ifcount++; + //printf("#if... depth=%d\n",g_ifcount); + } +"else" { + //printf("Else! g_ifcount=%d otherCaseDone=%d\n",g_ifcount,otherCaseDone()); + if (g_ifcount==0 && !otherCaseDone()) + { + setCaseDone(TRUE); + //outputChar('\n'); + BEGIN(Start); + } + } +("elif"|"else"{B}*"if")/[ \t(!] { + if (g_ifcount==0) + { + if (!otherCaseDone()) + { + g_guardExpr.resize(0); + g_lastGuardName.resize(0); + BEGIN(Guard); + } + else + { + BEGIN(SkipCPPBlock); + } + } + } +"endif" { + g_expectGuard = FALSE; + decrLevel(); + if (--g_ifcount<0) + { + //outputChar('\n'); + BEGIN(Start); + } + } +\n { + outputChar('\n'); + g_yyLineNr++; + BEGIN(SkipCPPBlock); + } +{ID} { // unknown directive + BEGIN(SkipLine); + } +. +[^'"/\n]+ +{CHARLIT} { } +\" { + BEGIN(SkipString); + } +. +"//"/[^\n]* { + } +"//"[^\n]* { + g_lastCPPContext=YY_START; + BEGIN(RemoveCPPComment); + } +"/*"/[^\n]* { + } +"/*"/[^\n]* { + g_lastCContext=YY_START; + BEGIN(RemoveCComment); + } +\n { + outputChar('\n'); + g_yyLineNr++; + BEGIN(SkipCPPBlock); + } +[^"\\\n]+ { } +\\. { } +\" { + BEGIN(SkipLine); + } +. { } +{ID}{B}*/"(" { + g_nospaces=TRUE; + g_roundCount=0; + g_defArgsStr=yytext; + g_findDefArgContext = IncludeID; + BEGIN(FindDefineArgs); + } +{ID} { + g_nospaces=TRUE; + readIncludeFile(expandMacro(yytext)); + BEGIN(Start); + } +[^\">\n]+[\">] { + g_incName+=yytext; + readIncludeFile(g_incName); + if (g_isImported) + { + BEGIN(EndImport); + } + else + { + BEGIN(Start); + } + } +[^\\\n]*/\n { + BEGIN(Start); + } +\\[\r]?"\n" { + outputChar('\n'); + g_yyLineNr++; + } +. { + } +{ID}/("\\\n")*"(" { // define with argument + //printf("Define() `%s'\n",yytext); + g_argDict = new QDict(31); + g_argDict->setAutoDelete(TRUE); + g_defArgs = 0; + g_defArgsStr.resize(0); + g_defText.resize(0); + g_defLitText.resize(0); + g_defName = yytext; + g_defVarArgs = FALSE; + g_defExtraSpacing.resize(0); + BEGIN(DefineArg); + } +{ID}{B}+"1"/[ \r\t\n] { // special case: define with 1 -> can be "guard" + //printf("Define `%s'\n",yytext); + g_argDict = 0; + g_defArgs = -1; + g_defArgsStr.resize(0); + g_defName = yytext; + g_defName = g_defName.left(g_defName.length()-1).stripWhiteSpace(); + g_defVarArgs = FALSE; + //printf("Guard check: %s!=%s || %d\n", + // g_defName.data(),g_lastGuardName.data(),g_expectGuard); + if ( g_defName!=g_lastGuardName || !g_expectGuard) + { // define may appear in the output + QCString tmp=(QCString)"#define "+g_defName; + outputArray(tmp.data(),tmp.length()); + g_quoteArg=FALSE; + g_insideComment=FALSE; + g_lastGuardName.resize(0); + g_defText="1"; + g_defLitText="1"; + BEGIN(DefineText); + } + else // define is a guard => hide + { + //printf("Found a guard %s\n",yytext); + g_defText.resize(0); + g_defLitText.resize(0); + BEGIN(Start); + } + g_expectGuard=FALSE; + } +{ID}/{B}*"\n" { // empty define + g_argDict = 0; + g_defArgs = -1; + g_defName = yytext; + g_defArgsStr.resize(0); + g_defText.resize(0); + g_defLitText.resize(0); + g_defVarArgs = FALSE; + //printf("Guard check: %s!=%s || %d\n", + // g_defName.data(),g_lastGuardName.data(),g_expectGuard); + if ( g_defName!=g_lastGuardName || !g_expectGuard) + { // define may appear in the output + QCString tmp=(QCString)"#define "+g_defName; + outputArray(tmp.data(),tmp.length()); + g_quoteArg=FALSE; + g_insideComment=FALSE; + if (g_insideCS) g_defText="1"; // for C#, use "1" as define text + BEGIN(DefineText); + } + else // define is a guard => hide + { + //printf("Found a guard %s\n",yytext); + g_guardName = yytext; + g_lastGuardName.resize(0); + BEGIN(Start); + } + g_expectGuard=FALSE; + } +{ID}/{B}* { // define with content + //printf("Define `%s'\n",yytext); + g_argDict = 0; + g_defArgs = -1; + g_defArgsStr.resize(0); + g_defText.resize(0); + g_defLitText.resize(0); + g_defName = yytext; + g_defVarArgs = FALSE; + QCString tmp=(QCString)"#define "+g_defName+g_defArgsStr; + outputArray(tmp.data(),tmp.length()); + g_quoteArg=FALSE; + g_insideComment=FALSE; + BEGIN(DefineText); + } +"\\\n" { + g_defExtraSpacing+="\n"; + g_yyLineNr++; + } +","{B}* { g_defArgsStr+=yytext; } +"("{B}* { g_defArgsStr+=yytext; } +{B}*")"{B}* { + g_defArgsStr+=yytext; + QCString tmp=(QCString)"#define "+g_defName+g_defArgsStr+g_defExtraSpacing; + outputArray(tmp.data(),tmp.length()); + g_quoteArg=FALSE; + g_insideComment=FALSE; + BEGIN(DefineText); + } +"..." { // Variadic macro + g_defVarArgs = TRUE; + g_defArgsStr+=yytext; + g_argDict->insert("__VA_ARGS__",new int(g_defArgs)); + g_defArgs++; + } +{ID}{B}*("..."?) { + //printf("Define addArg(%s)\n",yytext); + QCString argName=yytext; + g_defVarArgs = yytext[yyleng-1]=='.'; + if (g_defVarArgs) // strip ellipsis + { + argName=argName.left(argName.length()-3); + } + argName = argName.stripWhiteSpace(); + g_defArgsStr+=yytext; + g_argDict->insert(argName,new int(g_defArgs)); + g_defArgs++; + } + /* +"/ **"|"/ *!" { + g_defText+=yytext; + g_defLitText+=yytext; + g_insideComment=TRUE; + } +"* /" { + g_defText+=yytext; + g_defLitText+=yytext; + g_insideComment=FALSE; + } + */ +"/*"[!*]? { + g_defText+=yytext; + g_defLitText+=yytext; + g_lastCContext=YY_START; + g_commentCount=1; + BEGIN(CopyCComment); + } +"//"[!/]? { + outputArray(yytext,yyleng); + g_lastCPPContext=YY_START; + g_defLitText+=' '; + BEGIN(SkipCPPComment); + } +[/]?"*/" { + if (yytext[0]=='/') outputChar('/'); + outputChar('*');outputChar('/'); + if (--g_commentCount<=0) + { + if (g_lastCContext==Start) + // small hack to make sure that ^... rule will + // match when going to Start... Example: "/*...*/ some stuff..." + { + YY_CURRENT_BUFFER->yy_at_bol=1; + } + BEGIN(g_lastCContext); + } + } +"//"("/")* { + outputArray(yytext,yyleng); + } +"/*" { + outputChar('/');outputChar('*'); + //g_commentCount++; + } +[\\@][\\@]("f{"|"f$"|"f[") { + outputArray(yytext,yyleng); + } +[\\@][\\@]("verbatim"|"latexonly"|"htmlonly"|"xmlonly"|"rtfonly"|"manonly"|"dot"|"code"){BN}+ { + outputArray(yytext,yyleng); + g_yyLineNr+=QCString(yytext).contains('\n'); + } +[\\@]("verbatim"|"latexonly"|"htmlonly"|"xmlonly"|"rtfonly"|"manonly"|"dot"|"code"){BN}+ { + outputArray(yytext,yyleng); + g_yyLineNr+=QCString(yytext).contains('\n'); + if (yytext[1]=='f') + { + g_blockName="f"; + } + else + { + g_blockName=QCString(&yytext[1]).stripWhiteSpace(); + } + BEGIN(SkipVerbatim); + } +[\\@]"cond"[ \t]+ { // conditional section + g_condCtx = YY_START; + outputArray(yytext,yyleng); + BEGIN(CondLine); + } +[a-z_A-Z][a-z_A-Z0-9.\-]* { + startCondSection(yytext); + outputArray(yytext,yyleng); + BEGIN(g_condCtx); + } +[\\@]"cond"[ \t\r]*/\n { + g_condCtx = YY_START; + outputArray(yytext,yyleng); + } +. { + unput(*yytext); + startCondSection(" "); + BEGIN(g_condCtx); + } +[\\@]"endcond"/[^a-z_A-Z0-9] { + outputArray(yytext,yyleng); + endCondSection(); + } +[\\@]("endverbatim"|"endlatexonly"|"endhtmlonly"|"endxmlonly"|"endrtfonly"|"endmanonly"|"enddot"|"endcode"|"f$"|"f]"|"f}") { /* end of verbatim block */ + outputArray(yytext,yyleng); + if (yytext[1]=='f' && g_blockName=="f") + { + BEGIN(SkipCComment); + } + else if (&yytext[4]==g_blockName) + { + BEGIN(SkipCComment); + } + } +"*/"|"/*" { + outputArray(yytext,yyleng); + } +[^*\\@\x06\n\/]+ { + outputArray(yytext,yyleng); + } +\n { + g_yyLineNr++; + outputChar('\n'); + } +. { + outputChar(*yytext); + } +[^*a-z_A-Z\n]+ { + g_defLitText+=yytext; + g_defText+=escapeAt(yytext); + } +"*/" { + g_defLitText+=yytext; + g_defText+=yytext; + BEGIN(g_lastCContext); + } +\n { + g_yyLineNr++; + g_defLitText+=yytext; + g_defText+=' '; + } +"*/"{B}*"#" { // see bug 594021 for a usecase for this rule + if (g_lastCContext==SkipCPPBlock) + { + BEGIN(SkipCommand); + } + else + { + REJECT; + } + } +"*/" { BEGIN(g_lastCContext); } +"//" +"/*" +[^*\x06\n]+ +\n { g_yyLineNr++; outputChar('\n'); } +. +[^\n\/\\@]+ { + outputArray(yytext,yyleng); + } +\n { + unput(*yytext); + BEGIN(g_lastCPPContext); + } +"/*" { + outputChar('/');outputChar('*'); + } +"//" { + outputChar('/');outputChar('/'); + } +[^\x06\@\\\n]+ { + outputArray(yytext,yyleng); + } +. { + outputChar(*yytext); + } +"/*" +"//" +[^\x06\n]+ +. +"#" { + g_quoteArg=TRUE; + g_defLitText+=yytext; + } +{ID} { + g_defLitText+=yytext; + if (g_quoteArg) + { + g_defText+="\""; + } + if (g_defArgs>0) + { + int *n; + if ((n=(*g_argDict)[yytext])) + { + //if (!g_quoteArg) g_defText+=' '; + g_defText+='@'; + QCString numStr; + numStr.sprintf("%d",*n); + g_defText+=numStr; + //if (!g_quoteArg) g_defText+=' '; + } + else + { + g_defText+=yytext; + } + } + else + { + g_defText+=yytext; + } + if (g_quoteArg) + { + g_defText+="\""; + } + g_quoteArg=FALSE; + } +. { + g_defLitText+=yytext; + g_defText+=yytext; + } +\\[\r]?\n { + g_defLitText+=yytext; + outputChar('\n'); + g_defText += ' '; g_yyLineNr++; + } +\n { + QCString comment=extractTrailingComment(g_defLitText); + g_defLitText+=yytext; + if (!comment.isEmpty()) + { + outputArray(comment,comment.length()); + g_defLitText=g_defLitText.left(g_defLitText.length()-comment.length()-1); + } + outputChar('\n'); + Define *def=0; + //printf("Define name=`%s' text=`%s' litTexti=`%s'\n",g_defName.data(),g_defText.data(),g_defLitText.data()); + if (g_includeStack.isEmpty() || g_curlyCount>0) + { + addDefine(); + } + def=DefineManager::instance().isDefined(g_defName); + if (def==0) // new define + { + //printf("new define '%s'!\n",g_defName.data()); + Define *nd = newDefine(); + DefineManager::instance().addDefine(g_yyFileName,nd); + + // also add it to the local file list if it is a source file + //if (g_isSource && g_includeStack.isEmpty()) + //{ + // g_fileDefineDict->insert(g_defName,nd); + //} + } + else if (def /*&& macroIsAccessible(def)*/) + // name already exists + { + //printf("existing define!\n"); + //printf("define found\n"); + if (def->undef) // undefined name + { + def->undef = FALSE; + def->name = g_defName; + def->definition = g_defText.stripWhiteSpace(); + def->nargs = g_defArgs; + def->fileName = g_yyFileName.copy(); + def->lineNr = g_yyLineNr; + } + else + { + //printf("error: define %s is defined more than once!\n",g_defName.data()); + } + } + delete g_argDict; g_argDict=0; + g_yyLineNr++; + g_lastGuardName.resize(0); + BEGIN(Start); + } +{B}* { g_defText += ' '; g_defLitText+=yytext; } +{B}*"##"{B}* { g_defText += "##"; g_defLitText+=yytext; } +"@" { g_defText += "@@"; g_defLitText+=yytext; } +\" { + g_defText += *yytext; + g_defLitText+=yytext; + if (!g_insideComment) + { + BEGIN(SkipDoubleQuote); + } + } +\' { g_defText += *yytext; + g_defLitText+=yytext; + if (!g_insideComment) + { + BEGIN(SkipSingleQuote); + } + } +"//"[/]? { g_defText += yytext; g_defLitText+=yytext; } +"/*" { g_defText += yytext; g_defLitText+=yytext; } +\" { + g_defText += *yytext; g_defLitText+=yytext; + BEGIN(DefineText); + } +\\. { + g_defText += yytext; g_defLitText+=yytext; + } +\' { + g_defText += *yytext; g_defLitText+=yytext; + BEGIN(DefineText); + } +. { g_defText += *yytext; g_defLitText+=yytext; } +. { g_defText += *yytext; g_defLitText+=yytext; } +. { g_defText += *yytext; g_defLitText+=yytext; } +<> { + //fprintf(stderr,"End of include file\n"); + //printf("Include stack depth=%d\n",g_includeStack.count()); + if (g_includeStack.isEmpty()) + { + //fprintf(stderr,"Terminating scanner!\n"); + yyterminate(); + } + else + { + FileState *fs=g_includeStack.pop(); + //fileDefineCache->merge(g_yyFileName,fs->fileName); + YY_BUFFER_STATE oldBuf = YY_CURRENT_BUFFER; + yy_switch_to_buffer( fs->bufState ); + yy_delete_buffer( oldBuf ); + g_yyLineNr = fs->lineNr; + //preYYin = fs->oldYYin; + g_inputBuf = fs->oldFileBuf; + g_inputBufPos = fs->oldFileBufPos; + setFileName(fs->fileName); + //fprintf(stderr,"######## FileName %s\n",g_yyFileName.data()); + + // Deal with file changes due to + // #include's within { .. } blocks + QCString lineStr(15+g_yyFileName.length()); + lineStr.sprintf("# %d \"%s\" 2",g_yyLineNr,g_yyFileName.data()); + outputArray(lineStr.data(),lineStr.length()); + + delete fs; fs=0; + } + } +<*>"/*"/"*/" | +<*>"/*"[*]? { + outputArray(yytext,yyleng); + g_lastCContext=YY_START; + g_commentCount=1; + if (yyleng==3) g_lastGuardName.resize(0); // reset guard in case the #define is documented! + BEGIN(SkipCComment); + } +<*>"//"[/]? { + outputArray(yytext,yyleng); + g_lastCPPContext=YY_START; + if (yyleng==3) g_lastGuardName.resize(0); // reset guard in case the #define is documented! + BEGIN(SkipCPPComment); + } +<*>\n { + outputChar('\n'); + g_yyLineNr++; + } +<*>. { + g_expectGuard = FALSE; + outputChar(*yytext); + } + +%% + +/*@ ---------------------------------------------------------------------------- + */ + +static int getNextChar(const QCString &expr,QCString *rest,uint &pos) +{ + //printf("getNextChar(%s,%s,%d)\n",expr.data(),rest ? rest->data() : 0,pos); + if (posisEmpty()) + { + int cc=rest->at(0); + *rest=rest->right(rest->length()-1); + //printf("%c=rest\n",cc); + return cc; + } + else + { + int cc=yyinput(); + //printf("%c=yyinput()\n",cc); + return cc; + } +} + +static int getCurrentChar(const QCString &expr,QCString *rest,uint pos) +{ + //printf("getCurrentChar(%s,%s,%d)\n",expr.data(),rest ? rest->data() : 0,pos); + if (posisEmpty()) + { + int cc=rest->at(0); + //printf("%c=rest\n",cc); + return cc; + } + else + { + int cc=yyinput(); + returnCharToStream(cc); + //unput((char)cc); + //printf("%c=yyinput()\n",cc); + return cc; + } +} + +static void unputChar(const QCString &expr,QCString *rest,uint &pos,char c) +{ + //printf("unputChar(%s,%s,%d,%c)\n",expr.data(),rest ? rest->data() : 0,pos,c); + if (posprepend(cs); + } + else + { + //unput(c); + returnCharToStream(c); + } + //printf("result: unputChar(%s,%s,%d,%c)\n",expr.data(),rest ? rest->data() : 0,pos,c); +} + +void addSearchDir(const char *dir) +{ + QFileInfo fi(dir); + if (fi.isDir()) g_pathList->append(fi.absFilePath()); +} + +void initPreprocessor() +{ + g_pathList = new QStrList; + addSearchDir("."); + g_expandedDict = new DefineDict(17); +} + +void cleanUpPreprocessor() +{ + delete g_expandedDict; g_expandedDict=0; + delete g_pathList; g_pathList=0; + DefineManager::deleteInstance(); +} + + +void preprocessFile(const char *fileName,BufStr &input,BufStr &output) +{ + uint orgOffset=output.curPos(); + //printf("##########################\n%s\n####################\n", + // input.data()); + + g_macroExpansion = Config_getBool("MACRO_EXPANSION"); + g_expandOnlyPredef = Config_getBool("EXPAND_ONLY_PREDEF"); + g_curlyCount=0; + g_nospaces=FALSE; + g_inputBuf=&input; + g_inputBufPos=0; + g_outputBuf=&output; + g_includeStack.setAutoDelete(TRUE); + g_includeStack.clear(); + g_expandedDict->setAutoDelete(FALSE); + g_expandedDict->clear(); + g_condStack.clear(); + g_condStack.setAutoDelete(TRUE); + //g_fileDefineDict->clear(); + + setFileName(fileName); + g_inputFileDef = g_yyFileDef; + DefineManager::instance().startContext(g_yyFileName); + + static bool firstTime=TRUE; + if (firstTime) + { + // add predefined macros + char *defStr; + QStrList &predefList = Config_getList("PREDEFINED"); + QStrListIterator sli(predefList); + for (sli.toFirst();(defStr=sli.current());++sli) + { + QCString ds = defStr; + int i_equals=ds.find('='); + int i_obrace=ds.find('('); + int i_cbrace=ds.find(')'); + bool nonRecursive = i_equals>0 && ds.at(i_equals-1)==':'; + + if (i_obrace==0) continue; // no define name + + if (i_obrace argDict(17); + argDict.setAutoDelete(TRUE); + int i=i_obrace+1,p,l,count=0; + // gather the formal arguments in a dictionary + while (ii) definition+=tmp.mid(i,p-i); + int *argIndex; + if ((argIndex=argDict[tmp.mid(p,l)])!=0) + { + QCString marker; + marker.sprintf(" @%d ",*argIndex); + definition+=marker; + } + else + { + definition+=tmp.mid(p,l); + } + i=p+l; + } + if (i<(int)tmp.length()) definition+=tmp.mid(i,tmp.length()-i); + + // add define definition to the dictionary of defines for this file + QCString dname = ds.left(i_obrace); + if (!dname.isEmpty()) + { + Define *def = new Define; + def->name = dname; + def->definition = definition; + def->nargs = count; + def->isPredefined = TRUE; + def->nonRecursive = nonRecursive; + def->fileDef = g_yyFileDef; + def->fileName = fileName; + DefineManager::instance().addDefine(g_yyFileName,def); + } + + //printf("#define `%s' `%s' #nargs=%d\n", + // def->name.data(),def->definition.data(),def->nargs); + } + else if ((i_obrace==-1 || i_obrace>i_equals) && + (i_cbrace==-1 || i_cbrace>i_equals) && + !ds.isEmpty() && (int)ds.length()>i_equals + ) // predefined non-function macro definition + { + //printf("predefined normal macro '%s'\n",defStr); + Define *def = new Define; + if (i_equals==-1) // simple define without argument + { + def->name = ds; + def->definition = "1"; // substitute occurrences by 1 (true) + } + else // simple define with argument + { + int ine=i_equals - (nonRecursive ? 1 : 0); + def->name = ds.left(ine); + def->definition = ds.right(ds.length()-i_equals-1); + } + if (!def->name.isEmpty()) + { + def->nargs = -1; + def->isPredefined = TRUE; + def->nonRecursive = nonRecursive; + def->fileDef = g_yyFileDef; + def->fileName = fileName; + DefineManager::instance().addDefine(g_yyFileName,def); + } + else + { + delete def; + } + + //printf("#define `%s' `%s' #nargs=%d\n", + // def->name.data(),def->definition.data(),def->nargs); + } + } + //firstTime=FALSE; + } + + g_yyLineNr = 1; + g_level = 0; + g_ifcount = 0; + + BEGIN( Start ); + + g_expectGuard = guessSection(fileName)==Entry::HEADER_SEC; + g_guardName.resize(0); + g_lastGuardName.resize(0); + g_guardExpr.resize(0); + + preYYlex(); + g_lexInit=TRUE; + + // make sure we don't extend a \cond with missing \endcond over multiple files (see bug 624829) + forceEndCondSection(); + + // remove locally defined macros so they can be redefined in another source file + //if (g_fileDefineDict->count()>0) + //{ + // QDictIterator di(*g_fileDefineDict); + // Define *d; + // for (di.toFirst();(d=di.current());++di) + // { + // g_globalDefineDict->remove(di.currentKey()); + // } + // g_fileDefineDict->clear(); + //} + + if (Debug::isFlagSet(Debug::Preprocessor)) + { + char *orgPos=output.data()+orgOffset; + char *newPos=output.data()+output.curPos(); + Debug::print(Debug::Preprocessor,0,"Preprocessor output (size: %d bytes):\n",newPos-orgPos); + int line=1; + Debug::print(Debug::Preprocessor,0,"---------\n00001 "); + while (orgPos0) + { + Debug::print(Debug::Preprocessor,0,"Macros accessible in this file:\n"); + Debug::print(Debug::Preprocessor,0,"---------\n"); + QDictIterator di(DefineManager::instance().defineContext()); + Define *def; + for (di.toFirst();(def=di.current());++di) + { + Debug::print(Debug::Preprocessor,0,"%s ",def->name.data()); + } + Debug::print(Debug::Preprocessor,0,"\n---------\n"); + } + else + { + Debug::print(Debug::Preprocessor,0,"No macros accessible in this file.\n"); + } + } + DefineManager::instance().endContext(); +} + +void preFreeScanner() +{ +#if defined(YY_FLEX_SUBMINOR_VERSION) + if (g_lexInit) + { + preYYlex_destroy(); + } +#endif +} + +#if !defined(YY_FLEX_SUBMINOR_VERSION) +extern "C" { // some bogus code to keep the compiler happy +// int preYYwrap() { return 1 ; } + void preYYdummy() { yy_flex_realloc(0,0); } +} +#endif + diff --git a/trunk/src/printdocvisitor.h b/trunk/src/printdocvisitor.h new file mode 100644 index 0000000..cd9ba7b --- /dev/null +++ b/trunk/src/printdocvisitor.h @@ -0,0 +1,712 @@ +/****************************************************************************** + * + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#ifndef _PRINTDOCVISITOR_H +#define _PRINTDOCVISITOR_H + +#include "docvisitor.h" + +/*! Concrete visitor implementation for pretty printing */ +class PrintDocVisitor : public DocVisitor +{ + public: + PrintDocVisitor() : DocVisitor(DocVisitor_Other), m_indent(0), + m_needsEnter(FALSE), m_insidePre(FALSE) {} + + //-------------------------------------- + + void visit(DocWord *w) + { + indent_leaf(); + printf("%s",w->word().data()); + } + void visit(DocLinkedWord *w) + { + indent_leaf(); + printf("%s",w->word().data()); + } + void visit(DocWhiteSpace *w) + { + indent_leaf(); + if (m_insidePre) + { + printf("%s",w->chars().data()); + } + else + { + printf(" "); + } + } + void visit(DocSymbol *s) + { + indent_leaf(); + switch(s->symbol()) + { + case DocSymbol::BSlash: printf("\\"); break; + case DocSymbol::At: printf("@"); break; + case DocSymbol::Less: printf("<"); break; + case DocSymbol::Greater: printf(">"); break; + case DocSymbol::Amp: printf("&"); break; + case DocSymbol::Dollar: printf("$"); break; + case DocSymbol::Hash: printf("#"); break; + case DocSymbol::Percent: printf("%%"); break; + case DocSymbol::Copy: printf("©"); break; + case DocSymbol::Apos: printf("'"); break; + case DocSymbol::Quot: printf("\""); break; + case DocSymbol::Lsquo: printf("‘"); break; + case DocSymbol::Rsquo: printf("’"); break; + case DocSymbol::Ldquo: printf("“"); break; + case DocSymbol::Rdquo: printf("”"); break; + case DocSymbol::Ndash: printf("–"); break; + case DocSymbol::Mdash: printf("—"); break; + case DocSymbol::Uml: printf("&%cuml;",s->letter()); break; + case DocSymbol::Acute: printf("&%cacute;",s->letter()); break; + case DocSymbol::Grave: printf("&%cgrave;",s->letter()); break; + case DocSymbol::Circ: printf("&%ccirc;",s->letter()); break; + case DocSymbol::Tilde: printf("&%ctilde;",s->letter()); break; + case DocSymbol::Szlig: printf("ß"); break; + case DocSymbol::Cedil: printf("&%ccedul;",s->letter()); break; + case DocSymbol::Ring: printf("&%cring;",s->letter()); break; + case DocSymbol::Nbsp: printf(" "); break; + case DocSymbol::Aelig: printf("æ"); break; + case DocSymbol::AElig: printf("Æ"); break; + default: + printf("Error: unknown symbol found\n"); + } + } + void visit(DocURL *u) + { + indent_leaf(); + printf("%s",u->url().data()); + } + void visit(DocLineBreak *) + { + indent_leaf(); + printf("
    "); + } + void visit(DocHorRuler *) + { + indent_leaf(); + printf("
    "); + } + void visit(DocStyleChange *s) + { + indent_leaf(); + switch (s->style()) + { + case DocStyleChange::Bold: + if (s->enable()) printf(""); else printf(""); + break; + case DocStyleChange::Italic: + if (s->enable()) printf(""); else printf(""); + break; + case DocStyleChange::Code: + if (s->enable()) printf(""); else printf(""); + break; + case DocStyleChange::Subscript: + if (s->enable()) printf(""); else printf(""); + break; + case DocStyleChange::Superscript: + if (s->enable()) printf(""); else printf(""); + break; + case DocStyleChange::Center: + if (s->enable()) printf("
    "); else printf("
    "); + break; + case DocStyleChange::Small: + if (s->enable()) printf(""); else printf(""); + break; + case DocStyleChange::Preformatted: + if (s->enable()) printf("
    "); else printf("
    "); + break; + case DocStyleChange::Div: + if (s->enable()) printf("
    "); else printf("
    "); + break; + case DocStyleChange::Span: + if (s->enable()) printf(""); else printf(""); + break; + } + } + void visit(DocVerbatim *s) + { + indent_leaf(); + switch(s->type()) + { + case DocVerbatim::Code: printf(""); break; + case DocVerbatim::Verbatim: printf(""); break; + case DocVerbatim::HtmlOnly: printf(""); break; + case DocVerbatim::ManOnly: printf(""); break; + case DocVerbatim::LatexOnly: printf(""); break; + case DocVerbatim::XmlOnly: printf(""); break; + case DocVerbatim::Dot: printf(""); break; + case DocVerbatim::Msc: printf(""); break; + } + printf("%s",s->text().data()); + switch(s->type()) + { + case DocVerbatim::Code: printf(""); break; + case DocVerbatim::Verbatim: printf(""); break; + case DocVerbatim::HtmlOnly: printf(""); break; + case DocVerbatim::ManOnly: printf(""); break; + case DocVerbatim::LatexOnly: printf(""); break; + case DocVerbatim::XmlOnly: printf(""); break; + case DocVerbatim::Dot: printf(""); break; + case DocVerbatim::Msc: printf(""); break; + } + } + void visit(DocAnchor *a) + { + indent_leaf(); + printf("",a->anchor().data()); + } + void visit(DocInclude *inc) + { + indent_leaf(); + printf("file().data()); + switch(inc->type()) + { + case DocInclude::Include: printf("include"); break; + case DocInclude::IncWithLines: printf("incwithlines"); break; + case DocInclude::DontInclude: printf("dontinclude"); break; + case DocInclude::HtmlInclude: printf("htmlinclude"); break; + case DocInclude::VerbInclude: printf("verbinclude"); break; + case DocInclude::Snippet: printf("snippet"); break; + } + printf("\"/>"); + } + void visit(DocIncOperator *op) + { + indent_leaf(); + printf("pattern().data()); + switch(op->type()) + { + case DocIncOperator::Line: printf("line"); break; + case DocIncOperator::Skip: printf("skip"); break; + case DocIncOperator::SkipLine: printf("skipline"); break; + case DocIncOperator::Until: printf("until"); break; + } + printf("\"/>"); + } + void visit(DocFormula *f) + { + indent_leaf(); + printf("",f->name().data(),f->text().data()); + } + void visit(DocIndexEntry *i) + { + indent_leaf(); + printf("%sentry().data()); + } + void visit(DocSimpleSectSep *) + { + indent_leaf(); + printf(""); + } + void visit(DocCite *cite) + { + indent_leaf(); + printf("\n", + cite->ref().data(),cite->file().data(),cite->anchor().data(), + cite->text().data()); + } + + //-------------------------------------- + + void visitPre(DocAutoList *l) + { + indent_pre(); + if (l->isEnumList()) + { + printf("
      \n"); + } + else + { + printf("
        \n"); + } + } + void visitPost(DocAutoList *l) + { + indent_post(); + if (l->isEnumList()) + { + printf("
    \n"); + } + else + { + printf("\n"); + } + } + void visitPre(DocAutoListItem *) + { + indent_pre(); + printf("
  • \n"); + } + void visitPost(DocAutoListItem *) + { + indent_post(); + printf("
  • \n"); + } + void visitPre(DocPara *) + { + indent_pre(); + printf("\n"); + } + void visitPost(DocPara *) + { + indent_post(); + printf("\n"); + } + void visitPre(DocRoot *) + { + indent_pre(); + printf("\n"); + } + void visitPost(DocRoot *) + { + indent_post(); + printf("\n"); + } + void visitPre(DocSimpleSect *s) + { + indent_pre(); + printf("\n"); + } + void visitPost(DocSimpleSect *) + { + indent_post(); + printf("\n"); + } + void visitPre(DocTitle *) + { + indent_pre(); + printf("\n"); + } + void visitPost(DocTitle *) + { + indent_post(); + printf("\n"); + } + void visitPre(DocSimpleList *) + { + indent_pre(); + printf("
      \n"); + } + void visitPost(DocSimpleList *) + { + indent_post(); + printf("
    \n"); + } + void visitPre(DocSimpleListItem *) + { + indent_pre(); + printf("
  • \n"); + } + void visitPost(DocSimpleListItem *) + { + indent_post(); + printf("
  • \n"); + } + void visitPre(DocSection *s) + { + indent_pre(); + printf("\n",s->level()); + } + void visitPost(DocSection *s) + { + indent_post(); + printf("\n",s->level()); + } + void visitPre(DocHtmlList *s) + { + indent_pre(); + if (s->type()==DocHtmlList::Ordered) printf("
      \n"); else printf("
        \n"); + } + void visitPost(DocHtmlList *s) + { + indent_post(); + if (s->type()==DocHtmlList::Ordered) printf("
    \n"); else printf("\n"); + } + void visitPre(DocHtmlListItem *) + { + indent_pre(); + printf("
  • \n"); + } + void visitPost(DocHtmlListItem *) + { + indent_post(); + printf("
  • \n"); + } + //void visitPre(DocHtmlPre *) + //{ + // indent_pre(); + // printf("
    \n");
    +    //  m_insidePre=TRUE;
    +    //}
    +    //void visitPost(DocHtmlPre *) 
    +    //{
    +    //  m_insidePre=FALSE;
    +    //  indent_post();
    +    //  printf("
    \n"); + //} + void visitPre(DocHtmlDescList *) + { + indent_pre(); + printf("
    \n"); + } + void visitPost(DocHtmlDescList *) + { + indent_post(); + printf("
    \n"); + } + void visitPre(DocHtmlDescTitle *) + { + indent_pre(); + printf("
    \n"); + } + void visitPost(DocHtmlDescTitle *) + { + indent_post(); + printf("
    \n"); + } + void visitPre(DocHtmlDescData *) + { + indent_pre(); + printf("
    \n"); + } + void visitPost(DocHtmlDescData *) + { + indent_post(); + printf("
    \n"); + } + void visitPre(DocHtmlTable *t) + { + indent_pre(); + printf("\n", + t->numRows(),t->numColumns()); + } + void visitPost(DocHtmlTable *) + { + indent_post(); + printf("
    \n"); + } + void visitPre(DocHtmlRow *) + { + indent_pre(); + printf("\n"); + } + void visitPost(DocHtmlRow *) + { + indent_post(); + printf("\n"); + } + void visitPre(DocHtmlCell *c) + { + indent_pre(); + printf("\n",c->isHeading()?'h':'d'); + } + void visitPost(DocHtmlCell *c) + { + indent_post(); + printf("\n",c->isHeading()?'h':'d'); + } + void visitPre(DocHtmlCaption *) + { + indent_pre(); + printf("\n"); + } + void visitPost(DocHtmlCaption *) + { + indent_post(); + printf("\n"); + } + void visitPre(DocInternal *) + { + indent_pre(); + printf("\n"); + } + void visitPost(DocInternal *) + { + indent_post(); + printf("\n"); + } + void visitPre(DocHRef *href) + { + indent_pre(); + printf("\n",href->url().data()); + } + void visitPost(DocHRef *) + { + indent_post(); + printf("\n"); + } + void visitPre(DocHtmlHeader *header) + { + indent_pre(); + printf("\n",header->level()); + } + void visitPost(DocHtmlHeader *header) + { + indent_post(); + printf("\n",header->level()); + } + void visitPre(DocImage *img) + { + indent_pre(); + printf("name().data()); + switch(img->type()) + { + case DocImage::Html: printf("html"); break; + case DocImage::Latex: printf("latex"); break; + case DocImage::Rtf: printf("rtf"); break; + } + printf("\" width=%s height=%s>\n",img->width().data(),img->height().data()); + } + void visitPost(DocImage *) + { + indent_post(); + printf("\n"); + } + void visitPre(DocDotFile *df) + { + indent_pre(); + printf("\n",df->name().data()); + } + void visitPost(DocDotFile *) + { + indent_post(); + printf("\n"); + } + void visitPre(DocMscFile *df) + { + indent_pre(); + printf("\n",df->name().data()); + } + void visitPost(DocMscFile *) + { + indent_post(); + printf("\n"); + } + void visitPre(DocLink *lnk) + { + indent_pre(); + printf("\n", + lnk->ref().data(),lnk->file().data(),lnk->anchor().data()); + } + void visitPost(DocLink *) + { + indent_post(); + printf("\n"); + } + void visitPre(DocRef *ref) + { + indent_pre(); + printf("\n", + ref->ref().data(),ref->file().data(),ref->anchor().data(), + ref->targetTitle().data(),ref->hasLinkText()?"yes":"no", + ref->refToAnchor()?"yes":"no", ref->refToSection()?"yes":"no"); + } + void visitPost(DocRef *) + { + indent_post(); + printf("\n"); + } + void visitPre(DocSecRefItem *ref) + { + indent_pre(); + printf("\n",ref->target().data()); + } + void visitPost(DocSecRefItem *) + { + indent_post(); + printf("\n"); + } + void visitPre(DocSecRefList *) + { + indent_pre(); + printf("\n"); + } + void visitPost(DocSecRefList *) + { + indent_post(); + printf("\n"); + } + //void visitPre(DocLanguage *l) + //{ + // indent_pre(); + // printf("\n",l->id().data()); + //} + //void visitPost(DocLanguage *) + //{ + // indent_post(); + // printf("\n"); + //} + void visitPre(DocParamList *pl) + { + indent_pre(); + //QStrListIterator sli(pl->parameters()); + QListIterator sli(pl->parameters()); + //const char *s; + DocNode *param; + printf(""); + for (sli.toFirst();(param=sli.current());++sli) + { + printf(""); + if (param->kind()==DocNode::Kind_Word) + { + visit((DocWord*)param); + } + else if (param->kind()==DocNode::Kind_LinkedWord) + { + visit((DocLinkedWord*)param); + } + printf(""); + } + printf("\n"); + } + void visitPost(DocParamList *) + { + indent_post(); + printf("\n"); + } + void visitPre(DocParamSect *ps) + { + indent_pre(); + printf("\n"); + } + void visitPost(DocParamSect *) + { + indent_post(); + printf("\n"); + } + void visitPre(DocXRefItem *x) + { + indent_pre(); + printf("\n", + x->file().data(),x->anchor().data(),x->title().data()); + } + void visitPost(DocXRefItem *) + { + indent_post(); + printf("\n"); + } + void visitPre(DocInternalRef *r) + { + indent_pre(); + printf("\n",r->file().data(),r->anchor().data()); + } + void visitPost(DocInternalRef *) + { + indent_post(); + printf("\n"); + } + void visitPre(DocCopy *c) + { + indent_pre(); + printf("\n",c->link().data()); + } + void visitPost(DocCopy *) + { + indent_post(); + printf("\n"); + } + void visitPre(DocText *) + { + indent_pre(); + printf("\n"); + } + void visitPost(DocText *) + { + indent_post(); + printf("\n"); + } + void visitPre(DocHtmlBlockQuote *) + { + indent_pre(); + printf("
    \n"); + } + void visitPost(DocHtmlBlockQuote *) + { + indent_post(); + printf("
    \n"); + } + + private: + // helper functions + void indent() + { + if (m_needsEnter) printf("\n"); + for (int i=0;i. + */ + + +#ifndef PYCODE_H +#define PYCODE_H + +#include "qtbc.h" +#include + +class CodeOutputInterface; +class FileDef; +class MemberDef; + +extern void parsePythonCode(CodeOutputInterface &,const char *,const QCString &, + bool ,const char *,FileDef *fd=0, + int startLine=-1,int endLine=-1,bool inlineFragment=FALSE, + MemberDef *memberDef=0,bool showLineNumbers=TRUE); +extern void resetPythonCodeParserState(); + +#endif diff --git a/trunk/src/pycode.l b/trunk/src/pycode.l new file mode 100644 index 0000000..e24c8f9 --- /dev/null +++ b/trunk/src/pycode.l @@ -0,0 +1,1486 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ +/* This code is based on the work done by the MoxyPyDoxy team + * (Linda Leong, Mike Rivera, Kim Truong, and Gabriel Estrada) + * in Spring 2005 as part of CS 179E: Compiler Design Project + * at the University of California, Riverside; the course was + * taught by Peter H. Froehlich . + */ + + +%{ + +#include +#include + +#include "pycode.h" +#include "message.h" + +#include "scanner.h" +#include "entry.h" +#include "doxygen.h" +#include "outputlist.h" +#include "util.h" +#include "membername.h" +#include "searchindex.h" + +#define YY_NEVER_INTERACTIVE 1 + +static ClassSDict g_codeClassSDict(17); +static QCString g_curClassName; +static QStrList g_curClassBases; + + +static CodeOutputInterface * g_code; +static const char * g_inputString; //!< the code fragment as text +static int g_inputPosition; //!< read offset during parsing +static const char * g_currentFontClass; +static bool g_needsTermination; +static int g_inputLines; //!< number of line in the code fragment +static int g_yyLineNr; //!< current line number +static FileDef * g_sourceFileDef; +static Definition * g_currentDefinition; +static MemberDef * g_currentMemberDef; +static bool g_includeCodeFragment; +static QCString g_realScope; +//static bool g_insideBody; +static int g_bodyCurlyCount; +static bool g_searchingForBody; +static QCString g_classScope; +static int g_paramParens; +//static int g_anchorCount; + +static bool g_exampleBlock; +static QCString g_exampleName; +static QCString g_exampleFile; + +static QCString g_type; +static QCString g_name; + +static bool g_doubleStringIsDoc; +static bool g_doubleQuote; +static bool g_noSuiteFound; +static int g_stringContext; + +static QValueStack g_indents; //!< Tracks indentation levels for scoping in python + +static void endFontClass(); +static void adjustScopesAndSuites(unsigned indentLength); + + +/*! Represents a stack of variable to class mappings as found in the + * code. Each scope is enclosed in pushScope() and popScope() calls. + * Variables are added by calling addVariables() and one can search + * for variable using findVariable(). + */ +class PyVariableContext +{ + public: + static const ClassDef *dummyContext; + class Scope : public SDict + { + public: + Scope() : SDict(17) {} + }; + + PyVariableContext() + { + m_scopes.setAutoDelete(TRUE); + } + + virtual ~PyVariableContext() + { + } + + void pushScope() + { + m_scopes.append(new Scope); + } + + void popScope() + { + if (m_scopes.count()>0) + { + m_scopes.remove(m_scopes.count()-1); + } + } + + void clear() + { + m_scopes.clear(); + m_globalScope.clear(); + } + + void clearExceptGlobal() + { + m_scopes.clear(); + } + + void addVariable(const QCString &type,const QCString &name); + ClassDef *findVariable(const QCString &name); + + private: + Scope m_globalScope; + QList m_scopes; +}; + +void PyVariableContext::addVariable(const QCString &type,const QCString &name) +{ + //printf("PyVariableContext::addVariable(%s,%s)\n",type.data(),name.data()); + QCString ltype = type.simplifyWhiteSpace(); + QCString lname = name.simplifyWhiteSpace(); + + Scope *scope = m_scopes.count()==0 ? &m_globalScope : m_scopes.getLast(); + ClassDef *varType; + if ( + (varType=g_codeClassSDict[ltype]) || // look for class definitions inside the code block + (varType=getResolvedClass(g_currentDefinition,g_sourceFileDef,ltype)) // look for global class definitions + ) + { + scope->append(lname,varType); // add it to a list + } + else + { + if (m_scopes.count()>0) // for local variables add a dummy entry so the name + // is hidden to avoid FALSE links to global variables with the same name + // TODO: make this work for namespaces as well! + { + scope->append(lname,dummyContext); + } + } +} + +ClassDef *PyVariableContext::findVariable(const QCString &name) +{ + if (name.isEmpty()) return 0; + ClassDef *result = 0; + QListIterator sli(m_scopes); + Scope *scope; + // search from inner to outer scope + for (sli.toLast();(scope=sli.current());--sli) + { + result = scope->find(name); + if (result) + { + return result; + } + } + // nothing found -> also try the global scope + result=m_globalScope.find(name); + return result; +} + +static PyVariableContext g_theVarContext; +const ClassDef *PyVariableContext::dummyContext = (ClassDef*)0x8; + +class PyCallContext +{ + public: + struct Ctx + { + Ctx() : name(g_name), type(g_type), cd(0) {} + QCString name; + QCString type; + ClassDef *cd; + }; + + PyCallContext() + { + m_classList.append(new Ctx); + m_classList.setAutoDelete(TRUE); + } + + virtual ~PyCallContext() {} + + void setClass(ClassDef *cd) + { + Ctx *ctx = m_classList.getLast(); + if (ctx) + { + ctx->cd=cd; + } + } + void pushScope() + { + m_classList.append(new Ctx); + } + + void popScope() + { + if (m_classList.count()>1) + { + Ctx *ctx = m_classList.getLast(); + if (ctx) + { + g_name = ctx->name; + g_type = ctx->type; + } + m_classList.removeLast(); + } + else + { + } + } + + void clear() + { + m_classList.clear(); + m_classList.append(new Ctx); + } + + ClassDef *getClass() const + { + Ctx *ctx = m_classList.getLast(); + + if (ctx) + return ctx->cd; + else + return 0; + } + + private: + QList m_classList; +}; + +static PyCallContext g_theCallContext; + + +/*! counts the number of lines in the input */ +static int countLines() +{ + const char *p=g_inputString; + char c; + int count=1; + while ((c=*p)) + { + p++ ; + if (c=='\n') count++; + } + if (p>g_inputString && *(p-1)!='\n') + { // last line does not end with a \n, so we add an extra + // line and explicitly terminate the line after parsing. + count++, + g_needsTermination=TRUE; + } + return count; +} + +static void setCurrentDoc(const QCString &name,const QCString &base,const QCString &anchor="") +{ + if (Doxygen::searchIndex) + { + Doxygen::searchIndex->setCurrentDoc(name,base,anchor); + } +} + +static void addToSearchIndex(const char *text) +{ + if (Doxygen::searchIndex) + { + Doxygen::searchIndex->addWord(text,FALSE); + } +} + + +static ClassDef *stripClassName(const char *s,Definition *d=g_currentDefinition) +{ + int pos=0; + QCString type = s; + QCString className; + QCString templSpec; + while (extractClassNameFromType(type,pos,className,templSpec)!=-1) + { + QCString clName=className+templSpec; + + ClassDef *cd=0; + if (!g_classScope.isEmpty()) + { + cd=getResolvedClass(d,g_sourceFileDef,g_classScope+"::"+clName); + } + if (cd==0) + { + cd=getResolvedClass(d,g_sourceFileDef,clName); + } + if (cd) + { + return cd; + } + } + + return 0; +} + + + +/*! start a new line of code, inserting a line number if g_sourceFileDef + * is TRUE. If a definition starts at the current line, then the line + * number is linked to the documentation of that definition. + */ +static void startCodeLine() +{ + //if (g_currentFontClass) { g_code->endFontClass(); } + if (g_sourceFileDef) + { + //QCString lineNumber,lineAnchor; + //lineNumber.sprintf("%05d",g_yyLineNr); + //lineAnchor.sprintf("l%05d",g_yyLineNr); + + Definition *d = g_sourceFileDef->getSourceDefinition(g_yyLineNr); + //printf("startCodeLine %d d=%p\n",g_yyLineNr,d); + //g_code->startLineNumber(); + if (!g_includeCodeFragment && d && d->isLinkableInProject()) + { + g_currentDefinition = d; + g_currentMemberDef = g_sourceFileDef->getSourceMember(g_yyLineNr); + //g_insideBody = FALSE; + g_searchingForBody = TRUE; + g_realScope = d->name().copy(); + g_classScope = d->name().copy(); + //printf("Real scope: `%s'\n",g_realScope.data()); + g_bodyCurlyCount = 0; + QCString lineAnchor; + lineAnchor.sprintf("l%05d",g_yyLineNr); + if (g_currentMemberDef) + { + g_code->writeLineNumber(g_currentMemberDef->getReference(), + g_currentMemberDef->getOutputFileBase(), + g_currentMemberDef->anchor(),g_yyLineNr); + setCurrentDoc( + g_currentMemberDef->qualifiedName(), + g_sourceFileDef->getSourceFileBase(), + lineAnchor); + } + else + { + g_code->writeLineNumber(d->getReference(), + d->getOutputFileBase(), + 0,g_yyLineNr); + setCurrentDoc( + d->qualifiedName(), + g_sourceFileDef->getSourceFileBase(), + lineAnchor); + } + } + else + { + //g_code->codify(lineNumber); + g_code->writeLineNumber(0,0,0,g_yyLineNr); + } + //g_code->endLineNumber(); + } + g_code->startCodeLine(); + if (g_currentFontClass) + { + g_code->startFontClass(g_currentFontClass); + } +} + +static void codify(const char* text) +{ + g_code->codify(text); +} + +static void endCodeLine() +{ + endFontClass(); + g_code->endCodeLine(); +} + +static void nextCodeLine() +{ + const char *fc = g_currentFontClass; + endCodeLine(); + if (g_yyLineNrcodify(sp); + nextCodeLine(); + } + else + { + g_code->codify(sp); + done=TRUE; + } + } +} + +static void addDocCrossReference(MemberDef *src,MemberDef *dst) +{ + static bool referencedByRelation = Config_getBool("REFERENCED_BY_RELATION"); + static bool callerGraph = Config_getBool("CALLER_GRAPH"); + static bool referencesRelation = Config_getBool("REFERENCES_RELATION"); + static bool callGraph = Config_getBool("CALL_GRAPH"); + if (dst->isTypedef() || dst->isEnumerate()) return; // don't add types + //printf("addDocCrossReference src=%s,dst=%s\n",src->name().data(),dst->name().data()); + if ((referencedByRelation || callerGraph) && (src->isFunction() || src->isSlot())) + { + dst->addSourceReferencedBy(src); + } + if ((referencesRelation || callGraph) && (src->isFunction() || src->isSlot())) + { + src->addSourceReferences(dst); + } +} + + + +static bool getLinkInScope(const QCString &c, // scope + const QCString &m, // member + const char *memberText, // exact text + CodeOutputInterface &ol, + const char *text + ) +{ + MemberDef *md; + ClassDef *cd; + FileDef *fd; + NamespaceDef *nd; + GroupDef *gd; + //printf("Trying `%s'::`%s'\n",c.data(),m.data()); + if (getDefs(c,m,"()",md,cd,fd,nd,gd,FALSE,g_sourceFileDef) && + md->isLinkable()) + { + //Definition *d=0; + //if (cd) d=cd; else if (nd) d=nd; else if (fd) d=fd; else d=gd; + + Definition *d = md->getOuterScope()==Doxygen::globalScope ? + md->getBodyDef() : md->getOuterScope(); + //printf("Found! d=%s\n",d?d->name().data():""); + if (md->getGroupDef()) d = md->getGroupDef(); + if (d && d->isLinkable()) + { + g_theCallContext.setClass(stripClassName(md->typeString(),md->getOuterScope())); + //printf("g_currentDefinition=%p g_currentMemberDef=%p\n", + // g_currentDefinition,g_currentMemberDef); + + if (g_currentDefinition && g_currentMemberDef && + md!=g_currentMemberDef) + { + addDocCrossReference(g_currentMemberDef,md); + } + //printf("d->getReference()=`%s' d->getOutputBase()=`%s' name=`%s' member name=`%s'\n",d->getReference().data(),d->getOutputFileBase().data(),d->name().data(),md->name().data()); + + writeMultiLineCodeLink(ol,md->getReference(), + md->getOutputFileBase(), + md->anchor(), + text ? text : memberText, + md->briefDescriptionAsTooltip()); + addToSearchIndex(text ? text : memberText); + return TRUE; + } + } + return FALSE; +} + +static bool getLink(const char *className, + const char *memberName, + CodeOutputInterface &ol, + const char *text=0) +{ + QCString m=removeRedundantWhiteSpace(memberName); + QCString c=className; + if (!getLinkInScope(c,m,memberName,ol,text)) + { + if (!g_curClassName.isEmpty()) + { + if (!c.isEmpty()) c.prepend("::"); + c.prepend(g_curClassName); + return getLinkInScope(c,m,memberName,ol,text); + } + return FALSE; + } + return TRUE; +} + + +/* + For a given string in the source code, + finds its class or global id and links to it. +*/ +static void generateClassOrGlobalLink(CodeOutputInterface &ol,char *clName, + bool typeOnly=FALSE) +{ + QCString className=clName; + + // Don't do anything for empty text + if (className.isEmpty()) return; + + //fprintf(stderr,"generateClassOrGlobalLink(className=%s)\n",className.data()); + + ClassDef *cd=0,*lcd=0; /** Class def that we may find */ + MemberDef *md=0; /** Member def that we may find */ + //bool isLocal=FALSE; + + if ((lcd=g_theVarContext.findVariable(className))==0) // not a local variable + { + Definition *d = g_currentDefinition; + QCString scope = substitute(className,".","::"); + + cd = getResolvedClass(d,g_sourceFileDef,substitute(className,".","::"),&md); + + //fprintf(stderr,"d=%s g_sourceFileDef=%s\n", + // d?d->displayName().data():"", + // g_currentDefinition?g_currentDefinition->displayName().data():""); + //fprintf(stderr,"is found as a type %s\n",cd?cd->name().data():""); + + if (cd==0 && md==0) // also see if it is variable or enum or enum value + { + NamespaceDef *nd = getResolvedNamespace(scope); + if (nd) + { + writeMultiLineCodeLink(ol,nd->getReference(),nd->getOutputFileBase(),nd->anchor(),clName,nd->briefDescriptionAsTooltip()); + addToSearchIndex(className); + return; + } + else if (getLink(g_classScope,clName,ol,clName)) + { + return; + } + } + } + else + { + if (lcd!=PyVariableContext::dummyContext) + { + g_theCallContext.setClass(lcd); + } + //isLocal=TRUE; + //fprintf(stderr,"is a local variable cd=%p!\n",cd); + } + + if (cd && cd->isLinkable()) // is it a linkable class + { + writeMultiLineCodeLink(ol,cd->getReference(),cd->getOutputFileBase(),cd->anchor(),clName,cd->briefDescriptionAsTooltip()); + addToSearchIndex(className); + if (md) + { + Definition *d = md->getOuterScope()==Doxygen::globalScope ? + md->getBodyDef() : md->getOuterScope(); + if (md->getGroupDef()) d = md->getGroupDef(); + if (d && d->isLinkable() && md->isLinkable() && g_currentMemberDef) + { + addDocCrossReference(g_currentMemberDef,md); + } + } + } + else // not a class, maybe a global member + { + int scopeEnd = className.findRev("."); + if (scopeEnd!=-1 && !typeOnly) // name with explicit scope + { + QCString scope = substitute(className.left(scopeEnd),".","::"); + QCString locName = className.right(className.length()-scopeEnd-1); + ClassDef *mcd = getClass(scope); + //fprintf(stderr,"scope=%s locName=%s mcd=%p\n",scope.data(),locName.data(),mcd); + if (mcd) + { + MemberDef *md = mcd->getMemberByName(locName); + if (md) + { + g_theCallContext.setClass(stripClassName(md->typeString(),md->getOuterScope())); + writeMultiLineCodeLink(ol,md->getReference(),md->getOutputFileBase(),md->anchor(),clName,md->briefDescriptionAsTooltip()); + addToSearchIndex(className); + Definition *d = md->getOuterScope()==Doxygen::globalScope ? + md->getBodyDef() : md->getOuterScope(); + if (md->getGroupDef()) d = md->getGroupDef(); + if (d && d->isLinkable() && md->isLinkable() && g_currentMemberDef) + { + addDocCrossReference(g_currentMemberDef,md); + } + return; + } + } + else // check namespace as well + { + NamespaceDef *mnd = getResolvedNamespace(scope); + if (mnd) + { + MemberDef *md=mnd->getMemberByName(locName); + if (md) + { + //printf("name=%s scope=%s\n",locName.data(),scope.data()); + g_theCallContext.setClass(stripClassName(md->typeString(),md->getOuterScope())); + writeMultiLineCodeLink(ol,md->getReference(),md->getOutputFileBase(),md->anchor(),clName,md->briefDescriptionAsTooltip()); + addToSearchIndex(className); + Definition *d = md->getOuterScope()==Doxygen::globalScope ? + md->getBodyDef() : md->getOuterScope(); + if (md->getGroupDef()) d = md->getGroupDef(); + if (d && d->isLinkable() && md->isLinkable() && g_currentMemberDef) + { + addDocCrossReference(g_currentMemberDef,md); + } + return; + } + } + } + } + + // nothing found, just write out the word + codifyLines(clName); + addToSearchIndex(clName); + } +} + +/* + As of June 1, this function seems to work + for file members, but scopes are not + being correctly tracked for classes + so it doesn't work for classes yet. + +*/ +static void generateFunctionLink(CodeOutputInterface &ol,char *funcName) +{ + //CodeClassDef *ccd=0; + ClassDef *ccd=0; + QCString locScope=g_classScope.copy(); + QCString locFunc=removeRedundantWhiteSpace(funcName); + //fprintf(stdout,"*** locScope=%s locFunc=%s\n",locScope.data(),locFunc.data()); + int i=locFunc.findRev("::"); + if (i>0) + { + locScope=locFunc.left(i); + locFunc=locFunc.right(locFunc.length()-i-2).stripWhiteSpace(); + } + //printf("generateFunctionLink(%s) classScope=`%s'\n",locFunc.data(),locScope.data()); + if (!locScope.isEmpty() && (ccd=g_codeClassSDict[locScope])) + { + //printf("using classScope %s\n",g_classScope.data()); + if (ccd->baseClasses()) + { + BaseClassListIterator bcli(*ccd->baseClasses()); + for ( ; bcli.current() ; ++bcli) + { + if (getLink(bcli.current()->classDef->name(),locFunc,ol,funcName)) + { + return; + } + } + } + } + if (!getLink(locScope,locFunc,ol,funcName)) + { + generateClassOrGlobalLink(ol,funcName); + } + return; +} + +static bool findMemberLink(CodeOutputInterface &ol,Definition *sym,const char *symName) +{ + //printf("sym %s outerScope=%s equal=%d\n", + // sym->name().data(),sym->getOuterScope()->name().data(), + // sym->getOuterScope()==g_currentDefinition); + + if (sym->getOuterScope() && + sym->getOuterScope()->definitionType()==Definition::TypeClass && + g_currentDefinition->definitionType()==Definition::TypeClass) + { + ClassDef *cd = (ClassDef*)sym->getOuterScope(); + ClassDef *thisCd = (ClassDef *)g_currentDefinition; + QCString anchor=sym->anchor(); + if (sym->definitionType()==Definition::TypeMember) + { + if (g_currentMemberDef) + { + addDocCrossReference(g_currentMemberDef,(MemberDef*)sym); + } + } + //fprintf(stderr,"cd=%s thisCd=%s\n",cd?cd->name().data():"",thisCd?thisCd->name().data():""); + + // TODO: find the nearest base class in case cd is a base class of + // thisCd + if (cd==thisCd || (thisCd && thisCd->isBaseClass(cd,TRUE))) + { + writeMultiLineCodeLink(ol,sym->getReference(), + sym->getOutputFileBase(), + anchor, + symName, + sym->briefDescriptionAsTooltip()); + return TRUE; + } + } + return FALSE; +} + +static void findMemberLink(CodeOutputInterface &ol,char *symName) +{ + //printf("Member reference: %s scope=%s member=%s\n", + // yytext, + // g_currentDefinition?g_currentDefinition->name().data():"", + // g_currentMemberDef?g_currentMemberDef->name().data():"" + // ); + if (g_currentDefinition) + { + DefinitionIntf *di = Doxygen::symbolMap->find(symName); + if (di) + { + if (di->definitionType()==DefinitionIntf::TypeSymbolList) // multiple symbols + { + DefinitionListIterator dli(*(DefinitionList*)di); + Definition *sym; + for (dli.toFirst();(sym=dli.current());++dli) + { + if (findMemberLink(ol,sym,symName)) return; + } + } + else // single symbol + { + if (findMemberLink(ol,(Definition*)di,symName)) return; + } + } + } + //printf("sym %s not found\n",&yytext[5]); + codify(symName); +} + +static void startFontClass(const char *s) +{ + endFontClass(); + g_code->startFontClass(s); + g_currentFontClass=s; +} + +static void endFontClass() +{ + if (g_currentFontClass) + { + g_code->endFontClass(); + g_currentFontClass=0; + } +} + +#undef YY_INPUT +#define YY_INPUT(buf,result,max_size) result=yyread(buf,max_size); + +static int yyread(char *buf,int max_size) +{ + int c=0; + while( c < max_size && g_inputString[g_inputPosition] ) + { + *buf = g_inputString[g_inputPosition++] ; + c++; buf++; + } + return c; +} + +%} + + +BB [ \t]+ +B [ \t]* +NEWLINE \n + +DIGIT [0-9] +LETTER [A-Za-z] +NONEMPTY [A-Za-z0-9_] +EXPCHAR [#(){}\[\],:.%/\\=`*~|&<>!;+-] +NONEMPTYEXP [^ \t\n:] +PARAMNONEMPTY [^ \t\n():] +IDENTIFIER ({LETTER}|"_")({LETTER}|{DIGIT}|"_")* +BORDER ([^A-Za-z0-9]) + +POUNDCOMMENT "#".* + +TRISINGLEQUOTE "'''" +TRIDOUBLEQUOTE "\"\"\"" +LONGSTRINGCHAR [^\\"'] +ESCAPESEQ ("\\")(.) +LONGSTRINGITEM ({LONGSTRINGCHAR}|{ESCAPESEQ}) +SMALLQUOTE ("\"\""|"\""|"'"|"''") +LONGSTRINGBLOCK ({LONGSTRINGITEM}+|{SMALLQUOTE}) + +SHORTSTRING ("'"{SHORTSTRINGITEM}*"'"|'"'{SHORTSTRINGITEM}*'"') +SHORTSTRINGITEM ({SHORTSTRINGCHAR}|{ESCAPESEQ}) +SHORTSTRINGCHAR [^\\\n"] +STRINGLITERAL {STRINGPREFIX}?( {SHORTSTRING} | {LONGSTRING}) +STRINGPREFIX ("r"|"u"|"ur"|"R"|"U"|"UR"|"Ur"|"uR") +KEYWORD ("lambda"|"import"|"class"|"assert"|"as"|"from"|"global"|"def"|"True"|"False") +FLOWKW ("or"|"and"|"is"|"not"|"print"|"for"|"in"|"if"|"try"|"except"|"yield"|"raise"|"break"|"continue"|"pass"|"if"|"return"|"while"|"elif"|"else"|"finally") +QUOTES ("\""[^"]*"\"") +SINGLEQUOTES ("'"[^']*"'") + +LONGINTEGER {INTEGER}("l"|"L") +INTEGER ({DECIMALINTEGER}|{OCTINTEGER}|{HEXINTEGER}) +DECIMALINTEGER ({NONZERODIGIT}{DIGIT}*|"0") +OCTINTEGER "0"{OCTDIGIT}+ +HEXINTEGER "0"("x"|"X"){HEXDIGIT}+ +NONZERODIGIT [1-9] +OCTDIGIT [0-7] +HEXDIGIT ({DIGIT}|[a-f]|[A-F]) +FLOATNUMBER ({POINTFLOAT}|{EXPONENTFLOAT}) +POINTFLOAT ({INTPART}?{FRACTION}|{INTPART}".") +EXPONENTFLOAT ({INTPART}|{POINTFLOAT}){EXPONENT} +INTPART {DIGIT}+ +FRACTION "."{DIGIT}+ +EXPONENT ("e"|"E")("+"|"-")?{DIGIT}+ +IMAGNUMBER ({FLOATNUMBER}|{INTPART})("j"|"J") +ATOM ({IDENTIFIER}|{LITERAL}|{ENCLOSURE}) +ENCLOSURE ({PARENTH_FORM}|{LIST_DISPLAY}|{DICT_DISPLAY}|{STRING_CONVERSION}) +LITERAL ({STRINGLITERAL}|{INTEGER}|{LONGINTEGER}|{FLOATNUMBER}|{IMAGNUMBER}) +PARENTH_FORM "("{EXPRESSION_LIST}?")" +TEST ({AND_TEST}("or"{AND_TEST})*|{LAMBDA_FORM}) +TESTLIST {TEST}( ","{TEST})*","? +LIST_DISPLAY "["{LISTMAKER}?"]" +LISTMAKER {EXPRESSION}({LIST_FOR}|(","{EXPRESSION})*","?) +LIST_ITER ({LIST_FOR}|{LIST_IF}) +LIST_FOR "for"{EXPRESSION_LIST}"in"{TESTLIST}{LIST_ITER}? +LIST_IF "if"{TEST}{LIST_ITER}? +DICT_DISPLAY "\{"{KEY_DATUM_LIST}?"\}" +KEY_DATUM_LIST {KEY_DATUM}(","{KEY_DATUM})*","? +KEY_DATUM {EXPRESSION}":"{EXPRESSION} +STRING_CONVERSION "`"{EXPRESSION_LIST}"`" +PRIMARY ({ATOM}|{ATTRIBUTEREF}|{SUBSCRIPTION}|{SLICING}|{CALL}) +ATTRIBUTEREF {PRIMARY}"."{IDENTIFIER} +SUBSCRIPTION {PRIMARY}"["{EXPRESSION_LIST}"]" +SLICING ({SIMPLE_SLICING}|{EXTENDED_SLICING}) +SIMPLE_SLICING {PRIMARY}"["{SHORT_SLICE}"]" +EXTENDED_SLICING {PRIMARY}"["{SLICE_LIST}"]" +SLICE_LIST {SLICE_ITEM}(","{SLICE_ITEM})*","? +SLICE_ITEM ({EXPRESSION}|{PROPER_SLICE}|{ELLIPSIS}) +PROPER_SLICE ({SHORT_SLICE}|{LONG_SLICE}) +SHORT_SLICE {LOWER_BOUND}?":"{UPPER_BOUND}? +LONG_SLICE {SHORT_SLICE}":"{STRIDE}? +LOWER_BOUND {EXPRESSION} +UPPER_BOUND {EXPRESSION} +STRIDE {EXPRESSION} +ELLIPSIS "..." +CALL {PRIMARY}"("({ARGUMENT_LIST}","?)?")" +ARGUMENT_LIST ({POSITIONAL_ARGUMENTS}(","{KEYWORD_ARGUMENTS})?(",""*"{EXPRESSION})?(",""**"{EXPRESSION})?|{KEYWORD_ARGUMENTS}(",""*"{EXPRESSION})?(",""**"{EXPRESSION})?|"*"{EXPRESSION}(",""**"{EXPRESSION})?|"**"{EXPRESSION}) +POSITIONAL_ARGUMENTS {EXPRESSION}(","{EXPRESSION})* +KEYWORD_ARGUMENTS {KEYWORD_ITEM}(","{KEYWORD_ITEM})* +KEYWORD_ITEM {IDENTIFIER}"="{EXPRESSION} +POWER {PRIMARY}("**"{U_EXPR})? +U_EXPR ({POWER}|"-"{U_EXPR}|"+"{U_EXPR}|"\~"{U_EXPR}) +M_EXPR ({U_EXPR}|{M_EXPR}"*"{U_EXPR}|{M_EXPR}"//"{U_EXPR}|{M_EXPR}"/"{U_EXPR}|{M_EXPR}"\%"{U_EXPR}) +A_EXPR ({M_EXPR}|{A_EXPR}"+"{M_EXPR}|{A_EXPR}"-"{M_EXPR} +SHIFT_EXPR ({A_EXPR}|{SHIFT_EXPR}("<<"|">>"){A_EXPR}) +AND_EXPR ({SHIFT_EXPR}|{AND_EXPR}"\;SPMamp;"{SHIFT_EXPR} +XOR_EXPR ({AND_EXPR}|{XOR_EXPR}"\textasciicircum"{AND_EXPR}) +OR_EXPR ({XOR_EXPR}|{OR_EXPR}"|"{ XOR_EXPR}) + +COMPARISON {OR_EXPR}({COMP_OPERATOR}{OR_EXPR})* +COMP_OPERATOR ("<"|">"|"=="|">="|"<="|"<>"|"!="|"is""not"?|"not"?"in") +EXPRESSION ({OR_TEST}|{LAMBDA_FORM}) +OR_TEST ({AND_TEST}|{OR_TEST}"or"{AND_TEST}) +AND_TEST ({NOT_TEST}|{AND_TEST}"and"{NOT_TEST}) +NOT_TEST ({COMPARISON}|"not"{NOT_TEST}) +LAMBDA_FORM "lambda"{PARAMETER_LIST}?":"{EXPRESSION} +EXPRESSION_LIST {EXPRESSION}(","{EXPRESSION})*","? +SIMPLE_STMT ({EXPRESSION_STMT}|{ASSERT_STMT}|{ASSIGNMENT_STMT}|{AUGMENTED_ASSIGNMENT_STMT}|{PASS_STMT}|{DEL_STMT}|{PRINT_STMT}|{RETURN_STMT}|{YIELD_STMT}|{RAISE_STMT}|{BREAK_STMT}|{CONTINUE_STMT}|{IMPORT_STMT}|{GLOBAL_STMT}|{EXEC_STMT}) +EXPRESSION_STMT {EXPRESSION_LIST} +ASSERT_STMT "assert"{EXPRESSION}(","{EXPRESSION})? +ASSIGNMENT_STMT ({TARGET_LIST}"=")+{EXPRESSION_LIST} +TARGET_LIST {TARGET}(","{TARGET})*","? +TARGET ({IDENTIFIER}|"("{TARGET_LIST}")"|"["{TARGET_LIST}"]"|{ATTRIBUTEREF}|{SUBSCRIPTION}|{SLICING}) + + +%option noyywrap +%option nounput + +%x Body + +%x FunctionDec +%x FunctionParams + +%x ClassDec +%x ClassInheritance + +%x Suite +%x SuiteCaptureIndent +%x SuiteStart +%x SuiteMaintain +%x SuiteContinuing + +%x LongString + +%x SingleQuoteString +%x DoubleQuoteString +%x TripleString + +%% + +{ + "def"{BB} { + startFontClass("keyword"); + codify(yytext); + endFontClass(); + BEGIN( FunctionDec ); + } + + "class"{BB} { + startFontClass("keyword"); + codify(yytext); + endFontClass(); + BEGIN( ClassDec ); + } + "None" { + startFontClass("keywordtype"); + codify(yytext); + endFontClass(); + } + "self."{IDENTIFIER}/"(" { + codify("self."); + findMemberLink(*g_code,&yytext[5]); + } + "self."{IDENTIFIER} { + codify("self."); + findMemberLink(*g_code,&yytext[5]); + } +} + +{IDENTIFIER} { + + generateClassOrGlobalLink(*g_code,yytext); + // codify(yytext); + g_curClassName = yytext; + g_curClassBases.clear(); + BEGIN( ClassInheritance ); + } + +{ + ({BB}|[(,)]) { + codify(yytext); + } + + ({IDENTIFIER}".")*{IDENTIFIER} { + // The parser + // is assuming + // that ALL identifiers + // in this state + // are base classes; + // it doesn't check to see + // that the first parenthesis + // has been seen. + + // This is bad - it should + // probably be more strict + // about what to accept. + + g_curClassBases.inSort(yytext); + generateClassOrGlobalLink(*g_code,yytext); + // codify(yytext); + } + + ":" { + codify(yytext); + + // Assume this will + // be a one-line suite; + // found counter-example + // in SuiteStart. + + // Push a class scope + + ClassDef *classDefToAdd = new ClassDef("",1,g_curClassName,ClassDef::Class,0,0,FALSE); + g_codeClassSDict.append(g_curClassName,classDefToAdd); + char *s=g_curClassBases.first(); + while (s) + { + ClassDef *baseDefToAdd; + baseDefToAdd=g_codeClassSDict[s]; + + // Try to find class in global + // scope + if (baseDefToAdd==0) + { + baseDefToAdd=getResolvedClass(g_currentDefinition,g_sourceFileDef,s); + } + + if (baseDefToAdd && baseDefToAdd!=classDefToAdd) + { + classDefToAdd->insertBaseClass(baseDefToAdd,s,Public,Normal); + } + + s=g_curClassBases.next(); + } + + // Reset class-parsing variables. + g_curClassName.resize(0); + g_curClassBases.clear(); + + g_noSuiteFound = TRUE; + BEGIN( SuiteStart ); + } +} + + +{ + {IDENTIFIER} { + generateFunctionLink(*g_code,yytext); + } + + {B}"(" { + codify(yytext); + BEGIN( FunctionParams ); + } +} + +{ + ({BB}|",") { + // Parses delimiters + codify(yytext); + } + + ({IDENTIFIER}|{PARAMNONEMPTY}+) { + codify(yytext); + } + + ")" { + codify(yytext); + } + + ":" { + codify(yytext); + + // Assume this will + // be a one-line suite; + // found counter-example + // in SuiteStart. + g_noSuiteFound = TRUE; + BEGIN( SuiteStart ); + } +} + +{ + + {KEYWORD} { + // Position-sensitive rules! + // Must come AFTER keyword-triggered rules + // Must come BEFORE identifier NONEMPTY-like rules + // to syntax highlight. + + startFontClass("keyword"); + codify(yytext); + endFontClass(); + } + + {FLOWKW} { + startFontClass("keywordflow"); + codify(yytext); + endFontClass(); + } + ({IDENTIFIER}".")*{IDENTIFIER}/"(" { + generateClassOrGlobalLink(*g_code,yytext); + } + ({IDENTIFIER}".")+{IDENTIFIER} { + generateClassOrGlobalLink(*g_code,yytext,TRUE); + } + {IDENTIFIER} { codify(yytext); } + +} + + + +{ + + {BB} { + codify(yytext); + } + "pass" { + startFontClass("keyword"); + codifyLines(yytext); + endFontClass(); + BEGIN(Body); + } + {KEYWORD} { + startFontClass("keyword"); + codifyLines(yytext); + endFontClass(); + + // No indentation necesary + g_noSuiteFound = FALSE; + } + + {FLOWKW} { + startFontClass("keywordflow"); + codifyLines(yytext); + endFontClass(); + + // No indentation necesary + g_noSuiteFound = FALSE; + } + {IDENTIFIER} { + codify(yytext); + } + + + {POUNDCOMMENT} { + // This eats EVERYTHING + // except the newline + startFontClass("comment"); + codifyLines(yytext); + endFontClass(); + } + + {NEWLINE} { + codifyLines(yytext); + if ( g_noSuiteFound ) + { + // printf("New suite to capture! [%d]\n", g_yyLineNr); + BEGIN ( SuiteCaptureIndent ); + } + } +} + +{ + "\n"|({BB}"\n") { + // Blankline - ignore, keep looking for indentation. + codifyLines(yytext); + } + + {BB} { + // This state lasts momentarily, + // to check the indentation + // level that is about to be + // used. + codifyLines(yytext); + g_indents.push(yyleng); + // printf("Captured indent of %d [line %d]\n", yyleng, g_yyLineNr); + BEGIN( Suite ); + } +} + +{ + + {BB}/({NONEMPTY}|{EXPCHAR}) { + // This implements poor + // indendation-tracking; + // should be improved. + // (translate tabs to space, etc) + codifyLines(yytext); + adjustScopesAndSuites(yyleng); + } + + "\n"|({BB}"\n") { + // If this ever succeeds, + // it means that this is + // a blank line, and + // can be ignored. + codifyLines(yytext); + } + + ""/({NONEMPTY}|{EXPCHAR}) { + // Default rule; matches + // the empty string, assuming + // real text starts here. + // Just go straight to Body. + adjustScopesAndSuites(0); + } +} + + +{NEWLINE} { + codifyLines(yytext); + BEGIN( SuiteMaintain ); + } +{IDENTIFIER} { + codify(yytext); + } +{NEWLINE} { + codifyLines(yytext); + } + +{ // Single quoted string like 'That\'s a """nice""" string!' + \\{B}\n { // line continuation + codifyLines(yytext); + } + \\. { // espaced char + codify(yytext); + } + {STRINGPREFIX}?{TRIDOUBLEQUOTE} { // tripple double quotes + codify(yytext); + } + "'" { // end of the string + codify(yytext); + endFontClass(); + BEGIN(g_stringContext); + } + [^"'\n\\]+ { // normal chars + codify(yytext); + } + . { // normal char + codify(yytext); + } +} + +{ // Double quoted string like "That's \"a '''nice'''\" string!" + \\{B}\n { // line continuation + codifyLines(yytext); + } + \\. { // espaced char + codify(yytext); + } + {STRINGPREFIX}?{TRISINGLEQUOTE} { // tripple single quotes + codify(yytext); + } + "\"" { // end of the string + codify(yytext); + endFontClass(); + BEGIN(g_stringContext); + } + [^"'\n\\]+ { // normal chars + codify(yytext); + } + . { // normal char + codify(yytext); + } +} + +{ + {TRIDOUBLEQUOTE} | + {TRISINGLEQUOTE} { + codify(yytext); + if (g_doubleQuote==(yytext[0]=='"')) + { + endFontClass(); + BEGIN(g_stringContext); + } + } + {LONGSTRINGBLOCK} { + codifyLines(yytext); + } + \n { + codifyLines(yytext); + } + . { + codify(yytext); + } +} + + /* +<*>({NONEMPTY}|{EXPCHAR}|{BB}) { // This should go one character at a time. + codify(yytext); + // printf("[pycode] '%s' [ state %d ] [line %d] no match\n", + // yytext, YY_START, g_yyLineNr); + + //endFontClass(); + BEGIN(Body); + } + */ + +<*>{STRINGPREFIX}?{TRISINGLEQUOTE} | +<*>{STRINGPREFIX}?{TRIDOUBLEQUOTE} { + startFontClass("stringliteral"); + g_stringContext=YY_START; + g_doubleQuote=yytext[yyleng-1]=='"'; + codify(yytext); + BEGIN(TripleString); + } +<*>{STRINGPREFIX}?"'" { // single quoted string + startFontClass("stringliteral"); + g_stringContext=YY_START; + codify(yytext); + BEGIN(SingleQuoteString); + } +<*>{STRINGPREFIX}?"\"" { // double quoted string + startFontClass("stringliteral"); + g_stringContext=YY_START; + codify(yytext); + BEGIN(DoubleQuoteString); + } +<*>{POUNDCOMMENT} { + if (YY_START==SingleQuoteString || + YY_START==DoubleQuoteString || + YY_START==TripleString + ) + { + REJECT; + } + // This eats EVERYTHING + // except the newline + startFontClass("comment"); + codifyLines(yytext); + endFontClass(); + } +<*>{NEWLINE} { + codifyLines(yytext); + //printf("[pycode] %d NEWLINE [line %d] no match\n", + // YY_START, g_yyLineNr); + + //endFontClass(); + BEGIN(Body); + } + +<*>[ \t]+ { + codify(yytext); + BEGIN(Body); + } +<*>. { + codify(yytext); + // printf("[pycode] '%s' [ state %d ] [line %d] no match\n", + // yytext, YY_START, g_yyLineNr); + + //endFontClass(); + BEGIN(Body); + } + +%% + +/*@ ---------------------------------------------------------------------------- + */ + +void resetPythonCodeParserState() +{ + g_currentDefinition = 0; + g_currentMemberDef = 0; + g_doubleStringIsDoc = FALSE; + g_paramParens = 0; + g_indents.clear(); + BEGIN( Body ); +} + +/*! + Examines current stack of white-space indentations; + re-syncs the parser with the correct scope. +*/ +static void adjustScopesAndSuites(unsigned indentLength) +{ + // States to pop + if (!g_indents.isEmpty() && indentLength < g_indents.top()) + { + while (!g_indents.isEmpty() && indentLength < g_indents.top()) + { + // printf("Exited scope indent of [%d]\n", g_indents.top()); + g_indents.pop(); // Pop the old suite's indentation + + g_currentMemberDef=0; + if (g_currentDefinition) + g_currentDefinition=g_currentDefinition->getOuterScope(); + } + } + + // Are there any remaining indentation levels for suites? + if (!g_indents.isEmpty()) + { + BEGIN( Suite ); + } + else + { + BEGIN( Body ); + } +} + +void parsePythonCode(CodeOutputInterface &od,const char * /*className*/, + const QCString &s,bool exBlock, const char *exName, + FileDef *fd,int startLine,int endLine,bool /*inlineFragment*/, + MemberDef *,bool) +{ + + //printf("***parseCode()\n"); + + //-------------------------------------- + if (s.isEmpty()) return; + g_code = &od; + g_inputString = s; + g_inputPosition = 0; + g_currentFontClass = 0; + g_needsTermination = FALSE; + if (endLine!=-1) + g_inputLines = endLine+1; + else + g_inputLines = countLines(); + + if (startLine!=-1) + g_yyLineNr = startLine; + else + g_yyLineNr = 1; + + g_exampleBlock = exBlock; + g_exampleName = exName; + g_sourceFileDef = fd; + + + // Starts line 1 on the output + startCodeLine(); + + pycodeYYrestart( pycodeYYin ); + + pycodeYYlex(); + + if (!g_indents.isEmpty()) + { + // printf("Exited pysourceparser in inconsistent state!\n"); + } + + if (g_needsTermination) + { + endCodeLine(); + } + return; +} + + +#if !defined(YY_FLEX_SUBMINOR_VERSION) +extern "C" { // some bogus code to keep the compiler happy + void pycodeYYdummy() { yy_flex_realloc(0,0); } +} +#elif YY_FLEX_SUBMINOR_VERSION<33 +#error "You seem to be using a version of flex newer than 2.5.4. These are currently incompatible with 2.5.4, and do NOT work with doxygen! Please use version 2.5.4 or expect things to be parsed wrongly! A bug report has been submitted (#732132)." +#endif + diff --git a/trunk/src/pyscanner.h b/trunk/src/pyscanner.h new file mode 100644 index 0000000..3bb4b21 --- /dev/null +++ b/trunk/src/pyscanner.h @@ -0,0 +1,60 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ +/* This code is based on the work done by the MoxyPyDoxy team + * (Linda Leong, Mike Rivera, Kim Truong, and Gabriel Estrada) + * in Spring 2005 as part of CS 179E: Compiler Design Project + * at the University of California, Riverside; the course was + * taught by Peter H. Froehlich . + */ + + +#ifndef PYSCANNER_H +#define PYSCANNER_H + +#include "parserintf.h" + +/** \brief Python Language parser using state-based lexical scanning. + * + * This is the Python language parser for doxygen. + */ +class PythonLanguageScanner : public ParserInterface +{ + public: + virtual ~PythonLanguageScanner() {} + void parseInput(const char * fileName, + const char *fileBuf, + Entry *root); + bool needsPreprocessing(const QCString &extension); + void parseCode(CodeOutputInterface &codeOutIntf, + const char *scopeName, + const QCString &input, + bool isExampleBlock, + const char *exampleName=0, + FileDef *fileDef=0, + int startLine=-1, + int endLine=-1, + bool inlineFragment=FALSE, + MemberDef *memberDef=0, + bool showLineNumbers=TRUE + ); + void resetCodeParserState(); + void parsePrototype(const char *text); +}; + +void pyscanFreeScanner(); + +#endif diff --git a/trunk/src/pyscanner.l b/trunk/src/pyscanner.l new file mode 100644 index 0000000..7c571d6 --- /dev/null +++ b/trunk/src/pyscanner.l @@ -0,0 +1,1727 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ +/* This code is based on the work done by the MoxyPyDoxy team + * (Linda Leong, Mike Rivera, Kim Truong, and Gabriel Estrada) + * in Spring 2005 as part of CS 179E: Compiler Design Project + * at the University of California, Riverside; the course was + * taught by Peter H. Froehlich . + */ + + +%{ + +/* + * includes + */ +#include +#include +#include +#include + +#include "qtbc.h" +#include +#include +#include +#include +#include +#include + +#include "pyscanner.h" +#include "entry.h" +#include "message.h" +#include "config.h" +#include "doxygen.h" +#include "util.h" +#include "defargs.h" +#include "language.h" +#include "commentscan.h" +#include "pycode.h" +#include "arguments.h" + +#define YY_NEVER_INTERACTIVE 1 + +/* ----------------------------------------------------------------- + * + * statics + */ + + +static ParserInterface *g_thisParser; +static const char * inputString; +static int inputPosition; +static QFile inputFile; + +static Protection protection; + +static Entry* current_root = 0 ; +static Entry* current = 0 ; +static Entry* previous = 0 ; +static Entry* bodyEntry = 0 ; +static int yyLineNr = 1 ; +static QCString yyFileName; +static MethodTypes mtype; +static bool gstat; +static Specifier virt; + +static int docBlockContext; +static QCString docBlock; +static QCString docBlockName; +static bool docBlockInBody; +static bool docBlockJavaStyle; +static bool docBrief; +static bool docBlockSpecial; + +static bool g_doubleQuote; +static bool g_specialBlock; +static int g_stringContext; +static QGString * g_copyString; +static int g_indent = 0; +static int g_curIndent = 0; + +static QDict g_packageNameCache(257); +static QCString g_packageScope; + +static char g_atomStart; +static char g_atomEnd; +static int g_atomCount; + +//static bool g_insideConstructor; + +static QCString g_moduleScope; +static QCString g_packageName; + +//static bool g_hideClassDocs; + +static QCString g_defVal; +static int g_braceCount; + +static bool g_lexInit = FALSE; +static bool g_packageCommentAllowed; + +//----------------------------------------------------------------------------- + + +static void initParser() +{ + protection = Public; + mtype = Method; + gstat = FALSE; + virt = Normal; + previous = 0; + g_packageCommentAllowed = TRUE; + g_packageNameCache.setAutoDelete(TRUE); +} + +static void initEntry() +{ + //current->python = TRUE; + current->protection = protection ; + current->mtype = mtype; + current->virt = virt; + current->stat = gstat; + current->lang = SrcLangExt_Python; + current->setParent(current_root); + initGroupInfo(current); + gstat = FALSE; +} + +static void newEntry() +{ + previous = current; + current_root->addSubEntry(current); + current = new Entry ; + initEntry(); +} + +static void newVariable() +{ + if (!current->name.isEmpty() && current->name.at(0)=='_') // mark as private + { + current->protection=Private; + } + if (current_root->section&Entry::COMPOUND_MASK) // mark as class variable + { + current->stat = TRUE; + } + newEntry(); +} + +static void newFunction() +{ + if (current->name.left(2)=="__" && current->name.right(2)=="__") + { + // special method name, see + // http://docs.python.org/ref/specialnames.html + current->protection=Public; + } + else if (current->name.at(0)=='_') + { + current->protection=Private; + } +} + +static inline int computeIndent(const char *s) +{ + int col=0; + static int tabSize=Config_getInt("TAB_SIZE"); + const char *p=s; + char c; + while ((c=*p++)) + { + if (c==' ') col++; + else if (c=='\t') col+=tabSize-(col%tabSize); + else break; + } + return col; +} + +static QCString findPackageScopeFromPath(const QCString &path) +{ + QCString *pScope = g_packageNameCache.find(path); + if (pScope) + { + return *pScope; + } + QFileInfo pf(path+"/__init__.py"); // found package initialization file + if (pf.exists()) + { + int i=path.findRev('/'); + if (i!=-1) + { + QCString scope = findPackageScopeFromPath(path.left(i)); + if (!scope.isEmpty()) + { + scope+="::"; + } + scope+=path.mid(i+1); + g_packageNameCache.insert(path,new QCString(scope)); + return scope; + } + } + return ""; +} + +static QCString findPackageScope(const char *fileName) +{ + if (fileName==0) return ""; + QFileInfo fi(fileName); + return findPackageScopeFromPath(fi.dirPath(TRUE).data()); +} + +//----------------------------------------------------------------------------- + +static void lineCount() +{ + //fprintf(stderr,"yyLineNr=%d\n",yyLineNr); + for (const char *p = yytext; *p; ++p) + { + yyLineNr += (*p == '\n') ; + } +} + +static void incLineNr() +{ + //fprintf(stderr,"yyLineNr=%d\n",yyLineNr); + yyLineNr++; +} + +#if 0 +// Appends the current-name to current-type; +// Destroys current-name. +// Destroys current->args and current->argList +static void addType( Entry* current ) +{ + uint tl=current->type.length(); + if ( tl>0 && !current->name.isEmpty() && current->type.at(tl-1)!='.') + { + current->type += ' ' ; + } + current->type += current->name ; + current->name.resize(0) ; + tl=current->type.length(); + if ( tl>0 && !current->args.isEmpty() && current->type.at(tl-1)!='.') + { + current->type += ' ' ; + } + current->type += current->args ; + current->args.resize(0) ; + current->argList->clear(); +} + +static QCString stripQuotes(const char *s) +{ + QCString name; + if (s==0 || *s==0) return name; + name=s; + if (name.at(0)=='"' && name.at(name.length()-1)=='"') + { + name=name.mid(1,name.length()-2); + } + return name; +} +#endif +//----------------------------------------------------------------- + +//----------------------------------------------------------------- +static void startCommentBlock(bool brief) +{ + if (brief) + { + current->briefFile = yyFileName; + current->briefLine = yyLineNr; + } + else + { + current->docFile = yyFileName; + current->docLine = yyLineNr; + } +} + +/* +static void appendDocBlock() { + previous = current; + current_root->addSubEntry(current); + current = new Entry; + initEntry(); +} +*/ + +static void handleCommentBlock(const QCString &doc,bool brief) +{ + //printf("handleCommentBlock(doc=[%s] brief=%d docBlockInBody=%d docBlockJavaStyle=%d\n", + // doc.data(),brief,docBlockInBody,docBlockJavaStyle); + + // TODO: Fix me + docBlockInBody=FALSE; + + if (docBlockInBody && previous && !previous->doc.isEmpty()) + { + previous->doc=previous->doc.stripWhiteSpace()+"\n\n"; + } + + int position = 0; + bool needsEntry; + int lineNr = brief ? current->briefLine : current->docLine; + while (parseCommentBlock( + g_thisParser, + (docBlockInBody && previous) ? previous : current, + doc, // text + yyFileName, // file + lineNr, + docBlockInBody ? FALSE : brief, + docBlockJavaStyle, // javadoc style // or FALSE, + docBlockInBody, + protection, + position, + needsEntry) + ) // need to start a new entry + { + if (needsEntry) + { + newEntry(); + } + } + if (needsEntry) + { + newEntry(); + } + +} + +static void endOfDef(int correction=0) +{ + //printf("endOfDef at=%d\n",yyLineNr); + if (bodyEntry) + { + bodyEntry->endBodyLine = yyLineNr-correction; + bodyEntry = 0; + } + newEntry(); + //g_insideConstructor = FALSE; +} + +static inline void addToString(const char *s) +{ + if (g_copyString) (*g_copyString)+=s; +} + +static void initTriDoubleQuoteBlock() +{ + docBlockContext = YY_START; + docBlockInBody = FALSE; + docBlockJavaStyle = TRUE; + docBlockSpecial = yytext[3]=='!'; + docBlock.resize(0); + g_doubleQuote = TRUE; + startCommentBlock(FALSE); +} + +static void initTriSingleQuoteBlock() +{ + docBlockContext = YY_START; + docBlockInBody = FALSE; + docBlockJavaStyle = TRUE; + docBlockSpecial = yytext[3]=='!'; + docBlock.resize(0); + g_doubleQuote = FALSE; + startCommentBlock(FALSE); +} + +static void initSpecialBlock() +{ + docBlockContext = YY_START; + docBlockInBody = FALSE; + docBlockJavaStyle = TRUE; + docBrief = TRUE; + docBlock.resize(0); + startCommentBlock(TRUE); +} + +static void searchFoundDef() +{ + current->fileName = yyFileName; + current->startLine = yyLineNr; + current->bodyLine = yyLineNr; + current->section = Entry::FUNCTION_SEC; + current->protection = protection = Public; + current->lang = SrcLangExt_Python; + current->virt = Normal; + current->stat = gstat; + current->mtype = mtype = Method; + current->type.resize(0); + current->name.resize(0); + current->args.resize(0); + current->argList->clear(); + g_packageCommentAllowed = FALSE; + gstat=FALSE; + //printf("searchFoundDef at=%d\n",yyLineNr); +} + +static void searchFoundClass() +{ + current->section = Entry::CLASS_SEC; + current->argList->clear(); + current->type += "class" ; + current->fileName = yyFileName; + current->startLine = yyLineNr; + current->bodyLine = yyLineNr; + g_packageCommentAllowed = FALSE; +} + +//----------------------------------------------------------------------------- +/* ----------------------------------------------------------------- */ +#undef YY_INPUT +#define YY_INPUT(buf,result,max_size) result=yyread(buf,max_size); + +static int yyread(char *buf,int max_size) +{ + int c=0; + while ( c < max_size && inputString[inputPosition] ) + { + *buf = inputString[inputPosition++] ; + //printf("%d (%c)\n",*buf,*buf); + c++; buf++; + } + return c; +} + +%} + + /* start command character */ + + + +BB [ \t]+ +B [ \t]* +NEWLINE \n +BN [ \t\n] + +DIGIT [0-9] + +HEXNUMBER "0"[xX][0-9a-fA-F]+[lL]? +OCTNUMBER "0"[0-7]+[lL]? +NUMBER {DIGIT}+[lLjJ]? +INTNUMBER {HEXNUMBER}|{OCTNUMBER}|{NUMBER} +FLOATNUMBER {DIGIT}+"."{DIGIT}+([eE][+\-]?{DIGIT}+)?[jJ]? +LETTER [A-Za-z] +NONEMPTY [A-Za-z0-9_] +EXPCHAR [#(){}\[\],:.%/\\=`*~|&<>!;+-] +NONEMPTYEXP [^ \t\n:] +PARAMNONEMPTY [^ \t\n():] +IDENTIFIER ({LETTER}|"_")({LETTER}|{DIGIT}|"_")* +SCOPE {IDENTIFIER}("."{IDENTIFIER})* +BORDER ([^A-Za-z0-9]) + +TRISINGLEQUOTE "'''"(!)? +TRIDOUBLEQUOTE "\"\"\""(!)? +LONGSTRINGCHAR [^\\"'] +ESCAPESEQ ("\\")(.) +LONGSTRINGITEM ({LONGSTRINGCHAR}|{ESCAPESEQ}) +SMALLQUOTE ("\"\""|"\""|"'"|"''") +LONGSTRINGBLOCK ({LONGSTRINGITEM}+|{SMALLQUOTE}) + +SHORTSTRING ("'"{SHORTSTRINGITEM}*"'"|'"'{SHORTSTRINGITEM}*'"') +SHORTSTRINGITEM ({SHORTSTRINGCHAR}|{ESCAPESEQ}) +SHORTSTRINGCHAR [^\\\n"] +STRINGLITERAL {STRINGPREFIX}?( {SHORTSTRING} | {LONGSTRING}) +STRINGPREFIX ("r"|"u"|"ur"|"R"|"U"|"UR"|"Ur"|"uR") +KEYWORD ("lambda"|"import"|"class"|"assert"|"as"|"from"|"global"|"def"|"True"|"False") +FLOWKW ("or"|"and"|"is"|"not"|"print"|"for"|"in"|"if"|"try"|"except"|"yield"|"raise"|"break"|"continue"|"pass"|"if"|"return"|"while"|"elif"|"else"|"finally") +POUNDCOMMENT "#"[^#\n][^\n]* + +STARTDOCSYMS "##" + +%option noyywrap + + /* Main start state */ + +%x Search +%x SearchMemVars + + /* Mid-comment states */ + + /* %x FuncDoubleComment */ + /* %x ClassDoubleComment */ +%x TryClassDocString +%x TripleComment +%x SpecialComment + + /* Function states */ + +%x FunctionDec +%x FunctionParams +%x FunctionBody +%x FunctionParamDefVal + + /* Class states */ + +%x ClassDec +%x ClassInheritance +%x ClassCaptureIndent +%x ClassBody + + /* Variable states */ +%x VariableDec +%x VariableEnd +%x VariableAtom + + /* String states */ + +%x SingleQuoteString +%x DoubleQuoteString +%x TripleString + + /* import */ +%x FromMod +%x FromModItem +%x Import + +%% + + /* ------------ Function recognition rules -------------- */ + +{ + + ^{B}"def"{BB} { // start of a function/method definition with indent + //fprintf(stderr,"Found def at %d\n",yyLineNr); + g_indent=computeIndent(yytext); + searchFoundDef(); + BEGIN( FunctionDec ); + } + "def"{BB} { // start of a function/method definition + searchFoundDef(); + BEGIN( FunctionDec ); + } + + ^{B}"class"{BB} { // start of a class definition with indent + //fprintf(stderr,"Found class at %d\n",yyLineNr); + g_indent=computeIndent(yytext); + searchFoundClass(); + BEGIN( ClassDec ) ; + } + "class"{BB} { // start of a class definition + searchFoundClass(); + BEGIN( ClassDec ) ; + } + ^{B}"from"{BB} | + "from"{BB} { // start of an from import + g_packageCommentAllowed = FALSE; + BEGIN( FromMod ); + } + + ^{B}"import"{BB} | + "import"{BB} { // start of an import statement + g_packageCommentAllowed = FALSE; + BEGIN( Import ); + } + ^{B}{IDENTIFIER}/{B}"="{B}"property" { // property + current->section = Entry::VARIABLE_SEC; + current->mtype = Property; + current->name = QCString(yytext).stripWhiteSpace(); + current->fileName = yyFileName; + current->startLine = yyLineNr; + current->bodyLine = yyLineNr; + g_packageCommentAllowed = FALSE; + BEGIN(VariableDec); + } + ^{B}{IDENTIFIER}/{B}"="[^=] { // variable + g_indent=computeIndent(yytext); + current->section = Entry::VARIABLE_SEC; + current->name = QCString(yytext).stripWhiteSpace(); + current->fileName = yyFileName; + current->startLine = yyLineNr; + current->bodyLine = yyLineNr; + g_packageCommentAllowed = FALSE; + BEGIN(VariableDec); + } + "'" { // start of a single quoted string + g_stringContext=YY_START; + g_copyString=0; + g_packageCommentAllowed = FALSE; + BEGIN( SingleQuoteString ); + } + "\"" { // start of a double quoted string + g_stringContext=YY_START; + g_copyString=0; + g_packageCommentAllowed = FALSE; + BEGIN( DoubleQuoteString ); + } + "@staticmethod" { + gstat=TRUE; + } + {POUNDCOMMENT} { // normal comment + g_packageCommentAllowed = FALSE; + } + {IDENTIFIER} { // some other identifier + g_packageCommentAllowed = FALSE; + } + ^{BB} { + g_curIndent=computeIndent(yytext); + } + + {NEWLINE}+ { // new line + lineCount(); + } + + {TRIDOUBLEQUOTE} { // start of a comment block + initTriDoubleQuoteBlock(); + BEGIN(TripleComment); + } + + {TRISINGLEQUOTE} { // start of a comment block + initTriSingleQuoteBlock(); + BEGIN(TripleComment); + } + + {STARTDOCSYMS}/[^#] { // start of a special comment + g_curIndent=computeIndent(yytext); + g_packageCommentAllowed = FALSE; + initSpecialBlock(); + BEGIN(SpecialComment); + } + [^\n] { // any other character... + // This is the major default + // that should catch everything + // else in Body. + } +} + +{ + {IDENTIFIER}({B}"."{B}{IDENTIFIER})* { // from package import + g_packageName=yytext; + } + "import"{B} { + BEGIN(FromModItem); + } + \n { + incLineNr(); + BEGIN(Search); + } + {B} { + } + . { + unput(*yytext); + BEGIN(Search); + } +} + +{ + "*" { // import all + QCString item=g_packageName; + current->name=removeRedundantWhiteSpace(substitute(item,".","::")); + current->fileName = yyFileName; + //printf("Adding using directive: found:%s:%d name=%s\n",yyFileName.data(),yyLineNr,current->name.data()); + current->section=Entry::USINGDIR_SEC; + current_root->addSubEntry(current); + current = new Entry ; + initEntry(); + BEGIN(Search); + } + {IDENTIFIER}/{B}","{B} { + QCString item=g_packageName+"."+yytext; + current->name=removeRedundantWhiteSpace(substitute(item,".","::")); + current->fileName = yyFileName; + //printf("Adding using declaration: found:%s:%d name=%s\n",yyFileName.data(),yyLineNr,current->name.data()); + current->section=Entry::USINGDECL_SEC; + current_root->addSubEntry(current); + current = new Entry ; + initEntry(); + } + {IDENTIFIER} { + QCString item=g_packageName+"."+yytext; + current->name=removeRedundantWhiteSpace(substitute(item,".","::")); + current->fileName = yyFileName; + //printf("Adding using declaration: found:%s:%d name=%s\n",yyFileName.data(),yyLineNr,current->name.data()); + current->section=Entry::USINGDECL_SEC; + current_root->addSubEntry(current); + current = new Entry ; + initEntry(); + BEGIN(Search); + } + \n { + incLineNr(); + BEGIN(Search); + } + {B} { + } + "," { + } + . { + unput(*yytext); + BEGIN(Search); + } +} + +{ + {IDENTIFIER}({B}"."{B}{IDENTIFIER})* { + current->name=removeRedundantWhiteSpace(substitute(yytext,".","::")); + current->fileName = yyFileName; + //printf("Adding using declaration: found:%s:%d name=%s\n",yyFileName.data(),yyLineNr,current->name.data()); + current->section=Entry::USINGDECL_SEC; + current_root->addSubEntry(current); + current = new Entry ; + initEntry(); + BEGIN(Search); + } + \n { + incLineNr(); + BEGIN(Search); + } + {B} { + } + . { + unput(*yytext); + BEGIN(Search); + } +} + +{ + "self."{IDENTIFIER}/{B}"=" { + //fprintf(stderr,"Found member variable %s in %s at %d\n",&yytext[5],current_root->name.data(),yyLineNr); + current->name=&yytext[5]; + current->section=Entry::VARIABLE_SEC; + current->fileName = yyFileName; + current->startLine = yyLineNr; + current->bodyLine = yyLineNr; + current->type.resize(0); + if (current->name.at(0)=='_') // mark as private + { + current->protection=Private; + } + else + { + current->protection=Public; + } + newEntry(); + } + {TRIDOUBLEQUOTE} { // start of a comment block + initTriDoubleQuoteBlock(); + BEGIN(TripleComment); + } + + {TRISINGLEQUOTE} { // start of a comment block + initTriSingleQuoteBlock(); + BEGIN(TripleComment); + } + + {STARTDOCSYMS}/[^#] { // start of a special comment + initSpecialBlock(); + BEGIN(SpecialComment); + } + {POUNDCOMMENT} { // # + } + "'" { // start of a single quoted string + g_stringContext=YY_START; + g_copyString=0; + BEGIN( SingleQuoteString ); + } + "\"" { // start of a double quoted string + g_stringContext=YY_START; + g_copyString=0; + BEGIN( DoubleQuoteString ); + } + \n { incLineNr(); } + {IDENTIFIER} // identifiers + [^'"\.#a-z_A-Z\n]+ // other uninteresting stuff + . // anything else +} + +{ + \n{B}/{IDENTIFIER}{BB} { + //fprintf(stderr,"indent %d<=%d\n",computeIndent(&yytext[1]),g_indent); + if (computeIndent(&yytext[1])<=g_indent) + { + int i; + for (i=yyleng-1;i>=0;i--) + { + unput(yytext[i]); + } + endOfDef(); + //YY_CURRENT_BUFFER->yy_at_bol=TRUE; + BEGIN(Search); + } + else + { + incLineNr(); + current->program+=yytext; + } + } + \n{B}/"##" { + if (computeIndent(&yytext[1])<=g_indent) + { + int i; + for (i=yyleng-1;i>=0;i--) + { + unput(yytext[i]); + } + endOfDef(); + //YY_CURRENT_BUFFER->yy_at_bol=TRUE; + BEGIN(Search); + } + else + { + incLineNr(); + current->program+=yytext; + } + } + <> { + endOfDef(); + yyterminate(); + } + ^{BB}/\n { // skip empty line + current->program+=yytext; + } + ^{BB} { // something at indent >0 + current->program+=yytext; + g_curIndent = computeIndent(yytext); + if (g_curIndent<=g_indent) + // jumped out of the function + { + endOfDef(1); + BEGIN(Search); + } + } + "'" { // start of a single quoted string + current->program+=yytext; + g_stringContext=YY_START; + g_specialBlock = FALSE; + g_copyString=¤t->program; + BEGIN( SingleQuoteString ); + } + "\"" { // start of a double quoted string + current->program+=yytext; + g_stringContext=YY_START; + g_specialBlock = FALSE; + g_copyString=¤t->program; + BEGIN( DoubleQuoteString ); + } + [^ \t\n#'".]+ { // non-special stuff + current->program+=yytext; + g_specialBlock = FALSE; + } + ^{POUNDCOMMENT} { // normal comment + current->program+=yytext; + } + "#".* { // comment half way + current->program+=yytext; + } + {NEWLINE} { + incLineNr(); + current->program+=yytext; + } + . { // any character + current->program+=*yytext; + g_specialBlock = FALSE; + } + + {TRIDOUBLEQUOTE} { // start of a comment block + current->program+=yytext; + initTriDoubleQuoteBlock(); + BEGIN(TripleComment); + } + + {TRISINGLEQUOTE} { // start of a comment block + current->program+=yytext; + initTriSingleQuoteBlock(); + BEGIN(TripleComment); + } + + {STARTDOCSYMS}/[^#] { // start of a special comment + initSpecialBlock(); + BEGIN(SpecialComment); + } + +} + +{ + + {IDENTIFIER} { + //found function name + if (current->type.isEmpty()) + { + current->type = "def"; + } + current->name = yytext; + current->name = current->name.stripWhiteSpace(); + newFunction(); + } + {B}":" { // function without arguments + g_specialBlock = TRUE; // expecting a docstring + bodyEntry = current; + current->bodyLine = yyLineNr; + BEGIN( FunctionBody ); + } + + {B}"(" { + BEGIN( FunctionParams ); + } +} + +{ + ({BB}|",") { + } + + {IDENTIFIER} { // Name of parameter + lineCount(); + Argument *a = new Argument; + current->argList->append(a); + current->argList->getLast()->name = QCString(yytext).stripWhiteSpace(); + current->argList->getLast()->type = ""; + } + "=" { // default value + // TODO: this rule is too simple, need to be able to + // match things like =")" as well! + QCString defVal=&yytext[1]; + g_defVal.resize(0); + g_braceCount=0; + BEGIN(FunctionParamDefVal); + } + + ")" { // end of parameter list + } + + ":"{B} { + g_specialBlock = TRUE; // expecting a docstring + bodyEntry = current; + current->bodyLine = yyLineNr; + BEGIN( FunctionBody ); + } + {POUNDCOMMENT} { // a comment + } + {PARAMNONEMPTY} { // Default rule inside arguments. + } + +} + +{ + "(" { // internal opening brace + g_braceCount++; + g_defVal+=*yytext; + } + "," | + ")" { + if (g_braceCount==0) // end of default argument + { + if (current->argList->getLast()) + { + current->argList->getLast()->defval=g_defVal.stripWhiteSpace(); + } + BEGIN(FunctionParams); + } + else // continue + { + g_braceCount--; + g_defVal+=*yytext; + } + } + . { + g_defVal+=*yytext; + } + \n { + g_defVal+=*yytext; + incLineNr(); + } +} + + +{ + \n/{IDENTIFIER}{BB} { // new def at indent 0 + incLineNr(); + endOfDef(); + //g_hideClassDocs = FALSE; + //YY_CURRENT_BUFFER->yy_at_bol=TRUE; + BEGIN(Search); + } + \n/"##"[^#] { // start of a special comment at indent 0 + incLineNr(); + endOfDef(); + //g_hideClassDocs = FALSE; + //YY_CURRENT_BUFFER->yy_at_bol=TRUE; + BEGIN(Search); + } + ^{BB}/\n { // skip empty line + current->program+=yytext; + } + <> { + endOfDef(); + yyterminate(); + } + ^{BB} { // something at indent >0 + g_curIndent=computeIndent(yytext); + //fprintf(stderr,"g_curIndent=%d g_indent=%d\n",g_curIndent,g_indent); + if (g_curIndent<=g_indent) + // jumped out of the class/method + { + endOfDef(1); + g_indent=g_curIndent; + // make sure the next rule matches ^... + //YY_CURRENT_BUFFER->yy_at_bol=TRUE; + //g_hideClassDocs = FALSE; + BEGIN(Search); + } + else + { + current->program+=yytext; + } + } + "'" { // start of a single quoted string + current->program+=*yytext; + g_stringContext=YY_START; + g_specialBlock = FALSE; + g_copyString=¤t->program; + BEGIN( SingleQuoteString ); + } + "\"" { // start of a double quoted string + current->program+=*yytext; + g_stringContext=YY_START; + g_specialBlock = FALSE; + g_copyString=¤t->program; + BEGIN( DoubleQuoteString ); + } + [^ \t\n#'"]+ { // non-special stuff + current->program+=yytext; + g_specialBlock = FALSE; + //g_hideClassDocs = FALSE; + } + {NEWLINE} { + current->program+=*yytext; + incLineNr(); + } + {POUNDCOMMENT} { // normal comment + current->program+=yytext; + } + . { // any character + g_specialBlock = FALSE; + current->program+=*yytext; + } + {TRIDOUBLEQUOTE} { // start of a comment block + //if (!g_hideClassDocs) + current->program+=yytext; + initTriDoubleQuoteBlock(); + BEGIN(TripleComment); + } + + {TRISINGLEQUOTE} { // start of a comment block + //if (!g_hideClassDocs) + current->program+=yytext; + initTriSingleQuoteBlock(); + BEGIN(TripleComment); + } +} + +{IDENTIFIER} { + if (current->type.isEmpty()) + { + current->type = "class"; + } + + current->section = Entry::CLASS_SEC; + current->name = yytext; + + // prepend scope in case of nested classes + if (current_root->section&Entry::SCOPE_MASK) + { + //printf("*** Prepending scope %s to class %s\n",current_root->name.data(),current->name.data()); + current->name.prepend(current_root->name+"::"); + } + + current->name = current->name.stripWhiteSpace(); + current->fileName = yyFileName; + docBlockContext = YY_START; + docBlockInBody = FALSE; + docBlockJavaStyle = FALSE; + docBlock.resize(0); + + BEGIN(ClassInheritance); + } + +{ + ({BB}|[\(,\)]) { // syntactic sugar for the list + } + + ":" { // begin of the class definition + g_specialBlock = TRUE; // expecting a docstring + current->bodyLine = yyLineNr; + current->program.resize(0); + BEGIN(ClassCaptureIndent); + } + + {SCOPE} { + current->extends->append( + new BaseInfo(substitute(yytext,".","::"),Public,Normal) + ); + //Has base class-do stuff + } +} + + +{ + "\n"|({BB}"\n") { + // Blankline - ignore, keep looking for indentation. + lineCount(); + current->program+=yytext; + } + + {TRIDOUBLEQUOTE} { // start of a comment block + initTriDoubleQuoteBlock(); + current->program+=yytext; + BEGIN(TripleComment); + } + + {TRISINGLEQUOTE} { // start of a comment block + initTriSingleQuoteBlock(); + current->program+=yytext; + BEGIN(TripleComment); + } + + ^{BB} { + current->program+=yytext; + //current->startLine = yyLineNr; + g_curIndent=computeIndent(yytext); + bodyEntry = current; + //fprintf(stderr,"setting indent %d\n",g_curIndent); + //printf("current->program=[%s]\n",current->program.data()); + //g_hideClassDocs = TRUE; + BEGIN(ClassBody); + } + + ""/({NONEMPTY}|{EXPCHAR}) { + + // Just pushback an empty class, and + // resume parsing the body. + newEntry(); + current->program+=yytext; + + // printf("Failed to find indent - skipping!"); + BEGIN( Search ); + } +} + + +{ + "=" { // the assignment operator + //printf("====== VariableDec at line %d\n",yyLineNr); + } + {B} { // spaces + } + {INTNUMBER} { // integer value + current->type = "int"; + current->initializer = yytext; + BEGIN(VariableEnd); + } + {FLOATNUMBER} { // floating point value + current->type = "float"; + current->initializer = yytext; + BEGIN(VariableEnd); + } + {STRINGPREFIX}?"'" { // string + current->type = "string"; + current->initializer = yytext; + g_copyString=¤t->initializer; + g_stringContext=VariableEnd; + BEGIN( SingleQuoteString ); + } + {STRINGPREFIX}?"\"" { // string + current->type = "string"; + current->initializer = yytext; + g_copyString=¤t->initializer; + g_stringContext=VariableEnd; + BEGIN( DoubleQuoteString ); + } + {TRIDOUBLEQUOTE} { // start of a comment block + current->type = "string"; + current->initializer = yytext; + g_doubleQuote=TRUE; + g_copyString=¤t->initializer; + g_stringContext=VariableEnd; + BEGIN(TripleString); + } + + {TRISINGLEQUOTE} { // start of a comment block + current->type = "string"; + current->initializer = yytext; + g_doubleQuote=FALSE; + g_copyString=¤t->initializer; + g_stringContext=VariableEnd; + BEGIN(TripleString); + } + "(" { // tuple + if (current->mtype!=Property) + { + current->type = "tuple"; + } + current->initializer+=*yytext; + g_atomStart='('; + g_atomEnd=')'; + g_atomCount=1; + BEGIN( VariableAtom ); + } + "[" { // list + current->type = "list"; + current->initializer+=*yytext; + g_atomStart='['; + g_atomEnd=']'; + g_atomCount=1; + BEGIN( VariableAtom ); + } + "{" { // dictionary + current->type = "dictionary"; + current->initializer+=*yytext; + g_atomStart='{'; + g_atomEnd='}'; + g_atomCount=1; + BEGIN( VariableAtom ); + } + "#".* { // comment + BEGIN( VariableEnd ); + } + {IDENTIFIER} { + current->initializer+=yytext; + } + . { + current->initializer+=*yytext; + } + \n { + unput('\n'); + BEGIN( VariableEnd ); + } +} + +{ + [\(\[\{] { + current->initializer+=*yytext; + if (g_atomStart==*yytext) + { + g_atomCount++; + } + } + [\)\]\}] { + current->initializer+=*yytext; + if (g_atomEnd==*yytext) + { + g_atomCount--; + } + if (g_atomCount==0) + { + BEGIN(VariableEnd); + } + } + "\"" { + g_stringContext=YY_START; + current->initializer+="\""; + g_copyString=¤t->initializer; + BEGIN( DoubleQuoteString ); + } + {IDENTIFIER} { + current->initializer+=yytext; + } + . { + current->initializer+=*yytext; + } + \n { + current->initializer+=*yytext; + incLineNr(); + } + +} + +{ + \n { + incLineNr(); + newVariable(); + BEGIN(Search); + } + . { + unput(*yytext); + newVariable(); + BEGIN(Search); + } + <> { yyterminate(); + newEntry(); + } +} + +{ + {TRIDOUBLEQUOTE} | + {TRISINGLEQUOTE} { + // printf("Expected module block %d special=%d\n",g_expectModuleDocs,g_specialBlock); + if (g_doubleQuote==(yytext[0]=='"')) + { + if (g_specialBlock) // expecting a docstring + { + QCString actualDoc=docBlock; + if (!docBlockSpecial) // legacy unformatted docstring + { + actualDoc.prepend("\\verbatim "); + actualDoc.append("\\endverbatim "); + } + //printf("-------> current=%p bodyEntry=%p\n",current,bodyEntry); + handleCommentBlock(actualDoc, FALSE); + } + else if (g_packageCommentAllowed) // expecting module docs + { + QCString actualDoc=docBlock; + if (!docBlockSpecial) // legacy unformatted docstring + { + actualDoc.prepend("\\verbatim "); + actualDoc.append("\\endverbatim "); + } + actualDoc.prepend("\\namespace "+g_moduleScope+"\\_linebr "); + handleCommentBlock(actualDoc, FALSE); + } + if ((docBlockContext==ClassBody /*&& !g_hideClassDocs*/) || + docBlockContext==FunctionBody) + { + current->program+=docBlock; + current->program+=yytext; + } + //if (g_hideClassDocs) + //{ + // current->startLine = yyLineNr; + //} + //g_hideClassDocs=FALSE; + BEGIN(docBlockContext); + } + else + { + docBlock += yytext; + } + g_packageCommentAllowed = FALSE; + } + + + ^{BB} { // leading whitespace + int indent = computeIndent(yytext); + if (indent>=g_curIndent) + { // strip g_curIndent amount of whitespace + int i; + for (i=0;i{ + ^{B}"#"("#")* { // skip leading hashes + } + \n/{B}"#" { // continuation of the comment on the next line + docBlock+='\n'; + docBrief = FALSE; + startCommentBlock(FALSE); + incLineNr(); + } + [^#\n]+ { // any other stuff + docBlock+=yytext; + } + \n { // new line that ends the comment + handleCommentBlock(docBlock, docBrief); + incLineNr(); + BEGIN(docBlockContext); + } + . { // anything we missed + docBlock+=*yytext; + } +} + +{ + \\{B}\n { // line continuation + addToString(yytext); + incLineNr(); + } + \\. { // espaced char + addToString(yytext); + } + "\"\"\"" { // tripple double quotes + addToString(yytext); + } + "'" { // end of the string + addToString(yytext); + BEGIN(g_stringContext); + } + [^"'\n\\]+ { // normal chars + addToString(yytext); + } + . { // normal char + addToString(yytext); + } +} + +{ + \\{B}\n { // line continuation + addToString(yytext); + incLineNr(); + } + \\. { // espaced char + addToString(yytext); + } + "'''" { // tripple single quotes + addToString(yytext); + } + "\"" { // end of the string + addToString(yytext); + BEGIN(g_stringContext); + } + [^"'\n\\]+ { // normal chars + addToString(yytext); + } + . { // normal char + addToString(yytext); + } +} + +{ + {TRIDOUBLEQUOTE} | + {TRISINGLEQUOTE} { + *g_copyString += yytext; + if (g_doubleQuote==(yytext[0]=='"')) + { + BEGIN(g_stringContext); + } + } + + + ({LONGSTRINGBLOCK}) { + lineCount(); + *g_copyString += yytext; + } + \n { + incLineNr(); + *g_copyString += yytext; + } + . { + *g_copyString += *yytext; + } +} + + /* ------------ End rules -------------- */ + + /* +<*>({NONEMPTY}|{EXPCHAR}|{BB}) { // This should go one character at a time. + // printf("[pyscanner] '%s' [ state %d ] [line %d] no match\n", + // yytext, YY_START, yyLineNr); + + } + */ + +<*>{NEWLINE} { + //printf("[pyscanner] %d NEWLINE [line %d] no match\n", + // YY_START, yyLineNr); + + lineCount(); + } + +<*>. { + //printf("[pyscanner] '%s' [ state %d ] [line %d] no match\n", + // yytext, YY_START, yyLineNr); + + } + + +%% + +//---------------------------------------------------------------------------- + +static void parseCompounds(Entry *rt) +{ + //printf("parseCompounds(%s)\n",rt->name.data()); + EntryListIterator eli(*rt->children()); + Entry *ce; + for (;(ce=eli.current());++eli) + { + if (!ce->program.isEmpty()) + { + //printf("-- %s ---------\n%s\n---------------\n", + // ce->name.data(),ce->program.data()); + // init scanner state + inputString = ce->program; + inputPosition = 0; + pyscanYYrestart( pyscanYYin ) ; + if (ce->section&Entry::COMPOUND_MASK) + { + current_root = ce ; + BEGIN( Search ); + } + else if (ce->parent()) + { + current_root = ce->parent(); + //printf("Searching for member variables in %s parent=%s\n", + // ce->name.data(),ce->parent->name.data()); + BEGIN( SearchMemVars ); + } + yyFileName = ce->fileName; + yyLineNr = ce->bodyLine ; + if (current) delete current; + current = new Entry; + initEntry(); + + groupEnterCompound(yyFileName,yyLineNr,ce->name); + + pyscanYYlex() ; + g_lexInit=TRUE; + delete current; current=0; + ce->program.resize(0); + + groupLeaveCompound(yyFileName,yyLineNr,ce->name); + + } + parseCompounds(ce); + } +} + +//---------------------------------------------------------------------------- + + +static void parseMain(const char *fileName,const char *fileBuf,Entry *rt) +{ + initParser(); + + inputString = fileBuf; + inputPosition = 0; + + protection = Public; + mtype = Method; + gstat = FALSE; + virt = Normal; + current_root = rt; + g_specialBlock = FALSE; + + + inputFile.setName(fileName); + if (inputFile.open(IO_ReadOnly)) + { + yyLineNr= 1 ; + yyFileName = fileName; + //setContext(); + msg("Parsing file %s...\n",yyFileName.data()); + + QFileInfo fi(fileName); + g_moduleScope = findPackageScope(fileName); + QString baseName=fi.baseName(); + if (baseName!="__init__") // package initializer file is not a package itself + { + if (!g_moduleScope.isEmpty()) + { + g_moduleScope+="::"; + } + g_moduleScope+=baseName; + } + + current = new Entry; + initEntry(); + current->name = g_moduleScope; + current->section = Entry::NAMESPACE_SEC; + current->type = "namespace"; + current->fileName = yyFileName; + current->startLine = yyLineNr; + current->bodyLine = yyLineNr; + + rt->addSubEntry(current); + + current_root = current ; + initParser(); + current = new Entry; + + groupEnterFile(yyFileName,yyLineNr); + + current->reset(); + initEntry(); + pyscanYYrestart( pyscanYYin ); + BEGIN( Search ); + pyscanYYlex(); + g_lexInit=TRUE; + + groupLeaveFile(yyFileName,yyLineNr); + + current_root->program.resize(0); + delete current; current=0; + + parseCompounds(current_root); + + inputFile.close(); + } + +} + +//---------------------------------------------------------------------------- + +static void parsePrototype(const QCString &text) +{ + //printf("**** parsePrototype(%s) begin\n",text.data()); + if (text.isEmpty()) + { + warn(yyFileName,yyLineNr,"Empty prototype found!"); + return; + } + + g_specialBlock = FALSE; + g_packageCommentAllowed = FALSE; + + const char *orgInputString; + int orgInputPosition; + YY_BUFFER_STATE orgState; + + // save scanner state + orgState = YY_CURRENT_BUFFER; + yy_switch_to_buffer(yy_create_buffer(pyscanYYin, YY_BUF_SIZE)); + orgInputString = inputString; + orgInputPosition = inputPosition; + + // set new string + inputString = text; + inputPosition = 0; + pyscanYYrestart( pyscanYYin ); + + BEGIN( FunctionDec ); + + pyscanYYlex(); + g_lexInit=TRUE; + + current->name = current->name.stripWhiteSpace(); + if (current->section == Entry::MEMBERDOC_SEC && current->args.isEmpty()) + current->section = Entry::VARIABLEDOC_SEC; + + // restore original scanner state + + YY_BUFFER_STATE tmpBuf = YY_CURRENT_BUFFER; + yy_switch_to_buffer(orgState); + yy_delete_buffer(tmpBuf); + + inputString = orgInputString; + inputPosition = orgInputPosition; + + //printf("**** parsePrototype end\n"); +} + +void pyscanFreeScanner() +{ +#if defined(YY_FLEX_SUBMINOR_VERSION) + if (g_lexInit) + { + pyscanYYlex_destroy(); + } +#endif +} + +//---------------------------------------------------------------------------- + +void PythonLanguageScanner::parseInput(const char *fileName,const char *fileBuf,Entry *root) +{ + g_thisParser = this; + ::parseMain(fileName,fileBuf,root); + + // May print the AST for debugging purposes + // printAST(global_root); +} + +bool PythonLanguageScanner::needsPreprocessing(const QCString &) +{ + return FALSE; +} + +void PythonLanguageScanner::parseCode(CodeOutputInterface &codeOutIntf, + const char *scopeName, + const QCString &input, + bool isExampleBlock, + const char *exampleName, + FileDef *fileDef, + int startLine, + int endLine, + bool inlineFragment, + MemberDef *memberDef, + bool showLineNumbers + ) +{ + ::parsePythonCode(codeOutIntf,scopeName,input,isExampleBlock,exampleName, + fileDef,startLine,endLine,inlineFragment,memberDef, + showLineNumbers); +} + +void PythonLanguageScanner::parsePrototype(const char *text) +{ + ::parsePrototype(text); + +} + +void PythonLanguageScanner::resetCodeParserState() +{ + ::resetPythonCodeParserState(); +} + +//---------------------------------------------------------------------------- + +#if !defined(YY_FLEX_SUBMINOR_VERSION) +//---------------------------------------------------------------------------- +extern "C" { // some bogus code to keep the compiler happy + void pyscannerYYdummy() { yy_flex_realloc(0,0); } +} +#endif + diff --git a/trunk/src/qhp.cpp b/trunk/src/qhp.cpp new file mode 100644 index 0000000..bba308a --- /dev/null +++ b/trunk/src/qhp.cpp @@ -0,0 +1,340 @@ +/* + * Copyright (C) 2008 by Sebastian Pipping. + * Copyright (C) 2008 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. + * + * Sebastian Pipping + */ + +#include "qhp.h" +#include "qhpxmlwriter.h" +#include "message.h" +#include "config.h" +#include "memberdef.h" +#include "groupdef.h" +#include "filedef.h" + +#include +#include + +static QCString makeFileName(const char * withoutExtension) +{ + if (!withoutExtension) return QCString(); + return QCString(withoutExtension)+".html"; +} + +static QCString makeRef(const char * withoutExtension, const char * anchor) +{ + //printf("QHP::makeRef(%s,%s)\n",withoutExtension,anchor); + if (!withoutExtension) return QCString(); + QCString result = makeFileName(withoutExtension); + if (!anchor) return result; + return result+"#"+anchor; +} + +Qhp::Qhp() : m_prevSectionLevel(0), m_sectionLevel(0) +{ + m_doc.setIndentLevel(0); + m_toc.setIndentLevel(2); + m_index.setIndentLevel(2); + m_files.setIndentLevel(2); +} + +Qhp::~Qhp() +{ + clearPrevSection(); +} + +void Qhp::initialize() +{ + /* + + mycompany.com.myapplication.1_0 + doc + + myapp + 1.0 + + + myapp + 1.0 + .. + */ + QCString nameSpace = Config_getString("QHP_NAMESPACE"); + QCString virtualFolder = Config_getString("QHP_VIRTUAL_FOLDER"); + + const char * rootAttributes[] = + { "version", "1.0", 0 }; + + m_doc.open("QtHelpProject", rootAttributes); + m_doc.openCloseContent("namespace", nameSpace); + m_doc.openCloseContent("virtualFolder", virtualFolder); + + // Add custom filter + QCString filterName = Config_getString("QHP_CUST_FILTER_NAME"); + if (!filterName.isEmpty()) + { + const char * tagAttributes[] = + { "name", filterName, 0 }; + m_doc.open("customFilter", tagAttributes); + + QStringList customFilterAttributes = QStringList::split(QChar(' '), Config_getString("QHP_CUST_FILTER_ATTRS")); + for (int i = 0; i < (int)customFilterAttributes.count(); i++) + { + m_doc.openCloseContent("filterAttribute", customFilterAttributes[i]); + } + m_doc.close("customFilter"); + } + + m_doc.open("filterSection"); + + // Add section attributes + QStringList sectionFilterAttributes = QStringList::split(QChar(' '), + Config_getString("QHP_SECT_FILTER_ATTRS")); + if (!sectionFilterAttributes.contains(QString("doxygen"))) + { + sectionFilterAttributes << "doxygen"; + } + for (int i = 0; i < (int)sectionFilterAttributes.count(); i++) + { + m_doc.openCloseContent("filterAttribute", sectionFilterAttributes[i]); + } + + m_toc.open("toc"); + + // Add extra root node + QCString fullProjectname = getFullProjectName(); + const char * const attributes[] = + { "title", fullProjectname, + "ref", "index.html", + NULL + }; + m_toc.open("section", attributes); + m_prevSectionLevel = 1; + m_sectionLevel = 1; + + m_index.open("keywords"); + m_files.open("files"); +} + +void Qhp::finalize() +{ + // Finish TOC + handlePrevSection(); + for (int i = m_prevSectionLevel; i > 0; i--) + { + m_toc.close("section"); + } + m_toc.close("toc"); + m_doc.insert(m_toc); + + // Finish index + m_index.close("keywords"); + m_doc.insert(m_index); + + // Finish files + m_files.close("files"); + m_doc.insert(m_files); + + m_doc.close("filterSection"); + m_doc.close("QtHelpProject"); + + QCString fileName = Config_getString("HTML_OUTPUT") + "/" + getQhpFileName(); + QFile file(fileName); + if (!file.open(IO_WriteOnly)) + { + err("Could not open file %s for writing\n", fileName.data()); + exit(1); + } + m_doc.dumpTo(file); +} + +void Qhp::incContentsDepth() +{ + m_sectionLevel++; +} + +void Qhp::decContentsDepth() +{ + if (m_sectionLevel <= 0) + { + return; + } + m_sectionLevel--; +} + +void Qhp::addContentsItem(bool /*isDir*/, const char * name, + const char * /*ref*/, const char * file, + const char * /*anchor*/,bool /* separateIndex */, + bool /* addToNavIndex */) +{ + // Backup difference before modification + int diff = m_prevSectionLevel - m_sectionLevel; + + handlePrevSection(); + setPrevSection(name, file, m_sectionLevel); + + // Close sections as needed + for (; diff > 0; diff--) + { + m_toc.close("section"); + } +} + +void Qhp::addIndexItem(Definition *context,MemberDef *md, + const char *word) +{ + (void)word; + //printf("addIndexItem(%s %s %s\n", + // context?context->name().data():"", + // md?md->name().data():"", + // word); + + if (md) // member + { + static bool separateMemberPages = Config_getBool("SEPARATE_MEMBER_PAGES"); + if (context==0) // global member + { + if (md->getGroupDef()) + context = md->getGroupDef(); + else if (md->getFileDef()) + context = md->getFileDef(); + } + if (context==0) return; // should not happen + QCString cfname = md->getOutputFileBase(); + QCString cfiname = context->getOutputFileBase(); + QCString level1 = context->name(); + QCString level2 = word ? QCString(word) : md->name(); + QCString contRef = separateMemberPages ? cfname : cfiname; + QCString anchor = md->anchor(); + + QCString ref; + + // + ref = makeRef(contRef, anchor); + QCString id = level1+"::"+level2; + const char * attributes[] = + { + "name", level2, + "id", id, + "ref", ref, + 0 + }; + m_index.openClose("keyword", attributes); + } + else if (context) // container + { + // + QCString contRef = context->getOutputFileBase(); + QCString level1 = word ? QCString(word) : context->name(); + QCString ref = makeFileName(contRef); + const char * attributes[] = + { + "name", level1, + "id", level1, + "ref", ref, + 0 + }; + m_index.openClose("keyword", attributes); + } +} + +void Qhp::addIndexFile(const char * name) +{ + addFile(name); +} + +QCString Qhp::getQhpFileName() +{ + return "index.qhp"; +} + +QCString Qhp::getFullProjectName() +{ + QCString projectName = Config_getString("PROJECT_NAME"); + QCString versionText = Config_getString("PROJECT_NUMBER"); + if (projectName.isEmpty()) projectName="Root"; + return projectName + (versionText.isEmpty() + ? QCString("") + : QCString(" ") + versionText); +} + +void Qhp::handlePrevSection() +{ + /* + +
    +
    +
    +
    +
    + + */ + + if (m_prevSectionTitle.isNull()) + { + return; + } + + // We skip "Main Page" as our extra root is pointing to that + if (!((m_prevSectionLevel==1) && (m_prevSectionTitle=="Main Page"))) + { + QCString finalRef = makeFileName(m_prevSectionRef); + + const char * const attributes[] = + { "title", m_prevSectionTitle, + "ref", finalRef, + NULL + }; + + if (m_prevSectionLevel < m_sectionLevel) + { + // Section with children + m_toc.open("section", attributes); + } + else + { + // Section without children + m_toc.openClose("section", attributes); + } + } + + clearPrevSection(); +} + +void Qhp::setPrevSection(const char * title, const char * ref, int level) +{ + m_prevSectionTitle = title; + m_prevSectionRef = ref; + m_prevSectionLevel = level; +} + +void Qhp::clearPrevSection() +{ + m_prevSectionTitle.resize(0); + m_prevSectionRef.resize(0); +} + +void Qhp::addFile(const char * fileName) +{ + m_files.openCloseContent("file", fileName); +} + +void Qhp::addImageFile(const char *fileName) +{ + addFile(fileName); +} + +void Qhp::addStyleSheetFile(const char *fileName) +{ + addFile(fileName); +} + diff --git a/trunk/src/qhp.h b/trunk/src/qhp.h new file mode 100644 index 0000000..8185803 --- /dev/null +++ b/trunk/src/qhp.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2008 by Sebastian Pipping. + * Copyright (C) 2008 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. + * + * Sebastian Pipping + */ + +#ifndef DOXYGEN_QHP_H +#define DOXYGEN_QHP_H + +#include "index.h" +#include "qhpxmlwriter.h" + +class Qhp : public IndexIntf +{ + public: + Qhp(); + ~Qhp(); + + // BEGIN IndexIntf + void initialize(); + void finalize(); + void incContentsDepth(); + void decContentsDepth(); + void addContentsItem(bool isDir, const char * name, const char * ref, + const char * file, const char * anchor, + bool separateIndex,bool addToNavIndex); + void addIndexItem(Definition *context,MemberDef *md,const char *title); + void addIndexFile(const char * name); + void addImageFile(const char * name); + void addStyleSheetFile(const char * name); + // END IndexIntf + + static QCString getQhpFileName(); + + private: + void handlePrevSection(); + void clearPrevSection(); + void setPrevSection(const char * title, const char * ref, int level); + void addFile(const char * fileName); + + static QCString getFullProjectName(); + + QhpXmlWriter m_doc; + QhpXmlWriter m_toc; + QhpXmlWriter m_index; + QhpXmlWriter m_files; + + QCString m_prevSectionTitle; + QCString m_prevSectionRef; + + int m_prevSectionLevel; + int m_sectionLevel; + + //QCString m_prevIdName; + //QCString m_prevIdRef; +}; + +#endif // DOXYGEN_QHP_H + diff --git a/trunk/src/qhpxmlwriter.cpp b/trunk/src/qhpxmlwriter.cpp new file mode 100644 index 0000000..93bb8cd --- /dev/null +++ b/trunk/src/qhpxmlwriter.cpp @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2008 by Sebastian Pipping. + * Copyright (C) 2008 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. + * + * Sebastian Pipping + */ + +#include "qhpxmlwriter.h" +#include "util.h" + +#include + +QhpXmlWriter::QhpXmlWriter() + : m_out(&m_backend), m_indentLevel(0), + m_curLineIndented(false), m_compress(false) +{ +} + +QhpXmlWriter::~QhpXmlWriter() +{ +} + +void QhpXmlWriter::setIndentLevel(int level) +{ + m_indentLevel = level; +} + +void QhpXmlWriter::setCompressionEnabled(bool enabled) +{ + m_compress = enabled; +} + +void QhpXmlWriter::insert(QhpXmlWriter const & source) +{ + m_out << source.m_backend.data(); +} + +void QhpXmlWriter::dumpTo(QFile & file) +{ + file.writeBlock(m_backend.data(), m_backend.length()); +} + +void QhpXmlWriter::open(char const * elementName, + char const * const * attributes) +{ + indent(); + openPure(elementName, attributes); + newLine(); + m_indentLevel++; +} + +void QhpXmlWriter::openClose(char const * elementName, + char const * const * attributes) +{ + indent(); + openClosePure(elementName, attributes); + newLine(); +} + +void QhpXmlWriter::openCloseContent(char const * elementName, + char const * content) +{ + indent(); + openPure(elementName); + m_out << convertToXML(content); + closePure(elementName); + newLine(); +} + +void QhpXmlWriter::close(char const * elementName) +{ + m_indentLevel--; + indent(); + closePure(elementName); + newLine(); +} + +void QhpXmlWriter::indent() +{ + if (m_curLineIndented) + { + return; + } + for (int i = 0; i < m_indentLevel; i++) + { + m_out << " "; + } + m_curLineIndented = true; +} + +void QhpXmlWriter::newLine() +{ + if (!m_compress) + { + m_out << "\n"; + m_curLineIndented = false; + } +} + +void QhpXmlWriter::openPureHelper(char const * elementName, + char const * const * attributes, bool close) +{ + m_out << "<" << elementName; + if (attributes) + { + for (char const * const * walker = attributes; + walker[0]; walker += 2) + { + char const * const key = walker[0]; + char const * const value = walker[1]; + if (!value) + { + continue; + } + m_out << " " << key << "=\"" << convertToXML(value) << "\""; + } + } + + if (close) + { + m_out << " /"; + } + m_out << ">"; +} + +void QhpXmlWriter::openPure(char const * elementName, + char const * const * attributes) +{ + openPureHelper(elementName, attributes, false); +} + +void QhpXmlWriter::openClosePure(char const * elementName, + char const * const * attributes) +{ + openPureHelper(elementName, attributes, true); +} + +void QhpXmlWriter::closePure(char const * elementName) +{ + m_out << ""; +} + diff --git a/trunk/src/qhpxmlwriter.h b/trunk/src/qhpxmlwriter.h new file mode 100644 index 0000000..c88eebd --- /dev/null +++ b/trunk/src/qhpxmlwriter.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2008 by Sebastian Pipping. + * Copyright (C) 2008 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. + * + * Sebastian Pipping + */ + +#ifndef QHPXMLWRITER_H +#define QHPXMLWRITER_H + +#include +#include "ftextstream.h" + +class QFile; + +class QhpXmlWriter +{ + public: + QhpXmlWriter(); + ~QhpXmlWriter(); + + void setIndentLevel(int level); + void setCompressionEnabled(bool enabled); + void insert(QhpXmlWriter const & source); + void dumpTo(QFile & file); + void open(char const * elementName, + char const * const * attributes = 0); + void openClose(char const * elementName, + char const * const * attributes = 0); + void openCloseContent(char const * elementName, char const * content); + void close(char const * elementName); + + static char * dupEscaped(const char * source); + + private: + void indent(); + void newLine(); + void openPureHelper(char const * elementName, + char const * const * attributes, bool close); + void openPure(char const * elementName, + char const * const * attributes = 0); + void openClosePure(char const * elementName, + char const * const * attributes = 0); + void closePure(char const * elementName); + + QGString m_backend; + FTextStream m_out; + int m_indentLevel; + bool m_curLineIndented; + bool m_compress; + +}; + +#endif // QHPXMLWRITER_H diff --git a/trunk/src/qtbc.h b/trunk/src/qtbc.h new file mode 100644 index 0000000..5c3ceef --- /dev/null +++ b/trunk/src/qtbc.h @@ -0,0 +1,45 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#ifndef QTBC_H +#define QTBC_H + +/*! This file contains some hacks to make Doxygen work with + * Qt version 2.00 and Qt version 1.xx + */ + +#include + +#if QT_VERSION >= 200 + +#include + +#define GCI QCollection::Item + +#include +#include +inline QCString convertToQCString(const QString &s) { return s.utf8(); } + +#else /* QT_VERSION < 200 */ + +#include +#define QCString QString +inline QCString convertToQCString(const QCString &s) { return s; } + +#endif + +#endif diff --git a/trunk/src/reflist.cpp b/trunk/src/reflist.cpp new file mode 100644 index 0000000..8f103d7 --- /dev/null +++ b/trunk/src/reflist.cpp @@ -0,0 +1,171 @@ +/****************************************************************************** + * + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#include +#include "reflist.h" +#include "util.h" +#include "ftextstream.h" + +/*! Create a list of items that are cross referenced with documentation blocks + * @param listName String representing the name of the list. + * @param pageTitle String representing the title of the list page. + * @param secTitle String representing the title of the section. + */ +RefList::RefList(const char *listName, + const char *pageTitle, + const char *secTitle + ) +{ + m_itemList = 0; + m_dict = 0; + m_dictIterator = 0; + m_id = 0; + m_listName = listName; + m_pageTitle = pageTitle; + m_secTitle = secTitle; +} + +/*! Destroy the todo list. Currently not called! */ +RefList::~RefList() +{ + delete m_dictIterator; + delete m_dict; + delete m_itemList; +} + +/*! Adds a new item to the list. + * \returns A unique id for this item. + */ +int RefList::addRefItem() +{ + if (m_dict==0) + { + m_dict = new QIntDict(1009); + m_dict->setAutoDelete(TRUE); + m_dictIterator = new QIntDictIterator(*m_dict); + } + RefItem *item = new RefItem; + m_id++; + m_dict->insert(m_id,item); + return m_id; +} + +/*! Returns an item given it's id that is obtained with addRefItem() + * \param itemId item's identifier. + * \returns A pointer to the todo item's structure. + */ +RefItem *RefList::getRefItem(int itemId) +{ + return m_dict ? m_dict->find(itemId) : 0; +} + +/*! Returns the first item in the dictionary or 0 if + * non is available. + * Items are not sorted. + */ +RefItem *RefList::getFirstRefItem() +{ + return m_dictIterator ? m_dictIterator->toFirst() : 0; +} + +/*! Returns the next item in the dictionary or 0 if + * we are at the end of the list. + * Items are not sorted. + */ +RefItem *RefList::getNextRefItem() +{ + return m_dictIterator ? m_dictIterator->operator++() : 0; +} + +/*! Returns the name of the list as set in the constructor. */ +QCString RefList::listName() const +{ + return m_listName; +} + +QCString RefList::pageTitle() const +{ + return m_pageTitle; +} + +QCString RefList::sectionTitle() const +{ + return m_secTitle; +} + +void RefList::insertIntoList(const char *key,RefItem *item) +{ + if (m_itemList==0) + { + m_itemList = new SortedRefItems(1009); + } + RefItem *ri = m_itemList->find(key); + if (ri==0) + { + m_itemList->append(key,item); + } + else // item already added to the list (i.e. multiple item for the same + // entity) + { + if (ri!=item) + { + ri->extraItems.append(item); + } + } +} + + +void RefList::generatePage() +{ + if (m_itemList==0) return; + m_itemList->sort(); + SDict::Iterator it(*m_itemList); + RefItem *item; + QCString doc; + doc += "
    "; + for (it.toFirst();(item=it.current());++it) + { + doc += "
    "; + doc += "\\anchor "; + doc += item->listAnchor; + doc += "\n"; + doc += item->prefix; + doc += " \\_internalref "; + doc += item->name; + doc += " \""; + doc += item->title; + doc += "\" "; + // write declaration in case a function with arguments + if (!item->args.isEmpty()) + { + doc += item->args; + } + doc += "
    "; + doc += item->text; + QListIterator li(item->extraItems); + RefItem *extraItem; + for (li.toFirst();(extraItem=li.current());++li) + { + doc += "

    " + extraItem->text; + } + doc += "

    "; + } + doc += "
    \n"; + addRelatedPage(m_listName,m_pageTitle,doc,0,m_listName,1,0,0,0); +} + diff --git a/trunk/src/reflist.h b/trunk/src/reflist.h new file mode 100644 index 0000000..90c95c8 --- /dev/null +++ b/trunk/src/reflist.h @@ -0,0 +1,94 @@ +/****************************************************************************** + * + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#ifndef _REFLIST_H +#define _REFLIST_H + +#include "qtbc.h" +#include +#include +#include "sortdict.h" + +/*! This struct represents an item in the list of references. */ +struct RefItem +{ + RefItem() /*: written(FALSE)*/ {} + QCString text; //!< text of the item. + QCString listAnchor; //!< anchor in the list + + QCString prefix; //!< type prefix for the name + QCString name; //!< name of the entity containing the reference + QCString title; //!< display name of the entity + QCString args; //!< optional arguments for the entity (if function) + //bool written; + QList extraItems; //!< more items belonging to the same entity +}; + +/*! List of items sorted by title */ +class SortedRefItems : public SDict +{ + public: + SortedRefItems(int size=17) : SDict(size) {} + virtual ~SortedRefItems() {} + int compareItems(GCI item1,GCI item2) + { + RefItem *r1 = (RefItem*)item1; + RefItem *r2 = (RefItem*)item2; + return stricmp(r1->title,r2->title); + } +}; + +/*! @brief List of cross-referenced items + * + * This class represents a list of items that are put + * at a certain point in the documentation by some special command + * and are collected in a list. The items cross-reference the + * documentation and the list. + * + * Examples are the todo list, the test list and the bug list, + * introduced by the \\todo, \\test, and \\bug commands respectively. + */ +class RefList +{ + public: + int addRefItem(); + RefItem *getRefItem(int todoItemId); + RefItem *getFirstRefItem(); + RefItem *getNextRefItem(); + QCString listName() const; + QCString pageTitle() const; + QCString sectionTitle() const; + + RefList(const char *listName, + const char *pageTitle,const char *secTitle + ); + ~RefList(); + void insertIntoList(const char *key,RefItem *item); + void generatePage(); + + private: + int m_id; + QCString m_listName; + QCString m_pageTitle; + QCString m_secTitle; + SortedRefItems *m_itemList; + QIntDict *m_dict; + QIntDictIterator *m_dictIterator; +}; + +#endif diff --git a/trunk/src/resize.js b/trunk/src/resize.js new file mode 100644 index 0000000..04fa95c --- /dev/null +++ b/trunk/src/resize.js @@ -0,0 +1,81 @@ +var cookie_namespace = 'doxygen'; +var sidenav,navtree,content,header; + +function readCookie(cookie) +{ + var myCookie = cookie_namespace+"_"+cookie+"="; + if (document.cookie) + { + var index = document.cookie.indexOf(myCookie); + if (index != -1) + { + var valStart = index + myCookie.length; + var valEnd = document.cookie.indexOf(";", valStart); + if (valEnd == -1) + { + valEnd = document.cookie.length; + } + var val = document.cookie.substring(valStart, valEnd); + return val; + } + } + return 0; +} + +function writeCookie(cookie, val, expiration) +{ + if (val==undefined) return; + if (expiration == null) + { + var date = new Date(); + date.setTime(date.getTime()+(10*365*24*60*60*1000)); // default expiration is one week + expiration = date.toGMTString(); + } + document.cookie = cookie_namespace + "_" + cookie + "=" + val + "; expires=" + expiration+"; path=/"; +} + +function resizeWidth() +{ + var windowWidth = $(window).width() + "px"; + var sidenavWidth = $(sidenav).width(); + content.css({marginLeft:parseInt(sidenavWidth)+6+"px"}); //account for 6px-wide handle-bar + writeCookie('width',sidenavWidth, null); +} + +function restoreWidth(navWidth) +{ + var windowWidth = $(window).width() + "px"; + content.css({marginLeft:parseInt(navWidth)+6+"px"}); + sidenav.css({width:navWidth + "px"}); +} + +function resizeHeight() +{ + var headerHeight = header.height(); + var footerHeight = footer.height(); + var windowHeight = $(window).height() - headerHeight - footerHeight; + content.css({height:windowHeight + "px"}); + navtree.css({height:windowHeight + "px"}); + sidenav.css({height:windowHeight + "px",top: headerHeight+"px"}); +} + +function initResizable() +{ + header = $("#top"); + sidenav = $("#side-nav"); + content = $("#doc-content"); + navtree = $("#nav-tree"); + footer = $("#nav-path"); + $(".side-nav-resizable").resizable({resize: function(e, ui) { resizeWidth(); } }); + $(window).resize(function() { resizeHeight(); }); + var width = readCookie('width'); + if (width) { restoreWidth(width); } else { resizeWidth(); } + resizeHeight(); + var url = location.href; + var i=url.indexOf("#"); + if (i>=0) window.location.hash=url.substr(i); + var _preventDefault = function(evt) { evt.preventDefault(); }; + $("#splitbar").bind("dragstart", _preventDefault).bind("selectstart", _preventDefault); +} + + diff --git a/trunk/src/resize_js.h b/trunk/src/resize_js.h new file mode 100644 index 0000000..7e627cc --- /dev/null +++ b/trunk/src/resize_js.h @@ -0,0 +1,81 @@ +"var cookie_namespace = 'doxygen'; \n" +"var sidenav,navtree,content,header;\n" +"\n" +"function readCookie(cookie) \n" +"{\n" +" var myCookie = cookie_namespace+\"_\"+cookie+\"=\";\n" +" if (document.cookie) \n" +" {\n" +" var index = document.cookie.indexOf(myCookie);\n" +" if (index != -1) \n" +" {\n" +" var valStart = index + myCookie.length;\n" +" var valEnd = document.cookie.indexOf(\";\", valStart);\n" +" if (valEnd == -1) \n" +" {\n" +" valEnd = document.cookie.length;\n" +" }\n" +" var val = document.cookie.substring(valStart, valEnd);\n" +" return val;\n" +" }\n" +" }\n" +" return 0;\n" +"}\n" +"\n" +"function writeCookie(cookie, val, expiration) \n" +"{\n" +" if (val==undefined) return;\n" +" if (expiration == null) \n" +" {\n" +" var date = new Date();\n" +" date.setTime(date.getTime()+(10*365*24*60*60*1000)); // default expiration is one week\n" +" expiration = date.toGMTString();\n" +" }\n" +" document.cookie = cookie_namespace + \"_\" + cookie + \"=\" + val + \"; expires=\" + expiration+\"; path=/\";\n" +"}\n" +" \n" +"function resizeWidth() \n" +"{\n" +" var windowWidth = $(window).width() + \"px\";\n" +" var sidenavWidth = $(sidenav).width();\n" +" content.css({marginLeft:parseInt(sidenavWidth)+6+\"px\"}); //account for 6px-wide handle-bar\n" +" writeCookie('width',sidenavWidth, null);\n" +"}\n" +"\n" +"function restoreWidth(navWidth)\n" +"{\n" +" var windowWidth = $(window).width() + \"px\";\n" +" content.css({marginLeft:parseInt(navWidth)+6+\"px\"});\n" +" sidenav.css({width:navWidth + \"px\"});\n" +"}\n" +"\n" +"function resizeHeight() \n" +"{\n" +" var headerHeight = header.height();\n" +" var footerHeight = footer.height();\n" +" var windowHeight = $(window).height() - headerHeight - footerHeight;\n" +" content.css({height:windowHeight + \"px\"});\n" +" navtree.css({height:windowHeight + \"px\"});\n" +" sidenav.css({height:windowHeight + \"px\",top: headerHeight+\"px\"});\n" +"}\n" +"\n" +"function initResizable()\n" +"{\n" +" header = $(\"#top\");\n" +" sidenav = $(\"#side-nav\");\n" +" content = $(\"#doc-content\");\n" +" navtree = $(\"#nav-tree\");\n" +" footer = $(\"#nav-path\");\n" +" $(\".side-nav-resizable\").resizable({resize: function(e, ui) { resizeWidth(); } });\n" +" $(window).resize(function() { resizeHeight(); });\n" +" var width = readCookie('width');\n" +" if (width) { restoreWidth(width); } else { resizeWidth(); }\n" +" resizeHeight();\n" +" var url = location.href;\n" +" var i=url.indexOf(\"#\");\n" +" if (i>=0) window.location.hash=url.substr(i);\n" +" var _preventDefault = function(evt) { evt.preventDefault(); };\n" +" $(\"#splitbar\").bind(\"dragstart\", _preventDefault).bind(\"selectstart\", _preventDefault);\n" +"}\n" +"\n" +"\n" diff --git a/trunk/src/rtfdocvisitor.cpp b/trunk/src/rtfdocvisitor.cpp new file mode 100644 index 0000000..4cde286 --- /dev/null +++ b/trunk/src/rtfdocvisitor.cpp @@ -0,0 +1,1750 @@ +/****************************************************************************** + * + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#include "rtfdocvisitor.h" +#include "docparser.h" +#include "language.h" +#include "doxygen.h" +#include "outputgen.h" +#include "dot.h" +#include "msc.h" +#include "util.h" +#include "rtfstyle.h" +#include "message.h" +#include +#include "parserintf.h" +#include "msc.h" + + +//#define DBG_RTF(x) m_t << x +#define DBG_RTF(x) do {} while(0) + +static QCString align(DocHtmlCell *cell) +{ + HtmlAttribList attrs = cell->attribs(); + uint i; + for (i=0; iname.lower()=="align") + { + if (attrs.at(i)->value.lower()=="center") + return "\\qc "; + else if (attrs.at(i)->value.lower()=="right") + return "\\qr "; + else return ""; + } + } + return ""; +} + +RTFDocVisitor::RTFDocVisitor(FTextStream &t,CodeOutputInterface &ci, + const char *langExt) + : DocVisitor(DocVisitor_RTF), m_t(t), m_ci(ci), m_insidePre(FALSE), + m_hide(FALSE), m_indentLevel(0), m_lastIsPara(FALSE), m_langExt(langExt) +{ +} + +QCString RTFDocVisitor::getStyle(const char *name) +{ + QCString n; + n.sprintf("%s%d",name,m_indentLevel); + StyleData *sd = rtf_Style[n]; + ASSERT(sd!=0); + return sd->reference; +} + +void RTFDocVisitor::incIndentLevel() +{ + if (m_indentLevel0) m_indentLevel--; +} + + //-------------------------------------- + // visitor functions for leaf nodes + //-------------------------------------- + +void RTFDocVisitor::visit(DocWord *w) +{ + if (m_hide) return; + DBG_RTF("{\\comment RTFDocVisitor::visit(DocWord)}\n"); + filter(w->word()); + m_lastIsPara=FALSE; +} + +void RTFDocVisitor::visit(DocLinkedWord *w) +{ + if (m_hide) return; + DBG_RTF("{\\comment RTFDocVisitor::visit(DocLinkedWord)}\n"); + startLink(w->ref(),w->file(),w->anchor()); + filter(w->word()); + endLink(w->ref()); + m_lastIsPara=FALSE; +} + +void RTFDocVisitor::visit(DocWhiteSpace *w) +{ + if (m_hide) return; + DBG_RTF("{\\comment RTFDocVisitor::visit(DocWhiteSpace)}\n"); + if (m_insidePre) + { + m_t << w->chars(); + } + else + { + m_t << " "; + } + m_lastIsPara=FALSE; +} + +void RTFDocVisitor::visit(DocSymbol *s) +{ + if (m_hide) return; + DBG_RTF("{\\comment RTFDocVisitor::visit(DocSymbol)}\n"); + switch(s->symbol()) + { + case DocSymbol::BSlash: m_t << "\\\\"; break; + case DocSymbol::At: m_t << "@"; break; + case DocSymbol::Less: m_t << "<"; break; + case DocSymbol::Greater: m_t << ">"; break; + case DocSymbol::Amp: m_t << "&"; break; + case DocSymbol::Dollar: m_t << "$"; break; + case DocSymbol::Hash: m_t << "#"; break; + case DocSymbol::DoubleColon: m_t << "::"; break; + case DocSymbol::Percent: m_t << "%"; break; + case DocSymbol::Copy: m_t << "(C)"; break; + case DocSymbol::Tm: m_t << "(TM)"; break; + case DocSymbol::Reg: m_t << "(R)"; break; + case DocSymbol::Apos: m_t << "'"; break; + case DocSymbol::Quot: m_t << "\""; break; + case DocSymbol::Lsquo: m_t << "`"; break; + case DocSymbol::Rsquo: m_t << "'"; break; + case DocSymbol::Ldquo: m_t << "\""; break; + case DocSymbol::Rdquo: m_t << "\""; break; + case DocSymbol::Ndash: m_t << "-"; break; + case DocSymbol::Mdash: m_t << "--"; break; + case DocSymbol::Uml: switch(s->letter()) + { + case 'A' : m_t << '\304'; break; + case 'E' : m_t << '\313'; break; + case 'I' : m_t << '\317'; break; + case 'O' : m_t << '\326'; break; + case 'U' : m_t << '\334'; break; + case 'Y' : m_t << 'Y'; break; + case 'a' : m_t << '\344'; break; + case 'e' : m_t << '\353'; break; + case 'i' : m_t << '\357'; break; + case 'o' : m_t << '\366'; break; + case 'u' : m_t << '\374'; break; + case 'y' : m_t << '\377'; break; + default: m_t << '?'; break; + } + break; + case DocSymbol::Acute: switch(s->letter()) + { + case 'A' : m_t << '\301'; break; + case 'E' : m_t << '\311'; break; + case 'I' : m_t << '\315'; break; + case 'O' : m_t << '\323'; break; + case 'U' : m_t << '\332'; break; + case 'Y' : m_t << '\335'; break; + case 'a' : m_t << '\341'; break; + case 'e' : m_t << '\351'; break; + case 'i' : m_t << '\355'; break; + case 'o' : m_t << '\363'; break; + case 'u' : m_t << '\372'; break; + case 'y' : m_t << '\375'; break; + default: m_t << '?'; break; + } + break; + case DocSymbol::Grave: switch(s->letter()) + { + case 'A' : m_t << '\300'; break; + case 'E' : m_t << '\310'; break; + case 'I' : m_t << '\314'; break; + case 'O' : m_t << '\322'; break; + case 'U' : m_t << '\331'; break; + case 'a' : m_t << '\340'; break; + case 'e' : m_t << '\350'; break; + case 'i' : m_t << '\354'; break; + case 'o' : m_t << '\362'; break; + case 'u' : m_t << '\371'; break; + default: m_t << '?'; break; + } + break; + case DocSymbol::Circ: switch(s->letter()) + { + case 'A' : m_t << '\302'; break; + case 'E' : m_t << '\312'; break; + case 'I' : m_t << '\316'; break; + case 'O' : m_t << '\324'; break; + case 'U' : m_t << '\333'; break; + case 'a' : m_t << '\342'; break; + case 'e' : m_t << '\352'; break; + case 'i' : m_t << '\356'; break; + case 'o' : m_t << '\364'; break; + case 'u' : m_t << '\373'; break; + default: m_t << '?'; break; + } + break; + case DocSymbol::Tilde: switch(s->letter()) + { + case 'A' : m_t << '\303'; break; + case 'N' : m_t << '\321'; break; + case 'O' : m_t << '\325'; break; + case 'a' : m_t << '\343'; break; + case 'n' : m_t << '\361'; break; + case 'o' : m_t << '\365'; break; + default: m_t << '?'; break; + } + break; + case DocSymbol::Cedil: switch(s->letter()) + { + case 'C' : m_t << '\307'; break; + case 'c' : m_t << '\347'; break; + default: m_t << '?'; break; + } + break; + case DocSymbol::Slash: switch(s->letter()) + { + case 'O' : m_t << '\330'; break; + case 'o' : m_t << '\370'; break; + default: m_t << '?'; break; + } + break; + case DocSymbol::Ring: switch(s->letter()) + { + case 'A' : m_t << '\305'; break; + case 'a' : m_t << '\345'; break; + default: m_t << '?'; break; + } + break; + case DocSymbol::Szlig: m_t << "\337"; break; + case DocSymbol::Nbsp: m_t << "\\~ "; break; + case DocSymbol::Aelig: m_t << "\346"; break; + case DocSymbol::AElig: m_t << "\306"; break; + default: + err("error: unknown symbol found\n"); + } + m_lastIsPara=FALSE; +} + +void RTFDocVisitor::visit(DocURL *u) +{ + if (m_hide) return; + DBG_RTF("{\\comment RTFDocVisitor::visit(DocURL)}\n"); + if (Config_getBool("RTF_HYPERLINKS")) + { + m_t << "{\\field " + "{\\*\\fldinst " + "{ HYPERLINK \\\\l \""; + if (u->isEmail()) m_t << "mailto:"; + m_t << u->url(); + m_t << "\" }" + "{}"; + m_t << "}" + "{\\fldrslt " + "{\\cs37\\ul\\cf2 "; + filter(u->url()); + m_t << "}" + "}" + "}" << endl; + } + else + { + m_t << "{\\f2 "; + filter(u->url()); + m_t << "}"; + } + m_lastIsPara=FALSE; +} + +void RTFDocVisitor::visit(DocLineBreak *) +{ + if (m_hide) return; + DBG_RTF("{\\comment RTFDocVisitor::visit(DocLineBreak)}\n"); + m_t << "\\par"; + m_lastIsPara=TRUE; +} + +void RTFDocVisitor::visit(DocHorRuler *) +{ + if (m_hide) return; + DBG_RTF("{\\comment RTFDocVisitor::visit(DocHorRuler)}\n"); + m_t << "{\\pard\\widctlpar\\brdrb\\brdrs\\brdrw5\\brsp20 \\adjustright \\par}" << endl; + m_lastIsPara=TRUE; +} + +void RTFDocVisitor::visit(DocStyleChange *s) +{ + if (m_hide) return; + m_lastIsPara=FALSE; + DBG_RTF("{\\comment RTFDocVisitor::visit(DocStyleChange)}\n"); + switch (s->style()) + { + case DocStyleChange::Bold: + if (s->enable()) m_t << "{\\b "; else m_t << "} "; + break; + case DocStyleChange::Italic: + if (s->enable()) m_t << "{\\i "; else m_t << "} "; + break; + case DocStyleChange::Code: + if (s->enable()) m_t << "{\\f2 "; else m_t << "} "; + break; + case DocStyleChange::Subscript: + if (s->enable()) m_t << "{\\sub "; else m_t << "} "; + break; + case DocStyleChange::Superscript: + if (s->enable()) m_t << "{\\super "; else m_t << "} "; + break; + case DocStyleChange::Center: + if (s->enable()) m_t << "{\\qc "; else m_t << "} "; + break; + case DocStyleChange::Small: + if (s->enable()) m_t << "{\\sub "; else m_t << "} "; + break; + case DocStyleChange::Preformatted: + if (s->enable()) + { + m_t << "{" << endl; + m_t << "\\par" << endl; + m_t << rtf_Style_Reset << getStyle("CodeExample"); + m_insidePre=TRUE; + } + else + { + m_insidePre=FALSE; + m_t << "\\par"; + m_t << "}" << endl; + } + m_lastIsPara=TRUE; + break; + case DocStyleChange::Div: /* HTML only */ break; + case DocStyleChange::Span: /* HTML only */ break; + } +} + +void RTFDocVisitor::visit(DocVerbatim *s) +{ + if (m_hide) return; + DBG_RTF("{\\comment RTFDocVisitor::visit(DocVerbatim)}\n"); + QCString lang = m_langExt; + if (!s->language().isEmpty()) // explicit language setting + { + lang = s->language(); + } + switch(s->type()) + { + case DocVerbatim::Code: // fall though + m_t << "{" << endl; + m_t << "\\par" << endl; + m_t << rtf_Style_Reset << getStyle("CodeExample"); + Doxygen::parserManager->getParser(lang) + ->parseCode(m_ci,s->context(),s->text(), + s->isExample(),s->exampleFile()); + //m_t << "\\par" << endl; + m_t << "}" << endl; + break; + case DocVerbatim::Verbatim: + m_t << "{" << endl; + m_t << "\\par" << endl; + m_t << rtf_Style_Reset << getStyle("CodeExample"); + filter(s->text(),TRUE); + //m_t << "\\par" << endl; + m_t << "}" << endl; + break; + case DocVerbatim::HtmlOnly: + case DocVerbatim::LatexOnly: + case DocVerbatim::XmlOnly: + case DocVerbatim::ManOnly: + /* nothing */ + break; + case DocVerbatim::Dot: + { + static int dotindex = 1; + QCString fileName(4096); + + fileName.sprintf("%s%d%s", + (Config_getString("RTF_OUTPUT")+"/inline_dotgraph_").data(), + dotindex++, + ".dot" + ); + QFile file(fileName); + if (!file.open(IO_WriteOnly)) + { + err("Could not open file %s for writing\n",fileName.data()); + } + file.writeBlock( s->text(), s->text().length() ); + file.close(); + m_t << "\\par{\\qc "; // center picture + writeDotFile(fileName); + m_t << "} "; + if (Config_getBool("DOT_CLEANUP")) file.remove(); + } + break; + case DocVerbatim::Msc: + { + static int mscindex = 1; + QCString baseName(4096); + + baseName.sprintf("%s%d", + (Config_getString("RTF_OUTPUT")+"/inline_mscgraph_").data(), + mscindex++ + ); + QFile file(baseName+".msc"); + if (!file.open(IO_WriteOnly)) + { + err("Could not open file %s for writing\n",baseName.data()); + } + QCString text = "msc {"; + text+=s->text(); + text+="}"; + file.writeBlock( text, text.length() ); + file.close(); + m_t << "\\par{\\qc "; // center picture + writeMscFile(baseName); + m_t << "} "; + if (Config_getBool("DOT_CLEANUP")) file.remove(); + } + break; + } + m_lastIsPara=FALSE; +} + +void RTFDocVisitor::visit(DocAnchor *anc) +{ + if (m_hide) return; + DBG_RTF("{\\comment RTFDocVisitor::visit(DocAnchor)}\n"); + QCString anchor; + if (!anc->file().isEmpty()) + { + anchor+=anc->file(); + } + if (!anc->file().isEmpty() && !anc->anchor().isEmpty()) + { + anchor+="_"; + } + if (!anc->anchor().isEmpty()) + { + anchor+=anc->anchor(); + } + m_t << "{\\bkmkstart " << rtfFormatBmkStr(anchor) << "}" << endl; + m_t << "{\\bkmkend " << rtfFormatBmkStr(anchor) << "}" << endl; + m_lastIsPara=FALSE; +} + +void RTFDocVisitor::visit(DocInclude *inc) +{ + if (m_hide) return; + DBG_RTF("{\\comment RTFDocVisitor::visit(DocInclude)}\n"); + switch(inc->type()) + { + case DocInclude::IncWithLines: + { + m_t << "{" << endl; + m_t << "\\par" << endl; + m_t << rtf_Style_Reset << getStyle("CodeExample"); + QFileInfo cfi( inc->file() ); + FileDef fd( cfi.dirPath(), cfi.fileName() ); + Doxygen::parserManager->getParser(inc->extension()) + ->parseCode(m_ci,inc->context(), + inc->text(), + inc->isExample(), + inc->exampleFile(), &fd); + m_t << "\\par"; + m_t << "}" << endl; + } + break; + case DocInclude::Include: + m_t << "{" << endl; + m_t << "\\par" << endl; + m_t << rtf_Style_Reset << getStyle("CodeExample"); + Doxygen::parserManager->getParser(inc->extension()) + ->parseCode(m_ci,inc->context(), + inc->text(),inc->isExample(), + inc->exampleFile()); + m_t << "\\par"; + m_t << "}" << endl; + break; + case DocInclude::DontInclude: + break; + case DocInclude::HtmlInclude: + break; + case DocInclude::VerbInclude: + m_t << "{" << endl; + m_t << "\\par" << endl; + m_t << rtf_Style_Reset << getStyle("CodeExample"); + filter(inc->text()); + m_t << "\\par"; + m_t << "}" << endl; + break; + case DocInclude::Snippet: + m_t << "{" << endl; + if (!m_lastIsPara) m_t << "\\par" << endl; + m_t << rtf_Style_Reset << getStyle("CodeExample"); + Doxygen::parserManager->getParser(inc->extension()) + ->parseCode(m_ci, + inc->context(), + extractBlock(inc->text(),inc->blockId()), + inc->isExample(), + inc->exampleFile() + ); + m_t << "}"; + break; + } + m_lastIsPara=TRUE; +} + +void RTFDocVisitor::visit(DocIncOperator *op) +{ + //printf("DocIncOperator: type=%d first=%d, last=%d text=`%s'\n", + // op->type(),op->isFirst(),op->isLast(),op->text().data()); + DBG_RTF("{\\comment RTFDocVisitor::visit(DocIncOperator)}\n"); + if (op->isFirst()) + { + if (!m_hide) + { + m_t << "{" << endl; + m_t << "\\par" << endl; + m_t << rtf_Style_Reset << getStyle("CodeExample"); + } + pushEnabled(); + m_hide = TRUE; + } + if (op->type()!=DocIncOperator::Skip) + { + popEnabled(); + if (!m_hide) + { + Doxygen::parserManager->getParser(m_langExt) + ->parseCode(m_ci,op->context(),op->text(), + op->isExample(),op->exampleFile()); + } + pushEnabled(); + m_hide=TRUE; + } + if (op->isLast()) + { + popEnabled(); + if (!m_hide) + { + m_t << "\\par"; + m_t << "}" << endl; + } + m_lastIsPara=TRUE; + } + else + { + if (!m_hide) m_t << endl; + m_lastIsPara=FALSE; + } +} + +void RTFDocVisitor::visit(DocFormula *f) +{ + if (m_hide) return; + // TODO: do something sensible here, like including a bitmap + DBG_RTF("{\\comment RTFDocVisitor::visit(DocFormula)}\n"); + m_t << f->text(); + m_lastIsPara=FALSE; +} + +void RTFDocVisitor::visit(DocIndexEntry *i) +{ + if (m_hide) return; + DBG_RTF("{\\comment RTFDocVisitor::visit(DocIndexEntry)}\n"); + m_t << "{\\xe \\v " << i->entry() << "}" << endl; + m_lastIsPara=FALSE; +} + +void RTFDocVisitor::visit(DocSimpleSectSep *) +{ +} + +void RTFDocVisitor::visit(DocCite *cite) +{ + if (m_hide) return; + DBG_RTF("{\\comment RTFDocVisitor::visitPre(DocCite)}\n"); + if (!cite->file().isEmpty()) + { + startLink(cite->ref(),cite->file(),cite->anchor()); + } + else + { + m_t << "{\\b "; + } + filter(cite->text()); + if (!cite->file().isEmpty()) + { + endLink(cite->ref()); + } + else + { + m_t << "}"; + } +} + + +//-------------------------------------- +// visitor functions for compound nodes +//-------------------------------------- + +void RTFDocVisitor::visitPre(DocAutoList *l) +{ + if (m_hide) return; + DBG_RTF("{\\comment RTFDocVisitor::visitPre(DocAutoList)}\n"); + m_t << "{" << endl; + rtf_listItemInfo[m_indentLevel].isEnum = l->isEnumList(); + rtf_listItemInfo[m_indentLevel].number = 1; + m_lastIsPara=FALSE; +} + +void RTFDocVisitor::visitPost(DocAutoList *) +{ + if (m_hide) return; + DBG_RTF("{\\comment RTFDocVisitor::visitPost(DocAutoList)}\n"); + m_t << "\\par"; + m_t << "}" << endl; + m_lastIsPara=TRUE; +} + +void RTFDocVisitor::visitPre(DocAutoListItem *) +{ + if (m_hide) return; + DBG_RTF("{\\comment RTFDocVisitor::visitPre(DocAutoListItem)}\n"); + if (!m_lastIsPara) m_t << "\\par" << endl; + m_t << rtf_Style_Reset; + if (rtf_listItemInfo[m_indentLevel].isEnum) + { + m_t << getStyle("ListEnum") << endl; + m_t << rtf_listItemInfo[m_indentLevel].number << ".\\tab "; + rtf_listItemInfo[m_indentLevel].number++; + } + else + { + m_t << getStyle("ListBullet") << endl; + } + incIndentLevel(); + m_lastIsPara=FALSE; +} + +void RTFDocVisitor::visitPost(DocAutoListItem *) +{ + decIndentLevel(); + DBG_RTF("{\\comment RTFDocVisitor::visitPost(DocAutoListItem)}\n"); +} + +void RTFDocVisitor::visitPre(DocPara *) +{ + DBG_RTF("{\\comment RTFDocVisitor::visitPost(DocPara)}\n"); +} + +void RTFDocVisitor::visitPost(DocPara *p) +{ + if (m_hide) return; + DBG_RTF("{\\comment RTFDocVisitor::visitPost(DocPara)}\n"); + if (!m_lastIsPara && + !p->isLast() && // omit

    for last paragraph + !(p->parent() && // and for parameters & sections + p->parent()->kind()==DocNode::Kind_ParamSect + ) + ) + { + m_t << "\\par" << endl; + m_lastIsPara=TRUE; + } +} + +void RTFDocVisitor::visitPre(DocRoot *r) +{ + if (m_hide) return; + DBG_RTF("{\\comment RTFDocVisitor::visitPre(DocRoot)}\n"); + if (r->indent()) incIndentLevel(); + m_t << "{" << rtf_Style["BodyText"]->reference << endl; +} + +void RTFDocVisitor::visitPost(DocRoot *r) +{ + if (m_hide) return; + DBG_RTF("{\\comment RTFDocVisitor::visitPost(DocRoot)}\n"); + if (!m_lastIsPara && !r->singleLine()) m_t << "\\par" << endl; + m_t << "}"; + m_lastIsPara=TRUE; + if (r->indent()) decIndentLevel(); +} + +void RTFDocVisitor::visitPre(DocSimpleSect *s) +{ + if (m_hide) return; + DBG_RTF("{\\comment RTFDocVisitor::visitPre(DocSimpleSect)}\n"); + if (!m_lastIsPara) m_t << "\\par" << endl; + m_t << "{"; // start desc + //m_t << "{\\b "; // start bold + m_t << "{" << rtf_Style["Heading5"]->reference << endl; + switch(s->type()) + { + case DocSimpleSect::See: + m_t << theTranslator->trSeeAlso(); break; + case DocSimpleSect::Return: + m_t << theTranslator->trReturns(); break; + case DocSimpleSect::Author: + m_t << theTranslator->trAuthor(TRUE,TRUE); break; + case DocSimpleSect::Authors: + m_t << theTranslator->trAuthor(TRUE,FALSE); break; + case DocSimpleSect::Version: + m_t << theTranslator->trVersion(); break; + case DocSimpleSect::Since: + m_t << theTranslator->trSince(); break; + case DocSimpleSect::Date: + m_t << theTranslator->trDate(); break; + case DocSimpleSect::Note: + m_t << theTranslator->trNote(); break; + case DocSimpleSect::Warning: + m_t << theTranslator->trWarning(); break; + case DocSimpleSect::Pre: + m_t << theTranslator->trPrecondition(); break; + case DocSimpleSect::Post: + m_t << theTranslator->trPostcondition(); break; + case DocSimpleSect::Copyright: + m_t << theTranslator->trCopyright(); break; + case DocSimpleSect::Invar: + m_t << theTranslator->trInvariant(); break; + case DocSimpleSect::Remark: + m_t << theTranslator->trRemarks(); break; + case DocSimpleSect::Attention: + m_t << theTranslator->trAttention(); break; + case DocSimpleSect::User: break; + case DocSimpleSect::Rcs: break; + case DocSimpleSect::Unknown: break; + } + + // special case 1: user defined title + if (s->type()!=DocSimpleSect::User && s->type()!=DocSimpleSect::Rcs) + { + m_t << ":"; + m_t << "\\par"; + m_t << "}"; // end bold + incIndentLevel(); + m_t << rtf_Style_Reset << getStyle("DescContinue"); + } + m_lastIsPara=FALSE; +} + +void RTFDocVisitor::visitPost(DocSimpleSect *) +{ + if (m_hide) return; + DBG_RTF("{\\comment RTFDocVisitor::visitPost(DocSimpleSect)}\n"); + if (!m_lastIsPara) m_t << "\\par" << endl; + decIndentLevel(); + m_t << "}"; // end desc + m_lastIsPara=TRUE; +} + +void RTFDocVisitor::visitPre(DocTitle *) +{ + DBG_RTF("{\\comment RTFDocVisitor::visitPre(DocTitle)}\n"); +} + +void RTFDocVisitor::visitPost(DocTitle *) +{ + if (m_hide) return; + DBG_RTF("{\\comment RTFDocVisitor::visitPost(DocTitle)}\n"); + m_t << "\\par" << endl; + m_t << "}"; // end bold + incIndentLevel(); + m_t << rtf_Style_Reset << getStyle("DescContinue"); + m_lastIsPara=FALSE; +} + +void RTFDocVisitor::visitPre(DocSimpleList *) +{ + if (m_hide) return; + DBG_RTF("{\\comment RTFDocVisitor::visitPre(DocSimpleSect)}\n"); + m_t << "{" << endl; + rtf_listItemInfo[m_indentLevel].isEnum = FALSE; + m_lastIsPara=FALSE; +} + +void RTFDocVisitor::visitPost(DocSimpleList *) +{ + if (m_hide) return; + DBG_RTF("{\\comment RTFDocVisitor::visitPost(DocSimpleSect)}\n"); + if (!m_lastIsPara) m_t << "\\par" << endl; + m_t << "}" << endl; + m_lastIsPara=TRUE; +} + +void RTFDocVisitor::visitPre(DocSimpleListItem *) +{ + if (m_hide) return; + DBG_RTF("{\\comment RTFDocVisitor::visitPre(DocSimpleListItem)}\n"); + m_t << "\\par" << rtf_Style_Reset << getStyle("ListBullet") << endl; + m_lastIsPara=FALSE; + incIndentLevel(); +} + +void RTFDocVisitor::visitPost(DocSimpleListItem *) +{ + decIndentLevel(); + DBG_RTF("{\\comment RTFDocVisitor::visitPost(DocSimpleListItem)}\n"); +} + +void RTFDocVisitor::visitPre(DocSection *s) +{ + if (m_hide) return; + DBG_RTF("{\\comment RTFDocVisitor::visitPre(DocSection)}\n"); + if (!m_lastIsPara) m_t << "\\par" << endl; + m_t << "{\\bkmkstart " << rtfFormatBmkStr(s->file()+"_"+s->anchor()) << "}" << endl; + m_t << "{\\bkmkend " << rtfFormatBmkStr(s->file()+"_"+s->anchor()) << "}" << endl; + m_t << "{{" // start section + << rtf_Style_Reset; + QCString heading; + int level = QMIN(s->level()+1,4); + heading.sprintf("Heading%d",level); + // set style + m_t << rtf_Style[heading]->reference << endl; + // make table of contents entry + filter(s->title()); + m_t << endl << "\\par" << "}" << endl; + m_t << "{\\tc\\tcl" << level << " \\v "; + filter(s->title()); + m_t << "}" << endl; + m_lastIsPara=TRUE; +} + +void RTFDocVisitor::visitPost(DocSection *) +{ + if (m_hide) return; + DBG_RTF("{\\comment RTFDocVisitor::visitPost(DocSection)}\n"); + m_t << "\\par}" << endl; // end section + m_lastIsPara=TRUE; +} + +void RTFDocVisitor::visitPre(DocHtmlList *l) +{ + if (m_hide) return; + DBG_RTF("{\\comment RTFDocVisitor::visitPre(DocHtmlList)}\n"); + m_t << "{" << endl; + rtf_listItemInfo[m_indentLevel].isEnum = l->type()==DocHtmlList::Ordered; + rtf_listItemInfo[m_indentLevel].number = 1; + m_lastIsPara=FALSE; +} + +void RTFDocVisitor::visitPost(DocHtmlList *) +{ + if (m_hide) return; + DBG_RTF("{\\comment RTFDocVisitor::visitPost(DocHtmlList)}\n"); + m_t << "\\par" << "}" << endl; + m_lastIsPara=TRUE; +} + +void RTFDocVisitor::visitPre(DocHtmlListItem *) +{ + if (m_hide) return; + DBG_RTF("{\\comment RTFDocVisitor::visitPre(DocHtmlListItem)}\n"); + m_t << "\\par" << endl; + m_t << rtf_Style_Reset; + if (rtf_listItemInfo[m_indentLevel].isEnum) + { + m_t << getStyle("ListEnum") << endl; + m_t << rtf_listItemInfo[m_indentLevel].number << ".\\tab "; + rtf_listItemInfo[m_indentLevel].number++; + } + else + { + m_t << getStyle("ListBullet") << endl; + } + incIndentLevel(); + m_lastIsPara=FALSE; +} + +void RTFDocVisitor::visitPost(DocHtmlListItem *) +{ + decIndentLevel(); + DBG_RTF("{\\comment RTFDocVisitor::visitPost(DocHtmlListItem)}\n"); +} + +void RTFDocVisitor::visitPre(DocHtmlDescList *) +{ + if (m_hide) return; + DBG_RTF("{\\comment RTFDocVisitor::visitPre(DocHtmlDescList)}\n"); + //m_t << "{" << endl; + //m_t << rtf_Style_Reset << getStyle("ListContinue"); + //m_lastIsPara=FALSE; +} + +void RTFDocVisitor::visitPost(DocHtmlDescList *) +{ + if (m_hide) return; + DBG_RTF("{\\comment RTFDocVisitor::visitPost(DocHtmlDescList)}\n"); + //m_t << "}" << endl; + //m_t << "\\par" << endl; + //m_lastIsPara=TRUE; +} + +void RTFDocVisitor::visitPre(DocHtmlDescTitle *) +{ + if (m_hide) return; + DBG_RTF("{\\comment RTFDocVisitor::visitPre(DocHtmlDescTitle)}\n"); + //m_t << "\\par" << endl; + //m_t << "{\\b "; + m_t << "{" << rtf_Style["Heading5"]->reference << endl; + m_lastIsPara=FALSE; +} + +void RTFDocVisitor::visitPost(DocHtmlDescTitle *) +{ + if (m_hide) return; + DBG_RTF("{\\comment RTFDocVisitor::visitPost(DocHtmlDescTitle)}\n"); + m_t << "\\par" << endl; + m_t << "}" << endl; + m_lastIsPara=TRUE; +} + +void RTFDocVisitor::visitPre(DocHtmlDescData *) +{ + if (m_hide) return; + DBG_RTF("{\\comment RTFDocVisitor::visitPre(DocHtmlDescData)}\n"); + incIndentLevel(); + m_t << "{" << rtf_Style_Reset << getStyle("DescContinue"); +} + +void RTFDocVisitor::visitPost(DocHtmlDescData *) +{ + if (m_hide) return; + DBG_RTF("{\\comment RTFDocVisitor::visitPost(DocHtmlDescData)}\n"); + m_t << "\\par"; + m_t << "}" << endl; + decIndentLevel(); + m_lastIsPara=TRUE; +} + +void RTFDocVisitor::visitPre(DocHtmlTable *) +{ + if (m_hide) return; + DBG_RTF("{\\comment RTFDocVisitor::visitPre(DocHtmlTable)}\n"); + if (!m_lastIsPara) m_t << "\\par" << endl; + m_lastIsPara=TRUE; +} + +void RTFDocVisitor::visitPost(DocHtmlTable *) +{ + if (m_hide) return; + DBG_RTF("{\\comment RTFDocVisitor::visitPost(DocHtmlTable)}\n"); + m_t << "\\pard\\plain" << endl; + m_t << "\\par" << endl; + m_lastIsPara=TRUE; +} + +void RTFDocVisitor::visitPre(DocHtmlCaption *) +{ + DBG_RTF("{\\comment RTFDocVisitor::visitPre(DocHtmlCaption)}\n"); +} + +void RTFDocVisitor::visitPost(DocHtmlCaption *) +{ + DBG_RTF("{\\comment RTFDocVisitor::visitPost(DocHtmlCaption)}\n"); +} + +void RTFDocVisitor::visitPre(DocHtmlRow *r) +{ + if (m_hide) return; + DBG_RTF("{\\comment RTFDocVisitor::visitPre(DocHtmlRow)}\n"); + uint i,columnWidth=r->numCells()>0 ? rtf_pageWidth/r->numCells() : 10; + m_t << "\\trowd \\trgaph108\\trleft-108" + "\\trbrdrt\\brdrs\\brdrw10 " + "\\trbrdrl\\brdrs\\brdrw10 " + "\\trbrdrb\\brdrs\\brdrw10 " + "\\trbrdrr\\brdrs\\brdrw10 " + "\\trbrdrh\\brdrs\\brdrw10 " + "\\trbrdrv\\brdrs\\brdrw10 "<< endl; + for (i=0;inumCells();i++) + { + if (r->isHeading()) + { + m_t << "\\clcbpat16"; // set cell shading to light grey (color 16 in the clut) + } + m_t << "\\clvertalt\\clbrdrt\\brdrs\\brdrw10 " + "\\clbrdrl\\brdrs\\brdrw10 " + "\\clbrdrb\\brdrs\\brdrw10 " + "\\clbrdrr \\brdrs\\brdrw10 " + "\\cltxlrtb " + "\\cellx" << ((i+1)*columnWidth) << endl; + } + m_t << "\\pard \\widctlpar\\intbl\\adjustright" << endl; + m_lastIsPara=FALSE; +} + +void RTFDocVisitor::visitPost(DocHtmlRow *) +{ + if (m_hide) return; + DBG_RTF("{\\comment RTFDocVisitor::visitPost(DocHtmlRow)}\n"); + m_t << endl; + m_t << "\\pard \\widctlpar\\intbl\\adjustright" << endl; + m_t << "{\\row }" << endl; + m_lastIsPara=FALSE; +} + +void RTFDocVisitor::visitPre(DocHtmlCell *c) +{ + if (m_hide) return; + DBG_RTF("{\\comment RTFDocVisitor::visitPre(DocHtmlCell)}\n"); + m_t << "{" << align(c); + m_lastIsPara=FALSE; +} + +void RTFDocVisitor::visitPost(DocHtmlCell *) +{ + if (m_hide) return; + DBG_RTF("{\\comment RTFDocVisitor::visitPost(DocHtmlCell)}\n"); + m_t << "\\cell }"; + m_lastIsPara=FALSE; +} + +void RTFDocVisitor::visitPre(DocInternal *) +{ + if (m_hide) return; + //DBG_RTF("{\\comment RTFDocVisitor::visitPre(DocInternal)}\n"); + //m_t << "{"; // start desc + //m_t << "{\\b "; // start bold + //m_t << theTranslator->trForInternalUseOnly(); + //m_t << "}"; // end bold + //m_t << "\\par" << endl; + //incIndentLevel(); + //m_t << rtf_Style_Reset << getStyle("DescContinue"); + //m_lastIsPara=FALSE; +} + +void RTFDocVisitor::visitPost(DocInternal *) +{ + if (m_hide) return; + //DBG_RTF("{\\comment RTFDocVisitor::visitPost(DocInternal)}\n"); + //m_t << "\\par"; + //decIndentLevel(); + //m_t << "}"; // end desc + //m_lastIsPara=TRUE; +} + +void RTFDocVisitor::visitPre(DocHRef *href) +{ + if (m_hide) return; + DBG_RTF("{\\comment RTFDocVisitor::visitPre(DocHRef)}\n"); + if (Config_getBool("RTF_HYPERLINKS")) + { + m_t << "{\\field " + "{\\*\\fldinst " + "{ HYPERLINK \\\\l \"" << href->url() << "\" " + "}{}" + "}" + "{\\fldrslt " + "{\\cs37\\ul\\cf2 "; + + } + else + { + m_t << "{\\f2 "; + } + m_lastIsPara=FALSE; +} + +void RTFDocVisitor::visitPost(DocHRef *) +{ + if (m_hide) return; + DBG_RTF("{\\comment RTFDocVisitor::visitPost(DocHRef)}\n"); + if (Config_getBool("RTF_HYPERLINKS")) + { + m_t << "}" + "}" + "}"; + } + else + { + m_t << "}"; + } + m_lastIsPara=FALSE; +} + +void RTFDocVisitor::visitPre(DocHtmlHeader *header) +{ + if (m_hide) return; + DBG_RTF("{\\comment RTFDocVisitor::visitPre(DocHtmlHeader)}\n"); + m_t << "{" // start section + << rtf_Style_Reset; + QCString heading; + int level = QMIN(header->level()+2,4); + heading.sprintf("Heading%d",level); + // set style + m_t << rtf_Style[heading]->reference; + // make table of contents entry + m_t << "{\\tc\\tcl \\v " << level << "}"; + m_lastIsPara=FALSE; + +} + +void RTFDocVisitor::visitPost(DocHtmlHeader *) +{ + if (m_hide) return; + DBG_RTF("{\\comment RTFDocVisitor::visitPost(DocHtmlHeader)}\n"); + m_t << "\\par"; + m_t << "}" << endl; // end section + m_lastIsPara=TRUE; +} + +void RTFDocVisitor::visitPre(DocImage *img) +{ + DBG_RTF("{\\comment RTFDocVisitor::visitPre(DocImage)}\n"); + if (img->type()==DocImage::Rtf) + { + m_t << "\\par" << endl; + m_t << "{" << endl; + m_t << rtf_Style_Reset << endl; + m_t << "\\par\\pard \\qc {\\field\\flddirty {\\*\\fldinst INCLUDEPICTURE \""; + m_t << img->name(); + m_t << "\" \\\\d \\\\*MERGEFORMAT}{\\fldrslt IMAGE}}\\par" << endl; + m_t << "}" << endl; + m_lastIsPara=TRUE; + } + else // other format -> skip + { + } + // hide caption since it is not supported at the moment + pushEnabled(); + m_hide=TRUE; +} + +void RTFDocVisitor::visitPost(DocImage *) +{ + DBG_RTF("{\\comment RTFDocVisitor::visitPost(DocImage)}\n"); + popEnabled(); +} + +void RTFDocVisitor::visitPre(DocDotFile *df) +{ + DBG_RTF("{\\comment RTFDocVisitor::visitPre(DocDotFile)}\n"); + writeDotFile(df->file()); + + // hide caption since it is not supported at the moment + pushEnabled(); + m_hide=TRUE; +} + +void RTFDocVisitor::visitPost(DocDotFile *) +{ + DBG_RTF("{\\comment RTFDocVisitor::visitPost(DocDotFile)}\n"); + popEnabled(); +} +void RTFDocVisitor::visitPre(DocMscFile *df) +{ + DBG_RTF("{\\comment RTFDocVisitor::visitPre(DocMscFile)}\n"); + writeMscFile(df->file()); + + // hide caption since it is not supported at the moment + pushEnabled(); + m_hide=TRUE; +} + +void RTFDocVisitor::visitPost(DocMscFile *) +{ + DBG_RTF("{\\comment RTFDocVisitor::visitPost(DocMscFile)}\n"); + popEnabled(); +} + +void RTFDocVisitor::visitPre(DocLink *lnk) +{ + if (m_hide) return; + DBG_RTF("{\\comment RTFDocVisitor::visitPre(DocLink)}\n"); + startLink(lnk->ref(),lnk->file(),lnk->anchor()); +} + +void RTFDocVisitor::visitPost(DocLink *lnk) +{ + if (m_hide) return; + DBG_RTF("{\\comment RTFDocVisitor::visitPost(DocLink)}\n"); + endLink(lnk->ref()); +} + +void RTFDocVisitor::visitPre(DocRef *ref) +{ + if (m_hide) return; + DBG_RTF("{\\comment RTFDocVisitor::visitPre(DocRef)}\n"); + // when ref->isSubPage()==TRUE we use ref->file() for HTML and + // ref->anchor() for LaTeX/RTF + if (ref->isSubPage()) + { + startLink(ref->ref(),0,ref->anchor()); + } + else + { + if (!ref->file().isEmpty()) startLink(ref->ref(),ref->file(),ref->anchor()); + } + if (!ref->hasLinkText()) filter(ref->targetTitle()); +} + +void RTFDocVisitor::visitPost(DocRef *ref) +{ + if (m_hide) return; + DBG_RTF("{\\comment RTFDocVisitor::visitPost(DocRef)}\n"); + if (!ref->file().isEmpty()) endLink(ref->ref()); + //m_t << " "; +} + + +void RTFDocVisitor::visitPre(DocSecRefItem *) +{ + DBG_RTF("{\\comment RTFDocVisitor::visitPre(DocSecRefItem)}\n"); +} + +void RTFDocVisitor::visitPost(DocSecRefItem *) +{ + DBG_RTF("{\\comment RTFDocVisitor::visitPost(DocSecRefItem)}\n"); +} + +void RTFDocVisitor::visitPre(DocSecRefList *) +{ + if (m_hide) return; + DBG_RTF("{\\comment RTFDocVisitor::visitPre(DocSecRefList)}\n"); + m_t << "{" << endl; + incIndentLevel(); + m_t << rtf_Style_Reset << getStyle("LatexTOC") << endl; + m_t << "\\par" << endl; + m_lastIsPara=TRUE; +} + +void RTFDocVisitor::visitPost(DocSecRefList *) +{ + if (m_hide) return; + DBG_RTF("{\\comment RTFDocVisitor::visitPost(DocSecRefList)}\n"); + decIndentLevel(); + m_t << "\\par"; + m_t << "}" << endl; + m_lastIsPara=TRUE; +} + +//void RTFDocVisitor::visitPre(DocLanguage *l) +//{ +// DBG_RTF("{\\comment RTFDocVisitor::visitPre(DocLanguage)}\n"); +// QCString langId = Config_getEnum("OUTPUT_LANGUAGE"); +// if (l->id().lower()!=langId.lower()) +// { +// pushEnabled(); +// m_hide = TRUE; +// } +//} +// +//void RTFDocVisitor::visitPost(DocLanguage *l) +//{ +// DBG_RTF("{\\comment RTFDocVisitor::visitPost(DocLanguage)}\n"); +// QCString langId = Config_getEnum("OUTPUT_LANGUAGE"); +// if (l->id().lower()!=langId.lower()) +// { +// popEnabled(); +// } +//} + +void RTFDocVisitor::visitPre(DocParamSect *s) +{ + if (m_hide) return; + DBG_RTF("{\\comment RTFDocVisitor::visitPre(DocParamSect)}\n"); + m_t << "{"; // start param list + if (!m_lastIsPara) m_t << "\\par" << endl; + //m_t << "{\\b "; // start bold + m_t << "{" << rtf_Style["Heading5"]->reference << endl; + switch(s->type()) + { + case DocParamSect::Param: + m_t << theTranslator->trParameters(); break; + case DocParamSect::RetVal: + m_t << theTranslator->trReturnValues(); break; + case DocParamSect::Exception: + m_t << theTranslator->trExceptions(); break; + case DocParamSect::TemplateParam: + /* TODO: add this + m_t << theTranslator->trTemplateParam(); break; + */ + m_t << "Template Parameters"; break; + default: + ASSERT(0); + } + m_t << ":"; + m_t << "\\par"; + m_t << "}" << endl; + bool useTable = s->type()==DocParamSect::Param || + s->type()==DocParamSect::RetVal || + s->type()==DocParamSect::Exception || + s->type()==DocParamSect::TemplateParam; + if (!useTable) + { + incIndentLevel(); + } + m_t << rtf_Style_Reset << getStyle("DescContinue"); + m_lastIsPara=TRUE; +} + +void RTFDocVisitor::visitPost(DocParamSect *s) +{ + if (m_hide) return; + DBG_RTF("{\\comment RTFDocVisitor::visitPost(DocParamSect)}\n"); + //m_t << "\\par" << endl; + bool useTable = s->type()==DocParamSect::Param || + s->type()==DocParamSect::RetVal || + s->type()==DocParamSect::Exception || + s->type()==DocParamSect::TemplateParam; + if (!useTable) + { + decIndentLevel(); + } + m_t << "}" << endl; +} + +void RTFDocVisitor::visitPre(DocParamList *pl) +{ + static int columnPos[4][5] = + { { 2, 25, 100, 100, 100 }, // no inout, no type + { 3, 14, 35, 100, 100 }, // inout, no type + { 3, 25, 50, 100, 100 }, // no inout, type + { 4, 14, 35, 55, 100 }, // inout, type + }; + int config=0; + if (m_hide) return; + DBG_RTF("{\\comment RTFDocVisitor::visitPre(DocParamList)}\n"); + + DocParamSect::Type parentType = DocParamSect::Unknown; + DocParamSect *sect = 0; + if (pl->parent() && pl->parent()->kind()==DocNode::Kind_ParamSect) + { + parentType = ((DocParamSect*)pl->parent())->type(); + sect=(DocParamSect*)pl->parent(); + } + bool useTable = parentType==DocParamSect::Param || + parentType==DocParamSect::RetVal || + parentType==DocParamSect::Exception || + parentType==DocParamSect::TemplateParam; + if (sect && sect->hasInOutSpecifier()) config+=1; + if (sect && sect->hasTypeSpecifier()) config+=2; + if (useTable) + { + int i; + m_t << "\\trowd \\trgaph108\\trleft426\\tblind426" + "\\trbrdrt\\brdrs\\brdrw10\\brdrcf15 " + "\\trbrdrl\\brdrs\\brdrw10\\brdrcf15 " + "\\trbrdrb\\brdrs\\brdrw10\\brdrcf15 " + "\\trbrdrr\\brdrs\\brdrw10\\brdrcf15 " + "\\trbrdrh\\brdrs\\brdrw10\\brdrcf15 " + "\\trbrdrv\\brdrs\\brdrw10\\brdrcf15 "<< endl; + for (i=0;ihasInOutSpecifier()) + { + if (useTable) + { + m_t << "{"; + } + + // Put in the direction: in/out/in,out if specified. + if (pl->direction()!=DocParamSect::Unspecified) + { + if (pl->direction()==DocParamSect::In) + { + m_t << "in"; + } + else if (pl->direction()==DocParamSect::Out) + { + m_t << "out"; + } + else if (pl->direction()==DocParamSect::InOut) + { + m_t << "in,out"; + } + } + + if (useTable) + { + m_t << "\\cell }"; + } + } + + if (sect && sect->hasTypeSpecifier()) + { + if (useTable) + { + m_t << "{"; + } + QListIterator li(pl->paramTypes()); + DocNode *type; + bool first=TRUE; + for (li.toFirst();(type=li.current());++li) + { + if (!first) m_t << " | "; else first=FALSE; + if (type->kind()==DocNode::Kind_Word) + { + visit((DocWord*)type); + } + else if (type->kind()==DocNode::Kind_LinkedWord) + { + visit((DocLinkedWord*)type); + } + } + if (useTable) + { + m_t << "\\cell }"; + } + } + + + if (useTable) + { + m_t << "{"; + } + + m_t << "{\\i "; + //QStrListIterator li(pl->parameters()); + //const char *s; + QListIterator li(pl->parameters()); + DocNode *param; + bool first=TRUE; + for (li.toFirst();(param=li.current());++li) + { + if (!first) m_t << ","; else first=FALSE; + if (param->kind()==DocNode::Kind_Word) + { + visit((DocWord*)param); + } + else if (param->kind()==DocNode::Kind_LinkedWord) + { + visit((DocLinkedWord*)param); + } + } + m_t << "} "; + + if (useTable) + { + m_t << "\\cell }{"; + } + m_lastIsPara=TRUE; +} + +void RTFDocVisitor::visitPost(DocParamList *pl) +{ + if (m_hide) return; + DBG_RTF("{\\comment RTFDocVisitor::visitPost(DocParamList)}\n"); + + DocParamSect::Type parentType = DocParamSect::Unknown; + //DocParamSect *sect = 0; + if (pl->parent() && pl->parent()->kind()==DocNode::Kind_ParamSect) + { + parentType = ((DocParamSect*)pl->parent())->type(); + //sect=(DocParamSect*)pl->parent(); + } + bool useTable = parentType==DocParamSect::Param || + parentType==DocParamSect::RetVal || + parentType==DocParamSect::Exception || + parentType==DocParamSect::TemplateParam; + if (useTable) + { + m_t << "\\cell }" << endl; + //m_t << "\\pard \\widctlpar\\intbl\\adjustright" << endl; + m_t << "{\\row }" << endl; + } + else + { + m_t << "\\par" << endl; + } + + m_lastIsPara=TRUE; +} + +void RTFDocVisitor::visitPre(DocXRefItem *x) +{ + if (m_hide) return; + bool anonymousEnum = x->file()=="@"; + DBG_RTF("{\\comment RTFDocVisitor::visitPre(DocXRefItem)}\n"); + m_t << "{"; // start param list + //m_t << "{\\b "; // start bold + m_t << "{" << rtf_Style["Heading5"]->reference << endl; + if (Config_getBool("RTF_HYPERLINKS") && !anonymousEnum) + { + QCString refName; + if (!x->file().isEmpty()) + { + refName+=x->file(); + } + if (!x->file().isEmpty() && !x->anchor().isEmpty()) + { + refName+="_"; + } + if (!x->anchor().isEmpty()) + { + refName+=x->anchor(); + } + + m_t << "{\\field " + "{\\*\\fldinst " + "{ HYPERLINK \\\\l \"" << refName << "\" " + "}{}" + "}" + "{\\fldrslt " + "{\\cs37\\ul\\cf2 "; + filter(x->title()); + m_t << "}" + "}" + "}"; + } + else + { + filter(x->title()); + } + m_t << ":"; + m_t << "\\par"; + m_t << "}"; // end bold + incIndentLevel(); + m_t << rtf_Style_Reset << getStyle("DescContinue"); + m_lastIsPara=FALSE; +} + +void RTFDocVisitor::visitPost(DocXRefItem *) +{ + if (m_hide) return; + DBG_RTF("{\\comment RTFDocVisitor::visitPost(DocXRefItem)}\n"); + m_t << "\\par" << endl; + decIndentLevel(); + m_t << "}" << endl; // end xref item + m_lastIsPara=TRUE; +} + +void RTFDocVisitor::visitPre(DocInternalRef *ref) +{ + if (m_hide) return; + DBG_RTF("{\\comment RTFDocVisitor::visitPre(DocInternalRef)}\n"); + startLink("",ref->file(),ref->anchor()); +} + +void RTFDocVisitor::visitPost(DocInternalRef *) +{ + if (m_hide) return; + DBG_RTF("{\\comment RTFDocVisitor::visitPost(DocInternalRef)}\n"); + endLink(""); + m_t << " "; +} + +void RTFDocVisitor::visitPre(DocCopy *) +{ + if (m_hide) return; + DBG_RTF("{\\comment RTFDocVisitor::visitPre(DocCopy)}\n"); +} + +void RTFDocVisitor::visitPost(DocCopy *) +{ + if (m_hide) return; + DBG_RTF("{\\comment RTFDocVisitor::visitPost(DocCopy)}\n"); +} + +void RTFDocVisitor::visitPre(DocText *) +{ + if (m_hide) return; + DBG_RTF("{\\comment RTFDocVisitor::visitPre(DocText)}\n"); +} + +void RTFDocVisitor::visitPost(DocText *) +{ + if (m_hide) return; + DBG_RTF("{\\comment RTFDocVisitor::visitPost(DocText)}\n"); +} + +void RTFDocVisitor::visitPre(DocHtmlBlockQuote *) +{ + if (m_hide) return; + DBG_RTF("{\\comment RTFDocVisitor::visitPre(DocHtmlBlockQuote)}\n"); + if (!m_lastIsPara) m_t << "\\par" << endl; + m_t << "{"; // start desc + incIndentLevel(); + m_t << rtf_Style_Reset << getStyle("DescContinue"); +} + +void RTFDocVisitor::visitPost(DocHtmlBlockQuote *) +{ + if (m_hide) return; + DBG_RTF("{\\comment RTFDocVisitor::visitPost(DocHtmlBlockQuote)}\n"); + if (!m_lastIsPara) m_t << "\\par" << endl; + decIndentLevel(); + m_t << "}"; // end desc + m_lastIsPara=TRUE; +} + + +//static char* getMultiByte(int c) +//{ +// static char s[10]; +// sprintf(s,"\\'%X",c); +// return s; +//} + +void RTFDocVisitor::filter(const char *str,bool verbatim) +{ + if (str) + { + const unsigned char *p=(const unsigned char *)str; + unsigned char c; + unsigned char pc='\0'; + while (*p) + { + //static bool MultiByte = FALSE; + c=*p++; + + //if ( MultiByte ) + //{ + // m_t << getMultiByte( c ); + // MultiByte = FALSE; + // continue; + //} + //if ( c >= 0x80 ) + //{ + // MultiByte = TRUE; + // m_t << getMultiByte( c ); + // continue; + //} + + switch (c) + { + case '{': m_t << "\\{"; break; + case '}': m_t << "\\}"; break; + case '\\': m_t << "\\\\"; break; + case '\n': if (verbatim) + { + m_t << "\\par" << endl; + } + else + { + m_t << '\n'; + } + break; + default: m_t << (char)c; + } + pc = c; + } + } +} + +void RTFDocVisitor::startLink(const QCString &ref,const QCString &file,const QCString &anchor) +{ + if (ref.isEmpty() && Config_getBool("RTF_HYPERLINKS")) + { + QCString refName; + if (!file.isEmpty()) + { + refName+=file; + } + if (!file.isEmpty() && anchor) + { + refName+='_'; + } + if (anchor) + { + refName+=anchor; + } + + m_t << "{\\field {\\*\\fldinst { HYPERLINK \\\\l \""; + m_t << rtfFormatBmkStr(refName); + m_t << "\" }{}"; + m_t << "}{\\fldrslt {\\cs37\\ul\\cf2 "; + } + else + { + m_t << "{\\b "; + } + m_lastIsPara=FALSE; +} + +void RTFDocVisitor::endLink(const QCString &ref) +{ + if (ref.isEmpty() && Config_getBool("RTF_HYPERLINKS")) + { + m_t << "}}}"; + } + else + { + m_t << "}"; + } + m_lastIsPara=FALSE; +} + +void RTFDocVisitor::pushEnabled() +{ + m_enabled.push(new bool(m_hide)); +} + +void RTFDocVisitor::popEnabled() +{ + bool *v=m_enabled.pop(); + ASSERT(v!=0); + m_hide = *v; + delete v; +} + +void RTFDocVisitor::writeDotFile(const QCString &fileName) +{ + QCString baseName=fileName; + int i; + if ((i=baseName.findRev('/'))!=-1) + { + baseName=baseName.right(baseName.length()-i-1); + } + QCString outDir = Config_getString("RTF_OUTPUT"); + writeDotGraphFromFile(fileName,outDir,baseName,BITMAP); + if (!m_lastIsPara) m_t << "\\par" << endl; + m_t << "{" << endl; + m_t << rtf_Style_Reset; + m_t << "\\pard \\qc {\\field\\flddirty {\\*\\fldinst INCLUDEPICTURE \""; + m_t << baseName << "." << Config_getEnum("DOT_IMAGE_FORMAT"); + m_t << "\" \\\\d \\\\*MERGEFORMAT}{\\fldrslt IMAGE}}\\par" << endl; + m_t << "}" << endl; + m_lastIsPara=TRUE; +} + +void RTFDocVisitor::writeMscFile(const QCString &fileName) +{ + QCString baseName=fileName; + int i; + if ((i=baseName.findRev('/'))!=-1) + { + baseName=baseName.right(baseName.length()-i-1); + } + QCString outDir = Config_getString("RTF_OUTPUT"); + writeMscGraphFromFile(fileName+".msc",outDir,baseName,MSC_BITMAP); + if (!m_lastIsPara) m_t << "\\par" << endl; + m_t << "{" << endl; + m_t << rtf_Style_Reset; + m_t << "\\pard \\qc {\\field\\flddirty {\\*\\fldinst INCLUDEPICTURE \""; + m_t << baseName << ".png"; + m_t << "\" \\\\d \\\\*MERGEFORMAT}{\\fldrslt IMAGE}}\\par" << endl; + m_t << "}" << endl; + m_lastIsPara=TRUE; +} + diff --git a/trunk/src/rtfdocvisitor.h b/trunk/src/rtfdocvisitor.h new file mode 100644 index 0000000..2e35b3b --- /dev/null +++ b/trunk/src/rtfdocvisitor.h @@ -0,0 +1,166 @@ +/****************************************************************************** + * + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#ifndef _RTFDOCVISITOR_H +#define _RTFDOCVISITOR_H + +#include "docvisitor.h" +#include +#include + +class FTextStream; +class CodeOutputInterface; + +/*! @brief Concrete visitor implementation for RTF output. */ +class RTFDocVisitor : public DocVisitor +{ + public: + RTFDocVisitor(FTextStream &t,CodeOutputInterface &ci,const char *langExt); + + //-------------------------------------- + // visitor functions for leaf nodes + //-------------------------------------- + + void visit(DocWord *); + void visit(DocLinkedWord *); + void visit(DocWhiteSpace *); + void visit(DocSymbol *); + void visit(DocURL *); + void visit(DocLineBreak *); + void visit(DocHorRuler *); + void visit(DocStyleChange *); + void visit(DocVerbatim *); + void visit(DocAnchor *); + void visit(DocInclude *); + void visit(DocIncOperator *); + void visit(DocFormula *); + void visit(DocIndexEntry *); + void visit(DocSimpleSectSep *); + void visit(DocCite *); + + //-------------------------------------- + // visitor functions for compound nodes + //-------------------------------------- + + void visitPre(DocAutoList *); + void visitPost(DocAutoList *); + void visitPre(DocAutoListItem *); + void visitPost(DocAutoListItem *); + void visitPre(DocPara *); + void visitPost(DocPara *); + void visitPre(DocRoot *); + void visitPost(DocRoot *); + void visitPre(DocSimpleSect *); + void visitPost(DocSimpleSect *); + void visitPre(DocTitle *); + void visitPost(DocTitle *); + void visitPre(DocSimpleList *); + void visitPost(DocSimpleList *); + void visitPre(DocSimpleListItem *); + void visitPost(DocSimpleListItem *); + void visitPre(DocSection *s); + void visitPost(DocSection *); + void visitPre(DocHtmlList *s); + void visitPost(DocHtmlList *s); + void visitPre(DocHtmlListItem *); + void visitPost(DocHtmlListItem *); + //void visitPre(DocHtmlPre *); + //void visitPost(DocHtmlPre *); + void visitPre(DocHtmlDescList *); + void visitPost(DocHtmlDescList *); + void visitPre(DocHtmlDescTitle *); + void visitPost(DocHtmlDescTitle *); + void visitPre(DocHtmlDescData *); + void visitPost(DocHtmlDescData *); + void visitPre(DocHtmlTable *t); + void visitPost(DocHtmlTable *t); + void visitPre(DocHtmlCaption *); + void visitPost(DocHtmlCaption *); + void visitPre(DocHtmlRow *); + void visitPost(DocHtmlRow *) ; + void visitPre(DocHtmlCell *); + void visitPost(DocHtmlCell *); + void visitPre(DocInternal *); + void visitPost(DocInternal *); + void visitPre(DocHRef *); + void visitPost(DocHRef *); + void visitPre(DocHtmlHeader *); + void visitPost(DocHtmlHeader *) ; + void visitPre(DocImage *); + void visitPost(DocImage *); + void visitPre(DocDotFile *); + void visitPost(DocDotFile *); + void visitPre(DocMscFile *); + void visitPost(DocMscFile *); + void visitPre(DocLink *); + void visitPost(DocLink *); + void visitPre(DocRef *ref); + void visitPost(DocRef *); + void visitPre(DocSecRefItem *); + void visitPost(DocSecRefItem *); + void visitPre(DocSecRefList *); + void visitPost(DocSecRefList *); + void visitPre(DocParamSect *); + void visitPost(DocParamSect *); + void visitPre(DocParamList *); + void visitPost(DocParamList *); + void visitPre(DocXRefItem *); + void visitPost(DocXRefItem *); + void visitPre(DocInternalRef *); + void visitPost(DocInternalRef *); + void visitPre(DocCopy *); + void visitPost(DocCopy *); + void visitPre(DocText *); + void visitPost(DocText *); + void visitPre(DocHtmlBlockQuote *); + void visitPost(DocHtmlBlockQuote *); + + private: + + //-------------------------------------- + // helper functions + //-------------------------------------- + + void filter(const char *str,bool verbatim=FALSE); + void startLink(const QCString &ref,const QCString &file, + const QCString &anchor); + void endLink(const QCString &ref); + QCString getStyle(const char *name); + void incIndentLevel(); + void decIndentLevel(); + + void pushEnabled(); + void popEnabled(); + void writeDotFile(const QCString &fileName); + void writeMscFile(const QCString &fileName); + + //-------------------------------------- + // state variables + //-------------------------------------- + + FTextStream &m_t; + CodeOutputInterface &m_ci; + bool m_insidePre; + bool m_hide; + int m_indentLevel; + QStack m_enabled; + bool m_lastIsPara; + QCString m_langExt; +}; + +#endif diff --git a/trunk/src/rtfgen.cpp b/trunk/src/rtfgen.cpp new file mode 100644 index 0000000..90d6e4c --- /dev/null +++ b/trunk/src/rtfgen.cpp @@ -0,0 +1,2931 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 by Parker Waechter & Dimitri van Heesch. + * + * Style sheet additions by Alexander Bartolich + * + * 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. + * + */ + +#include + +#include "qtbc.h" +#include +#include + +#include "rtfgen.h" +#include "config.h" +#include "message.h" +#include "doxygen.h" +#include "util.h" +#include "diagram.h" +#include "language.h" +#include "dot.h" +#include "version.h" +#include "pagedef.h" +#include "rtfstyle.h" +#include "rtfdocvisitor.h" +#include "docparser.h" +#include "dirdef.h" +#include "vhdldocgen.h" +#include "portable.h" + +//#define DBG_RTF(x) x; +#define DBG_RTF(x) + +static QCString dateToRTFDateString() +{ + const QDateTime &d = QDateTime::currentDateTime(); + QCString result; + result.sprintf("\\yr%d\\mo%d\\dy%d\\hr%d\\min%d\\sec%d", + d.date().year(), d.date().month(), d.date().day(), + d.time().hour(),d.time().minute(),d.time().second()); + return result; +} + +RTFGenerator::RTFGenerator() : OutputGenerator() +{ + dir=Config_getString("RTF_OUTPUT"); + col=0; + //insideTabbing=FALSE; + m_listLevel = 0; + m_bstartedBody = FALSE; + m_omitParagraph = FALSE; + m_numCols = 0; +} + +RTFGenerator::~RTFGenerator() +{ +} + +//void RTFGenerator::append(const OutputGenerator *g) +//{ +// t << g->getContents(); +// col+=((RTFGenerator *)g)->col; +// //insideTabbing=insideTabbing || ((RTFGenerator *)g)->insideTabbing; +// m_listLevel=((RTFGenerator *)g)->m_listLevel; +// m_omitParagraph=((RTFGenerator *)g)->m_omitParagraph; +// //printf("RTFGenerator::append(%s) insideTabbing=%s\n", g->getContents().data(), +// // insideTabbing ? "TRUE" : "FALSE" ); +//} + +//OutputGenerator *RTFGenerator::copy() +//{ +// RTFGenerator *result = new RTFGenerator; +// //result->insideTabbing=insideTabbing; +// result->m_listLevel=m_listLevel; +// result->m_omitParagraph=m_omitParagraph; +// return result; +//} + +void RTFGenerator::writeStyleSheetFile(QFile &file) +{ + QTextStream t(&file); + t << "# Generated by doxygen " << versionString << "\n\n"; + t << "# This file describes styles used for generating RTF output.\n"; + t << "# All text after a hash (#) is considered a comment and will be ignored.\n"; + t << "# Remove a hash to activate a line.\n\n"; + + int i; + for ( i=0 ; rtf_Style_Default[i].reference!=0 ; i++ ) + { + t << "# " << rtf_Style_Default[i].name << " = " + << rtf_Style_Default[i].reference + << rtf_Style_Default[i].definition << endl; + } +} + +void RTFGenerator::writeExtensionsFile(QFile &file) +{ + QTextStream t(&file); + t << "# Generated by doxygen " << versionString << "\n\n"; + t << "# This file describes extensions used for generating RTF output.\n"; + t << "# All text after a hash (#) is considered a comment and will be ignored.\n"; + t << "# Remove a hash to activate a line.\n\n"; + + t << "# Overrides the project title.\n"; + + t << "#Title = \n\n"; + + t << "# Name of the company that produced this document.\n"; + t << "#Company = \n\n"; + + t << "# Filename of a company or project logo.\n"; + t << "#LogoFilename = \n\n"; + + t << "# Author of the document.\n"; + t << "#Author = \n\n"; + + t << "# Type of document (e.g. Design Specification, User Manual, etc.).\n"; + t << "#DocumentType = \n\n"; + + t << "# Document tracking number.\n"; + t << "#DocumentId = \n\n"; + + t << "# Name of the author's manager.\n"; + t << "# This field is not displayed in the document itself, but it is \n"; + t << "# available in the information block of the rtf file. In Microsoft \n"; + t << "# Word, it is available under File:Properties.\n"; + t << "#Manager = \n\n"; + + t << "# Subject of the document.\n"; + t << "# This field is not displayed in the document itself, but it is \n"; + t << "# available in the information block of the rtf file. In Microsoft \n"; + t << "# Word, it is available under File:Properties.\n"; + t << "#Subject = \n\n"; + + t << "# Comments regarding the document.\n"; + t << "# This field is not displayed in the document itself, but it is \n"; + t << "# available in the information block of the rtf file. In Microsoft \n"; + t << "# Word, it is available under File:Properties.\n"; + t << "#Comments = \n\n"; + + t << "# Keywords associated with the document.\n"; + t << "# This field is not displayed in the document itself, but it is \n"; + t << "# available in the information block of the rtf file. In Microsoft \n"; + t << "# Word, it is available under File:Properties.\n"; + t << "#Keywords = \n\n"; +} + + +void RTFGenerator::init() +{ + QCString dir=Config_getString("RTF_OUTPUT"); + QDir d(dir); + if (!d.exists() && !d.mkdir(dir)) + { + err("Could not create output directory %s\n",dir.data()); + exit(1); + } + rtf_Style.setAutoDelete(TRUE); + + // first duplicate strings of rtf_Style_Default + const struct Rtf_Style_Default* def = rtf_Style_Default; + while(def->reference != 0) + { + if (def->definition == 0) + err("Internal error: rtf_Style_Default[%s] has no definition.\n", def->name); + StyleData* styleData = new StyleData(def->reference, def->definition); + rtf_Style.insert(def->name, styleData); + def++; + } + + // overwrite some (or all) definitions from file + QCString &rtfStyleSheetFile = Config_getString("RTF_STYLESHEET_FILE"); + if (!rtfStyleSheetFile.isEmpty()) + { + loadStylesheet(rtfStyleSheetFile, rtf_Style); + } + + // If user has defined an extension file, load its contents. + QCString &rtfExtensionsFile = Config_getString("RTF_EXTENSIONS_FILE"); + if (!rtfExtensionsFile.isEmpty()) + { + loadExtensions(rtfExtensionsFile); + } + + createSubDirs(d); +} + +static QCString makeIndexName(const char *s,int i) +{ + QCString result=s; + result+=(char)(i+'0'); + return result; +} + +void RTFGenerator::beginRTFDocument() +{ + /* all the included RTF files should begin with the + * same header + */ + t <<"{\\rtf1\\ansi\\ansicpg" << theTranslator->trRTFansicp(); + t <<"\\uc1 \\deff0\\deflang1033\\deflangfe1033\n"; + + DBG_RTF(t <<"{\\comment Begining font list}\n") + t <<"{\\fonttbl "; + t <<"{\\f0\\froman\\fcharset" << theTranslator->trRTFCharSet(); + t <<"\\fprq2{\\*\\panose 02020603050405020304}Times New Roman;}\n"; + t <<"{\\f1\\fswiss\\fcharset" << theTranslator->trRTFCharSet(); + t <<"\\fprq2{\\*\\panose 020b0604020202020204}Arial;}\n"; + t <<"{\\f2\\fmodern\\fcharset" << theTranslator->trRTFCharSet(); + t <<"\\fprq1{\\*\\panose 02070309020205020404}Courier New;}\n"; + t <<"{\\f3\\froman\\fcharset2\\fprq2{\\*\\panose 05050102010706020507}Symbol;}\n"; + t <<"}\n"; + DBG_RTF(t <<"{\\comment begin colors}\n") + t <<"{\\colortbl;"; + t <<"\\red0\\green0\\blue0;"; + t <<"\\red0\\green0\\blue255;"; + t <<"\\red0\\green255\\blue255;"; + t <<"\\red0\\green255\\blue0;"; + t <<"\\red255\\green0\\blue255;"; + t <<"\\red255\\green0\\blue0;"; + t <<"\\red255\\green255\\blue0;"; + t <<"\\red255\\green255\\blue255;"; + t <<"\\red0\\green0\\blue128;"; + t <<"\\red0\\green128\\blue128;"; + t <<"\\red0\\green128\\blue0;"; + t <<"\\red128\\green0\\blue128;"; + t <<"\\red128\\green0\\blue0;"; + t <<"\\red128\\green128\\blue0;"; + t <<"\\red128\\green128\\blue128;"; + t <<"\\red192\\green192\\blue192;}" << endl; + + DBG_RTF(t <<"{\\comment Beginning style list}\n") + t <<"{\\stylesheet\n"; + t <<"{\\widctlpar\\adjustright \\fs20\\cgrid \\snext0 Normal;}\n"; + + // sort styles ascending by \s-number via an intermediate QArray + QArray array(128); + array.fill(0); + QDictIterator iter(rtf_Style); + const StyleData* style; + for(; (style = iter.current()); ++iter) + { + unsigned index = style->index; + unsigned size = array.size(); + if (index >= size) + { + // +1 to add at least one element, then align up to multiple of 8 + array.resize((index + 1 + 7) & ~7); + array.fill(0, size); + ASSERT(index < array.size()); + } + if (array.at(index) != 0) + { + QCString key(convertToQCString(iter.currentKey())); + msg("Style '%s' redefines \\s%d.\n", key.data(), index); + } + array.at(index) = style; + } + + // write array elements + unsigned size = array.size(); + for(unsigned i = 0; i < size; i++) + { + const StyleData* style = array.at(i); + if (style != 0) + t <<"{" << style->reference << style->definition << ";}\n"; + } + + t <<"}" << endl; + // this comment is needed for postprocessing! + t <<"{\\comment begin body}" << endl; + +} + +void RTFGenerator::beginRTFChapter() +{ + t <<"\n"; + DBG_RTF(t << "{\\comment BeginRTFChapter}\n") + t << rtf_Style_Reset; + + // if we are compact, no extra page breaks... + if (Config_getBool("COMPACT_RTF")) + { + // t <<"\\sect\\sectd\\sbknone\n"; + t <<"\\sect\\sbknone\n"; + rtfwriteRuler_thick(); + } + else + t <<"\\sect\\sbkpage\n"; + //t <<"\\sect\\sectd\\sbkpage\n"; + + t << rtf_Style["Heading1"]->reference << "\n"; +} + +void RTFGenerator::beginRTFSection() +{ + t <<"\n"; + DBG_RTF(t << "{\\comment BeginRTFSection}\n") + t << rtf_Style_Reset; + + // if we are compact, no extra page breaks... + if (Config_getBool("COMPACT_RTF")) + { + // t <<"\\sect\\sectd\\sbknone\n"; + t <<"\\sect\\sbknone\n"; + rtfwriteRuler_emboss(); + } + else + t <<"\\sect\\sbkpage\n"; + //t <<"\\sect\\sectd\\sbkpage\n"; + + t << rtf_Style["Heading2"]->reference << "\n"; +} + +void RTFGenerator::startFile(const char *name,const char *,const char *) +{ + //setEncoding(QCString().sprintf("CP%s",theTranslator->trRTFansicp())); + QCString fileName=name; + relPath = relativePathToRoot(fileName); + + if (fileName.right(4)!=".rtf" ) fileName+=".rtf"; + startPlainFile(fileName); + beginRTFDocument(); +} + +void RTFGenerator::endFile() +{ + DBG_RTF(t << "{\\comment endFile}\n") + t << "}"; + + endPlainFile(); +} + +void RTFGenerator::startProjectNumber() +{ + DBG_RTF(t <<"{\\comment startProjectNumber }" << endl) + t << " "; +} + +void RTFGenerator::endProjectNumber() +{ + DBG_RTF(t <<"{\\comment endProjectNumber }" << endl) +} + +void RTFGenerator::startIndexSection(IndexSections is) +{ + //QCString paperName; + + m_listLevel = 0; + + switch (is) + { + case isTitlePageStart: + // basic RTFstart + // get readyfor author etc + + t << "{\\info \n"; + t << "{\\title {\\comment "; + break; + case isTitlePageAuthor: + t << "}\n"; + if (rtf_subject) t << "{\\subject " << rtf_subject << "}\n"; + if (rtf_comments) t << "{\\comment " << rtf_comments << "}\n"; + if (rtf_company) t << "{\\company " << rtf_company << "}\n"; + if (rtf_author) t << "{\\author " << rtf_author << "}\n"; + if (rtf_manager) t << "{\\manager " << rtf_manager << "}\n"; + if (rtf_documentType) t << "{\\category " << rtf_documentType << "}\n"; + if (rtf_keywords) t << "{\\keywords " << rtf_keywords << "}\n"; + t << "{\\comment "; + break; + case isMainPage: + //Introduction + beginRTFChapter(); + break; + //case isPackageIndex: + // //Package Index + // beginRTFChapter(); + // break; + case isModuleIndex: + //Module Index + beginRTFChapter(); + break; + case isDirIndex: + //Directory Index + beginRTFChapter(); + break; + case isNamespaceIndex: + //Namespace Index + beginRTFChapter(); + break; + case isClassHierarchyIndex: + //Hierarchical Index + DBG_RTF(t << "{\\comment start classhierarchy}\n") + beginRTFChapter(); + break; + case isCompoundIndex: + //Annotated Compound Index + beginRTFChapter(); + break; + case isFileIndex: + //Annotated File Index + beginRTFChapter(); + break; + case isPageIndex: + //Related Page Index + beginRTFChapter(); + break; + case isModuleDocumentation: + { + //Module Documentation + GroupSDict::Iterator gli(*Doxygen::groupSDict); + GroupDef *gd; + bool found=FALSE; + for (gli.toFirst();(gd=gli.current()) && !found;++gli) + { + if (!gd->isReference()) + { + beginRTFChapter(); + found=TRUE; + } + } + } + break; + case isDirDocumentation: + { + //Directory Documentation + SDict::Iterator dli(*Doxygen::directories); + DirDef *dd; + bool found=FALSE; + for (dli.toFirst();(dd=dli.current()) && !found;++dli) + { + if (dd->isLinkableInProject()) + { + beginRTFChapter(); + found=TRUE; + } + } + } + break; + case isNamespaceDocumentation: + { + // Namespace Documentation + NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict); + NamespaceDef *nd; + bool found=FALSE; + for (nli.toFirst();(nd=nli.current()) && !found;++nli) + { + if (nd->isLinkableInProject()) + { + beginRTFChapter(); + found=TRUE; + } + } + } + break; + case isClassDocumentation: + { + //Compound Documentation + ClassSDict::Iterator cli(*Doxygen::classSDict); + ClassDef *cd=0; + bool found=FALSE; + for (cli.toFirst();(cd=cli.current()) && !found;++cli) + { + if (cd->isLinkableInProject() && + cd->templateMaster()==0 && + !cd->isEmbeddedInOuterScope() + ) + { + beginRTFChapter(); + found=TRUE; + } + } + } + break; + case isFileDocumentation: + { + //File Documentation + bool isFirst=TRUE; + FileName *fn=Doxygen::inputNameList->first(); + while (fn) + { + FileDef *fd=fn->first(); + while (fd) + { + if (fd->isLinkableInProject()) + { + if (isFirst) + { + beginRTFChapter(); + isFirst=FALSE; + break; + } + } + fd=fn->next(); + } + fn=Doxygen::inputNameList->next(); + } + } + break; + case isExampleDocumentation: + { + //Example Documentation + beginRTFChapter(); + } + break; + case isPageDocumentation: + { + //Page Documentation + beginRTFChapter(); + } + break; + case isPageDocumentation2: + { + t << "{\\tc \\v "; + } + break; + case isEndIndex: + break; + } +} + +void RTFGenerator::endIndexSection(IndexSections is) +{ + bool fortranOpt = Config_getBool("OPTIMIZE_FOR_FORTRAN"); + bool vhdlOpt = Config_getBool("OPTIMIZE_OUTPUT_VHDL"); + switch (is) + { + case isTitlePageStart: + if (rtf_title) + // User has overridden document title in extensions file + t << "}" << rtf_title; + else + t << "}" << Config_getString("PROJECT_NAME"); + break; + case isTitlePageAuthor: + { + t << "Doxgyen. }\n"; + t << "{\\creatim " << dateToRTFDateString() << "}\n}"; + DBG_RTF(t << "{\\comment end of infoblock}\n"); + // setup for this section + t << rtf_Style_Reset <<"\n"; + t <<"\\sectd\\pgnlcrm\n"; + t <<"{\\footer "<reference << "{\\chpgn}}\n"; + // the title entry + DBG_RTF(t << "{\\comment begin title page}\n") + + + t << rtf_Style_Reset << rtf_Style["SubTitle"]->reference << endl; // set to title style + + t << "\\vertalc\\qc\\par\\par\\par\\par\\par\\par\\par\n"; + if (rtf_logoFilename) + { + t << "{\\field\\flddirty {\\*\\fldinst INCLUDEPICTURE \"" << rtf_logoFilename; + t << "\" \\\\d \\\\*MERGEFORMAT} {\\fldrslt IMAGE }}\\par\\par\n"; + } + if (rtf_company) + { + t << rtf_company << "\\par\\par\n"; + } + + t << rtf_Style_Reset << rtf_Style["Title"]->reference << endl; // set to title style + t << "{\\field\\fldedit {\\*\\fldinst TITLE \\\\*MERGEFORMAT}{\\fldrslt TITLE}}\\par" << endl; + + t << rtf_Style_Reset << rtf_Style["SubTitle"]->reference << endl; // set to title style + t << "\\par\n"; + if (rtf_documentType) + { + t << rtf_documentType << "\\par\n"; + } + if (rtf_documentId) + { + t << rtf_documentId << "\\par\n"; + } + t << "\\par\\par\\par\\par\\par\\par\\par\\par\\par\\par\\par\\par\n"; + + t << rtf_Style_Reset << rtf_Style["SubTitle"]->reference << endl; // set to subtitle style + t << "{\\field\\fldedit {\\*\\fldinst AUTHOR \\\\*MERGEFORMAT}{\\fldrslt AUTHOR}}\\par" << endl; + t << "Version " << Config_getString("PROJECT_NUMBER") << "\\par"; + t << "{\\field\\fldedit {\\*\\fldinst CREATEDATE \\\\*MERGEFORMAT}" + "{\\fldrslt CREATEDATE}}\\par"<reference; + t << theTranslator->trRTFTableOfContents() << "\\par"<< endl; + t << rtf_Style_Reset << "\\par" << endl; + t << "{\\field\\fldedit {\\*\\fldinst TOC \\\\f \\\\*MERGEFORMAT}{\\fldrslt Table of contents}}\\par\n"; + t << rtf_Style_Reset << endl; + } + break; + case isMainPage: + t << "\\par " << rtf_Style_Reset << endl; + if (!Doxygen::mainPage || Doxygen::mainPage->title().isEmpty()) + { + t << "{\\tc \\v " << theTranslator->trMainPage() << "}"<< endl; + } + else + { + t << "{\\tc \\v " << substitute(Doxygen::mainPage->title(),"%","") << "}"<< endl; + } + t << "{\\field\\fldedit{\\*\\fldinst INCLUDETEXT \""; + //if (Config_getBool("GENERATE_TREEVIEW")) t << "main"; else t << "index"; + t << "index"; + t << ".rtf\" \\\\*MERGEFORMAT}{\\fldrslt includedstuff}}\n"; + break; + //case isPackageIndex: + // t << "\\par " << rtf_Style_Reset << endl; + // t << "{\\tc \\v " << theTranslator->trPackageList() << "}"<< endl; + // t << "{\\field\\fldedit{\\*\\fldinst INCLUDETEXT \"packages.rtf\" \\\\*MERGEFORMAT}{\\fldrslt includedstuff}}\n"; + // break; + case isModuleIndex: + t << "\\par " << rtf_Style_Reset << endl; + t << "{\\tc \\v " << theTranslator->trModuleIndex() << "}"<< endl; + t << "{\\field\\fldedit{\\*\\fldinst INCLUDETEXT \"modules.rtf\" \\\\*MERGEFORMAT}{\\fldrslt includedstuff}}\n"; + break; + case isDirIndex: + t << "\\par " << rtf_Style_Reset << endl; + t << "{\\tc \\v " << theTranslator->trDirIndex() << "}"<< endl; + t << "{\\field\\fldedit{\\*\\fldinst INCLUDETEXT \"dirs.rtf\" \\\\*MERGEFORMAT}{\\fldrslt includedstuff}}\n"; + break; + case isNamespaceIndex: + t << "\\par " << rtf_Style_Reset << endl; + if (fortranOpt) + { + t << "{\\tc \\v " << theTranslator->trModulesIndex() << "}" << endl; + } + else + { + t << "{\\tc \\v " << theTranslator->trNamespaceIndex() << "}" << endl; + } + + t << "{\\field\\fldedit{\\*\\fldinst INCLUDETEXT \"namespaces.rtf\" \\\\*MERGEFORMAT}{\\fldrslt includedstuff}}\n"; + break; + case isClassHierarchyIndex: + t << "\\par " << rtf_Style_Reset << endl; + t << "{\\tc \\v " << theTranslator->trHierarchicalIndex() << "}"<< endl; + t << "{\\field\\fldedit{\\*\\fldinst INCLUDETEXT \"hierarchy.rtf\" \\\\*MERGEFORMAT}{\\fldrslt includedstuff}}\n"; + break; + case isCompoundIndex: + t << "\\par " << rtf_Style_Reset << endl; + if (fortranOpt) + { + t << "{\\tc \\v " << theTranslator->trCompoundIndexFortran() << "}"<< endl; + } + else if (vhdlOpt) + { + t << "{\\tc \\v " << VhdlDocGen::trDesignUnitIndex() << "}"<< endl; + } + else + { + t << "{\\tc \\v " << theTranslator->trCompoundIndex() << "}"<< endl; + } + t << "{\\field\\fldedit{\\*\\fldinst INCLUDETEXT \"annotated.rtf\" \\\\*MERGEFORMAT}{\\fldrslt includedstuff}}\n"; + break; + case isFileIndex: + t << "\\par " << rtf_Style_Reset << endl; + t << "{\\tc \\v " << theTranslator->trFileIndex() << "}"<< endl; + t << "{\\field\\fldedit{\\*\\fldinst INCLUDETEXT \"files.rtf\" \\\\*MERGEFORMAT}{\\fldrslt includedstuff}}\n"; + break; + case isPageIndex: + t << "\\par " << rtf_Style_Reset << endl; + t << "{\\tc \\v " << theTranslator->trPageIndex() << "}"<< endl; + t << "{\\field\\fldedit{\\*\\fldinst INCLUDETEXT \"pages.rtf\" \\\\*MERGEFORMAT}{\\fldrslt includedstuff}}\n"; + break; + case isModuleDocumentation: + { + GroupSDict::Iterator gli(*Doxygen::groupSDict); + GroupDef *gd; + t << "{\\tc \\v " << theTranslator->trModuleDocumentation() << "}"<< endl; + for (gli.toFirst();(gd=gli.current());++gli) + { + if (!gd->isReference()) + { + t << "\\par " << rtf_Style_Reset << endl; + t << "{\\field\\fldedit{\\*\\fldinst INCLUDETEXT \""; + t << gd->getOutputFileBase(); + t << ".rtf\" \\\\*MERGEFORMAT}{\\fldrslt includedstuff}}\n"; + } + } + } + break; + case isDirDocumentation: + { + SDict::Iterator dli(*Doxygen::directories); + DirDef *dd; + t << "{\\tc \\v " << theTranslator->trDirDocumentation() << "}"<< endl; + for (dli.toFirst();(dd=dli.current());++dli) + { + if (dd->isLinkableInProject()) + { + t << "\\par " << rtf_Style_Reset << endl; + t << "{\\field\\fldedit{\\*\\fldinst INCLUDETEXT \""; + t << dd->getOutputFileBase(); + t << ".rtf\" \\\\*MERGEFORMAT}{\\fldrslt includedstuff}}\n"; + } + } + } + break; + case isNamespaceDocumentation: + { + NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict); + NamespaceDef *nd; + bool found=FALSE; + for (nli.toFirst();(nd=nli.current()) && !found;++nli) + { + if (nd->isLinkableInProject()) + { + t << "\\par " << rtf_Style_Reset << endl; + t << "{\\field\\fldedit{\\*\\fldinst INCLUDETEXT \""; + t << nd->getOutputFileBase(); + t << ".rtf\" \\\\*MERGEFORMAT}{\\fldrslt includedstuff}}\n"; + found=TRUE; + } + } + while ((nd=nli.current())) + { + if (nd->isLinkableInProject()) + { + t << "\\par " << rtf_Style_Reset << endl; + beginRTFSection(); + t << "{\\field\\fldedit{\\*\\fldinst INCLUDETEXT \""; + t << nd->getOutputFileBase(); + t << ".rtf\" \\\\*MERGEFORMAT}{\\fldrslt includedstuff}}\n"; + } + ++nli; + } + } + break; + case isClassDocumentation: + { + ClassSDict::Iterator cli(*Doxygen::classSDict); + ClassDef *cd=0; + bool found=FALSE; + if (fortranOpt) + { + t << "{\\tc \\v " << theTranslator->trTypeDocumentation() << "}"<< endl; + } + else + { + t << "{\\tc \\v " << theTranslator->trClassDocumentation() << "}"<< endl; + } + for (cli.toFirst();(cd=cli.current()) && !found;++cli) + { + if (cd->isLinkableInProject() && + cd->templateMaster()==0 && + !cd->isEmbeddedInOuterScope() + ) + { + t << "\\par " << rtf_Style_Reset << endl; + t << "{\\field\\fldedit{\\*\\fldinst INCLUDETEXT \""; + t << cd->getOutputFileBase(); + t << ".rtf\" \\\\*MERGEFORMAT}{\\fldrslt includedstuff}}\n"; + found=TRUE; + } + } + for (;(cd=cli.current());++cli) + { + if (cd->isLinkableInProject() && + cd->templateMaster()==0 && + !cd->isEmbeddedInOuterScope() + ) + { + t << "\\par " << rtf_Style_Reset << endl; + beginRTFSection(); + t << "{\\field\\fldedit{\\*\\fldinst INCLUDETEXT \""; + t << cd->getOutputFileBase(); + t << ".rtf\" \\\\*MERGEFORMAT}{\\fldrslt includedstuff}}\n"; + } + } + } + break; + case isFileDocumentation: + { + bool isFirst=TRUE; + FileName *fn=Doxygen::inputNameList->first(); + + t << "{\\tc \\v " << theTranslator->trFileDocumentation() << "}"<< endl; + while (fn) + { + FileDef *fd=fn->first(); + while (fd) + { + if (fd->isLinkableInProject()) + { + if (isFirst) + { + t << "\\par " << rtf_Style_Reset << endl; + t << "{\\field\\fldedit{\\*\\fldinst INCLUDETEXT \""; + t << fd->getOutputFileBase(); + t << ".rtf\" \\\\*MERGEFORMAT}{\\fldrslt includedstuff}}\n"; + isFirst=FALSE; + } + else + { + t << "\\par " << rtf_Style_Reset << endl; + beginRTFSection(); + t << "{\\field\\fldedit{\\*\\fldinst INCLUDETEXT \""; + t << fd->getOutputFileBase(); + t << ".rtf\" \\\\*MERGEFORMAT}{\\fldrslt includedstuff}}\n"; + } + } + fd=fn->next(); + } + fn=Doxygen::inputNameList->next(); + } + } + break; + case isExampleDocumentation: + { + //t << "}\n"; + t << "{\\tc \\v " << theTranslator->trExampleDocumentation() << "}"<< endl; + PageSDict::Iterator pdi(*Doxygen::exampleSDict); + PageDef *pd=pdi.toFirst(); + if (pd) + { + t << "\\par " << rtf_Style_Reset << endl; + t << "{\\field\\fldedit{\\*\\fldinst INCLUDETEXT \""; + t << pd->getOutputFileBase(); + t << ".rtf\" \\\\*MERGEFORMAT}{\\fldrslt includedstuff}}\n"; + } + for (++pdi;(pd=pdi.current());++pdi) + { + t << "\\par " << rtf_Style_Reset << endl; + beginRTFSection(); + t << "{\\field\\fldedit{\\*\\fldinst INCLUDETEXT \""; + t << pd->getOutputFileBase(); + t << ".rtf\" \\\\*MERGEFORMAT}{\\fldrslt includedstuff}}\n"; + } + } + break; + case isPageDocumentation: + { +//#error "fix me in the same way as the latex index..." + //t << "{\\tc \\v " << theTranslator->trPageDocumentation() << "}"<< endl; + //t << "}"<< endl; + //PageSDict::Iterator pdi(*Doxygen::pageSDict); + //PageDef *pd=pdi.toFirst(); + //bool first=TRUE; + //for (pdi.toFirst();(pd=pdi.current());++pdi) + //{ + // if (!pd->getGroupDef() && !pd->isReference()) + // { + // if (first) t << "\\par " << rtf_Style_Reset << endl; + // t << "{\\field\\fldedit{\\*\\fldinst INCLUDETEXT \""; + // t << pd->getOutputFileBase(); + // t << ".rtf\" \\\\*MERGEFORMAT}{\\fldrslt includedstuff}}\n"; + // first=FALSE; + // } + //} + } + break; + case isPageDocumentation2: + { + t << "}"; + t << "\\par " << rtf_Style_Reset << endl; + } + break; + case isEndIndex: + beginRTFChapter(); + t << rtf_Style["Heading1"]->reference; + t << theTranslator->trRTFGeneralIndex() << "\\par "<< endl; + t << rtf_Style_Reset << endl; + t << "{\\tc \\v " << theTranslator->trRTFGeneralIndex() << "}" << endl; + t << "{\\field\\fldedit {\\*\\fldinst INDEX \\\\c2 \\\\*MERGEFORMAT}{\\fldrslt INDEX}}\n"; + + break; + } +} + +void RTFGenerator::writePageLink(const char *name,bool first) +{ + if (first) t << "\\par " << rtf_Style_Reset << endl; + t << "{\\field\\fldedit{\\*\\fldinst INCLUDETEXT \""; + t << name; + t << ".rtf\" \\\\*MERGEFORMAT}{\\fldrslt includedstuff}}\n"; +} + +void RTFGenerator::lastIndexPage() +{ + DBG_RTF(t <<"{\\comment Beginning Body of RTF Document}\n") + // end page and setup for rest of document + t <<"\\sect \\sbkpage \\pgndec \\pgnrestart\n"; + t <<"\\sect \\sectd \\sbknone\n"; + + // set new footer with arabic numbers + t <<"{\\footer "<< rtf_Style["Footer"]->reference << "{\\chpgn}}\n"; + //t << rtf_Style["Heading1"]->reference << "\n"; + +} + +void RTFGenerator::writeStyleInfo(int) +{ +} + +void RTFGenerator::lineBreak(const char *) +{ + DBG_RTF(t << "{\\comment (lineBreak)}" << endl) + t << "\\par" << endl; + m_omitParagraph = TRUE; +} + +void RTFGenerator::writeString(const char *text) +{ + t << text; +} + +void RTFGenerator::startIndexList() +{ + DBG_RTF(t << "{\\comment (startIndexList)}" << endl) + t << "{" << endl; + t << "\\par" << endl; + incrementIndentLevel(); + t << rtf_Style_Reset << rtf_LCList_DepthStyle() << endl; + m_omitParagraph = TRUE; +} + +void RTFGenerator::endIndexList() +{ + DBG_RTF(t << "{\\comment (endIndexList)}" << endl) + if (!m_omitParagraph) + { + t << "\\par"; + m_omitParagraph = TRUE; + } + t << "}"; + decrementIndentLevel(); +} + +/*! start bullet list */ +void RTFGenerator::startItemList() +{ + newParagraph(); + DBG_RTF(t << "{\\comment (startItemList level=" << m_listLevel << ") }" << endl) + t << "{"; + incrementIndentLevel(); + rtf_listItemInfo[m_listLevel].isEnum = FALSE; +} + +/*! end bullet list */ +void RTFGenerator::endItemList() +{ + newParagraph(); + DBG_RTF(t << "{\\comment (endItemList level=" << m_listLevel << ")}" << endl) + t << "}"; + decrementIndentLevel(); + m_omitParagraph = TRUE; +} + +///*! start enumeration list */ +//void RTFGenerator::startEnumList() // starts an enumeration list +//{ +// DBG_RTF(t << "{\\comment (startEnumList)}" << endl) +// t << "{" << endl; +// incrementIndentLevel(); +// rtf_listItemInfo[m_listLevel].isEnum = TRUE; +// rtf_listItemInfo[m_listLevel].number = 1; +//} +// +///*! end enumeration list */ +//void RTFGenerator::endEnumList() +//{ +// newParagraph(); +// DBG_RTF(t << "{\\comment (endEnumList)}" << endl) +// t << "}"; +// decrementIndentLevel(); +// m_omitParagraph = TRUE; +//} + +/*! write bullet or enum item */ +void RTFGenerator::startItemListItem() +{ + DBG_RTF(t << "{\\comment (startItemListItem)}" << endl) + newParagraph(); + t << rtf_Style_Reset; + if (rtf_listItemInfo[m_listLevel].isEnum) + { + t << rtf_EList_DepthStyle() << endl; + t << rtf_listItemInfo[m_listLevel].number << ".\\tab "; + rtf_listItemInfo[m_listLevel].number++; + } + else + { + t << rtf_BList_DepthStyle() << endl; + } + m_omitParagraph = TRUE; +} + +void RTFGenerator::endItemListItem() +{ + DBG_RTF(t << "{\\comment (endItemListItem)}" << endl) +} + +void RTFGenerator::startIndexItem(const char *,const char *) +{ + DBG_RTF(t << "{\\comment (startIndexItem)}" << endl) + + if (!m_omitParagraph) + { + t << "\\par" << endl; + m_omitParagraph = TRUE; + } +} + +void RTFGenerator::endIndexItem(const char *ref,const char *fn) +{ + DBG_RTF(t << "{\\comment (endIndexItem)}" << endl) + if (!ref && fn) + { + t << "\\tab "; + writeRTFReference(fn); + t << endl; + } + else + { + t << endl; + } + m_omitParagraph = TRUE; +} + +//void RTFGenerator::writeIndexFileItem(const char *,const char *text) +//{ +// t << "\\item\\contentsline{section}{"; +// docify(text); +// t << "}{\\pageref{" << text << "}}" << endl; +//} + +void RTFGenerator::startHtmlLink(const char *url) +{ + + if (Config_getBool("RTF_HYPERLINKS")) + { + t << "{\\field {\\*\\fldinst { HYPERLINK \\\\l \""; + t << url; + t << "\" }{}"; + t << "}{\\fldrslt {\\cs37\\ul\\cf2 "; + } + else + { + startTypewriter(); + } +} + +void RTFGenerator::endHtmlLink() +{ + if (Config_getBool("RTF_HYPERLINKS")) + { + t << "}}}" << endl; + } + else + { + endTypewriter(); + } +} + +//void RTFGenerator::writeMailLink(const char *url) +//{ +// startTypewriter(); +// docify(url); +// endTypewriter(); +//} + +void RTFGenerator::writeStartAnnoItem(const char *,const char *f, + const char *path,const char *name) +{ + DBG_RTF(t << "{\\comment (writeStartAnnoItem)}" << endl) + t << "{\\b "; + if (path) docify(path); + if (f && Config_getBool("RTF_HYPERLINKS")) + { + t << "{\\field {\\*\\fldinst { HYPERLINK \\\\l \""; + t << rtfFormatBmkStr(f); + t << "\" }{}"; + t << "}{\\fldrslt {\\cs37\\ul\\cf2 "; + + docify(name); + + t << "}}}" << endl; + } + else + { + docify(name); + } + t << "} "; +} + +void RTFGenerator::writeEndAnnoItem(const char *name) +{ + DBG_RTF(t << "{\\comment (writeEndAnnoItem)}" << endl) + if (name) + { + t << "\\tab "; + writeRTFReference(name); + t << endl; + } + else + { + t << endl; + } + newParagraph(); +} + +void RTFGenerator::startIndexKey() +{ + DBG_RTF(t << "{\\comment (startIndexKey)}" << endl) + t << "{\\b "; +} + +void RTFGenerator::endIndexKey() +{ + DBG_RTF(t << "{\\comment (endIndexKey)}" << endl) +} + +void RTFGenerator::startIndexValue(bool hasBrief) +{ + DBG_RTF(t << "{\\comment (startIndexValue)}" << endl) + t << " "; + if (hasBrief) t << "("; +} + +void RTFGenerator::endIndexValue(const char *name,bool hasBrief) +{ + DBG_RTF(t << "{\\comment (endIndexValue)}" << endl) + if (hasBrief) t << ")"; + t << "} "; + if (name) + { + t << "\\tab "; + writeRTFReference(name); + t << endl; + } + else + { + t << endl; + } + m_omitParagraph=FALSE; + newParagraph(); +} + +void RTFGenerator::startSubsection() +{ + //beginRTFSubSection(); + t <<"\n"; + DBG_RTF(t << "{\\comment Begin SubSection}\n") + t << rtf_Style_Reset; + t << rtf_Style["Heading3"]->reference << "\n"; +} + +void RTFGenerator::endSubsection() +{ + newParagraph(); + t << rtf_Style_Reset << endl; +} + +void RTFGenerator::startSubsubsection() +{ + //beginRTFSubSubSection(); + t << "\n"; + DBG_RTF(t << "{\\comment Begin SubSubSection}\n") + t << "{" << endl; + t << rtf_Style_Reset << rtf_Style["Heading4"]->reference << "\n"; +} + +void RTFGenerator::endSubsubsection() +{ + newParagraph(); + t << "}" << endl; +} + + +//void RTFGenerator::writeClassLink(const char *,const char *, +// const char *,const char *name) +//{ +// t << "{\\bf "; +// docify(name); +// t << "}"; +//} + +//void RTFGenerator::startTable(bool,int colNumbers) +//{ +// DBG_RTF(t << "{\\comment startTable}\n";) +// m_numCols=colNumbers; +// t << "\\par\n"; +//} +// +//void RTFGenerator::endTable(bool hasCaption) +//{ +// DBG_RTF(t << "{\\comment endTable}\n";) +// if (!hasCaption) +// t << "\n\\pard \\widctlpar\\intbl\\adjustright\n{\\row }\n"; +// t << "\\pard\n" << endl; +//} +// +//void RTFGenerator::startCaption() +//{ +// DBG_RTF(t << "{\\comment startCaption}\n";) +// endTableRow(); +// t << "\\trowd \\trgaph108\\trleft-108\\trbrdrt\\brdrs\\brdrw10 \\trbrdrl\\brdrs\\brdrw10 \\trbrdrb\\brdrs\\brdrw10 \\trbrdrr\\brdrs\\brdrw10 \\trbrdrh\\brdrs\\brdrw10 \\trbrdrv\\brdrs\\brdrw10" << endl; +// t << "\\clvertalt\\clbrdrt\\brdrs\\brdrw10 \\clbrdrl\\brdrs\\brdrw10 \\clbrdrb\\brdrs\\brdrw10 \\clbrdrr \\brdrs\\brdrw10 \\cltxlrtb \\cellx"<0 && m_numCols<25); +// uint columnWidth=rtf_pageWidth/m_numCols; +// t << "\\trowd \\trgaph108\\trleft-108\\trbrdrt\\brdrs\\brdrw10 " +// "\\trbrdrl\\brdrs\\brdrw10 \\trbrdrb\\brdrs\\brdrw10 " +// "\\trbrdrr\\brdrs\\brdrw10 \\trbrdrh\\brdrs\\brdrw10 " +// "\\trbrdrv\\brdrs\\brdrw10 "<reference << endl; +} + +void RTFGenerator::endTitleHead(const char *fileName,const char *name) +{ + DBG_RTF(t <<"{\\comment endTitleHead}" << endl) + t << "\\par " << rtf_Style_Reset << endl; + if (name) + { + // make table of contents entry + t << "{\\tc\\tcl2 \\v "; + docify(name); + t << "}" << endl; + + // make an index entry + addIndexItem(name,0); + + //if (name) + //{ + // writeAnchor(0,name); + //} + // + //if (Config_getBool("RTF_HYPERLINKS") && fileName) + //{ + writeAnchor(fileName,0); + //} + } +} + +void RTFGenerator::startTitle() +{ + DBG_RTF(t <<"{\\comment startTitle}" << endl) + if (Config_getBool("COMPACT_RTF")) + beginRTFSection(); + else + beginRTFChapter(); +} + +void RTFGenerator::startGroupHeader(int extraIndent) +{ + DBG_RTF(t <<"{\\comment startGroupHeader}" << endl) + //newParagraph(); + t << rtf_Style_Reset; + if (extraIndent==2) + { + t << rtf_Style["Heading5"]->reference; + } + else if (extraIndent==1) + { + t << rtf_Style["Heading4"]->reference; + } + else // extraIndent==0 + { + t << rtf_Style["Heading3"]->reference; + } + t << endl; +} + +void RTFGenerator::endGroupHeader(int) +{ + DBG_RTF(t <<"{\\comment endGroupHeader}" << endl) + t << "\\par" << endl; + t << rtf_Style_Reset << endl; +} + +void RTFGenerator::startMemberDoc(const char *clname, + const char *memname, + const char *, + const char *, + bool showInline) +{ + DBG_RTF(t << "{\\comment startMemberDoc}" << endl) + if (memname && memname[0]!='@') + { + addIndexItem(memname,clname); + addIndexItem(clname,memname); + } + t << rtf_Style_Reset << rtf_Style[showInline ? "Heading5" : "Heading4"]->reference; + //styleStack.push(rtf_Style_Heading4); + t << "{" << endl; + //printf("RTFGenerator::startMemberDoc() `%s'\n",rtf_Style["Heading4"]->reference); + startBold(); + t << endl; +} + +void RTFGenerator::endMemberDoc(bool) +{ + DBG_RTF(t << "{\\comment endMemberDoc}" << endl) + //const char *style = styleStack.pop(); + //printf("RTFGenerator::endMemberDoc() `%s'\n",style); + //ASSERT(style==rtf_Style["Heading4"]->reference); + endBold(); + t << "}" << endl; + newParagraph(); +} + +void RTFGenerator::startDoxyAnchor(const char *,const char *, + const char *,const char *, + const char * + ) +{ + DBG_RTF(t << "{\\comment startDoxyAnchor}" << endl) +} + +void RTFGenerator::endDoxyAnchor(const char *fName,const char *anchor) +{ + QCString ref; + if (fName) + { + ref+=fName; + } + if (anchor) + { + ref+='_'; + ref+=anchor; + } + + DBG_RTF(t << "{\\comment endDoxyAnchor}" << endl) + t << "{\\bkmkstart "; + t << rtfFormatBmkStr(ref); + t << "}" << endl; + t << "{\\bkmkend "; + t << rtfFormatBmkStr(ref); + t << "}" << endl; +} + + +//void RTFGenerator::writeLatexLabel(const char *clName,const char *anchor) +//{ +// writeDoxyAnchor(0,clName,anchor,0); +//} + +void RTFGenerator::addIndexItem(const char *s1,const char *s2) +{ + if (s1) + { + t << "{\\xe \\v "; + docify(s1); + if (s2) + { + t << "\\:"; + docify(s2); + } + t << "}" << endl; + } +} + +void RTFGenerator::startIndent() +{ + incrementIndentLevel(); + DBG_RTF(t << "{\\comment (startIndent) }" << endl) + t << "{" << endl; + t << rtf_Style_Reset << rtf_CList_DepthStyle() << endl; +} + +void RTFGenerator::endIndent() +{ + t << "}" << endl; + decrementIndentLevel(); +} + + +void RTFGenerator::startDescription() +{ + DBG_RTF(t << "{\\comment (startDescription)}" << endl) + t << "{" << endl; + t << rtf_Style_Reset << rtf_DList_DepthStyle(); +} + +void RTFGenerator::endDescription() +{ + DBG_RTF(t << "{\\comment (endDescription)}" << endl) + newParagraph(); + t << "}"; +} + +void RTFGenerator::startDescItem() +{ + newParagraph(); + DBG_RTF(t << "{\\comment (startDescItem)}" << endl) + t << "{\\b "; +} + +void RTFGenerator::endDescItem() +{ + DBG_RTF(t << "{\\comment (endDescItem)}" << endl) + t << "}" << endl; + newParagraph(); +} + +void RTFGenerator::startMemberDescription(const char *) +{ + DBG_RTF(t << "{\\comment (startMemberDescription)}" << endl) + t << "{" << endl; + incrementIndentLevel(); + t << rtf_Style_Reset << rtf_CList_DepthStyle(); + startEmphasis(); +} + +void RTFGenerator::endMemberDescription() +{ + DBG_RTF(t << "{\\comment (endMemberDescription)}" << endl) + endEmphasis(); + newParagraph(); + decrementIndentLevel(); + //t << "\\par"; + t << "}" << endl; + //m_omitParagraph = TRUE; +} + +void RTFGenerator::startDescList(SectionTypes) +{ + DBG_RTF(t << "{\\comment (startDescList)}" << endl) + t << "{"; // ends at endDescList + t << "{"; // ends at endDescTitle + startBold(); + newParagraph(); +} + +//void RTFGenerator::endDescTitle() +//{ +// DBG_RTF(t << "{\\comment (endDescTitle) }" << endl) +// endBold(); +// t << "}"; +// newParagraph(); +// incrementIndentLevel(); +// t << rtf_Style_Reset << rtf_DList_DepthStyle(); +//} + +void RTFGenerator::startDescForItem() +{ + DBG_RTF(t << "{\\comment (startDescForItem) }" << endl) +} + +void RTFGenerator::endDescForItem() +{ + DBG_RTF(t << "{\\comment (endDescForItem) }" << endl) +} + +//void RTFGenerator::endDescList() +//{ +// DBG_RTF(t << "{\\comment (endDescList)}" << endl) +// newParagraph(); +// decrementIndentLevel(); +// m_omitParagraph = TRUE; +// t << "}"; +//} + + +void RTFGenerator::startSection(const char *,const char *title,SectionInfo::SectionType type) +{ + DBG_RTF(t << "{\\comment (startSection)}" << endl) + t << "{"; + t<< rtf_Style_Reset; + int num=4; + switch(type) + { + case SectionInfo::Page: num=2; break; + case SectionInfo::Section: num=3; break; + case SectionInfo::Subsection: num=4; break; + case SectionInfo::Subsubsection: num=4; break; + case SectionInfo::Paragraph: num=4; break; + default: ASSERT(0); break; + } + QCString heading; + heading.sprintf("Heading%d",num); + // set style + t << rtf_Style[heading]->reference; + // make table of contents entry + t << "{\\tc\\tcl" << num << " \\v "; + docify(title); + t << "}" << endl; +} + +void RTFGenerator::endSection(const char *lab,SectionInfo::SectionType) +{ + DBG_RTF(t << "{\\comment (endSection)}" << endl) + // make bookmark + m_omitParagraph=FALSE; + newParagraph(); + writeAnchor(0,lab); + t << "}"; +} + +//void RTFGenerator::writeSectionRef(const char *ref,const char *, +// const char *lab,const char *title) +//{ +// if (ref) +// { +// docify(title); +// } +// else +// { +// startBold(); +// docify(title); +// endBold(); +// t << " ("; +// docify(theTranslator->trPageAbbreviation()); +// writeRTFReference(lab); +// t << ")" << endl; +// } +//} +// +//void RTFGenerator::writeSectionRefItem(const char *,const char *lab, +// const char *title) +//{ +// docify(title); +// t << "\\tab"; +// writeRTFReference(lab); +// t << endl; +//} +// +//void RTFGenerator::writeSectionRefAnchor(const char *name,const char *lab, +// const char *title) +//{ +// writeSectionRef(name,lab,title); +//} + +//char* RTFGenerator::getMultiByte(int c) +//{ +// static char s[10]; +// +// sprintf(s,"\\'%X",c); +// return s; +//} + +void RTFGenerator::docify(const char *str) +{ + if (str) + { + const unsigned char *p=(const unsigned char *)str; + unsigned char c; + //unsigned char pc='\0'; + while (*p) + { + //static bool MultiByte = FALSE; + c=*p++; + +#if 0 + if ( MultiByte ) + { + t << getMultiByte( c ); + MultiByte = FALSE; + continue; + } + if ( c >= 0x80 ) + { + MultiByte = TRUE; + t << getMultiByte( c ); + continue; + } +#endif + + switch (c) + { + case '{': t << "\\{"; break; + case '}': t << "\\}"; break; + case '\\': t << "\\\\"; break; + default: + { + // see if we can insert an hyphenation hint + //if (isupper(c) && islower(pc) && !insideTabbing) t << "\\-"; + t << (char)c; + } + } + //pc = c; + m_omitParagraph = FALSE; + } + } +} + +void RTFGenerator::codify(const char *str) +{ + // note that RTF does not have a "verbatim", so "\n" means + // nothing... add a "newParagraph()"; + //static char spaces[]=" "; + if (str) + { + const unsigned char *p=(const unsigned char *)str; + unsigned char c; + int spacesToNextTabStop; + + while (*p) + { + //static bool MultiByte = FALSE; + + c=*p++; + +#if 0 + if( MultiByte ) + { + t << getMultiByte( c ); + MultiByte = FALSE; + continue; + } + if( c >= 0x80 ) + { + MultiByte = TRUE; + t << getMultiByte( c ); + continue; + } +#endif + + switch(c) + { + case '\t': spacesToNextTabStop = Config_getInt("TAB_SIZE") - (col%Config_getInt("TAB_SIZE")); + t << Doxygen::spaces.left(spacesToNextTabStop); + col+=spacesToNextTabStop; + break; + case '\n': newParagraph(); + t << '\n'; col=0; + break; + case '{': t << "\\{"; col++; break; + case '}': t << "\\}"; col++; break; + case '\\': t << "\\\\"; col++; break; + default: t << (char)c; col++; break; + } + } + } +} + +void RTFGenerator::writeChar(char c) +{ + char cs[2]; + cs[0]=c; + cs[1]=0; + docify(cs); +} + +void RTFGenerator::startClassDiagram() +{ + DBG_RTF(t <<"{\\comment startClassDiagram }" << endl) +} + +void RTFGenerator::endClassDiagram(const ClassDiagram &d, + const char *fileName,const char *) +{ + newParagraph(); + + // create a png file + d.writeImage(t,dir,relPath,fileName,FALSE); + + // display the file + t << "{" << endl; + t << rtf_Style_Reset << endl; + t << "\\par\\pard \\qc {\\field\\flddirty {\\*\\fldinst INCLUDEPICTURE \""; + t << fileName << ".png\""; + t << " \\\\d \\\\*MERGEFORMAT}{\\fldrslt IMAGE}}\\par" << endl; + t << "}" << endl; +} + +//void RTFGenerator::writeFormula(const char *,const char *text) +//{ +// t << text; +//} + +void RTFGenerator::startMemberItem(const char *,int) +{ + DBG_RTF(t <<"{\\comment startMemberItem }" << endl) + t << rtf_Style_Reset << rtf_BList_DepthStyle() << endl; // set style to apropriate depth +} + +void RTFGenerator::endMemberItem() +{ + DBG_RTF(t <<"{\\comment endMemberItem }" << endl) + newParagraph(); +} + +void RTFGenerator::writeAnchor(const char *fileName,const char *name) +{ + QCString anchor; + if (fileName) + { + anchor+=fileName; + } + if (fileName && name) + { + anchor+='_'; + } + if (name) + { + anchor+=name; + } + + DBG_RTF(t <<"{\\comment writeAnchor (" << anchor << ")}" << endl) + t << "{\\bkmkstart " << rtfFormatBmkStr(anchor) << "}" << endl; + t << "{\\bkmkend " << rtfFormatBmkStr(anchor) << "}" << endl; +} + +void RTFGenerator::writeRTFReference(const char *label) +{ + t << "{\\field\\fldedit {\\*\\fldinst PAGEREF "; + t << rtfFormatBmkStr(label); + t << " \\\\*MERGEFORMAT}{\\fldrslt pagenum}}"; +} + +void RTFGenerator::startCodeFragment() +{ + DBG_RTF(t << "{\\comment (startCodeFragment) }" << endl) + t << "{" << endl; + //newParagraph(); + t << rtf_Style_Reset << rtf_Code_DepthStyle(); + //styleStack.push(rtf_Style_CodeExample); +} + +void RTFGenerator::endCodeFragment() +{ + //newParagraph(); + //styleStack.pop(); + //printf("RTFGenerator::endCodeFrament() top=%s\n",styleStack.top()); + //t << rtf_Style_Reset << styleStack.top() << endl; + DBG_RTF(t << "{\\comment (endCodeFragment) }" << endl) + t << "}" << endl; + m_omitParagraph = TRUE; +} + +void RTFGenerator::writeNonBreakableSpace(int) +{ + t << "\\~ "; +} + + +void RTFGenerator::startMemberList() +{ + t << endl; + DBG_RTF(t << "{\\comment (startMemberList) }" << endl) + t << "{" << endl; +#ifdef DELETEDCODE + if (!insideTabbing) + t << "\\begin{CompactItemize}" << endl; +#endif +} + +void RTFGenerator::endMemberList() +{ + DBG_RTF(t << "{\\comment (endMemberList) }" << endl) + t << "}" << endl; +#ifdef DELETEDCODE + if (!insideTabbing) + t << "\\end{CompactItemize}" << endl; +#endif +} + +//void RTFGenerator::startImage(const char *name,const char *,bool) +//{ +// newParagraph(); +// t << "{" << endl; +// t << rtf_Style_Reset << endl; +// t << "\\par\\pard \\qc {\\field\\flddirty {\\*\\fldinst INCLUDEPICTURE "; +// t << name; +// t << " \\\\d \\\\*MERGEFORMAT}{\\fldrslt IMAGE}}\\par" << endl; +// t << "}" << endl; +//} +// +//void RTFGenerator::endImage(bool) +//{ +// // not yet implemented +//} +// +//void RTFGenerator::startDotFile(const char *name,bool) +//{ +// QCString baseName=name; +// int i; +// if ((i=baseName.findRev('/'))!=-1 || (i=baseName.findRev('\\'))!=-1) +// { +// baseName=baseName.right(baseName.length()-i-1); +// } +// QCString outDir = Config_getString("RTF_OUTPUT"); +// writeDotGraphFromFile(name,outDir,baseName,BITMAP); +// newParagraph(); +// t << "{" << endl; +// t << rtf_Style_Reset << endl; +// t << "\\par\\pard \\qc {\\field\\flddirty {\\*\\fldinst INCLUDEPICTURE "; +// t << outDir << "\\" << baseName; +// t << " \\\\d \\\\*MERGEFORMAT}{\\fldrslt IMAGE}}\\par" << endl; +// t << "}" << endl; +//} +// +//void RTFGenerator::endDotFile(bool) +//{ +// // not yet implemented +//} +// +void RTFGenerator::startDescTable() +{ + DBG_RTF(t << "{\\comment (startDescTable) }" << endl) + //t << "{" << endl; + //incrementIndentLevel(); + //t << rtf_Style_Reset << rtf_CList_DepthStyle(); +} + +void RTFGenerator::endDescTable() +{ + //decrementIndentLevel(); + DBG_RTF(t << "{\\comment (endDescTable)}" << endl) + //t << "}" << endl; + //t << rtf_Style_Reset << styleStack.top(); +} + +void RTFGenerator::startDescTableTitle() +{ + //t << rtf_BList_DepthStyle() << endl; + DBG_RTF(t << "{\\comment (startDescTableTitle) }" << endl) + startBold(); + startEmphasis(); +} + +void RTFGenerator::endDescTableTitle() +{ + DBG_RTF(t << "{\\comment (endDescTableTitle) }" << endl) + endEmphasis(); + endBold(); + t << " "; +} + +void RTFGenerator::startDescTableData() +{ + DBG_RTF(t << "{\\comment (startDescTableData) }" << endl) + m_omitParagraph = FALSE; +} + +void RTFGenerator::endDescTableData() +{ + DBG_RTF(t << "{\\comment (endDescTableData) }" << endl) + newParagraph(); + m_omitParagraph = TRUE; +} + +// a style for list formatted as a "bulleted list" + +void RTFGenerator::incrementIndentLevel() +{ + m_listLevel++; + if (m_listLevel>rtf_maxIndentLevels-1) + { + err("error: Maximum indent level (%d) exceeded while generating RTF output!\n",rtf_maxIndentLevels); + m_listLevel=rtf_maxIndentLevels-1; + } +} + +void RTFGenerator::decrementIndentLevel() +{ + m_listLevel--; + if (m_listLevel<0) + { + err("error: Negative indent level while generating RTF output!\n"); + m_listLevel=0; + } +} + +// a style for list formatted with "list continue" style +const char * RTFGenerator::rtf_CList_DepthStyle() +{ + QCString n=makeIndexName("ListContinue",m_listLevel); + return rtf_Style[n]->reference; +} + +// a style for list formatted as a "latext style" table of contents +const char * RTFGenerator::rtf_LCList_DepthStyle() +{ + QCString n=makeIndexName("LatexTOC",m_listLevel); + return rtf_Style[n]->reference; +} + +// a style for list formatted as a "bullet" style +const char * RTFGenerator::rtf_BList_DepthStyle() +{ + QCString n=makeIndexName("ListBullet",m_listLevel); + return rtf_Style[n]->reference; +} + +// a style for list formatted as a "enumeration" style +const char * RTFGenerator::rtf_EList_DepthStyle() +{ + QCString n=makeIndexName("ListEnum",m_listLevel); + return rtf_Style[n]->reference; +} + +const char * RTFGenerator::rtf_DList_DepthStyle() +{ + QCString n=makeIndexName("DescContinue",m_listLevel); + return rtf_Style[n]->reference; +} + +const char * RTFGenerator::rtf_Code_DepthStyle() +{ + QCString n=makeIndexName("CodeExample",m_listLevel); + return rtf_Style[n]->reference; +} + +void RTFGenerator::startTextBlock(bool dense) +{ + DBG_RTF(t << "{\\comment startTextBlock}" << endl) + t << "{" << endl; + t << rtf_Style_Reset; + if (dense) // no spacing between "paragraphs" + { + t << rtf_Style["DenseText"]->reference; + } + else // some spacing + { + t << rtf_Style["BodyText"]->reference; + } +} + +void RTFGenerator::endTextBlock(bool /*paraBreak*/) +{ + newParagraph(); + DBG_RTF(t << "{\\comment endTextBlock}" << endl) + t << "}" << endl; + //m_omitParagraph = TRUE; +} + +void RTFGenerator::newParagraph() +{ + if (!m_omitParagraph) + { + DBG_RTF(t << "{\\comment (newParagraph)}" << endl) + t << "\\par" << endl; + } + m_omitParagraph = FALSE; +} + +void RTFGenerator::startParagraph() +{ + DBG_RTF(t << "{\\comment startParagraph}" << endl) + newParagraph(); + t << "{" << endl; +} + +void RTFGenerator::endParagraph() +{ + DBG_RTF(t << "{\\comment endParagraph}" << endl) + t << "}\\par" << endl; + m_omitParagraph = TRUE; +} + +void RTFGenerator::startMemberSubtitle() +{ + DBG_RTF(t << "{\\comment startMemberSubtitle}" << endl) + t << "{" << endl; + t << rtf_Style_Reset << rtf_CList_DepthStyle() << endl; +} + +void RTFGenerator::endMemberSubtitle() +{ + DBG_RTF(t << "{\\comment endMemberSubtitle}" << endl) + newParagraph(); + t << "}" << endl; +} + +//void RTFGenerator::writeUmlaut(char c) +//{ +// switch(c) +// { +// case 'A' : t << '\304'; break; +// case 'E' : t << '\313'; break; +// case 'I' : t << '\317'; break; +// case 'O' : t << '\326'; break; +// case 'U' : t << '\334'; break; +// case 'Y' : t << 'Y'; break; +// case 'a' : t << '\344'; break; +// case 'e' : t << '\353'; break; +// case 'i' : t << '\357'; break; +// case 'o' : t << '\366'; break; +// case 'u' : t << '\374'; break; +// case 'y' : t << '\377'; break; +// default: t << '?'; break; +// } +//} +// +//void RTFGenerator::writeAcute(char c) +//{ +// switch(c) +// { +// case 'A' : t << '\301'; break; +// case 'E' : t << '\311'; break; +// case 'I' : t << '\315'; break; +// case 'O' : t << '\323'; break; +// case 'U' : t << '\332'; break; +// case 'Y' : t << '\335'; break; +// case 'a' : t << '\341'; break; +// case 'e' : t << '\351'; break; +// case 'i' : t << '\355'; break; +// case 'o' : t << '\363'; break; +// case 'u' : t << '\372'; break; +// case 'y' : t << '\375'; break; +// default: t << '?'; break; +// } +//} +// +//void RTFGenerator::writeGrave(char c) +//{ +// switch(c) +// { +// case 'A' : t << '\300'; break; +// case 'E' : t << '\310'; break; +// case 'I' : t << '\314'; break; +// case 'O' : t << '\322'; break; +// case 'U' : t << '\331'; break; +// case 'a' : t << '\340'; break; +// case 'e' : t << '\350'; break; +// case 'i' : t << '\354'; break; +// case 'o' : t << '\362'; break; +// case 'u' : t << '\371'; break; +// default: t << '?'; break; +// } +//} +// +//void RTFGenerator::writeCirc(char c) +//{ +// switch(c) +// { +// case 'A' : t << '\302'; break; +// case 'E' : t << '\312'; break; +// case 'I' : t << '\316'; break; +// case 'O' : t << '\324'; break; +// case 'U' : t << '\333'; break; +// case 'a' : t << '\342'; break; +// case 'e' : t << '\352'; break; +// case 'i' : t << '\356'; break; +// case 'o' : t << '\364'; break; +// case 'u' : t << '\373'; break; +// default: t << '?'; break; +// } +//} +// +//void RTFGenerator::writeTilde(char c) +//{ +// switch(c) +// { +// case 'A' : t << '\303'; break; +// case 'N' : t << '\321'; break; +// case 'O' : t << '\325'; break; +// case 'a' : t << '\343'; break; +// case 'n' : t << '\361'; break; +// case 'o' : t << '\365'; break; +// default: t << '?'; break; +// } +//} +// +//void RTFGenerator::writeRing(char c) +//{ +// switch(c) +// { +// case 'A' : t << '\305'; break; +// case 'a' : t << '\345'; break; +// default: t << '?'; break; +// } +//} +// +//void RTFGenerator::writeCCedil(char c) +//{ +// switch(c) +// { +// case 'C' : t << '\307'; break; +// case 'c' : t << '\347'; break; +// default: t << '?'; break; +// } +//} +// + +bool isLeadBytes(int c) +{ + bool result; + + QCString codePage = theTranslator->trRTFansicp(); + + if (codePage == "932") // cp932 (Japanese Shift-JIS) + { + result = (0x81<=c && c<=0x9f) || (0xe0<=c && c<=0xfc); + } + else if (codePage == "936") // cp936 (Simplified Chinese GBK) + { + result = 0x81<=c && c<=0xFE; + } + else if (codePage == "949") // cp949 (Korean) + { + result = 0x81<=c && c<=0xFE; + } + else if (codePage == "950") // cp950 (Traditional Chinese Big5) + { + result = 0x81<=c && c<=0xFE; + } + else // for SBCS Codepages (cp1252,1251 etc...) + { + result = false; + } + + return result; +} + + +// note: function is not reentrant! +static void encodeForOutput(FTextStream &t,const QCString &s) +{ + QCString encoding; + bool converted=FALSE; + int l = s.length(); + static QByteArray enc; + if (l*4>(int)enc.size()) enc.resize(l*4); // worst case + encoding.sprintf("CP%s",theTranslator->trRTFansicp().data()); + if (!encoding.isEmpty()) + { + // convert from UTF-8 back to the output encoding + void *cd = portable_iconv_open(encoding,"UTF-8"); + if (cd!=(void *)(-1)) + { + size_t iLeft=l; + size_t oLeft=enc.size(); + const char *inputPtr = s.data(); + char *outputPtr = enc.data(); + if (!portable_iconv(cd, &inputPtr, &iLeft, &outputPtr, &oLeft)) + { + enc.resize(enc.size()-oLeft); + converted=TRUE; + } + portable_iconv_close(cd); + } + } + if (!converted) // if we did not convert anything, copy as is. + { + memcpy(enc.data(),s.data(),l); + enc.resize(l); + } + uint i; + bool multiByte = FALSE; + + for (i=0;i=0x80 || multiByte) + { + char esc[10]; + sprintf(esc,"\\'%X",c); // escape sequence for SBCS and DBCS(1st&2nd bytes). + t << esc; + + if (!multiByte) + { + multiByte = isLeadBytes(c); // It may be DBCS Codepages. + } + else + { + multiByte = FALSE; // end of Double Bytes Character. + } + } + else + { + t << (char)c; + } + } +} + +/** + * VERY brittle routine inline RTF's included by other RTF's. + * it is recursive and ugly. + */ +static bool preProcessFile(QDir &d,QCString &infName, FTextStream &t, bool bIncludeHeader=TRUE) +{ + QFile f(infName); + if (!f.open(IO_ReadOnly)) + { + err("error: problems opening rtf file %s for reading\n",infName.data()); + return FALSE; + } + + const int maxLineLength = 10240; + static QCString lineBuf(maxLineLength); + + // scan until find end of header + // this is EXTREEEEEEEMLY brittle. It works on OUR rtf + // files because the first line before the body + // ALWAYS contains "{\comment begin body}" + do + { + if (f.readLine(lineBuf.data(),maxLineLength)==-1) + { + err("ERROR - read error in %s before end of RTF header!\n",infName.data()); + return FALSE; + } + if (bIncludeHeader) encodeForOutput(t,lineBuf); + } while (lineBuf.find("\\comment begin body")==-1); + + + while (f.readLine(lineBuf.data(),maxLineLength)!=-1) + { + int pos; + if ((pos=lineBuf.find("INCLUDETEXT"))!=-1) + { + int startNamePos = lineBuf.find('"',pos)+1; + int endNamePos = lineBuf.find('"',startNamePos); + QCString fileName = lineBuf.mid(startNamePos,endNamePos-startNamePos); + DBG_RTF(t << "{\\comment begin include " << fileName << "}" << endl) + if (!preProcessFile(d,fileName,t,FALSE)) return FALSE; + DBG_RTF(t << "{\\comment end include " << fileName << "}" << endl) + } + else // no INCLUDETEXT on this line + { + // elaborate hoopla to skip the final "}" if we didn't include the + // headers + if (!f.atEnd() || bIncludeHeader) + { + encodeForOutput(t,lineBuf); + } + else // last line of included file + { + // null terminate at the last '}' + //char *str = strrchr(buffer,'}'); + int pos = lineBuf.findRev('}'); + + if (pos != -1) + lineBuf.at(pos) = '\0'; + else + err("Strange, the last char was not a '}'\n"); + encodeForOutput(t,lineBuf); + } + } + } + f.close(); + // remove temporary file + d.remove(infName); + return TRUE; +} + +void RTFGenerator::startDotGraph() +{ + DBG_RTF(t << "{\\comment (startDotGraph)}" << endl) +} + +void RTFGenerator::endDotGraph(const DotClassGraph &g) +{ + newParagraph(); + + QCString fileName = + g.writeGraph(t,BITMAP,Config_getString("RTF_OUTPUT"),fileName,relPath,TRUE,FALSE); + + // display the file + t << "{" << endl; + t << rtf_Style_Reset << endl; + t << "\\par\\pard \\qc {\\field\\flddirty {\\*\\fldinst INCLUDEPICTURE \""; + t << fileName << "." << Config_getEnum("DOT_IMAGE_FORMAT"); + t << "\" \\\\d \\\\*MERGEFORMAT}{\\fldrslt IMAGE}}\\par" << endl; + t << "}" << endl; + newParagraph(); + DBG_RTF(t << "{\\comment (endDotGraph)}" << endl) +} + +void RTFGenerator::startInclDepGraph() +{ + DBG_RTF(t << "{\\comment (startInclDepGraph)}" << endl) +} + +void RTFGenerator::endInclDepGraph(const DotInclDepGraph &g) +{ + newParagraph(); + + QCString fn = g.writeGraph(t,BITMAP,Config_getString("RTF_OUTPUT"), + fileName,relPath,FALSE); + + // display the file + t << "{" << endl; + t << rtf_Style_Reset << endl; + t << "\\par\\pard \\qc {\\field\\flddirty {\\*\\fldinst INCLUDEPICTURE \""; + t << fn << "." << Config_getEnum("DOT_IMAGE_FORMAT"); + t << "\" \\\\d \\\\*MERGEFORMAT}{\\fldrslt IMAGE}}\\par" << endl; + t << "}" << endl; + DBG_RTF(t << "{\\comment (endInclDepGraph)}" << endl) +} + +void RTFGenerator::startGroupCollaboration() +{ +} + +void RTFGenerator::endGroupCollaboration(const DotGroupCollaboration &) +{ +} + +void RTFGenerator::startCallGraph() +{ + DBG_RTF(t << "{\\comment (startCallGraph)}" << endl) +} + +void RTFGenerator::endCallGraph(const DotCallGraph &g) +{ + newParagraph(); + + QCString fn = g.writeGraph(t,BITMAP,Config_getString("RTF_OUTPUT"), + fileName,relPath,FALSE); + + // display the file + t << "{" << endl; + t << rtf_Style_Reset << endl; + t << "\\par\\pard \\qc {\\field\\flddirty {\\*\\fldinst INCLUDEPICTURE \""; + t << fn << "." << Config_getEnum("DOT_IMAGE_FORMAT"); + t << "\" \\\\d \\\\*MERGEFORMAT}{\\fldrslt IMAGE}}\\par" << endl; + t << "}" << endl; + DBG_RTF(t << "{\\comment (endCallGraph)}" << endl) +} + +void RTFGenerator::startDirDepGraph() +{ + DBG_RTF(t << "{\\comment (startDirDepGraph)}" << endl) +} + +void RTFGenerator::endDirDepGraph(const DotDirDeps &g) +{ + newParagraph(); + + QCString fileName = g.writeGraph(t,BITMAP,Config_getString("RTF_OUTPUT"), + fileName,relPath,FALSE); + + // display the file + t << "{" << endl; + t << rtf_Style_Reset << endl; + t << "\\par\\pard \\qc {\\field\\flddirty {\\*\\fldinst INCLUDEPICTURE \""; + t << fileName << "." << Config_getEnum("DOT_IMAGE_FORMAT"); + t << "\" \\\\d \\\\*MERGEFORMAT}{\\fldrslt IMAGE}}\\par" << endl; + t << "}" << endl; + DBG_RTF(t << "{\\comment (endDirDepGraph)}" << endl) +} + +/** Tests the integrity of the result by counting brackets. + * + */ +void testRTFOutput(const char *name) +{ + int bcount=0; + int line=1; + int c; + QFile f(name); + if (f.open(IO_ReadOnly)) + { + while ((c=f.getch())!=-1) + { + if (c=='\\') // escape char + { + c=f.getch(); + if (c==-1) break; + } + else if (c=='{') // open bracket + { + bcount++; + } + else if (c=='}') // close bracket + { + bcount--; + if (bcount<0) + { + goto err; + break; + } + } + else if (c=='\n') // newline + { + line++; + } + } + } + if (bcount==0) return; // file is OK. +err: + err("error: RTF integrity test failed at line %d of %s due to a bracket mismatch.\n",line,name); + err(" Please try to create a small code example that produces this error \n" + " and send that to dimitri@stack.nl.\n"); +} + +/** + * This is an API to a VERY brittle RTF preprocessor that combines nested + * RTF files. This version replaces the infile with the new file + */ +bool RTFGenerator::preProcessFileInplace(const char *path,const char *name) +{ + QDir d(path); + // store the original directory + if (!d.exists()) + { + err("error: Output dir %s does not exist!\n",path); + return FALSE; + } + QCString oldDir = convertToQCString(QDir::currentDirPath()); + + // go to the html output directory (i.e. path) + QDir::setCurrent(d.absPath()); + QDir thisDir; + + QCString combinedName = (QCString)path+"/combined.rtf"; + QCString mainRTFName = (QCString)path+"/"+name; + + QFile outf(combinedName); + if (!outf.open(IO_WriteOnly)) + { + err("Failed to open %s for writing!\n",combinedName.data()); + return FALSE; + } + FTextStream outt(&outf); + + if (!preProcessFile(thisDir,mainRTFName,outt)) + { + // it failed, remove the temp file + outf.close(); + thisDir.remove(combinedName); + QDir::setCurrent(oldDir); + return FALSE; + } + + // everything worked, move the files + outf.close(); + thisDir.remove(mainRTFName); + thisDir.rename(combinedName,mainRTFName); + + testRTFOutput(mainRTFName); + + QDir::setCurrent(oldDir); + return TRUE; +} + +void RTFGenerator::startMemberGroupHeader(bool hasHeader) +{ + DBG_RTF(t << "{\\comment startMemberGroupHeader}" << endl) + t << "{" << endl; + if (hasHeader) incrementIndentLevel(); + t << rtf_Style_Reset << rtf_Style["GroupHeader"]->reference; +} + +void RTFGenerator::endMemberGroupHeader() +{ + DBG_RTF(t << "{\\comment endMemberGroupHeader}" << endl) + newParagraph(); + t << rtf_Style_Reset << rtf_CList_DepthStyle(); +} + +void RTFGenerator::startMemberGroupDocs() +{ + DBG_RTF(t << "{\\comment startMemberGroupDocs}" << endl) + startEmphasis(); +} + +void RTFGenerator::endMemberGroupDocs() +{ + DBG_RTF(t << "{\\comment endMemberGroupDocs}" << endl) + endEmphasis(); + newParagraph(); +} + +void RTFGenerator::startMemberGroup() +{ + DBG_RTF(t << "{\\comment startMemberGroup}" << endl) + t << rtf_Style_Reset << rtf_BList_DepthStyle() << endl; +} + +void RTFGenerator::endMemberGroup(bool hasHeader) +{ + DBG_RTF(t << "{\\comment endMemberGroup}" << endl) + if (hasHeader) decrementIndentLevel(); + t << "}"; +} + +void RTFGenerator::startSimpleSect(SectionTypes,const char *file,const char *anchor,const char *title) +{ + DBG_RTF(t << "{\\comment (startSimpleSect)}" << endl) + t << "{"; // ends at endDescList + t << "{"; // ends at endDescTitle + startBold(); + newParagraph(); + if (file) + { + writeObjectLink(0,file,anchor,title); + } + else + { + docify(title); + } + endBold(); + t << "}"; + newParagraph(); + incrementIndentLevel(); + t << rtf_Style_Reset << rtf_DList_DepthStyle(); +} + +void RTFGenerator::endSimpleSect() +{ + DBG_RTF(t << "{\\comment (endSimpleSect)}" << endl) + newParagraph(); + decrementIndentLevel(); + m_omitParagraph = TRUE; + t << "}"; +} + +void RTFGenerator::startParamList(ParamListTypes,const char *title) +{ + DBG_RTF(t << "{\\comment (startParamList)}" << endl) + t << "{"; // ends at endParamList + t << "{"; // ends at endDescTitle + startBold(); + newParagraph(); + docify(title); + endBold(); + t << "}"; + newParagraph(); + incrementIndentLevel(); + t << rtf_Style_Reset << rtf_DList_DepthStyle(); +} + +void RTFGenerator::endParamList() +{ + DBG_RTF(t << "{\\comment (endParamList)}" << endl) + newParagraph(); + decrementIndentLevel(); + m_omitParagraph = TRUE; + t << "}"; +} + +void RTFGenerator::startParameterType(bool first,const char *key) +{ + DBG_RTF(t << "{\\comment (startParameterType)}" << endl) + if (!first && key) + { + t << " " << key << " "; + } +} + +void RTFGenerator::endParameterType() +{ + DBG_RTF(t << "{\\comment (endParameterType)}" << endl) + t << " "; +} + +void RTFGenerator::printDoc(DocNode *n,const char *langExt) +{ + RTFDocVisitor *visitor = new RTFDocVisitor(t,*this,langExt); + n->accept(visitor); + delete visitor; + m_omitParagraph = TRUE; +} + +void RTFGenerator::rtfwriteRuler_doubleline() +{ + DBG_RTF(t << "{\\comment (rtfwriteRuler_doubleline)}" << endl) + t << "{\\pard\\widctlpar\\brdrb\\brdrdb\\brdrw15\\brsp20 \\adjustright \\par}" << endl; +} + +void RTFGenerator::rtfwriteRuler_emboss() +{ + DBG_RTF(t << "{\\comment (rtfwriteRuler_emboss)}" << endl) + t << "{\\pard\\widctlpar\\brdrb\\brdremboss\\brdrw15\\brsp20 \\adjustright \\par}" << endl; +} + +void RTFGenerator::rtfwriteRuler_thick() +{ + DBG_RTF(t << "{\\comment (rtfwriteRuler_thick)}" << endl) + t << "{\\pard\\widctlpar\\brdrb\\brdrs\\brdrw75\\brsp20 \\adjustright \\par}" << endl; +} + +void RTFGenerator::rtfwriteRuler_thin() +{ + DBG_RTF(t << "{\\comment (rtfwriteRuler_thin)}" << endl) + t << "{\\pard\\widctlpar\\brdrb\\brdrs\\brdrw5\\brsp20 \\adjustright \\par}" << endl; +} + +#if 0 +void RTFGenerator::postProcess(QByteArray &a) +{ + QByteArray enc(a.size()*4); // worst case + int off=0; + uint i; + bool mbFlag=FALSE; + for (i=0;i 0x80 as multibyte characters, except when they + // are control characters + if (c>0x80 || (mbFlag && c!='\\' && c!='{' && c!='}')) + { + char s[10]; + sprintf(s,"\\'%X",c); + qstrcpy(enc.data()+off,s); + off+=qstrlen(s); + mbFlag=c>0x80; + } + else + { + enc.at(off++)=c; + } + } + enc.resize(off); + a = enc; +} +#endif + +void RTFGenerator::startConstraintList(const char *header) +{ + DBG_RTF(t << "{\\comment (startConstraintList)}" << endl) + t << "{"; // ends at endConstraintList + t << "{"; + startBold(); + newParagraph(); + docify(header); + endBold(); + t << "}"; + newParagraph(); + incrementIndentLevel(); + t << rtf_Style_Reset << rtf_DList_DepthStyle(); +} + +void RTFGenerator::startConstraintParam() +{ + DBG_RTF(t << "{\\comment (startConstraintParam)}" << endl) + startEmphasis(); +} + +void RTFGenerator::endConstraintParam() +{ + DBG_RTF(t << "{\\comment (endConstraintParam)}" << endl) + endEmphasis(); + t << " : "; +} + +void RTFGenerator::startConstraintType() +{ + DBG_RTF(t << "{\\comment (startConstraintType)}" << endl) + startEmphasis(); +} + +void RTFGenerator::endConstraintType() +{ + DBG_RTF(t << "{\\comment (endConstraintType)}" << endl) + endEmphasis(); + t << " "; +} + +void RTFGenerator::startConstraintDocs() +{ + DBG_RTF(t << "{\\comment (startConstraintDocs)}" << endl) +} + +void RTFGenerator::endConstraintDocs() +{ + DBG_RTF(t << "{\\comment (endConstraintDocs)}" << endl) + newParagraph(); +} + +void RTFGenerator::endConstraintList() +{ + DBG_RTF(t << "{\\comment (endConstraintList)}" << endl) + newParagraph(); + decrementIndentLevel(); + m_omitParagraph = TRUE; + t << "}"; +} + +void RTFGenerator::startIndexListItem() +{ + DBG_RTF(t << "{\\comment (startIndexListItem)}" << endl) +} + +void RTFGenerator::endIndexListItem() +{ + DBG_RTF(t << "{\\comment (endIndexListItem)}" << endl) + t << "\\par" << endl; +} + +void RTFGenerator::startInlineHeader() +{ + DBG_RTF(t << "{\\comment (startInlineHeader)}" << endl) + t << "{" << endl; + t << rtf_Style_Reset << rtf_Style["Heading5"]->reference; + startBold(); +} + +void RTFGenerator::endInlineHeader() +{ + DBG_RTF(t << "{\\comment (endInlineHeader)}" << endl) + endBold(); + t << "\\par"; + t << "}" << endl; +} + +void RTFGenerator::startMemberDocSimple() +{ + DBG_RTF(t << "{\\comment (startMemberDocSimple)}" << endl) + t << "{\\par" << endl; + t << "{" << rtf_Style["Heading5"]->reference << endl; + t << theTranslator->trCompoundMembers() << ":\\par}" << endl; + t << rtf_Style_Reset << rtf_DList_DepthStyle(); + t << "\\trowd \\trgaph108\\trleft426\\tblind426" + "\\trbrdrt\\brdrs\\brdrw10\\brdrcf15 " + "\\trbrdrl\\brdrs\\brdrw10\\brdrcf15 " + "\\trbrdrb\\brdrs\\brdrw10\\brdrcf15 " + "\\trbrdrr\\brdrs\\brdrw10\\brdrcf15 " + "\\trbrdrh\\brdrs\\brdrw10\\brdrcf15 " + "\\trbrdrv\\brdrs\\brdrw10\\brdrcf15 "<< endl; + int i,columnPos[3] = { 25, 50, 100 }; + for (i=0;i<3;i++) + { + t << "\\clvertalt\\clbrdrt\\brdrs\\brdrw10\\brdrcf15 " + "\\clbrdrl\\brdrs\\brdrw10\\brdrcf15 " + "\\clbrdrb\\brdrs\\brdrw10\\brdrcf15 " + "\\clbrdrr \\brdrs\\brdrw10\\brdrcf15 " + "\\cltxlrtb " + "\\cellx" << (rtf_pageWidth*columnPos[i]/100) << endl; + } + t << "\\pard \\widctlpar\\intbl\\adjustright" << endl; +} + +void RTFGenerator::endMemberDocSimple() +{ + DBG_RTF(t << "{\\comment (endMemberDocSimple)}" << endl) + t << "}" << endl; +} + +void RTFGenerator::startInlineMemberType() +{ + DBG_RTF(t << "{\\comment (startInlineMemberType)}" << endl) + t << "{\\qr "; +} + +void RTFGenerator::endInlineMemberType() +{ + DBG_RTF(t << "{\\comment (endInlineMemberType)}" << endl) + t << "\\cell }"; +} + +void RTFGenerator::startInlineMemberName() +{ + DBG_RTF(t << "{\\comment (startInlineMemberName)}" << endl) + t << "{"; +} + +void RTFGenerator::endInlineMemberName() +{ + DBG_RTF(t << "{\\comment (endInlineMemberName)}" << endl) + t << "\\cell }"; +} + +void RTFGenerator::startInlineMemberDoc() +{ + DBG_RTF(t << "{\\comment (startInlineMemberDoc)}" << endl) + t << "{"; +} + +void RTFGenerator::endInlineMemberDoc() +{ + DBG_RTF(t << "{\\comment (endInlineMemberDoc)}" << endl) + t << "\\cell }{\\row }" << endl; +} + + diff --git a/trunk/src/rtfgen.h b/trunk/src/rtfgen.h new file mode 100644 index 0000000..c9dec0b --- /dev/null +++ b/trunk/src/rtfgen.h @@ -0,0 +1,284 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 by Parker Waechter & 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. + * + */ + +#ifndef RTFGEN_H +#define RTFGEN_H + +#include "outputgen.h" + +class QFile; + +class RTFGenerator : public OutputGenerator +{ + public: + RTFGenerator(); + ~RTFGenerator(); + static void init(); + static void writeStyleSheetFile(QFile &f); + static void writeExtensionsFile(QFile &file); + + void enable() + { if (genStack->top()) active=*genStack->top(); else active=TRUE; } + void disable() { active=FALSE; } + void enableIf(OutputType o) { if (o==RTF) enable(); } + void disableIf(OutputType o) { if (o==RTF) disable(); } + void disableIfNot(OutputType o) { if (o!=RTF) disable(); } + bool isEnabled(OutputType o) { return (o==RTF && active); } + OutputGenerator *get(OutputType o) { return (o==RTF) ? this : 0; } + + void printDoc(DocNode *,const char *); + + void startFile(const char *name,const char *manName,const char *title); + void writeSearchInfo() {} + void writeFooter() {} + void endFile(); + void clearBuffer(); + //void postProcess(QByteArray &); + + void startIndexSection(IndexSections); + void endIndexSection(IndexSections); + void writePageLink(const char *,bool); + void startProjectNumber(); + void endProjectNumber(); + void writeStyleInfo(int part); + void startTitleHead(const char *); + void startTitle(); + void endTitleHead(const char *,const char *name); + void endTitle() {} + + void newParagraph(); + void startParagraph(); + void endParagraph(); + void writeString(const char *text); + void startIndexListItem(); + void endIndexListItem(); + void startIndexList(); + void endIndexList(); + void startIndexKey(); + void endIndexKey(); + void startIndexValue(bool); + void endIndexValue(const char *,bool); + void startItemList(); + void endItemList(); + void startIndexItem(const char *ref,const char *file); + void endIndexItem(const char *ref,const char *file); + void docify(const char *text); + void codify(const char *text); + void writeObjectLink(const char *ref,const char *file, + const char *anchor,const char *name); + void writeCodeLink(const char *ref, const char *file, + const char *anchor,const char *name, + const char *tooltip); + void startTextLink(const char *f,const char *anchor); + void endTextLink(); + void startHtmlLink(const char *url); + void endHtmlLink(); + void startTypewriter() { t << "{\\f2 "; } + void endTypewriter() { t << "}"; } + void startGroupHeader(int); + void endGroupHeader(int); + //void writeListItem(); + void startItemListItem(); + void endItemListItem(); + + void startMemberSections() {} + void endMemberSections() {} + void startHeaderSection() {} + void endHeaderSection() {} + void startMemberHeader(const char *) { startGroupHeader(FALSE); } + void endMemberHeader() { endGroupHeader(FALSE); } + void startMemberSubtitle(); + void endMemberSubtitle(); + void startMemberDocList() {} + void endMemberDocList() {} + void startMemberList(); + void endMemberList(); + void startInlineHeader(); + void endInlineHeader(); + void startAnonTypeScope(int) {} + void endAnonTypeScope(int) {} + void startMemberItem(const char *,int); + void endMemberItem(); + void startMemberTemplateParams() {} + void endMemberTemplateParams(const char *) {} + void insertMemberAlign(bool) {} + + void writeRuler() { rtfwriteRuler_thin(); } + + void writeAnchor(const char *fileName,const char *name); + void startCodeFragment(); + void endCodeFragment(); + void writeLineNumber(const char *,const char *,const char *,int l) { t << l << " "; } + void startCodeLine() { col=0; } + void endCodeLine() { lineBreak(); } + void startEmphasis() { t << "{\\i "; } + void endEmphasis() { t << "}"; } + void startBold() { t << "{\\b "; } + void endBold() { t << "}"; } + void startDescription(); + void endDescription(); + void startDescItem(); + void endDescItem(); + void lineBreak(const char *style=0); + void startMemberDoc(const char *,const char *,const char *,const char *,bool); + void endMemberDoc(bool); + void startDoxyAnchor(const char *,const char *,const char *,const char *,const char *); + void endDoxyAnchor(const char *,const char *); + void startCodeAnchor(const char *) {}; + void endCodeAnchor() {}; + void writeChar(char c); + void writeLatexSpacing() {};//{ t << "\\hspace{0.3cm}"; } + void writeStartAnnoItem(const char *type,const char *file, + const char *path,const char *name); + void writeEndAnnoItem(const char *name); + void startSubsection(); + void endSubsection(); + void startSubsubsection(); + void endSubsubsection(); + void startCenter() { t << "{\\qc" << endl; } + void endCenter() { t << "}"; } + void startSmall() { t << "{\\sub "; } + void endSmall() { t << "}"; } + + void startMemberDescription(const char *); + void endMemberDescription(); + void startDescList(SectionTypes); + void startSimpleSect(SectionTypes,const char *,const char *,const char *); + void endSimpleSect(); + void startParamList(ParamListTypes,const char *); + void endParamList(); + //void writeDescItem(); + void startDescForItem(); + void endDescForItem(); + void startSection(const char *,const char *,SectionInfo::SectionType); + void endSection(const char *,SectionInfo::SectionType); + void addIndexItem(const char *,const char *); + void startIndent(); + void endIndent(); + void writeSynopsis() {} + void startClassDiagram(); + void endClassDiagram(const ClassDiagram &,const char *filename,const char *name); + void startPageRef(); + void endPageRef(const char *,const char *); + void startQuickIndices() {} + void endQuickIndices() {} + void writeSplitBar(const char *) {} + void writeLogo() {} + void writeQuickLinks(bool,HighlightedItem,const char *) {} + void startContents() {} + void endContents() {} + void writeNonBreakableSpace(int); + + void startDescTable(); + void endDescTable(); + void startDescTableTitle(); + void endDescTableTitle(); + void startDescTableData(); + void endDescTableData(); + + void startDotGraph(); + void endDotGraph(const DotClassGraph &); + void startInclDepGraph(); + void endInclDepGraph(const DotInclDepGraph &); + void startGroupCollaboration(); + void endGroupCollaboration(const DotGroupCollaboration &g); + void startCallGraph(); + void endCallGraph(const DotCallGraph &); + void startDirDepGraph(); + void endDirDepGraph(const DotDirDeps &g); + void writeGraphicalHierarchy(const DotGfxHierarchyTable &) {} + + void startMemberGroupHeader(bool); + void endMemberGroupHeader(); + void startMemberGroupDocs(); + void endMemberGroupDocs(); + void startMemberGroup(); + void endMemberGroup(bool); + + void startTextBlock(bool dense); + void endTextBlock(bool); + void lastIndexPage(); + + void startMemberDocPrefixItem() {} + void endMemberDocPrefixItem() {} + void startMemberDocName(bool) {} + void endMemberDocName() {} + void startParameterType(bool,const char *); + void endParameterType(); + void startParameterName(bool) {} + void endParameterName(bool,bool,bool) {} + void startParameterList(bool) {} + void endParameterList() {} + + void startConstraintList(const char *); + void startConstraintParam(); + void endConstraintParam(); + void startConstraintType(); + void endConstraintType(); + void startConstraintDocs(); + void endConstraintDocs(); + void endConstraintList(); + + void startMemberDocSimple(); + void endMemberDocSimple(); + void startInlineMemberType(); + void endInlineMemberType(); + void startInlineMemberName(); + void endInlineMemberName(); + void startInlineMemberDoc(); + void endInlineMemberDoc(); + + void startFontClass(const char *) {} + void endFontClass() {} + + void writeCodeAnchor(const char *) {} + void linkableSymbol(int,const char *,Definition *,Definition *) {} + + static bool preProcessFileInplace(const char *path,const char *name); + + private: + RTFGenerator(const RTFGenerator &); + RTFGenerator &operator=(const RTFGenerator &); + + const char *rtf_BList_DepthStyle(); + const char *rtf_CList_DepthStyle(); + const char *rtf_EList_DepthStyle(); + const char *rtf_LCList_DepthStyle(); + const char *rtf_DList_DepthStyle(); + const char *rtf_Code_DepthStyle(); + void incrementIndentLevel(); + void decrementIndentLevel(); + int col; + + bool m_bstartedBody; // has startbody been called yet? + int m_listLevel; // // RTF does not really have a addative indent...manually set list level. + bool m_omitParagraph; // should a the next paragraph command be ignored? + int m_numCols; // number of columns in a table + QCString relPath; + + void beginRTFDocument(); + void beginRTFChapter(); + void beginRTFSection(); + void rtfwriteRuler_doubleline(); + void rtfwriteRuler_emboss(); + void rtfwriteRuler_thick(); + void rtfwriteRuler_thin(); + void writeRTFReference(const char *label); + //char *getMultiByte(int c); +}; + +#endif diff --git a/trunk/src/rtfstyle.cpp b/trunk/src/rtfstyle.cpp new file mode 100644 index 0000000..716cf2a --- /dev/null +++ b/trunk/src/rtfstyle.cpp @@ -0,0 +1,518 @@ +/****************************************************************************** + * + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#include "rtfstyle.h" + +#include +#include +#include + +#include "message.h" + + +RTFListItemInfo rtf_listItemInfo[rtf_maxIndentLevels]; + +QCString rtf_title; +QCString rtf_subject; +QCString rtf_comments; +QCString rtf_company; +QCString rtf_logoFilename; +QCString rtf_author; +QCString rtf_manager; +QCString rtf_documentType; +QCString rtf_documentId; +QCString rtf_keywords; + +char rtf_Style_Reset[] = "\\pard\\plain "; + +Rtf_Style_Default rtf_Style_Default[] = +{ + { "Heading1", + "\\s1\\sb240\\sa60\\keepn\\widctlpar\\adjustright \\b\\f1\\fs36\\kerning36\\cgrid ", + "\\sbasedon0 \\snext0 heading 1" + }, + { "Heading2", + "\\s2\\sb240\\sa60\\keepn\\widctlpar\\adjustright \\b\\f1\\fs28\\kerning28\\cgrid ", + "\\sbasedon0 \\snext0 heading 2" + }, + { "Heading3", + "\\s3\\sb240\\sa60\\keepn\\widctlpar\\adjustright \\b\\f1\\cgrid ", + "\\sbasedon0 \\snext0 heading 3" + }, + { "Heading4", + "\\s4\\sb240\\sa60\\keepn\\widctlpar\\adjustright \\b\\f1\\fs20\\cgrid ", + "\\sbasedon0 \\snext0 heading 4;}{\\*\\cs10 \\additive Default Paragraph Font" + }, + { "Heading5", + "\\s5\\sb90\\sa30\\keepn\\widctlpar\\adjustright \\b\\f1\\fs20\\cgrid ", + "\\sbasedon0 \\snext0 heading 5;}{\\*\\cs10 \\additive Default Paragraph Font" + }, + { "Title", + "\\s15\\qc\\sb240\\sa60\\widctlpar\\outlinelevel0\\adjustright \\b\\f1\\fs32\\kerning28\\cgrid ", + "\\sbasedon0 \\snext15 Title" + }, + { "SubTitle", + "\\s16\\qc\\sa60\\widctlpar\\outlinelevel1\\adjustright \\f1\\cgrid ", + "\\sbasedon0 \\snext16 Subtitle" + }, + { "BodyText", + "\\s17\\sa60\\sb30\\widctlpar\\qj \\fs22\\cgrid ", + "\\sbasedon0 \\snext17 BodyText" + }, + { "DenseText", + "\\s18\\widctlpar\\fs22\\cgrid ", + "\\sbasedon0 \\snext18 DenseText" + }, + { "Header", + "\\s28\\widctlpar\\tqc\\tx4320\\tqr\\tx8640\\adjustright \\fs20\\cgrid ", + "\\sbasedon0 \\snext28 header" + }, + { "Footer", + "\\s29\\widctlpar\\tqc\\tx4320\\tqr\\tx8640\\qr\\adjustright \\fs20\\cgrid ", + "\\sbasedon0 \\snext29 footer" + }, + { "GroupHeader", + "\\s30\\li360\\sa60\\sb120\\keepn\\widctlpar\\adjustright \\b\\f1\\fs20\\cgrid ", + "\\sbasedon0 \\snext30 GroupHeader" + }, + { "CodeExample0", + "\\s40\\li0\\widctlpar\\adjustright \\shading1000\\cbpat8 \\f2\\fs16\\cgrid ", + "\\sbasedon0 \\snext41 Code Example 0" + }, + { "CodeExample1", + "\\s41\\li360\\widctlpar\\adjustright \\shading1000\\cbpat8 \\f2\\fs16\\cgrid ", + "\\sbasedon0 \\snext42 Code Example 1" + }, + { "CodeExample2", + "\\s42\\li720\\widctlpar\\adjustright \\shading1000\\cbpat8 \\f2\\fs16\\cgrid ", + "\\sbasedon0 \\snext43 Code Example 2" + }, + { "CodeExample3", + "\\s43\\li1080\\widctlpar\\adjustright \\shading1000\\cbpat8 \\f2\\fs16\\cgrid ", + "\\sbasedon0 \\snext44 Code Example 3" + }, + { "CodeExample4", + "\\s44\\li1440\\widctlpar\\adjustright \\shading1000\\cbpat8 \\f2\\fs16\\cgrid ", + "\\sbasedon0 \\snext45 Code Example 4" + }, + { "CodeExample5", + "\\s45\\li1800\\widctlpar\\adjustright \\shading1000\\cbpat8 \\f2\\fs16\\cgrid ", + "\\sbasedon0 \\snext46 Code Example 5" + }, + { "CodeExample6", + "\\s46\\li2160\\widctlpar\\adjustright \\shading1000\\cbpat8 \\f2\\fs16\\cgrid ", + "\\sbasedon0 \\snext47 Code Example 6" + }, + { "CodeExample7", + "\\s47\\li2520\\widctlpar\\adjustright \\shading1000\\cbpat8 \\f2\\fs16\\cgrid ", + "\\sbasedon0 \\snext48 Code Example 7" + }, + { "CodeExample8", + "\\s48\\li2880\\widctlpar\\adjustright \\shading1000\\cbpat8 \\f2\\fs16\\cgrid ", + "\\sbasedon0 \\snext49 Code Example 8" + }, + { "CodeExample9", + "\\s49\\li3240\\widctlpar\\adjustright \\shading1000\\cbpat8 \\f2\\fs16\\cgrid ", + "\\sbasedon0 \\snext49 Code Example 9" + }, + { "ListContinue0", + "\\s50\\li0\\sa60\\sb30\\qj\\widctlpar\\qj\\adjustright \\fs20\\cgrid ", + "\\sbasedon0 \\snext51 List Continue 0" + }, + { "ListContinue1", + "\\s51\\li360\\sa60\\sb30\\qj\\widctlpar\\qj\\adjustright \\fs20\\cgrid ", + "\\sbasedon0 \\snext52 List Continue 1" + }, + { "ListContinue2", + "\\s52\\li720\\sa60\\sb30\\qj\\widctlpar\\qj\\adjustright \\fs20\\cgrid ", + "\\sbasedon0 \\snext53 List Continue 2" + }, + { "ListContinue3", + "\\s53\\li1080\\sa60\\sb30\\qj\\widctlpar\\qj\\adjustright \\fs20\\cgrid ", + "\\sbasedon0 \\snext54 List Continue 3" + }, + { "ListContinue4", + "\\s54\\li1440\\sa60\\sb30\\qj\\widctlpar\\qj\\adjustright \\fs20\\cgrid ", + "\\sbasedon0 \\snext55 List Continue 4" + }, + { "ListContinue5", + "\\s55\\li1800\\sa60\\sb30\\qj\\widctlpar\\qj\\adjustright \\fs20\\cgrid ", + "\\sbasedon0 \\snext56 List Continue 5" + }, + { "ListContinue6", + "\\s56\\li2160\\sa60\\sb30\\qj\\widctlpar\\qj\\adjustright \\fs20\\cgrid ", + "\\sbasedon0 \\snext57 List Continue 6" + }, + { "ListContinue7", + "\\s57\\li2520\\sa60\\sb30\\qj\\widctlpar\\qj\\adjustright \\fs20\\cgrid ", + "\\sbasedon0 \\snext58 List Continue 7" + }, + { "ListContinue8", + "\\s58\\li2880\\sa60\\sb30\\qj\\widctlpar\\qj\\adjustright \\fs20\\cgrid ", + "\\sbasedon0 \\snext59 List Continue 8" + }, + { "ListContinue9", + "\\s59\\li3240\\sa60\\sb30\\qj\\widctlpar\\qj\\adjustright \\fs20\\cgrid ", + "\\sbasedon0 \\snext59 List Continue 9" + }, + { "DescContinue0", + "\\s60\\li0\\widctlpar\\ql\\adjustright \\fs20\\cgrid ", + "\\sbasedon0 \\snext61 DescContinue 0" + }, + { "DescContinue1", + "\\s61\\li360\\widctlpar\\ql\\adjustright \\fs20\\cgrid ", + "\\sbasedon0 \\snext62 DescContinue 1" + }, + { "DescContinue2", + "\\s62\\li720\\widctlpar\\ql\\adjustright \\fs20\\cgrid ", + "\\sbasedon0 \\snext63 DescContinue 2" + }, + { "DescContinue3", + "\\s63\\li1080\\widctlpar\\ql\\adjustright \\fs20\\cgrid ", + "\\sbasedon0 \\snext64 DescContinue 3" + }, + { "DescContinue4", + "\\s64\\li1440\\widctlpar\\ql\\adjustright \\fs20\\cgrid ", + "\\sbasedon0 \\snext65 DescContinue 4" + }, + { "DescContinue5", + "\\s65\\li1800\\widctlpar\\ql\\adjustright \\fs20\\cgrid ", + "\\sbasedon0 \\snext66 DescContinue 5" + }, + { "DescContinue6", + "\\s66\\li2160\\widctlpar\\ql\\adjustright \\fs20\\cgrid ", + "\\sbasedon0 \\snext67 DescContinue 6" + }, + { "DescContinue7", + "\\s67\\li2520\\widctlpar\\ql\\adjustright \\fs20\\cgrid ", + "\\sbasedon0 \\snext68 DescContinue 7" + }, + { "DescContinue8", + "\\s68\\li2880\\widctlpar\\ql\\adjustright \\fs20\\cgrid ", + "\\sbasedon0 \\snext69 DescContinue 8" + }, + { "DescContinue9", + "\\s69\\li3240\\widctlpar\\ql\\adjustright \\fs20\\cgrid ", + "\\sbasedon0 \\snext69 DescContinue 9" + }, + { "LatexTOC0", + "\\s70\\li0\\sa30\\sb30\\widctlpar\\tqr\\tldot\\tx8640\\adjustright \\fs20\\cgrid ", + "\\sbasedon0 \\snext81 LatexTOC 0" + }, + { "LatexTOC1", + "\\s71\\li360\\sa27\\sb27\\widctlpar\\tqr\\tldot\\tx8640\\adjustright \\fs20\\cgrid ", + "\\sbasedon0 \\snext82 LatexTOC 1" + }, + { "LatexTOC2", + "\\s72\\li720\\sa24\\sb24\\widctlpar\\tqr\\tldot\\tx8640\\adjustright \\fs20\\cgrid ", + "\\sbasedon0 \\snext83 LatexTOC 2" + }, + { "LatexTOC3", + "\\s73\\li1080\\sa21\\sb21\\widctlpar\\tqr\\tldot\\tx8640\\adjustright \\fs20\\cgrid ", + "\\sbasedon0 \\snext84 LatexTOC 3" + }, + { "LatexTOC4", + "\\s74\\li1440\\sa18\\sb18\\widctlpar\\tqr\\tldot\\tx8640\\adjustright \\fs20\\cgrid ", + "\\sbasedon0 \\snext85 LatexTOC 4" + }, + { "LatexTOC5", + "\\s75\\li1800\\sa15\\sb15\\widctlpar\\tqr\\tldot\\tx8640\\adjustright \\fs20\\cgrid ", + "\\sbasedon0 \\snext86 LatexTOC 5" + }, + { "LatexTOC6", + "\\s76\\li2160\\sa12\\sb12\\widctlpar\\tqr\\tldot\\tx8640\\adjustright \\fs20\\cgrid ", + "\\sbasedon0 \\snext87 LatexTOC 6" + }, + { "LatexTOC7", + "\\s77\\li2520\\sa9\\sb9\\widctlpar\\tqr\\tldot\\tx8640\\adjustright \\fs20\\cgrid ", + "\\sbasedon0 \\snext88 LatexTOC 7" + }, + { "LatexTOC8", + "\\s78\\li2880\\sa6\\sb6\\widctlpar\\tqr\\tldot\\tx8640\\adjustright \\fs20\\cgrid ", + "\\sbasedon0 \\snext89 LatexTOC 8" + }, + { "LatexTOC9", + "\\s79\\li3240\\sa3\\sb3\\widctlpar\\tqr\\tldot\\tx8640\\adjustright \\fs20\\cgrid ", + "\\sbasedon0 \\snext89 LatexTOC 9" + }, + { "ListBullet0", + "\\s80\\fi-360\\li360\\widctlpar\\jclisttab\\tx360{\\*\\pn \\pnlvlbody\\ilvl0\\ls1\\pnrnot0\\pndec }\\ls1\\adjustright \\fs20\\cgrid ", + "\\sbasedon0 \\snext81 \\sautoupd List Bullet 0" + }, + { "ListBullet1", + "\\s81\\fi-360\\li720\\widctlpar\\jclisttab\\tx720{\\*\\pn \\pnlvlbody\\ilvl0\\ls2\\pnrnot0\\pndec }\\ls2\\adjustright \\fs20\\cgrid ", + "\\sbasedon0 \\snext82 \\sautoupd List Bullet 1" + }, + { "ListBullet2", + "\\s82\\fi-360\\li1080\\widctlpar\\jclisttab\\tx1080{\\*\\pn \\pnlvlbody\\ilvl0\\ls3\\pnrnot0\\pndec }\\ls3\\adjustright \\fs20\\cgrid ", + "\\sbasedon0 \\snext83 \\sautoupd List Bullet 2" + }, + { "ListBullet3", + "\\s83\\fi-360\\li1440\\widctlpar\\jclisttab\\tx1440{\\*\\pn \\pnlvlbody\\ilvl0\\ls4\\pnrnot0\\pndec }\\ls4\\adjustright \\fs20\\cgrid ", + "\\sbasedon0 \\snext84 \\sautoupd List Bullet 3" + }, + { "ListBullet4", + "\\s84\\fi-360\\li1800\\widctlpar\\jclisttab\\tx1800{\\*\\pn \\pnlvlbody\\ilvl0\\ls5\\pnrnot0\\pndec }\\ls5\\adjustright \\fs20\\cgrid ", + "\\sbasedon0 \\snext85 \\sautoupd List Bullet 4" + }, + { "ListBullet5", + "\\s85\\fi-360\\li2160\\widctlpar\\jclisttab\\tx2160{\\*\\pn \\pnlvlbody\\ilvl0\\ls6\\pnrnot0\\pndec }\\ls6\\adjustright \\fs20\\cgrid ", + "\\sbasedon0 \\snext86 \\sautoupd List Bullet 5" + }, + { "ListBullet6", + "\\s86\\fi-360\\li2520\\widctlpar\\jclisttab\\tx2520{\\*\\pn \\pnlvlbody\\ilvl0\\ls7\\pnrnot0\\pndec }\\ls7\\adjustright \\fs20\\cgrid ", + "\\sbasedon0 \\snext87 \\sautoupd List Bullet 6" + }, + { "ListBullet7", + "\\s87\\fi-360\\li2880\\widctlpar\\jclisttab\\tx2880{\\*\\pn \\pnlvlbody\\ilvl0\\ls8\\pnrnot0\\pndec }\\ls8\\adjustright \\fs20\\cgrid ", + "\\sbasedon0 \\snext88 \\sautoupd List Bullet 7" + }, + { "ListBullet8", + "\\s88\\fi-360\\li3240\\widctlpar\\jclisttab\\tx3240{\\*\\pn \\pnlvlbody\\ilvl0\\ls9\\pnrnot0\\pndec }\\ls9\\adjustright \\fs20\\cgrid ", + "\\sbasedon0 \\snext89 \\sautoupd List Bullet 8" + }, + { "ListBullet9", + "\\s89\\fi-360\\li3600\\widctlpar\\jclisttab\\tx3600{\\*\\pn \\pnlvlbody\\ilvl0\\ls10\\pnrnot0\\pndec }\\ls10\\adjustright \\fs20\\cgrid ", + "\\sbasedon0 \\snext89 \\sautoupd List Bullet 9" + }, + { "ListEnum0", + "\\s90\\fi-360\\li360\\widctlpar\\fs20\\cgrid ", + "\\sbasedon0 \\snext91 \\sautoupd List Enum 0" + }, + { "ListEnum1", + "\\s91\\fi-360\\li720\\widctlpar\\fs20\\cgrid ", + "\\sbasedon0 \\snext92 \\sautoupd List Enum 1" + }, + { "ListEnum2", + "\\s92\\fi-360\\li1080\\widctlpar\\fs20\\cgrid ", + "\\sbasedon0 \\snext93 \\sautoupd List Enum 2" + }, + { "ListEnum3", + "\\s93\\fi-360\\li1440\\widctlpar\\fs20\\cgrid ", + "\\sbasedon0 \\snext94 \\sautoupd List Enum 3" + }, + { "ListEnum4", + "\\s94\\fi-360\\li1800\\widctlpar\\fs20\\cgrid ", + "\\sbasedon0 \\snext95 \\sautoupd List Enum 4" + }, + { "ListEnum5", + "\\s95\\fi-360\\li2160\\widctlpar\\fs20\\cgrid ", + "\\sbasedon0 \\snext96 \\sautoupd List Enum 5" + }, + { "ListEnum6", + "\\s96\\fi-360\\li2520\\widctlpar\\fs20\\cgrid ", + "\\sbasedon0 \\snext96 \\sautoupd List Enum 5" + }, + { "ListEnum7", + "\\s97\\fi-360\\li2880\\widctlpar\\fs20\\cgrid ", + "\\sbasedon0 \\snext98 \\sautoupd List Enum 7" + }, + { "ListEnum8", + "\\s98\\fi-360\\li3240\\widctlpar\\fs20\\cgrid ", + "\\sbasedon0 \\snext99 \\sautoupd List Enum 8" + }, + { "ListEnum9", + "\\s99\\fi-360\\li3600\\widctlpar\\fs20\\cgrid ", + "\\sbasedon0 \\snext99 \\sautoupd List Enum 9" + }, + { 0, + 0, + 0 + } +}; + +const QRegExp StyleData::s_clause("\\\\s[0-9]+\\s*"); + +StyleData::StyleData(const char* reference, const char* definition) +{ + int start = s_clause.match(reference); ASSERT(start >= 0); + reference += start; + index = (int)atol(reference + 2); ASSERT(index > 0); + + ASSERT(reference != 0); + size_t size = 1 + strlen(reference); + memcpy(this->reference = new char[size], reference, size); + + ASSERT(definition != 0); + size = 1 + strlen(definition); + memcpy(this->definition = new char[size], definition, size); +} + +StyleData::~StyleData() +{ + delete[] reference; + delete[] definition; +} + +bool StyleData::setStyle(const char* s, const char* styleName) +{ + static const QRegExp subgroup("^{[^}]*}\\s*"); + static const QRegExp any_clause("^\\\\[a-z][a-z0-9-]*\\s*"); + + int len = 0; // length of a particular RTF formatting control + int ref_len = 0; // length of the whole formatting section of a style + int start = s_clause.match(s, 0, &len); + if (start < 0) + { + err("Style sheet '%s' contains no '\\s' clause.\n{%s}\n", styleName, s); + return FALSE; + } + s += start; + index = (int)atol(s + 2); ASSERT(index > 0); + + // search for the end of pure formatting codes + const char* end = s + len; + ref_len = len; + bool haveNewDefinition = TRUE; + for(;;) + { + if (*end == '{') + { + // subgroups are used for \\additive + if (0 != subgroup.match(end, 0, &len)) + break; + else + { + end += len; + ref_len += len; + } + } + else if (*end == '\\') + { + if (0 == strncmp(end, "\\snext", 6)) + break; + if (0 == strncmp(end, "\\sbasedon", 9)) + break; + if (0 != any_clause.match(end, 0, &len)) + break; + end += len; + ref_len += len; + } + else if (*end == 0) + { // no style-definition part, keep default value + haveNewDefinition = FALSE; + break; + } + else // plain name without leading \\snext + break; + } + delete[] reference; + reference = new char[ref_len + 1]; + memcpy(reference, s, ref_len); + reference[ref_len] = 0; + if (haveNewDefinition) + { + delete[] definition; + size_t size = 1 + strlen(end); + definition = new char[size]; + memcpy(definition, end, size); + } + return TRUE; +} + +void loadStylesheet(const char *name, QDict& dict) +{ + QFile file(name); + if (!file.open(IO_ReadOnly)) + { + err("Can't open RTF style sheet file %s. Using defaults.\n",name); + return; + } + msg("Loading RTF style sheet %s...\n",name); + + static const QRegExp separator("[ \t]*=[ \t]*"); + uint lineNr=1; + QTextStream t(&file); + t.setEncoding(QTextStream::UnicodeUTF8); + + while (!t.eof()) + { + QCString s(4096); // string buffer of max line length + s = t.readLine().stripWhiteSpace(); + if (s.isEmpty() || s.at(0)=='#') continue; // skip blanks & comments + int sepLength; + int sepStart = separator.match(s,0,&sepLength); + if (sepStart<=0) // no valid assignment statement + { + warn(name,lineNr,"Assignment of style sheet name expected!\n"); + continue; + } + QCString key=s.left(sepStart); + if (dict[key]==0) // not a valid style sheet name + { + warn(name,lineNr,"Invalid style sheet name %s ignored.\n",key.data()); + continue; + } + StyleData* styleData = dict.find(key); + if (styleData == 0) + { + warn(name,lineNr,"Unknown style sheet name %s ignored.\n",key.data()); + continue; + } + s+=" "; // add command separator + styleData->setStyle(s.data() + sepStart + sepLength, key.data()); + lineNr++; + } +} + +QDict rtf_Style(257); + +void loadExtensions(const char *name) +{ + QFile file(name); + if (!file.open(IO_ReadOnly)) + { + err("Can't open RTF extensions file %s. Using defaults.\n",name); + return; + } + msg("Loading RTF extensions %s...\n",name); + + static const QRegExp separator("[ \t]*=[ \t]*"); + uint lineNr=1; + QTextStream t(&file); + t.setEncoding(QTextStream::UnicodeUTF8); + + while (!t.eof()) + { + QCString s(4096); // string buffer of max line length + s = t.readLine().stripWhiteSpace(); + if (s.length()==0 || s.at(0)=='#') continue; // skip blanks & comments + int sepLength; + int sepStart = separator.match(s,0,&sepLength); + if (sepStart<=0) // no valid assignment statement + { + warn(name,lineNr,"Assignment of extension field expected!\n"); + continue; + } + QCString key=s.left(sepStart); + QCString data=s.data() + sepStart + sepLength; + + if (key == "Title") rtf_title = data.data(); + if (key == "Subject") rtf_subject = data.data(); + if (key == "Comments") rtf_comments = data.data(); + if (key == "Company") rtf_company = data.data(); + if (key == "LogoFilename") rtf_logoFilename = data.data(); + if (key == "Author") rtf_author = data.data(); + if (key == "Manager") rtf_manager = data.data(); + if (key == "DocumentType") rtf_documentType = data.data(); + if (key == "DocumentId") rtf_documentId = data.data(); + if (key == "Keywords") rtf_keywords = data.data(); + lineNr++; + } +} + diff --git a/trunk/src/rtfstyle.h b/trunk/src/rtfstyle.h new file mode 100644 index 0000000..3dd4897 --- /dev/null +++ b/trunk/src/rtfstyle.h @@ -0,0 +1,83 @@ +/****************************************************************************** + * + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#ifndef RTFSTYLE_H +#define RTFSTYLE_H + +#include "qtbc.h" +#include +#include + +// used for table column width calculation +const int rtf_pageWidth = 8748; + +extern QCString rtf_title; +extern QCString rtf_subject; +extern QCString rtf_comments; +extern QCString rtf_company; +extern QCString rtf_logoFilename; +extern QCString rtf_author; +extern QCString rtf_manager; +extern QCString rtf_documentType; +extern QCString rtf_documentId; +extern QCString rtf_keywords; + +struct RTFListItemInfo +{ + bool isEnum; + int number; +}; + +const int rtf_maxIndentLevels = 10; + +extern RTFListItemInfo rtf_listItemInfo[rtf_maxIndentLevels]; + +struct Rtf_Style_Default +{ + const char *name; + const char *reference; + const char *definition; +}; + +extern char rtf_Style_Reset[]; +extern Rtf_Style_Default rtf_Style_Default[]; + +struct StyleData +{ + // elements of this type are stored in dictionary Rtf_Style + // + // to define a tag in the header reference + definition is required + // to use a tag in the body of the document only reference is required + + unsigned index; // index in style-sheet, i.e. number in s-clause + char* reference; // everything required to apply the style + char* definition; // aditional tags like \snext and style name + + StyleData(const char* reference, const char* definition); + ~StyleData(); + bool setStyle(const char* s, const char* styleName); + + static const QRegExp s_clause; +}; + +extern QDict rtf_Style; + +void loadExtensions(const char *name); +void loadStylesheet(const char *name, QDict& dict); + +#endif diff --git a/trunk/src/scanner.h b/trunk/src/scanner.h new file mode 100644 index 0000000..70dad99 --- /dev/null +++ b/trunk/src/scanner.h @@ -0,0 +1,55 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#ifndef SCANNER_H +#define SCANNER_H + +#include "parserintf.h" + +/** \brief C-like language parser using state-based lexical scanning. + * + * This is the language parser for doxygen. It is somewhat fuzzy and + * supports C++ and various languages that are closely related to C++, + * such as C, C#, Objective-C, Java, PHP, and IDL. + */ +class CLanguageScanner : public ParserInterface +{ + public: + virtual ~CLanguageScanner() {} + void parseInput(const char *fileName, + const char *fileBuf, + Entry *root); + bool needsPreprocessing(const QCString &extension); + void parseCode(CodeOutputInterface &codeOutIntf, + const char *scopeName, + const QCString &input, + bool isExampleBlock, + const char *exampleName=0, + FileDef *fileDef=0, + int startLine=-1, + int endLine=-1, + bool inlineFragment=FALSE, + MemberDef *memberDef=0, + bool showLineNumbers=TRUE + ); + void resetCodeParserState(); + void parsePrototype(const char *text); +}; + +void scanFreeScanner(); + +#endif diff --git a/trunk/src/scanner.l b/trunk/src/scanner.l new file mode 100644 index 0000000..7bf8f2b --- /dev/null +++ b/trunk/src/scanner.l @@ -0,0 +1,6154 @@ +/***************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +%{ + +/* + * includes + */ +#include +#include +#include +#include + +#include "qtbc.h" +#include +#include +#include +#include +#include + +#include "scanner.h" +#include "entry.h" +#include "message.h" +#include "config.h" +#include "doxygen.h" +#include "util.h" +#include "defargs.h" +#include "language.h" +#include "commentscan.h" +#include "code.h" +#include "arguments.h" + +#define YY_NEVER_INTERACTIVE 1 + +/* ----------------------------------------------------------------- + * + * statics + */ +static ParserInterface *g_thisParser; +static const char * inputString; +static int inputPosition; +static QFile inputFile; +static int lastContext; +static int lastCContext; +static int lastDocContext; +static int lastCPPContext; +static int lastSkipSharpContext; +static int lastSkipRoundContext; +static int lastStringContext; +static int lastCurlyContext; +static int lastRoundContext; +static int lastSquareContext; +static int lastInitializerContext; +static int lastClassTemplSpecContext; +static int lastPreLineCtrlContext; +static int lastSkipVerbStringContext; +static int lastCommentInArgContext; +static int lastCSConstraint; +static int lastHereDocContext; +static int lastDefineContext; +static Protection protection; +static Protection baseProt; +static int sharpCount = 0 ; +static int roundCount = 0 ; +static int curlyCount = 0 ; +static int squareCount = 0 ; +static int padCount = 0 ; +static QCString slString; +static Entry* current_root = 0 ; +static Entry* global_root = 0 ; +static Entry* current = 0 ; +static Entry* previous = 0 ; +static Entry* tempEntry = 0 ; +static Entry* firstTypedefEntry = 0 ; +static Entry* memspecEntry = 0 ; +static int yyLineNr = 1 ; +static int anonCount = 0 ; +static int anonNSCount = 0 ; +static QCString yyFileName; +static MethodTypes mtype; +static bool gstat; +static bool removeSlashes; +static Specifier virt; +static Specifier baseVirt; +static QCString msType,msName,msArgs; +static bool isTypedef; +static int tmpDocType; +static QCString sectionLabel; +static QCString sectionTitle; +static QCString funcPtrType; +static QCString templateStr; +static QCString aliasName; +static QCString baseName; +static QCString* specName; +static QCString formulaText; +static QCString formulaEnd; +static bool useOverrideCommands = FALSE; + +static SrcLangExt language; +static bool insideIDL = FALSE; //!< processing IDL code? +static bool insideJava = FALSE; //!< processing Java code? +static bool insideCS = FALSE; //!< processing C# code? +static bool insideD = FALSE; //!< processing D code? +static bool insidePHP = FALSE; //!< processing PHP code? +static bool insideObjC = FALSE; //!< processing Objective C code? +static bool insideCli = FALSE; //!< processing C++/CLI code? +static bool insideJS = FALSE; //!< processing JavaScript code? + +static bool insideCppQuote = FALSE; +static bool insideProtocolList = FALSE; + +static int argRoundCount; +static int argSharpCount; +static int currentArgumentContext; +static int lastCopyArgStringContext; +static int lastCopyArgContext; +static QCString *copyArgString; +static QCString fullArgString; + +static ArgumentList *currentArgumentList; +static char lastCopyArgChar; + +static QCString *pCopyQuotedString; +static QCString *pCopyRoundString; +static QCString *pCopyCurlyString; + +static QGString *pCopyCurlyGString; +static QGString *pCopyRoundGString; +static QGString *pCopyQuotedGString; +static QGString *pCopyHereDocGString; +static QGString *pSkipVerbString; +static QStack autoGroupStack; + +static bool insideFormula; +static bool insideTryBlock=FALSE; +static bool insideCode; +static bool needsSemi; + +//static int depthIf; +static int initBracketCount; +static QCString memberGroupRelates; +static QCString memberGroupInside; +static QCString xrefItemKey; +static QCString xrefItemTitle; +static QCString xrefListTitle; + +static QCString g_skipBlockName; +static QCString oldStyleArgType; +static QCString docBackup; +static QCString briefBackup; +static bool g_inputFromFile; + +static int docBlockContext; +static QGString docBlock; +static QCString docBlockName; +static bool docBlockInBody; +static bool docBlockAutoBrief; +static char docBlockTerm; + +static QCString idlAttr; +static QCString idlProp; + +static bool g_lexInit = FALSE; +static bool externC; + +static QCString g_hereDocId; + +//----------------------------------------------------------------------------- + +// forward declarations +//static void handleGroupStartCommand(const char *header); +//static void handleGroupEndCommand(); + +//----------------------------------------------------------------------------- + +static void initParser() +{ + sectionLabel.resize(0); + sectionTitle.resize(0); + baseName.resize(0); + formulaText.resize(0); + protection = Public; + baseProt = Public; + sharpCount = 0; + roundCount = 0; + curlyCount = 0; + mtype = Method; + gstat = FALSE; + virt = Normal; + baseVirt = Normal; + isTypedef = FALSE; + autoGroupStack.clear(); + insideTryBlock = FALSE; + autoGroupStack.setAutoDelete(TRUE); + insideFormula = FALSE; + insideCode=FALSE; + insideCli=Config_getBool("CPP_CLI_SUPPORT"); + previous = 0; +} + +static void initEntry() +{ + if (insideJava) + { + protection = (current_root->spec & (Entry::Interface|Entry::Enum)) ? Public : Package; + } + current->protection = protection ; + current->mtype = mtype; + current->virt = virt; + current->stat = gstat; + current->lang = language; + //printf("*** initEntry() language=%d\n",language); + //if (!autoGroupStack.isEmpty()) + //{ + // //printf("Appending group %s\n",autoGroupStack.top()->groupname.data()); + // current->groups->append(new Grouping(*autoGroupStack.top())); + //} + initGroupInfo(current); + isTypedef=FALSE; +} + + +//----------------------------------------------------------------------------- + +///// remove any automatic grouping and add new one (if given) +//static void setCurrentGroup( QCString *newgroup, Grouping::GroupPri_t pri ) +//{ +// /* remove auto group name from current entry and discard it */ +// Grouping *g = current->groups->first(); +// int i=0; +// while (g) +// { +// if (g->pri <= Grouping::GROUPING_AUTO_DEF) +// { +// current->groups->remove(i); +// i--; +// } +// g=current->groups->next(); +// i++; +// } +// +// /* use new group name instead? */ +// if ( newgroup ) +// { +// current->groups->append(new Grouping(*newgroup, pri)); +// } +//} +// +//static int newMemberGroupId() +//{ +// static int curGroupId=0; +// return curGroupId++; +//} +// +// forward declarations +//static void startGroupInDoc(); +//static void endGroup(); + +//----------------------------------------------------------------------------- + +static void lineCount() +{ + for( const char* c = yytext ; *c ; ++c ) + yyLineNr += (*c == '\n') ; +} + +static void addType( Entry* current ) +{ + uint tl=current->type.length(); + if( tl>0 && !current->name.isEmpty() && current->type.at(tl-1)!='.') + { + current->type += ' ' ; + } + current->type += current->name ; + current->name.resize(0) ; + tl=current->type.length(); + if( tl>0 && !current->args.isEmpty() && current->type.at(tl-1)!='.') + { + current->type += ' ' ; + } + current->type += current->args ; + current->args.resize(0) ; + current->argList->clear(); +} + + +static QCString stripQuotes(const char *s) +{ + QCString name; + if (s==0 || *s==0) return name; + name=s; + if (name.at(0)=='"' && name.at(name.length()-1)=='"') + { + name=name.mid(1,name.length()-2); + } + return name; +} + +//----------------------------------------------------------------- + +static void startCommentBlock(bool); +static void handleCommentBlock(const QCString &doc,bool brief); +static void handleParametersCommentBlocks(ArgumentList *al); + +//----------------------------------------------------------------- + +static bool nameIsOperator(QCString &name) +{ + int i=name.find("operator"); + if (i==-1) return FALSE; + if (i==0 && !isId(name.at(8))) return TRUE; // case operator ::X + if (i>0 && !isId(name.at(i-1)) && !isId(name.at(i+8))) return TRUE; // case X::operator + return FALSE; // case TEXToperatorTEXT +} + +//----------------------------------------------------------------------------- + +static void setContext() +{ + QCString fileName = yyFileName; + language = getLanguageFromFileName(fileName); + insideIDL = language==SrcLangExt_IDL; + insideJava = language==SrcLangExt_Java; + insideCS = language==SrcLangExt_CSharp; + insideD = language==SrcLangExt_D; + insidePHP = language==SrcLangExt_PHP; + insideObjC = language==SrcLangExt_ObjC; + insideJS = language==SrcLangExt_JS; + if ( insidePHP ) + { + useOverrideCommands = TRUE; + } + //printf("setContext(%s) insideIDL=%d insideJava=%d insideCS=%d " + // "insideD=%d insidePHP=%d insideObjC=%d\n", + // yyFileName.data(),insideIDL,insideJava,insideCS,insideD,insidePHP,insideObjC + // ); +} + +//----------------------------------------------------------------------------- + +static void prependScope() +{ + if (current_root->section & Entry::SCOPE_MASK) + { + //printf("--- prependScope %s to %s\n",current_root->name.data(),current->name.data()); + current->name.prepend(current_root->name+"::"); + if (current_root->tArgLists) + { + if (current->tArgLists==0) + { + current->tArgLists = new QList; + current->tArgLists->setAutoDelete(TRUE); + } + //printf("prependScope #=%d #current=%d\n",current_root->tArgLists->count(),current->tArgLists->count()); + QListIterator talsi(*current_root->tArgLists); + ArgumentList *srcAl=0; + for (talsi.toLast();(srcAl=talsi.current());--talsi) + { + ArgumentList *dstAl = new ArgumentList; + QListIterator tali(*srcAl); + Argument *a; + for (;(a=tali.current());++tali) + { + dstAl->append(new Argument(*a)); + //printf("appending argument %s %s\n",a->type.data(),a->name.data()); + } + current->tArgLists->insert(0,dstAl); + } + } + } +} + +//----------------------------------------------------------------------------- + +/*! Returns TRUE iff the current entry could be a K&R style C function */ +static bool checkForKnRstyleC() +{ + if (((QCString)yyFileName).right(2).lower()!=".c") return FALSE; // must be a C file + if (!current->argList) return FALSE; // must have arguments + ArgumentListIterator ali(*current->argList); + Argument *a; + for (ali.toFirst();(a=ali.current());++ali) + { + // in K&R style argument do not have a type, but doxygen expects a type + // so it will think the argument has no name + if (a->type.isEmpty() || !a->name.isEmpty()) return FALSE; + } + return TRUE; +} + +//----------------------------------------------------------------------------- + +static void splitKnRArg(QCString &oldStyleArgPtr,QCString &oldStyleArgName) +{ + int si = current->args.length(); + if (oldStyleArgType.isEmpty()) // new argument + { + static QRegExp re("([^)]*)"); + int bi1 = current->args.findRev(re); + int bi2 = bi1!=-1 ? current->args.findRev(re,bi1-1) : -1; + char c; + if (bi1!=-1 && bi2!=-1) // found something like "int (*func)(int arg)" + { + int s=bi2+1; + oldStyleArgType = current->args.left(s); + int i=s; + while (iargs.at(i))=='*' || isspace((uchar)c))) i++; + oldStyleArgType += current->args.mid(s,i-s); + s=i; + while (iargs.at(i))) i++; + oldStyleArgName = current->args.mid(s,i-s); + oldStyleArgType+=current->args.mid(i); + } + else if (bi1!=-1) // redundant braces like in "int (*var)" + { + int s=bi1; + oldStyleArgType = current->args.left(s); + s++; + int i=s+1; + while (iargs.at(i))=='*' || isspace((uchar)c))) i++; + oldStyleArgType += current->args.mid(s,i-s); + s=i; + while (iargs.at(i))) i++; + oldStyleArgName = current->args.mid(s,i-s); + } + else // normal "int *var" + { + int l=si,i=l-1,j; + char c; + // look for start of name in "type *name" + while (i>=0 && isId(current->args.at(i))) i--; + j=i+1; + // look for start of *'s + while (i>=0 && ((c=current->args.at(i))=='*' || isspace((uchar)c))) i--; + i++; + if (i!=l) + { + oldStyleArgType=current->args.left(i); + oldStyleArgPtr=current->args.mid(i,j-i); + oldStyleArgName=current->args.mid(j).stripWhiteSpace(); + } + else + { + oldStyleArgName=current->args.copy().stripWhiteSpace(); + } + } + } + else // continuation like *arg2 in "int *args,*arg2" + { + int l=si,j=0; + char c; + while (jargs.at(j))=='*' || isspace((uchar)c))) j++; + if (j>0) + { + oldStyleArgPtr=current->args.left(j); + oldStyleArgName=current->args.mid(j).stripWhiteSpace(); + } + else + { + oldStyleArgName=current->args.copy().stripWhiteSpace(); + } + } + //fprintf(stderr,"type=%s ptr=%s name=%s\n",oldStyleArgType.data(),oldStyleArgPtr.data(),oldStyleArgName.data()); +} + +//----------------------------------------------------------------------------- + +/*! Update the argument \a name with additional \a type info. For K&R style + * function the type is found \e after the argument list, so this routine + * in needed to fix up. + */ +static void addKnRArgInfo(const QCString &type,const QCString &name, + const QCString &brief,const QCString &docs) +{ + if (current->argList==0) return; + ArgumentListIterator ali(*current->argList); + Argument *a; + for (ali.toFirst();(a=ali.current());++ali) + { + if (a->type==name) + { + a->type=type.stripWhiteSpace(); + if (a->type.left(9)=="register ") // strip keyword + { + a->type=a->type.mid(9); + } + a->name=name.stripWhiteSpace(); + if (!brief.isEmpty() && !docs.isEmpty()) + { + a->docs=brief+"\n\n"+docs; + } + else if (!brief.isEmpty()) + { + a->docs=brief; + } + else + { + a->docs=docs; + } + } + } +} + +//----------------------------------------------------------------------------- + + +void fixArgumentListForJavaScript(ArgumentList *al) +{ + if (al==0) return; + ArgumentListIterator ali(*al); + Argument *a; + for (ali.toFirst();(a=ali.current());++ali) + { + if (!a->type.isEmpty() && a->name.isEmpty()) + { // a->type is actually the (typeless) parameter name, so move it + a->name=a->type; + a->type.resize(0); + } + } +} + +/* ----------------------------------------------------------------- */ +#undef YY_INPUT +#define YY_INPUT(buf,result,max_size) result=yyread(buf,max_size); + +static int yyread(char *buf,int max_size) +{ + int c=0; + if (g_inputFromFile) + { + c = inputFile.readBlock(buf,max_size); + if (c==-1) yy_fatal_error("input in flex scanner failed"); + } + else + { + while( c < max_size && inputString[inputPosition] ) + { + *buf = inputString[inputPosition++] ; + //printf("%d (%c)\n",*buf,*buf); + c++; buf++; + } + } + return c; +} + +%} + + /* start command character */ +CMD ("\\"|"@") +SECTIONCMD {CMD}("image"|"author"|"internal"|"version"|"date"|"deprecated"|"param"|"exception"|"return"[s]?|"retval"|"bug"|"warning"|"par"|"sa"|"see"|"pre"|"post"|"invariant"|"note"|"remark"[s]?|"todo"|"test"|"xrefitem"|"ingroup"|"callgraph"|"callergraph"|"latexonly"|"htmlonly"|"xmlonly"|"manonly"|"{"|"verbatim"|"dotfile"|"dot"|"defgroup"|"addtogroup"|"weakgroup"|"class"|"namespace"|"union"|"struct"|"fn"|"var"|"details"|"typedef"|"def"|"overload")|("<"{PRE}">") +BN [ \t\n\r] +BL [ \t\r]*"\n" +B [ \t] +BS ^(({B}*"//")?)(({B}*"*"+)?){B}* +FILESCHAR [a-z_A-Z0-9\x80-\xFF\\:\\\/\-\+] +FILEECHAR [a-z_A-Z0-9\x80-\xFF\-\+] +FILE ({FILESCHAR}*{FILEECHAR}+("."{FILESCHAR}*{FILEECHAR}+)*)|("\""[^\n\"]+"\"") +ID "$"?[a-z_A-Z\x80-\xFF][a-z_A-Z0-9\x80-\xFF]* +SCOPEID {ID}({ID}*{BN}*"::"{BN}*)*({ID}?) +SCOPENAME "$"?(({ID}?{BN}*"::"{BN}*)*)(((~|!){BN}*)?{ID}) +PHPSCOPENAME ({ID}"\\")+{ID} +TSCOPE {ID}("<"[a-z_A-Z0-9 \t\*\&,:]*">")? +CSSCOPENAME (({ID}?{BN}*"."{BN}*)*)((~{BN}*)?{ID}) +PRE [pP][rR][eE] +CODE [cC][oO][dD][eE] +CHARLIT (("'"\\[0-7]{1,3}"'")|("'"\\."'")|("'"[^'\\\n]{1,4}"'")) +PHPKW ("require"|"require_once"|"include"|"include_once"|"echo")[^a-zA-Z0-9_;] +IDLATTR ("["[^\]]*"]"){BN}* +TYPEDEFPREFIX (("typedef"{BN}+)?)((("volatile"|"const"){BN}+)?) + +%option noyywrap + + /* language parsing states */ + +%x Define +%x DefineEnd +%x CompoundName +%x ClassVar +%x CSConstraintName +%x CSConstraintType +%x CSIndexer +%x ClassCategory +%x ClassTemplSpec +%x CliPropertyType +%x CliPropertyIndex +%x CliOverride +%x Bases +%x BasesProt +%x NextSemi +%x BitFields +%x FindMembers +%x FindMembersPHP +%x FindMemberName +%x FindFields +%x FindFieldArg +%x Function +%x FuncRound +%x ExcpRound +%x ExcpList +%x FuncQual +%x Operator +%x Array +%x ReadBody +%x ReadNSBody +%x ReadBodyIntf +%x Using +%x UsingDirective +%x SkipCurly +%x SkipCurlyCpp +%x SkipCurlyEndDoc +%x SkipString +%x SkipPHPString +%x SkipInits +%x SkipCPP +%x SkipCPPBlock +%x SkipComment +%x SkipCxxComment +%x SkipCurlyBlock +%x SkipRoundBlock +%x Sharp +%x SkipSharp +%x SkipRound +%x SkipSquare +%x SkipRemainder +%x TypedefName +%x TryFunctionBlock +%x TryFunctionBlockEnd +%x Comment +%x PackageName +%x JavaImport +%x PHPUse +%x PHPUseAs +%x CSAccessorDecl +%x CSGeneric +%x PreLineCtrl +%x DefinePHP +%x DefinePHPEnd +%x OldStyleArgs +%x SkipVerbString +%x ObjCMethod +%x ObjCReturnType +%x ObjCParams +%x ObjCParamType +%x ObjCProtocolList +%x ObjCPropAttr +%x ObjCSkipStatement +%x QtPropType +%x QtPropName +%x QtPropAttr +%x QtPropRead +%x QtPropWrite +%x ReadInitializer +%x GetCallType +%x CppQuote +%x EndCppQuote +%x MemberSpec +%x MemberSpecSkip +%x EndTemplate +%x FuncPtr +%x FuncPtrOperator +%x EndFuncPtr +%x ReadFuncArgType +%x ReadTempArgs +%x IDLUnionCase +%x NSAliasName +%x NSAliasArg +%x CopyString +%x CopyPHPString +%x CopyGString +%x CopyPHPGString +%x CopyRound +%x CopyCurly +%x GCopyRound +%x GCopyCurly +%x SkipUnionSwitch +%x Specialization +%x FuncPtrInit +%x FuncFunc +%x FuncFuncEnd +%x FuncFuncType +%x FuncFuncArray +%x CopyArgString +%x CopyArgPHPString +%x CopyArgRound +%x CopyArgSharp +%x CopyArgComment +%x CopyArgCommentLine +%x CopyArgVerbatim +%x HereDoc +%x HereDocEnd +%x CopyHereDoc +%x CopyHereDocEnd + +%x IDLAttribute +%x IDLProp +%x IDLPropName + + /** Prototype scanner states */ + +%x Prototype +%x PrototypePtr +%x PrototypeQual +%x PrototypeExc +%x PrototypeSkipLine + + /** comment parsing states */ + +%x DocLine +%x DocBlock +%x DocCopyBlock + +%% + +"{" { + curlyCount=0; + needsSemi = TRUE; + BEGIN(SkipCurlyBlock); + } +"(" { + roundCount=0; + BEGIN(SkipRoundBlock); + } +"(" { + ++roundCount; + } +")" { + if (roundCount ) + --roundCount ; + else + BEGIN( NextSemi ) ; + } +"{" { + ++curlyCount ; + } +"}" { + if( curlyCount ) + { + --curlyCount ; + } + else if (needsSemi) + { + BEGIN( NextSemi ); + } + else + { + BEGIN( FindMembers ); + } + } +\' { + if (insidePHP) + { + lastStringContext=NextSemi; + BEGIN(SkipPHPString); + } + } +{CHARLIT} { if (insidePHP) REJECT; } +\" { + lastStringContext=NextSemi; + BEGIN(SkipString); + } +[;,] { + unput(*yytext); + BEGIN( FindMembers ); + } +[;,] { + unput(*yytext); + BEGIN( FindMembers ); + } +"""" { // PHP code start + lineCount() ; + BEGIN( FindMembers ); + } +[^\n<]+ { // Non-PHP code text, ignore + } +\n { // Non-PHP code text, ignore + yyLineNr++; + } +. { // Non-PHP code text, ignore + } +"?>"|"" { // PHP code end + if (insidePHP) + BEGIN( FindMembersPHP ); + else + REJECT; + } +{PHPKW} { if (insidePHP) + BEGIN( NextSemi ); + else + REJECT; + } +"%{"[^\n]* { // Mozilla XPIDL lang-specific block + if (!insideIDL) + REJECT; + } +"%}" { // Mozilla XPIDL lang-specific block end + if (!insideIDL) + REJECT; + } +{B}*("properties"){BN}*":"{BN}* { // IDL or Borland C++ builder property + current->mtype = mtype = Property; + current->protection = protection = Public ; + current->type.resize(0); + current->name.resize(0); + current->args.resize(0); + current->argList->clear(); + lineCount() ; + } + +{B}*"k_dcop"{BN}*":"{BN}* { current->mtype = mtype = DCOP; + current->protection = protection = Public ; + current->type.resize(0); + current->name.resize(0); + current->args.resize(0); + current->argList->clear(); + lineCount() ; + } + +{B}*("signals"|"Q_SIGNALS"){BN}*":"{BN}* { current->mtype = mtype = Signal; + + current->protection = protection = Public ; + current->type.resize(0); + current->name.resize(0); + current->args.resize(0); + current->argList->clear(); + lineCount() ; + } + +{B}*"public"{BN}*("slots"|"Q_SLOTS"){BN}*":"{BN}* { + current->protection = protection = Public ; + current->mtype = mtype = Slot; + current->type.resize(0); + current->name.resize(0); + current->args.resize(0); + current->argList->clear(); + lineCount(); + } + +{B}*"protected"{BN}*("slots"|"Q_SLOTS"){BN}*":"{BN}* { + current->protection = protection = Protected ; + current->mtype = mtype = Slot; + current->type.resize(0); + current->name.resize(0); + current->args.resize(0); + current->argList->clear(); + lineCount(); + } + +{B}*"private"{BN}*("slots"|"Q_SLOTS"){BN}*":"{BN}* { + current->protection = protection = Private ; + current->mtype = mtype = Slot; + current->type.resize(0); + current->name.resize(0); + current->args.resize(0); + current->argList->clear(); + lineCount(); + } +{B}*("public"|"methods"|"__published"){BN}*":"{BN}* { + current->protection = protection = Public ; + current->mtype = mtype = Method; + current->type.resize(0); + current->name.resize(0); + current->args.resize(0); + current->argList->clear(); + lineCount() ; + } +{B}*"internal"{BN}*":"{BN}* { // for now treat C++/CLI's internal as package... + if (insideCli) + { + current->protection = protection = Package ; + current->mtype = mtype = Method; + current->type.resize(0); + current->name.resize(0); + current->args.resize(0); + current->argList->clear(); + lineCount() ; + } + else + { + REJECT; + } + } +{B}*"protected"{BN}*":"{BN}* { + current->protection = protection = Protected ; + current->mtype = mtype = Method; + current->type.resize(0); + current->name.resize(0); + current->args.resize(0); + current->argList->clear(); + lineCount() ; + } +{B}*"private"{BN}*":"{BN}* { + current->protection = protection = Private ; + current->mtype = mtype = Method; + current->type.resize(0); + current->name.resize(0); + current->args.resize(0); + current->argList->clear(); + lineCount() ; + } +{B}*"event"{BN}+ { + if (insideCli) + { + // C++/CLI event + lineCount() ; + current->mtype = mtype = Event; + current->bodyLine = yyLineNr; + curlyCount=0; + BEGIN( CliPropertyType ); + } + else if (insideCS) + { + lineCount() ; + current->mtype = Event; + current->bodyLine = yyLineNr; + } + else + { + REJECT; + } + } +{B}*"property"{BN}+ { + if (insideCli) + { + // C++/CLI property + lineCount() ; + current->mtype = mtype = Property; + current->bodyLine = yyLineNr; + curlyCount=0; + BEGIN( CliPropertyType ); + } + else + { + REJECT; + } + } +{ID} { + addType( current ); + current->name = yytext; + } +"[" { // C++/CLI indexed property + current->name += yytext; + BEGIN( CliPropertyIndex ); + } +"{" { + curlyCount=0; + //printf("event: '%s' '%s'\n",current->type.data(),current->name.data()); + BEGIN( CSAccessorDecl ); + } +";" { + unput(*yytext); + BEGIN( FindMembers ); + } +\n { + yyLineNr++; + } +{B}* { + } +. { + addType( current ); + current->type += yytext; + } +"]" { + BEGIN( CliPropertyType ); + current->name+=yytext; + } +. { + current->name+=yytext; + } + /* +{B}*"property"{BN}+ { + if (!current->type.isEmpty()) + { + REJECT; + } + else + { + current->mtype = mtype = Property; + lineCount(); + } + } + */ +{B}*"@private"{BN}+ { + current->protection = protection = Private ; + current->mtype = mtype = Method; + current->type.resize(0); + current->name.resize(0); + current->args.resize(0); + current->argList->clear(); + lineCount() ; + } +{B}*"@protected"{BN}+ { + current->protection = protection = Protected ; + current->mtype = mtype = Method; + current->type.resize(0); + current->name.resize(0); + current->args.resize(0); + current->argList->clear(); + lineCount() ; + } +{B}*"@public"{BN}+ { + current->protection = protection = Public ; + current->mtype = mtype = Method; + current->type.resize(0); + current->name.resize(0); + current->args.resize(0); + current->argList->clear(); + lineCount() ; + } +[\-+]{BN}* { + if (!insideObjC) + { + REJECT; + } + else + { + lineCount(); + current->fileName = yyFileName; + current->startLine = yyLineNr; + current->bodyLine = yyLineNr; + current->section = Entry::FUNCTION_SEC; + current->protection = protection = Public ; + language = current->lang = SrcLangExt_ObjC; + insideObjC = TRUE; + current->virt = Virtual; + current->stat=yytext[0]=='+'; + current->mtype = mtype = Method; + current->type.resize(0); + current->name.resize(0); + current->args.resize(0); + current->argList->clear(); + BEGIN( ObjCMethod ); + } + } +"(" { // start of method's return type + BEGIN( ObjCReturnType ); + } +{ID} { // found method name + if (current->type.isEmpty()) + { + current->type = "id"; + } + current->name = yytext; + } +":"{B}* { // start of parameter list + current->name += ':'; + Argument *a = new Argument; + current->argList->append(a); + BEGIN( ObjCParams ); + } +[^)]* { // TODO: check if nested braches are possible. + current->type = yytext; + } +")" { + BEGIN( ObjCMethod ); + } +({ID})?":" { // Keyword of parameter + QCString keyw = yytext; + keyw=keyw.left(keyw.length()-1); // strip : + if (keyw.isEmpty()) + { + current->name += " :"; + } + else + { + current->name += keyw+":"; + } + if (current->argList->getLast()->type.isEmpty()) + { + current->argList->getLast()->type="id"; + } + Argument *a = new Argument; + a->attrib=(QCString)"["+keyw+"]"; + current->argList->append(a); + } +{ID}{BN}* { // name of parameter + lineCount(); + current->argList->getLast()->name=QCString(yytext).stripWhiteSpace(); + } +","{BN}*"..." { // name of parameter + lineCount(); + // do we want the comma as part of the name? + //current->name += ","; + Argument *a = new Argument; + a->attrib="[,]"; + a->type="..."; + current->argList->append(a); + } + /* +":" { + current->name += ':'; + } + */ +"(" { + BEGIN( ObjCParamType ); + } +[^)]* { + current->argList->getLast()->type=QCString(yytext).stripWhiteSpace(); + } +")"/{B}* { + BEGIN( ObjCParams ); + } +";" { // end of method declaration + if (current->argList->getLast() && current->argList->getLast()->type.isEmpty()) + { + current->argList->getLast()->type="id"; + } + current->args = argListToString(current->argList); + //printf("argList=%s\n",current->args.data()); + unput(';'); + BEGIN( Function ); + } +(";"{BN}+)?"{" { // start of a method body + lineCount(); + //printf("Type=%s Name=%s args=%s\n", + // current->type.data(),current->name.data(),argListToString(current->argList).data() + // ); + if (current->argList->getLast() && current->argList->getLast()->type.isEmpty()) + { + current->argList->getLast()->type="id"; + } + current->args = argListToString(current->argList); + unput('{'); + BEGIN( Function ); + } +{BN}{1,80} { + lineCount(); + } +"@"({ID}".")*{ID}{BN}*"(" { + if (insideJava) // Java annotation + { + lineCount(); + lastSkipRoundContext = YY_START; + roundCount=1; + BEGIN( SkipRound ); + } + else if (strncmp(yytext,"@property",9)==0) // ObjC 2.0 property + { + current->mtype = mtype = Property; + current->spec|=Entry::Readable | Entry::Writable | Entry::Assign; + current->protection = Public ; + unput('('); + BEGIN( ObjCPropAttr ); + } + else + { + REJECT; + } + } +"getter="{ID} { + current->read = yytext+7; + } +"setter="{ID} { + current->write = yytext+7; + } +"readonly" { + current->spec&=~Entry::Writable; + } +"readwrite" { // default + } +"assign" { // default + } +"retain" { + current->spec&=~Entry::Assign; + current->spec|=Entry::Retain; + } +"copy" { + current->spec&=~Entry::Assign; + current->spec|=Entry::Copy; + } +"nonatmic" { + current->spec|=Entry::NonAtomic; + } +")" { + BEGIN(FindMembers); + } +"@"{ID} { + if (insideJava) // Java annotation + { + // skip annotation + } + else if (strcmp(yytext,"@property")==0) // ObjC 2.0 property + { + current->mtype = mtype = Property; + current->spec|=Entry::Writable | Entry::Readable | Entry::Assign; + current->protection = Public ; + } + else if (strcmp(yytext,"@synthesize")==0) + { + BEGIN( ObjCSkipStatement ); + } + else if (strcmp(yytext,"@dynamic")==0) + { + BEGIN( ObjCSkipStatement ); + } + else + { + REJECT; + } + } +";" { + BEGIN(FindMembers); + } +{ID}(("."|"\\"){ID})* { + isTypedef=FALSE; + //printf("Found namespace %s lang=%d\n",yytext,current->lang); + current->name = yytext; + current->name = substitute(current->name,".","::"); + current->name = substitute(current->name,"\\","::"); + current->section = Entry::NAMESPACE_SEC; + current->type = "namespace" ; + current->fileName = yyFileName; + current->startLine = yyLineNr; + current->bodyLine = yyLineNr; + lineCount(); + } +";" { + current_root->addSubEntry(current); + current_root = current ; + current = new Entry ; + initEntry(); + BEGIN(FindMembers); + } +"{" { + curlyCount=0; + BEGIN( ReadNSBody ); + } +{B}*"initonly"{BN}+ { + current->type += " initonly "; + if (insideCli) current->spec |= Entry::Initonly; + lineCount(); + } +{B}*"static"{BN}+ { current->type += " static "; + current->stat = TRUE; + lineCount(); + } +{B}*"extern"{BN}+ { + current->stat = FALSE; + current->explicitExternal = TRUE; + lineCount(); + } +{B}*"virtual"{BN}+ { current->type += " virtual "; + current->virt = Virtual; + lineCount(); + } +{B}*"abstract"{BN}+ { + if (!insidePHP) + { + current->type += " abstract "; + current->virt = Pure; + } + else + { + current->spec|=Entry::Abstract; + } + lineCount(); + } +{B}*"inline"{BN}+ { current->spec|=Entry::Inline; + lineCount(); + } +{B}*"mutable"{BN}+ { current->spec|=Entry::Mutable; + lineCount(); + } +{B}*"explicit"{BN}+ { current->spec|=Entry::Explicit; + lineCount(); + } +{B}*"@required"{BN}+ { // Objective C 2.0 protocol required section + current->spec=(current->spec & ~Entry::Optional) | Entry::Required; + lineCount(); + } +{B}*"@optional"{BN}+ { // Objective C 2.0 protocol optional section + current->spec=(current->spec & ~Entry::Required) | Entry::Optional; + lineCount(); + } + /* +{B}*"import"{BN}+ { // IDL import keyword + BEGIN( NextSemi ); + } + */ +{B}*"typename"{BN}+ { lineCount(); } +{B}*"namespace"{BN}*/[^a-z_A-Z0-9] { + isTypedef=FALSE; + current->section = Entry::NAMESPACE_SEC; + current->type = "namespace" ; + current->fileName = yyFileName; + current->startLine = yyLineNr; + current->bodyLine = yyLineNr; + lineCount(); + if (insidePHP) + { + BEGIN( PackageName ); + } + else + { + BEGIN( CompoundName ); + } + } +{B}*"module"{BN}+ { + lineCount(); + if (insideIDL) + { + isTypedef=FALSE; + current->section = Entry::NAMESPACE_SEC; + current->type = "module" ; + current->fileName = yyFileName; + current->startLine = yyLineNr; + current->bodyLine = yyLineNr; + BEGIN( CompoundName ); + } + else if (insideD) + { + lineCount(); + BEGIN(PackageName); + } + else + { + addType( current ) ; + current->name = QCString(yytext).stripWhiteSpace(); + } + } +{B}*"library"{BN}+ { + lineCount(); + if (insideIDL) + { + isTypedef=FALSE; + current->section = Entry::NAMESPACE_SEC; + current->type = "library" ; + current->fileName = yyFileName; + current->startLine = yyLineNr; + current->bodyLine = yyLineNr; + BEGIN( CompoundName ); + } + else + { + addType( current ) ; + current->name = QCString(yytext).stripWhiteSpace(); + } + } +{B}*((("disp")?"interface")|"valuetype"){BN}+ { // M$/Corba IDL/Java interface + lineCount(); + if (insideIDL || insideJava || insideCS || insideD || insidePHP) + { + isTypedef=FALSE; + current->section = Entry::CLASS_SEC; + current->spec = Entry::Interface; + addType( current ) ; + current->type += " interface" ; + current->fileName = yyFileName; + current->startLine = yyLineNr; + current->bodyLine = yyLineNr; + BEGIN( CompoundName ); + } + else + { + addType( current ) ; + current->name = QCString(yytext).stripWhiteSpace(); + } + } +{B}*"@implementation"{BN}+ { // Objective-C class implementation + lineCount(); + isTypedef=FALSE; + current->section = Entry::OBJCIMPL_SEC; + language = current->lang = SrcLangExt_ObjC; + insideObjC = TRUE; + current->protection = protection = Public ; + addType( current ) ; + current->type += " implementation" ; + current->fileName = yyFileName; + current->startLine = yyLineNr; + current->bodyLine = yyLineNr; + BEGIN( CompoundName ); + } +{B}*"@interface"{BN}+ { // Objective-C class interface, or Java attribute + lineCount(); + isTypedef=FALSE; + current->section = Entry::CLASS_SEC; + current->spec = Entry::Interface; + if (!insideJava) + { + language = current->lang = SrcLangExt_ObjC; + insideObjC = TRUE; + } + current->protection = protection = Public ; + addType( current ) ; + current->type += " interface" ; + current->fileName = yyFileName; + current->startLine = yyLineNr; + current->bodyLine = yyLineNr; + BEGIN( CompoundName ); + } +{B}*"@protocol"{BN}+ { // Objective-C protocol definition + lineCount(); + isTypedef=FALSE; + current->section = Entry::CLASS_SEC; + current->spec = Entry::Protocol; + language = current->lang = SrcLangExt_ObjC; + insideObjC = TRUE; + current->protection = protection = Public ; + addType( current ) ; + current->type += " protocol" ; + current->fileName = yyFileName; + current->startLine = yyLineNr; + current->bodyLine = yyLineNr; + BEGIN( CompoundName ); + } +{B}*"exception"{BN}+ { // Corba IDL exception + isTypedef=FALSE; + current->section = Entry::CLASS_SEC; + current->spec = Entry::Exception; + addType( current ) ; + current->type += " exception" ; + current->fileName = yyFileName; + current->startLine = yyLineNr; + current->bodyLine = yyLineNr; + lineCount(); + BEGIN( CompoundName ); + } +"@class" | // for Objective C class declarations +{B}*{TYPEDEFPREFIX}"class{" | +{B}*{TYPEDEFPREFIX}"class"{BN}+ { + isTypedef=((QCString)yytext).find("typedef")!=-1; + current->section = Entry::CLASS_SEC; + addType( current ) ; + current->type += " class" ; + current->fileName = yyFileName; + current->startLine = yyLineNr; + current->bodyLine = yyLineNr; + if (yytext[0]=='@') + { + language = current->lang = SrcLangExt_ObjC; + insideObjC = TRUE; + } + lineCount() ; + if (yytext[yyleng-1]=='{') unput('{'); + if (insidePHP && current->spec&Entry::Abstract) + { + // convert Abstract to AbstractClass + current->spec=(current->spec&~Entry::Abstract)|Entry::AbstractClass; + } + BEGIN( CompoundName ) ; + } +{B}*"value class{" | // C++/CLI extension +{B}*"value class"{BN}+ { + isTypedef=FALSE; + current->section = Entry::CLASS_SEC; + current->spec = Entry::Value; + addType( current ) ; + current->type += " value class" ; + current->fileName = yyFileName; + current->startLine = yyLineNr; + current->bodyLine = yyLineNr; + lineCount() ; + if (yytext[yyleng-1]=='{') unput('{'); + BEGIN( CompoundName ) ; + } +{B}*"ref class{" | // C++/CLI extension +{B}*"ref class"{BN}+ { + isTypedef=FALSE; + current->section = Entry::CLASS_SEC; + current->spec = Entry::Ref; + addType( current ) ; + current->type += " ref class" ; + current->fileName = yyFileName; + current->startLine = yyLineNr; + current->bodyLine = yyLineNr; + lineCount() ; + if (yytext[yyleng-1]=='{') unput('{'); + BEGIN( CompoundName ) ; + } +{B}*"interface class{" | // C++/CLI extension +{B}*"interface class"{BN}+ { + isTypedef=FALSE; + current->section = Entry::CLASS_SEC; + current->spec = Entry::Interface; + addType( current ) ; + current->type += " interface class" ; + current->fileName = yyFileName; + current->startLine = yyLineNr; + current->bodyLine = yyLineNr; + lineCount() ; + if (yytext[yyleng-1]=='{') unput('{'); + BEGIN( CompoundName ) ; + } +{B}*"coclass"{BN}+ { + if (insideIDL) + { + isTypedef=FALSE; + current->section = Entry::CLASS_SEC; + addType( current ) ; + current->type += " coclass" ; + current->fileName = yyFileName; + current->startLine = yyLineNr; + current->bodyLine = yyLineNr; + lineCount() ; + BEGIN( CompoundName ) ; + } + else + { + addType(current); + current->name = yytext; + current->name = current->name.stripWhiteSpace(); + lineCount(); + } + } +{B}*{TYPEDEFPREFIX}"struct{" | +{B}*{TYPEDEFPREFIX}"struct"/{BN}+ { + isTypedef=((QCString)yytext).find("typedef")!=-1; + current->section = Entry::CLASS_SEC ; + current->spec = Entry::Struct; + // bug 582676: can be a struct nested in an interface so keep insideObjC state + //current->objc = insideObjC = FALSE; + addType( current ) ; + current->type += " struct" ; + current->fileName = yyFileName; + current->startLine = yyLineNr; + current->bodyLine = yyLineNr; + lineCount() ; + if (yytext[yyleng-1]=='{') unput('{'); + BEGIN( CompoundName ) ; + } +{B}*"value struct{" | // C++/CLI extension +{B}*"value struct"{BN}+ { + isTypedef=FALSE; + current->section = Entry::CLASS_SEC; + current->spec = Entry::Struct | Entry::Value; + addType( current ) ; + current->type += " value struct" ; + current->fileName = yyFileName; + current->startLine = yyLineNr; + current->bodyLine = yyLineNr; + lineCount() ; + if (yytext[yyleng-1]=='{') unput('{'); + BEGIN( CompoundName ) ; + } +{B}*"ref struct{" | // C++/CLI extension +{B}*"ref struct"{BN}+ { + isTypedef=FALSE; + current->section = Entry::CLASS_SEC; + current->spec = Entry::Struct | Entry::Ref; + addType( current ) ; + current->type += " ref struct" ; + current->fileName = yyFileName; + current->startLine = yyLineNr; + current->bodyLine = yyLineNr; + lineCount() ; + if (yytext[yyleng-1]=='{') unput('{'); + BEGIN( CompoundName ) ; + } +{B}*"interface struct{" | // C++/CLI extension +{B}*"interface struct"{BN}+ { + isTypedef=FALSE; + current->section = Entry::CLASS_SEC; + current->spec = Entry::Struct | Entry::Interface; + addType( current ) ; + current->type += " interface struct"; + current->fileName = yyFileName; + current->startLine = yyLineNr; + current->bodyLine = yyLineNr; + lineCount() ; + if (yytext[yyleng-1]=='{') unput('{'); + BEGIN( CompoundName ) ; + } +{B}*{TYPEDEFPREFIX}"union{" | +{B}*{TYPEDEFPREFIX}"union"{BN}+ { + isTypedef=((QCString)yytext).find("typedef")!=-1; + current->section = Entry::CLASS_SEC; + current->spec = Entry::Union; + // bug 582676: can be a struct nested in an interface so keep insideObjC state + //current->objc = insideObjC = FALSE; + addType( current ) ; + current->type += " union" ; + current->fileName = yyFileName; + current->startLine = yyLineNr; + current->bodyLine = yyLineNr; + lineCount() ; + if (yytext[yyleng-1]=='{') unput('{'); + BEGIN( CompoundName ) ; + } +{B}*{TYPEDEFPREFIX}{IDLATTR}?"enum"({BN}+("class"|"struct"))?"{" | +{B}*{TYPEDEFPREFIX}{IDLATTR}?"enum"({BN}+("class"|"struct"))?{BN}+ { // for IDL: typedef [something] enum + isTypedef=((QCString)yytext).find("typedef")!=-1; + if (insideJava) + { + current->section = Entry::CLASS_SEC; + current->spec = Entry::Enum; + } + else + { + current->section = Entry::ENUM_SEC ; + } + addType( current ) ; + current->type += " enum" ; + current->fileName = yyFileName; + current->startLine = yyLineNr; + current->bodyLine = yyLineNr; + lineCount() ; + if (yytext[yyleng-1]=='{') unput('{'); + BEGIN( CompoundName ) ; + } +"("{BN}*")"({BN}*"<"[^>]*">"){BN}*/"(" { // A::operator()(int arg) + lineCount(); + current->name += "()"; + BEGIN( FindMembers ); + } +"("{BN}*")"{BN}*/"(" { + lineCount(); + current->name += yytext ; + current->name = current->name.simplifyWhiteSpace(); + BEGIN( FindMembers ) ; + } +";" { // can occur when importing members + unput(';'); + BEGIN( FindMembers ) ; + } +[^(] { + lineCount(); + current->name += *yytext ; + } +"<>" { /* skip guided templ specifiers */ } +"(" { + current->name = current->name.simplifyWhiteSpace(); + unput(*yytext); + BEGIN( FindMembers ) ; + } +("template"|"generic")({BN}*)"<"/[>]? { // generic is a C++/CLI extension + lineCount(); + if (current->tArgLists==0) + { + current->tArgLists = new QList; + current->tArgLists->setAutoDelete(TRUE); + } + ArgumentList *al = new ArgumentList; + //current->spec |= (yytext[0]=='g') ? Entry::Generic : Entry::Template; + current->tArgLists->append(al); + currentArgumentList = al; + templateStr="<"; + fullArgString = templateStr; + copyArgString = &templateStr; + currentArgumentContext = FindMembers; + BEGIN( ReadTempArgs ); + } +"namespace"{BN}+/{ID}{BN}*"=" { // namespace alias + lineCount(); + BEGIN( NSAliasName ); + } +{ID} { + aliasName = yytext; + BEGIN( NSAliasArg ); + } +({ID}"::")*{ID} { + //printf("Inserting namespace alias %s::%s->%s\n",current_root->name.data(),aliasName.data(),yytext); + //if (current_root->name.isEmpty()) + //{ + // TODO: namespace aliases are now treated as global entities + // while they should be aware of the scope they are in + Doxygen::namespaceAliasDict.insert(aliasName,new QCString(yytext)); + //} + //else + //{ + // Doxygen::namespaceAliasDict.insert(current_root->name+"::"+aliasName, + // new QCString(current_root->name+"::"+yytext)); + //} + } +";" { + BEGIN( FindMembers ); + } +({ID}{BN}*"\\"{BN}*)*{ID}/{BN}+"as" { + lineCount(); + aliasName=yytext; + BEGIN(PHPUseAs); + } +({ID}{BN}*"\\"{BN}*)*{ID} { + lineCount(); + current->name=removeRedundantWhiteSpace(substitute(yytext,"\\","::")); + //printf("PHP: adding use relation: %s\n",current->name.data()); + current->fileName = yyFileName; + current->section=Entry::USINGDIR_SEC; + current_root->addSubEntry(current); + current = new Entry; + initEntry(); + aliasName.resize(0); + } +{BN}+"as"{BN}+ { + lineCount(); + } +{ID} { + //printf("PHP: adding use as relation: %s->%s\n",yytext,aliasName.data()); + Doxygen::namespaceAliasDict.insert(yytext, + new QCString(removeRedundantWhiteSpace( + substitute(aliasName,"\\","::")))); + aliasName.resize(0); + } +[,;] { + /* + if (!aliasName.isEmpty()) + { + int i=aliasName.findRev('\\'); + if (i!=-1) + { + QCString an = removeRedundantWhiteSpace( + substitute(aliasName,"\\","::")); + printf("PHP: adding use relation: %s->%s\n",aliasName.mid(i+1).data(),an.data()); + Doxygen::namespaceAliasDict.insert(aliasName.mid(i+1), + new QCString(an)); + current->name = an; + current->fileName = yyFileName; + current->section=Entry::USINGDECL_SEC; + current_root->addSubEntry(current); + current = new Entry ; + initEntry(); + } + else if (i==0) + { + } + } + */ + if (*yytext==',') + { + BEGIN(PHPUse); + } + else + { + BEGIN(FindMembers); + } + } +({ID}{BN}*"."{BN}*)+"*" { // package import => add as a using directive + lineCount(); + QCString scope=yytext; + current->name=removeRedundantWhiteSpace(substitute(scope.left(scope.length()-1),".","::")); + current->fileName = yyFileName; + current->section=Entry::USINGDIR_SEC; + current_root->addSubEntry(current); + current = new Entry; + initEntry(); + BEGIN(Using); + } +({ID}{BN}*"."{BN}*)+{ID} { // class import => add as a using declaration + lineCount(); + QCString scope=yytext; + current->name=removeRedundantWhiteSpace(substitute(scope,".","::")); + current->fileName = yyFileName; + if (insideD) + { + current->section=Entry::USINGDIR_SEC; + } + else + { + //printf("import name = %s -> %s\n",yytext,current->name.data()); + current->section=Entry::USINGDECL_SEC; + } + current_root->addSubEntry(current); + current = new Entry ; + initEntry(); + BEGIN(Using); + } +"using"{BN}+ { + current->startLine=yyLineNr; + lineCount(); + BEGIN(Using); + } +"namespace"{BN}+ { lineCount(); BEGIN(UsingDirective); } +{ID}{BN}*({BN}*("::"|"."){BN}*{ID})* { + lineCount(); + current->name=yytext; + current->fileName = yyFileName; + current->section=Entry::USINGDECL_SEC; + current_root->addSubEntry(current); + current = new Entry ; + if (insideCS) /* Hack: in C# a using declaration and + directive have the same syntax, so we + also add it as a using directive here + */ + { + current->name=yytext; + current->fileName = yyFileName; + current->startLine = yyLineNr; + current->section=Entry::USINGDIR_SEC; + current_root->addSubEntry(current); + current = new Entry ; + } + initEntry(); + BEGIN(Using); + } +{SCOPENAME} { current->name=removeRedundantWhiteSpace(yytext); + current->fileName = yyFileName; + current->section=Entry::USINGDIR_SEC; + current_root->addSubEntry(current); + current = new Entry ; + initEntry(); + BEGIN(Using); + } +";" { BEGIN(FindMembers); } +{SCOPENAME}{BN}*"<>" { // guided template decl + QCString n=yytext; + addType( current ); + current->name=n.left(n.length()-2); + } +{SCOPENAME}{BN}*/"<" { // Note: this could be a return type! + roundCount=0; + sharpCount=0; + lineCount(); + addType( current ); + current->name=yytext; + current->name=current->name.stripWhiteSpace(); + //current->scopeSpec.resize(0); + // currentTemplateSpec = ¤t->scopeSpec; + if (nameIsOperator(current->name)) + BEGIN( Operator ); + else + BEGIN( EndTemplate ); + } +{SCOPENAME}{BN}*/"<" { + sharpCount=0; + roundCount=0; + lineCount(); + current->name+=((QCString)yytext).stripWhiteSpace(); + //current->memberSpec.resize(0); + // currentTemplateSpec = ¤t->memberSpec; + if (nameIsOperator(current->name)) + BEGIN( Operator ); + else + BEGIN( EndTemplate ); + } +"<<<" { + if (!insidePHP) + { + REJECT; + } + else + { + lastHereDocContext = YY_START; + BEGIN(HereDoc); + } + } +"<<" { + current->name+=yytext; + // *currentTemplateSpec+=yytext; + } +"<" { + current->name+='<'; + // *currentTemplateSpec+='<'; + sharpCount++; + } +">>" { + if (insideJava || insideCS || insideCli || roundCount==0) + { + unput('>'); + unput(' '); + unput('>'); + } + else + { + current->name+=yytext; + } + // *currentTemplateSpec+=yytext; + } +">" { + current->name+='>'; + // *currentTemplateSpec+='>'; + if (--sharpCount<=0) + { + //printf("Found %s\n",current->name.data()); + BEGIN(FindMembers); + } + } +">"{BN}*"(" { + lineCount(); + current->name+='>'; + // *currentTemplateSpec+='>'; + if (--sharpCount<=0) + { + current->bodyLine = yyLineNr; + current->args = "("; + currentArgumentContext = FuncQual; + fullArgString = current->args.copy(); + copyArgString = ¤t->args; + //printf("Found %s\n",current->name.data()); + BEGIN( ReadFuncArgType ) ; + } + } +">"{BN}*/"("({BN}*{ID}{BN}*"::")*({BN}*"*"{BN}*)+ { // function pointer returning a template instance + lineCount(); + current->name+='>'; + BEGIN(FindMembers); + } +">"{BN}*/"::" { + lineCount(); + current->name+='>'; + // *currentTemplateSpec+='>'; + if (--sharpCount<=0) + { + BEGIN(FindMemberName); + } + } +"(" { current->name+=*yytext; + roundCount++; + } +")" { current->name+=*yytext; + if (roundCount>0) roundCount--; + } +. { + current->name+=*yytext; + // *currentTemplateSpec+=*yytext; + } +"define"{BN}*"("{BN}*["'] { + if (insidePHP) + { + current->bodyLine = yyLineNr; + BEGIN( DefinePHP ); + } + else + REJECT; + } +{ID} { // PHP heredoc + g_hereDocId = yytext; + *pCopyHereDocGString += yytext; + BEGIN(CopyHereDocEnd); + } +"'"{ID}/"'" { // PHP nowdoc + g_hereDocId = &yytext[1]; + *pCopyHereDocGString += yytext; + BEGIN(CopyHereDocEnd); + } +{ID} { // PHP heredoc + g_hereDocId = yytext; + BEGIN(HereDocEnd); + } +"'"{ID}/"'" { // PHP nowdoc + g_hereDocId = &yytext[1]; + BEGIN(HereDocEnd); + } +^{ID} { // id at start of the line could mark the end of the block + if (g_hereDocId==yytext) // it is the end marker + { + BEGIN(lastHereDocContext); + } + } +. { } +^{ID} { // id at start of the line could mark the end of the block + *pCopyHereDocGString += yytext; + if (g_hereDocId==yytext) // it is the end marker + { + BEGIN(lastHereDocContext); + } + } +\n { + *pCopyHereDocGString += yytext; + } +. { + *pCopyHereDocGString += yytext; + } +"Q_OBJECT" { // Qt object macro + } +"Q_PROPERTY" { // Qt property declaration + current->protection = protection = Public ; + current->mtype = mtype = Property; + current->type.resize(0); + BEGIN(QtPropType); + } +"(" { // start of property arguments + } +")" { // end of property arguments + unput(';'); + BEGIN(FindMembers); + } +"const"|"volatile" { + current->type+=yytext; + } +{B}+ { + current->type+=yytext; + } +({TSCOPE}"::")*{TSCOPE} { + current->type+=yytext; + BEGIN(QtPropName); + } +{ID} { + current->name=yytext; + BEGIN(QtPropAttr); + } +"READ" { + current->spec |= Entry::Readable; + BEGIN(QtPropRead); + } +"WRITE" { + current->spec |= Entry::Writable; + BEGIN(QtPropWrite); + } +"RESET"{B}+{ID} { // reset method => not supported yet + } +"SCRIPTABLE"{B}+{ID} { // scriptable property => not supported yet + } +"DESIGNABLE"{B}+{ID} { // designable property => not supported yet + } +{ID} { + current->read = yytext; + BEGIN(QtPropAttr); + } +{ID} { + current->write = yytext; + BEGIN(QtPropAttr); + } +"friend"{BN}+("class"|"union"|"struct"){BN}+ { + current->name=yytext; + BEGIN(FindMembers); + } +{SCOPENAME} { + lineCount(); + if (insideIDL && yyleng==9 && strcmp(yytext,"cpp_quote")==0) + { + BEGIN(CppQuote); + } + else if ((insideIDL || insideJava || insideD) && yyleng==6 && strcmp(yytext,"import")==0) + { + if (insideIDL) + BEGIN(NextSemi); + else // insideJava or insideD + BEGIN(JavaImport); + } + else if (insidePHP && strcmp(yytext,"use")==0) + { + BEGIN(PHPUse); + } + else if (insideJava && strcmp(yytext,"package")==0) + { + lineCount(); + BEGIN(PackageName); + } + else if (insideIDL && strcmp(yytext,"case")==0) + { + BEGIN(IDLUnionCase); + } + else if (insideTryBlock && strcmp(yytext,"catch")==0) + { + insideTryBlock=FALSE; + BEGIN(TryFunctionBlock); + } + else if (insideJS && strcmp(yytext,"var")==0) + { // javascript variable + current->type="var"; + } + else if (insideJS && strcmp(yytext,"function")==0) + { // javascript function + current->type="function"; + } + else if (insideCS && strcmp(yytext,"this")==0) + { + // C# indexer + addType( current ) ; + current->name="this"; + BEGIN(CSIndexer); + } + else + { + if (YY_START==FindMembers) + { + addType( current ) ; + } + bool javaLike = insideJava || insideCS || insideD || insidePHP || insideJS; + if (javaLike && strcmp(yytext,"public")==0) + { + current->protection = Public; + } + else if (javaLike && strcmp(yytext,"protected")==0) + { + current->protection = Protected; + } + else if (javaLike && strcmp(yytext,"internal")==0) + { + current->protection = Package; + } + else if (javaLike && strcmp(yytext,"private")==0) + { + current->protection = Private; + } + else if (javaLike && strcmp(yytext,"static")==0) + { + if (YY_START==FindMembers) + current->name = yytext; + else + current->name += yytext; + current->stat = TRUE; + } + else + { + if (YY_START==FindMembers) + current->name = yytext; + else + current->name += yytext; + if (current->name.left(7)=="static ") + { + current->stat = TRUE; + current->name= current->name.mid(7); + } + else if (current->name.left(7)=="inline ") + { + if (current->type.isEmpty()) + { + current->type="inline"; + } + else + { + current->type+="inline "; + } + current->name= current->name.mid(7); + } + else if (current->name.left(6)=="const ") + { + if (current->type.isEmpty()) + { + current->type="const"; + } + else + { + current->type+="const "; + } + current->name=current->name.mid(6); + } + } + QCString tmp=yytext; + if (nameIsOperator(tmp)) + { + BEGIN( Operator ); + } + else + { + BEGIN(FindMembers); + } + } + } +"["[^\n\]]*"]" { + current->name+=removeRedundantWhiteSpace(yytext); + BEGIN(FindMembers); + } +[0-9]{ID} { // some number where we did not expect one + } +"." { + if (insideJava || insideCS || insideD) + { + current->name+="."; + } + } +"::" { + current->name+=yytext; + } +"("{B}*"\"" { + insideCppQuote=TRUE; + BEGIN(FindMembers); + } +"::" +":" { BEGIN(FindMembers); } +\n { yyLineNr++; } +. +\n { yyLineNr++; } +"{" { + curlyCount=0; + lastCurlyContext = TryFunctionBlockEnd ; + BEGIN( SkipCurly ); + } +. +{BN}*"catch" { lineCount(); BEGIN(TryFunctionBlock); // {BN}* added to fix bug 611193 + } +\n { unput(*yytext); // rule added to fix bug id 601138 + BEGIN( FindMembers ); + } +. { unput(*yytext); + BEGIN( FindMembers ); + } +")" { + insideCppQuote=FALSE; + BEGIN(FindMembers); + } +{B}*"#" { if (insidePHP) + REJECT; + lastCPPContext = YY_START; + BEGIN( SkipCPP ) ; + } +{B}*"#"{B}*("cmake")?"define" { + if (insidePHP) + REJECT; + current->bodyLine = yyLineNr; + lastDefineContext = YY_START; + BEGIN( Define ); + } +{B}*"#"{B}+[0-9]+{B}+/"\"" { /* line control directive */ + yyLineNr = atoi(&yytext[1]); + //printf("setting line number to %d\n",yyLineNr); + lastPreLineCtrlContext = YY_START; + if (YY_START==ReadBody || + YY_START==ReadNSBody || + YY_START==ReadBodyIntf) + { + current->program+=yytext; + } + BEGIN( PreLineCtrl ); + } +"\""[^\n\"]*"\"" { + yyFileName = stripQuotes(yytext); + if (lastPreLineCtrlContext==ReadBody || + lastPreLineCtrlContext==ReadNSBody || + lastPreLineCtrlContext==ReadBodyIntf) + { + current->program+=yytext; + } + } +. { + if (lastPreLineCtrlContext==ReadBody || + lastPreLineCtrlContext==ReadNSBody || + lastPreLineCtrlContext==ReadBodyIntf) + { + current->program+=yytext; + } + } +\n { + if (lastPreLineCtrlContext==ReadBody || + lastPreLineCtrlContext==ReadNSBody || + lastPreLineCtrlContext==ReadBodyIntf) + { + current->program+=yytext; + } + yyLineNr++; + BEGIN( lastPreLineCtrlContext ); + } +. +\\[\r]*"\n"[\r]* { yyLineNr++ ; } +[\r]*\n[\r]* { yyLineNr++ ; + BEGIN( lastCPPContext) ; + } +{ID}{B}*"(" { + current->name = yytext; + current->name = current->name.left(current->name.length()-1).stripWhiteSpace(); + current->args = "("; + current->bodyLine = yyLineNr; + currentArgumentContext = DefineEnd; + fullArgString=current->args.copy(); + copyArgString=¤t->args; + BEGIN( ReadFuncArgType ) ; + } + /* +")" { + //printf("Define with args\n"); + current->args += ')'; + BEGIN( DefineEnd ); + } +. { + current->args += *yytext; + } + */ +{ID} { + //printf("Define `%s' without args\n",yytext); + current->bodyLine = yyLineNr; + current->name = yytext; + BEGIN(DefineEnd); + } +\n { + //printf("End define: doc=%s docFile=%s docLine=%d\n",current->doc.data(),current->docFile.data(),current->docLine); + yyLineNr++; + current->fileName = yyFileName; + current->startLine = yyLineNr; + current->type.resize(0); + current->args = current->args.simplifyWhiteSpace(); + current->name = current->name.stripWhiteSpace(); + current->section = Entry::DEFINE_SEC; + current_root->addSubEntry(current); + current = new Entry ; + initEntry(); + BEGIN(lastDefineContext); + } +";" { + //printf("End define\n"); + current->fileName = yyFileName; + current->startLine = yyLineNr; + current->type.resize(0); + current->args = current->args.simplifyWhiteSpace(); + current->name = current->name.stripWhiteSpace(); + current->section = Entry::ENUM_SEC; //HACK! + current_root->addSubEntry(current); + current = new Entry ; + initEntry(); + BEGIN(FindMembers); + } +. +\\[\r]?\n { + yyLineNr++; + } +\" { + if (insideIDL && insideCppQuote) + { + BEGIN(EndCppQuote); + } + else + { + lastStringContext=DefineEnd; + BEGIN(SkipString); + } + } +. +{ID}["']{BN}*","{BN}* { + current->name = yytext; + current->name = current->name.stripWhiteSpace(); + current->name = current->name.left(current->name.length()-1).stripWhiteSpace(); + current->name = current->name.left(current->name.length()-1); + current->args = "("; + current->bodyLine = yyLineNr; + lastRoundContext = DefinePHPEnd; + pCopyRoundString = ¤t->args; + roundCount = 0; + BEGIN( CopyRound ); + } + +[\^%] { // ^ and % are C++/CLI extensions + if (insideCli) + { + addType( current ); + current->name = yytext ; + } + else + { + REJECT; + } + } +[*&]+ { + current->name += yytext ; + addType( current ); + } +";"{BN}*("/**"|"//!"|"/*!"|"///")"<" { + lineCount(); + if (current->bodyLine==-1) + { + current->bodyLine=yyLineNr; + } + docBlockContext = YY_START; + docBlockInBody = FALSE; + docBlockAutoBrief = ( yytext[yyleng-2]=='*' && Config_getBool("JAVADOC_AUTOBRIEF") ) || + ( yytext[yyleng-2]=='!' && Config_getBool("QT_AUTOBRIEF") ); + docBlock.resize(0); + docBlockTerm = ';'; + if (yytext[yyleng-3]=='/') + { + startCommentBlock(TRUE); + BEGIN( DocLine ); + } + else + { + startCommentBlock(FALSE); + BEGIN( DocBlock ); + } + } +","{BN}*("/**"|"//!"|"/*!"|"///")"<" { + lineCount(); + docBlockContext = YY_START; + docBlockInBody = FALSE; + docBlockAutoBrief = ( yytext[yyleng-2]=='*' && Config_getBool("JAVADOC_AUTOBRIEF") ) || + ( yytext[yyleng-2]=='!' && Config_getBool("QT_AUTOBRIEF") ); + docBlock.resize(0); + docBlockTerm = ','; + if (yytext[yyleng-3]=='/') + { + startCommentBlock(TRUE); + BEGIN( DocLine ); + } + else + { + startCommentBlock(FALSE); + BEGIN( DocBlock ); + } + } +{BN}*("/**"|"//!"|"/*!"|"///")"<" { + lineCount(); + if (current->bodyLine==-1) + { + current->bodyLine=yyLineNr; + } + docBlockContext = YY_START; + docBlockInBody = FALSE; + docBlockAutoBrief = ( yytext[yyleng-2]=='*' && Config_getBool("JAVADOC_AUTOBRIEF") ) || + ( yytext[yyleng-2]=='!' && Config_getBool("QT_AUTOBRIEF") ); + docBlock.resize(0); + docBlockTerm = 0; + if (yytext[yyleng-3]=='/') + { + startCommentBlock(TRUE); + BEGIN( DocLine ); + } + else + { + startCommentBlock(FALSE); + BEGIN( DocBlock ); + } + } + +("//"([!/]?){B}*{CMD}"{")|("/*"([!*]?){B}*{CMD}"{") { + //handleGroupStartCommand(current->name); + if (previous && previous->section==Entry::GROUPDOC_SEC) + { + // link open command to the group defined in the previous entry + openGroup(previous,yyFileName,yyLineNr); + } + else + { + // link open command to the current entry + openGroup(current,yyFileName,yyLineNr); + } + //current = tmp; + initEntry(); + if (yytext[1]=='/') + { + if (yytext[2]=='!' || yytext[2]=='/') + { + docBlockContext = YY_START; + docBlockInBody = FALSE; + docBlockAutoBrief = FALSE; + docBlock.resize(0); + docBlockTerm = 0; + startCommentBlock(TRUE); + BEGIN(DocLine); + } + else + { + lastCContext=YY_START; + BEGIN(SkipCxxComment); + } + } + else + { + if (yytext[2]=='!' || yytext[2]=='*') + { + docBlockContext = YY_START; + docBlockInBody = FALSE; + docBlock.resize(0); + docBlockAutoBrief = ( yytext[yyleng-2]=='*' && Config_getBool("JAVADOC_AUTOBRIEF") ) || + ( yytext[yyleng-2]=='!' && Config_getBool("QT_AUTOBRIEF") ); + docBlockTerm = 0; + startCommentBlock(FALSE); + BEGIN(DocBlock); + } + else + { + lastCContext=YY_START; + BEGIN(SkipComment); + } + } + } +"//"([!/]?){B}*{CMD}"}".*|"/*"([!*]?){B}*{CMD}"}"[^*]*"*/" { + closeGroup(current,yyFileName,yyLineNr); + } +"=" { // in PHP code this could also be due to "bodyLine = yyLineNr; + lastInitializerContext = YY_START; + initBracketCount=0; + BEGIN(ReadInitializer); + } + /* Read initializer rules */ +"(" { + lastRoundContext=YY_START; + pCopyRoundGString=¤t->initializer; + roundCount=0; + current->initializer+=*yytext; + BEGIN(GCopyRound); + } +"{" { + lastCurlyContext=YY_START; + pCopyCurlyGString=¤t->initializer; + curlyCount=0; + current->initializer+=*yytext; + BEGIN(GCopyCurly); + } +[;,] { + //printf(">> initializer `%s' <<\n",current->initializer.data()); + if (*yytext==';' && (current_root->spec&Entry::Enum)) + { + current->fileName = yyFileName; + current->startLine = yyLineNr; + current->args = current->args.simplifyWhiteSpace(); + current->name = current->name.stripWhiteSpace(); + current->section = Entry::VARIABLE_SEC; + current_root->addSubEntry(current); + current = new Entry; + initEntry(); + BEGIN(FindMembers); + } + else if (*yytext==';' || (lastInitializerContext==FindFields && initBracketCount==0)) // initBracketCount==0 was added for bug 665778 + { + unput(*yytext); + BEGIN(lastInitializerContext); + } + else if (*yytext==',' && initBracketCount==0) // for "int a=0,b=0" + { + unput(*yytext); + BEGIN(lastInitializerContext); + } + else + { + current->initializer+=*yytext; + } + } +\" { + if (insideIDL && insideCppQuote) + { + BEGIN(EndCppQuote); + } + else + { + lastStringContext=YY_START; + current->initializer=yytext; + pCopyQuotedGString=¤t->initializer; + BEGIN(CopyGString); + } + } +"->" { + current->initializer+=yytext; + } +"<<" { + current->initializer+=yytext; + } +">>" { + current->initializer+=yytext; + } +[<\[{(] { + initBracketCount++; + current->initializer+=*yytext; + } +[>\]})] { + initBracketCount--; + current->initializer+=*yytext; + } +\' { + if (insidePHP) + { + current->initializer+=yytext; + pCopyQuotedGString = ¤t->initializer; + lastStringContext=YY_START; + BEGIN(CopyPHPGString); + } + else + { + current->initializer+=yytext; + } + } +{CHARLIT} { + if (insidePHP) + { + REJECT; + } + else + { + current->initializer+=yytext; + } + } +\n { + current->initializer+=*yytext; + yyLineNr++; + } +"@\"" { + //printf("insideCS=%d\n",insideCS); + current->initializer+=yytext; + if (!insideCS && !insideObjC) + { + REJECT; + } + else + { + // C#/ObjC verbatim string + lastSkipVerbStringContext=YY_START; + pSkipVerbString=¤t->initializer; + BEGIN(SkipVerbString); + } + } +[^\n"]+ { + *pSkipVerbString+=yytext; + } +"\"\"" { // quote escape + *pSkipVerbString+=yytext; + } +"\"" { + *pSkipVerbString+=*yytext; + BEGIN(lastSkipVerbStringContext); + } +\n { + *pSkipVerbString+=*yytext; + yyLineNr++; + } +. { + *pSkipVerbString+=*yytext; + } +"?>" { + if (insidePHP) + BEGIN( FindMembersPHP ); + else + current->initializer+=yytext; + } +. { + current->initializer+=*yytext; + } + + /* generic quoted string copy rules */ +\\. { + *pCopyQuotedString+=yytext; + } +\" { + *pCopyQuotedString+=*yytext; + BEGIN( lastStringContext ); + } +\' { + *pCopyQuotedString+=*yytext; + BEGIN( lastStringContext ); + } +"/*"|"*/"|"//" { + *pCopyQuotedString+=yytext; + } +\n { + *pCopyQuotedString+=*yytext; + yyLineNr++; + } +. { + *pCopyQuotedString+=*yytext; + } + + /* generic quoted growable string copy rules */ +\\. { + *pCopyQuotedGString+=yytext; + } +\" { + *pCopyQuotedGString+=*yytext; + BEGIN( lastStringContext ); + } +\' { + *pCopyQuotedGString+=*yytext; + BEGIN( lastStringContext ); + } +"/*"|"*/"|"//" { + *pCopyQuotedGString+=yytext; + } +\n { + *pCopyQuotedGString+=*yytext; + yyLineNr++; + } +. { + *pCopyQuotedGString+=*yytext; + } + + /* generic round bracket list copy rules */ +\" { + *pCopyRoundString+=*yytext; + pCopyQuotedString=pCopyRoundString; + lastStringContext=YY_START; + BEGIN(CopyString); + } +"(" { + *pCopyRoundString+=*yytext; + roundCount++; + } +")" { + *pCopyRoundString+=*yytext; + if (--roundCount<0) + BEGIN(lastRoundContext); + } +\n { + yyLineNr++; + *pCopyRoundString+=*yytext; + } +\' { + if (insidePHP) + { + current->initializer+=yytext; + pCopyQuotedString = pCopyRoundString; + lastStringContext=YY_START; + BEGIN(CopyPHPString); + } + else + { + *pCopyRoundString+=yytext; + } + } +{CHARLIT} { + if (insidePHP) + { + REJECT; + } + else + { + *pCopyRoundString+=yytext; + } + } +[^"'()\n]+ { + *pCopyRoundString+=yytext; + } +. { + *pCopyRoundString+=*yytext; + } + + /* generic round bracket list copy rules for growable strings */ +\" { + *pCopyRoundGString+=*yytext; + pCopyQuotedGString=pCopyRoundGString; + lastStringContext=YY_START; + BEGIN(CopyGString); + } +"(" { + *pCopyRoundGString+=*yytext; + roundCount++; + } +")" { + *pCopyRoundGString+=*yytext; + if (--roundCount<0) + BEGIN(lastRoundContext); + } +\n { + yyLineNr++; + *pCopyRoundGString+=*yytext; + } +\' { + if (insidePHP) + { + current->initializer+=yytext; + pCopyQuotedGString = pCopyRoundGString; + lastStringContext=YY_START; + BEGIN(CopyPHPGString); + } + else + { + *pCopyRoundGString+=yytext; + } + } +{CHARLIT} { + if (insidePHP) + { + REJECT; + } + else + { + *pCopyRoundGString+=yytext; + } + } +[^"'()\n/]+ { + *pCopyRoundGString+=yytext; + } +. { + *pCopyRoundGString+=*yytext; + } + + /* generic curly bracket list copy rules */ +\" { + *pCopyCurlyString+=*yytext; + pCopyQuotedString=pCopyCurlyString; + lastStringContext=YY_START; + BEGIN(CopyString); + } +\' { + *pCopyCurlyString+=*yytext; + if (insidePHP) + { + pCopyQuotedString=pCopyCurlyString; + lastStringContext=YY_START; + BEGIN(CopyPHPString); + } + } +"{" { + *pCopyCurlyString+=*yytext; + curlyCount++; + } +"}" { + *pCopyCurlyString+=*yytext; + if (--curlyCount<0) + BEGIN(lastCurlyContext); + } +{CHARLIT} { if (insidePHP) + { + REJECT; + } + else + { + *pCopyCurlyString+=yytext; + } + } +[^"'{}\/\n]+ { + *pCopyCurlyString+=yytext; + } +"/" { *pCopyCurlyString+=yytext; } +\n { + yyLineNr++; + *pCopyCurlyString+=*yytext; + } +. { + *pCopyCurlyString+=*yytext; + } + + /* generic curly bracket list copy rules for growable strings */ +^"#"{B}+[0-9]+{B}+"\""[^\"\n]+"\""{B}+"1"{B}*\n? { // start of included file marker + } +^"#"{B}+[0-9]+{B}+"\""[^\"\n]+"\""{B}+"2"{B}*\n? { // end of included file marker + QCString line = QCString(yytext); + int s = line.find(' '); + int e = line.find('"',s); + yyLineNr = line.mid(s,e-s).toInt(); + if (yytext[yyleng-1]=='\n') + { + yyLineNr++; + } + } +\" { + *pCopyCurlyGString+=*yytext; + pCopyQuotedGString=pCopyCurlyGString; + lastStringContext=YY_START; + BEGIN(CopyGString); + } +\' { + *pCopyCurlyGString+=*yytext; + if (insidePHP) + { + pCopyQuotedGString=pCopyCurlyGString; + lastStringContext=YY_START; + BEGIN(CopyPHPGString); + } + } +"{" { + *pCopyCurlyGString+=*yytext; + curlyCount++; + } +"}" { + *pCopyCurlyGString+=*yytext; + if (--curlyCount<0) + BEGIN(lastCurlyContext); + } +{CHARLIT} { if (insidePHP) + { + REJECT; + } + else + { + *pCopyCurlyGString+=yytext; + } + } +[^"'{}\/\n]+ { + *pCopyCurlyGString+=yytext; + } +"/" { *pCopyCurlyGString+=yytext; } +\n { + yyLineNr++; + *pCopyCurlyGString+=*yytext; + } +. { + *pCopyCurlyGString+=*yytext; + } + + /* ---------------------- */ + + +":" { + if (current->type.isEmpty()) // anonymous padding field, e.g. "int :7;" + { + addType(current); + current->name.sprintf("__pad%d__",padCount++); + } + BEGIN(BitFields); + current->bitfields+=":"; + } +. { + current->bitfields+=*yytext; + } +[;,] { + QCString oldType = current->type.copy(); + if (current->bodyLine==-1) + { + current->bodyLine = yyLineNr; + } + if ( insidePHP && current->type.left(3) == "var" ) + { + current->type = current->type.mid(3); + } + if (isTypedef && current->type.left(8)!="typedef ") + { + current->type.prepend("typedef "); + } + bool needNewCurrent=FALSE; + if (!current->name.isEmpty() && current->section!=Entry::ENUM_SEC) + { + current->type=current->type.simplifyWhiteSpace(); + current->args=removeRedundantWhiteSpace(current->args); + current->name=current->name.stripWhiteSpace(); + if (current->section==Entry::CLASS_SEC) // remove spec for "struct Bla bla;" + { + current->spec = 0; + } + current->section = Entry::VARIABLE_SEC ; + current->fileName = yyFileName; + current->startLine = yyLineNr; + current_root->addSubEntry( current ) ; + needNewCurrent=TRUE; + } + if ( *yytext == ',') + { + bool stat = current->stat; + if (needNewCurrent) + { + current = new Entry(*current); + initEntry(); + } + current->stat = stat; // the static attribute holds for all variables + current->name.resize(0); + current->args.resize(0); + current->brief.resize(0); + current->doc.resize(0); + current->initializer.resize(0); + current->bitfields.resize(0); + int i=oldType.length(); + while (i>0 && (oldType[i-1]=='*' || oldType[i-1]=='&' || oldType[i-1]==' ')) i--; + current->type = oldType.left(i); + } + else + { + if (needNewCurrent) + { + current = new Entry ; + } + else if (current->groups) + { + current->groups->clear(); + } + initEntry(); + } + } + +"[" { + if (!insideCS && + (current->name.isEmpty() || + current->name=="typedef" + ) + ) // IDL function property + { + squareCount=1; + lastSquareContext = YY_START; + idlAttr.resize(0); + idlProp.resize(0); + current->mtype = mtype; + BEGIN( IDLAttribute ); + } + else if (insideCS && + current->name.isEmpty()) + { + squareCount=1; + lastSquareContext = YY_START; + // Skip the C# attribute + // for this member + current->args.resize(0); + BEGIN( SkipSquare ); + } + else + { + current->args += yytext ; + squareCount=1; + BEGIN( Array ) ; + } + } +"]" { + // end of IDL function attribute + if (--squareCount<=0) + { + lineCount(); + if (current->mtype == Property) + BEGIN( IDLPropName ); + else + BEGIN( lastSquareContext ); + } + } +"propput" { + if (Config_getBool("IDL_PROPERTY_SUPPORT")) + { + current->mtype = Property; + } + current->spec |= Entry::Settable; + } +"propget" { + if (Config_getBool("IDL_PROPERTY_SUPPORT")) + { + current->mtype = Property; + } + current->spec |= Entry::Gettable; + } +. { + } +{BN}*{ID}{BN}* { + // return type (probably HRESULT) - skip it + } +{ID}{BN}*"(" { + current->name = yytext; + current->name = current->name.left(current->name.length()-1).stripWhiteSpace(); + current->startLine = yyLineNr; + BEGIN( IDLProp ); + } +{BN}*"["[^\]]*"]"{BN}* { // attribute of a parameter + idlAttr = yytext; + idlAttr=idlAttr.stripWhiteSpace(); + } +{ID} { // property type + idlProp = yytext; + } +{BN}*{ID}{BN}*"," { // Rare: Another parameter ([propput] HRESULT Item(int index, [in] Type theRealProperty);) + if (!current->args) + current->args = "("; + else + current->args += ", "; + current->args += idlAttr; + current->args += " "; + current->args += idlProp; // prop was actually type of extra parameter + current->args += " "; + current->args += yytext; + current->args = current->args.left(current->args.length() - 1); // strip comma + idlProp.resize(0); + idlAttr.resize(0); + BEGIN( IDLProp ); + } +{BN}*{ID}{BN}*")"{BN}* { + // the parameter name for the property - just skip. + } +";" { + current->fileName = yyFileName; + current->type = idlProp; + current->args = current->args.simplifyWhiteSpace(); + if (current->args) + current->args += ")"; + current->name = current->name.stripWhiteSpace(); + current->section = Entry::VARIABLE_SEC; + current_root->addSubEntry(current); + current = new Entry; + initEntry(); + BEGIN( FindMembers ); + } +. { // spaces, *, or other stuff + //idlProp+=yytext; + } +"]" { current->args += *yytext ; + if (--squareCount<=0) + BEGIN( FindMembers ) ; + } +"]" { current->args += *yytext ; + if (--squareCount<=0) + BEGIN( Function ) ; + } +"[" { current->args += *yytext ; + squareCount++; + } +. { current->args += *yytext ; } +"[" { squareCount++; } +"]" { + if (--squareCount<=0) + BEGIN( lastSquareContext ); + } +\" { + lastStringContext=YY_START; + BEGIN( SkipString ); + } +[^\n\[\]\"]+ +"<" { addType( current ) ; + current->type += yytext ; + BEGIN( Sharp ) ; + } +">" { current->type += *yytext ; + if (--sharpCount<=0) + BEGIN( FindMembers ) ; + } +"<" { current->type += *yytext ; + sharpCount++; + } +{BN}+ { + lineCount(); + } +. { current->type += *yytext ; } +{ID} { + current->bodyLine = yyLineNr; + current->name = yytext; + } +"(" { + // Java enum initializer + unput('('); + lastInitializerContext = YY_START; + initBracketCount=0; + BEGIN(ReadInitializer); + } +"=" { + lastInitializerContext = YY_START; + initBracketCount=0; + BEGIN(ReadInitializer); + } +";" { + if (insideJava) // last enum field in Java class + { + if (!current->name.isEmpty()) + { + current->fileName = yyFileName; + current->startLine = yyLineNr; + current->type = "@"; // enum marker + current->args = current->args.simplifyWhiteSpace(); + current->name = current->name.stripWhiteSpace(); + current->section = Entry::VARIABLE_SEC; + current_root->addSubEntry(current); + current = new Entry ; + initEntry(); + } + + BEGIN( FindMembers ); + } + else + { + REJECT; + } + } +\n { + yyLineNr++; + } +[^\n]* +"," { + //printf("adding `%s' `%s' `%s' to enum `%s' (mGrpId=%d)\n", + // current->type.data(), current->name.data(), + // current->args.data(), current_root->name.data(),current->mGrpId); + if (!current->name.isEmpty()) + { + current->fileName = yyFileName; + current->startLine = yyLineNr; + if (!(current_root->spec&Entry::Enum)) + { + current->type = "@"; // enum marker + } + current->args = current->args.simplifyWhiteSpace(); + current->name = current->name.stripWhiteSpace(); + current->section = Entry::VARIABLE_SEC; + // add to the scope of the enum + current_root->addSubEntry(current); + if (!insideCS && !insideJava) // for C# and Java 1.5+ enum values always have to be explicitly qualified + { + current = new Entry(*current); + // add to the scope surrounding the enum (copy!) + current_root->parent()->addSubEntry(current); + } + current = new Entry ; + initEntry(); + } + else // probably a redundant , + { + current->reset(); + initEntry(); + } + } +"[" { // attribute list in IDL + squareCount=1; + lastSquareContext = YY_START; + BEGIN(SkipSquare); + } + /* +"," { unput(*yytext); BEGIN(FindFields); } + */ +[^\r\n\#{}"@'/<]* { current->program += yytext ; } +"//".* { current->program += yytext ; } +"#".* { if (!insidePHP) + REJECT; + // append PHP comment. + current->program += yytext ; + } +@\" { current->program += yytext ; + pSkipVerbString = ¤t->program; + lastSkipVerbStringContext=YY_START; + BEGIN( SkipVerbString ); + } +"<<<" { if (insidePHP) + { + current->program += yytext ; + pCopyHereDocGString = ¤t->program; + lastHereDocContext=YY_START; + BEGIN( CopyHereDoc ); + } + else + { + REJECT; + } + } +\" { current->program += yytext ; + pCopyQuotedGString = ¤t->program; + lastStringContext=YY_START; + BEGIN( CopyGString ); + } +"/*"{B}* { current->program += yytext ; + lastContext = YY_START ; + BEGIN( Comment ) ; + } +"/*"{BL} { current->program += yytext ; + ++yyLineNr ; + lastContext = YY_START ; + BEGIN( Comment ) ; + } +"'" { + if (!insidePHP) + { + current->program += yytext; + } + else + { // begin of single quoted string + current->program += yytext; + pCopyQuotedGString = ¤t->program; + lastStringContext=YY_START; + BEGIN(CopyPHPGString); + } + } +{CHARLIT} { + if (insidePHP) + { + REJECT; // for PHP code single quotes + // are used for strings of arbitrary length + } + else + { + current->program += yytext; + } + } +"{" { current->program += yytext ; + ++curlyCount ; + } +"}" { + current->program += yytext ; + --curlyCount ; + } +"}" { //err("ReadBody count=%d\n",curlyCount); + if ( curlyCount>0 ) + { + current->program += yytext ; + --curlyCount ; + } + else + { + current->endBodyLine = yyLineNr; + QCString &cn = current->name; + QCString rn = current_root->name.copy(); + //printf("cn=`%s' rn=`%s' isTypedef=%d\n",cn.data(),rn.data(),isTypedef); + if (!cn.isEmpty() && !rn.isEmpty()) + { + prependScope(); + } + if (isTypedef && cn.isEmpty()) + { + //printf("Typedef Name\n"); + BEGIN( TypedefName ); + } + else + { + if ((current->section == Entry::ENUM_SEC) || (current->spec&Entry::Enum)) + { + current->program+=','; // add field terminator + } + // add compound definition to the tree + current->args=removeRedundantWhiteSpace(current->args); + // was: current->args.simplifyWhiteSpace(); + current->type = current->type.simplifyWhiteSpace(); + current->name = current->name.stripWhiteSpace(); + //printf("adding `%s' `%s' `%s' brief=%s insideObjC=%d %x\n",current->type.data(),current->name.data(),current->args.data(),current->brief.data(),insideObjC,current->section); + if (insideObjC && + ((current->spec&Entry::Interface) || (current->spec==Entry::Category)) + ) // method definition follows + { + BEGIN( ReadBodyIntf ) ; + } + else + { + current_root->addSubEntry( current ) ; + memspecEntry = current; + current = new Entry(*current); + if (current->section==Entry::NAMESPACE_SEC || + (current->spec==Entry::Interface) || + insideJava || insidePHP || insideCS || insideD || insideJS + ) + { // namespaces and interfaces and java classes ends with a closing bracket without semicolon + current->reset(); + initEntry(); + memspecEntry = 0; + BEGIN( FindMembers ) ; + } + else + { + if (!isTypedef && cn.find('@')==-1) // not typedef or unnamed struct + { + // enabled the next two lines for bug 623424 + current->doc.resize(0); + current->brief.resize(0); + } + BEGIN( MemberSpec ) ; + } + } + } + } + } +"}"{BN}+"typedef"{BN}+ { //err("ReadBody count=%d\n",curlyCount); + lineCount(); + if ( curlyCount>0 ) + { + current->program += yytext ; + --curlyCount ; + } + else + { + isTypedef = TRUE; + current->endBodyLine = yyLineNr; + QCString &cn = current->name; + QCString rn = current_root->name.copy(); + if (!cn.isEmpty() && !rn.isEmpty()) + { + prependScope(); + } + BEGIN( TypedefName ); + } + } +("const"|"volatile"){BN} { // late "const" or "volatile" keyword + lineCount(); + current->type.prepend(yytext); + } +{ID} { + if ((current->section == Entry::ENUM_SEC) || (current->spec&Entry::Enum)) + { + current->program+=","; // add field terminator + } + current->name=yytext; + prependScope(); + current->args = current->args.simplifyWhiteSpace(); + current->type = current->type.simplifyWhiteSpace(); + //printf("Adding compound %s %s %s\n",current->type.data(),current->name.data(),current->args.data()); + current_root->addSubEntry( current ) ; + if (!firstTypedefEntry) + { + firstTypedefEntry = current; + } + current = new Entry; + initEntry(); + isTypedef=TRUE; // to undo reset by initEntry() + BEGIN(MemberSpecSkip); + } +";" { /* typedef of anonymous type */ + current->name.sprintf("@%d",anonCount++); + if ((current->section == Entry::ENUM_SEC) || (current->spec&Entry::Enum)) + { + current->program+=','; // add field terminator + } + // add compound definition to the tree + current->args = current->args.simplifyWhiteSpace(); + current->type = current->type.simplifyWhiteSpace(); + current_root->addSubEntry( current ) ; + memspecEntry = current; + current = new Entry(*current); + initEntry(); + unput(';'); + BEGIN( MemberSpec ) ; + } +([*&]*{BN}*)*{ID}{BN}*("["[^\]\n]*"]")* { // the [] part could be improved. + lineCount(); + int i=0,l=yyleng,j; + while (ispec&Entry::Struct) + { + msType.prepend("struct "+firstTypedefEntry->name); + } + else if (firstTypedefEntry->spec&Entry::Union) + { + msType.prepend("union "+firstTypedefEntry->name); + } + else if (firstTypedefEntry->section==Entry::ENUM_SEC) + { + msType.prepend("enum "+firstTypedefEntry->name); + } + else + { + msType.prepend(firstTypedefEntry->name); + } + } + } +"(" { // function with struct return type + addType(current); + current->name = msName; + current->spec = 0; + unput('('); + BEGIN(FindMembers); + } +[,;] { + if (msName.isEmpty() && !current->name.isEmpty()) + { + // see if the compound does not have a name or is inside another + // anonymous compound. If so we insert a + // special `anonymous' variable. + //Entry *p=current_root; + Entry *p=current; + while (p) + { + // only look for class scopes, not namespace scopes + if ((p->section & Entry::COMPOUND_MASK) && !p->name.isEmpty()) + { + //printf("Trying scope `%s'\n",p->name.data()); + int i=p->name.findRev("::"); + int pi = (i==-1) ? 0 : i+2; + if (p->name.at(pi)=='@') + { + // anonymous compound inside -> insert dummy variable name + //printf("Adding anonymous variable for scope %s\n",p->name.data()); + msName.sprintf("@%d",anonCount++); + break; + } + } + //p=p->parent; + if (p==current) p=current_root; else p=p->parent(); + } + } + //printf("msName=%s current->name=%s\n",msName.data(),current->name.data()); + if (!msName.isEmpty() + /*&& msName!=current->name*/) // skip typedef T {} T;, removed due to bug608493 + { + static bool typedefHidesStruct = Config_getBool("TYPEDEF_HIDES_STRUCT"); + // case 1: typedef struct _S { ... } S_t; + // -> omit typedef and use S_t as the struct name + if (typedefHidesStruct && + isTypedef && + ((current->spec&(Entry::Struct|Entry::Union)) || + current->section==Entry::ENUM_SEC )&& + msType.stripWhiteSpace().isEmpty() && + memspecEntry) + { + memspecEntry->name=msName; + } + else // case 2: create a typedef field + { + Entry *varEntry=new Entry; + varEntry->lang = language; + varEntry->protection = current->protection ; + varEntry->mtype = current->mtype; + varEntry->virt = current->virt; + varEntry->stat = current->stat; + varEntry->section = Entry::VARIABLE_SEC; + varEntry->name = msName.stripWhiteSpace(); + varEntry->type = current->type.simplifyWhiteSpace()+" "; + varEntry->args = msArgs; + if (isTypedef) + { + varEntry->type.prepend("typedef "); + // //printf("current->name = %s %s\n",current->name.data(),msName.data()); + } + if (typedefHidesStruct && + isTypedef && + (current->spec&(Entry::Struct|Entry::Union)) && + memspecEntry + ) // case 1: use S_t as type for pS_t in "typedef struct _S {} S_t, *pS_t;" + { + varEntry->type+=memspecEntry->name+msType; + } + else // case 2: use _S as type for for pS_t + { + varEntry->type+=current->name+msType; + } + varEntry->fileName = yyFileName; + varEntry->startLine = yyLineNr; + varEntry->doc = current->doc.copy(); + varEntry->brief = current->brief.copy(); + varEntry->mGrpId = current->mGrpId; + + // deep copy group list + QListIterator gli(*current->groups); + Grouping *g; + for (;(g=gli.current());++gli) + { + varEntry->groups->append(new Grouping(*g)); + } + if (current->sli) // copy special list items + { + QListIterator li(*current->sli); + ListItemInfo *lii; + for (li.toFirst();(lii=li.current());++li) + { + varEntry->addSpecialListItem(lii->type,lii->itemId); + } + } + + //printf("Add: type=`%s',name=`%s',args=`%s' brief=%s doc=%s\n", + // varEntry->type.data(),varEntry->name.data(), + // varEntry->args.data(),varEntry->brief.data(),varEntry->doc.data()); + current_root->addSubEntry(varEntry); + } + } + if (*yytext==';') // end of a struct/class ... + { + if (!isTypedef && msName.isEmpty() && memspecEntry && (current->section&Entry::COMPOUND_MASK)) + { // case where a class/struct has a doc block after it + if (!current->doc.isEmpty()) + { + memspecEntry->doc += current->doc; + } + if (!current->brief.isEmpty()) + { + memspecEntry->brief += current->brief; + } + } + msType.resize(0); + msName.resize(0); + msArgs.resize(0); + isTypedef=FALSE; + firstTypedefEntry=0; + memspecEntry=0; + current->reset(); + initEntry(); + BEGIN( FindMembers ); + } + else + { + current->doc.resize(0); + current->brief.resize(0); + } + + } +"=" { + lastInitializerContext=YY_START; + initBracketCount=0; + BEGIN(ReadInitializer); + /* BEGIN(MemberSpecSkip); */ + } + /* +"{" { + curlyCount=0; + lastCurlyContext = MemberSpecSkip; + previous = current; + BEGIN(SkipCurly); + } + */ +"," { BEGIN(MemberSpec); } +";" { unput(';'); BEGIN(MemberSpec); } +{BN}{1,80} { current->program += yytext ; + lineCount() ; + } +"@end"/[^a-z_A-Z0-9] { // end of Objective C block + current_root->addSubEntry( current ) ; + current=new Entry; + initEntry(); + insideObjC=FALSE; + BEGIN( FindMembers ); + } +. { current->program += yytext ; } + +"("/{BN}*"::"*{BN}*({TSCOPE}{BN}*"::")*{TSCOPE}{BN}*")"{BN}*"(" | /* typedef void (A::func_t)(args...) */ +("("({BN}*"::"*{BN}*{TSCOPE}{BN}*"::")*({BN}*[*&\^]{BN}*)+)+ { /* typedef void (A::*ptr_t)(args...) or int (*func(int))[], the ^ is for Obj-C blocks */ + if (insidePHP) // reference parameter + { + REJECT + } + else + { + current->bodyLine = yyLineNr; + lineCount(); + addType(current); + funcPtrType=yytext; + roundCount=0; + //current->type += yytext; + BEGIN( FuncPtr ); + } + } +{SCOPENAME} { + current->name = yytext; + if (nameIsOperator(current->name)) + { + BEGIN( FuncPtrOperator ); + } + else + { + if (current->name=="const" || current->name=="volatile") + { + funcPtrType += current->name; + } + else + { + BEGIN( EndFuncPtr ); + } + } + } +. { + //printf("error: FuncPtr `%c' unexpected at line %d of %s\n",*yytext,yyLineNr,yyFileName); + } +"("{BN}*")"{BN}*/"(" { + current->name += yytext; + current->name = current->name.simplifyWhiteSpace(); + lineCount(); + } +\n { + yyLineNr++; + current->name += *yytext; + } +"(" { + unput(*yytext); + BEGIN( EndFuncPtr ); + } +. { + current->name += *yytext; + } +")"{BN}*/";" { // a variable with extra braces + lineCount(); + current->type+=funcPtrType.data()+1; + BEGIN(FindMembers); + } +")"{BN}*/"(" { // a function pointer + lineCount(); + current->type+=funcPtrType+")"; + BEGIN(FindMembers); + } +")"{BN}*/"[" { // an array of variables + lineCount(); + current->type+=funcPtrType.data(); + current->args += ")"; + BEGIN(FindMembers); + } +"(" { // a function returning a function or + // a function returning a pointer to an array + current->args += *yytext ; + //roundCount=0; + //BEGIN( FuncFunc ); + current->bodyLine = yyLineNr; + currentArgumentContext = FuncFuncEnd; + fullArgString=current->args.copy(); + copyArgString=¤t->args; + BEGIN( ReadFuncArgType ) ; + } +"["[^\n\]]*"]" { + funcPtrType+=yytext; + } +")" { + BEGIN(FindMembers); + } +"(" { + current->args += *yytext ; + ++roundCount; + } +")" { + current->args += *yytext ; + if ( roundCount ) + --roundCount; + else + { + BEGIN(FuncFuncEnd); + } + } +")"{BN}*"(" { + lineCount(); + current->type+=funcPtrType+")("; + BEGIN(FuncFuncType); + } +")"{BN}*/[;{] { + lineCount(); + current->type+=funcPtrType.data()+1; + BEGIN(Function); + } +")"{BN}*/"[" { // function returning a pointer to an array + lineCount(); + current->type+=funcPtrType; + current->args+=")"; + BEGIN(FuncFuncArray); + } +. { + current->args += *yytext; + } +"(" { + current->type += *yytext; + roundCount++; + } +")" { + current->type += *yytext; + if (roundCount) + --roundCount; + else + BEGIN(Function); + } +{BN}*","{BN}* { lineCount() ; current->type += ", " ; } +{BN}+ { lineCount() ; current->type += ' ' ; } +. { + current->type += *yytext; + } +"("/{BN}*{ID}{BN}*"*"{BN}*{ID}*")(" { // for catching typedef void (__stdcall *f)() like definitions + if (current->type.left(7)=="typedef" && current->bodyLine==-1) + // the bodyLine check is to prevent this guard to be true more than once + { + current->bodyLine = yyLineNr; + BEGIN( GetCallType ); + } + else if (!current->name.isEmpty()) // normal function + { + current->args = yytext; + current->bodyLine = yyLineNr; + currentArgumentContext = FuncQual; + fullArgString=current->args.copy(); + copyArgString=¤t->args; + BEGIN( ReadFuncArgType ) ; + //printf(">>> Read function arguments!\n"); + } + } +{BN}*{ID}{BN}*"*" { + lineCount(); + addType(current); + funcPtrType="("; + funcPtrType+=yytext; + roundCount=0; + BEGIN( FuncPtr ); + } +"(" { + if (!current->name.isEmpty()) + { + current->args = yytext; + current->bodyLine = yyLineNr; + currentArgumentContext = FuncQual; + fullArgString=current->args.copy(); + copyArgString=¤t->args; + BEGIN( ReadFuncArgType ) ; + //printf(">>> Read function arguments current->argList->count()=%d\n",current->argList->count()); + } + } + /* +"("{BN}*("void"{BN}*)?")" { + lineCount(); + current->args = "()"; + BEGIN( FuncQual ); + } + */ + + /*- Function argument reading rules ---------------------------------------*/ + +[^ \/\r\t\n\)\(\"\'#]+ { *copyArgString+=yytext; + fullArgString+=yytext; + } +[^\n\\\"\']+ { *copyArgString+=yytext; + fullArgString+=yytext; + } +[^\/\n\)\(\"\']+ { + *copyArgString+=yytext; + fullArgString+=yytext; + } +{BN}* { + *copyArgString+=" "; + fullArgString+=" "; + lineCount(); + } +\" { + *copyArgString+=*yytext; + fullArgString+=*yytext; + lastCopyArgStringContext = YY_START; + BEGIN( CopyArgString ); + } +"(" { + *copyArgString+=*yytext; + fullArgString+=*yytext; + argRoundCount=0; + lastCopyArgContext = YY_START; + BEGIN( CopyArgRound ); + } +")" { + *copyArgString+=*yytext; + fullArgString+=*yytext; + stringToArgumentList(fullArgString,current->argList); + if (insideJS) + { + fixArgumentListForJavaScript(current->argList); + } + handleParametersCommentBlocks(current->argList); + + /* remember the current documentation block, since + we could overwrite it with the documentation of + a function argument, which we then have to correct later + on + */ + docBackup = current->doc; + briefBackup = current->brief; + + BEGIN( currentArgumentContext ); + } + /* a special comment */ +("/*"[*!]|"//"[/!])("<"?) { + if (currentArgumentContext==DefineEnd) + { + // for defines we interpret a comment + // as documentation for the define + int i;for (i=yyleng-1;i>=0;i--) + { + unput(yytext[i]); + } + stringToArgumentList(fullArgString,current->argList); + handleParametersCommentBlocks(current->argList); + BEGIN( currentArgumentContext ); + } + else // not a define + { + // for functions we interpret a comment + // as documentation for the argument + fullArgString+=yytext; + lastCopyArgChar=0; + lastCommentInArgContext=YY_START; + if (yytext[1]=='/') + BEGIN( CopyArgCommentLine ); + else + BEGIN( CopyArgComment ); + } + } + /* a non-special comment */ +"/**/" { /* empty comment */ } +"/*" { + lastCContext = YY_START; + BEGIN( SkipComment ); + } +"//" { + lastCContext = YY_START; + BEGIN( SkipCxxComment ); + } + /* +"'#" { if (insidePHP) + REJECT; + *copyArgString+=yytext; + fullArgString+=yytext; + } +"#" { + if (!insidePHP) + REJECT; + lastCContext = YY_START; + BEGIN( SkipCxxComment ); + } + */ + /* `)' followed by a special comment */ +")"{BN}*("/*"[*!]|"//"[/!])"<" { + lineCount(); + if (currentArgumentContext==DefineEnd) + { + // for defines we interpret a comment + // as documentation for the define + int i;for (i=yyleng-1;i>0;i--) + { + unput(yytext[i]); + } + *copyArgString+=*yytext; + fullArgString+=*yytext; + stringToArgumentList(fullArgString,current->argList); + handleParametersCommentBlocks(current->argList); + BEGIN( currentArgumentContext ); + } + else + { + // for functions we interpret a comment + // as documentation for the last argument + lastCopyArgChar=*yytext; + QCString text=&yytext[1]; + text=text.stripWhiteSpace(); + lastCommentInArgContext=YY_START; + fullArgString+=text; + if (text.find("//")!=-1) + BEGIN( CopyArgCommentLine ); + else + BEGIN( CopyArgComment ); + } + } +^{B}*"*"+/{BN}+ +[^\n\\\@\*]+ { fullArgString+=yytext; } +"*/" { fullArgString+=yytext; + if (lastCopyArgChar!=0) + unput(lastCopyArgChar); + BEGIN( lastCommentInArgContext ); + } +\n { fullArgString+=yytext; + yyLineNr++; + if (lastCopyArgChar!=0) + unput(lastCopyArgChar); + BEGIN( lastCommentInArgContext ); + } +{CMD}("verbatim"|"latexonly"|"htmlonly"|"xmlonly"|"manonly"|"dot"|"code")/[^a-z_A-Z0-9] { // verbatim command (which could contain nested comments!) + docBlockName=&yytext[1]; + fullArgString+=yytext; + BEGIN(CopyArgVerbatim); + } +{CMD}("f$"|"f["|"f{") { + docBlockName=&yytext[1]; + if (docBlockName.at(1)=='[') + { + docBlockName.at(1)='}'; + } + if (docBlockName.at(1)=='{') + { + docBlockName.at(1)='}'; + } + fullArgString+=yytext; + BEGIN(CopyArgVerbatim); + } +[\\@]("endverbatim"|"endlatexonly"|"endhtmlonly"|"endxmlonly"|"endmanonly"|"enddot"|"endcode"|"f$"|"f]"|"f}")/[^a-z_A-Z0-9] { // end of verbatim block + fullArgString+=yytext; + if (yytext[1]=='f') // end of formula + { + BEGIN(CopyArgCommentLine); + } + if (&yytext[4]==docBlockName) + { + BEGIN(CopyArgCommentLine); + } + } +[^\\\@\n]+ { fullArgString+=yytext; } +. { fullArgString+=*yytext; } +\n { fullArgString+=*yytext; yyLineNr++; } +. { fullArgString+=*yytext; } +{CMD}("brief"|"short"){B}+ { + warn(yyFileName,yyLineNr, + "warning: Ignoring %cbrief command inside argument documentation",*yytext + ); + fullArgString+=' '; + } +"<" { + *copyArgString+=*yytext; + fullArgString+=*yytext; + argSharpCount=1; + BEGIN( CopyArgSharp ); + } +">" { + *copyArgString+=*yytext; + fullArgString+=*yytext; + //printf("end template list %s\n",copyArgString->data()); + stringToArgumentList(fullArgString,currentArgumentList); + BEGIN( currentArgumentContext ); + } +"(" { + argRoundCount++; + *copyArgString+=*yytext; + fullArgString+=*yytext; + } +")" { + *copyArgString+=*yytext; + fullArgString+=*yytext; + if (argRoundCount>0) + argRoundCount--; + else + BEGIN( lastCopyArgContext ); + } +"<" { + argSharpCount++; + //printf("argSharpCount++=%d copy\n",argSharpCount); + *copyArgString+=*yytext; + fullArgString+=*yytext; + } +">" { + *copyArgString+=*yytext; + fullArgString+=*yytext; + argSharpCount--; + if (argSharpCount>0) + { + //printf("argSharpCount--=%d copy\n",argSharpCount); + } + else + { + BEGIN( ReadTempArgs ); + //printf("end of argSharpCount\n"); + } + } +\\. { + *copyArgString+=yytext; + fullArgString+=yytext; + } +\" { + *copyArgString+=*yytext; + fullArgString+=*yytext; + BEGIN( lastCopyArgStringContext ); + } +\' { + *copyArgString+=*yytext; + fullArgString+=*yytext; + BEGIN( lastCopyArgStringContext ); + } +{CHARLIT} { + if (insidePHP) + { + REJECT; + } + else + { + *copyArgString+=yytext; + fullArgString+=yytext; + } + } +\' { + *copyArgString+=yytext; + fullArgString+=yytext; + if (insidePHP) + { + lastCopyArgStringContext=YY_START; + BEGIN(CopyArgPHPString); + } + } +\n { + yyLineNr++; + *copyArgString+=*yytext; + fullArgString+=*yytext; + } +. { + *copyArgString+=*yytext; + fullArgString+=*yytext; + } + + + + /*------------------------------------------------------------------------*/ + + +"(" { current->args += *yytext ; + ++roundCount ; + } +")" { current->args += *yytext ; + if ( roundCount ) + --roundCount ; + else + BEGIN( FuncQual ) ; + } + /* +"#" { if (insidePHP) + REJECT; + lastCPPContext = YY_START; + BEGIN(SkipCPP); + } + */ +[{:;,] { + if ( strcmp(yytext,";")==0 && + insidePHP && + !containsWord(current->type,"function") ) + { + current->reset(); + initEntry(); + BEGIN( FindMembers ); + } + else + { + unput(*yytext); BEGIN( Function ); + } + } +{BN}*"abstract"{BN}* { // pure virtual member function + lineCount() ; + current->virt = Pure; + current->args += " override "; + } +{BN}*"override"{BN}* { // overridden virtual member function + lineCount() ; + current->spec |= Entry::Override; + current->args += " override "; + } +{BN}*"sealed"{BN}* { // sealed member function + lineCount() ; + current->spec |= Entry::Sealed; + current->args += " sealed "; + } +{BN}*"new"{BN}* { // new member function + lineCount() ; + current->spec |= Entry::New; + current->args += " new "; + } +{BN}*"const"{BN}* { // const member function + lineCount() ; + current->args += " const "; + current->argList->constSpecifier=TRUE; + } +{BN}*"volatile"{BN}* { // volatile member function + lineCount() ; + current->args += " volatile "; + current->argList->volatileSpecifier=TRUE; + } +{BN}*"="{BN}*"0"{BN}* { // pure virtual member function + lineCount() ; + current->args += " = 0"; + current->virt = Pure; + current->argList->pureSpecifier=TRUE; + } +{BN}*","{BN}* { + lineCount() ; + current->args += ", " ; + } +{BN}+ { + lineCount() ; + current->args += ' ' ; + } +"#" { if (insidePHP) + REJECT; + lastCPPContext = YY_START; + BEGIN(SkipCPP); + } +"=" { + if (insideCli && + (current_root->section&Entry::COMPOUND_MASK) + ) + { + BEGIN(CliOverride); + } + else + { + // typically an initialized function pointer + lastInitializerContext=YY_START; + initBracketCount=0; + BEGIN(ReadInitializer); + } + } +{ID} { + } +"{" { + unput(*yytext); + BEGIN(FuncQual); + } +\n { + yyLineNr++; + } +. { + } +[{;] { + unput(*yytext); + BEGIN(FuncQual); + } +\" { + current->args += *yytext; + pCopyQuotedString=¤t->args; + lastStringContext=FuncPtrInit; + BEGIN(CopyString); + } +\' { + current->args += *yytext; + if (insidePHP) + { + pCopyQuotedString=¤t->args; + lastStringContext=FuncPtrInit; + BEGIN(CopyPHPString); + } + } +{CHARLIT} { + if (insidePHP) + { + REJECT; + } + else + { + current->args += yytext; + } + } +{ID} { + current->args += yytext; + } +. { + current->args += *yytext; + } +\n { + current->args += *yytext; + yyLineNr++; + } +{ID} { // typically a K&R style C function + if (insideCS && strcmp(yytext,"where")==0) + { + // type contraint for a method + delete current->typeConstr; + current->typeConstr = new ArgumentList; + current->typeConstr->append(new Argument); + lastCSConstraint = YY_START; + BEGIN( CSConstraintName ); + } + else if (checkForKnRstyleC()) + { + //fprintf(stderr,"===> got a K&R style function\n"); + current->args = yytext; + oldStyleArgType.resize(0); + BEGIN(OldStyleArgs); + } + else + { + current->args += yytext; + } + } +[,;] { + QCString oldStyleArgPtr; + QCString oldStyleArgName; + splitKnRArg(oldStyleArgPtr,oldStyleArgName); + QCString doc,brief; + if (current->doc!=docBackup) + { + doc=current->doc.copy(); + current->doc=docBackup; + } + if (current->brief!=briefBackup) + { + brief=current->brief.copy(); + current->brief=briefBackup; + } + addKnRArgInfo(oldStyleArgType+oldStyleArgPtr, + oldStyleArgName,brief,doc); + current->args.resize(0); + if (*yytext==';') oldStyleArgType.resize(0); + } +{ID} { current->args += yytext; } +"{" { + current->args = argListToString(current->argList); + unput('{'); + BEGIN(FuncQual); + } +. { current->args += *yytext; } +. { current->args += *yytext; } +{BN}*"try:" | +{BN}*"try"{BN}+ { /* try-function-block */ + insideTryBlock=TRUE; + lineCount(); + if (yytext[yyleng-1]==':') + { + unput(':'); + BEGIN( Function ); + } + } +{BN}*"throw"{BN}*"(" { // C++ style throw clause + current->exception = " throw (" ; + roundCount=0; + lineCount() ; + BEGIN( ExcpRound ) ; + } +{BN}*"raises"{BN}*"(" { + current->exception = " raises (" ; + lineCount() ; + roundCount=0; + BEGIN( ExcpRound ) ; + } +{BN}*"throws"{BN}+ { // Java style throw clause + current->exception = " throws " ; + lineCount() ; + BEGIN( ExcpList ); + } +"(" { current->exception += *yytext ; + ++roundCount ; + } +")" { current->exception += *yytext ; + if ( roundCount ) + --roundCount ; + else + BEGIN( FuncQual ) ; + } +. { + current->exception += *yytext; + } +"{" { + unput('{'); BEGIN( FuncQual ); + } +";" { + unput(';'); BEGIN( FuncQual ); + } +"\n" { + current->exception += ' '; + yyLineNr++; + } +. { + current->exception += *yytext; + } +"(" { current->type += current->name ; + current->name = current->args ; + current->args = yytext ; + roundCount=0; + BEGIN( FuncRound ) ; + } +":" { + if (!insidePHP) BEGIN(SkipInits); + } +[;{,] { + current->name=current->name.simplifyWhiteSpace(); + current->type=current->type.simplifyWhiteSpace(); + current->args=removeRedundantWhiteSpace(current->args); + // was: current->args.simplifyWhiteSpace(); + current->fileName = yyFileName; + current->startLine = yyLineNr; + static QRegExp re("([^)]*[*&][^)]*)"); // (...*...) + if (*yytext!=';' || (current_root->section&Entry::COMPOUND_MASK) ) + { + int tempArg=current->name.find('<'); + QCString tempName; + if (tempArg==-1) tempName=current->name; else tempName=current->name.left(tempArg); + if (!current->type.isEmpty() && + (current->type.find(re,0)!=-1 || current->type.left(8)=="typedef ")) + { + //printf("Scanner.l: found in class variable: `%s' `%s' `%s'\n", current->type.data(),current->name.data(),current->args.data()); + if (isTypedef && current->type.left(8)!="typedef ") + { + current->type.prepend("typedef "); + } + current->section = Entry::VARIABLE_SEC ; + } + else + { + //printf("Scanner.l: found in class function: `%s' `%s' `%s'\n", current->type.data(),current->name.data(),current->args.data()); + current->section = Entry::FUNCTION_SEC ; + current->proto = *yytext==';'; + } + } + else // a global function prototype or function variable + { + //printf("Scanner.l: prototype? type=`%s' name=`%s' args=`%s'\n",current->type.data(),current->name.data(),current->args.data()); + if (!current->type.isEmpty() && + (current->type.find(re,0)!=-1 || current->type.left(8)=="typedef ")) + { + if (isTypedef && current->type.left(8)!="typedef ") + { + current->type.prepend("typedef "); + } + //printf("Scanner.l: found function variable!\n"); + current->section = Entry::VARIABLE_SEC; + } + else + { + //printf("Scanner.l: found prototype\n"); + current->section = Entry::FUNCTION_SEC; + current->proto = TRUE; + } + } + //printf("Adding entry `%s'\n",current->name.data()); + if ( insidePHP) + { + if (findAndRemoveWord(current->type,"final")) + { + current->spec |= Entry::Final; + } + if (findAndRemoveWord(current->type,"abstract")) + { + current->spec |= Entry::Abstract; + } + } + if ( insidePHP && !containsWord(current->type,"function")) + { + initEntry(); + if ( *yytext == '{' ) + { + lastCurlyContext = FindMembers; + curlyCount=0; + BEGIN( SkipCurly ); + } + else + { + BEGIN( FindMembers ); + } + } + else + { + if ( insidePHP) + { + findAndRemoveWord(current->type,"function"); + } + previous = current; + current_root->addSubEntry(current); + current = new Entry ; + initEntry(); + // Objective C 2.0: Required/Optional section + if (previous->spec & (Entry::Optional | Entry::Required)) + { + current->spec |= previous->spec & (Entry::Optional|Entry::Required); + } + lastCurlyContext = FindMembers; + if ( *yytext == ',' ) + { + current->type = previous->type; + // we need to strip any trailing * and & (see bugs 623023 and 649103 for test cases) + int i=current->type.length(); + while (i>0 && (current->type[i-1]=='*' || current->type[i-1]=='&' || current->type[i-1]==' ')) i--; + current->type = current->type.left(i); + } + if ( *yytext == '{' ) + { + if ( !insidePHP && (current_root->section & Entry::COMPOUND_MASK) ) + { + previous->spec |= Entry::Inline; + } + //addToBody(yytext); + curlyCount=0; + BEGIN( SkipCurly ) ; + } + else + { + if (previous->section!=Entry::VARIABLE_SEC) + previous->bodyLine=-1; // a function/member declaration + BEGIN( FindMembers ) ; + } + } + } +"{" { + //addToBody(yytext); + //lastCurlyContext = FindMembers; + //curlyCount=0; + //BEGIN( SkipCurly ) ; + unput('{'); + BEGIN( Function ); + } +"{" { + //addToBody(yytext); + ++curlyCount ; + } +"}" { + //addToBody(yytext); + if( curlyCount ) + { + --curlyCount ; + } + else + { +#if 0 + if (!Config_getBool("HIDE_IN_BODY_DOCS") && + !current->doc.isEmpty()) + { + // copy documentation found inside the body + // to the previous item + if (previous->inbodyLine==-1) + { + previous->inbodyLine = current->docLine; + previous->inbodyFile = current->docFile; + } + //printf("*** inbodyDocs+=%s\n",current->doc.data()); + previous->inbodyDocs += current->doc; + current->doc.resize(0); + } +#endif + if (current->sli && previous) // copy special list items + { + QListIterator li(*current->sli); + ListItemInfo *lii; + for (li.toFirst();(lii=li.current());++li) + { + previous->addSpecialListItem(lii->type,lii->itemId); + } + delete current->sli; + current->sli = 0; + } + if (previous) previous->endBodyLine=yyLineNr; + BEGIN( lastCurlyContext ) ; + } + } +"}"{BN}*("/*!"|"/**"|"//!"|"///")"<" { + lineCount(); + if ( curlyCount ) + { + //addToBody(yytext); + --curlyCount ; + } + else + { + current->endBodyLine=yyLineNr; + + tempEntry = current; // temporarily switch to the previous entry + current = previous; + + docBlockContext = SkipCurlyEndDoc; + docBlockInBody = FALSE; + docBlockAutoBrief = ( yytext[yyleng-2]=='*' && Config_getBool("JAVADOC_AUTOBRIEF") ) || + ( yytext[yyleng-2]=='!' && Config_getBool("QT_AUTOBRIEF") ); + docBlock.resize(0); + docBlockTerm = '}'; + if (yytext[yyleng-3]=='/') + { + startCommentBlock(TRUE); + BEGIN( DocLine ); + } + else + { + startCommentBlock(FALSE); + BEGIN( DocBlock ); + } + } + } +"}"{BN}*("/*!"|"/**"|"//!"|"///")"<" { // desc is followed by another one + docBlockContext = SkipCurlyEndDoc; + docBlockInBody = FALSE; + docBlockAutoBrief = ( yytext[yyleng-2]=='*' && Config_getBool("JAVADOC_AUTOBRIEF") ) || + ( yytext[yyleng-2]=='!' && Config_getBool("QT_AUTOBRIEF") ); + docBlock.resize(0); + docBlockTerm = '}'; + if (yytext[yyleng-3]=='/') + { + startCommentBlock(TRUE); + BEGIN( DocLine ); + } + else + { + startCommentBlock(FALSE); + BEGIN( DocBlock ); + } + } +"}" { + //addToBody("}"); + current = tempEntry; + BEGIN( lastCurlyContext ); + } +\" { + //addToBody(yytext); + lastStringContext=SkipCurly; + BEGIN( SkipString ); + } +^{B}*"#" { + if (insidePHP) + REJECT; + //addToBody(yytext); + BEGIN( SkipCurlyCpp ); + } +\n { + yyLineNr++; + //addToBody(yytext); + } +"<<<" { + if (!insidePHP) + { + REJECT; + } + else + { + lastHereDocContext = YY_START; + BEGIN(HereDoc); + } + } +[^\n#"'@\\/{}<]+ { + //addToBody(yytext); + } +\n { + //addToBody(yytext); + yyLineNr++; + lastCurlyContext = FindMembers; + BEGIN( SkipCurly ); + } +\\[\r]*"\n"[\r]* { + //addToBody(yytext); + yyLineNr++; + } +"/*" { + //addToBody(yytext); + lastCContext = YY_START; + BEGIN(SkipComment); + } +"//" { + //addToBody(yytext); + lastCContext = YY_START; + BEGIN(SkipCxxComment); + } +\" { + lastStringContext=YY_START; + BEGIN( SkipString ); + } +; { + warn(yyFileName,yyLineNr, + "warning: Found ';' while parsing initializer list! " + "(doxygen could be confused by a macro call without semicolon)" + ); + BEGIN( FindMembers ); + } +"#" { + if (!insidePHP) + REJECT; + //addToBody(yytext); + lastCContext = YY_START; + BEGIN(SkipCxxComment); + } +@\" { + if (!insideCS) REJECT; + // C# verbatim string + lastSkipVerbStringContext=YY_START; + pSkipVerbString=¤t->initializer; + BEGIN(SkipVerbString); + } +{CHARLIT} { + if (insidePHP) REJECT; + } +\' { + if (insidePHP) + { + lastStringContext=YY_START; + BEGIN(SkipPHPString); + } + } +. { } +\\. { } +\" { + BEGIN( lastStringContext ); + } +\' { + BEGIN( lastStringContext ); + } +"/*"|"*/"|"//" { } +\n { + yyLineNr++; + } +. { } +":" { // for "class : public base {} var;" construct, see bug 608359 + unput(':'); + BEGIN(ClassVar); + } +";" { + current->section = Entry::EMPTY_SEC ; + current->type.resize(0) ; + current->name.resize(0) ; + current->args.resize(0) ; + current->argList->clear(); + BEGIN( FindMembers ) ; + } +{SCOPENAME}{BN}*/"<" { + sharpCount = 0; + current->name = yytext ; + if (current->spec & Entry::Protocol) + { + current->name+="-p"; + } + lineCount(); + lastClassTemplSpecContext = ClassVar; + if (insideObjC) // protocol list + { + BEGIN( ObjCProtocolList ); + } + else if (insideCS) // C# generic class + { + current->name+="-g"; + BEGIN( CSGeneric ); + } + else // C++ template specialization + { + roundCount=0; + BEGIN( ClassTemplSpec ); + } + } +"<" { + if (current->tArgLists==0) + { + current->tArgLists = new QList; + current->tArgLists->setAutoDelete(TRUE); + } + ArgumentList *al = new ArgumentList; + // check bug 612858 before enabling the next line + //current->spec |= Entry::Template; + current->tArgLists->append(al); + currentArgumentList = al; + templateStr="<"; + //current->name += "<"; + fullArgString = templateStr; + //copyArgString = ¤t->name; + copyArgString = &templateStr; + currentArgumentContext = ClassVar; + BEGIN( ReadTempArgs ); + } +"<" { + insideProtocolList=TRUE; + BEGIN( Bases ); + } +">"({BN}*"::"{BN}*{SCOPENAME})? { + current->name += yytext; + lineCount(); + if (--sharpCount<=0) + { + current->name = removeRedundantWhiteSpace(current->name); + if (current->spec & Entry::Protocol) + { // Objective-C protocol + unput('{'); // fake start of body + BEGIN( ClassVar ); + } + else + { + BEGIN( lastClassTemplSpecContext ); + } + } + } +"<" { + current->name += yytext; + sharpCount++; + } +. { + current->name += yytext; + } +{SCOPENAME}{BN}*";" { // forward declaration + unput(';'); + current->reset(); + initEntry(); + if (isTypedef) // typedef of a class, put typedef keyword back + { + current->type.prepend("typedef"); + } + BEGIN( FindMembers ); + } +{SCOPENAME}/"(" { + current->name = yytext ; + lineCount(); + if (current->spec & Entry::Protocol) + { + current->name += "-p"; + } + BEGIN( ClassVar ); + } +{SCOPENAME}/{BN}*"," { // multiple forward declarations on one line + // e.g. @protocol A,B; + current->reset(); + initEntry(); + } +{SCOPENAME} { + current->name = yytext ; + lineCount(); + if (current->spec & Entry::Protocol) + { + current->name += "-p"; + } + if ((current->spec & Entry::Protocol) || + current->section == Entry::OBJCIMPL_SEC) + { + unput('{'); // fake start of body + } + BEGIN( ClassVar ); + } +{CSSCOPENAME} { // C# style scope + current->name = substitute(yytext,".","::"); + lineCount(); + BEGIN( ClassVar ); + } +{SCOPENAME}{BN}*/"(" { + if (insideIDL && strncmp(yytext,"switch",6)==0 && !isId(yytext[6])) + { + // Corba IDL style union + roundCount=0; + BEGIN(SkipUnionSwitch); + } + else + { + addType(current); + current->name = yytext; + current->name = current->name.stripWhiteSpace(); + lineCount(); + BEGIN( FindMembers ); + } + } +"," { + if (isTypedef) + { + // multiple types in one typedef + unput(','); + current->type.prepend("typedef "); + BEGIN(FindMembers); + } + else + { + // Multiple class forward declaration + } + } +("sealed"|"abstract")/{BN}*(":"|"{") { + if (insideCli) + { + if (yytext[0]=='s') // sealed + current->spec |= Entry::SealedClass; + else // abstract + current->spec |= Entry::AbstractClass; + BEGIN( ClassVar ); + } + else + { + REJECT; + } + } +{ID} { + if (insideIDL && strcmp(yytext,"switch")==0) + { + // Corba IDL style union + roundCount=0; + BEGIN(SkipUnionSwitch); + } + else if ((insideJava || insidePHP || insideJS) && (strcmp(yytext,"implements")==0 || strcmp(yytext,"extends")==0)) + { + current->type.resize(0); + baseProt=Public; + baseVirt=Normal; + baseName.resize(0); + BEGIN( BasesProt ) ; + } + else if (insideCS && strcmp(yytext,"where")==0) // C# type contraint + { + delete current->typeConstr; + current->typeConstr = new ArgumentList; + current->typeConstr->append(new Argument); + lastCSConstraint = YY_START; + BEGIN( CSConstraintName ); + } + else if (insideCli && strcmp(yytext,"abstract")) + { + current->spec|=Entry::Abstract; + } + else if (insideCli && strcmp(yytext,"sealed")) + { + current->spec|=Entry::Sealed; + } + else + { + if (current->section == Entry::ENUM_SEC) + { // found "enum a b" -> variable + current->section = Entry::VARIABLE_SEC ; + } + current->type += ' ' ; + current->type += current->name ; + current->name = yytext ; + + if (nameIsOperator(current->name)) + { + BEGIN( Operator ); + } + } + } +[(\[] { + if (insideObjC && *yytext=='(') // class category + { + current->name+='('; + if (current->section!=Entry::OBJCIMPL_SEC) + { + current->spec|=Entry::Category; + } + BEGIN( ClassCategory ); + } + else + { + // probably a function anyway + unput(*yytext); + BEGIN( FindMembers ); + } + } +"/**/" { /* empty comment */ } +("/*"[*!]|"//"[/!])("<"?) { // special comment + fullArgString.resize(0); + lastCopyArgChar='#'; // end marker + lastCommentInArgContext=YY_START; + if (yytext[1]=='/') + BEGIN( CopyArgCommentLine ); + else + BEGIN( CopyArgComment ); + } +"#" { // artificially inserted token to signal end of comment block + current->typeConstr->last()->docs = fullArgString; + } +"{" { // end of type constraint reached + // parse documentation of the constraints + handleParametersCommentBlocks(current->typeConstr); + unput('{'); + BEGIN( lastCSConstraint ); + } +";" { + handleParametersCommentBlocks(current->typeConstr); + unput(';'); + BEGIN( lastCSConstraint ); + } +":" { + BEGIN( CSConstraintType ); + } +{ID} { + // parameter name + current->typeConstr->last()->name=yytext; + } +"where" { // another constraint for a different param + current->typeConstr->append(new Argument); + BEGIN( CSConstraintName ); + } +({ID}".")*{ID}("<"{ID}">")?("()")? { + if (current->typeConstr->last()->type.isEmpty()) + // first type constraint for this parameter + { + current->typeConstr->last()->type=yytext; + } + else // new type constraint for same parameter + { + QCString name = current->typeConstr->last()->name; + current->typeConstr->append(new Argument); + current->typeConstr->last()->name=name; + current->typeConstr->last()->type=yytext; + } + } +\n { + yyLineNr++; + } +. { + } +{ID} { + current->name+=yytext; + } +")" { + current->name+=')'; + if ((current->section & Entry::Protocol) || + current->section == Entry::OBJCIMPL_SEC) + { + unput('{'); // fake start of body + } + else // category has no variables so push back an empty body + { + unput('}'); + unput('{'); + } + BEGIN( ClassVar ); + } +":" { + if (current->section == Entry::VARIABLE_SEC) // enum a b:2, see bug 313527 + { + BEGIN(BitFields); + current->bitfields+=":"; + } + else + { + current->type.resize(0); + if ((current->spec & Entry::Interface) || + (current->spec & Entry::Struct) || + (current->spec & Entry::Ref) || + (current->spec & Entry::Value) || + insidePHP || insideCS || insideD || insideObjC + ) + baseProt=Public; + else + baseProt=Private; + baseVirt=Normal; + baseName.resize(0); + BEGIN( BasesProt ) ; + } + } +[;=*&] { + unput(*yytext); + if (isTypedef) // typedef of a class, put typedef keyword back + { + current->type.prepend("typedef"); + } + if ((yytext[0]=='*' || yytext[0]=='&') && + current->section == Entry::ENUM_SEC) + { // found "enum a *b" -> variable + current->section = Entry::VARIABLE_SEC ; + } + BEGIN( FindMembers ); + } +"///"/[^/] { + if (!insideObjC) + { + REJECT; + } + else + { + lineCount(); + current->program+=yytext; + current->fileName = yyFileName ; + current->startLine = yyLineNr ; + curlyCount=0; + BEGIN( ReadBodyIntf ); + } + } +("//"{B}*)?"/**"/[^/*] | +("//"{B}*)?"/*!" | +"//!" | +[\-+]{BN}* { + if (!insideObjC) + { + REJECT; + } + else + { + lineCount(); + current->program+=yytext; + current->fileName = yyFileName ; + current->startLine = yyLineNr ; + curlyCount=0; + BEGIN( ReadBodyIntf ); + } + } +{B}*"{"{B}* { + current->fileName = yyFileName ; + current->startLine = yyLineNr ; + current->name = removeRedundantWhiteSpace(current->name); + if (current->name.isEmpty() && !isTypedef) // anonymous compound + { + if (current->section==Entry::NAMESPACE_SEC) // allow reopening of anonymous namespaces + { + if (Config_getBool("EXTRACT_ANON_NSPACES")) // use visible name + { + current->name="anonymous_namespace{"+stripPath(current->fileName)+"}"; + } + else // use invisible name + { + current->name.sprintf("@%d",anonNSCount); + } + } + else + { + current->name.sprintf("@%d",anonCount++); + } + } + curlyCount=0; + if (current_root && // not a nested struct inside an @interface section + !(current_root->spec & Entry::Interface) && + ((current->spec & (Entry::Interface | Entry::Protocol | Entry::Category) || + current->section==Entry::OBJCIMPL_SEC) + ) && + insideObjC + ) + { // ObjC body that ends with @end + BEGIN( ReadBodyIntf ); + } + else if (current->section==Entry::NAMESPACE_SEC) + { // namespace body + BEGIN( ReadNSBody ); + } + else + { // class body + BEGIN( ReadBody ) ; + } + } +"virtual"{BN}+ { lineCount(); baseVirt = Virtual; } +"public"{BN}+ { lineCount(); baseProt = Public; } +"protected"{BN}+ { lineCount(); baseProt = Protected; } +"internal"{BN}+ { lineCount(); baseProt = Package; } +"private"{BN}+ { lineCount(); baseProt = Private; } +{BN} { lineCount(); } +. { unput(*yytext); BEGIN(Bases); } +("\\")?({ID}"\\")*{ID} { // PHP namespace token, not sure if interspacing is allowed but it gives problems (see bug 640847) + if (!insidePHP) + { + REJECT; + } + else // PHP base class of the form \Ns\Cl or Ns\Cl + { + lineCount(); + QCString bn=yytext; + bn = substitute(bn,"\\","::"); + baseName += bn; + current->args += ' '; + current->args += yytext; + } + } +("::")?{BN}*({ID}{BN}*"::"{BN}*)*{ID} { + lineCount(); + QCString baseScope = yytext; + if (insideCS && baseScope.stripWhiteSpace()=="where") + { + // type contraint for a class + delete current->typeConstr; + current->typeConstr = new ArgumentList; + current->typeConstr->append(new Argument); + lastCSConstraint = YY_START; + BEGIN( CSConstraintName ); + } + else + { + baseName+=yytext; + current->args += ' '; + current->args += yytext; + } + } +{BN}*{ID}("."{ID})* { // Java style class + QCString name = substitute(yytext,".","::"); + baseName += name; + current->args += ' '; + current->args += name; + } +\n/{BN}*[^{, \t\n] { + if (!insideObjC) + { + REJECT; + } + else + { + yyLineNr++; + unput('{'); + } + } +"@end" { // empty ObjC interface + unput('d'); // insert fake body: {}@end + unput('n'); + unput('e'); + unput('@'); + unput('}'); + unput('{'); + } +"<" { current->name += *yytext; + sharpCount=1; + roundCount=0; + lastSkipSharpContext = YY_START; + specName = ¤t->name; + BEGIN ( Specialization ); + } +"<" { + sharpCount=1; + roundCount=0; + lastSkipSharpContext = YY_START; + if (insideObjC) // start of protocol list + { + unput(','); + } + else // template specialization + { + //if (insideCS) // generic + //{ + // baseName+="-g"; + //} + templateStr = yytext; + specName = &templateStr; + BEGIN ( Specialization ); + } + } +"<" { *specName += *yytext; + if (roundCount==0) sharpCount++; + } +">" { + *specName += *yytext; + if (roundCount==0 && --sharpCount<=0) + { + if (1 /*!insideCS*/) + { + baseName+=*specName; + } + else + { + if (current->tArgLists==0) + { + current->tArgLists = new QList; + current->tArgLists->setAutoDelete(TRUE); + } + ArgumentList *al = new ArgumentList; + current->tArgLists->append(al); + stringToArgumentList(*specName,al); + } + BEGIN(lastSkipSharpContext); + } + } +{BN}+ { lineCount(); *specName +=' '; } +"<<" { *specName += yytext; } +">>"/{B}*"::" { // M$ C++ extension to allow >> to close a template... + unput('>'); + unput(' '); + unput('>'); + } +">>" { + if (insideCS) // for C# >> ends a nested template + { + REJECT; + } + else // for C++ >> is a bitshift + // operator and > > would end + // a nested template. + // We require the bitshift to be enclosed in braces. + // See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1757.html + { + if (roundCount>0) + { + *specName += yytext; + } + else + { + unput('>'); + unput(' '); + unput('>'); + } + } + } +"typename"{BN}+ { lineCount(); } +"(" { *specName += *yytext; roundCount++; } +")" { *specName += *yytext; roundCount--; } +. { + *specName += *yytext; + } +"<" { ++sharpCount; } +">" { if (--sharpCount<=0) + BEGIN ( lastSkipSharpContext ); + } +"(" { ++roundCount; } +")" { if (--roundCount<=0) + BEGIN ( lastSkipRoundContext ); + } +\" { + lastStringContext=SkipRound; + BEGIN(SkipString); + } +","|(">"({BN}*"{")?)|({BN}+"implements"{BN}*) { lineCount(); + if (insideProtocolList) + { + baseName+="-p"; + } + else + { + current->args += ',' ; + } + current->name = removeRedundantWhiteSpace(current->name); + if (!baseName.isEmpty()) + { + current->extends->append( + new BaseInfo(baseName,baseProt,baseVirt) + ); + } + if ((current->spec & (Entry::Interface|Entry::Struct)) || + insideJava || insidePHP || insideCS || + insideD || insideObjC) + { + baseProt=Public; + } + else + { + baseProt=Private; + } + baseVirt=Normal; + baseName.resize(0); + if (*yytext=='>') + { // end of a ObjC protocol list + insideProtocolList=FALSE; + if (yyleng==1) + { + unput('{'); // dummy start body + } + else + { + yyless(1); + } + } + else + { + if (*yytext==',' && insideObjC) // Begin of protocol list + { + insideProtocolList=TRUE; + } + BEGIN(BasesProt); + } + } +{B}*"{"{B}* { current->fileName = yyFileName ; + current->startLine = yyLineNr ; + current->name = removeRedundantWhiteSpace(current->name); + if (!baseName.isEmpty()) + current->extends->append( + new BaseInfo(baseName,baseProt,baseVirt) + ); + curlyCount=0; + if (insideObjC) + { + BEGIN( ReadBodyIntf ); + } + else + { + BEGIN( ReadBody ) ; + } + } +{B}*"(" { + roundCount++; + } +")" { + if (--roundCount==0) + { + BEGIN(ClassVar); + } + } +\n { yyLineNr++; } +. +{BN}+ { current->program += yytext ; + lineCount() ; + } +"/*" { current->program += yytext ; } +"//" { current->program += yytext ; } +{CMD}("code"|"verbatim") { + insideCode=TRUE; + current->program += yytext ; + } +{CMD}("endcode"|"endverbatim") { + insideCode=FALSE; + current->program += yytext ; + } +[^ \.\t\r\n\/\*]+ { current->program += yytext ; } +"*/" { current->program += yytext ; + if (!insideCode) BEGIN( lastContext ) ; + } +. { current->program += *yytext ; } + +("//"{B}*)?"/*!" { + //printf("Start doc block at %d\n",yyLineNr); + removeSlashes=(yytext[1]=='/'); + tmpDocType=-1; + if (!current->doc.isEmpty()) + { + current->doc+="\n\n"; + } + else + { + current->docLine = yyLineNr; + current->docFile = yyFileName; + } + + lastDocContext = YY_START; + if (current_root->section & Entry::SCOPE_MASK) + { + current->inside = current_root->name+"::"; + } + docBlockContext = YY_START; + docBlockInBody = YY_START==SkipCurly; + docBlockAutoBrief = Config_getBool("QT_AUTOBRIEF"); + docBlock.resize(0); + if (docBlockAutoBrief) + { + current->briefLine = yyLineNr; + current->briefFile = yyFileName; + } + startCommentBlock(FALSE); + BEGIN( DocBlock ); + } +("//"{B}*)?"/**"/[^/*] { + removeSlashes=(yytext[1]=='/'); + lastDocContext = YY_START; + + //printf("Found comment block at %s:%d\n",yyFileName,yyLineNr); + if (current_root->section & Entry::SCOPE_MASK) + { + current->inside = current_root->name+"::"; + } + current->docLine = yyLineNr; + current->docFile = yyFileName; + docBlockContext = YY_START; + docBlockInBody = YY_START==SkipCurly; + docBlockAutoBrief = Config_getBool("JAVADOC_AUTOBRIEF"); + docBlock.resize(0); + if (docBlockAutoBrief) + { + current->briefLine = yyLineNr; + current->briefFile = yyFileName; + } + startCommentBlock(FALSE); + BEGIN( DocBlock ); + } +"//!" { + tmpDocType=-1; + lastDocContext = YY_START; + if (current_root->section & Entry::SCOPE_MASK) + { + current->inside = current_root->name+"::"; + } + docBlockContext = YY_START; + docBlockInBody = YY_START==SkipCurly; + docBlockAutoBrief = FALSE; + docBlock.resize(0); + startCommentBlock(current->brief.isEmpty()); + BEGIN( DocLine ); + } +"///"/[^/] { + tmpDocType=-1; + lastDocContext = YY_START; + if (current_root->section & Entry::SCOPE_MASK) + { + current->inside = current_root->name+"::"; + } + docBlockContext = YY_START; + docBlockInBody = YY_START==SkipCurly; + docBlockAutoBrief = FALSE; + docBlock.resize(0); + startCommentBlock(current->brief.isEmpty()); + BEGIN( DocLine ); + } +"extern"{BN}*"\"C"("++")?"\""{BN}*("{")? { + lineCount(); + externC=TRUE; + } +"{" { + if (externC) + { + externC=FALSE; + } + else if (insideCS && + !current->name.isEmpty() && + !current->type.isEmpty()) + { + if (containsWord(current->type,"event")) // event + { + current->mtype = mtype = Event; + } + else // property + { + current->mtype = mtype = Property; + } + current->bodyLine = yyLineNr; + curlyCount=0; + BEGIN( CSAccessorDecl ); + } + else + { + if ((insideJava || insideCS || insideD) && + current->name.isEmpty() + ) + { + // static Java initializer + needsSemi = FALSE; + if (current->stat) + { + current->name="[static initializer]"; + current->type.resize(0); + } + else + { + current->name="[instance initializer]"; + } + unput(*yytext); + BEGIN( Function ); + } + else + { + needsSemi = TRUE; + current->type.resize(0); + current->name.resize(0); + current->args.resize(0); + current->argList->clear(); + curlyCount=0; + BEGIN( SkipCurlyBlock ); + } + } + } +"{" { curlyCount++; } +"}" { + if (curlyCount) + { + curlyCount--; + } + else + { + mtype = Method; + unput(';'); + BEGIN(FindMembers); + } + } +"set" { if (curlyCount==0) current->spec |= Entry::Settable; } +"get" { if (curlyCount==0) current->spec |= Entry::Gettable; } +"add" { if (curlyCount==0) current->spec |= Entry::Addable; } +"remove" { if (curlyCount==0) current->spec |= Entry::Removable; } +"raise" { if (curlyCount==0) current->spec |= Entry::Raisable; } +. {} +\n { yyLineNr++; } + + + + + /**********************************************************************************/ + /******************** Documentation block related rules ***************************/ + /**********************************************************************************/ + + /* ---- Single line comments ------ */ +[^\n]*"\n"[ \t]*"//"[/!] { // continuation of multiline C++-style comment + docBlock+=yytext; + docBlock.resize(docBlock.length() - 3); + yyLineNr++; + } +[^\n]*/"\n" { // whole line + docBlock+=yytext; + handleCommentBlock(docBlock.data(),current->brief.isEmpty()); + BEGIN( docBlockContext ); + } + + /* ---- Comments blocks ------ */ + +"*"*"*/" { // end of comment block + handleCommentBlock(docBlock.data(),FALSE); + BEGIN(docBlockContext); + } +^{B}*("//")?{B}*"*"+/[^//a-z_A-Z0-9*] { // start of a comment line + } +^{B}*("//"){B}* { // strip embedded C++ comments if at the start of a line + } +"//" { // slashes in the middle of a comment block + docBlock+=yytext; + } +"/*" { // start of a new comment in the + // middle of a comment block + docBlock+=yytext; + } +("@@"|"\\\\"){ID}/[^a-z_A-Z0-9] { // escaped command + docBlock+=yytext; + } +{CMD}("f$"|"f["|"f{") { + docBlock+=yytext; + docBlockName=&yytext[1]; + if (docBlockName.at(1)=='{') + { + docBlockName.at(1)='}'; + } + BEGIN(DocCopyBlock); + } +"<"{PRE}">" { + docBlock+=yytext; + docBlockName="

    ";
    +  					  BEGIN(DocCopyBlock);
    +  					}
    +{CMD}("verbatim"|"latexonly"|"htmlonly"|"xmlonly"|"manonly"|"dot"|"code")/[^a-z_A-Z0-9]	{ // verbatim command (which could contain nested comments!)
    +                                          docBlock+=yytext;
    +				          docBlockName=&yytext[1];
    +  					  BEGIN(DocCopyBlock);
    +  					}
    +{B}*""                  {
    +  					  if (insideCS)
    +					  {
    +					    docBlock+=yytext;
    +					    docBlockName="";
    +					    BEGIN(DocCopyBlock);
    +					  }
    +					  else
    +					  {
    +					    REJECT;
    +					  }
    +  					}
    +[^@*\/\\\n]+			{ // any character that isn't special
    +  					  docBlock+=yytext;
    +  					}
    +\n				{ // newline
    +  					  yyLineNr++;
    +					  docBlock+=*yytext;
    +  					}
    +.				{ // command block
    +					  docBlock+=*yytext;
    +  					}
    +
    + /* ---- Copy verbatim sections ------ */
    +
    +""		{ // end of a 
     block
    +  					  docBlock+=yytext;
    +					  if (docBlockName=="
    ")
    +					  {
    +  					    BEGIN(DocBlock);
    +					  }
    +  					}
    +""		{ // end of a  block
    +  					  docBlock+=yytext;
    +					  if (docBlockName=="")
    +					  {
    +  					    BEGIN(DocBlock);
    +					  }
    +  					}
    +[\\@]("f$"|"f]"|"f}")     {
    +  					  docBlock+=yytext;
    +					  BEGIN(DocBlock);
    +  					}
    +[\\@]("endverbatim"|"endlatexonly"|"endhtmlonly"|"endxmlonly"|"endmanonly"|"enddot"|"endcode")/[^a-z_A-Z0-9] { // end of verbatim block
    +  					  docBlock+=yytext;
    +					  if (&yytext[4]==docBlockName)
    +					  {
    +  					    BEGIN(DocBlock);
    +					  }
    +  					}
    +^{B}*"*"+/{BN}+		{ // start of a comment line
    +  					  if (docBlockName=="verbatim")
    +					  {
    +					    REJECT;
    +					  }
    +  					}
    +[^\<@/*\]\$\\\n]+		{ // any character that is not special
    +  					  docBlock+=yytext;
    +  					}
    +"/*"|"*/"|"//"		{
    +  					  docBlock+=yytext;
    +					}
    +\n			{ // newline
    +  					  docBlock+=*yytext;
    +					  yyLineNr++;
    +  					}
    +.				{ // any other character
    +  					  docBlock+=*yytext;
    +  					}
    +<>			{
    +  					  warn(yyFileName,yyLineNr,
    +					      "warning: reached end of file while inside a %s block!\n"
    +					      "The command that should end the block seems to be missing!\n",
    +					      docBlockName.data());
    +  					  yyterminate();
    +  					}
    +
    +
    +    /* ------------- Prototype parser -------------- */
    +
    +"operator"{B}*"("{B}*")"	{
    +  					  current->name+=yytext;
    +  					}
    +"("			       {
    +  					  current->args+=*yytext;
    +					  currentArgumentContext = PrototypeQual;
    +					  fullArgString = current->args.copy();
    +					  copyArgString = ¤t->args;
    +					  BEGIN( ReadFuncArgType ) ;
    +  					}
    +"("({ID}"::")*({B}*[&*])+	{
    +  					  current->type+=current->name+yytext;
    +					  current->name.resize(0);
    +  					  BEGIN( PrototypePtr );
    +  					}
    +{SCOPENAME}		{
    +  					  current->name+=yytext;
    +  					}
    +"("			{
    +  					  current->args+=*yytext;
    +					  currentArgumentContext = PrototypeQual;
    +					  fullArgString = current->args.copy();
    +					  copyArgString = ¤t->args;
    +					  BEGIN( ReadFuncArgType ) ;
    +  					}
    +")"			{
    +  					  current->type+=')';
    +  					  BEGIN( Prototype );
    +  					}
    +.				{
    +  					  current->name+=yytext;
    +  					}
    +"{"			{
    +  					  BEGIN( PrototypeSkipLine);
    +  					}
    +{B}*"const"{B}*    	{ 
    +  					  current->args += " const "; 
    +					  current->argList->constSpecifier=TRUE;
    +					}
    +{B}*"volatile"{B}* 	{ 
    +  					  current->args += " volatile "; 
    +					  current->argList->volatileSpecifier=TRUE;
    +					}
    +{B}*"="{B}*"0"{B}*	{ 
    +					  current->args += " = 0"; 
    +					  current->virt = Pure; 
    +					  current->argList->pureSpecifier=TRUE;
    +					}
    +"throw"{B}*"("	        {
    +  					  current->exception = "throw(";
    +					  BEGIN(PrototypeExc);
    +  					}
    +")"			{
    +  					  current->exception += ')';
    +					  BEGIN(PrototypeQual);
    +  					}
    +.			        {
    +  					  current->exception += *yytext;
    +  					}
    +.			{
    +  					  current->args += *yytext;
    +  					}
    +.	                        {
    +  					  current->name += *yytext;
    +  					}
    +.			{
    +  					}
    +
    +
    +  /* ------------ Generic rules -------------- */
    +
    +
    +.*"\\\n"		{  // line continuation
    +  					  if (insideCS) 
    +					  {
    +					    REJECT;
    +					  }
    +					  else 
    +					  {
    +					    yyLineNr++; 
    +					  }
    +  					}
    +.*/\n			{ 
    +					  BEGIN( lastCContext ) ;
    +					}
    +[^\*\n]+
    +<*>\n					{ yyLineNr++ ; }
    +<*>\"					{
    +					  if (insideIDL && insideCppQuote)
    +					  {
    +					    BEGIN(EndCppQuote);
    +					  }
    +					}
    +<*>"#"				        {	
    +  					  if (!insidePHP)
    +  					    REJECT;
    +  					  lastCContext = YY_START ;
    +					  BEGIN( SkipCxxComment ) ;
    +					}
    +<*>\'					{
    +  					  if (insidePHP)
    +					  {
    +  					    lastStringContext=YY_START;
    +					    BEGIN(SkipPHPString);
    +					  }
    +  					}
    +<*>\"					{
    +  					  if (insidePHP)
    +					  {
    +  					    lastStringContext=YY_START;
    +					    BEGIN(SkipString);
    +					  }
    +  					}
    +<*>.
    +"//"|"/*"
    +<*>"/*"					{ lastCContext = YY_START ;
    +					  BEGIN( SkipComment ) ;
    +					}
    +{B}*"*/"			{ BEGIN( lastCContext ) ; }
    +<*>"//"				        {	
    +  					  lastCContext = YY_START ;
    +					  BEGIN( SkipCxxComment ) ;
    +					}
    +%%
    +
    +//----------------------------------------------------------------------------
    +
    +static void startCommentBlock(bool brief)
    +{
    +  if (brief)
    +  {
    +    current->briefFile = yyFileName;
    +    current->briefLine = yyLineNr;
    +  }
    +  else
    +  {
    +    current->docFile = yyFileName;
    +    current->docLine = yyLineNr;
    +  }
    +}
    +  
    +//----------------------------------------------------------------------------
    +
    +static void newEntry()
    +{
    +  current_root->addSubEntry(current);
    +  previous = current;
    +  current = new Entry ;
    +  initEntry();
    +}
    +
    +static void handleCommentBlock(const QCString &doc,bool brief)
    +{
    +  static bool hideInBodyDocs = Config_getBool("HIDE_IN_BODY_DOCS");
    +  int position=0;
    +  bool needsEntry=FALSE;
    +  if (docBlockInBody && hideInBodyDocs) return;
    +  //printf("parseCommentBlock [%s] brief=%d\n",doc.data(),brief);
    +  int lineNr = brief ? current->briefLine : current->docLine;   // line of block start
    +  
    +  // fill in inbodyFile && inbodyLine the first time, see bug 633891
    +  Entry *docEntry = docBlockInBody && previous ? previous : current;
    +  if (docBlockInBody && docEntry && docEntry->inbodyLine==-1)
    +  {
    +    docEntry->inbodyFile = yyFileName;
    +    docEntry->inbodyLine = lineNr;
    +  }
    +
    +  while (parseCommentBlock(
    +	g_thisParser,
    +	docBlockInBody && previous ? previous : current,
    +	doc,        // text
    +	yyFileName, // file
    +	lineNr,     // line of block start
    +	docBlockInBody ? FALSE : brief,               // isBrief
    +	docBlockInBody ? FALSE : docBlockAutoBrief,   // isJavaDocStyle
    +	docBlockInBody,                               // isInBody
    +	protection,
    +        position,
    +        needsEntry
    +        )
    +     ) 
    +  {
    +    //printf("parseCommentBlock position=%d [%s]\n",position,doc.data()+position);
    +    if (needsEntry) 
    +    {
    +      QCString docFile = current->docFile;
    +      newEntry();
    +      current->docFile = docFile;
    +      current->docLine = lineNr;
    +    }
    +  }
    +  if (needsEntry)
    +  {
    +    newEntry();
    +  }
    +
    +  if (docBlockTerm)
    +  {
    +    unput(docBlockTerm);
    +    docBlockTerm=0;
    +  }
    +}
    +
    +static void handleParametersCommentBlocks(ArgumentList *al)
    +{
    +  //printf(">>>>>>> handleParametersCommentBlocks()\n");
    +  ArgumentListIterator ali(*al);
    +  Argument *a;
    +  for (ali.toFirst();(a=ali.current());++ali)
    +  {
    +    //printf("    Param %s docs=%s\n",a->name.data(),a->docs.data());
    +    if (!a->docs.isEmpty())
    +    {
    +      int position=0;
    +      bool needsEntry;
    +
    +      // save context
    +      QCString orgDoc   = current->doc;
    +      QCString orgBrief = current->brief;
    +      int orgDocLine    = current->docLine;
    +      int orgBriefLine  = current->briefLine;
    +
    +      current->doc.resize(0);
    +      current->brief.resize(0);
    +
    +      //printf("handleParametersCommentBlock [%s]\n",doc.data());
    +      while (parseCommentBlock(
    +	     g_thisParser,
    +	     current,
    +	     a->docs,            // text
    +	     yyFileName,         // file
    +	     current->docLine,   // line of block start
    +	     FALSE, 
    +	     FALSE,
    +	     FALSE,
    +	     protection,
    +	     position,
    +	     needsEntry
    +	    )
    +	  ) 
    +      {
    +	//printf("handleParametersCommentBlock position=%d [%s]\n",position,doc.data()+position);
    +	if (needsEntry) newEntry();
    +      }
    +      if (needsEntry)
    +      {
    +	newEntry();
    +      }
    +      a->docs = current->doc;
    +
    +      // restore context
    +      current->doc       = orgDoc;
    +      current->brief     = orgBrief;
    +      current->docLine   = orgDocLine;
    +      current->briefLine = orgBriefLine;
    +    }
    +  }
    +}
    +
    +
    +//----------------------------------------------------------------------------
    +
    +static void parseCompounds(Entry *rt)
    +{
    +  //printf("parseCompounds(%s)\n",rt->name.data());
    +  g_inputFromFile = FALSE;
    +  EntryListIterator eli(*rt->children());
    +  Entry *ce;
    +  for (;(ce=eli.current());++eli)
    +  {
    +    if (!ce->program.isEmpty())
    +    {
    +      //printf("-- %s ---------\n%s\n---------------\n",
    +      //  ce->name.data(),ce->program.data());
    +      // init scanner state
    +      padCount=0;
    +      //depthIf = 0;
    +      inputString = ce->program;
    +      inputPosition = 0;
    +      scanYYrestart( scanYYin ) ;
    +      if (ce->section==Entry::ENUM_SEC || (ce->spec&Entry::Enum))
    +	BEGIN( FindFields ) ;
    +      else
    +	BEGIN( FindMembers ) ;
    +      current_root = ce ;
    +      yyFileName = ce->fileName;
    +      //setContext();
    +      yyLineNr = ce->startLine ;
    +      insideObjC = ce->lang==SrcLangExt_ObjC;
    +      //printf("---> Inner block starts at line %d objC=%d\n",yyLineNr,insideObjC);
    +      //current->reset();
    +      if (current) delete current;
    +      current = new Entry;
    +      initEntry();
    +      gstat = FALSE;
    +      int ni=ce->name.findRev("::"); if (ni==-1) ni=0; else ni+=2;
    +      // set default protection based on the compound type
    +      if( ce->section==Entry::CLASS_SEC ) // class
    +      {
    +
    +        if (insidePHP || insideD || insideJS)
    +	{
    +          current->protection = protection = Public ; 
    +	}
    +	else if (insideJava)
    +	{
    +          current->protection = protection = (ce->spec & (Entry::Interface|Entry::Enum)) ?  Public : Package;
    +	}
    +	else if (ce->spec&(Entry::Interface | Entry::Ref | Entry::Value | Entry::Struct | Entry::Union))
    +	{
    +	  if (ce->lang==SrcLangExt_ObjC)
    +	  {
    +	    current->protection = protection = Protected ;
    +	  }
    +	  else
    +	  {
    +	    current->protection = protection = Public ;
    +	  }
    +	}
    +	else 
    +	{
    +          current->protection = protection = Private ;
    +	}
    +      }
    +      else if (ce->section == Entry::ENUM_SEC ) // enum
    +      {
    +	current->protection = protection = ce->protection;
    +      }
    +      else if (!ce->name.isEmpty() && ce->name.at(ni)=='@') // unnamed union or namespace
    +      {
    +	if (ce->section == Entry::NAMESPACE_SEC ) // unnamed namespace
    +	{
    +          current->stat = gstat = TRUE;
    +	}
    +	current->protection = protection = ce->protection;
    +      }
    +      else // named struct, union, protocol, category
    +      {
    +	current->protection = protection = Public ;
    +      }
    +      mtype = Method;
    +      virt = Normal;
    +      //printf("name=%s current->stat=%d gstat=%d\n",ce->name.data(),current->stat,gstat);
    +
    +      //memberGroupId = DOX_NOGROUP;
    +      //memberGroupRelates.resize(0);
    +      //memberGroupInside.resize(0);
    +      groupEnterCompound(yyFileName,yyLineNr,ce->name);
    +      
    +      scanYYlex() ;
    +      g_lexInit=TRUE;
    +      //forceEndGroup();
    +
    +      groupLeaveCompound(yyFileName,yyLineNr,ce->name);
    +      
    +      delete current; current=0;
    +      ce->program.resize(0);
    +
    +
    +      //if (depthIf>0)
    +      //{
    +      //	warn(yyFileName,yyLineNr,"Documentation block ended in the middle of a conditional section!");
    +      //}
    +    }
    +    parseCompounds(ce);
    +  }
    +}
    +
    +//----------------------------------------------------------------------------
    +
    +static void parseMain(const char *fileName,const char *fileBuf,Entry *rt)
    +{
    +  initParser();
    +  //g_inputFromFile = TRUE;
    +
    +  inputString = fileBuf;
    +  inputPosition = 0;
    +  g_inputFromFile = FALSE;
    +
    +  //anonCount     = 0;  // don't reset per file
    +  //depthIf       = 0;
    +  protection    = Public;
    +  mtype         = Method;
    +  gstat         = FALSE;
    +  virt          = Normal;
    +  current_root  = rt;
    +  global_root   = rt;
    +  inputFile.setName(fileName);
    +  if (inputFile.open(IO_ReadOnly))
    +  {
    +    yyLineNr= 1 ; 
    +    yyFileName = fileName;
    +    setContext();
    +    rt->lang = language;
    +    msg("Parsing file %s...\n",yyFileName.data());
    +
    +    current_root  = rt ;
    +    initParser();
    +    groupEnterFile(yyFileName,yyLineNr);
    +    current       = new Entry;
    +    //printf("current=%p current_root=%p\n",current,current_root);
    +    int sec=guessSection(yyFileName);
    +    if (sec)
    +    {
    +      current->name    = yyFileName;
    +      current->section = sec;
    +      current_root->addSubEntry(current);
    +      current          = new Entry;
    +    }
    +    current->reset();
    +    initEntry();
    +    scanYYrestart( scanYYin );
    +    if ( insidePHP )
    +    {
    +      BEGIN( FindMembersPHP );
    +    }
    +    else
    +    {
    +      BEGIN( FindMembers );
    +    }
    +
    +    scanYYlex();
    +    g_lexInit=TRUE;
    +
    +    if (YY_START==Comment)
    +    {
    +      warn(yyFileName,yyLineNr,"File ended in the middle of a comment block! Perhaps a missing \\endcode?");
    +    }
    +
    +    //forceEndGroup();
    +    groupLeaveFile(yyFileName,yyLineNr);
    +
    +    //if (depthIf>0)
    +    //{
    +    //  warn(yyFileName,yyLineNr,"Documentation block ended in the middle of a conditional section!");
    +    //}
    +
    +    rt->program.resize(0);
    +    if (rt->children()->contains(current)==0) 
    +      // it could be that current is already added as a child to rt, so we
    +      // only delete it if this is not the case. See bug 635317.
    +    {
    +      delete current; current=0;
    +    }
    +
    +    parseCompounds(rt);
    +
    +    inputFile.close();
    +
    +    anonNSCount++;
    +  }
    +}
    +
    +//----------------------------------------------------------------------------
    +
    +static void parsePrototype(const QCString &text)
    +{
    +  //printf("**** parsePrototype(%s) begin\n",text.data());
    +  if (text.isEmpty()) 
    +  {
    +    warn(yyFileName,yyLineNr,"Empty prototype found!");
    +    return;
    +  }
    +
    +  const char *orgInputString;
    +  int orgInputPosition;
    +  YY_BUFFER_STATE orgState;
    +  bool orgInputFromFile;
    +  
    +  // save scanner state
    +  orgState = YY_CURRENT_BUFFER;
    +  yy_switch_to_buffer(yy_create_buffer(scanYYin, YY_BUF_SIZE));
    +  orgInputString = inputString; 
    +  orgInputPosition = inputPosition;
    +  orgInputFromFile = g_inputFromFile;
    +
    +  // set new string
    +  inputString = text;
    +  inputPosition = 0;
    +  g_inputFromFile = FALSE;
    +  scanYYrestart( scanYYin );
    +  BEGIN(Prototype);
    +  scanYYlex();
    +  g_lexInit=TRUE;
    +
    +  current->name = current->name.stripWhiteSpace();
    +  if (current->section == Entry::MEMBERDOC_SEC && current->args.isEmpty())
    +    current->section = Entry::VARIABLEDOC_SEC;
    +
    +  // restore original scanner state
    +  YY_BUFFER_STATE tmpState = YY_CURRENT_BUFFER;
    +  yy_switch_to_buffer(orgState);
    +  yy_delete_buffer(tmpState);
    +  inputString = orgInputString; 
    +  inputPosition = orgInputPosition;
    +  g_inputFromFile = orgInputFromFile;
    +
    +  //printf("**** parsePrototype end\n");
    +}
    +
    +void scanFreeScanner()
    +{
    +#if defined(YY_FLEX_SUBMINOR_VERSION)
    +  if (g_lexInit)
    +  {
    +    scanYYlex_destroy();
    +  }
    +#endif
    +}
    +
    +//static void handleGroupStartCommand(const char *header)
    +//{
    +//  memberGroupHeader=header;
    +//  startGroupInDoc();
    +//}
    +//
    +//static void handleGroupEndCommand()
    +//{
    +//  endGroup();
    +//  previous=0;
    +//}
    +
    +//----------------------------------------------------------------------------
    +
    +void CLanguageScanner::parseInput(const char *fileName,const char *fileBuf,Entry *root)
    +{
    +  g_thisParser = this;
    +  ::parseMain(fileName,fileBuf,root);
    +}
    +
    +void CLanguageScanner::parseCode(CodeOutputInterface & codeOutIntf,
    +                   const char * scopeName,
    +                   const QCString & input,
    +                   bool isExampleBlock,
    +                   const char * exampleName,
    +                   FileDef * fileDef,
    +                   int startLine,
    +                   int endLine,
    +                   bool inlineFragment,
    +		   MemberDef *memberDef,
    +		   bool showLineNumbers
    +                  )
    +{
    +  ::parseCCode(codeOutIntf,scopeName,input,isExampleBlock,exampleName,
    +               fileDef,startLine,endLine,inlineFragment,memberDef,
    +	       showLineNumbers);
    +}
    +
    +bool CLanguageScanner::needsPreprocessing(const QCString &extension)
    +{
    +  QCString fe=extension.lower();
    +  return 
    +   !( fe==".java" || fe==".as"  || fe==".d"    || fe==".php" || 
    +      fe==".php4" || fe==".inc" || fe==".phtml" 
    +    );
    +}
    +
    +void CLanguageScanner::resetCodeParserState()
    +{
    +  ::resetCCodeParserState();
    +}
    +
    +void CLanguageScanner::parsePrototype(const char *text)
    +{
    +  ::parsePrototype(text);
    +}
    +
    +//----------------------------------------------------------------------------
    +
    +#if !defined(YY_FLEX_SUBMINOR_VERSION) 
    +//----------------------------------------------------------------------------
    +extern "C" { // some bogus code to keep the compiler happy
    +  void scannerYYdummy() { yy_flex_realloc(0,0); } 
    +}
    +#endif
    +
    diff --git a/trunk/src/search.css b/trunk/src/search.css
    new file mode 100644
    index 0000000..5e6b12f
    --- /dev/null
    +++ b/trunk/src/search.css
    @@ -0,0 +1,238 @@
    +/*---------------- Search Box */
    +
    +#FSearchBox {
    +    float: left;
    +}
    +
    +#MSearchBox {
    +    white-space : nowrap;
    +    position: absolute;
    +    float: none;
    +    display: inline;
    +    margin-top: 8px;
    +    right: 0px;
    +    width: 170px;
    +    z-index: 102;
    +    background-color: white;
    +}
    +
    +#MSearchBox .left
    +{
    +    display:block;
    +    position:absolute;
    +    left:10px;
    +    width:20px;
    +    height:19px;
    +    background:url('search_l.png') no-repeat;
    +    background-position:right;
    +}
    +
    +#MSearchSelect {
    +    display:block;
    +    position:absolute;
    +    width:20px;
    +    height:19px;
    +}
    +
    +.left #MSearchSelect {
    +    left:4px;
    +}
    +
    +.right #MSearchSelect {
    +    right:5px;
    +}
    +
    +#MSearchField {
    +    display:block;
    +    position:absolute;
    +    height:19px;
    +    background:url('search_m.png') repeat-x;
    +    border:none;
    +    width:116px;
    +    margin-left:20px;
    +    padding-left:4px;
    +    color: #909090;
    +    outline: none;
    +    font: 9pt Arial, Verdana, sans-serif;
    +}
    +
    +#FSearchBox #MSearchField {
    +    margin-left:15px;
    +}
    +
    +#MSearchBox .right {
    +    display:block;
    +    position:absolute;
    +    right:10px;
    +    top:0px;
    +    width:20px;
    +    height:19px;
    +    background:url('search_r.png') no-repeat;
    +    background-position:left;
    +}
    +
    +#MSearchClose {
    +    display: none;
    +    position: absolute;
    +    top: 4px;
    +    background : none;
    +    border: none;
    +    margin: 0px 4px 0px 0px;
    +    padding: 0px 0px;
    +    outline: none;
    +}
    +
    +.left #MSearchClose {
    +    left: 6px;
    +}
    +
    +.right #MSearchClose {
    +    right: 2px;
    +}
    +
    +.MSearchBoxActive #MSearchField {
    +    color: #000000;
    +}
    +
    +/*---------------- Search filter selection */
    +
    +#MSearchSelectWindow {
    +    display: none;
    +    position: absolute;
    +    left: 0; top: 0;
    +    border: 1px solid ##A0;
    +    background-color: ##FA;
    +    z-index: 1;
    +    padding-top: 4px;
    +    padding-bottom: 4px;
    +    -moz-border-radius: 4px;
    +    -webkit-border-top-left-radius: 4px;
    +    -webkit-border-top-right-radius: 4px;
    +    -webkit-border-bottom-left-radius: 4px;
    +    -webkit-border-bottom-right-radius: 4px;
    +    -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15);
    +}
    +
    +.SelectItem {
    +    font: 8pt Arial, Verdana, sans-serif;
    +    padding-left:  2px;
    +    padding-right: 12px;
    +    border: 0px;
    +}
    +
    +span.SelectionMark {
    +    margin-right: 4px;
    +    font-family: monospace;
    +    outline-style: none;
    +    text-decoration: none;
    +}
    +
    +a.SelectItem {
    +    display: block;
    +    outline-style: none;
    +    color: #000000; 
    +    text-decoration: none;
    +    padding-left:   6px;
    +    padding-right: 12px;
    +}
    +
    +a.SelectItem:focus,
    +a.SelectItem:active {
    +    color: #000000; 
    +    outline-style: none;
    +    text-decoration: none;
    +}
    +
    +a.SelectItem:hover {
    +    color: #FFFFFF;
    +    background-color: ##50;
    +    outline-style: none;
    +    text-decoration: none;
    +    cursor: pointer;
    +    display: block;
    +}
    +
    +/*---------------- Search results window */
    +
    +iframe#MSearchResults {
    +    width: 60ex;
    +    height: 15em;
    +}
    +
    +#MSearchResultsWindow {
    +    display: none;
    +    position: absolute;
    +    left: 0; top: 0;
    +    border: 1px solid #000;
    +    background-color: ##F0;
    +}
    +
    +/* ----------------------------------- */
    +
    +
    +#SRIndex {
    +    clear:both; 
    +    padding-bottom: 15px;
    +}
    +
    +.SREntry {
    +    font-size: 10pt;
    +    padding-left: 1ex;
    +}
    +
    +.SRPage .SREntry {
    +    font-size: 8pt;
    +    padding: 1px 5px;
    +}
    +
    +body.SRPage {
    +    margin: 5px 2px;
    +}
    +
    +.SRChildren {
    +    padding-left: 3ex; padding-bottom: .5em 
    +}
    +
    +.SRPage .SRChildren {
    +    display: none;
    +}
    +
    +.SRSymbol {
    +    font-weight: bold; 
    +    color: ##58;
    +    font-family: Arial, Verdana, sans-serif;
    +    text-decoration: none;
    +    outline: none;
    +}
    +
    +a.SRScope {
    +    display: block;
    +    color: ##58; 
    +    font-family: Arial, Verdana, sans-serif;
    +    text-decoration: none;
    +    outline: none;
    +}
    +
    +a.SRSymbol:focus, a.SRSymbol:active,
    +a.SRScope:focus, a.SRScope:active {
    +    text-decoration: underline;
    +}
    +
    +span.SRScope {
    +    padding-left: 4px;
    +}
    +
    +.SRPage .SRStatus {
    +    padding: 2px 5px;
    +    font-size: 8pt;
    +    font-style: italic;
    +}
    +
    +.SRResult {
    +    display: none;
    +}
    +
    +DIV.searchresults {
    +    margin-left: 10px;
    +    margin-right: 10px;
    +}
    diff --git a/trunk/src/search.js b/trunk/src/search.js
    new file mode 100644
    index 0000000..3ed3f90
    --- /dev/null
    +++ b/trunk/src/search.js
    @@ -0,0 +1,778 @@
    +function convertToId(search)
    +{
    +  var result = '';
    +  for (i=0;i do a search
    +    {
    +      this.Search();
    +    }
    +  }
    +
    +  this.OnSearchSelectKey = function(evt)
    +  {
    +    var e = (evt) ? evt : window.event; // for IE
    +    if (e.keyCode==40 && this.searchIndex0) // Up
    +    {
    +      this.searchIndex--;
    +      this.OnSelectItem(this.searchIndex);
    +    }
    +    else if (e.keyCode==13 || e.keyCode==27)
    +    {
    +      this.OnSelectItem(this.searchIndex);
    +      this.CloseSelectionWindow();
    +      this.DOMSearchField().focus();
    +    }
    +    return false;
    +  }
    +
    +  // --------- Actions
    +
    +  // Closes the results window.
    +  this.CloseResultsWindow = function()
    +  {
    +    this.DOMPopupSearchResultsWindow().style.display = 'none';
    +    this.DOMSearchClose().style.display = 'none';
    +    this.Activate(false);
    +  }
    +
    +  this.CloseSelectionWindow = function()
    +  {
    +    this.DOMSearchSelectWindow().style.display = 'none';
    +  }
    +
    +  // Performs a search.
    +  this.Search = function()
    +  {
    +    this.keyTimeout = 0;
    +
    +    // strip leading whitespace
    +    var searchValue = this.DOMSearchField().value.replace(/^ +/, "");
    +
    +    var code = searchValue.toLowerCase().charCodeAt(0);
    +    var hexCode;
    +    if (code<16) 
    +    {
    +      hexCode="0"+code.toString(16);
    +    }
    +    else 
    +    {
    +      hexCode=code.toString(16);
    +    }
    +
    +    var resultsPage;
    +    var resultsPageWithSearch;
    +    var hasResultsPage;
    +
    +    if (indexSectionsWithContent[this.searchIndex].charAt(code) == '1')
    +    {
    +       resultsPage = this.resultsPath + '/' + indexSectionNames[this.searchIndex] + '_' + hexCode + '.html';
    +       resultsPageWithSearch = resultsPage+'?'+escape(searchValue);
    +       hasResultsPage = true;
    +    }
    +    else // nothing available for this search term
    +    {
    +       resultsPage = this.resultsPath + '/nomatches.html';
    +       resultsPageWithSearch = resultsPage;
    +       hasResultsPage = false;
    +    }
    +
    +    window.frames.MSearchResults.location = resultsPageWithSearch;  
    +    var domPopupSearchResultsWindow = this.DOMPopupSearchResultsWindow();
    +
    +    if (domPopupSearchResultsWindow.style.display!='block')
    +    {
    +       var domSearchBox = this.DOMSearchBox();
    +       this.DOMSearchClose().style.display = 'inline';
    +       if (this.insideFrame)
    +       {
    +         var domPopupSearchResults = this.DOMPopupSearchResults();
    +         domPopupSearchResultsWindow.style.position = 'relative';
    +         domPopupSearchResultsWindow.style.display  = 'block';
    +         var width = document.body.clientWidth - 8; // the -8 is for IE :-(
    +         domPopupSearchResultsWindow.style.width    = width + 'px';
    +         domPopupSearchResults.style.width          = width + 'px';
    +       }
    +       else
    +       {
    +         var domPopupSearchResults = this.DOMPopupSearchResults();
    +         var left = getXPos(domSearchBox) + 150; // domSearchBox.offsetWidth;
    +         var top  = getYPos(domSearchBox) + 20;  // domSearchBox.offsetHeight + 1;
    +         domPopupSearchResultsWindow.style.display = 'block';
    +         left -= domPopupSearchResults.offsetWidth;
    +         domPopupSearchResultsWindow.style.top     = top  + 'px';
    +         domPopupSearchResultsWindow.style.left    = left + 'px';
    +       }
    +    }
    +
    +    this.lastSearchValue = searchValue;
    +    this.lastResultsPage = resultsPage;
    +  }
    +
    +  // -------- Activation Functions
    +
    +  // Activates or deactivates the search panel, resetting things to 
    +  // their default values if necessary. 
    +  this.Activate = function(isActive)
    +  {
    +    if (isActive || // open it
    +        this.DOMPopupSearchResultsWindow().style.display == 'block' 
    +       )
    +    {
    +      this.DOMSearchBox().className = 'MSearchBoxActive';
    +
    +      var searchField = this.DOMSearchField();
    +
    +      if (searchField.value == this.searchLabel) // clear "Search" term upon entry
    +      {  
    +        searchField.value = '';  
    +        this.searchActive = true;
    +      }
    +    }
    +    else if (!isActive) // directly remove the panel
    +    {
    +      this.DOMSearchBox().className = 'MSearchBoxInactive';
    +      this.DOMSearchField().value   = this.searchLabel;
    +      this.searchActive             = false;
    +      this.lastSearchValue          = ''
    +      this.lastResultsPage          = '';
    +    }
    +  }
    +}
    +
    +// -----------------------------------------------------------------------
    +
    +// The class that handles everything on the search results page.
    +function SearchResults(name)
    +{
    +    // The number of matches from the last run of .
    +    this.lastMatchCount = 0;
    +    this.lastKey = 0;
    +    this.repeatOn = false;
    +
    +    // Toggles the visibility of the passed element ID.
    +    this.FindChildElement = function(id)
    +    {
    +      var parentElement = document.getElementById(id);
    +      var element = parentElement.firstChild;
    +
    +      while (element && element!=parentElement)
    +      {
    +        if (element.nodeName == 'DIV' && element.className == 'SRChildren')
    +        {
    +          return element;
    +        }
    +
    +        if (element.nodeName == 'DIV' && element.hasChildNodes())
    +        {  
    +           element = element.firstChild;  
    +        }
    +        else if (element.nextSibling)
    +        {  
    +           element = element.nextSibling;  
    +        }
    +        else
    +        {
    +          do
    +          {
    +            element = element.parentNode;
    +          }
    +          while (element && element!=parentElement && !element.nextSibling);
    +
    +          if (element && element!=parentElement)
    +          {  
    +            element = element.nextSibling;  
    +          }
    +        }
    +      }
    +    }
    +
    +    this.Toggle = function(id)
    +    {
    +      var element = this.FindChildElement(id);
    +      if (element)
    +      {
    +        if (element.style.display == 'block')
    +        {
    +          element.style.display = 'none';
    +        }
    +        else
    +        {
    +          element.style.display = 'block';
    +        }
    +      }
    +    }
    +
    +    // Searches for the passed string.  If there is no parameter,
    +    // it takes it from the URL query.
    +    //
    +    // Always returns true, since other documents may try to call it
    +    // and that may or may not be possible.
    +    this.Search = function(search)
    +    {
    +      if (!search) // get search word from URL
    +      {
    +        search = window.location.search;
    +        search = search.substring(1);  // Remove the leading '?'
    +        search = unescape(search);
    +      }
    +
    +      search = search.replace(/^ +/, ""); // strip leading spaces
    +      search = search.replace(/ +$/, ""); // strip trailing spaces
    +      search = search.toLowerCase();
    +      search = convertToId(search);
    +
    +      var resultRows = document.getElementsByTagName("div");
    +      var matches = 0;
    +
    +      var i = 0;
    +      while (i < resultRows.length)
    +      {
    +        var row = resultRows.item(i);
    +        if (row.className == "SRResult")
    +        {
    +          var rowMatchName = row.id.toLowerCase();
    +          rowMatchName = rowMatchName.replace(/^sr\d*_/, ''); // strip 'sr123_'
    +
    +          if (search.length<=rowMatchName.length && 
    +             rowMatchName.substr(0, search.length)==search)
    +          {
    +            row.style.display = 'block';
    +            matches++;
    +          }
    +          else
    +          {
    +            row.style.display = 'none';
    +          }
    +        }
    +        i++;
    +      }
    +      document.getElementById("Searching").style.display='none';
    +      if (matches == 0) // no results
    +      {
    +        document.getElementById("NoMatches").style.display='block';
    +      }
    +      else // at least one result
    +      {
    +        document.getElementById("NoMatches").style.display='none';
    +      }
    +      this.lastMatchCount = matches;
    +      return true;
    +    }
    +
    +    // return the first item with index index or higher that is visible
    +    this.NavNext = function(index)
    +    {
    +      var focusItem;
    +      while (1)
    +      {
    +        var focusName = 'Item'+index;
    +        focusItem = document.getElementById(focusName);
    +        if (focusItem && focusItem.parentNode.parentNode.style.display=='block')
    +        {
    +          break;
    +        }
    +        else if (!focusItem) // last element
    +        {
    +          break;
    +        }
    +        focusItem=null;
    +        index++;
    +      }
    +      return focusItem;
    +    }
    +
    +    this.NavPrev = function(index)
    +    {
    +      var focusItem;
    +      while (1)
    +      {
    +        var focusName = 'Item'+index;
    +        focusItem = document.getElementById(focusName);
    +        if (focusItem && focusItem.parentNode.parentNode.style.display=='block')
    +        {
    +          break;
    +        }
    +        else if (!focusItem) // last element
    +        {
    +          break;
    +        }
    +        focusItem=null;
    +        index--;
    +      }
    +      return focusItem;
    +    }
    +
    +    this.ProcessKeys = function(e)
    +    {
    +      if (e.type == "keydown") 
    +      {
    +        this.repeatOn = false;
    +        this.lastKey = e.keyCode;
    +      }
    +      else if (e.type == "keypress")
    +      {
    +        if (!this.repeatOn)
    +        {
    +          if (this.lastKey) this.repeatOn = true;
    +          return false; // ignore first keypress after keydown
    +        }
    +      }
    +      else if (e.type == "keyup")
    +      {
    +        this.lastKey = 0;
    +        this.repeatOn = false;
    +      }
    +      return this.lastKey!=0;
    +    }
    +
    +    this.Nav = function(evt,itemIndex) 
    +    {
    +      var e  = (evt) ? evt : window.event; // for IE
    +      if (e.keyCode==13) return true;
    +      if (!this.ProcessKeys(e)) return false;
    +
    +      if (this.lastKey==38) // Up
    +      {
    +        var newIndex = itemIndex-1;
    +        var focusItem = this.NavPrev(newIndex);
    +        if (focusItem)
    +        {
    +          var child = this.FindChildElement(focusItem.parentNode.parentNode.id);
    +          if (child && child.style.display == 'block') // children visible
    +          { 
    +            var n=0;
    +            var tmpElem;
    +            while (1) // search for last child
    +            {
    +              tmpElem = document.getElementById('Item'+newIndex+'_c'+n);
    +              if (tmpElem)
    +              {
    +                focusItem = tmpElem;
    +              }
    +              else // found it!
    +              {
    +                break;
    +              }
    +              n++;
    +            }
    +          }
    +        }
    +        if (focusItem)
    +        {
    +          focusItem.focus();
    +        }
    +        else // return focus to search field
    +        {
    +           parent.document.getElementById("MSearchField").focus();
    +        }
    +      }
    +      else if (this.lastKey==40) // Down
    +      {
    +        var newIndex = itemIndex+1;
    +        var focusItem;
    +        var item = document.getElementById('Item'+itemIndex);
    +        var elem = this.FindChildElement(item.parentNode.parentNode.id);
    +        if (elem && elem.style.display == 'block') // children visible
    +        {
    +          focusItem = document.getElementById('Item'+itemIndex+'_c0');
    +        }
    +        if (!focusItem) focusItem = this.NavNext(newIndex);
    +        if (focusItem)  focusItem.focus();
    +      }
    +      else if (this.lastKey==39) // Right
    +      {
    +        var item = document.getElementById('Item'+itemIndex);
    +        var elem = this.FindChildElement(item.parentNode.parentNode.id);
    +        if (elem) elem.style.display = 'block';
    +      }
    +      else if (this.lastKey==37) // Left
    +      {
    +        var item = document.getElementById('Item'+itemIndex);
    +        var elem = this.FindChildElement(item.parentNode.parentNode.id);
    +        if (elem) elem.style.display = 'none';
    +      }
    +      else if (this.lastKey==27) // Escape
    +      {
    +        parent.searchBox.CloseResultsWindow();
    +        parent.document.getElementById("MSearchField").focus();
    +      }
    +      else if (this.lastKey==13) // Enter
    +      {
    +        return true;
    +      }
    +      return false;
    +    }
    +
    +    this.NavChild = function(evt,itemIndex,childIndex)
    +    {
    +      var e  = (evt) ? evt : window.event; // for IE
    +      if (e.keyCode==13) return true;
    +      if (!this.ProcessKeys(e)) return false;
    +
    +      if (this.lastKey==38) // Up
    +      {
    +        if (childIndex>0)
    +        {
    +          var newIndex = childIndex-1;
    +          document.getElementById('Item'+itemIndex+'_c'+newIndex).focus();
    +        }
    +        else // already at first child, jump to parent
    +        {
    +          document.getElementById('Item'+itemIndex).focus();
    +        }
    +      }
    +      else if (this.lastKey==40) // Down
    +      {
    +        var newIndex = childIndex+1;
    +        var elem = document.getElementById('Item'+itemIndex+'_c'+newIndex);
    +        if (!elem) // last child, jump to parent next parent
    +        {
    +          elem = this.NavNext(itemIndex+1);
    +        }
    +        if (elem)
    +        {
    +          elem.focus();
    +        } 
    +      }
    +      else if (this.lastKey==27) // Escape
    +      {
    +        parent.searchBox.CloseResultsWindow();
    +        parent.document.getElementById("MSearchField").focus();
    +      }
    +      else if (this.lastKey==13) // Enter
    +      {
    +        return true;
    +      }
    +      return false;
    +    }
    +}
    +
    +function setKeyActions(elem,action)
    +{
    +  elem.setAttribute('onkeydown',action);
    +  elem.setAttribute('onkeypress',action);
    +  elem.setAttribute('onkeyup',action);
    +}
    +
    +function setClassAttr(elem,attr)
    +{
    +  elem.setAttribute('class',attr);
    +  elem.setAttribute('className',attr);
    +}
    +
    +function createResults()
    +{
    +  var results = document.getElementById("SRResults");
    +  for (var e=0; e
    +require_once "search-config.php";
    +
    +function end_form($value)
    +{
    +  global $config;
    +  global $translator;
    +  if ($config['DISABLE_INDEX'] == false)
    +  {
    +  echo "            \n            \n          
    \n \n
  • \n \n \n\n"; + } + if ($config['GENERATE_TREEVIEW']) + { + echo $translator['split_bar']; + } +} + +function end_page() +{ + global $config; + global $translator; + if ($config['GENERATE_TREEVIEW']) + { + echo "\n
    \n
      \n
    • "; + echo $translator['logo']; + echo "
    • \n
    \n
    "; + } + echo ""; +} + +function search_results() +{ + global $translator; + return $translator['search_results_title']; +} + +function matches_text($num) +{ + global $translator; + $string = $translator['search_results'][($num>2)?2:$num]; + // The eval is used so that translator strings can contain $num. + eval("\$result = \"$string\";"); + return $result; +} + +function report_matches() +{ + global $translator; + return $translator['search_matches']; +} + +function readInt($file) +{ + $b1 = ord(fgetc($file)); $b2 = ord(fgetc($file)); + $b3 = ord(fgetc($file)); $b4 = ord(fgetc($file)); + return ($b1<<24)|($b2<<16)|($b3<<8)|$b4; +} + +function readString($file) +{ + $result=""; + while (ord($c=fgetc($file))) $result.=$c; + return $result; +} + +function readHeader($file) +{ + $header =fgetc($file); $header.=fgetc($file); + $header.=fgetc($file); $header.=fgetc($file); + return $header; +} + +function computeIndex($word) +{ + // Simple hashing that allows for substring search + if (strlen($word)<2) return -1; + // high char of the index + $hi = ord($word{0}); + if ($hi==0) return -1; + // low char of the index + $lo = ord($word{1}); + if ($lo==0) return -1; + // return index + return $hi*256+$lo; +} + +function search($file,$word,&$statsList) +{ + $index = computeIndex($word); + if ($index!=-1) // found a valid index + { + fseek($file,$index*4+4); // 4 bytes per entry, skip header + $index = readInt($file); + if ($index) // found words matching the hash key + { + $start=sizeof($statsList); + $count=$start; + fseek($file,$index); + $w = readString($file); + while ($w) + { + $statIdx = readInt($file); + if ($word==substr($w,0,strlen($word))) + { // found word that matches (as substring) + $statsList[$count++]=array( + "word"=>$word, + "match"=>$w, + "index"=>$statIdx, + "full"=>strlen($w)==strlen($word), + "docs"=>array() + ); + } + $w = readString($file); + } + $totalHi=0; + $totalFreqHi=0; + $totalFreqLo=0; + for ($count=$start;$count $idx, + "freq" => $freq>>1, + "rank" => 0.0, + "hi" => $freq&1 + ); + if ($freq&1) // word occurs in high priority doc + { + $totalHi++; + $totalFreqHi+=$freq*$multiplier; + } + else // word occurs in low priority doc + { + $totalFreqLo+=$freq*$multiplier; + } + } + // read name and url info for the doc + for ($i=0;$i<$numDocs;$i++) + { + fseek($file,$docInfo[$i]["idx"]); + $docInfo[$i]["name"]=readString($file); + $docInfo[$i]["url"]=readString($file); + } + $statInfo["docs"]=$docInfo; + } + $totalFreq=($totalHi+1)*$totalFreqLo + $totalFreqHi; + for ($count=$start;$count$key, + "name"=>$di["name"], + "rank"=>$rank + ); + } + $docs[$key]["words"][] = array( + "word"=>$wordInfo["word"], + "match"=>$wordInfo["match"], + "freq"=>$di["freq"] + ); + } + } + return $docs; +} + +function filter_results($docs,&$requiredWords,&$forbiddenWords) +{ + $filteredDocs=array(); + while (list ($key, $val) = each ($docs)) + { + $words = &$docs[$key]["words"]; + $copy=1; // copy entry by default + if (sizeof($requiredWords)>0) + { + foreach ($requiredWords as $reqWord) + { + $found=0; + foreach ($words as $wordInfo) + { + $found = $wordInfo["word"]==$reqWord; + if ($found) break; + } + if (!$found) + { + $copy=0; // document contains none of the required words + break; + } + } + } + if (sizeof($forbiddenWords)>0) + { + foreach ($words as $wordInfo) + { + if (in_array($wordInfo["word"],$forbiddenWords)) + { + $copy=0; // document contains a forbidden word + break; + } + } + } + if ($copy) $filteredDocs[$key]=$docs[$key]; + } + return $filteredDocs; +} + +function compare_rank($a,$b) +{ + if ($a["rank"] == $b["rank"]) + { + return 0; + } + return ($a["rank"]>$b["rank"]) ? -1 : 1; +} + +function sort_results($docs,&$sorted) +{ + $sorted = $docs; + usort($sorted,"compare_rank"); + return $sorted; +} + +function report_results(&$docs) +{ + echo "
    "; + echo "
    \n"; + echo "

    ".search_results()."

    \n"; + echo "
    \n"; + echo "
    \n"; + echo "
    \n"; + echo "\n"; + $numDocs = sizeof($docs); + if ($numDocs==0) + { + echo " \n"; + echo " \n"; + echo " \n"; + } + else + { + echo " \n"; + echo " \n"; + echo " \n"; + $num=1; + foreach ($docs as $doc) + { + echo " \n"; + echo " "; + echo "\n"; + echo " \n"; + echo " \n"; + echo " \n"; + $num++; + } + } + echo "
    ".matches_text(0)."
    ".matches_text($numDocs); + echo "\n"; + echo "
    $num.".$doc["name"]."
    ".report_matches()." "; + foreach ($doc["words"] as $wordInfo) + { + $word = $wordInfo["word"]; + $matchRight = substr($wordInfo["match"],strlen($word)); + echo "$word$matchRight(".$wordInfo["freq"].") "; + } + echo "
    \n"; + echo "
    \n"; +} + +function run_query($query) +{ + if(strcmp('4.1.0', phpversion()) > 0) + { + die("Error: PHP version 4.1.0 or above required!"); + } + if (!($file=fopen("search/search.idx","rb"))) + { + die("Error: Search index file could NOT be opened!"); + } + if (readHeader($file)!="DOXS") + { + die("Error: Header of index file is invalid!"); + } + $results = array(); + $requiredWords = array(); + $forbiddenWords = array(); + $foundWords = array(); + $word=strtok($query," "); + while ($word) // for each word in the search query + { + if (($word{0}=='+')) { $word=substr($word,1); $requiredWords[]=$word; } + if (($word{0}=='-')) { $word=substr($word,1); $forbiddenWords[]=$word; } + if (!in_array($word,$foundWords)) + { + $foundWords[]=$word; + search($file,strtolower($word),$results); + } + $word=strtok(" "); + } + fclose($file); + $docs = array(); + combine_results($results,$docs); + // filter out documents with forbidden word or that do not contain + // required words + $filteredDocs = filter_results($docs,$requiredWords,$forbiddenWords); + // sort the results based on rank + $sorted = array(); + sort_results($filteredDocs,$sorted); + return $sorted; +} + +function main() +{ + $query = ""; + if (array_key_exists("query", $_GET)) + { + $query=$_GET["query"]; + } + $sorted = run_query($query); + // Now output the HTML stuff... + // End the HTML form + end_form(preg_replace("/[^a-zA-Z0-9\-\_\.]/i", " ", $query )); + // report results to the user + report_results($sorted); + end_page(); +} + diff --git a/trunk/src/search_functions_php.h b/trunk/src/search_functions_php.h new file mode 100644 index 0000000..27c722c --- /dev/null +++ b/trunk/src/search_functions_php.h @@ -0,0 +1,374 @@ +"\n" diff --git a/trunk/src/search_js.h b/trunk/src/search_js.h new file mode 100644 index 0000000..985d03c --- /dev/null +++ b/trunk/src/search_js.h @@ -0,0 +1,778 @@ +"function convertToId(search)\n" +"{\n" +" var result = '';\n" +" for (i=0;i do a search\n" +" {\n" +" this.Search();\n" +" }\n" +" }\n" +"\n" +" this.OnSearchSelectKey = function(evt)\n" +" {\n" +" var e = (evt) ? evt : window.event; // for IE\n" +" if (e.keyCode==40 && this.searchIndex0) // Up\n" +" {\n" +" this.searchIndex--;\n" +" this.OnSelectItem(this.searchIndex);\n" +" }\n" +" else if (e.keyCode==13 || e.keyCode==27)\n" +" {\n" +" this.OnSelectItem(this.searchIndex);\n" +" this.CloseSelectionWindow();\n" +" this.DOMSearchField().focus();\n" +" }\n" +" return false;\n" +" }\n" +"\n" +" // --------- Actions\n" +"\n" +" // Closes the results window.\n" +" this.CloseResultsWindow = function()\n" +" {\n" +" this.DOMPopupSearchResultsWindow().style.display = 'none';\n" +" this.DOMSearchClose().style.display = 'none';\n" +" this.Activate(false);\n" +" }\n" +"\n" +" this.CloseSelectionWindow = function()\n" +" {\n" +" this.DOMSearchSelectWindow().style.display = 'none';\n" +" }\n" +"\n" +" // Performs a search.\n" +" this.Search = function()\n" +" {\n" +" this.keyTimeout = 0;\n" +"\n" +" // strip leading whitespace\n" +" var searchValue = this.DOMSearchField().value.replace(/^ +/, \"\");\n" +"\n" +" var code = searchValue.toLowerCase().charCodeAt(0);\n" +" var hexCode;\n" +" if (code<16) \n" +" {\n" +" hexCode=\"0\"+code.toString(16);\n" +" }\n" +" else \n" +" {\n" +" hexCode=code.toString(16);\n" +" }\n" +"\n" +" var resultsPage;\n" +" var resultsPageWithSearch;\n" +" var hasResultsPage;\n" +"\n" +" if (indexSectionsWithContent[this.searchIndex].charAt(code) == '1')\n" +" {\n" +" resultsPage = this.resultsPath + '/' + indexSectionNames[this.searchIndex] + '_' + hexCode + '.html';\n" +" resultsPageWithSearch = resultsPage+'?'+escape(searchValue);\n" +" hasResultsPage = true;\n" +" }\n" +" else // nothing available for this search term\n" +" {\n" +" resultsPage = this.resultsPath + '/nomatches.html';\n" +" resultsPageWithSearch = resultsPage;\n" +" hasResultsPage = false;\n" +" }\n" +"\n" +" window.frames.MSearchResults.location = resultsPageWithSearch; \n" +" var domPopupSearchResultsWindow = this.DOMPopupSearchResultsWindow();\n" +"\n" +" if (domPopupSearchResultsWindow.style.display!='block')\n" +" {\n" +" var domSearchBox = this.DOMSearchBox();\n" +" this.DOMSearchClose().style.display = 'inline';\n" +" if (this.insideFrame)\n" +" {\n" +" var domPopupSearchResults = this.DOMPopupSearchResults();\n" +" domPopupSearchResultsWindow.style.position = 'relative';\n" +" domPopupSearchResultsWindow.style.display = 'block';\n" +" var width = document.body.clientWidth - 8; // the -8 is for IE :-(\n" +" domPopupSearchResultsWindow.style.width = width + 'px';\n" +" domPopupSearchResults.style.width = width + 'px';\n" +" }\n" +" else\n" +" {\n" +" var domPopupSearchResults = this.DOMPopupSearchResults();\n" +" var left = getXPos(domSearchBox) + 150; // domSearchBox.offsetWidth;\n" +" var top = getYPos(domSearchBox) + 20; // domSearchBox.offsetHeight + 1;\n" +" domPopupSearchResultsWindow.style.display = 'block';\n" +" left -= domPopupSearchResults.offsetWidth;\n" +" domPopupSearchResultsWindow.style.top = top + 'px';\n" +" domPopupSearchResultsWindow.style.left = left + 'px';\n" +" }\n" +" }\n" +"\n" +" this.lastSearchValue = searchValue;\n" +" this.lastResultsPage = resultsPage;\n" +" }\n" +"\n" +" // -------- Activation Functions\n" +"\n" +" // Activates or deactivates the search panel, resetting things to \n" +" // their default values if necessary. \n" +" this.Activate = function(isActive)\n" +" {\n" +" if (isActive || // open it\n" +" this.DOMPopupSearchResultsWindow().style.display == 'block' \n" +" )\n" +" {\n" +" this.DOMSearchBox().className = 'MSearchBoxActive';\n" +"\n" +" var searchField = this.DOMSearchField();\n" +"\n" +" if (searchField.value == this.searchLabel) // clear \"Search\" term upon entry\n" +" { \n" +" searchField.value = ''; \n" +" this.searchActive = true;\n" +" }\n" +" }\n" +" else if (!isActive) // directly remove the panel\n" +" {\n" +" this.DOMSearchBox().className = 'MSearchBoxInactive';\n" +" this.DOMSearchField().value = this.searchLabel;\n" +" this.searchActive = false;\n" +" this.lastSearchValue = ''\n" +" this.lastResultsPage = '';\n" +" }\n" +" }\n" +"}\n" +"\n" +"// -----------------------------------------------------------------------\n" +"\n" +"// The class that handles everything on the search results page.\n" +"function SearchResults(name)\n" +"{\n" +" // The number of matches from the last run of .\n" +" this.lastMatchCount = 0;\n" +" this.lastKey = 0;\n" +" this.repeatOn = false;\n" +"\n" +" // Toggles the visibility of the passed element ID.\n" +" this.FindChildElement = function(id)\n" +" {\n" +" var parentElement = document.getElementById(id);\n" +" var element = parentElement.firstChild;\n" +"\n" +" while (element && element!=parentElement)\n" +" {\n" +" if (element.nodeName == 'DIV' && element.className == 'SRChildren')\n" +" {\n" +" return element;\n" +" }\n" +"\n" +" if (element.nodeName == 'DIV' && element.hasChildNodes())\n" +" { \n" +" element = element.firstChild; \n" +" }\n" +" else if (element.nextSibling)\n" +" { \n" +" element = element.nextSibling; \n" +" }\n" +" else\n" +" {\n" +" do\n" +" {\n" +" element = element.parentNode;\n" +" }\n" +" while (element && element!=parentElement && !element.nextSibling);\n" +"\n" +" if (element && element!=parentElement)\n" +" { \n" +" element = element.nextSibling; \n" +" }\n" +" }\n" +" }\n" +" }\n" +"\n" +" this.Toggle = function(id)\n" +" {\n" +" var element = this.FindChildElement(id);\n" +" if (element)\n" +" {\n" +" if (element.style.display == 'block')\n" +" {\n" +" element.style.display = 'none';\n" +" }\n" +" else\n" +" {\n" +" element.style.display = 'block';\n" +" }\n" +" }\n" +" }\n" +"\n" +" // Searches for the passed string. If there is no parameter,\n" +" // it takes it from the URL query.\n" +" //\n" +" // Always returns true, since other documents may try to call it\n" +" // and that may or may not be possible.\n" +" this.Search = function(search)\n" +" {\n" +" if (!search) // get search word from URL\n" +" {\n" +" search = window.location.search;\n" +" search = search.substring(1); // Remove the leading '?'\n" +" search = unescape(search);\n" +" }\n" +"\n" +" search = search.replace(/^ +/, \"\"); // strip leading spaces\n" +" search = search.replace(/ +$/, \"\"); // strip trailing spaces\n" +" search = search.toLowerCase();\n" +" search = convertToId(search);\n" +"\n" +" var resultRows = document.getElementsByTagName(\"div\");\n" +" var matches = 0;\n" +"\n" +" var i = 0;\n" +" while (i < resultRows.length)\n" +" {\n" +" var row = resultRows.item(i);\n" +" if (row.className == \"SRResult\")\n" +" {\n" +" var rowMatchName = row.id.toLowerCase();\n" +" rowMatchName = rowMatchName.replace(/^sr\\d*_/, ''); // strip 'sr123_'\n" +"\n" +" if (search.length<=rowMatchName.length && \n" +" rowMatchName.substr(0, search.length)==search)\n" +" {\n" +" row.style.display = 'block';\n" +" matches++;\n" +" }\n" +" else\n" +" {\n" +" row.style.display = 'none';\n" +" }\n" +" }\n" +" i++;\n" +" }\n" +" document.getElementById(\"Searching\").style.display='none';\n" +" if (matches == 0) // no results\n" +" {\n" +" document.getElementById(\"NoMatches\").style.display='block';\n" +" }\n" +" else // at least one result\n" +" {\n" +" document.getElementById(\"NoMatches\").style.display='none';\n" +" }\n" +" this.lastMatchCount = matches;\n" +" return true;\n" +" }\n" +"\n" +" // return the first item with index index or higher that is visible\n" +" this.NavNext = function(index)\n" +" {\n" +" var focusItem;\n" +" while (1)\n" +" {\n" +" var focusName = 'Item'+index;\n" +" focusItem = document.getElementById(focusName);\n" +" if (focusItem && focusItem.parentNode.parentNode.style.display=='block')\n" +" {\n" +" break;\n" +" }\n" +" else if (!focusItem) // last element\n" +" {\n" +" break;\n" +" }\n" +" focusItem=null;\n" +" index++;\n" +" }\n" +" return focusItem;\n" +" }\n" +"\n" +" this.NavPrev = function(index)\n" +" {\n" +" var focusItem;\n" +" while (1)\n" +" {\n" +" var focusName = 'Item'+index;\n" +" focusItem = document.getElementById(focusName);\n" +" if (focusItem && focusItem.parentNode.parentNode.style.display=='block')\n" +" {\n" +" break;\n" +" }\n" +" else if (!focusItem) // last element\n" +" {\n" +" break;\n" +" }\n" +" focusItem=null;\n" +" index--;\n" +" }\n" +" return focusItem;\n" +" }\n" +"\n" +" this.ProcessKeys = function(e)\n" +" {\n" +" if (e.type == \"keydown\") \n" +" {\n" +" this.repeatOn = false;\n" +" this.lastKey = e.keyCode;\n" +" }\n" +" else if (e.type == \"keypress\")\n" +" {\n" +" if (!this.repeatOn)\n" +" {\n" +" if (this.lastKey) this.repeatOn = true;\n" +" return false; // ignore first keypress after keydown\n" +" }\n" +" }\n" +" else if (e.type == \"keyup\")\n" +" {\n" +" this.lastKey = 0;\n" +" this.repeatOn = false;\n" +" }\n" +" return this.lastKey!=0;\n" +" }\n" +"\n" +" this.Nav = function(evt,itemIndex) \n" +" {\n" +" var e = (evt) ? evt : window.event; // for IE\n" +" if (e.keyCode==13) return true;\n" +" if (!this.ProcessKeys(e)) return false;\n" +"\n" +" if (this.lastKey==38) // Up\n" +" {\n" +" var newIndex = itemIndex-1;\n" +" var focusItem = this.NavPrev(newIndex);\n" +" if (focusItem)\n" +" {\n" +" var child = this.FindChildElement(focusItem.parentNode.parentNode.id);\n" +" if (child && child.style.display == 'block') // children visible\n" +" { \n" +" var n=0;\n" +" var tmpElem;\n" +" while (1) // search for last child\n" +" {\n" +" tmpElem = document.getElementById('Item'+newIndex+'_c'+n);\n" +" if (tmpElem)\n" +" {\n" +" focusItem = tmpElem;\n" +" }\n" +" else // found it!\n" +" {\n" +" break;\n" +" }\n" +" n++;\n" +" }\n" +" }\n" +" }\n" +" if (focusItem)\n" +" {\n" +" focusItem.focus();\n" +" }\n" +" else // return focus to search field\n" +" {\n" +" parent.document.getElementById(\"MSearchField\").focus();\n" +" }\n" +" }\n" +" else if (this.lastKey==40) // Down\n" +" {\n" +" var newIndex = itemIndex+1;\n" +" var focusItem;\n" +" var item = document.getElementById('Item'+itemIndex);\n" +" var elem = this.FindChildElement(item.parentNode.parentNode.id);\n" +" if (elem && elem.style.display == 'block') // children visible\n" +" {\n" +" focusItem = document.getElementById('Item'+itemIndex+'_c0');\n" +" }\n" +" if (!focusItem) focusItem = this.NavNext(newIndex);\n" +" if (focusItem) focusItem.focus();\n" +" }\n" +" else if (this.lastKey==39) // Right\n" +" {\n" +" var item = document.getElementById('Item'+itemIndex);\n" +" var elem = this.FindChildElement(item.parentNode.parentNode.id);\n" +" if (elem) elem.style.display = 'block';\n" +" }\n" +" else if (this.lastKey==37) // Left\n" +" {\n" +" var item = document.getElementById('Item'+itemIndex);\n" +" var elem = this.FindChildElement(item.parentNode.parentNode.id);\n" +" if (elem) elem.style.display = 'none';\n" +" }\n" +" else if (this.lastKey==27) // Escape\n" +" {\n" +" parent.searchBox.CloseResultsWindow();\n" +" parent.document.getElementById(\"MSearchField\").focus();\n" +" }\n" +" else if (this.lastKey==13) // Enter\n" +" {\n" +" return true;\n" +" }\n" +" return false;\n" +" }\n" +"\n" +" this.NavChild = function(evt,itemIndex,childIndex)\n" +" {\n" +" var e = (evt) ? evt : window.event; // for IE\n" +" if (e.keyCode==13) return true;\n" +" if (!this.ProcessKeys(e)) return false;\n" +"\n" +" if (this.lastKey==38) // Up\n" +" {\n" +" if (childIndex>0)\n" +" {\n" +" var newIndex = childIndex-1;\n" +" document.getElementById('Item'+itemIndex+'_c'+newIndex).focus();\n" +" }\n" +" else // already at first child, jump to parent\n" +" {\n" +" document.getElementById('Item'+itemIndex).focus();\n" +" }\n" +" }\n" +" else if (this.lastKey==40) // Down\n" +" {\n" +" var newIndex = childIndex+1;\n" +" var elem = document.getElementById('Item'+itemIndex+'_c'+newIndex);\n" +" if (!elem) // last child, jump to parent next parent\n" +" {\n" +" elem = this.NavNext(itemIndex+1);\n" +" }\n" +" if (elem)\n" +" {\n" +" elem.focus();\n" +" } \n" +" }\n" +" else if (this.lastKey==27) // Escape\n" +" {\n" +" parent.searchBox.CloseResultsWindow();\n" +" parent.document.getElementById(\"MSearchField\").focus();\n" +" }\n" +" else if (this.lastKey==13) // Enter\n" +" {\n" +" return true;\n" +" }\n" +" return false;\n" +" }\n" +"}\n" +"\n" +"function setKeyActions(elem,action)\n" +"{\n" +" elem.setAttribute('onkeydown',action);\n" +" elem.setAttribute('onkeypress',action);\n" +" elem.setAttribute('onkeyup',action);\n" +"}\n" +"\n" +"function setClassAttr(elem,attr)\n" +"{\n" +" elem.setAttribute('class',attr);\n" +" elem.setAttribute('className',attr);\n" +"}\n" +"\n" +"function createResults()\n" +"{\n" +" var results = document.getElementById(\"SRResults\");\n" +" for (var e=0; e +require "search-functions.php"; + +$mode = array_key_exists('v', $_GET)?$_GET['v']:""; +$query = array_key_exists('query', $_GET)?$_GET['query']:""; + +$query_results = run_query($query); + +switch ($mode) +{ + case "opensearch.xml": + opensearch_description(); + break; + case "json": + opensearch_json_results($query, $query_results); + break; + case "xml": + opensearch_xml_results($query, $query_results); + break; + default: + invalid_format($query, $query_results); + break; +} + +function opensearch_description() +{ + global $config; + global $translator; + + $shortname = $translator['search']." ".$config['PROJECT_NAME']; + $link = "http://".$_SERVER['HTTP_HOST'].dirname($_SERVER['SCRIPT_NAME']); + header("Content-Type: application/xml"); + echo << + +$shortname +Doxygen Search +UTF-8 + + + + + +END_OPENSEARCH; +} + +function opensearch_xml_results($query, array $results) +{ + // Much as I hate copy'n'paste code re-use, this is for testing; + // I expect a richer version to come soon. + // Although I hate that IE does this richer than FF more... + $qs_results = array(); + foreach ($results as $i => $val) + { + foreach ($val['words'] as $j => $word) + { + if (array_key_exists($word, $qs_results)) + $qs_results[$word['match']]++; + else + $qs_results[$word['match']] = 1; + } + } + $result = << + +$query +
    +END_FRAG; + foreach ($qs_results as $word => $count) + { + $result .= << +$word +$count results + +END_FRAG; + } + $result .= << + +END_FRAG; + echo $result; +} + +function opensearch_json_results($query, array $results) +{ + $qs_results = array(); + foreach ($results as $i => $val) + { + foreach ($val['words'] as $j => $word) + { + if (array_key_exists($word, $qs_results)) + $qs_results[$word['match']]++; + else + $qs_results[$word['match']] = 1; + } + } + $result = '["'.$query.'", ['; + $json_words = ""; + $json_descriptions = ""; + $i = 0; + foreach ($qs_results as $word => $count) + { + if ($i != 0) + { + $json_words .= ", "; + $json_descriptions .= ", "; + } + $json_words .= '"'.$word.'"'; + $json_descriptions .= '"'.$count.' result'.($count==1?'':'s').'"'; + $i++; + } + print "[\"$query\", [$json_words],[$json_descriptions]]"; +} + +function invalid_format($query, array $results) +{ + print "Search results for '$query':\n\n"; + print_r($results); +} + diff --git a/trunk/src/search_opensearch_php.h b/trunk/src/search_opensearch_php.h new file mode 100644 index 0000000..b1e9529 --- /dev/null +++ b/trunk/src/search_opensearch_php.h @@ -0,0 +1,127 @@ +"\n" diff --git a/trunk/src/searchindex.cpp b/trunk/src/searchindex.cpp new file mode 100644 index 0000000..6757711 --- /dev/null +++ b/trunk/src/searchindex.cpp @@ -0,0 +1,1084 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#include "qtbc.h" +#include "searchindex.h" +#include "config.h" +#include "util.h" +#include +#include +#include + + +// file format: (all multi-byte values are stored in big endian format) +// 4 byte header +// 256*256*4 byte index (4 bytes) +// for each index entry: a zero terminated list of words +// for each word: a \0 terminated string + 4 byte offset to the stats info +// padding bytes to align at 4 byte boundary +// for each word: the number of urls (4 bytes) +// + for each url containing the word 8 bytes statistics +// (4 bytes index to url string + 4 bytes frequency counter) +// for each url: a \0 terminated string + +const int numIndexEntries = 256*256; + +//-------------------------------------------------------------------- + +IndexWord::IndexWord(const char *word) : m_word(word), m_urls(17) +{ + m_urls.setAutoDelete(TRUE); + //printf("IndexWord::IndexWord(%s)\n",word); +} + +void IndexWord::addUrlIndex(int idx,bool hiPriority) +{ + //printf("IndexWord::addUrlIndex(%d,%d)\n",idx,hiPriority); + URLInfo *ui = m_urls.find(idx); + if (ui==0) + { + //printf("URLInfo::URLInfo(%d)\n",idx); + ui=new URLInfo(idx,0); + m_urls.insert(idx,ui); + } + ui->freq+=2; + if (hiPriority) ui->freq|=1; // mark as high priority document +} + +//-------------------------------------------------------------------- + +SearchIndex::SearchIndex() : m_words(328829), m_index(numIndexEntries), m_urlIndex(-1) +{ + int i; + m_words.setAutoDelete(TRUE); + m_urls.setAutoDelete(TRUE); + m_index.setAutoDelete(TRUE); + for (i=0;i); +} + +void SearchIndex::setCurrentDoc(const char *name,const char *baseName,const char *anchor) +{ + if (name==0 || baseName==0) return; + //printf("SearchIndex::setCurrentDoc(%s,%s,%s)\n",name,baseName,anchor); + QCString url=baseName+Config_getString("HTML_FILE_EXTENSION"); + if (anchor) url+=(QCString)"#"+anchor; + m_urlIndex++; + m_urls.insert(m_urlIndex,new URL(name,url)); +} + +static int charsToIndex(const char *word) +{ + if (word==0) return -1; + + // Fast string hashing algorithm + //register ushort h=0; + //const char *k = word; + //ushort mask=0xfc00; + //while ( *k ) + //{ + // h = (h&mask)^(h<<6)^(*k++); + //} + //return h; + + // Simple hashing that allows for substring searching + uint c1=word[0]; + if (c1==0) return -1; + uint c2=word[1]; + if (c2==0) return -1; + return c1*256+c2; +} + +void SearchIndex::addWord(const char *word,bool hiPriority,bool recurse) +{ + static QRegExp nextPart("[_a-z:][A-Z]"); + //printf("SearchIndex::addWord(%s,%d)\n",word,hiPriority); + QString wStr(word); + if (wStr.isEmpty()) return; + wStr=wStr.lower(); + IndexWord *w = m_words[wStr]; + if (w==0) + { + int idx=charsToIndex(wStr); + if (idx<0) return; + w = new IndexWord(wStr); + //fprintf(stderr,"addWord(%s) at index %d\n",word,idx); + m_index[idx]->append(w); + m_words.insert(wStr,w); + } + w->addUrlIndex(m_urlIndex,hiPriority); + int i; + bool found=FALSE; + if (!recurse) // the first time we check if we can strip the prefix + { + i=getPrefixIndex(word); + if (i>0) + { + addWord(word+i,hiPriority,TRUE); + found=TRUE; + } + } + if (!found) // no prefix stripped + { + if ((i=nextPart.match(word))>=1) + { + addWord(word+i+1,hiPriority,TRUE); + } + } +} + + +static void writeInt(QFile &f,int index) +{ + f.putch(((uint)index)>>24); + f.putch((((uint)index)>>16)&0xff); + f.putch((((uint)index)>>8)&0xff); + f.putch(((uint)index)&0xff); +} + +static void writeString(QFile &f,const char *s) +{ + const char *p = s; + while (*p) f.putch(*p++); + f.putch(0); +} + +void SearchIndex::write(const char *fileName) +{ + int i; + int size=4; // for the header + size+=4*numIndexEntries; // for the index + int wordsOffset = size; + // first pass: compute the size of the wordlist + for (i=0;i *wlist = m_index[i]; + if (!wlist->isEmpty()) + { + QListIterator iwi(*wlist); + IndexWord *iw; + for (iwi.toFirst();(iw=iwi.current());++iwi) + { + int ws = iw->word().length()+1; + size+=ws+4; // word + url info list offset + } + size+=1; // zero list terminator + } + } + + // second pass: compute the offsets in the index + int indexOffsets[numIndexEntries]; + int offset=wordsOffset; + for (i=0;i *wlist = m_index[i]; + if (!wlist->isEmpty()) + { + indexOffsets[i]=offset; + QListIterator iwi(*wlist); + IndexWord *iw; + for (iwi.toFirst();(iw=iwi.current());++iwi) + { + offset+= iw->word().length()+1; + offset+=4; // word + offset to url info array + } + offset+=1; // zero list terminator + } + else + { + indexOffsets[i]=0; + } + } + int padding = size; + size = (size+3)&~3; // round up to 4 byte boundary + padding = size - padding; + + //int statsOffset = size; + QDictIterator wdi(m_words); + //IndexWord *iw; + int *wordStatOffsets = new int[m_words.count()]; + + int count=0; + + // third pass: compute offset to stats info for each word + for (i=0;i *wlist = m_index[i]; + if (!wlist->isEmpty()) + { + QListIterator iwi(*wlist); + IndexWord *iw; + for (iwi.toFirst();(iw=iwi.current());++iwi) + { + //printf("wordStatOffsets[%d]=%d\n",count,size); + wordStatOffsets[count++] = size; + size+=4+iw->urls().count()*8; // count + (url_index,freq) per url + } + } + } + int *urlOffsets = new int[m_urls.count()]; + //int urlsOffset = size; + QIntDictIterator udi(m_urls); + URL *url; + for (udi.toFirst();(url=udi.current());++udi) + { + urlOffsets[udi.currentKey()]=size; + size+=url->name.length()+1+ + url->url.length()+1; + } + //printf("Total size %x bytes (word=%x stats=%x urls=%x)\n",size,wordsOffset,statsOffset,urlsOffset); + QFile f(fileName); + if (f.open(IO_WriteOnly)) + { + // write header + f.putch('D'); f.putch('O'); f.putch('X'); f.putch('S'); + // write index + for (i=0;i *wlist = m_index[i]; + if (!wlist->isEmpty()) + { + QListIterator iwi(*wlist); + IndexWord *iw; + for (iwi.toFirst();(iw=iwi.current());++iwi) + { + writeString(f,iw->word()); + writeInt(f,wordStatOffsets[count++]); + } + f.putch(0); + } + } + // write extra padding bytes + for (i=0;i *wlist = m_index[i]; + if (!wlist->isEmpty()) + { + QListIterator iwi(*wlist); + IndexWord *iw; + for (iwi.toFirst();(iw=iwi.current());++iwi) + { + int numUrls = iw->urls().count(); + writeInt(f,numUrls); + QIntDictIterator uli(iw->urls()); + URLInfo *ui; + for (uli.toFirst();(ui=uli.current());++uli) + { + writeInt(f,urlOffsets[ui->urlIdx]); + writeInt(f,ui->freq); + } + } + } + } + // write urls + QIntDictIterator udi(m_urls); + URL *url; + for (udi.toFirst();(url=udi.current());++udi) + { + writeString(f,url->name); + writeString(f,url->url); + } + } + + delete[] urlOffsets; + delete[] wordStatOffsets; +} + +//--------------------------------------------------------------------------- +// the following part is for the javascript based search engine + +#include "memberdef.h" +#include "namespacedef.h" +#include "pagedef.h" +#include "classdef.h" +#include "filedef.h" +#include "language.h" +#include "doxygen.h" +#include "message.h" + +static const char search_script[]= +#include "search_js.h" +; + +#define MEMBER_INDEX_ENTRIES 256 + +#define NUM_SEARCH_INDICES 15 +#define SEARCH_INDEX_ALL 0 +#define SEARCH_INDEX_CLASSES 1 +#define SEARCH_INDEX_NAMESPACES 2 +#define SEARCH_INDEX_FILES 3 +#define SEARCH_INDEX_FUNCTIONS 4 +#define SEARCH_INDEX_VARIABLES 5 +#define SEARCH_INDEX_TYPEDEFS 6 +#define SEARCH_INDEX_ENUMS 7 +#define SEARCH_INDEX_ENUMVALUES 8 +#define SEARCH_INDEX_PROPERTIES 9 +#define SEARCH_INDEX_EVENTS 10 +#define SEARCH_INDEX_RELATED 11 +#define SEARCH_INDEX_DEFINES 12 +#define SEARCH_INDEX_GROUPS 13 +#define SEARCH_INDEX_PAGES 14 + +class SearchIndexList : public SDict< QList > +{ + public: + SearchIndexList(int size=17) : SDict< QList >(size,FALSE) + { + setAutoDelete(TRUE); + } + ~SearchIndexList() {} + void append(Definition *d) + { + QList *l = find(d->name()); + if (l==0) + { + l=new QList; + SDict< QList >::append(d->name(),l); + } + l->append(d); + } + int compareItems(GCI item1, GCI item2) + { + QList *md1=(QList *)item1; + QList *md2=(QList *)item2; + QCString n1 = md1->first()->localName(); + QCString n2 = md2->first()->localName(); + return stricmp(n1.data(),n2.data()); + } +}; + +static void addMemberToSearchIndex( + SearchIndexList symbols[NUM_SEARCH_INDICES][MEMBER_INDEX_ENTRIES], + int symbolCount[NUM_SEARCH_INDICES], + MemberDef *md) +{ + static bool hideFriendCompounds = Config_getBool("HIDE_FRIEND_COMPOUNDS"); + bool isLinkable = md->isLinkable(); + ClassDef *cd=0; + NamespaceDef *nd=0; + FileDef *fd=0; + GroupDef *gd=0; + if (isLinkable && + ( + ((cd=md->getClassDef()) && cd->isLinkable() && cd->templateMaster()==0) || + ((gd=md->getGroupDef()) && gd->isLinkable()) + ) + ) + { + QCString n = md->name(); + uchar charCode = (uchar)n.at(0); + uint letter = charCode<128 ? tolower(charCode) : charCode; + if (!n.isEmpty()) + { + bool isFriendToHide = hideFriendCompounds && + (QCString(md->typeString())=="friend class" || + QCString(md->typeString())=="friend struct" || + QCString(md->typeString())=="friend union"); + if (!(md->isFriend() && isFriendToHide)) + { + symbols[SEARCH_INDEX_ALL][letter].append(md); + symbolCount[SEARCH_INDEX_ALL]++; + } + if (md->isFunction() || md->isSlot() || md->isSignal()) + { + symbols[SEARCH_INDEX_FUNCTIONS][letter].append(md); + symbolCount[SEARCH_INDEX_FUNCTIONS]++; + } + else if (md->isVariable()) + { + symbols[SEARCH_INDEX_VARIABLES][letter].append(md); + symbolCount[SEARCH_INDEX_VARIABLES]++; + } + else if (md->isTypedef()) + { + symbols[SEARCH_INDEX_TYPEDEFS][letter].append(md); + symbolCount[SEARCH_INDEX_TYPEDEFS]++; + } + else if (md->isEnumerate()) + { + symbols[SEARCH_INDEX_ENUMS][letter].append(md); + symbolCount[SEARCH_INDEX_ENUMS]++; + } + else if (md->isEnumValue()) + { + symbols[SEARCH_INDEX_ENUMVALUES][letter].append(md); + symbolCount[SEARCH_INDEX_ENUMVALUES]++; + } + else if (md->isProperty()) + { + symbols[SEARCH_INDEX_PROPERTIES][letter].append(md); + symbolCount[SEARCH_INDEX_PROPERTIES]++; + } + else if (md->isEvent()) + { + symbols[SEARCH_INDEX_EVENTS][letter].append(md); + symbolCount[SEARCH_INDEX_EVENTS]++; + } + else if (md->isRelated() || md->isForeign() || + (md->isFriend() && !isFriendToHide)) + { + symbols[SEARCH_INDEX_RELATED][letter].append(md); + symbolCount[SEARCH_INDEX_RELATED]++; + } + } + } + else if (isLinkable && + (((nd=md->getNamespaceDef()) && nd->isLinkable()) || + ((fd=md->getFileDef()) && fd->isLinkable()) + ) + ) + { + QCString n = md->name(); + uchar charCode = (uchar)n.at(0); + uint letter = charCode<128 ? tolower(charCode) : charCode; + if (!n.isEmpty()) + { + symbols[SEARCH_INDEX_ALL][letter].append(md); + symbolCount[SEARCH_INDEX_ALL]++; + + if (md->isFunction()) + { + symbols[SEARCH_INDEX_FUNCTIONS][letter].append(md); + symbolCount[SEARCH_INDEX_FUNCTIONS]++; + } + else if (md->isVariable()) + { + symbols[SEARCH_INDEX_VARIABLES][letter].append(md); + symbolCount[SEARCH_INDEX_VARIABLES]++; + } + else if (md->isTypedef()) + { + symbols[SEARCH_INDEX_TYPEDEFS][letter].append(md); + symbolCount[SEARCH_INDEX_TYPEDEFS]++; + } + else if (md->isEnumerate()) + { + symbols[SEARCH_INDEX_ENUMS][letter].append(md); + symbolCount[SEARCH_INDEX_ENUMS]++; + } + else if (md->isEnumValue()) + { + symbols[SEARCH_INDEX_ENUMVALUES][letter].append(md); + symbolCount[SEARCH_INDEX_ENUMVALUES]++; + } + else if (md->isDefine()) + { + symbols[SEARCH_INDEX_DEFINES][letter].append(md); + symbolCount[SEARCH_INDEX_DEFINES]++; + } + } + } +} + +static QCString searchId(const QCString &s) +{ + int c; + uint i; + QCString result; + for (i=0;i='0' && c<='9') || (c>='A' && c<='Z') || (c>='a' && c<='z')) + { + result+=(char)tolower(c); + } + else + { + char val[4]; + sprintf(val,"_%02x",(uchar)c); + result+=val; + } + } + return result; +} + +static int g_searchIndexCount[NUM_SEARCH_INDICES]; +static SearchIndexList g_searchIndexSymbols[NUM_SEARCH_INDICES][MEMBER_INDEX_ENTRIES]; +static const char *g_searchIndexName[NUM_SEARCH_INDICES] = +{ + "all", + "classes", + "namespaces", + "files", + "functions", + "variables", + "typedefs", + "enums", + "enumvalues", + "properties", + "events", + "related", + "defines", + "groups", + "pages" +}; + + +class SearchIndexCategoryMapping +{ + public: + SearchIndexCategoryMapping() + { + categoryLabel[SEARCH_INDEX_ALL] = theTranslator->trAll(); + categoryLabel[SEARCH_INDEX_CLASSES] = theTranslator->trClasses(); + categoryLabel[SEARCH_INDEX_NAMESPACES] = theTranslator->trNamespace(TRUE,FALSE); + categoryLabel[SEARCH_INDEX_FILES] = theTranslator->trFile(TRUE,FALSE); + categoryLabel[SEARCH_INDEX_FUNCTIONS] = theTranslator->trFunctions(); + categoryLabel[SEARCH_INDEX_VARIABLES] = theTranslator->trVariables(); + categoryLabel[SEARCH_INDEX_TYPEDEFS] = theTranslator->trTypedefs(); + categoryLabel[SEARCH_INDEX_ENUMS] = theTranslator->trEnumerations(); + categoryLabel[SEARCH_INDEX_ENUMVALUES] = theTranslator->trEnumerationValues(); + categoryLabel[SEARCH_INDEX_PROPERTIES] = theTranslator->trProperties(); + categoryLabel[SEARCH_INDEX_EVENTS] = theTranslator->trEvents(); + categoryLabel[SEARCH_INDEX_RELATED] = theTranslator->trFriends(); + categoryLabel[SEARCH_INDEX_DEFINES] = theTranslator->trDefines(); + categoryLabel[SEARCH_INDEX_GROUPS] = theTranslator->trGroup(TRUE,FALSE); + categoryLabel[SEARCH_INDEX_PAGES] = theTranslator->trPage(TRUE,FALSE); + } + QCString categoryLabel[NUM_SEARCH_INDICES]; +}; + +void writeJavascriptSearchIndex() +{ + if (!Config_getBool("GENERATE_HTML")) return; + + // index classes + ClassSDict::Iterator cli(*Doxygen::classSDict); + ClassDef *cd; + for (;(cd=cli.current());++cli) + { + uchar charCode = (uchar)cd->localName().at(0); + uint letter = charCode<128 ? tolower(charCode) : charCode; + if (cd->isLinkable() && isId(letter)) + { + g_searchIndexSymbols[SEARCH_INDEX_ALL][letter].append(cd); + g_searchIndexSymbols[SEARCH_INDEX_CLASSES][letter].append(cd); + g_searchIndexCount[SEARCH_INDEX_ALL]++; + g_searchIndexCount[SEARCH_INDEX_CLASSES]++; + } + } + + // index namespaces + NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict); + NamespaceDef *nd; + for (;(nd=nli.current());++nli) + { + uchar charCode = (uchar)nd->name().at(0); + uint letter = charCode<128 ? tolower(charCode) : charCode; + if (nd->isLinkable() && isId(letter)) + { + g_searchIndexSymbols[SEARCH_INDEX_ALL][letter].append(nd); + g_searchIndexSymbols[SEARCH_INDEX_NAMESPACES][letter].append(nd); + g_searchIndexCount[SEARCH_INDEX_ALL]++; + g_searchIndexCount[SEARCH_INDEX_NAMESPACES]++; + } + } + + // index files + FileNameListIterator fnli(*Doxygen::inputNameList); + FileName *fn; + for (;(fn=fnli.current());++fnli) + { + FileNameIterator fni(*fn); + FileDef *fd; + for (;(fd=fni.current());++fni) + { + uchar charCode = (uchar)fd->name().at(0); + uint letter = charCode<128 ? tolower(charCode) : charCode; + if (fd->isLinkable() && isId(letter)) + { + g_searchIndexSymbols[SEARCH_INDEX_ALL][letter].append(fd); + g_searchIndexSymbols[SEARCH_INDEX_FILES][letter].append(fd); + g_searchIndexCount[SEARCH_INDEX_ALL]++; + g_searchIndexCount[SEARCH_INDEX_FILES]++; + } + } + } + + // index class members + { + MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict); + MemberName *mn; + // for each member name + for (mnli.toFirst();(mn=mnli.current());++mnli) + { + MemberDef *md; + MemberNameIterator mni(*mn); + // for each member definition + for (mni.toFirst();(md=mni.current());++mni) + { + addMemberToSearchIndex(g_searchIndexSymbols,g_searchIndexCount,md); + } + } + } + + // index file/namespace members + { + MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict); + MemberName *mn; + // for each member name + for (fnli.toFirst();(mn=fnli.current());++fnli) + { + MemberDef *md; + MemberNameIterator mni(*mn); + // for each member definition + for (mni.toFirst();(md=mni.current());++mni) + { + addMemberToSearchIndex(g_searchIndexSymbols,g_searchIndexCount,md); + } + } + } + + // index groups + GroupSDict::Iterator gli(*Doxygen::groupSDict); + GroupDef *gd; + for (gli.toFirst();(gd=gli.current());++gli) + { + if (gd->isLinkable()) + { + QCString title = gd->groupTitle(); + if (!title.isEmpty()) // TODO: able searching for all word in the title + { + uchar charCode = title.at(0); + uint letter = charCode<128 ? tolower(charCode) : charCode; + if (isId(letter)) + { + g_searchIndexSymbols[SEARCH_INDEX_ALL][letter].append(gd); + g_searchIndexSymbols[SEARCH_INDEX_GROUPS][letter].append(gd); + g_searchIndexCount[SEARCH_INDEX_ALL]++; + g_searchIndexCount[SEARCH_INDEX_GROUPS]++; + } + } + } + } + + // index pages + PageSDict::Iterator pdi(*Doxygen::pageSDict); + PageDef *pd=0; + for (pdi.toFirst();(pd=pdi.current());++pdi) + { + if (pd->isLinkable()) + { + QCString title = pd->title(); + if (!title.isEmpty()) + { + uchar charCode = title.at(0); + uint letter = charCode<128 ? tolower(charCode) : charCode; + if (isId(letter)) + { + g_searchIndexSymbols[SEARCH_INDEX_ALL][letter].append(pd); + g_searchIndexSymbols[SEARCH_INDEX_PAGES][letter].append(pd); + g_searchIndexCount[SEARCH_INDEX_ALL]++; + g_searchIndexCount[SEARCH_INDEX_PAGES]++; + } + } + } + } + if (Doxygen::mainPage) + { + QCString title = Doxygen::mainPage->title(); + if (!title.isEmpty()) + { + uchar charCode = title.at(0); + uint letter = charCode<128 ? tolower(charCode) : charCode; + if (isId(letter)) + { + g_searchIndexSymbols[SEARCH_INDEX_ALL][letter].append(Doxygen::mainPage); + g_searchIndexSymbols[SEARCH_INDEX_PAGES][letter].append(Doxygen::mainPage); + g_searchIndexCount[SEARCH_INDEX_ALL]++; + g_searchIndexCount[SEARCH_INDEX_PAGES]++; + } + } + } + + // sort all lists + int i,p; + for (i=0;i0) + { + g_searchIndexSymbols[i][p].sort(); + } + } + } + + // write index files + QCString searchDirName = Config_getString("HTML_OUTPUT")+"/search"; + + for (i=0;i0) + { + QCString baseName; + baseName.sprintf("%s_%02x",g_searchIndexName[i],p); + + QCString fileName = searchDirName + "/"+baseName+".html"; + QCString dataFileName = searchDirName + "/"+baseName+".js"; + + QFile outFile(fileName); + QFile dataOutFile(dataFileName); + if (outFile.open(IO_WriteOnly) && dataOutFile.open(IO_WriteOnly)) + { + { + FTextStream t(&outFile); + + t << "" << endl; + t << "" << endl; + t << "" << endl; + t << "" << endl; + t << "" << endl; + t << "" << endl; + t << "" << endl; + t << "" << endl; + t << "
    " << endl; + t << "
    " << theTranslator->trLoading() << "
    " << endl; + t << "
    " << endl; // here the results will be inserted + t << "" << endl; + t << "
    " + << theTranslator->trSearching() << "
    " << endl; + t << "
    " + << theTranslator->trNoMatches() << "
    " << endl; + + t << "" << endl; + t << "
    " << endl; // SRIndex + t << "" << endl; + t << "" << endl; + } + FTextStream ti(&dataOutFile); + + ti << "var searchData=" << endl; + // format + // searchData[] = array of items + // searchData[x][0] = id + // searchData[x][1] = [ name + child1 + child2 + .. ] + // searchData[x][1][0] = name as shown + // searchData[x][1][y+1] = info for child y + // searchData[x][1][y+1][0] = url + // searchData[x][1][y+1][1] = 1 => target="_parent" + // searchData[x][1][y+1][2] = scope + + ti << "[" << endl; + bool firstEntry=TRUE; + + SDict >::Iterator li(g_searchIndexSymbols[i][p]); + QList *dl; + int itemCount=0; + for (li.toFirst();(dl=li.current());++li) + { + Definition *d = dl->first(); + QCString id = d->localName(); + + if (!firstEntry) + { + ti << "," << endl; + } + firstEntry=FALSE; + + QCString dispName = d->localName(); + if (d->definitionType()==Definition::TypeGroup) + { + dispName = ((GroupDef*)d)->groupTitle(); + } + else if (d->definitionType()==Definition::TypePage) + { + dispName = ((PageDef*)d)->title(); + } + ti << " ['" << searchId(dispName) << "',['" + << convertToXML(dispName) << "',["; + + if (dl->count()==1) // item with a unique name + { + MemberDef *md = 0; + bool isMemberDef = d->definitionType()==Definition::TypeMember; + if (isMemberDef) md = (MemberDef*)d; + QCString anchor = d->anchor(); + + ti << "'" << externalRef("../",d->getReference(),TRUE) + << d->getOutputFileBase() << Doxygen::htmlFileExtension; + if (!anchor.isEmpty()) + { + ti << "#" << anchor; + } + ti << "',"; + + static bool extLinksInWindow = Config_getBool("EXT_LINKS_IN_WINDOW"); + if (!extLinksInWindow || d->getReference().isEmpty()) + { + ti << "1,"; + } + else + { + ti << "0,"; + } + + if (d->getOuterScope()!=Doxygen::globalScope) + { + ti << "'" << convertToXML(d->getOuterScope()->name()) << "'"; + } + else if (md) + { + FileDef *fd = md->getBodyDef(); + if (fd==0) fd = md->getFileDef(); + if (fd) + { + ti << "'" << convertToXML(fd->localName()) << "'"; + } + } + else + { + ti << "''"; + } + ti << "]]"; + } + else // multiple items with the same name + { + QListIterator di(*dl); + bool overloadedFunction = FALSE; + Definition *prevScope = 0; + int childCount=0; + for (di.toFirst();(d=di.current());) + { + ++di; + Definition *scope = d->getOuterScope(); + Definition *next = di.current(); + Definition *nextScope = 0; + MemberDef *md = 0; + bool isMemberDef = d->definitionType()==Definition::TypeMember; + if (isMemberDef) md = (MemberDef*)d; + if (next) nextScope = next->getOuterScope(); + QCString anchor = d->anchor(); + + if (childCount>0) + { + ti << "],["; + } + ti << "'" << externalRef("../",d->getReference(),TRUE) + << d->getOutputFileBase() << Doxygen::htmlFileExtension; + if (!anchor.isEmpty()) + { + ti << "#" << anchor; + } + ti << "',"; + + static bool extLinksInWindow = Config_getBool("EXT_LINKS_IN_WINDOW"); + if (!extLinksInWindow || d->getReference().isEmpty()) + { + ti << "1,"; + } + else + { + ti << "0,"; + } + bool found=FALSE; + overloadedFunction = ((prevScope!=0 && scope==prevScope) || + (scope && scope==nextScope) + ) && md && + (md->isFunction() || md->isSlot()); + QCString prefix; + if (md) prefix=convertToXML(md->localName()); + if (overloadedFunction) // overloaded member function + { + prefix+=convertToXML(md->argsString()); + // show argument list to disambiguate overloaded functions + } + else if (md) // unique member function + { + prefix+="()"; // only to show it is a function + } + QCString name; + if (d->definitionType()==Definition::TypeClass) + { + name = convertToXML(((ClassDef*)d)->displayName()); + found = TRUE; + } + else if (d->definitionType()==Definition::TypeNamespace) + { + name = convertToXML(((NamespaceDef*)d)->displayName()); + found = TRUE; + } + else if (scope==0 || scope==Doxygen::globalScope) // in global scope + { + if (md) + { + FileDef *fd = md->getBodyDef(); + if (fd==0) fd = md->getFileDef(); + if (fd) + { + if (!prefix.isEmpty()) prefix+=": "; + name = prefix + convertToXML(fd->localName()); + found = TRUE; + } + } + } + else if (md && (md->getClassDef() || md->getNamespaceDef())) + // member in class or namespace scope + { + SrcLangExt lang = md->getLanguage(); + name = convertToXML(d->getOuterScope()->qualifiedName()) + + getLanguageSpecificSeparator(lang) + prefix; + found = TRUE; + } + else if (scope) // some thing else? -> show scope + { + name = prefix + convertToXML(scope->name()); + found = TRUE; + } + if (!found) // fallback + { + name = prefix + "("+theTranslator->trGlobalNamespace()+")"; + } + + ti << "'" << name << "'"; + + prevScope = scope; + childCount++; + } + + ti << "]]"; + } + ti << "]"; + itemCount++; + } + if (!firstEntry) + { + ti << endl; + } + + ti << "];" << endl; + + } + else + { + err("Failed to open file '%s' for writing...\n",fileName.data()); + } + } + } + } + + { + QFile f(searchDirName+"/search.js"); + if (f.open(IO_WriteOnly)) + { + FTextStream t(&f); + t << "// Search script generated by doxygen" << endl; + t << "// Copyright (C) 2009 by Dimitri van Heesch." << endl << endl; + t << "// The code in this file is loosly based on main.js, part of Natural Docs," << endl; + t << "// which is Copyright (C) 2003-2008 Greg Valure" << endl; + t << "// Natural Docs is licensed under the GPL." << endl << endl; + t << "var indexSectionsWithContent =" << endl; + t << "{" << endl; + bool first=TRUE; + int j=0; + for (i=0;i0) + { + if (!first) t << "," << endl; + t << " " << j << ": \""; + for (p=0;p0 ? "1" : "0"); + } + t << "\""; + first=FALSE; + j++; + } + } + if (!first) t << "\n"; + t << "};" << endl << endl; + t << "var indexSectionNames =" << endl; + t << "{" << endl; + first=TRUE; + j=0; + for (i=0;i0) + { + if (!first) t << "," << endl; + t << " " << j << ": \"" << g_searchIndexName[i] << "\""; + first=FALSE; + j++; + } + } + if (!first) t << "\n"; + t << "};" << endl << endl; + t << search_script; + } + } + { + QFile f(searchDirName+"/nomatches.html"); + if (f.open(IO_WriteOnly)) + { + FTextStream t(&f); + t << "" << endl; + t << "" << endl; + t << "" << endl; + t << "" << endl; + t << "" << endl; + t << "" << endl; + t << "" << endl; + t << "
    " << endl; + t << "
    " + << theTranslator->trNoMatches() << "
    " << endl; + t << "
    " << endl; + t << "" << endl; + t << "" << endl; + } + } + Doxygen::indexList.addStyleSheetFile("search/search.js"); +} + +void writeSearchCategories(FTextStream &t) +{ + static SearchIndexCategoryMapping map; + int i,j=0; + for (i=0;i0) + { + t << "" + << " " + << convertToXML(map.categoryLabel[i]) + << ""; + j++; + } + } +} + + + diff --git a/trunk/src/searchindex.h b/trunk/src/searchindex.h new file mode 100644 index 0000000..024e70a --- /dev/null +++ b/trunk/src/searchindex.h @@ -0,0 +1,79 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#ifndef _SEARCHINDEX_H +#define _SEARCHINDEX_H + +#include "qtbc.h" +#include +#include +#include +#include +#include + +class FTextStream; + +//------- server side search index ---------------------- + +struct URL +{ + URL(const char *n,const char *u) : name(n), url(u) {} + QCString name; + QCString url; +}; + + +struct URLInfo +{ + URLInfo(int idx,int f) : urlIdx(idx), freq(f) {} + int urlIdx; + int freq; +}; + +class IndexWord +{ + public: + IndexWord(const char *word); + void addUrlIndex(int,bool); + const QIntDict &urls() const { return m_urls; } + QCString word() const { return m_word; } + + private: + QCString m_word; + QIntDict m_urls; +}; + +class SearchIndex +{ + public: + SearchIndex(); + void setCurrentDoc(const char *name,const char *baseName,const char *anchor=0); + void addWord(const char *word,bool hiPriority,bool recurse=FALSE); + void write(const char *file); + private: + QDict m_words; + QVector< QList > m_index; + QIntDict m_urls; + int m_urlIndex; +}; + +//------- client side search index ---------------------- + +void writeJavascriptSearchIndex(); +void writeSearchCategories(FTextStream &t); + +#endif diff --git a/trunk/src/section.h b/trunk/src/section.h new file mode 100644 index 0000000..556cad0 --- /dev/null +++ b/trunk/src/section.h @@ -0,0 +1,68 @@ +/****************************************************************************** + * + * + * + * + * Copyright (C) 1997-2012 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. + * + */ + +#ifndef SECTION_H +#define SECTION_H + +#include "qtbc.h" +#include +#include +#include "sortdict.h" + +class Definition; + +struct SectionInfo +{ + enum SectionType { Page = 0, + Section = 1, + Subsection = 2, + Subsubsection = 3, + Paragraph = 4, + Anchor = 5 + }; + SectionInfo(const char *f,const char *l,const char *t, + SectionType st,int lev,const char *r=0) : + label(l), title(t), type(st), ref(r), definition(0), + fileName(f), generated(FALSE), level(lev) + { + } + SectionInfo(const SectionInfo &s) + { + label=s.label.copy(); title=s.title.copy(); ref=s.ref.copy(); + type =s.type; definition=s.definition; + fileName=s.fileName.copy(); generated=s.generated; + } + ~SectionInfo() {} + QCString label; + QCString title; + SectionType type; + QCString ref; + Definition *definition; + QCString fileName; + bool generated; + int level; +}; + +class SectionDict : public SDict +{ + public: + SectionDict(int size) : SDict(size) {} + ~SectionDict() {} +}; + +#endif diff --git a/trunk/src/sizzle.js b/trunk/src/sizzle.js new file mode 100644 index 0000000..b37b0d4 --- /dev/null +++ b/trunk/src/sizzle.js @@ -0,0 +1,19 @@ +/* + * Sizzle CSS Selector Engine - v0.9.3 + * Copyright 2009, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * More information: http://sizzlejs.com/ + */ +(function(){var R=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?/g,L=0,H=Object.prototype.toString;var F=function(Y,U,ab,ac){ab=ab||[];U=U||document;if(U.nodeType!==1&&U.nodeType!==9){return[]}if(!Y||typeof Y!=="string"){return ab}var Z=[],W,af,ai,T,ad,V,X=true;R.lastIndex=0;while((W=R.exec(Y))!==null){Z.push(W[1]);if(W[2]){V=RegExp.rightContext;break}}if(Z.length>1&&M.exec(Y)){if(Z.length===2&&I.relative[Z[0]]){af=J(Z[0]+Z[1],U)}else{af=I.relative[Z[0]]?[U]:F(Z.shift(),U);while(Z.length){Y=Z.shift();if(I.relative[Y]){Y+=Z.shift()}af=J(Y,af)}}}else{var ae=ac?{expr:Z.pop(),set:E(ac)}:F.find(Z.pop(),Z.length===1&&U.parentNode?U.parentNode:U,Q(U));af=F.filter(ae.expr,ae.set);if(Z.length>0){ai=E(af)}else{X=false}while(Z.length){var ah=Z.pop(),ag=ah;if(!I.relative[ah]){ah=""}else{ag=Z.pop()}if(ag==null){ag=U}I.relative[ah](ai,ag,Q(U))}}if(!ai){ai=af}if(!ai){throw"Syntax error, unrecognized expression: "+(ah||Y)}if(H.call(ai)==="[object Array]"){if(!X){ab.push.apply(ab,ai)}else{if(U.nodeType===1){for(var aa=0;ai[aa]!=null;aa++){if(ai[aa]&&(ai[aa]===true||ai[aa].nodeType===1&&K(U,ai[aa]))){ab.push(af[aa])}}}else{for(var aa=0;ai[aa]!=null;aa++){if(ai[aa]&&ai[aa].nodeType===1){ab.push(af[aa])}}}}}else{E(ai,ab)}if(V){F(V,U,ab,ac);if(G){hasDuplicate=false;ab.sort(G);if(hasDuplicate){for(var aa=1;aa":function(Z,U,aa){var X=typeof U==="string";if(X&&!/\W/.test(U)){U=aa?U:U.toUpperCase();for(var V=0,T=Z.length;V=0)){if(!V){T.push(Y)}}else{if(V){U[X]=false}}}}return false},ID:function(T){return T[1].replace(/\\/g,"")},TAG:function(U,T){for(var V=0;T[V]===false;V++){}return T[V]&&Q(T[V])?U[1]:U[1].toUpperCase()},CHILD:function(T){if(T[1]=="nth"){var U=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(T[2]=="even"&&"2n"||T[2]=="odd"&&"2n+1"||!/\D/.test(T[2])&&"0n+"+T[2]||T[2]);T[2]=(U[1]+(U[2]||1))-0;T[3]=U[3]-0}T[0]=L++;return T},ATTR:function(X,U,V,T,Y,Z){var W=X[1].replace(/\\/g,"");if(!Z&&I.attrMap[W]){X[1]=I.attrMap[W]}if(X[2]==="~="){X[4]=" "+X[4]+" "}return X},PSEUDO:function(X,U,V,T,Y){if(X[1]==="not"){if(X[3].match(R).length>1||/^\w/.test(X[3])){X[3]=F(X[3],null,null,U)}else{var W=F.filter(X[3],U,V,true^Y);if(!V){T.push.apply(T,W)}return false}}else{if(I.match.POS.test(X[0])||I.match.CHILD.test(X[0])){return true}}return X},POS:function(T){T.unshift(true);return T}},filters:{enabled:function(T){return T.disabled===false&&T.type!=="hidden"},disabled:function(T){return T.disabled===true},checked:function(T){return T.checked===true},selected:function(T){T.parentNode.selectedIndex;return T.selected===true},parent:function(T){return !!T.firstChild},empty:function(T){return !T.firstChild},has:function(V,U,T){return !!F(T[3],V).length},header:function(T){return/h\d/i.test(T.nodeName)},text:function(T){return"text"===T.type},radio:function(T){return"radio"===T.type},checkbox:function(T){return"checkbox"===T.type},file:function(T){return"file"===T.type},password:function(T){return"password"===T.type},submit:function(T){return"submit"===T.type},image:function(T){return"image"===T.type},reset:function(T){return"reset"===T.type},button:function(T){return"button"===T.type||T.nodeName.toUpperCase()==="BUTTON"},input:function(T){return/input|select|textarea|button/i.test(T.nodeName)}},setFilters:{first:function(U,T){return T===0},last:function(V,U,T,W){return U===W.length-1},even:function(U,T){return T%2===0},odd:function(U,T){return T%2===1},lt:function(V,U,T){return UT[3]-0},nth:function(V,U,T){return T[3]-0==U},eq:function(V,U,T){return T[3]-0==U}},filter:{PSEUDO:function(Z,V,W,aa){var U=V[1],X=I.filters[U];if(X){return X(Z,W,V,aa)}else{if(U==="contains"){return(Z.textContent||Z.innerText||"").indexOf(V[3])>=0}else{if(U==="not"){var Y=V[3];for(var W=0,T=Y.length;W=0)}}},ID:function(U,T){return U.nodeType===1&&U.getAttribute("id")===T},TAG:function(U,T){return(T==="*"&&U.nodeType===1)||U.nodeName===T},CLASS:function(U,T){return(" "+(U.className||U.getAttribute("class"))+" ").indexOf(T)>-1},ATTR:function(Y,W){var V=W[1],T=I.attrHandle[V]?I.attrHandle[V](Y):Y[V]!=null?Y[V]:Y.getAttribute(V),Z=T+"",X=W[2],U=W[4];return T==null?X==="!=":X==="="?Z===U:X==="*="?Z.indexOf(U)>=0:X==="~="?(" "+Z+" ").indexOf(U)>=0:!U?Z&&T!==false:X==="!="?Z!=U:X==="^="?Z.indexOf(U)===0:X==="$="?Z.substr(Z.length-U.length)===U:X==="|="?Z===U||Z.substr(0,U.length+1)===U+"-":false},POS:function(X,U,V,Y){var T=U[2],W=I.setFilters[T];if(W){return W(X,V,U,Y)}}}};var M=I.match.POS;for(var O in I.match){I.match[O]=RegExp(I.match[O].source+/(?![^\[]*\])(?![^\(]*\))/.source)}var E=function(U,T){U=Array.prototype.slice.call(U);if(T){T.push.apply(T,U);return T}return U};try{Array.prototype.slice.call(document.documentElement.childNodes)}catch(N){E=function(X,W){var U=W||[];if(H.call(X)==="[object Array]"){Array.prototype.push.apply(U,X)}else{if(typeof X.length==="number"){for(var V=0,T=X.length;V";var T=document.documentElement;T.insertBefore(U,T.firstChild);if(!!document.getElementById(V)){I.find.ID=function(X,Y,Z){if(typeof Y.getElementById!=="undefined"&&!Z){var W=Y.getElementById(X[1]);return W?W.id===X[1]||typeof W.getAttributeNode!=="undefined"&&W.getAttributeNode("id").nodeValue===X[1]?[W]:g:[]}};I.filter.ID=function(Y,W){var X=typeof Y.getAttributeNode!=="undefined"&&Y.getAttributeNode("id");return Y.nodeType===1&&X&&X.nodeValue===W}}T.removeChild(U)})();(function(){var T=document.createElement("div");T.appendChild(document.createComment(""));if(T.getElementsByTagName("*").length>0){I.find.TAG=function(U,Y){var X=Y.getElementsByTagName(U[1]);if(U[1]==="*"){var W=[];for(var V=0;X[V];V++){if(X[V].nodeType===1){W.push(X[V])}}X=W}return X}}T.innerHTML="";if(T.firstChild&&typeof T.firstChild.getAttribute!=="undefined"&&T.firstChild.getAttribute("href")!=="#"){I.attrHandle.href=function(U){return U.getAttribute("href",2)}}})();if(document.querySelectorAll){(function(){var T=F,U=document.createElement("div");U.innerHTML="

    ";if(U.querySelectorAll&&U.querySelectorAll(".TEST").length===0){return}F=function(Y,X,V,W){X=X||document;if(!W&&X.nodeType===9&&!Q(X)){try{return E(X.querySelectorAll(Y),V)}catch(Z){}}return T(Y,X,V,W)};F.find=T.find;F.filter=T.filter;F.selectors=T.selectors;F.matches=T.matches})()}if(document.getElementsByClassName&&document.documentElement.getElementsByClassName){(function(){var T=document.createElement("div");T.innerHTML="
    ";if(T.getElementsByClassName("e").length===0){return}T.lastChild.className="e";if(T.getElementsByClassName("e").length===1){return}I.order.splice(1,0,"CLASS");I.find.CLASS=function(U,V,W){if(typeof V.getElementsByClassName!=="undefined"&&!W){return V.getElementsByClassName(U[1])}}})()}function P(U,Z,Y,ad,aa,ac){var ab=U=="previousSibling"&&!ac;for(var W=0,V=ad.length;W0){X=T;break}}}T=T[U]}ad[W]=X}}}var K=document.compareDocumentPosition?function(U,T){return U.compareDocumentPosition(T)&16}:function(U,T){return U!==T&&(U.contains?U.contains(T):true)};var Q=function(T){return T.nodeType===9&&T.documentElement.nodeName!=="HTML"||!!T.ownerDocument&&Q(T.ownerDocument)};var J=function(T,aa){var W=[],X="",Y,V=aa.nodeType?[aa]:aa;while((Y=I.match.PSEUDO.exec(T))){X+=Y[0];T=T.replace(I.match.PSEUDO,"")}T=I.relative[T]?T+"*":T;for(var Z=0,U=V.length;Z0||T.offsetHeight>0};F.selectors.filters.animated=function(T){return o.grep(o.timers,function(U){return T===U.elem}).length};o.multiFilter=function(V,T,U){if(U){V=":not("+V+")"}return F.matches(V,T)};o.dir=function(V,U){var T=[],W=V[U];while(W&&W!=document){if(W.nodeType==1){T.push(W)}W=W[U]}return T};o.nth=function(X,T,V,W){T=T||1;var U=0;for(;X;X=X[V]){if(X.nodeType==1&&++U==T){break}}return X};o.sibling=function(V,U){var T=[];for(;V;V=V.nextSibling){if(V.nodeType==1&&V!=U){T.push(V)}}return T};return;l.Sizzle=F})();o.event={add:function(I,F,H,K){if(I.nodeType==3||I.nodeType==8){return}if(I.setInterval&&I!=l){I=l}if(!H.guid){H.guid=this.guid++}if(K!==g){var G=H;H=this.proxy(G);H.data=K}var E=o.data(I,"events")||o.data(I,"events",{}),J=o.data(I,"handle")||o.data(I,"handle",function(){return typeof o!=="undefined"&&!o.event.triggered?o.event.handle.apply(arguments.callee.elem,arguments):g});J.elem=I;o.each(F.split(/\s+/),function(M,N){var O=N.split(".");N=O.shift();H.type=O.slice().sort().join(".");var L=E[N];if(o.event.specialAll[N]){o.event.specialAll[N].setup.call(I,K,O)}if(!L){L=E[N]={};if(!o.event.special[N]||o.event.special[N].setup.call(I,K,O)===false){if(I.addEventListener){I.addEventListener(N,J,false)}else{if(I.attachEvent){I.attachEvent("on"+N,J)}}}}L[H.guid]=H;o.event.global[N]=true});I=null},guid:1,global:{},remove:function(K,H,J){if(K.nodeType==3||K.nodeType==8){return}var G=o.data(K,"events"),F,E;if(G){if(H===g||(typeof H==="string"&&H.charAt(0)==".")){for(var I in G){this.remove(K,I+(H||""))}}else{if(H.type){J=H.handler;H=H.type}o.each(H.split(/\s+/),function(M,O){var Q=O.split(".");O=Q.shift();var N=RegExp("(^|\\.)"+Q.slice().sort().join(".*\\.")+"(\\.|$)");if(G[O]){if(J){delete G[O][J.guid]}else{for(var P in G[O]){if(N.test(G[O][P].type)){delete G[O][P]}}}if(o.event.specialAll[O]){o.event.specialAll[O].teardown.call(K,Q)}for(F in G[O]){break}if(!F){if(!o.event.special[O]||o.event.special[O].teardown.call(K,Q)===false){if(K.removeEventListener){K.removeEventListener(O,o.data(K,"handle"),false)}else{if(K.detachEvent){K.detachEvent("on"+O,o.data(K,"handle"))}}}F=null;delete G[O]}}})}for(F in G){break}if(!F){var L=o.data(K,"handle");if(L){L.elem=null}o.removeData(K,"events");o.removeData(K,"handle")}}},trigger:function(I,K,H,E){var G=I.type||I;if(!E){I=typeof I==="object"?I[h]?I:o.extend(o.Event(G),I):o.Event(G);if(G.indexOf("!")>=0) +{I.type=G=G.slice(0,-1);I.exclusive=true}if(!H){I.stopPropagation();if(this.global[G]){o.each(o.cache,function(){if(this.events&&this.events[G]){o.event.trigger(I,K,this.handle.elem)}})}}if(!H||H.nodeType==3||H.nodeType==8){return g}I.result=g;I.target=H;K=o.makeArray(K);K.unshift(I)}I.currentTarget=H;var J=o.data(H,"handle");if(J){J.apply(H,K)}if((!H[G]||(o.nodeName(H,"a")&&G=="click"))&&H["on"+G]&&H["on"+G].apply(H,K)===false){I.result=false}if(!E&&H[G]&&!I.isDefaultPrevented()&&!(o.nodeName(H,"a")&&G=="click")){this.triggered=true;try{H[G]()}catch(L){}}this.triggered=false;if(!I.isPropagationStopped()){var F=H.parentNode||H.ownerDocument;if(F){o.event.trigger(I,K,F,true)}}},handle:function(K){var J,E;K=arguments[0]=o.event.fix(K||l.event);K.currentTarget=this;var L=K.type.split(".");K.type=L.shift();J=!L.length&&!K.exclusive;var I=RegExp("(^|\\.)"+L.slice().sort().join(".*\\.")+"(\\.|$)");E=(o.data(this,"events")||{})[K.type];for(var G in E){var H=E[G];if(J||I.test(H.type)){K.handler=H;K.data=H.data;var F=H.apply(this,arguments);if(F!==g){K.result=F;if(F===false){K.preventDefault();K.stopPropagation()}}if(K.isImmediatePropagationStopped()){break}}}},props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode metaKey newValue originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),fix:function(H){if(H[h]){return H}var F=H;H=o.Event(F);for(var G=this.props.length,J;G;){J=this.props[--G];H[J]=F[J]}if(!H.target){H.target=H.srcElement||document}if(H.target.nodeType==3){H.target=H.target.parentNode}if(!H.relatedTarget&&H.fromElement){H.relatedTarget=H.fromElement==H.target?H.toElement:H.fromElement}if(H.pageX==null&&H.clientX!=null){var I=document.documentElement,E=document.body;H.pageX=H.clientX+(I&&I.scrollLeft||E&&E.scrollLeft||0)-(I.clientLeft||0);H.pageY=H.clientY+(I&&I.scrollTop||E&&E.scrollTop||0)-(I.clientTop||0)}if(!H.which&&((H.charCode||H.charCode===0)?H.charCode:H.keyCode)){H.which=H.charCode||H.keyCode}if(!H.metaKey&&H.ctrlKey){H.metaKey=H.ctrlKey}if(!H.which&&H.button){H.which=(H.button&1?1:(H.button&2?3:(H.button&4?2:0)))}return H},proxy:function(F,E){E=E||function(){return F.apply(this,arguments)};E.guid=F.guid=F.guid||E.guid||this.guid++;return E},special:{ready:{setup:B,teardown:function(){}}},specialAll:{live:{setup:function(E,F){o.event.add(this,F[0],c)},teardown:function(G){if(G.length){var E=0,F=RegExp("(^|\\.)"+G[0]+"(\\.|$)");o.each((o.data(this,"events").live||{}),function(){if(F.test(this.type)){E++}});if(E<1){o.event.remove(this,G[0],c)}}}}}};o.Event=function(E){if(!this.preventDefault){return new o.Event(E)}if(E&&E.type){this.originalEvent=E;this.type=E.type}else{this.type=E}this.timeStamp=e();this[h]=true};function k(){return false}function u(){return true}o.Event.prototype={preventDefault:function(){this.isDefaultPrevented=u;var E=this.originalEvent;if(!E){return}if(E.preventDefault){E.preventDefault()}E.returnValue=false},stopPropagation:function(){this.isPropagationStopped=u;var E=this.originalEvent;if(!E){return}if(E.stopPropagation){E.stopPropagation()}E.cancelBubble=true},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=u;this.stopPropagation()},isDefaultPrevented:k,isPropagationStopped:k,isImmediatePropagationStopped:k};var a=function(F){var E=F.relatedTarget;while(E&&E!=this){try{E=E.parentNode}catch(G){E=this}}if(E!=this){F.type=F.data;o.event.handle.apply(this,arguments)}};o.each({mouseover:"mouseenter",mouseout:"mouseleave"},function(F,E){o.event.special[E]={setup:function(){o.event.add(this,F,a,E)},teardown:function(){o.event.remove(this,F,a)}}});o.fn.extend({bind:function(F,G,E){return F=="unload"?this.one(F,G,E):this.each(function(){o.event.add(this,F,E||G,E&&G)})},one:function(G,H,F){var E=o.event.proxy(F||H,function(I){o(this).unbind(I,E);return(F||H).apply(this,arguments)});return this.each(function(){o.event.add(this,G,E,F&&H)})},unbind:function(F,E){return this.each(function(){o.event.remove(this,F,E)})},trigger:function(E,F){return this.each(function(){o.event.trigger(E,F,this)})},triggerHandler:function(E,G){if(this[0]){var F=o.Event(E);F.preventDefault();F.stopPropagation();o.event.trigger(F,G,this[0]);return F.result}},toggle:function(G){var E=arguments,F=1;while(F=0){var E=G.slice(I,G.length);G=G.slice(0,I)}var H="GET";if(J){if(o.isFunction(J)){K=J;J=null}else{if(typeof J==="object"){J=o.param(J);H="POST"}}}var F=this;o.ajax({url:G,type:H,dataType:"html",data:J,complete:function(M,L){if(L=="success"||L=="notmodified"){F.html(E?o("
    ").append(M.responseText.replace(//g,"")).find(E):M.responseText)}if(K){F.each(K,[M.responseText,L,M])}}});return this},serialize:function(){return o.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?o.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||/select|textarea/i.test(this.nodeName)||/text|hidden|password|search/i.test(this.type))}).map(function(E,F){var G=o(this).val();return G==null?null:o.isArray(G)?o.map(G,function(I,H){return{name:F.name,value:I}}):{name:F.name,value:G}}).get()}});o.each("ajaxStart,ajaxStop,ajaxComplete,ajaxError,ajaxSuccess,ajaxSend".split(","),function(E,F){o.fn[F]=function(G){return this.bind(F,G)}});var r=e();o.extend({get:function(E,G,H,F){if(o.isFunction(G)){H=G;G=null}return o.ajax({type:"GET",url:E,data:G,success:H,dataType:F})},getScript:function(E,F){return o.get(E,null,F,"script")},getJSON:function(E,F,G){return o.get(E,F,G,"json")},post:function(E,G,H,F){if(o.isFunction(G)){H=G;G={}}return o.ajax({type:"POST",url:E,data:G,success:H,dataType:F})},ajaxSetup:function(E){o.extend(o.ajaxSettings,E)},ajaxSettings:{url:location.href,global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:function(){return l.ActiveXObject?new ActiveXObject("Microsoft.XMLHTTP"):new XMLHttpRequest()},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},ajax:function(M){M=o.extend(true,M,o.extend(true,{},o.ajaxSettings,M));var W,F=/=\?(&|$)/g,R,V,G=M.type.toUpperCase();if(M.data&&M.processData&&typeof M.data!=="string"){M.data=o.param(M.data)}if(M.dataType=="jsonp"){if(G=="GET"){if(!M.url.match(F)){M.url+=(M.url.match(/\?/)?"&":"?")+(M.jsonp||"callback")+"=?"}}else{if(!M.data||!M.data.match(F)){M.data=(M.data?M.data+"&":"")+(M.jsonp||"callback")+"=?"}}M.dataType="json"}if(M.dataType=="json"&&(M.data&&M.data.match(F)||M.url.match(F))){W="jsonp"+r++;if(M.data){M.data=(M.data+"").replace(F,"="+W+"$1")}M.url=M.url.replace(F,"="+W+"$1");M.dataType="script";l[W]=function(X){V=X;I();L();l[W]=g;try{delete l[W]}catch(Y){}if(H){H.removeChild(T)}}}if(M.dataType=="script"&&M.cache==null){M.cache=false}if(M.cache===false&&G=="GET"){var E=e();var U=M.url.replace(/(\?|&)_=.*?(&|$)/,"$1_="+E+"$2");M.url=U+((U==M.url)?(M.url.match(/\?/)?"&":"?")+"_="+E:"")}if(M.data&&G=="GET"){M.url+=(M.url.match(/\?/)?"&":"?")+M.data;M.data=null}if(M.global&&!o.active++){o.event.trigger("ajaxStart")}var Q=/^(\w+:)?\/\/([^\/?#]+)/.exec(M.url);if(M.dataType=="script"&&G=="GET"&&Q&&(Q[1]&&Q[1]!=location.protocol||Q[2]!=location.host)){var H=document.getElementsByTagName("head")[0];var T=document.createElement("script");T.src=M.url;if(M.scriptCharset){T.charset=M.scriptCharset}if(!W){var O=false;T.onload=T.onreadystatechange=function(){if(!O&&(!this.readyState||this.readyState=="loaded"||this.readyState=="complete")){O=true;I();L();T.onload=T.onreadystatechange=null;H.removeChild(T)}}}H.appendChild(T);return g}var K=false;var J=M.xhr();if(M.username){J.open(G,M.url,M.async,M.username,M.password)}else{J.open(G,M.url,M.async)}try{if(M.data){J.setRequestHeader("Content-Type",M.contentType)}if(M.ifModified){J.setRequestHeader("If-Modified-Since",o.lastModified[M.url]||"Thu, 01 Jan 1970 00:00:00 GMT")}J.setRequestHeader("X-Requested-With","XMLHttpRequest");J.setRequestHeader("Accept",M.dataType&&M.accepts[M.dataType]?M.accepts[M.dataType]+", */*":M.accepts._default)}catch(S){}if(M.beforeSend&&M.beforeSend(J,M)===false){if(M.global&&!--o.active){o.event.trigger("ajaxStop")}J.abort();return false}if(M.global){o.event.trigger("ajaxSend",[J,M])}var N=function(X){if(J.readyState==0){if(P){clearInterval(P);P=null;if(M.global&&!--o.active){o.event.trigger("ajaxStop")}}}else{if(!K&&J&&(J.readyState==4||X=="timeout")){K=true;if(P){clearInterval(P);P=null}R=X=="timeout"?"timeout":!o.httpSuccess(J)?"error":M.ifModified&&o.httpNotModified(J,M.url)?"notmodified":"success";if(R=="success"){try{V=o.httpData(J,M.dataType,M)}catch(Z){R="parsererror"}}if(R=="success"){var Y;try{Y=J.getResponseHeader("Last-Modified")}catch(Z){}if(M.ifModified&&Y){o.lastModified[M.url]=Y}if(!W){I()}}else{o.handleError(M,J,R)}L();if(X){J.abort()}if(M.async){J=null}}}};if(M.async){var P=setInterval(N,13);if(M.timeout>0){setTimeout(function(){if(J&&!K){N("timeout")}},M.timeout)}}try{J.send(M.data)}catch(S){o.handleError(M,J,null,S)}if(!M.async){N()}function I(){if(M.success){M.success(V,R)}if(M.global){o.event.trigger("ajaxSuccess",[J,M])}}function L(){if(M.complete){M.complete(J,R)}if(M.global){o.event.trigger("ajaxComplete",[J,M])}if(M.global&&!--o.active){o.event.trigger("ajaxStop")}}return J},handleError:function(F,H,E,G){if(F.error){F.error(H,E,G)}if(F.global){o.event.trigger("ajaxError",[H,F,G])}},active:0,httpSuccess:function(F){try{return !F.status&&location.protocol=="file:"||(F.status>=200&&F.status<300)||F.status==304||F.status==1223}catch(E){}return false},httpNotModified:function(G,E){try{var H=G.getResponseHeader("Last-Modified");return G.status==304||H==o.lastModified[E]}catch(F){}return false},httpData:function(J,H,G){var F=J.getResponseHeader("content-type"),E=H=="xml"||!H&&F&&F.indexOf("xml")>=0,I=E?J.responseXML:J.responseText;if(E&&I.documentElement.tagName=="parsererror"){throw"parsererror"}if(G&&G.dataFilter){I=G.dataFilter(I,H)}if(typeof I==="string"){if(H=="script"){o.globalEval(I)}if(H=="json"){I=l["eval"]("("+I+")")}}return I},param:function(E){var G=[];function H(I,J){G[G.length]=encodeURIComponent(I)+"="+encodeURIComponent(J)}if(o.isArray(E)||E.jquery){o.each(E,function(){H(this.name,this.value)})}else{for(var F in E){if(o.isArray(E[F])){o.each(E[F],function(){H(F,this)})}else{H(F,o.isFunction(E[F])?E[F]():E[F])}}}return G.join("&").replace(/%20/g,"+")}});var m={},n,d=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];function t(F,E){var G={};o.each(d.concat.apply([],d.slice(0,E)),function() +{G[this]=F});return G}o.fn.extend({show:function(J,L){if(J){return this.animate(t("show",3),J,L)}else{for(var H=0,F=this.length;H").appendTo("body");K=I.css("display");if(K==="none"){K="block"}I.remove();m[G]=K}o.data(this[H],"olddisplay",K)}}for(var H=0,F=this.length;H=0;H--){if(G[H].elem==this){if(E){G[H](true)}G.splice(H,1)}}});if(!E){this.dequeue()}return this}});o.each({slideDown:t("show",1),slideUp:t("hide",1),slideToggle:t("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(E,F){o.fn[E]=function(G,H){return this.animate(F,G,H)}});o.extend({speed:function(G,H,F){var E=typeof G==="object"?G:{complete:F||!F&&H||o.isFunction(G)&&G,duration:G,easing:F&&H||H&&!o.isFunction(H)&&H};E.duration=o.fx.off?0:typeof E.duration==="number"?E.duration:o.fx.speeds[E.duration]||o.fx.speeds._default;E.old=E.complete;E.complete=function(){if(E.queue!==false){o(this).dequeue()}if(o.isFunction(E.old)){E.old.call(this)}};return E},easing:{linear:function(G,H,E,F){return E+F*G},swing:function(G,H,E,F){return((-Math.cos(G*Math.PI)/2)+0.5)*F+E}},timers:[],fx:function(F,E,G){this.options=E;this.elem=F;this.prop=G;if(!E.orig){E.orig={}}}});o.fx.prototype={update:function(){if(this.options.step){this.options.step.call(this.elem,this.now,this)}(o.fx.step[this.prop]||o.fx.step._default)(this);if((this.prop=="height"||this.prop=="width")&&this.elem.style){this.elem.style.display="block"}},cur:function(F){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null)){return this.elem[this.prop]}var E=parseFloat(o.css(this.elem,this.prop,F));return E&&E>-10000?E:parseFloat(o.curCSS(this.elem,this.prop))||0},custom:function(I,H,G){this.startTime=e();this.start=I;this.end=H;this.unit=G||this.unit||"px";this.now=this.start;this.pos=this.state=0;var E=this;function F(J){return E.step(J)}F.elem=this.elem;if(F()&&o.timers.push(F)&&!n){n=setInterval(function(){var K=o.timers;for(var J=0;J=this.options.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;var E=true;for(var F in this.options.curAnim){if(this.options.curAnim[F]!==true){E=false}}if(E){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;this.elem.style.display=this.options.display;if(o.css(this.elem,"display")=="none"){this.elem.style.display="block"}}if(this.options.hide){o(this.elem).hide()}if(this.options.hide||this.options.show){for(var I in this.options.curAnim){o.attr(this.elem.style,I,this.options.orig[I])}}this.options.complete.call(this.elem)}return false}else{var J=G-this.startTime;this.state=J/this.options.duration;this.pos=o.easing[this.options.easing||(o.easing.swing?"swing":"linear")](this.state,J,0,1,this.options.duration);this.now=this.start+((this.end-this.start)*this.pos);this.update()}return true}};o.extend(o.fx,{speeds:{slow:600,fast:200,_default:400},step:{opacity:function(E){o.attr(E.elem.style,"opacity",E.now)},_default:function(E){if(E.elem.style&&E.elem.style[E.prop]!=null){E.elem.style[E.prop]=E.now+E.unit}else{E.elem[E.prop]=E.now}}}});if(document.documentElement.getBoundingClientRect){o.fn.offset=function(){if(!this[0]){return{top:0,left:0}}if(this[0]===this[0].ownerDocument.body){return o.offset.bodyOffset(this[0])}var G=this[0].getBoundingClientRect(),J=this[0].ownerDocument,F=J.body,E=J.documentElement,L=E.clientTop||F.clientTop||0,K=E.clientLeft||F.clientLeft||0,I=G.top+(self.pageYOffset||o.boxModel&&E.scrollTop||F.scrollTop)-L,H=G.left+(self.pageXOffset||o.boxModel&&E.scrollLeft||F.scrollLeft)-K;return{top:I,left:H}}}else{o.fn.offset=function(){if(!this[0]){return{top:0,left:0}}if(this[0]===this[0].ownerDocument.body){return o.offset.bodyOffset(this[0])}o.offset.initialized||o.offset.initialize();var J=this[0],G=J.offsetParent,F=J,O=J.ownerDocument,M,H=O.documentElement,K=O.body,L=O.defaultView,E=L.getComputedStyle(J,null),N=J.offsetTop,I=J.offsetLeft;while((J=J.parentNode)&&J!==K&&J!==H){M=L.getComputedStyle(J,null);N-=J.scrollTop,I-=J.scrollLeft;if(J===G){N+=J.offsetTop,I+=J.offsetLeft;if(o.offset.doesNotAddBorder&&!(o.offset.doesAddBorderForTableAndCells&&/^t(able|d|h)$/i.test(J.tagName))){N+=parseInt(M.borderTopWidth,10)||0,I+=parseInt(M.borderLeftWidth,10)||0}F=G,G=J.offsetParent}if(o.offset.subtractsBorderForOverflowNotVisible&&M.overflow!=="visible"){N+=parseInt(M.borderTopWidth,10)||0,I+=parseInt(M.borderLeftWidth,10)||0}E=M}if(E.position==="relative"||E.position==="static"){N+=K.offsetTop,I+=K.offsetLeft}if(E.position==="fixed"){N+=Math.max(H.scrollTop,K.scrollTop),I+=Math.max(H.scrollLeft,K.scrollLeft)}return{top:N,left:I}}}o.offset={initialize:function(){if(this.initialized){return}var L=document.body,F=document.createElement("div"),H,G,N,I,M,E,J=L.style.marginTop,K='
    ';M={position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"};for(E in M){F.style[E]=M[E]}F.innerHTML=K;L.insertBefore(F,L.firstChild);H=F.firstChild,G=H.firstChild,I=H.nextSibling.firstChild.firstChild;this.doesNotAddBorder=(G.offsetTop!==5);this.doesAddBorderForTableAndCells=(I.offsetTop===5);H.style.overflow="hidden",H.style.position="relative";this.subtractsBorderForOverflowNotVisible=(G.offsetTop===-5);L.style.marginTop="1px";this.doesNotIncludeMarginInBodyOffset=(L.offsetTop===0);L.style.marginTop=J;L.removeChild(F);this.initialized=true},bodyOffset:function(E){o.offset.initialized||o.offset.initialize();var G=E.offsetTop,F=E.offsetLeft;if(o.offset.doesNotIncludeMarginInBodyOffset){G+=parseInt(o.curCSS(E,"marginTop",true),10)||0,F+=parseInt(o.curCSS(E,"marginLeft",true),10)||0}return{top:G,left:F}}};o.fn.extend({position:function(){var I=0,H=0,F;if(this[0]){var G=this.offsetParent(),J=this.offset(),E=/^body|html$/i.test(G[0].tagName)?{top:0,left:0}:G.offset();J.top-=j(this,"marginTop");J.left-=j(this,"marginLeft");E.top+=j(G,"borderTopWidth");E.left+=j(G,"borderLeftWidth");F={top:J.top-E.top,left:J.left-E.left}}return F},offsetParent:function(){var E=this[0].offsetParent||document.body;while(E&&(!/^body|html$/i.test(E.tagName)&&o.css(E,"position")=="static")){E=E.offsetParent}return o(E)}});o.each(["Left","Top"],function(F,E){var G="scroll"+E;o.fn[G]=function(H){if(!this[0]){return null}return H!==g?this.each(function(){this==l||this==document?l.scrollTo(!F?H:o(l).scrollLeft(),F?H:o(l).scrollTop()):this[G]=H}):this[0]==l||this[0]==document?self[F?"pageYOffset":"pageXOffset"]||o.boxModel&&document.documentElement[G]||document.body[G]:this[0][G]}});o.each(["Height","Width"],function(I,G){var E=I?"Left":"Top",H=I?"Right":"Bottom",F=G.toLowerCase();o.fn["inner"+G]=function(){return this[0]?o.css(this[0],F,false,"padding"):null};o.fn["outer"+G]=function(K){return this[0]?o.css(this[0],F,false,K?"margin":"border"):null};var J=G.toLowerCase();o.fn[J]=function(K){return this[0]==l?document.compatMode=="CSS1Compat"&&document.documentElement["client"+G]||document.body["client"+G]:this[0]==document?Math.max(document.documentElement["client"+G],document.body["scroll"+G],document.documentElement["scroll"+G],document.body["offset"+G],document.documentElement["offset"+G]):K===g?(this.length?o.css(this[0],J):null):this.css(J,typeof K==="string"?K:K+"px")}})})(); + +/* + * jQuery hashchange event - v1.3 - 7/21/2010 + * http://benalman.com/projects/jquery-hashchange-plugin/ + * + * Copyright (c) 2010 "Cowboy" Ben Alman + * Dual licensed under the MIT and GPL licenses. + * http://benalman.com/about/license/ + */ +(function($,e,b){var c="hashchange",h=document,f,g=$.event.special,i=h.documentMode,d="on"+c in e&&(i===b||i>7);function a(j){j=j||location.href;return"#"+j.replace(/^[^#]*#?(.*)$/,"$1")}$.fn[c]=function(j){return j?this.bind(c,j):this.trigger(c)};$.fn[c].delay=50;g[c]=$.extend(g[c],{setup:function(){if(d){return false}$(f.start)},teardown:function(){if(d){return false}$(f.stop)}});f=(function(){var j={},p,m=a(),k=function(q){return q},l=k,o=k;j.start=function(){p||n()};j.stop=function(){p&&clearTimeout(p);p=b};function n(){var r=a(),q=o(m);if(r!==m){l(m=r,q);$(e).trigger(c)}else{if(q!==m){location.href=location.href.replace(/#.*/,"")+q}}p=setTimeout(n,$.fn[c].delay)}$.browser.msie&&!d&&(function(){var q,r;j.start=function(){if(!q){r=$.fn[c].src;r=r&&r+a();q=$('